bot_host / templates /admin_audit.html
ItsBounvy's picture
Upload 21 files
4272701 verified
Raw History Blame Contribute Delete
4.93 kB
{% extends "base.html" %}
{% block title %}{{ _("Audit log") }}{% endblock %}
{% block content %}
<div class="page-header">
<div>
<h1>{{ _("Audit log") }}</h1>
<div class="subtitle">{{ _("Last") }} {{ logs|length }} {{ ngettext("event", "events", logs|length, count=logs|length) }}.</div>
</div>
</div>
<form class="filters" method="GET" action="/admin/audit">
<div class="form-group">
<label for="user_id">{{ _("User") }}</label>
<select id="user_id" name="user_id">
<option value="">{{ _("All users") }}</option>
{% for u in users_in_logs %}
<option value="{{ u.id }}" {% if filters.user_id == u.id %}selected{% endif %}>{{ u.username }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="action">{{ _("Action") }}</label>
<select id="action" name="action">
<option value="">{{ _("All actions") }}</option>
{% for a in actions_list %}
<option value="{{ a }}" {% if filters.action == a %}selected{% endif %}>{{ a }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="target_type">{{ _("Target") }}</label>
<select id="target_type" name="target_type">
<option value="">{{ _("All targets") }}</option>
{% for t in targets_list %}
<option value="{{ t }}" {% if filters.target_type == t %}selected{% endif %}>{{ t }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="q">{{ _("Search") }}</label>
<input type="search" id="q" name="q" value="{{ filters.q }}" placeholder="{{ _("ip, details, action…") }}">
</div>
<div class="form-group" style="display: flex; gap: 8px; align-self: end;">
<button type="submit" class="btn btn-primary">{{ panel_icon('filter')|safe }} {{ _("Filter") }}</button>
<a href="/admin/audit" class="btn btn-ghost">{{ _("Reset") }}</a>
</div>
</form>
<div class="card flush">
<div class="table-wrap" style="border: 0; border-radius: 0;">
<table class="table">
<thead>
<tr>
<th>{{ _("When") }}</th>
<th>{{ _("User") }}</th>
<th>{{ _("Action") }}</th>
<th>{{ _("Target") }}</th>
<th>{{ _("Details") }}</th>
<th>{{ _("IP") }}</th>
</tr>
</thead>
<tbody>
{% for log in logs %}
<tr>
<td class="mono" style="font-size: 12px; white-space: nowrap;" data-time="{{ log.created_at.isoformat() if log.created_at else '' }}" title="{{ log.created_at.isoformat() if log.created_at else '' }}">{{ log.created_at.strftime('%Y-%m-%d %H:%M:%S') if log.created_at else '—' }}</td>
<td>
{% if log.user %}
<a href="/admin/audit?user_id={{ log.user.id }}">{{ log.user.username }}</a>
{% else %}
<span class="muted">{{ _("system") }}</span>
{% endif %}
</td>
<td><span class="badge" style="background: var(--surface-2); color: var(--text); border: 1px solid var(--border);"><code style="background: transparent; padding: 0;">{{ log.action }}</code></span></td>
<td>
{% if log.target_type and log.target_id %}
<a href="/admin/audit?target_type={{ log.target_type }}">{{ log.target_type }} <span class="muted">#{{ log.target_id }}</span></a>
{% else %}—{% endif %}
</td>
<td>
{% if log.details_json %}
<details>
<summary style="cursor: pointer; color: var(--text-muted); font-size: 12px; max-width: 380px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{{ log.details_json[:80] }}{% if log.details_json|length > 80 %}…{% endif %}</summary>
<pre class="mono" style="margin-top: 6px; font-size: 12px; max-width: 380px;">{{ log.details_json }}</pre>
</details>
{% else %}<span class="muted">—</span>{% endif %}
</td>
<td class="mono" style="font-size: 12px;">{{ log.ip_address or '—' }}</td>
</tr>
{% endfor %}
{% if not logs %}
<tr><td colspan="6">
<div class="empty-state" style="padding: 36px 12px;">
<div class="ico">{{ panel_icon('audit')|safe }}</div>
<h3>{{ _("No matching events") }}</h3>
<p>{{ _("Try a different filter combination.") }}</p>
</div>
</td></tr>
{% endif %}
</tbody>
</table>
</div>
</div>
{% endblock %}