diff --git a/views/admin/UserActivityView.php b/views/admin/UserActivityView.php
index 00548da..3d80857 100644
--- a/views/admin/UserActivityView.php
+++ b/views/admin/UserActivityView.php
@@ -43,11 +43,23 @@ include __DIR__ . '/../../views/layout_header.php';
+ =1 tracked action within the selected date range.
+ // The query LEFT JOINs from all users, so $userStats includes zero-activity users.
+ $activeUsers = 0;
+ foreach ($userStats as $_u) {
+ $_activity = ($_u['tickets_created'] ?? 0) + ($_u['tickets_resolved'] ?? 0)
+ + ($_u['comments_added'] ?? 0) + ($_u['tickets_assigned'] ?? 0);
+ if ($_activity > 0) {
+ $activeUsers++;
+ }
+ }
+ ?>
[ # ]
-
= count($userStats) ?>
+
= (int)$activeUsers ?>
Active Users
diff --git a/views/layout_footer.php b/views/layout_footer.php
index 04018e0..e10a1ce 100644
--- a/views/layout_footer.php
+++ b/views/layout_footer.php
@@ -138,10 +138,13 @@
var themeBtn = document.getElementById('lt-theme-btn');
if (themeBtn) themeBtn.addEventListener('click', function() { lt.theme.toggle(); });
- // Command palette — global navigation commands available on all pages
+ // Command palette — single global instance (overlay DOM above; base.js binds Ctrl/Cmd+K)
var _cpCmds = [
{ id: 'nav-dashboard', group: 'Navigation', icon: '~', label: 'Dashboard', kbd: 'G D', action: function() { window.location.href = '/'; } },
{ id: 'nav-new-ticket', group: 'Navigation', icon: '+', label: 'New Ticket', kbd: 'N', action: function() { window.location.href = '/ticket/create'; } },
+ { id: 'filter-mine', group: 'Filter', icon: '◈', label: 'My Open Tickets', action: function() { window.location.href = '/?assigned_to=me&status=Open,In+Progress,Pending'; } },
+ { id: 'filter-unassigned', group: 'Filter', icon: '◌', label: 'Unassigned Tickets', action: function() { window.location.href = '/?assigned_to=unassigned'; } },
+ { id: 'filter-critical', group: 'Filter', icon: '!', label: 'P1 Critical Tickets', action: function() { window.location.href = '/?priority=1'; } },
{ id: 'help-shortcuts', group: 'Help', icon: '?', label: 'Keyboard Shortcuts', kbd: '?', action: function() { lt.modal.open('lt-keys-help'); } },
{ id: 'help-theme', group: 'Help', icon: '*', label: 'Toggle Theme', action: function() { lt.theme.toggle(); } },
];
@@ -156,7 +159,20 @@
{ id: 'admin-api-keys', group: 'Admin', icon: 'K', label: 'API Keys', action: function() { window.location.href = '/admin/api-keys'; } },
]);
+ // Recently viewed tickets from localStorage
+ try {
+ var _recent = JSON.parse(localStorage.getItem('lt_recent_tickets') || '[]');
+ _recent.slice(0, 5).forEach(function(id) {
+ _cpCmds.push({ id: 'recent-' + id, group: 'Recent', icon: '◷', label: 'Ticket #' + id, tags: ['ticket'], action: function(tid) { return function() { window.location.href = '/ticket/' + tid; }; }(id) });
+ });
+ } catch (_e) { /* ignore malformed localStorage */ }
lt.cmdPalette.init(_cpCmds);
+
+ // Bind the header ⌘K trigger button (no inline onclick — CSP blocks inline handlers)
+ var _cmdTrigger = document.getElementById('lt-cmd-trigger');
+ if (_cmdTrigger) {
+ _cmdTrigger.addEventListener('click', function() { lt.cmdPalette.open(); });
+ }
}
// Patch lt.api mutating methods to auto-rotate CSRF token when server returns a new one
@@ -194,7 +210,7 @@
return Math.floor(diff / 86400) + 'd ago';
}
- function esc(s) { return String(s).replace(/&/g,'&').replace(//g,'>'); }
+ function esc(s) { return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,'''); }
function renderNotifications(data) {
lt.notif.set(bell, data.unread_count || 0);
diff --git a/views/layout_header.php b/views/layout_header.php
index d5be680..2690e2f 100644
--- a/views/layout_header.php
+++ b/views/layout_header.php
@@ -196,7 +196,9 @@ $_lt_assetVer = $GLOBALS['config']['ASSET_VERSION'] ?? '20260329';
Loading…