Files
IT_Ticket_System/app/templates/admin/activity_logs.html
T
2026-05-22 11:53:41 -04:00

186 lines
8.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Activity Logs{% endblock %}
{% block page_title %}Activity Logs{% endblock %}
{% block content %}
<!-- ── Stats + Cleanup panel ───────────────────────────────────────────────── -->
<div class="row g-3 mb-3">
<!-- Summary -->
<div class="col-lg-4">
<div class="card h-100">
<div class="card-header"><i class="bi bi-bar-chart me-2"></i>Log Summary</div>
<div class="card-body">
<div style="font-size:28px;font-weight:700;color:var(--text);">{{ '{:,}'.format(total) }}</div>
<div style="font-size:13px;color:var(--muted);margin-bottom:12px;">total log entries</div>
{% if oldest %}
<div style="font-size:12px;color:var(--muted);">
<i class="bi bi-calendar3 me-1"></i>Oldest entry:
<span style="color:var(--text);">{{ oldest.strftime('%b %d, %Y') }}</span>
</div>
{% endif %}
<hr style="border-color:var(--border);margin:12px 0;">
<div style="font-size:12px;color:var(--muted);">Entries eligible for cleanup:</div>
<div class="mt-2" style="font-size:13px;">
{% for days, count in counts_by_retention.items() %}
<div class="d-flex justify-content-between align-items-center py-1"
style="border-bottom:1px solid var(--border);">
<span style="color:var(--muted);">Older than {{ days }} days</span>
<span style="font-weight:600;color:{% if count > 0 %}var(--warning){% else %}var(--success){% endif %};">
{{ '{:,}'.format(count) }}
</span>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Cleanup -->
<div class="col-lg-8">
<div class="card h-100">
<div class="card-header d-flex align-items-center gap-2">
<i class="bi bi-trash3 me-1"></i>Clean Up Old Logs
<span style="font-size:11px;color:var(--muted);font-weight:400;">— permanently deletes entries older than the selected threshold</span>
</div>
<div class="card-body">
<p style="font-size:13px;color:var(--muted);margin-bottom:16px;">
Select a retention period. All activity log entries older than that threshold will be
<strong style="color:var(--danger);">permanently deleted</strong> and cannot be recovered.
This action is itself logged before the deletion runs.
</p>
<div class="row g-3">
{% set options = [
(7, 'danger', 'bi-lightning-charge', 'Last 7 days', 'Aggressive — keeps only the past week'),
(30, 'warning', 'bi-calendar-week', 'Last 30 days', 'Recommended for busy systems'),
(60, 'info', 'bi-calendar-month', 'Last 60 days', 'Balanced retention'),
(90, 'success', 'bi-calendar3', 'Last 90 days', 'Conservative — keeps 3 months'),
] %}
{% for days, colour, icon, label, hint in options %}
<div class="col-6 col-lg-3">
<form method="POST" action="{{ url_for('admin.activity_logs') }}"
onsubmit="return confirmCleanup(this, {{ days }}, {{ counts_by_retention[days] }})">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<input type="hidden" name="days" value="{{ days }}"/>
<button type="submit" class="btn btn-sm w-100 d-flex flex-column align-items-center py-3 gap-1"
style="background:rgba(var(--{{ colour }}-rgb, 100,100,100),.08);
border:1px solid rgba(var(--{{ colour }}-rgb, 100,100,100),.25);
color:var(--{{ colour }});"
{% if counts_by_retention[days] == 0 %}disabled title="No entries to delete"{% endif %}>
<i class="bi {{ icon }}" style="font-size:20px;"></i>
<span style="font-size:13px;font-weight:600;">{{ label }}</span>
<span style="font-size:11px;opacity:.75;">
{{ '{:,}'.format(counts_by_retention[days]) }} to delete
</span>
<span style="font-size:10px;opacity:.6;text-align:center;line-height:1.3;">{{ hint }}</span>
</button>
</form>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<!-- ── Log table ────────────────────────────────────────────────────────────── -->
<div class="card">
<div class="card-header">
<i class="bi bi-list-ul me-2"></i>System Activity Log
<span style="font-size:12px;color:var(--muted);">
— page {{ logs.page }} of {{ logs.pages }} ({{ '{:,}'.format(logs.total) }} entries)
</span>
</div>
<div class="card-body p-0">
<table class="table mb-0">
<thead>
<tr>
<th>Timestamp</th>
<th>Action</th>
<th>User</th>
<th>Entity</th>
<th>Details</th>
<th>IP Address</th>
</tr>
</thead>
<tbody>
{% for log in logs.items %}
<tr>
<td style="font-size:11px;color:var(--muted);font-family:'Space Mono',monospace;white-space:nowrap;">
{{ log.created_at.strftime('%Y-%m-%d %H:%M:%S') }}
</td>
<td>
<span class="mono" style="font-size:11px;
color:{% if 'create' in log.action %}var(--success)
{% elif 'delete' in log.action or 'deactivate' in log.action %}var(--danger)
{% elif 'update' in log.action or 'edit' in log.action or 'change' in log.action %}var(--warning)
{% elif 'login' in log.action %}var(--accent3)
{% elif 'cleanup' in log.action %}var(--danger)
{% else %}var(--muted){% endif %};">
{{ log.action }}
</span>
</td>
<td style="font-size:13px;">
{% if log.user %}
{{ log.user.full_name }}<br>
<span style="font-size:11px;color:var(--muted);">{{ log.user.email }}</span>
{% else %}
<span style="color:var(--muted);">System</span>
{% endif %}
</td>
<td style="font-size:12px;color:var(--muted);">
{{ log.entity_type or '—' }}{% if log.entity_id %} <span class="mono">#{{ log.entity_id }}</span>{% endif %}
</td>
<td style="font-size:12px;color:var(--muted);max-width:250px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"
title="{{ log.details or '' }}">
{{ log.details or '—' }}
</td>
<td style="font-size:11px;color:var(--muted);font-family:'Space Mono',monospace;">
{{ log.ip_address or '—' }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if logs.pages > 1 %}
<div class="d-flex justify-content-center py-3">
<nav><ul class="pagination mb-0">
{% if logs.has_prev %}
<li class="page-item"><a class="page-link" href="{{ url_for('admin.activity_logs', page=logs.prev_num) }}"> Prev</a></li>
{% endif %}
{% for p in logs.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %}
{% if p %}
<li class="page-item {% if p==logs.page %}active{% endif %}">
<a class="page-link" href="{{ url_for('admin.activity_logs', page=p) }}">{{ p }}</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link"></span></li>
{% endif %}
{% endfor %}
{% if logs.has_next %}
<li class="page-item"><a class="page-link" href="{{ url_for('admin.activity_logs', page=logs.next_num) }}">Next </a></li>
{% endif %}
</ul></nav>
</div>
{% endif %}
</div>
</div>
<script>
function confirmCleanup(form, days, count) {
if (count === 0) return false;
confirmModal(
'Clean Up Activity Logs',
'Delete ' + count.toLocaleString() + ' log entr' + (count === 1 ? 'y' : 'ies') +
' older than ' + days + ' days? This action cannot be undone.',
'Delete Logs',
'btn-danger',
() => { form._confirmed = true; form.submit(); }
);
return false;
}
</script>
{% endblock %}