dashboard: the SW4RM tab is the agents tab
The swarm lives in the swarm UI; this tab lists the hive's agents. The tab is 4G3NTS at #agents, its pane and count pill follow, and the module that renders the containers is agents.js. Comments and docs that named SW4RM or swarm.js follow.
This commit is contained in:
parent
ee5c057d8f
commit
e455964cb3
16 changed files with 70 additions and 69 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// hive-agent-menu.js — <hive-agent-menu>, the per-agent "⋮" context-menu
|
||||
// custom element. One instance per agent card, appended after
|
||||
// .card-body in the container row's flex layout (swarm.js's
|
||||
// .card-body in the container row's flex layout (agents.js's
|
||||
// buildContainerLi via buildAgentMenu).
|
||||
//
|
||||
// Deliberately a *light-DOM* element with no shadow root of its own: all
|
||||
|
|
@ -66,7 +66,7 @@ async function agentMenuPost(actionPath, name, body, flags) {
|
|||
class HiveAgentMenu extends HTMLElement {
|
||||
connectedCallback() {
|
||||
// Same reconnect-without-detach hazard as <hive-menu> (see its
|
||||
// connectedCallback comment) — swarm.js's row cache can move an
|
||||
// connectedCallback comment) — agents.js's row cache can move an
|
||||
// already-built <li> subtree without a real detach. Without this
|
||||
// guard a reconnect would append a second <hive-menu> on top of the
|
||||
// first, doubling the dropdown.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SW4RM (containers) domain — extracted from tabs.js.
|
||||
// 4G3NTS (containers) domain — extracted from tabs.js.
|
||||
// Agent topology, container-row rendering, selection bar, and all
|
||||
// live-update apply handlers for container-state, transient, and
|
||||
// job-queue-rollup ops. See docs/web-ui/dashboard.md::Container row for the
|
||||
|
|
@ -52,7 +52,7 @@ 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: "swarm.js should not need to pull in the jobq to do its
|
||||
// narrow — mara: "agents.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
|
||||
|
|
@ -752,7 +752,7 @@ export function renderContainers(s) {
|
|||
}
|
||||
|
||||
// ─── selection bar ───────────────────────────────────────────────────────────
|
||||
// Sticky-bottom strip; visible when >=1 agent selected on the SW4RM
|
||||
// Sticky-bottom strip; visible when >=1 agent selected on the 4G3NTS
|
||||
// tab. See docs/web-ui/dashboard.md::Selection bar for the interaction model
|
||||
// and the per-action availability rules (disabled-with-tooltip for
|
||||
// actions that don't apply to the full selection). Actions POST per
|
||||
|
|
@ -767,11 +767,12 @@ export function renderSelectionBar(containers) {
|
|||
if (!countSpan || !namesSpan || !actions) return;
|
||||
|
||||
const selected = containers.filter((c) => selectionState.has(c.name));
|
||||
// Tab-gate: bar only renders on SW4RM (the only tab with agent
|
||||
// Tab-gate: bar only renders on 4G3NTS (the only tab with agent
|
||||
// cards to cross-reference). Selection state lives in-memory and
|
||||
// the bar reappears on return to SW4RM if still non-empty.
|
||||
const onSwarmTab = (document.body.dataset.activeTab || "swarm") === "swarm";
|
||||
if (!selected.length || !onSwarmTab) {
|
||||
// the bar reappears on return to 4G3NTS if still non-empty.
|
||||
const onAgentsTab =
|
||||
(document.body.dataset.activeTab || "agents") === "agents";
|
||||
if (!selected.length || !onAgentsTab) {
|
||||
bar.hidden = true;
|
||||
document.body.classList.remove("has-selection");
|
||||
return;
|
||||
|
|
@ -84,7 +84,7 @@ code {
|
|||
Semantic colour variants only — shape comes from `hive-pill-sm`
|
||||
(shared with the agent UI's pill/chip family, @hive/shared/pill.css),
|
||||
carried directly in the markup alongside each of these classnames
|
||||
(swarm.js/core.js/builds.js). Used on container rows and build-log
|
||||
(agents.js/core.js/builds.js). Used on container rows and build-log
|
||||
rows. */
|
||||
.badge-warn {
|
||||
color: var(--amber);
|
||||
|
|
|
|||
|
|
@ -127,14 +127,14 @@ body.dashboard-shell {
|
|||
font-weight: bold;
|
||||
}
|
||||
/* `display` above beats the UA's `[hidden]` rule, so an empty count (the
|
||||
SW4RM and R3BU1LD QU3U3 pills at zero) would otherwise draw a "0". */
|
||||
4G3NTS and R3BU1LD QU3U3 pills at zero) would otherwise draw a "0". */
|
||||
.tab-count[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Tab pane visibility — createTabStrip (@hive/shared/tabs.js) sets the
|
||||
`hidden` attribute on every inactive pane (resolved from the URL hash;
|
||||
default — no hash — is SW4RM). Only the active pane stays visible. */
|
||||
default — no hash — is 4G3NTS). Only the active pane stays visible. */
|
||||
.tab-pane[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ hive-agent-menu {
|
|||
--menu-btn-opacity: 1;
|
||||
}
|
||||
/* Card actions dim while a row has any pending-state badge (transient-
|
||||
driven only now — see swarm.js's pending-badge derivation comment;
|
||||
driven only now — see agents.js's pending-badge derivation comment;
|
||||
there is no separate queued-but-not-running row state to tell apart
|
||||
from this one anymore). */
|
||||
.container-row.pending-running .actions {
|
||||
|
|
@ -443,12 +443,12 @@ hive-agent-menu {
|
|||
shared <hive-warn> component — amber/no-pulse for
|
||||
the standing caveat (a pulsing banner that's always present just
|
||||
teaches you to stop seeing it), `severity="red" pulse` for the port
|
||||
collision (an incident, not a caveat). See core.js/swarm.js and
|
||||
collision (an incident, not a caveat). See core.js/agents.js and
|
||||
hive-warn.css for the actual styling now. */
|
||||
|
||||
/* Build-queue summary banner on the SW4RM tab moved to the shared
|
||||
/* Build-queue summary banner on the 4G3NTS tab moved to the shared
|
||||
`JobqRollup` Preact component (`.jqr-*` classes, imported above) —
|
||||
mounted by swarm.js::initJobqRollup into #jobq-rollup-section. */
|
||||
mounted by agents.js::initJobqRollup into #jobq-rollup-section. */
|
||||
|
||||
.pending-state {
|
||||
color: var(--amber);
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@
|
|||
<nav class="tabbar" id="tabbar" role="tablist">
|
||||
<a
|
||||
class="tab"
|
||||
id="tab-swarm"
|
||||
href="#swarm"
|
||||
id="tab-agents"
|
||||
href="#agents"
|
||||
role="tab"
|
||||
aria-controls="tab-pane-swarm"
|
||||
data-tab="swarm"
|
||||
aria-controls="tab-pane-agents"
|
||||
data-tab="agents"
|
||||
>
|
||||
<span class="tab-label">◆ SW4RM ◆</span>
|
||||
<span class="tab-count" id="tab-count-swarm" hidden></span>
|
||||
<span class="tab-label">◆ 4G3NTS ◆</span>
|
||||
<span class="tab-count" id="tab-count-agents" hidden></span>
|
||||
</a>
|
||||
<!-- SYST3M moved to its own standalone page (/core.html, "C0R3"),
|
||||
reached from the H0M3 hub — keeps the dashboard tab strip lean.
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
view, not part of the operational tab strip. -->
|
||||
|
||||
<!-- (Peer hives are no longer a tab — they render as a headline
|
||||
under SW4RM. See tab-pane-swarm.) -->
|
||||
under 4G3NTS. See tab-pane-agents.) -->
|
||||
|
||||
<!-- FL0W and the other standalone pages are reachable from the
|
||||
H0M3 hub (served at /), not from the dashboard tab strip —
|
||||
|
|
@ -99,33 +99,33 @@
|
|||
|
||||
<!-- Tab panes. createTabStrip (@hive/shared/tabs.js) keeps exactly one
|
||||
visible by toggling the `hidden` attribute, resolved from the URL
|
||||
hash (default SW4RM). Panes start `hidden` to avoid a flash before
|
||||
hash (default 4G3NTS). Panes start `hidden` to avoid a flash before
|
||||
the script runs. -->
|
||||
<!-- Padded content wrapper: carries the 1.5em side gutter
|
||||
(.page-content, common.css) while <body> stays full-bleed so the
|
||||
sticky chrome above + the footer below span the full width. -->
|
||||
<div class="page-content">
|
||||
<main class="dashboard-main">
|
||||
<!-- SW4RM: the swarm itself. Container cards (the central thing
|
||||
<!-- 4G3NTS: the agents. Container cards (the central thing
|
||||
the operator looks at) and rebuild queue / cascade visualisation
|
||||
that drives them. No inline `C0NTAINERS` h2 heading + divider
|
||||
— the tab label SW4RM already says it. -->
|
||||
— the tab label 4G3NTS already says it. -->
|
||||
<section
|
||||
class="tab-pane"
|
||||
id="tab-pane-swarm"
|
||||
data-tab-pane="swarm"
|
||||
id="tab-pane-agents"
|
||||
data-tab-pane="agents"
|
||||
hidden
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-swarm"
|
||||
aria-labelledby="tab-agents"
|
||||
>
|
||||
<!-- Swarm / hive identity headline. Populated by refreshState from
|
||||
hive_name + swarm_name; stays hidden when neither is set. -->
|
||||
<h2 id="swarm-identity" hidden></h2>
|
||||
<!-- JobqRollup mount point, kept outside #containers-section
|
||||
deliberately — that section is wiped + rebuilt on every
|
||||
container-list render (see swarm.js::renderContainers), which
|
||||
container-list render (see agents.js::renderContainers), which
|
||||
would tear down and remount the Preact tree on every
|
||||
container-state tick. Mounted once by swarm.js::initJobqRollup,
|
||||
container-state tick. Mounted once by agents.js::initJobqRollup,
|
||||
refreshed via its own handle rather than by re-rendering. -->
|
||||
<div id="jobq-rollup-section"></div>
|
||||
<div id="containers-section">
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// live in `./common.js`; the flow-page surface (broker
|
||||
// terminal, @-mention composer) lives in `./flow.js` — `flow.html` and
|
||||
// `dashboard.html` each load their own bundle.
|
||||
// SW4RM (containers) domain lives in `./swarm.js`.
|
||||
// 4G3NTS (containers) domain lives in `./agents.js`.
|
||||
|
||||
import { marked } from "marked";
|
||||
import { $, openStream, renderServerWarnings } from "./common.js";
|
||||
|
|
@ -33,7 +33,7 @@ import {
|
|||
applyTransientCleared,
|
||||
renderContainers,
|
||||
renderSelectionBar,
|
||||
} from "./swarm.js";
|
||||
} from "./agents.js";
|
||||
import {
|
||||
initBuilds,
|
||||
onBuildsTabShown,
|
||||
|
|
@ -126,7 +126,7 @@ window.marked = marked;
|
|||
window.__hyperhive_state = s;
|
||||
renderServerWarnings(s.server_warnings);
|
||||
// Hive identity: render the swarm/hive name as a headline at the
|
||||
// top of the SW4RM pane + update the page title once the
|
||||
// top of the 4G3NTS pane + update the page title once the
|
||||
// server-side display names are known. `hive_name` / `swarm_name`
|
||||
// come from HYPERHIVE_HIVE_NAME / HYPERHIVE_SWARM_NAME env vars
|
||||
// (set by services.hyperhive.{hiveName,swarmName} nix options).
|
||||
|
|
@ -148,8 +148,8 @@ window.marked = marked;
|
|||
// `transientsState` + `containersState`, not from `s.*`).
|
||||
syncTransientsFromSnapshot(s);
|
||||
syncContainersFromSnapshot(s);
|
||||
// Job-queue rollup feeds only the SW4RM queue-summary banner
|
||||
// (per-agent card badges are transient-only — see swarm.js). Its
|
||||
// Job-queue rollup feeds only the 4G3NTS queue-summary banner
|
||||
// (per-agent card badges are transient-only — see agents.js). Its
|
||||
// own `JobqRollup` mount self-fetches GET /api/jobq/rollup — not
|
||||
// read off `s` (this page's snapshot carries no jobq field).
|
||||
// initJobqRollup mounts once and is a no-op on later calls; the
|
||||
|
|
@ -182,7 +182,7 @@ window.marked = marked;
|
|||
|
||||
// ─── live updates: dashboard event stream ──────────────────────────────
|
||||
// The dashboard subscribes to /dashboard/stream for live mutation
|
||||
// events so the SW4RM / SYST3M panes update without an
|
||||
// events so the 4G3NTS / SYST3M panes update without an
|
||||
// operator action triggering a refreshState.
|
||||
//
|
||||
// Bare `EventSource` (no terminal infrastructure needed — the
|
||||
|
|
@ -202,7 +202,7 @@ window.marked = marked;
|
|||
container_state_changed: applyContainerStateChanged,
|
||||
container_removed: applyContainerRemoved,
|
||||
// rebuild_queue_changed: a payload-less push trigger. Refreshes the
|
||||
// SW4RM queue-summary banner (see swarm.js) and the R3BU1LD QU3U3
|
||||
// 4G3NTS queue-summary banner (see agents.js) and the R3BU1LD QU3U3
|
||||
// tab's JobqGraph (see builds.js).
|
||||
rebuild_queue_changed: () => {
|
||||
applyRebuildQueueChanged();
|
||||
|
|
@ -260,9 +260,9 @@ window.marked = marked;
|
|||
})();
|
||||
|
||||
// ─── tab routing ───────────────────────────────────────────────────────
|
||||
// Hash-based: `#swarm` / `#rebuild` / `#meta` / `#buildlogs` /
|
||||
// Hash-based: `#agents` / `#rebuild` / `#meta` / `#buildlogs` /
|
||||
// `#permissions` activate the matching pane on the dashboard. Empty
|
||||
// hash defaults to SW4RM. FL0W and ST4TS are NOT tabs —
|
||||
// hash defaults to 4G3NTS. FL0W and ST4TS are NOT tabs —
|
||||
// they're separate pages (`/flow.html`, `/stats.html`) reached from
|
||||
// the H0M3 hub. Tab routing only
|
||||
// applies when the tab DOM is present (e.g. not on the flow page
|
||||
|
|
@ -275,7 +275,7 @@ window.marked = marked;
|
|||
// to their own pages rather than hide them in a dropdown.
|
||||
function activateTab(target) {
|
||||
// Track active tab on the body so renderSelectionBar can gate
|
||||
// visibility (bar only belongs on SW4RM where agent cards live).
|
||||
// visibility (bar only belongs on 4G3NTS where agent cards live).
|
||||
document.body.dataset.activeTab = target;
|
||||
renderSelectionBar(Array.from(containersState.values()));
|
||||
// Permissions tables: SSE covers worker-applied changes
|
||||
|
|
@ -292,9 +292,9 @@ window.marked = marked;
|
|||
|
||||
// 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
|
||||
// (default 4G3NTS), toggles the active tab/pane + aria-selected, and
|
||||
// fires activateTab for the per-tab side-effects on every change.
|
||||
createTabStrip($("tabbar"), { defaultId: "swarm", onShow: activateTab });
|
||||
createTabStrip($("tabbar"), { defaultId: "agents", onShow: activateTab });
|
||||
// The rebuild queue mounts now, not on first show, so its tab's count pill
|
||||
// is live from the start.
|
||||
initBuilds();
|
||||
|
|
@ -313,14 +313,14 @@ window.marked = marked;
|
|||
/** Recompute every tab's count from the current state. Called on
|
||||
* every renderXxx that's tab-relevant. */
|
||||
function refreshTabCounts() {
|
||||
// SW4RM — flag any container that's stale (needs_update). Empty
|
||||
// 4G3NTS — flag any container that's stale (needs_update). Empty
|
||||
// when everyone's current. Container-row pulse signals state
|
||||
// transitions; the pill catches "deploy-pending" specifically.
|
||||
let swarm = 0;
|
||||
let stale = 0;
|
||||
for (const c of containersState.values()) {
|
||||
if (c.needs_update) swarm++;
|
||||
if (c.needs_update) stale++;
|
||||
}
|
||||
setTabCount("swarm", swarm);
|
||||
setTabCount("agents", stale);
|
||||
// R3BU1LD QU3U3 — rebuilds in flight.
|
||||
setTabCount("rebuild", rebuildCount());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue