/* Brain of Reese — Tokens view (access tokens, phase 79 task 06; * the phase-76 fold pattern: shell view module). * * TODO.md L5 (owner 2026-09-06): "…api tokens that the admin can * generate and hand out so people can log in to use the app." * * Wires the admin-only token endpoints (phase 79 task 02) into the * view: * * • the create row (name + Generate): a BLANK / whitespace-only * name is REFUSED client-side (phase 101 D3) — the live region * reads `Give the token a name first.`, the name input re-focuses, * and NO request is sent (the server's 422 on a blank/over-long * label is defense in depth; the old blank-label "token" * fallback is GONE). On a named generate: POST /api/tokens → 201 — the ONE * response that carries the plaintext (owner-locked A4) — and the * plaintext appears EXACTLY ONCE: in the #token-once block's mono * read-only field, with a Copy (the clipboard; a non-secure http * origin that rejects it gets the inline fallback — the field * selects itself for Ctrl/Cmd+C). The block hides on the NEXT * loadTokens() / re-show (and the field is wiped with it) — the * plaintext is NOT stored anywhere client-side (no localStorage, * no data attribute), so a re-render can never re-show it; * • the SPLIT tables (phase 101 D1 — AGENTS.md rule 5, full width, * no skinny list): the ACTIVE table on top (Label | Created | * Last used | Actions — the two-step inline Regenerate BEFORE * the two-step inline Revoke — phase 101 task 03 / D2) and the * REVOKED table below * it (Label | Created | Last used | Revoked — the revoked_at * date). The Status column is GONE from both: the table's * position IS the status (an all-active table needs no status; a * row in the revoked table is a dead token — no actions, nothing * left to revoke). The revoked SECTION (heading + search + table * wrap) is hidden while no token is revoked (an empty table is * noise); the active table keeps its empty-state row; * • the per-table LIVE label search (phase 101 D4): one type=search * input per table — a case-insensitive SUBSTRING over the * rendered rows' label cells, applied on `input` with NO fetch * (each data row toggles its `hidden`), and RE-APPLIED after * every loadTokens() (the queries live in module state — * activeQuery / revokedQuery — and survive re-renders / re-shows, * the phase-77 contract). Zero visible matches with a non-empty * query → the per-table no-match row (`No tokens match * "".` — textContent, the distinct-from-empty-state * language); an empty query shows every row; * • the one-click REGENERATE (phase 101 task 03, D2 — rotation, * atomic): every ACTIVE row carries a Regenerate button BEFORE * its Revoke (the primary lifecycle action — ONE button starts * it). The control is a structural mirror of the Revoke control: * the first click swaps the button, in place, to the house * two-step confirm (`Regenerate? The current token is revoked. * [Yes] [No]` — the history-confirm-* classes, focus to Yes), * and it owns its OWN .tokens-actions wrapper span, so a confirm * in it never clobbers the Revoke control's. Yes → POST * /api/tokens//regenerate (JSON, NO body) — the server * rotates in ONE transaction: the old row is stamped revoked (it * lands in the revoked table) and the successor is created under * the SAME label (it lands in the active table); the 201 body * ({ id, label, token, created_at }) is the new token's ONLY * plaintext moment (A4). On 201 the re-entrant loadTokens() runs * FIRST (the relocation), THEN the shown-once block reveals the * NEW plaintext — the SAME #token-once block, the value-only * contract (the plaintext lives in the field's value, never a * data attribute) — and the live region reads `Regenerated * "