feat(admin): data topics — trash split, audit grid, spaces inventory #328

Merged
Cordy merged 9 commits from feat/admin-data into main 2026-08-27 17:23:43 +00:00
Owner

Admin redesign, slice C of four.

Deleted files — eligibility becomes visible

The purge list encoded "can this be purged?" only as a disabled button, so a legally held file looked identical to a purgeable one. The list now splits into Eligible now — N and Protected — N, each protected row carrying its reason as a hold chip (Legal hold / Keep until <date>) on a sunk plate, and offering "Protected" rather than a dead Purge button. "Purge all eligible" then acts on a set you can actually see.

The API already returns eligible, hold and keepUntil per item — I checked before designing, so no backend change was needed.

Audit log — a grid, not sentences

fmtEvt() concatenated action + path + dest into one string, so the axis you scan (what happened) sat mid-sentence and nothing aligned. Now a five-column grid: time / actor / action / path / outcome, with → dest appended inside the path cell. Destructive actions (delete, manual-purge, auto-purge, revoke) are tinted; everything else shares one neutral plate — six tints would be decoration. Failed events keep the danger row tint and surface result as a chip.

  • An action filter is added, using the action query parameter the purge log already relies on — so it's a filter the server genuinely supports, plus a Reset.
  • The 200 cap is stated: "N shown · the server returns at most 200 — narrow the range to see the rest." The endpoint returns no total, so this reports what came back and what the ceiling is rather than inventing an "N of M" it cannot know.
  • The filter bar is flex, not grid, deliberately: repeat(auto-fit, …) cannot be combined with an intrinsic track, so the obvious grid declaration would be dropped whole and the bar would silently collapse to one column per field.

Spaces — an inventory instead of a sentence

loadSpaces() rendered a single hint paragraph. Creation and membership do live in the file browser, but it doesn't follow that the admin page shows nothing: a deactivated space is invisible in normal browsing and still holds storage, which is precisely an administrator's problem. Now a table of every space with members, size and state; deactivated rows are dimmed with an outlined chip (a plain off chip is muted-on-sunk, which loses its plate on a dimmed row) and a panel says how they behave.

Written defensively against field-name variation (name|space, members|memberCount, size|bytes, active|state|deactivated) and degrades to exactly today's behaviour — the hint alone — if /api/v1/spaces is unavailable or empty. No row actions: deactivate/reactivate/delete belong with a confirmed API, not a guess.

Verification

node --check on all script blocks; nine anchored splices at count=1. I also ran a full i18n key audit across the file (465 defined, 251 used) — it caught ownerLbl as undefined, which would have rendered the key verbatim in the spaces list, and it's now defined in all four languages. Worth keeping that check around.

Operator check: Administration → Deleted files → Manual purge; → Audit log (filter by action, confirm the cap line); → Spaces.

Admin redesign, slice C of four. ## Deleted files — eligibility becomes visible The purge list encoded "can this be purged?" **only** as a disabled button, so a legally held file looked identical to a purgeable one. The list now splits into **Eligible now — N** and **Protected — N**, each protected row carrying its reason as a hold chip (`Legal hold` / `Keep until <date>`) on a sunk plate, and offering "Protected" rather than a dead Purge button. "Purge all eligible" then acts on a set you can actually see. The API already returns `eligible`, `hold` and `keepUntil` per item — I checked before designing, so **no backend change was needed**. ## Audit log — a grid, not sentences `fmtEvt()` concatenated action + path + dest into one string, so the axis you scan (*what happened*) sat mid-sentence and nothing aligned. Now a five-column grid: time / actor / action / path / outcome, with `→ dest` appended inside the path cell. Destructive actions (`delete`, `manual-purge`, `auto-purge`, `revoke`) are tinted; everything else shares one neutral plate — six tints would be decoration. Failed events keep the danger row tint and surface `result` as a chip. - **An action filter** is added, using the `action` query parameter the purge log already relies on — so it's a filter the server genuinely supports, plus a Reset. - **The 200 cap is stated**: "N shown · the server returns at most 200 — narrow the range to see the rest." The endpoint returns no total, so this reports what came back and what the ceiling is rather than inventing an "N of M" it cannot know. - The filter bar is flex, not grid, deliberately: `repeat(auto-fit, …)` cannot be combined with an intrinsic track, so the obvious grid declaration would be dropped whole and the bar would silently collapse to one column per field. ## Spaces — an inventory instead of a sentence `loadSpaces()` rendered a single hint paragraph. Creation and membership do live in the file browser, but it doesn't follow that the admin page shows nothing: a **deactivated space is invisible in normal browsing and still holds storage**, which is precisely an administrator's problem. Now a table of every space with members, size and state; deactivated rows are dimmed with an outlined chip (a plain `off` chip is muted-on-sunk, which loses its plate on a dimmed row) and a panel says how they behave. Written defensively against field-name variation (`name|space`, `members|memberCount`, `size|bytes`, `active|state|deactivated`) and **degrades to exactly today's behaviour** — the hint alone — if `/api/v1/spaces` is unavailable or empty. No row actions: deactivate/reactivate/delete belong with a confirmed API, not a guess. ## Verification `node --check` on all script blocks; nine anchored splices at count=1. I also ran a **full i18n key audit** across the file (465 defined, 251 used) — it caught `ownerLbl` as undefined, which would have rendered the key verbatim in the spaces list, and it's now defined in all four languages. Worth keeping that check around. Operator check: Administration → Deleted files → Manual purge; → Audit log (filter by action, confirm the cap line); → Spaces.
Cordy merged commit 3fe532807f into main 2026-08-27 17:23:43 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#328
No description provided.