Fit the audit-log table; drop the collector token preset button
All checks were successful
CI / backend (push) Successful in 1m20s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s

Audit Logs now uses a fixed table layout with tuned column widths:
every column fits the card without horizontal scrolling, long entity
names truncate with a hover tooltip, timestamps show a compact
no-seconds form (full value on hover), and the 9-digit user SSO renders
fully.

Removed the Collector service token quick-preset from the create modal
per user preference - the collector.ingest checkbox in the scope grid
is the path now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-12 09:57:02 -04:00
parent 12da0429b0
commit 1c5128a5c8
2 changed files with 31 additions and 43 deletions

View File

@@ -125,18 +125,6 @@
<small class="form-hint">Leave blank for a token that never expires.</small>
</div>
<div v-if="canCollectorPreset" class="form-group preset-group">
<button type="button" class="btn btn-secondary btn-sm"
@click="applyCollectorPreset">
Collector service token
</button>
<small class="form-hint">
For GE-Enforce / fleet reporting. Pre-selects only
<code>collector.ingest</code>; the token works only on the
collector API and nothing else.
</small>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" v-model="form.restrict" />
@@ -320,17 +308,6 @@ const availableGrouped = computed(() => {
return result
})
// The collector preset is offered only when the caller can actually mint a
// collector.ingest token (admins hold everything; others must hold the perm).
const COLLECTOR_SCOPE = 'collector.ingest'
const canCollectorPreset = computed(
() => isAdmin.value || myPermissions.value.includes(COLLECTOR_SCOPE))
function applyCollectorPreset() {
form.value.restrict = true
form.value.scopes = [COLLECTOR_SCOPE]
}
onMounted(() => loadData())
async function loadData() {
@@ -522,17 +499,6 @@ async function revokeToken() {
color: var(--text-light);
margin-top: 0.25rem;
}
.preset-group {
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg);
}
.preset-group code {
background: var(--bg-card);
padding: 0.1rem 0.3rem;
border-radius: 3px;
}
.secret-warning {
color: var(--danger);
margin-bottom: 1rem;

View File

@@ -27,13 +27,13 @@
<table>
<thead>
<tr>
<th style="width: 160px">Timestamp</th>
<th style="width: 100px">Action</th>
<th style="width: 100px">Entity</th>
<th style="width: 180px">Timestamp</th>
<th style="width: 90px">Action</th>
<th style="width: 110px">Entity</th>
<th>Name/ID</th>
<th style="width: 120px">User</th>
<th style="width: 130px">IP Address</th>
<th>Changes</th>
<th style="width: 118px">User</th>
<th style="width: 108px">IP Address</th>
<th style="width: 80px">Changes</th>
</tr>
</thead>
<tbody>
@@ -44,14 +44,14 @@
<td colspan="7" class="empty">No audit logs found</td>
</tr>
<tr v-for="log in logs" :key="log.auditlogid">
<td class="timestamp">{{ formatDate(log.timestamp) }}</td>
<td class="timestamp" :title="formatDateFull(log.timestamp)">{{ formatDate(log.timestamp) }}</td>
<td>
<span class="badge" :class="actionClass(log.action)">
{{ log.action }}
</span>
</td>
<td>{{ log.entitytype }}</td>
<td>
<td class="name-cell" :title="log.entityname || `#${log.entityid}`">
<router-link
v-if="getEntityLink(log)"
:to="getEntityLink(log)"
@@ -165,7 +165,16 @@ async function loadLogs() {
function formatDate(isoString) {
if (!isoString) return '-'
const d = new Date(isoString)
return d.toLocaleString()
// compact for the fixed-width column; the cell title carries the full form
return d.toLocaleString(undefined, {
year: 'numeric', month: 'numeric', day: 'numeric',
hour: 'numeric', minute: '2-digit'
})
}
function formatDateFull(isoString) {
if (!isoString) return ''
return new Date(isoString).toLocaleString()
}
function actionClass(action) {
@@ -271,6 +280,19 @@ onMounted(loadLogs)
background: var(--primary-dark);
}
.table-container > table {
table-layout: fixed;
width: 100%;
}
.table-container > table td {
overflow: hidden;
text-overflow: ellipsis;
}
.name-cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.no-changes {
color: var(--text-light);
}