common.js + flow.js + index.html + flow.html: cookie scrub + doc pointers (#712 batch 13 cont.)

Final dashboard frontend cleanup. Four files at 0 cookies each.

common.js (11 → 0):
- #406 module-split history → drop, present-state intro
- #448 SharedWorker SSE pipe (×3) → docs/web-ui.md SSE multiplexing
  paragraph pointer
- #515 worker-death self-heal (×3) → docs pointer + brief inline
- #453 bfcache argus-nit (×2) → drop framing, keep inline why
- #451 drag-to-resize → docs/web-ui.md::Side panel pointer
- #233 marked autolinks new-tab → drop cookie

flow.js (8 → 0):
- #406 module-split history → drop
- #389 banner-in-footer → drop framing
- #375 stacking context → docs/web-ui.md::Per-agent page Terminal-wrap
- #408 server-side filter, #499 backend allow-list → drop cookies,
  keep inline why
- #448 SharedWorker per-URL keying → docs pointer
- #163 SSE catchup drift → drop cookie, keep inline why

index.html (13 → 0):
- #389 chrome history → drop
- #459 schedules, #607 matrix, #609 nginx-front, #15 → drop cookies,
  keep functional comments + docs/web-ui.md::Tab strip + gateway.md
  pointers for matrix
- #385 dropped C0NTAINERS heading → drop framing
- #460 reminders-moved-here → drop framing
- #444 SchedulesChanged SSE absence → drop cookie, keep inline why
- #443 selection bar → docs/web-ui.md::Selection bar pointer
- #564 fold-create-into-table → drop framing
- #369#issuecomment-3437 → drop attribution
- #406 step 3 bundle rename → drop history

flow.html (3 → 0):
- #389 slug + #362 pill pattern + #406 step 2 bundle → drop cookies,
  preserve functional descriptions

Total this batch (across all 4 files): **35 cookies scrubbed**.
Net effect: the dashboard SPA's HTML + JS comments all point at
docs/web-ui.md for substantive design context now, with inline
comments only retaining present-state operational descriptions.
This commit is contained in:
iris 2026-05-31 15:07:35 +02:00 committed by mara
commit f7e38c0b42
4 changed files with 123 additions and 182 deletions

View file

@ -1,11 +1,8 @@
// /flow.html entry point (#406 step 2 — flow-specific split from the
// previous combined entry; #406 step 3 renamed that combined entry
// from `app.js` to `tabs.js`).
//
// Owns the full-page broker terminal, the operator-inbox derived store
// (populated from the broker stream), the inbox pill flyout, and the
// @-mention compose box. Pulls shared infrastructure (DOM helpers, side
// panel, OS notifications, path linkification) from `./common.js`.
// /flow.html entry point. Owns the full-page broker terminal, the
// operator-inbox derived store (populated from the broker stream),
// the inbox pill flyout, and the @-mention compose box. Pulls shared
// infrastructure (DOM helpers, side panel, OS notifications, path
// linkification) from `./common.js`.
//
// Does NOT contain the dashboard's tab renderers, mutation-event
// dispatchers, or refreshState — that's `./tabs.js`, loaded only by
@ -106,11 +103,11 @@ import {
if (!flow) return;
flow.innerHTML = '';
const tsFmt = (n) => new Date(n * 1000).toISOString().slice(11, 19);
// Pulse the page banner whenever a broker event lands. (Note:
// post-#389 the `.banner` lives in the dashboard's <footer>, not
// in the flow page chrome — `pulseBanner` no-ops on /flow.html
// since there's no element to find. Kept for parity if a future
// chrome change reintroduces a banner.)
// Pulse the page banner whenever a broker event lands. The
// `.banner` element lives in the dashboard's <footer> rather than
// in the flow chrome — `pulseBanner` no-ops on /flow.html since
// there's no element to find. Kept for parity if a future chrome
// change reintroduces a banner.
const banner = document.querySelector('.banner');
let bannerOffTimer = null;
function pulseBanner() {
@ -174,33 +171,28 @@ import {
// Register this row so future replies can reference it.
if (ev.id != null && ev.id > 0) msgRowMap.set(ev.id, row);
}
// Anchor the `↓ N new` pill in `.flow-main` (NOT the default
// `log.parentElement` = `.terminal-wrap`). `.terminal-wrap`
// applies `backdrop-filter`, which creates a CSS stacking
// context — the pill's z-index would otherwise be trapped
// inside and clipped under the fixed composer (issue #375).
// `.flow-main` has no backdrop-filter / stacking-context
// creators, so the pill's z-index reaches the root and floats
// above the composer.
// Anchor the `↓ N new` pill in `.flow-main` rather than the
// default `.terminal-wrap` parent — see docs/web-ui.md::Per-agent
// page (Terminal-wrap) for the backdrop-filter stacking-context
// gotcha (same shape on the flow page).
const flowMain = document.querySelector('.flow-main');
termCreate({
logEl: flow,
pillAnchor: flowMain,
historyUrl: '/dashboard/history',
// #408: server-side filter — only the kinds this page actually
// renders or routes (sent/delivered → broker terminal,
// Server-side filter — only the kinds this page actually renders
// or routes (sent/delivered → broker terminal,
// container_state_changed/_removed → local autocomplete cache).
// Backend (#499) pre-parses the allow-list at subscribe time so
// the per-frame hot path is one HashSet::contains and the
// Backend pre-parses the allow-list at subscribe time so the
// per-frame hot path is one HashSet::contains and the
// JSON-serialise is skipped entirely on irrelevant kinds. The
// dashboard tabs page (tabs.js) keeps the unfiltered subscribe
// since it routes every mutation kind into its derived stores.
streamUrl: '/dashboard/stream?kinds=sent,delivered,container_state_changed,container_removed',
// #448: route through the SharedWorker so this page's SSE shares
// a single backend connection with /index.html (and any other
// open hyperhive tab). Worker keys on the full URL (incl.
// query string), so the filtered subscribe is its own upstream
// — won't accidentally share with tabs.js's wider subscribe.
// Route through the SharedWorker — see docs/web-ui.md (SSE
// multiplexing paragraph). Worker keys on the full URL incl.
// query string, so this filtered subscribe is its own upstream
// and won't accidentally share with tabs.js's wider subscribe.
streamFactory: openStream,
renderers: {
sent: (ev, api) => renderMsg(ev, api, '→'),
@ -232,10 +224,9 @@ import {
// Re-sync the local containers cache on every SSE (re)connect.
// Live mutation events that fired during a disconnect window
// are never replayed, so without this the compose autocomplete
// could drift stale (issue #163). We don't try to recover
// missed broker rows here — operator inbox briefly stales on
// reconnect; HiveTerminal's history-replay covers the next
// page load.
// could drift stale. We don't try to recover missed broker rows
// here — operator inbox briefly stales on reconnect; the
// history-replay covers the next page load.
onStreamOpen: () => {
fetch('/api/state').then((r) => r.ok ? r.json() : null).then((s) => {
if (!s || !Array.isArray(s.containers)) return;