dashboard: subscribe to /dashboard/stream for live updates (#406 step 3)
Pre-step-2, the SSE subscription on /index.html was conditionally created by the broker-terminal IIFE that only ran on /flow.html (via the `if (!flow || !window.HiveTerminal) return;` guard) — so the dashboard only updated on cold load + after async-form submits. The split in step 2 made the gap more obvious; close it. Bare `EventSource` (the dashboard doesn't render broker rows, so none of the HiveTerminal infrastructure is wanted here). Each event's `kind` looks up against a `MUTATION_HANDLERS` table that fans out to the existing `applyXxx` handlers. Unknown kinds (broker `sent` / `delivered`, anything the backend adds later) silently no-op. On (re)connect we kick `refreshState()` to recover events lost during the disconnect window — same pattern as flow.js's `onStreamOpen`. EventSource handles auto-reconnect. #408 will give /index.html its own stream that omits broker traffic; for now both pages subscribe to `/dashboard/stream` and filter client-side. Closes the #406 architectural roadmap: - step 1 (#410): common.js extraction ✓ - step 2 (#412): split into app.js + flow.js entry points ✓ - step 3 (this PR): /index.html re-acquires its SSE subscription
This commit is contained in:
parent
0e17459943
commit
1819bee43c
1 changed files with 57 additions and 0 deletions
|
|
@ -1828,6 +1828,63 @@ window.marked = marked;
|
|||
NOTIF.bind();
|
||||
Panel.bind();
|
||||
|
||||
// ─── live updates: dashboard event stream (#406 step 3) ────────────────
|
||||
// The dashboard subscribes to /dashboard/stream for live mutation
|
||||
// events so the SW4RM / Y3R C4LL / SYST3M panes update without an
|
||||
// operator action triggering a refreshState. Pre-step-2 this wiring
|
||||
// lived inside the broker-terminal IIFE which only fired on /flow.html
|
||||
// — meaning /index.html only updated on cold load + after async-form
|
||||
// submits.
|
||||
//
|
||||
// Bare `EventSource` (no terminal infrastructure needed — the
|
||||
// dashboard doesn't render broker rows). Each event's `kind` is
|
||||
// looked up against `MUTATION_HANDLERS`; unknown kinds (broker
|
||||
// `sent` / `delivered`, anything new the backend adds) silently
|
||||
// no-op. On (re)connect we kick a refreshState() to recover events
|
||||
// lost during the disconnect window (same pattern as flow.js's
|
||||
// onStreamOpen).
|
||||
//
|
||||
// `#408` will give /index.html its own stream that omits the
|
||||
// broker traffic the dashboard never uses; for now both pages
|
||||
// subscribe to `/dashboard/stream` and filter client-side.
|
||||
const MUTATION_HANDLERS = {
|
||||
approval_added: applyApprovalAdded,
|
||||
approval_resolved: applyApprovalResolved,
|
||||
question_added: applyQuestionAdded,
|
||||
question_resolved: applyQuestionResolved,
|
||||
transient_set: applyTransientSet,
|
||||
transient_cleared: applyTransientCleared,
|
||||
container_state_changed: applyContainerStateChanged,
|
||||
container_removed: applyContainerRemoved,
|
||||
tombstones_changed: applyTombstonesChanged,
|
||||
meta_inputs_changed: applyMetaInputsChanged,
|
||||
meta_update_running: applyMetaUpdateRunning,
|
||||
rebuild_queue_changed: applyRebuildQueueChanged,
|
||||
};
|
||||
(function bindDashboardStream() {
|
||||
const es = new EventSource('/dashboard/stream');
|
||||
es.onmessage = (e) => {
|
||||
let ev;
|
||||
try { ev = JSON.parse(e.data); } catch { return; }
|
||||
const h = MUTATION_HANDLERS[ev.kind];
|
||||
if (!h) return; // broker rows + future kinds — dashboard doesn't care
|
||||
try { h(ev); }
|
||||
catch (err) { console.error('dashboard SSE handler', ev.kind, err); }
|
||||
};
|
||||
es.onopen = () => {
|
||||
// Re-sync to recover events that fired during a disconnect
|
||||
// window (issue #163). Initial connect also fires onopen — the
|
||||
// first refreshState() above and this one race, but refreshState
|
||||
// is idempotent so the second call just overwrites with the
|
||||
// freshest snapshot. Cheap on a quiescent server, fine to repeat.
|
||||
refreshState();
|
||||
};
|
||||
es.onerror = () => {
|
||||
// EventSource auto-reconnects; nothing to do beyond logging.
|
||||
console.debug('dashboard SSE error, will retry');
|
||||
};
|
||||
})();
|
||||
|
||||
// ─── tab routing (#369) ────────────────────────────────────────────────
|
||||
// Hash-based: `#swarm` / `#call` / `#system` activate the matching
|
||||
// pane on the dashboard. Empty hash defaults to SW4RM. FL0W is NOT
|
||||
|
|
|
|||
Loading…
Reference in a new issue