diff --git a/frontend/packages/dashboard/src/swarm.js b/frontend/packages/dashboard/src/swarm.js index 3181182c..2b4a9478 100644 --- a/frontend/packages/dashboard/src/swarm.js +++ b/frontend/packages/dashboard/src/swarm.js @@ -56,27 +56,16 @@ const selectionState = new Set(); // ─── job queue rollup (queue-summary banner only) ────────────────────────── // // The ONE piece of job-queue-derived state on this page, and deliberately -// narrow — mara, on review of the DagView migration: "swarm.js should not -// need to pull in the jobq to do its job." An earlier version of this file -// fetched GET /api/jobq/graph (the full node tree) for two things: a -// per-agent queued-but-not-running badge (`queuedOpsByAgent()`, removed -// per "remove the per agent pending stuff - only show what is running" — -// a card's pending badges are transients-only now, which already means -// "what is running") and this banner, which was pulled entirely per "dont -// replace one legacy thing with another" (a client-side tally over the -// generic graph was itself judged a stopgap). Rendering itself later -// moved out to the shared `JobqRollup` Preact component (same one -// swarm-ui's /jobs page mounts), which owns its own fetch of -// GET /api/jobq/rollup — this file just calls Preact's own -// `render(h(...))` directly (no `mountX()` wrapper: `render` is -// already the re-render/diff entry point, per mara on review) and -// bumps a refresh token to force a refetch. +// narrow — mara: "swarm.js should not need to pull in the jobq to do its +// job." Rendering is owned by the shared `JobqRollup` Preact component +// (same one swarm-ui's /jobs page mounts, self-fetching +// GET /api/jobq/rollup); this file just calls `render(h(...))` and bumps +// a refresh token to force a refetch. // // Rendered into #jobq-rollup-section, a sibling of #containers-section // kept OUTSIDE that section's per-render `replaceChildren()` wipe (see -// dashboard.html's comment on the mount div) — rendering into a -// section that gets wiped on every container-state tick would defeat -// the component owning its own fetch lifecycle. +// dashboard.html) — a section that gets wiped on every container-state +// tick would defeat the component owning its own fetch lifecycle. let jobqRollupToken = 0; export function initJobqRollup() { @@ -334,12 +323,9 @@ function buildContainerLi(c, node, opts) { pending, opRunning, selected, url, containerBase, forgeBase, s, } = opts; - // A single `pending-running` class now covers the whole "has at - // least one badge" state — there's no more queued-but-not-running - // row to distinguish it from (see the pending-badge derivation - // comment in renderContainers), so the separate no-tint `pending` - // class from before that removal is gone rather than kept as a - // class that would now always co-occur with this one. + // A single `pending-running` class covers any active transient + // badge state (see the pending-badge derivation comment in + // renderContainers). const li = el('li', { class: 'container-row' + (opRunning ? ' pending-running' : '') @@ -348,9 +334,7 @@ function buildContainerLi(c, node, opts) { // Topology: depth contributes left-padding; the glyph string in // the .tree-prefix span draws the ├─ / └─ joint + continuation // lines (`│ `) for ancestors whose subtree extends below this - // row. Both are CSS-driven from the data attributes so the - // legacy flat layout (every container at depth 0) is bit- - // identical to today's render — no glyph, no indent. + // row. A depth-0 row gets neither — no glyph, no indent. if (node.depth > 0) li.dataset.depth = String(node.depth); const prefix = treePrefixDom(node); if (prefix) li.prepend(prefix); @@ -615,9 +599,7 @@ export function renderContainers(s) { )); } - // Queue-summary banner lives outside this section now — see - // #jobq-rollup-section / initJobqRollup, mounted once rather than - // rebuilt on every render this function does. + // Queue-summary banner: see initJobqRollup, above. if (!containers.length && !transientsState.size) { root.append(el('p', { class: 'empty' }, 'no managed containers')); diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index 3d6cd2a9..d37202ad 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -89,15 +89,11 @@ window.marked = marked; // opts out via `data-no-refresh` (its mutation arrives via an SSE event). bindAsyncForms(() => refreshState()); - // Live ticker for approval request-age chips. Approval cards only - // re-render on `approval_added`/`approval_resolved` SSE events, so - // a request pending for an hour could still show "0s ago" without - // this ticker. Also flips `.stale` (amber highlight) at exactly 1h - // rather than only at the next re-render. - // Live countdown for schedule next-fire cells. Renderers stamp - // `data-due-at` on `.sched-due` elements so this single ticker keeps - // them fresh without triggering a full re-render. Also keeps - // `.approval-ts` stale-highlight fresh at the 1h boundary. + // One ticker feeds two live displays that would otherwise only + // update on the next SSE-triggered re-render: approval request-age + // chips (`.approval-ts`, flips `.stale` at the 1h mark) and schedule + // next-fire countdowns (`.sched-due`, stamped with `data-due-at` by + // the renderers so this loop can refresh them without a full re-render). setInterval(() => { const now = Math.floor(Date.now() / 1000); document.querySelectorAll('.approval-ts[data-requested-at]').forEach((node) => { @@ -188,8 +184,6 @@ window.marked = marked; // names from here instead of refetching on every keystroke). window.__hyperhive_state = s; renderServerWarnings(s.server_warnings); - // (The M4TR1X surface is reachable directly at /matrix/ when enabled - // — no link in the dashboard tab strip or the H0M3 hub.) // Hive identity: render the swarm/hive name as a headline at the // top of the SW4RM pane + update the page title once the // server-side display names are known. `hive_name` / `swarm_name` @@ -228,8 +222,6 @@ window.marked = marked; // Sync the derived approvals store from the snapshot, then // render. Live `*_added` / `*_resolved` events mutate the store // directly and re-render without a snapshot refetch. - // (renderInbox now lives in ./flow.js — dashboard has no - // #inbox-section element to render into.) syncApprovalsFromSnapshot(s); renderApprovals(); refreshSchedules(); @@ -289,8 +281,6 @@ window.marked = marked; transient_cleared: applyTransientCleared, container_state_changed: applyContainerStateChanged, container_removed: applyContainerRemoved, - // tombstones_changed / meta_inputs_changed / meta_update_running are - // handled on /core.html now (the SYST3M panels moved there). // rebuild_queue_changed: refreshes the SW4RM queue-summary banner // (see swarm.js) — a payload-less push trigger, same treatment // /builds.html gives it for its JobqGraph mount handle's .refresh() @@ -383,11 +373,6 @@ window.marked = marked; if (target === 'call') { refreshOperatorInbox(); } } - // ST4TS (hive-wide turn-stats rollup) moved to its own page, - // `/stats.html` — the render JS + the window selector live in - // stats.js now. The dashboard no longer fetches - // /api/stats-hive. - // Wire the shared tab strip now that activateTab + the lazy-load fns it // calls are defined. The strip resolves the active tab from the hash // (default SW4RM), toggles the active tab/pane + aria-selected, and @@ -404,10 +389,6 @@ window.marked = marked; // stores so SSE-driven updates flow through without extra plumbing. // Set `hidden` when the count is zero so the pill doesn't draw // attention to an empty room. - // The operator inbox (unread agent->operator messages) now lives in - // call.js — `refreshOperatorInbox`, `operatorInboxAppendFromEvent`, and - // `operatorInboxCount` are imported above. It calls back through the - // `onCountsChanged` callback registered via `initCall` at boot. function setTabCount(tab, n) { const el_ = $('tab-count-' + tab);