refactored tickets to include tags
This commit is contained in:
parent
b13cd3448f
commit
c0f9ed1094
@ -9,9 +9,16 @@ class TicketController extends BaseController implements CRUD {
|
||||
|
||||
$this->requireLogin();
|
||||
|
||||
$filter = $f3->get('GET.status');
|
||||
|
||||
// retrieve tickets
|
||||
$ticket_mapper = new Ticket($this->getDB());
|
||||
|
||||
if($filter){
|
||||
$tickets = $ticket_mapper->findFiltered($filter);
|
||||
} else {
|
||||
$tickets = $ticket_mapper->findAll();
|
||||
}
|
||||
|
||||
// render
|
||||
$this->renderView('../ui/views/ticket/index.html',
|
||||
|
||||
79
app/models/Tag.php
Normal file
79
app/models/Tag.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
class Tag extends \DB\SQL\Mapper
|
||||
{
|
||||
|
||||
protected $tag_table, $tag_table_id;
|
||||
|
||||
function __construct($db, $type = null)
|
||||
{
|
||||
if($type == null){
|
||||
// do tag mapping
|
||||
parent::__construct($db, 'tags');
|
||||
} else {
|
||||
$this->tag_table = $type . '_tags';
|
||||
$this->tag_table_id = $type . '_id';
|
||||
parent::__construct($db, $this->tag_table);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
// VERIFY: possible issue with this?
|
||||
public function getTagsFor($objects, $id_key = 'id')
|
||||
{
|
||||
// echo $this->get('_type_id'); exit;
|
||||
// printf('<pre>%s</pre>', print_r($this,1)); exit;
|
||||
if(empty($objects)) return [];
|
||||
$ids = array_column($objects, $id_key);
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
$sql =
|
||||
'SELECT tt.%1$s, t.id, t.name, t.color
|
||||
FROM %2$s tt
|
||||
INNER JOIN tags t ON tt.tag_id = t.id
|
||||
WHERE tt.%1$s IN (%3$s)';
|
||||
$sql_sprintf = sprintf($sql, $this->tag_table_id, $this->tag_table, $placeholders);
|
||||
$rows = $this->db->exec($sql_sprintf, $ids);
|
||||
|
||||
$tags_map = [];
|
||||
foreach($rows as $row)
|
||||
{
|
||||
$tags_map[$row[$this->tag_table_id]][] = $row;
|
||||
}
|
||||
|
||||
foreach($objects as &$object)
|
||||
{
|
||||
$object['tags'] = $tags_map[$object[$id_key]] ?? [];
|
||||
}
|
||||
return $objects;
|
||||
|
||||
}
|
||||
|
||||
public function getTagsForID($id, $id_key = 'id')
|
||||
{
|
||||
$sql = 'SELECT tt.%1$s, t.id, t.name, t.color
|
||||
FROM %2$s tt
|
||||
INNER JOIN tags t ON tt.tag_id = t.id
|
||||
WHERE tt.%1$s = ?';
|
||||
$sql_sprintf = sprintf($sql, $this->tag_table_id, $this->tag_table);
|
||||
$rows = $this->db->exec($sql_sprintf, $id);
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function findLinkedTags($id = '')
|
||||
{
|
||||
$sql = '
|
||||
SELECT t.name, t.color
|
||||
FROM `?` tt
|
||||
LEFT JOIN `tags` t ON t.id = tt.id
|
||||
WHERE tt.`?` = ?
|
||||
';
|
||||
$params = [
|
||||
$this->_type,
|
||||
$this->_type_id,
|
||||
$id
|
||||
];
|
||||
return $this->db->exec($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
class Ticket extends \DB\SQL\Mapper {
|
||||
function __construct($db){
|
||||
parent::__construct($db, 'tickets');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10,8 +11,9 @@ class Ticket extends \DB\SQL\Mapper {
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->db->exec(
|
||||
'SELECT t.* , tp.name AS priority_name, ts.name AS status_name, u.display_name
|
||||
$tickets = $this->db->exec(
|
||||
'SELECT t.id, t.title, t.created_at,
|
||||
tp.name AS priority_name, ts.name AS status_name, u.display_name
|
||||
FROM tickets t
|
||||
LEFT JOIN ticket_priorities tp ON t.priority_id = tp.id
|
||||
LEFT JOIN ticket_statuses ts ON t.status_id = ts.id
|
||||
@ -19,11 +21,60 @@ class Ticket extends \DB\SQL\Mapper {
|
||||
WHERE t.recycled = 0
|
||||
ORDER BY t.created_at DESC'
|
||||
);
|
||||
$result = $this->getTagsForTickets($tickets);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function findFiltered(string $filter): array
|
||||
{
|
||||
$sql = '
|
||||
SELECT t.*, tp.name AS priority_name, ts.name AS status_name, u.display_name
|
||||
FROM tickets t
|
||||
LEFT JOIN ticket_priorities tp ON t.priority_id = tp.id
|
||||
LEFT JOIN ticket_statuses ts ON t.status_id = ts.id
|
||||
LEFT JOIN users u ON t.created_by = u.id
|
||||
WHERE t.recycled = 0
|
||||
';
|
||||
$params = [];
|
||||
switch($filter){
|
||||
case 'open':
|
||||
$sql .= ' AND status_id = ?';
|
||||
$params[] = 1;
|
||||
break;
|
||||
case 'in_progress':
|
||||
$sql .= ' AND status_id = ?';
|
||||
$params[] = 2;
|
||||
break;
|
||||
case 'on_hold':
|
||||
$sql .= ' AND status_id = ?';
|
||||
$params[] = 3;
|
||||
break;
|
||||
case 'completed':
|
||||
$sql .= ' AND status_id = ?';
|
||||
$params[] = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
$sql .= ' ORDER BY t.created_at DESC';
|
||||
$tickets = $this->db->exec($sql, $params);
|
||||
$result = $this->getTagsForTickets($tickets);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getTagsForTickets(array $tickets)
|
||||
{
|
||||
$tag_mapper = new Tag($this->db, 'ticket');
|
||||
$tickets = $tag_mapper->getTagsFor($tickets);
|
||||
|
||||
return $tickets;
|
||||
}
|
||||
|
||||
public function findById($id): ?Ticket
|
||||
{
|
||||
$this->status_name = 'SELECT name FROM ticket_statuses WHERE tickets.status_id = ticket_statuses.id';
|
||||
$this->priority_name = 'SELECT name FROM ticket_priorities WHERE tickets.priority_id = ticket_priorities.id';
|
||||
$this->load(['id = ?', $id]);
|
||||
$this->tags = (new Tag($this->db,'ticket'))->getTagsForID($id, 'ticket_id');
|
||||
return $this->dry() ? null : $this;
|
||||
}
|
||||
|
||||
@ -35,7 +86,7 @@ class Ticket extends \DB\SQL\Mapper {
|
||||
$this->description = $data['description'] ?? '';
|
||||
//
|
||||
$this->priority_id = $data['priority_id'] ?? null;
|
||||
$this->status = $data['status_id'] ?? null;
|
||||
$this->status_id = $data['status_id'] ?? null;
|
||||
//
|
||||
$this->created_by = $data['created_by'] ?? null;
|
||||
$this->created_at = ($data['created_at'] == '' ? date('Y-m-d H:i:s') : $data['created_at']) ?? date('Y-m-d H:i:s');
|
||||
|
||||
2
public/css/main.min.css
vendored
2
public/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -28,12 +28,13 @@
|
||||
@extend .is-flex;
|
||||
@extend .is-justify-content-flex-start;
|
||||
@extend .is-flex-wrap-wrap;
|
||||
@extend .mb-1;
|
||||
align-items: center;
|
||||
|
||||
.ticket-title {
|
||||
@extend .title;
|
||||
@extend .mb-0;
|
||||
@extend .is-5;
|
||||
@extend .mb-1;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
||||
@ -15,16 +15,10 @@
|
||||
<span class="ticket-title">
|
||||
<a href="/ticket/{{ @ticket.id }}">{{ @ticket.title }}</a>
|
||||
</span>
|
||||
<div class="tags">
|
||||
<div class="tags ml-2">
|
||||
<!-- TODO: get tags -->
|
||||
<span class="tag is-link">tag</span>
|
||||
</div>
|
||||
<?php /*
|
||||
<repeat group="{{ @ticket.tags }}" value="{{ @tag }}">
|
||||
<span class="tag is-link">{{ @tag }}</span>
|
||||
<span class="tag is-{{@tag.color}}">{{ @tag.name }}</span>
|
||||
</repeat>
|
||||
*/ ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ticket-meta">
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<bulma type="H_FIELD_INPUT" label="Created At:" name="created_at" value=""></bulma>
|
||||
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value=""></bulma>
|
||||
|
||||
<!-- TODO implement priority and status -->
|
||||
<!-- priority and status -->
|
||||
<bulma type="H_FIELD_SELECT_NEW" label="Priority:" name="priority_id"
|
||||
options="priorities" option_value="id" option_name="name"
|
||||
selected="2"></bulma>
|
||||
|
||||
@ -51,6 +51,16 @@
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="block">
|
||||
<!-- priority and status -->
|
||||
<bulma type="FIELD_SELECT" label="Priority:" name="priority_id"
|
||||
options="{{@priorities}}" option_value="id" option_name="name"
|
||||
selected="{{@ticket.priority_id}}"></bulma>
|
||||
|
||||
<bulma type="FIELD_SELECT" label="Status:" name="status_id"
|
||||
options="{{@statuses}}" option_value="id" option_name="name"
|
||||
selected="{{@ticket.status_id}}"></bulma>
|
||||
</div>
|
||||
<!-- meta data -->
|
||||
<div class="block">
|
||||
<table class="table is-bordered is-fullwidth">
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
<bulma type="H_FIELD_SELECT_NEW" label="Status:" name="status_id"
|
||||
options="statuses" option_value="id" option_name="name"
|
||||
selected="@ticket.status_id"></bulma>
|
||||
selected="{{@ticket.status_id}}"></bulma>
|
||||
|
||||
<include href="/ui/parts/clipboard.html"></include>
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<include href="/ui/session/error.html"></include>
|
||||
</include>
|
||||
<!-- updated design -- inspiration gitea -->
|
||||
<div class="block">
|
||||
<div class="field is-grouped">
|
||||
<div class="control is-expanded">
|
||||
<div class="field has-addons is-expanded">
|
||||
@ -9,7 +10,8 @@
|
||||
<input class="input" type="text" placeholder="Find a ticket">
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info"><span class="icon"><i class="fas fa-magnifying-glass"></i></span></button>
|
||||
<button class="button is-info"><span class="icon"><i
|
||||
class="fas fa-magnifying-glass"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -19,6 +21,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block">
|
||||
<div class="field has-addons">
|
||||
<!-- TODO: move this into a template -->
|
||||
<repeat group="{{ IconsHelper::$status_icons}}" key="{{ @k }}" value="{{ @icon }}">
|
||||
<p class="control">
|
||||
<a href="{{ @PATH }}/?status={{ @k }}" class="button">
|
||||
<span class="icon is-small"><i class="fas fa-{{ @icon[0] }}"></i></span>
|
||||
<span>{{ IconsHelper::$status_names[@k] }}</span>
|
||||
</a>
|
||||
</p>
|
||||
</repeat>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div id="ticket_list">
|
||||
|
||||
@ -24,6 +24,11 @@
|
||||
<div class="column">
|
||||
<!-- meta data -->
|
||||
<div class="block">
|
||||
<div class="tags">
|
||||
<repeat group="{{ @ticket.tags }}" value="{{@tag}}">
|
||||
<span class="tag is-{{@tag.color}}">{{@tag.name}}</span>
|
||||
</repeat>
|
||||
</div>
|
||||
<table class="table is-bordered is-fullwidth">
|
||||
<thead>
|
||||
<tr><th class="has-width-100">Property</th><th>Value</th></tr>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user