forked from UKSOURCE/cms.hailearning.edu.vn
162 lines
7.6 KiB
Plaintext
162 lines
7.6 KiB
Plaintext
<!-- Page Header -->
|
|
<div class="page-title-area">
|
|
<div>
|
|
<h1>Audit Log Details</h1>
|
|
<p class="subtitle">Detailed activity record</p>
|
|
</div>
|
|
<a href="/admin/audit-logs" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left"></i> Back
|
|
</a>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
|
|
<!-- Main Info -->
|
|
<div class="col-lg-8">
|
|
<div class="card border-0 mb-3">
|
|
<div class="card-header">
|
|
<h5 class="card-header-title"><i class="fas fa-info-circle"></i> Audit Information</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<div class="form-label">Model</div>
|
|
<span class="badge badge-soft-primary" style="font-size:0.8rem"><%= auditLog.model %></span>
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="form-label">Action</div>
|
|
<%
|
|
let badgeClass = 'badge-soft-primary';
|
|
if (auditLog.action.includes('CREATE')) badgeClass = 'bg-soft-success';
|
|
else if (auditLog.action.includes('UPDATE')) badgeClass = 'bg-soft-warning';
|
|
else if (auditLog.action.includes('DELETE')) badgeClass = 'bg-soft-danger';
|
|
%>
|
|
<span class="badge <%= badgeClass %>" style="font-size:0.8rem"><%= auditLog.action %></span>
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="form-label">Document ID</div>
|
|
<code style="font-size:0.8rem;color:var(--primary-color)"><%= auditLog.documentId %></code>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<div class="form-label">Date & Time</div>
|
|
<div style="font-size:var(--font-size-sm)">
|
|
<%= new Date(auditLog.createdAt).toLocaleDateString('en-GB') %>
|
|
<span style="color:var(--text-muted)"><%= new Date(auditLog.createdAt).toLocaleTimeString() %></span>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="form-label">Performed By</div>
|
|
<% if (auditLog.performedBy) { %>
|
|
<div style="font-weight:500;font-size:var(--font-size-sm)"><%= auditLog.performedBy.username %></div>
|
|
<div style="font-size:var(--font-size-xs);color:var(--text-muted)"><%= auditLog.performedBy.email %></div>
|
|
<% } else { %>
|
|
<span style="color:var(--text-muted);font-size:var(--font-size-sm)">System</span>
|
|
<% } %>
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="form-label">IP Address</div>
|
|
<code style="font-size:0.8rem;color:var(--text-muted)"><%= auditLog.ipAddress %></code>
|
|
</div>
|
|
</div>
|
|
<% if (auditLog.userAgent) { %>
|
|
<div class="col-12">
|
|
<div class="form-label">User Agent</div>
|
|
<div style="font-size:0.75rem;color:var(--text-muted);font-family:monospace;word-break:break-all"><%= auditLog.userAgent %></div>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Field Changes -->
|
|
<% if (auditLog.changes && auditLog.changes.length > 0) { %>
|
|
<div class="card border-0">
|
|
<div class="card-header">
|
|
<h5 class="card-header-title"><i class="fas fa-pen"></i> Field Changes</h5>
|
|
<span class="badge badge-soft-accent"><%= auditLog.changes.length %> field<%= auditLog.changes.length > 1 ? 's' : '' %></span>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<% if (user && (user.role === 'admin' || user.role === 'superadmin')) { %>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th style="width:160px">Field</th>
|
|
<th>Before</th>
|
|
<th>After</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% auditLog.changes.forEach(change => { %>
|
|
<tr>
|
|
<td style="font-weight:500;font-size:var(--font-size-sm)"><%= change.field %></td>
|
|
<td>
|
|
<div style="background:var(--danger-soft);border-left:3px solid var(--danger-color);padding:0.4rem 0.6rem;border-radius:0 var(--border-radius-sm) var(--border-radius-sm) 0;font-size:0.8rem;word-break:break-all;">
|
|
<% if (change.before === null || change.before === undefined) { %>
|
|
<em style="color:var(--text-muted)">null</em>
|
|
<% } else if (typeof change.before === 'object') { %>
|
|
<pre style="margin:0;font-size:0.75rem;max-height:100px;overflow:auto"><%= JSON.stringify(change.before, null, 2) %></pre>
|
|
<% } else { %>
|
|
<%= change.before %>
|
|
<% } %>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div style="background:var(--success-soft);border-left:3px solid var(--success-color);padding:0.4rem 0.6rem;border-radius:0 var(--border-radius-sm) var(--border-radius-sm) 0;font-size:0.8rem;word-break:break-all;">
|
|
<% if (change.after === null || change.after === undefined) { %>
|
|
<em style="color:var(--text-muted)">null</em>
|
|
<% } else if (typeof change.after === 'object') { %>
|
|
<pre style="margin:0;font-size:0.75rem;max-height:100px;overflow:auto"><%= JSON.stringify(change.after, null, 2) %></pre>
|
|
<% } else { %>
|
|
<%= change.after %>
|
|
<% } %>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<% }); %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% } else { %>
|
|
<div class="p-3">
|
|
<div class="alert d-flex gap-2 align-items-center" style="background:var(--info-soft);border:1px solid rgba(14,116,144,0.15);border-radius:var(--border-radius-sm);padding:0.75rem;">
|
|
<i class="fas fa-info-circle" style="color:var(--info-color)"></i>
|
|
<span style="font-size:var(--font-size-sm)">Detailed field values are restricted to administrators.</span>
|
|
</div>
|
|
<% auditLog.changes.forEach(change => { %>
|
|
<div style="display:flex;align-items:center;gap:0.5rem;padding:0.4rem 0;border-bottom:1px solid var(--border-light);">
|
|
<span style="font-weight:500;font-size:var(--font-size-sm)"><%= change.field %></span>
|
|
<span class="badge bg-soft-info">Modified</span>
|
|
</div>
|
|
<% }); %>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
|
|
<!-- Sidebar summary -->
|
|
<div class="col-lg-4">
|
|
<div class="card border-0">
|
|
<div class="card-header">
|
|
<h5 class="card-header-title"><i class="fas fa-chart-bar"></i> Summary</h5>
|
|
</div>
|
|
<div class="card-body d-flex flex-column gap-2">
|
|
<div class="stat-card primary">
|
|
<div class="stat-card-value"><%= auditLog.changes ? auditLog.changes.length : 0 %></div>
|
|
<div class="stat-card-label">Fields Changed</div>
|
|
</div>
|
|
<div class="stat-card accent">
|
|
<div class="stat-card-value" style="font-size:1.25rem"><%= new Date(auditLog.createdAt).toLocaleDateString('en-GB') === new Date().toLocaleDateString('en-GB') ? 'Today' : 'Past' %></div>
|
|
<div class="stat-card-label">Timing</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|