dashboard: surface in-flight rebuild on container card (#398)
The SW4RM tab's container card was reading container state straight from the snapshot — when a rebuild was in flight and the container was momentarily stopped between teardown and bring-up, the card showed "stopped" while the SYST3M tab's rebuild queue showed the operation running. The two surfaces disagreed. Mara: *should show as building in container page as well*. Cross-reference: build a `inFlightOpsByAgent()` map from `rebuildQueueState` (kinds: rebuild / meta_update / destroy; states: queued / running — skip `spawn` since transients already drive that case). When rendering each container row, prefer the operator-initiated transient if set; otherwise fall back to the in-flight queue entry as a synthetic pending kind: `rebuilding` / `meta-updating` / `destroying` (or `… queued` when still waiting on the worker). The existing `pending-state` spinner badge surfaces it visually — no new CSS rule needed. Also wire `applyRebuildQueueChanged` to re-render containers so the badge lights up the moment a rebuild lands in the queue and clears the moment it finishes — no manual refresh.
This commit is contained in:
parent
7743c07380
commit
88bc07fbbe
1 changed files with 51 additions and 4 deletions
|
|
@ -535,6 +535,34 @@ window.marked = marked;
|
||||||
function applyRebuildQueueChanged(ev) {
|
function applyRebuildQueueChanged(ev) {
|
||||||
rebuildQueueState = (ev.queue || []).slice();
|
rebuildQueueState = (ev.queue || []).slice();
|
||||||
renderRebuildQueueFromState();
|
renderRebuildQueueFromState();
|
||||||
|
// Container cards surface in-flight rebuild / meta-update ops as
|
||||||
|
// a "building..." badge (#398) — re-render the SW4RM tab so
|
||||||
|
// newly-queued / newly-running ops light up the right card,
|
||||||
|
// and finished ops fall back to the regular state badges.
|
||||||
|
renderContainersFromState();
|
||||||
|
}
|
||||||
|
// Map from agent name → highest-priority in-flight queue entry
|
||||||
|
// (`running` beats `queued`). Used by the container row renderer
|
||||||
|
// to surface "building..." / "meta-updating..." badges on the
|
||||||
|
// SW4RM tab when an op is still in the rebuild queue but no
|
||||||
|
// operator-initiated transient is set (#398).
|
||||||
|
function inFlightOpsByAgent() {
|
||||||
|
const out = new Map();
|
||||||
|
for (const e of rebuildQueueState) {
|
||||||
|
if (e.state !== 'queued' && e.state !== 'running') continue;
|
||||||
|
// spawn ops target an agent that doesn't exist yet as a
|
||||||
|
// container — the transient store already drives the
|
||||||
|
// pending row for that case. Skip here to avoid double-
|
||||||
|
// surfacing if the spawn op happens to land in the queue
|
||||||
|
// while the row exists transiently.
|
||||||
|
if (e.kind === 'spawn') continue;
|
||||||
|
const cur = out.get(e.agent);
|
||||||
|
// Prefer running over queued; otherwise keep the first match.
|
||||||
|
if (!cur || (cur.state === 'queued' && e.state === 'running')) {
|
||||||
|
out.set(e.agent, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
function renderRebuildQueueFromState() {
|
function renderRebuildQueueFromState() {
|
||||||
renderRebuildQueue({ rebuild_queue: rebuildQueueState });
|
renderRebuildQueue({ rebuild_queue: rebuildQueueState });
|
||||||
|
|
@ -729,13 +757,32 @@ window.marked = marked;
|
||||||
const hostname = (s && s.hostname) || window.location.hostname;
|
const hostname = (s && s.hostname) || window.location.hostname;
|
||||||
const ul = el('ul', { class: 'containers' });
|
const ul = el('ul', { class: 'containers' });
|
||||||
const tree = buildAgentTree(containers);
|
const tree = buildAgentTree(containers);
|
||||||
|
// In-flight rebuild / meta-update / destroy ops per agent name.
|
||||||
|
// Surface them as "building..." style badges on the container
|
||||||
|
// card when no operator-initiated transient already covers the
|
||||||
|
// row (#398). Mara: the SW4RM tab showed an agent as stopped
|
||||||
|
// while SYST3M showed an active rebuild; cross-reference fixes
|
||||||
|
// that.
|
||||||
|
const inFlight = inFlightOpsByAgent();
|
||||||
for (const node of tree) {
|
for (const node of tree) {
|
||||||
const c = node.container;
|
const c = node.container;
|
||||||
const url = `http://${hostname}:${c.port}/`;
|
const url = `http://${hostname}:${c.port}/`;
|
||||||
// Pending state is overlaid from the transient store, not from
|
// Pending state is overlaid from the transient store first
|
||||||
// the container row — `ContainerStateChanged` doesn't carry it,
|
// (operator-initiated spawn/destroy/rebuild — covers the
|
||||||
// `TransientSet` / `TransientCleared` do.
|
// create+start window where the container literally isn't up
|
||||||
const pending = transientsState.get(c.name)?.kind || null;
|
// yet), then from the rebuild_queue (#398 — covers in-flight
|
||||||
|
// ops the worker is running even if no transient was set).
|
||||||
|
// `ContainerStateChanged` doesn't carry either signal.
|
||||||
|
const transientKind = transientsState.get(c.name)?.kind || null;
|
||||||
|
const op = !transientKind ? inFlight.get(c.name) : null;
|
||||||
|
const pending = transientKind
|
||||||
|
|| (op && (op.state === 'running'
|
||||||
|
? (op.kind === 'meta_update' ? 'meta-updating'
|
||||||
|
: op.kind === 'destroy' ? 'destroying'
|
||||||
|
: 'rebuilding')
|
||||||
|
: (op.kind === 'meta_update' ? 'meta-update queued'
|
||||||
|
: op.kind === 'destroy' ? 'destroy queued'
|
||||||
|
: 'rebuild queued')));
|
||||||
const li = el('li', { class: 'container-row' + (pending ? ' pending' : '') });
|
const li = el('li', { class: 'container-row' + (pending ? ' pending' : '') });
|
||||||
// Topology: depth contributes left-padding; the glyph string in
|
// Topology: depth contributes left-padding; the glyph string in
|
||||||
// the .tree-prefix span draws the ├─ / └─ joint + continuation
|
// the .tree-prefix span draws the ├─ / └─ joint + continuation
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue