dashboard: replace agent-tab transient list with build-queue summary banner

The SW4RM tab rendered a per-transient spinner list above the container
list, duplicating the running-step badge already shown on each agent card.
Replace it with a single compact amber banner that appears when the rebuild
queue has active (queued/running) entries — 'build queue — N running / M
queued — view queue →', linking to the full queue on /core.html. Per-agent
detail stays on the cards; the top of the tab just gives the at-a-glance
summary + a jump to the queue. Closes #1817.
This commit is contained in:
iris 2026-06-21 21:43:05 +02:00 committed by mara
commit 6bb976ec72
3 changed files with 53 additions and 13 deletions

View file

@ -767,6 +767,14 @@ per-agent actions and navigation links. Contents:
agent is stale. Banner pulses on each broker SSE event agent is stale. Banner pulses on each broker SSE event
(`pulseBanner` with a 4s grace timer). (`pulseBanner` with a 4s grace timer).
**Build-queue summary banner** — when the rebuild queue has any
`queued` / `running` entries, a compact amber banner sits above the
container list: `◐ build queue — N running · M queued — view queue →`
(the link goes to the C0R3 page's R3BU1LD QU3U3). It replaces the
old per-transient spinner list; the actual running step for each
agent is already shown on its card (transient + in-flight-queue
badges), so the top of the tab only needs the at-a-glance summary.
### Themed dialogs ### Themed dialogs
All confirmations, prompts, and transient error notices use an All confirmations, prompts, and transient error notices use an

View file

@ -564,6 +564,31 @@ body.dashboard-shell {
} }
.port-conflict strong { color: var(--red); } .port-conflict strong { color: var(--red); }
/* Build-queue summary banner on the SW4RM tab: one compact line
when the rebuild queue has active work, with a link to the full queue on
the C0R3 page. Amber to match the in-progress / "rebuilding" card tint. */
.queue-summary {
display: flex;
align-items: center;
gap: 0.4em;
flex-wrap: wrap;
background: color-mix(in srgb, var(--amber) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--amber) 55%, transparent);
color: var(--amber);
padding: 0.45em 0.8em;
margin-bottom: 0.6em;
border-radius: 4px;
}
.queue-summary strong { color: var(--amber); }
.queue-summary-link {
margin-left: auto;
color: var(--amber);
text-decoration: none;
font-weight: bold;
white-space: nowrap;
}
.queue-summary-link:hover { text-decoration: underline; }
/* .notif-row / .btn-notif moved to settings.css with the S3TT1NGS /* .notif-row / .btn-notif moved to settings.css with the S3TT1NGS
page. */ page. */

View file

@ -808,19 +808,26 @@ window.marked = marked;
)); ));
} }
if (transientsState.size) { // Queue-summary banner: when the rebuild queue has active work,
const ul = el('ul'); // show one compact at-a-glance line + a link to the full queue on the
const nowUnix = Math.floor(Date.now() / 1000); // C0R3 page. Replaces the old per-transient spinner list — the actual
for (const [name, t] of transientsState) { // running step is already visible per-agent on each card (transient +
const secs = Math.max(0, nowUnix - t.since_unix); // in-flight-queue badges), so the top of the tab only needs the summary.
ul.append(el('li', {}, const activeQueue = rebuildQueueState.filter(
el('span', { class: 'glyph spinner' }, '◐'), ' ', (e) => e.state === 'queued' || e.state === 'running',
el('span', { class: 'agent' }, name), ' ', );
el('span', { class: 'role role-pending' }, t.kind + '…'), ' ', if (activeQueue.length) {
el('span', { class: 'meta' }, `nixos-container create + start (${secs}s)`), const running = activeQueue.filter((e) => e.state === 'running').length;
)); const queued = activeQueue.length - running;
} const parts = [];
root.append(ul); if (running) parts.push(`${running} running`);
if (queued) parts.push(`${queued} queued`);
root.append(el('div', { class: 'queue-summary' },
el('span', { class: 'glyph spinner' }, '◐'), ' ',
el('strong', {}, 'build queue'), ' — ',
parts.join(' · '), ' ',
el('a', { class: 'queue-summary-link', href: '/core.html' }, 'view queue →'),
));
} }
if (!containers.length && !transientsState.size) { if (!containers.length && !transientsState.size) {