75 lines
4.3 KiB
Handlebars
75 lines
4.3 KiB
Handlebars
<div class="page-header d-flex flex-wrap align-items-start gap-3">
|
|
<div>
|
|
<h2>Audit log</h2>
|
|
<p>Review recorded authentication, security, and session events.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card card-outline card-secondary" data-table-search-container data-table-pagination-card>
|
|
<div class="card-header">
|
|
<form method="get" action="/settings/audit-log" class="row g-2 align-items-end">
|
|
<div class="col-12 col-md-3">
|
|
<label class="form-label small" for="audit-category">Category</label>
|
|
<select id="audit-category" name="category" class="form-select form-select-sm">
|
|
<option value="">All categories</option>
|
|
{{#each categories}}<option value="{{this}}" {{#if (eq ../selectedCategory this)}}selected{{/if}}>{{this}}</option>{{/each}}
|
|
</select>
|
|
</div>
|
|
<div class="col-12 col-md-3">
|
|
<label class="form-label small" for="audit-event-type">Event type</label>
|
|
<input id="audit-event-type" name="event_type" class="form-control form-control-sm" value="{{selectedEventType}}" placeholder="e.g. login.success" list="audit-event-type-options" autocomplete="off">
|
|
<datalist id="audit-event-type-options">
|
|
{{#each eventTypes}}<option value="{{this}}"></option>{{/each}}
|
|
</datalist>
|
|
</div>
|
|
<div class="col-12 col-md-4">
|
|
<label class="form-label small" for="audit-search">Search</label>
|
|
<div class="input-group input-group-sm table-search-group">
|
|
<span class="input-group-text" role="button" tabindex="0" aria-label="Search" data-table-search-toggle><i class="bi bi-search"></i></span>
|
|
<input id="audit-search" name="search" type="search" class="form-control" value="{{search}}" placeholder="Event, actor, or target" data-table-search>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-md-2 d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary btn-sm flex-fill"><i class="bi bi-search me-1" aria-hidden="true"></i>Filter</button>
|
|
{{#if (hasPermission currentUser 'audit-log.allow')}}<a class="btn btn-outline-primary btn-sm flex-fill" href="{{exportUrl}}"><i class="bi bi-download me-1" aria-hidden="true"></i>Export</a>{{/if}}
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="card-body p-0 table-responsive">
|
|
<table class="table table-striped align-middle mb-0" data-table-searchable>
|
|
<thead><tr><th data-table-sort-key="time">Time</th><th data-table-sort-key="event">Event</th><th data-table-sort-key="actor">Actor</th><th data-table-sort-key="target">Target</th><th>Source</th><th>Details</th></tr></thead>
|
|
<tbody>
|
|
{{#if events.length}}
|
|
{{#each events}}
|
|
<tr data-table-search-row>
|
|
<td class="text-nowrap"><time data-local-datetime data-local-datetime-format="24h" datetime="{{occurredAtValue}}">{{occurredAtValue}}</time></td>
|
|
<td><div class="fw-semibold text-capitalize">{{eventLabel}}</div><div class="text-muted small">{{category}}</div></td>
|
|
<td>{{actorLabel}}</td>
|
|
<td>{{targetLabelDisplay}}</td>
|
|
<td><div>{{ip_address}}</div><div class="text-muted small text-break">{{userAgentLabel}}</div></td>
|
|
<td class="text-break">
|
|
{{#if auditDetailView.hasChanges}}
|
|
<div class="audit-change-list">
|
|
{{#each auditDetailView.changeRows}}
|
|
<div class="audit-change-row">
|
|
<code class="audit-change-path">{{path}}</code>
|
|
<span class="audit-change-from"><span class="visually-hidden">From: </span>{{from}}</span>
|
|
{{#if (eq direction "changed")}}<span class="audit-change-arrow" aria-hidden="true">→</span>{{else}}<span></span>{{/if}}
|
|
<span class="audit-change-to"><span class="visually-hidden">To: </span>{{to}}</span>
|
|
</div>
|
|
{{/each}}
|
|
</div>
|
|
{{else}}
|
|
<small>{{detailsDisplay}}</small>
|
|
{{/if}}
|
|
</td>
|
|
</tr>
|
|
{{/each}}
|
|
{{else}}
|
|
<tr data-table-search-empty-default><td colspan="6" class="empty">No audit events match these filters.</td></tr>
|
|
{{/if}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{> table-pagination pagination=pagination basePath="/settings/audit-log" alwaysShow=true}}
|
|
</div> |