feat: complete TDS v1.2 redesign across all views
Full application redesign using Terminal Design System v1.2 (lt-* class system). Introduces shared layout_header/footer partials, upgrades base.css/base.js to TDS v1.2, and rewrites all views (Dashboard, Ticket, CreateTicket, and all 7 admin views) with lt-frame, lt-table, lt-modal, lt-stats-grid, lt-kv-grid, and data-action event delegation patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+122
-159
@@ -1,166 +1,129 @@
|
||||
<?php
|
||||
// Admin view for browsing audit logs
|
||||
// Receives $auditLogs, $totalPages, $page, $filters from controller
|
||||
require_once __DIR__ . '/../../middleware/SecurityHeadersMiddleware.php';
|
||||
require_once __DIR__ . '/../../middleware/CsrfMiddleware.php';
|
||||
$nonce = SecurityHeadersMiddleware::getNonce();
|
||||
$nonce = SecurityHeadersMiddleware::getNonce();
|
||||
$pageTitle = 'Audit Log';
|
||||
$activeNav = 'admin-audit-log';
|
||||
$pageStyles = ['/assets/css/dashboard.css?v=20260327'];
|
||||
$pageScripts = [];
|
||||
include __DIR__ . '/../../views/layout_header.php';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Audit Log - Admin</title>
|
||||
<link rel="icon" type="image/png" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/images/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/base.css">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260320">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260320">
|
||||
<script nonce="<?php echo $nonce; ?>" src="/assets/js/base.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>">
|
||||
window.CSRF_TOKEN = '<?php echo CsrfMiddleware::getToken(); ?>';
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="user-header">
|
||||
<div class="user-header-left">
|
||||
<a href="/" class="back-link">[ ← DASHBOARD ]</a>
|
||||
<span class="admin-page-title">Admin: Audit Log</span>
|
||||
</div>
|
||||
<div class="user-header-right">
|
||||
<?php if (isset($GLOBALS['currentUser'])): ?>
|
||||
<span class="user-name">[ <?php echo htmlspecialchars(strtoupper($GLOBALS['currentUser']['display_name'] ?? $GLOBALS['currentUser']['username'])); ?> ]</span>
|
||||
<span class="admin-badge">[ ADMIN ]</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="lt-page-header">
|
||||
<div class="lt-flex lt-flex-gap-sm lt-flex-align-center">
|
||||
<a href="/" class="lt-btn lt-btn-ghost lt-btn-sm">← Dashboard</a>
|
||||
<span class="lt-text-muted lt-text-xs">/</span>
|
||||
<span class="lt-text-muted lt-text-xs">Admin: Audit Log</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Audit Log Browser</div>
|
||||
<div class="lt-section-body">
|
||||
|
||||
<!-- Filters -->
|
||||
<form method="GET" class="lt-flex lt-flex-wrap lt-flex-gap-sm lt-mb-md" role="search" aria-label="Filter audit logs">
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" for="action_type">Action Type</label>
|
||||
<select name="action_type" id="action_type" class="lt-select lt-select-sm">
|
||||
<option value="">All Actions</option>
|
||||
<?php foreach (['create','update','delete','comment','assign','status_change','login','security'] as $a): ?>
|
||||
<option value="<?= $a ?>" <?= ($filters['action_type'] ?? '') === $a ? 'selected' : '' ?>><?= ucfirst(str_replace('_',' ',$a)) ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" for="user_id">User</label>
|
||||
<select name="user_id" id="user_id" class="lt-select lt-select-sm">
|
||||
<option value="">All Users</option>
|
||||
<?php if (isset($users)): foreach ($users as $u): ?>
|
||||
<option value="<?= $u['user_id'] ?>" <?= ($filters['user_id'] ?? '') == $u['user_id'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($u['display_name'] ?? $u['username']) ?>
|
||||
</option>
|
||||
<?php endforeach; endif ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" for="date_from">Date From</label>
|
||||
<input type="date" name="date_from" id="date_from" class="lt-input lt-input-sm"
|
||||
value="<?= htmlspecialchars($filters['date_from'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" for="date_to">Date To</label>
|
||||
<input type="date" name="date_to" id="date_to" class="lt-input lt-input-sm"
|
||||
value="<?= htmlspecialchars($filters['date_to'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="lt-form-group lt-flex lt-flex-align-center lt-flex-gap-sm" style="margin:0;align-self:flex-end">
|
||||
<button type="submit" class="lt-btn lt-btn-primary lt-btn-sm">FILTER</button>
|
||||
<a href="?" class="lt-btn lt-btn-ghost lt-btn-sm">RESET</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Log table -->
|
||||
<div class="lt-table-wrap">
|
||||
<table class="lt-table lt-table-responsive" aria-label="Audit log entries">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Timestamp</th>
|
||||
<th scope="col">User</th>
|
||||
<th scope="col">Action</th>
|
||||
<th scope="col">Entity</th>
|
||||
<th scope="col">Entity ID</th>
|
||||
<th scope="col">Details</th>
|
||||
<th scope="col">IP Address</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($auditLogs)): ?>
|
||||
<tr><td colspan="7" class="lt-empty">No audit log entries found.</td></tr>
|
||||
<?php else: foreach ($auditLogs as $log): ?>
|
||||
<tr>
|
||||
<td data-label="Timestamp" class="lt-text-xs"><?= date('Y-m-d H:i:s', strtotime($log['created_at'])) ?></td>
|
||||
<td data-label="User"><?= htmlspecialchars($log['display_name'] ?? $log['username'] ?? 'System') ?></td>
|
||||
<td data-label="Action"><span class="lt-text-amber"><?= htmlspecialchars($log['action_type']) ?></span></td>
|
||||
<td data-label="Entity" class="lt-text-xs"><?= htmlspecialchars($log['entity_type'] ?? '-') ?></td>
|
||||
<td data-label="Entity ID" class="lt-text-xs">
|
||||
<?php if ($log['entity_type'] === 'ticket' && $log['entity_id']): ?>
|
||||
<a href="/ticket/<?= htmlspecialchars($log['entity_id']) ?>"><?= htmlspecialchars($log['entity_id']) ?></a>
|
||||
<?php else: ?>
|
||||
<?= htmlspecialchars($log['entity_id'] ?? '-') ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
<td data-label="Details" class="lt-text-xs lt-text-muted" style="max-width:200px;overflow:hidden;text-overflow:ellipsis">
|
||||
<?php
|
||||
if ($log['details']) {
|
||||
$det = is_string($log['details']) ? json_decode($log['details'], true) : $log['details'];
|
||||
echo '<code>' . htmlspecialchars(is_array($det) ? json_encode($det) : (string)$log['details']) . '</code>';
|
||||
} else {
|
||||
echo '-';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td data-label="IP" class="lt-text-xs lt-text-muted"><?= htmlspecialchars($log['ip_address'] ?? '-') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; endif ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="ascii-frame-outer admin-container-wide">
|
||||
<span class="bottom-left-corner">╚</span>
|
||||
<span class="bottom-right-corner">╝</span>
|
||||
|
||||
<div class="ascii-section-header">Audit Log Browser</div>
|
||||
<div class="ascii-content">
|
||||
<div class="ascii-frame-inner">
|
||||
<!-- Filters -->
|
||||
<form method="GET" class="admin-form-row">
|
||||
<div class="admin-form-field">
|
||||
<label class="admin-label" for="action_type">Action Type</label>
|
||||
<select name="action_type" id="action_type" class="admin-input">
|
||||
<option value="">All Actions</option>
|
||||
<option value="create" <?php echo ($filters['action_type'] ?? '') === 'create' ? 'selected' : ''; ?>>Create</option>
|
||||
<option value="update" <?php echo ($filters['action_type'] ?? '') === 'update' ? 'selected' : ''; ?>>Update</option>
|
||||
<option value="delete" <?php echo ($filters['action_type'] ?? '') === 'delete' ? 'selected' : ''; ?>>Delete</option>
|
||||
<option value="comment" <?php echo ($filters['action_type'] ?? '') === 'comment' ? 'selected' : ''; ?>>Comment</option>
|
||||
<option value="assign" <?php echo ($filters['action_type'] ?? '') === 'assign' ? 'selected' : ''; ?>>Assign</option>
|
||||
<option value="status_change" <?php echo ($filters['action_type'] ?? '') === 'status_change' ? 'selected' : ''; ?>>Status Change</option>
|
||||
<option value="login" <?php echo ($filters['action_type'] ?? '') === 'login' ? 'selected' : ''; ?>>Login</option>
|
||||
<option value="security" <?php echo ($filters['action_type'] ?? '') === 'security' ? 'selected' : ''; ?>>Security</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="admin-form-field">
|
||||
<label class="admin-label" for="user_id">User</label>
|
||||
<select name="user_id" id="user_id" class="admin-input">
|
||||
<option value="">All Users</option>
|
||||
<?php if (isset($users)): foreach ($users as $user): ?>
|
||||
<option value="<?php echo $user['user_id']; ?>" <?php echo ($filters['user_id'] ?? '') == $user['user_id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($user['display_name'] ?? $user['username']); ?>
|
||||
</option>
|
||||
<?php endforeach; endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="admin-form-field">
|
||||
<label class="admin-label" for="date_from">Date From</label>
|
||||
<input type="date" name="date_from" id="date_from" value="<?php echo htmlspecialchars($filters['date_from'] ?? ''); ?>" class="admin-input">
|
||||
</div>
|
||||
<div class="admin-form-field">
|
||||
<label class="admin-label" for="date_to">Date To</label>
|
||||
<input type="date" name="date_to" id="date_to" value="<?php echo htmlspecialchars($filters['date_to'] ?? ''); ?>" class="admin-input">
|
||||
</div>
|
||||
<div class="admin-form-actions">
|
||||
<button type="submit" class="btn">FILTER</button>
|
||||
<a href="?" class="btn btn-secondary">RESET</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Log Table -->
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>User</th>
|
||||
<th>Action</th>
|
||||
<th>Entity</th>
|
||||
<th>Entity ID</th>
|
||||
<th>Details</th>
|
||||
<th>IP Address</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($auditLogs)): ?>
|
||||
<tr>
|
||||
<td colspan="7" class="empty-state">No audit log entries found.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($auditLogs as $log): ?>
|
||||
<tr>
|
||||
<td class="nowrap"><?php echo date('Y-m-d H:i:s', strtotime($log['created_at'])); ?></td>
|
||||
<td><?php echo htmlspecialchars($log['display_name'] ?? $log['username'] ?? 'System'); ?></td>
|
||||
<td>
|
||||
<span class="text-amber"><?php echo htmlspecialchars($log['action_type']); ?></span>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($log['entity_type'] ?? '-'); ?></td>
|
||||
<td>
|
||||
<?php if ($log['entity_type'] === 'ticket' && $log['entity_id']): ?>
|
||||
<a href="/ticket/<?php echo htmlspecialchars($log['entity_id']); ?>" class="text-green">
|
||||
<?php echo htmlspecialchars($log['entity_id']); ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<?php echo htmlspecialchars($log['entity_id'] ?? '-'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="td-truncate">
|
||||
<?php
|
||||
if ($log['details']) {
|
||||
$details = is_string($log['details']) ? json_decode($log['details'], true) : $log['details'];
|
||||
if (is_array($details)) {
|
||||
echo '<code>' . htmlspecialchars(json_encode($details)) . '</code>';
|
||||
} else {
|
||||
echo htmlspecialchars($log['details']);
|
||||
}
|
||||
} else {
|
||||
echo '-';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="nowrap text-sm"><?php echo htmlspecialchars($log['ip_address'] ?? '-'); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php
|
||||
$params = $_GET;
|
||||
for ($i = 1; $i <= min($totalPages, 10); $i++) {
|
||||
$params['page'] = $i;
|
||||
$activeClass = ($i == $page) ? 'active' : '';
|
||||
$url = htmlspecialchars('?' . http_build_query($params), ENT_QUOTES, 'UTF-8');
|
||||
echo "<a href='$url' class='btn btn-small $activeClass'>$i</a> ";
|
||||
}
|
||||
if ($totalPages > 10) {
|
||||
echo "...";
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
<?php if (($totalPages ?? 1) > 1): ?>
|
||||
<div class="lt-pagination" role="navigation">
|
||||
<?php
|
||||
$params = $_GET;
|
||||
for ($i = 1; $i <= min($totalPages, 10); $i++) {
|
||||
$params['page'] = $i;
|
||||
$url = htmlspecialchars('?' . http_build_query($params), ENT_QUOTES, 'UTF-8');
|
||||
$class = ($i == $page) ? ' lt-btn-primary' : '';
|
||||
echo "<a href='$url' class='lt-btn lt-btn-sm$class'>$i</a> ";
|
||||
}
|
||||
if ($totalPages > 10) echo '<span class="lt-text-muted lt-text-xs">…</span>';
|
||||
?>
|
||||
</div>
|
||||
<script nonce="<?php echo $nonce; ?>">if (window.lt) lt.keys.initDefaults();</script>
|
||||
</body>
|
||||
</html>
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . '/../../views/layout_footer.php'; ?>
|
||||
|
||||
Reference in New Issue
Block a user