feat: Add 9 new features for enhanced UX and security

Quick Wins:
- Feature 1: Ticket linking in comments (#123456789 auto-links)
- Feature 6: Checkbox click area fix (click anywhere in cell)
- Feature 7: User groups display in settings modal

UI Enhancements:
- Feature 4: Collapsible sidebar with localStorage persistence
- Feature 5: Inline ticket preview popup on hover (300ms delay)
- Feature 2: Mobile responsive improvements (44px touch targets, iOS zoom fix)

Major Features:
- Feature 3: Kanban card view with status columns (toggle with localStorage)
- Feature 9: API key generation admin panel (/admin/api-keys)
- Feature 8: Ticket visibility levels (public/internal/confidential)

New files:
- views/admin/ApiKeysView.php
- api/generate_api_key.php
- api/revoke_api_key.php
- migrations/008_ticket_visibility.sql

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-23 10:01:50 -05:00
parent c32e9c871b
commit e86a5de3fd
19 changed files with 1933 additions and 39 deletions

View File

@@ -92,6 +92,7 @@
<a href="/admin/custom-fields">📝 Custom Fields</a>
<a href="/admin/user-activity">👥 User Activity</a>
<a href="/admin/audit-log">📜 Audit Log</a>
<a href="/admin/api-keys">🔑 API Keys</a>
</div>
</div>
<?php endif; ?>
@@ -125,7 +126,11 @@
<!-- Dashboard Layout with Sidebar -->
<div class="dashboard-layout">
<!-- Left Sidebar with Filters -->
<aside class="dashboard-sidebar">
<aside class="dashboard-sidebar" id="dashboardSidebar">
<button class="sidebar-toggle" onclick="toggleSidebar()" title="Toggle Sidebar">
<span class="toggle-arrow">◀</span>
</button>
<div class="sidebar-content">
<div class="ascii-frame-inner">
<div class="ascii-subsection-header">Filters</div>
@@ -184,6 +189,7 @@
<button id="apply-filters-btn" class="btn">Apply Filters</button>
<button id="clear-filters-btn" class="btn btn-secondary">Clear All</button>
</div>
</div>
</aside>
<!-- Main Content Area -->
@@ -277,6 +283,10 @@
<!-- Center: Actions + Count -->
<div class="toolbar-center">
<div class="view-toggle">
<button id="tableViewBtn" class="view-btn active" onclick="setViewMode('table')" title="Table View">≡</button>
<button id="cardViewBtn" class="view-btn" onclick="setViewMode('card')" title="Kanban View">▦</button>
</div>
<button onclick="window.location.href='<?php echo $GLOBALS['config']['BASE_URL']; ?>/ticket/create'" class="btn create-ticket">+ New Ticket</button>
<div class="export-dropdown" id="exportDropdown" style="display: none;">
<button class="btn" onclick="toggleExportMenu(event)">↓ Export Selected (<span id="exportCount">0</span>)</button>
@@ -395,7 +405,7 @@
// Add checkbox column for admins
if ($GLOBALS['currentUser']['is_admin'] ?? false) {
echo "<td><input type='checkbox' class='ticket-checkbox' value='{$row['ticket_id']}' onchange='updateSelectionCount()'></td>";
echo "<td onclick='toggleRowCheckbox(event, this)' class='checkbox-cell'><input type='checkbox' class='ticket-checkbox' value='{$row['ticket_id']}' onchange='updateSelectionCount()'></td>";
}
echo "<td><a href='/ticket/{$row['ticket_id']}' class='ticket-link'>{$row['ticket_id']}</a></td>";
@@ -440,6 +450,40 @@
</div>
<!-- END OUTER FRAME -->
<!-- Kanban Card View -->
<div id="cardView" class="card-view-container" style="display: none;">
<div class="kanban-board">
<div class="kanban-column" data-status="Open">
<div class="kanban-column-header status-Open">
<span class="column-title">Open</span>
<span class="column-count">0</span>
</div>
<div class="kanban-cards"></div>
</div>
<div class="kanban-column" data-status="Pending">
<div class="kanban-column-header status-Pending">
<span class="column-title">Pending</span>
<span class="column-count">0</span>
</div>
<div class="kanban-cards"></div>
</div>
<div class="kanban-column" data-status="In Progress">
<div class="kanban-column-header status-In-Progress">
<span class="column-title">In Progress</span>
<span class="column-count">0</span>
</div>
<div class="kanban-cards"></div>
</div>
<div class="kanban-column" data-status="Closed">
<div class="kanban-column-header status-Closed">
<span class="column-title">Closed</span>
<span class="column-count">0</span>
</div>
<div class="kanban-cards"></div>
</div>
</div>
</div>
<!-- Settings Modal -->
<div class="settings-modal" id="settingsModal" style="display: none;" onclick="closeOnBackdropClick(event)">
<div class="settings-content">
@@ -571,6 +615,23 @@
<div><strong>Role:</strong></div>
<div><?php echo $GLOBALS['currentUser']['is_admin'] ? 'Administrator' : 'User'; ?></div>
<div><strong>Groups:</strong></div>
<div class="user-groups-list">
<?php
$groups = explode(',', $GLOBALS['currentUser']['groups'] ?? '');
foreach ($groups as $g):
if (trim($g)):
?>
<span class="group-badge"><?php echo htmlspecialchars(trim($g)); ?></span>
<?php
endif;
endforeach;
if (empty(trim($GLOBALS['currentUser']['groups'] ?? ''))):
?>
<span style="color: var(--text-muted);">No groups assigned</span>
<?php endif; ?>
</div>
</div>
</div>
</div>