From c0dfbdbc26eecf35a11ef28cb383ea902026e505 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 4 Apr 2026 11:54:26 -0400 Subject: [PATCH] feat: status dots, priority banners, lt-tags, command palette, activity timeline improvements - Fix DashboardView asset version (was hardcoded 20260327, now uses config ASSET_VERSION) - Add lt-dot status indicators on dashboard table rows and ticket view toolbar - Add lt-tag display for Category/Type in ticket read mode (swaps to select in edit mode) - Add P1/P2 SLA alert banner with elapsed time, progress bar, per-session dismiss - Wire command palette (Ctrl+K): global nav + admin links via lt.cmdPalette.init() - Fix cmdPalette.init() call format (flat array, not nested group objects) - Improve activity timeline: richer formatAction(), better color coding by event type, inline status transitions shown in meta row, icon column added Co-Authored-By: Claude Sonnet 4.6 --- assets/js/ticket.js | 20 ++++++ views/DashboardView.php | 21 ++++-- views/TicketView.php | 146 ++++++++++++++++++++++++++++++++-------- views/layout_footer.php | 31 +++++---- 4 files changed, 170 insertions(+), 48 deletions(-) diff --git a/assets/js/ticket.js b/assets/js/ticket.js index b6d6e58..2e36fc0 100644 --- a/assets/js/ticket.js +++ b/assets/js/ticket.js @@ -138,6 +138,10 @@ function toggleEditMode() { metadataFields.forEach(field => { field.classList.remove('lt-display-field'); }); + + // Show edit-mode selects for category/type, hide their read-mode tags + document.querySelectorAll('.read-mode-tag').forEach(el => { el.style.display = 'none'; }); + document.querySelectorAll('.edit-mode-field').forEach(el => { el.style.display = ''; }); } else { saveTicket(); editButton.textContent = 'Edit Ticket'; @@ -159,6 +163,22 @@ function toggleEditMode() { metadataFields.forEach(field => { field.classList.add('lt-display-field'); }); + + // Hide edit-mode selects, show and update read-mode tags + document.querySelectorAll('.edit-mode-field').forEach(el => { el.style.display = 'none'; }); + var catSel = document.getElementById('categorySelect'); + var typSel = document.getElementById('typeSelect'); + var catTag = document.getElementById('categoryTag'); + var typTag = document.getElementById('typeTag'); + if (catTag) { + if (catSel) catTag.textContent = catSel.options[catSel.selectedIndex].text; + catTag.style.display = ''; + } + if (typTag) { + if (typSel) typTag.textContent = typSel.options[typSel.selectedIndex].text; + typTag.style.display = ''; + } + document.querySelectorAll('.read-mode-tag:not(#categoryTag):not(#typeTag)').forEach(el => { el.style.display = ''; }); } } diff --git a/views/DashboardView.php b/views/DashboardView.php index 01e3780..0765e9b 100644 --- a/views/DashboardView.php +++ b/views/DashboardView.php @@ -14,13 +14,14 @@ require_once __DIR__ . '/../middleware/CsrfMiddleware.php'; $nonce = SecurityHeadersMiddleware::getNonce(); $pageTitle = 'Dashboard'; $activeNav = 'dashboard'; -$pageStyles = ['/assets/css/dashboard.css?v=20260327']; +$_v = $GLOBALS['config']['ASSET_VERSION'] ?? '1'; +$pageStyles = ["/assets/css/dashboard.css?v={$_v}"]; $pageScripts = [ - '/assets/js/markdown.js?v=20260327', - '/assets/js/dashboard.js?v=20260327', - '/assets/js/advanced-search.js?v=20260327', - '/assets/js/keyboard-shortcuts.js?v=20260327', - '/assets/js/settings.js?v=20260327', + "/assets/js/markdown.js?v={$_v}", + "/assets/js/dashboard.js?v={$_v}", + "/assets/js/advanced-search.js?v={$_v}", + "/assets/js/keyboard-shortcuts.js?v={$_v}", + "/assets/js/settings.js?v={$_v}", ]; // ── Pagination helpers ──────────────────────────────────────────────────────── @@ -431,6 +432,14 @@ include __DIR__ . '/layout_header.php'; + 'lt-dot-up', + 'In Progress' => 'lt-dot-warn', + 'Pending' => 'lt-dot--orange', + 'Closed' => 'lt-dot-idle', + default => 'lt-dot-idle', + }; ?> + diff --git a/views/TicketView.php b/views/TicketView.php index 9b83e18..13db444 100644 --- a/views/TicketView.php +++ b/views/TicketView.php @@ -22,26 +22,46 @@ $pageScripts = [ // Helper functions function getEventIcon(string $actionType): string { return match($actionType) { - 'create' => '[ + ]', - 'update' => '[ ~ ]', - 'comment' => '[ > ]', - 'view' => '[ . ]', - 'assign' => '[ @ ]', - 'status_change' => '[ ! ]', - default => '[ * ]', + 'create' => '[+]', + 'update' => '[~]', + 'comment' => '[>]', + 'view' => '[.]', + 'assign' => '[@]', + 'status_change' => '[!]', + 'attachment' => '[^]', + 'delete' => '[x]', + default => '[*]', }; } function formatAction(array $event): string { - return match($event['action_type']) { - 'create' => 'created this ticket', - 'update' => 'updated this ticket', - 'comment' => 'added a comment', - 'view' => 'viewed this ticket', - 'assign' => 'assigned this ticket', - 'status_change' => 'changed the status', - default => $event['action_type'], - }; + $det = $event['details'] ?? []; + switch ($event['action_type']) { + case 'create': return 'created this ticket'; + case 'comment': return 'posted a comment'; + case 'view': return 'viewed this ticket'; + case 'attachment': return 'uploaded a file'; + case 'delete': return 'deleted a comment'; + case 'assign': + if (is_array($det) && isset($det['assigned_to']['to'])) { + $to = $det['assigned_to']['to'] ?: 'Unassigned'; + return 'assigned to ' . htmlspecialchars($to); + } + return 'assigned this ticket'; + case 'status_change': + if (is_array($det) && isset($det['status']['from'], $det['status']['to'])) { + return htmlspecialchars($det['status']['from']) . ' → ' . htmlspecialchars($det['status']['to']); + } + return 'changed the status'; + case 'update': + if (is_array($det)) { + $fields = array_keys(array_filter($det, fn($v) => is_array($v) && isset($v['from'], $v['to']))); + if ($fields) return 'updated ' . implode(', ', array_map(fn($f) => str_replace('_', ' ', $f), $fields)); + } + return 'updated this ticket'; + default: + return $event['action_type']; + } } // Calculate ticket age @@ -113,6 +133,17 @@ include __DIR__ . '/layout_header.php'; Ticket #
+ + 'lt-dot-up', + 'In Progress' => 'lt-dot-warn', + 'Pending' => 'lt-dot--orange', + 'Closed' => 'lt-dot-idle', + default => 'lt-dot-idle', + }; + ?> + + 'lt-tag--orange','Software'=>'lt-tag--cyan','Network'=>'lt-tag--purple','Security'=>'lt-tag--red',default=>'' }; ?> + + + + + 'lt-tag--orange','Issue'=>'lt-tag--red','Problem'=>'lt-tag--red','Upgrade'=>'lt-tag--purple','Install'=>'lt-tag--cyan',default=>'' }; ?> + + + +