fix(admin): fix audit log rows overflowing off-screen

flex-wrap with long IDs/IPs pushed content past the viewport edge instead
of wrapping. Switched to a fixed-column grid with truncation + title
tooltips, wrapped in a horizontal-scroll container so the whole table
scrolls as a unit on narrow screens instead of individual cells clipping.
This commit is contained in:
admin committed 2026-08-12 09:09:34 +02:00
1 parent e099763211
commit 3ea668a137
1 file changed
+58 -33
+58 -33
View File
@@ -117,41 +117,66 @@ export default function AdminAuditLogPage() {
<p className="text-sm text-zinc-500 text-center py-12">No entries match these filters</p>
) : (
<div className="space-y-2">
{entries.map((entry) => (
<div
key={entry.id}
className="flex flex-wrap items-center gap-x-4 gap-y-1 rounded-xl border border-zinc-800 bg-zinc-900 px-4 py-3"
>
<Badge variant="secondary" className="text-[10px] shrink-0">
{entry.action}
</Badge>
<p className="text-xs text-zinc-500 shrink-0">
{entry.targetType} · <span className="font-mono">{entry.targetId.slice(0, 16)}…</span>
</p>
<div className="flex-1 min-w-[10rem]">
<p className="text-sm text-zinc-200 truncate">
{entry.moderatorName ?? <span className="text-zinc-500">unnamed</span>}
{entry.moderatorRole && (
<Badge
className={`ml-2 text-[10px] ${
ROLE_BADGE_CLASS[entry.moderatorRole] ?? "bg-zinc-700 text-zinc-200"
}`}
>
{entry.moderatorRole}
</Badge>
)}
</p>
<p className="text-xs text-zinc-600 font-mono truncate">{entry.moderatorId}</p>
{/* Fixed-width grid columns instead of flex-wrap — long IDs/IPs used
to force rows to overflow the viewport instead of wrapping. The
outer scroll wrapper lets the whole table scroll as one unit on
narrow screens rather than clipping individual cells. */}
<div className="overflow-x-auto rounded-xl border border-zinc-800">
<div className="min-w-[1000px]">
<div className="grid grid-cols-[150px_190px_1fr_130px_170px] gap-3 border-b border-zinc-800 bg-zinc-900/80 px-4 py-2 text-[11px] font-semibold uppercase tracking-wide text-zinc-500">
<span>Action</span>
<span>Target</span>
<span>Moderator</span>
<span>IP</span>
<span>Time</span>
</div>
<p className="text-xs text-zinc-500 font-mono shrink-0">{entry.ipAddress ?? "—"}</p>
<p className="text-xs text-zinc-600 shrink-0">
{new Date(entry.createdAt).toLocaleString()}
</p>
{entry.reason && (
<p className="w-full text-xs text-zinc-400 truncate">Reason: {entry.reason}</p>
)}
{entries.map((entry) => (
<div key={entry.id} className="border-b border-zinc-800 bg-zinc-900 last:border-b-0">
<div className="grid grid-cols-[150px_190px_1fr_130px_170px] items-center gap-3 px-4 py-3">
<Badge variant="secondary" className="w-fit text-[10px]">
{entry.action}
</Badge>
<p className="min-w-0 truncate text-xs text-zinc-500" title={entry.targetId}>
{entry.targetType} · <span className="font-mono">{entry.targetId}</span>
</p>
<div className="min-w-0">
<p className="flex items-center gap-2 truncate text-sm text-zinc-200">
<span className="truncate">
{entry.moderatorName ?? <span className="text-zinc-500">unnamed</span>}
</span>
{entry.moderatorRole && (
<Badge
className={`shrink-0 text-[10px] ${
ROLE_BADGE_CLASS[entry.moderatorRole] ?? "bg-zinc-700 text-zinc-200"
}`}
>
{entry.moderatorRole}
</Badge>
)}
</p>
<p
className="truncate font-mono text-xs text-zinc-600"
title={entry.moderatorId}
>
{entry.moderatorId}
</p>
</div>
<p className="truncate font-mono text-xs text-zinc-500">
{entry.ipAddress ?? "—"}
</p>
<p className="truncate text-xs text-zinc-600">
{new Date(entry.createdAt).toLocaleString()}
</p>
</div>
{entry.reason && (
<p className="truncate px-4 pb-3 text-xs text-zinc-400">
Reason: {entry.reason}
</p>
)}
</div>
))}
</div>
))}
</div>
{hasNextPage && (
<div className="flex justify-center pt-2">