Begin splitting the tabs.js monolith: lift the Y3R C4LL domain into a new call.js module (mirrors permissions.js / schedules.js). - questionsState + QUESTION_HISTORY_LIMIT move to state.js: they're read by both the SW4RM container rows (per-agent question-count badges) and the Y3R C4LL questions domain, so they're cross-domain shared state. - operator-inbox domain (state + refresh/render/mark/append) → call.js. - approvals domain (state + sync/apply/render/diff-panel/history) → call.js. - call.js exposes count getters (activeApprovalCount, operatorInboxCount); the entry's refreshTabCounts pulls them. Live-mutation paths call an injected onCountsChanged callback (registered via initCall at boot) instead of reaching into the coordinator (avoids a circular import). - renderPeerHives, physically interleaved in the moved range but part of the SW4RM/peers domain, stays in tabs.js. Behaviour-preserving; no visual change. Questions domain follows next. (Recreated after a harness-restart git-object corruption; identical content.)
35 lines
1.9 KiB
JavaScript
35 lines
1.9 KiB
JavaScript
// Shared dashboard state — the one piece of cross-domain state in the
|
|
// dashboard SPA: the live agent roster.
|
|
//
|
|
// The roster is read by nearly every tab (the container tree, the
|
|
// capabilities + tool-group matrices, the schedule target-chips, the
|
|
// container-load poll, the selection bar, and the operator inbox), so
|
|
// it lives here as a single source of truth that each domain module
|
|
// imports rather than threading through call signatures. Everything
|
|
// else in the dashboard is domain-local and lives with its own module.
|
|
//
|
|
// `containersState` is keyed by `ContainerView.name` so a lifecycle
|
|
// form's POST → 200 → matching SSE event can flip a single row without
|
|
// a full snapshot refetch. Mutated in place (`set` / `delete` / `clear`)
|
|
// by the container apply-handlers; consumers read it by reference, so
|
|
// the imported binding always reflects the latest roster.
|
|
|
|
export const containersState = new Map();
|
|
|
|
// Replace the whole roster from a fresh `/api/state` snapshot. Called by
|
|
// the entry's `refreshState` on cold load and after async-form submits;
|
|
// live single-row updates go through the container apply-handlers.
|
|
export function syncContainersFromSnapshot(s) {
|
|
containersState.clear();
|
|
for (const c of s.containers || []) containersState.set(c.name, c);
|
|
}
|
|
|
|
// Derived question state — the other genuinely cross-domain store. Owned by
|
|
// the Y3R C4LL questions domain (`call.js`: cold-loaded from /api/state, then
|
|
// mutated live by `question_added` / `question_resolved` events), but also
|
|
// read by the SW4RM container rows, which render per-agent asker/target
|
|
// question-count badges off `questionsState.pending`. It lives here for the
|
|
// same reason as `containersState`: a single source of truth both domains
|
|
// import by reference rather than threading through call signatures.
|
|
export const QUESTION_HISTORY_LIMIT = 20;
|
|
export const questionsState = { pending: [], history: [] };
|