dashboard: the hive UI no longer shows container load
The cpu, memory and disk figures are exported as OTEL metrics and graphed in Grafana, and the caps are set in the swarm UI, so the C0NT41N3R L04D tab on the C0R3 page only duplicated both. C0R3 is now the kept-state page alone, without a tab strip.
This commit is contained in:
parent
4285faf07c
commit
a2540be98b
11 changed files with 52 additions and 515 deletions
|
|
@ -619,8 +619,8 @@ hive-side-panel .md td {
|
|||
|
||||
/* ─── stats table ─────────────────────────────────────────────────
|
||||
Shared right-aligned numeric table. Used by /stats.html (busiest
|
||||
agents) and the dashboard SYST3M › C0NT41N3R L04D table — moved here
|
||||
from dashboard.css when ST4TS became its own page. */
|
||||
agents) — moved here from dashboard.css when ST4TS became its own
|
||||
page. */
|
||||
.hive-stats-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* ─── /core.html — C0R3 page ───────────────────────────────────────
|
||||
Kept state (tombstones) and container load. Section rules imported
|
||||
from system-sections.css (shared with dashboard.css + builds.css). */
|
||||
Kept state (tombstones) and stale permission entries. Section rules
|
||||
imported from system-sections.css (shared with dashboard.css +
|
||||
builds.css). */
|
||||
@import "./system-sections.css";
|
||||
|
||||
body.core-shell {
|
||||
|
|
@ -8,22 +9,10 @@ body.core-shell {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
/* Fill the header row next to the ← home back-link, same as the
|
||||
builds sub-tab strip. */
|
||||
.core-tabbar {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.core-main {
|
||||
padding: 1.2em 1.5em 2em;
|
||||
}
|
||||
|
||||
/* createTabStrip toggles the native `hidden` attribute on inactive
|
||||
panes; ensure it wins over any inherited display. */
|
||||
.core-pane[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ─── K3PT ST4T3 container cards ────────────────────────────────────
|
||||
core.html doesn't load dashboard.css (that's the operator SPA),
|
||||
so the .container-row card styles aren't inherited. Redefine them
|
||||
|
|
|
|||
|
|
@ -13,70 +13,31 @@
|
|||
<body class="core-shell">
|
||||
<!-- C0R3: the host/coordinator surface. Standalone page (served at
|
||||
/core.html) carved out of the dashboard's old SYST3M tab so the
|
||||
dashboard tab strip stays lean. Same minimal chrome as
|
||||
/builds.html — a `← home` back-link to the H0M3 hub + a
|
||||
<hive-tab-strip> sub-tab nav. Two sub-tabs: kept state (tombstones)
|
||||
and container load. Rebuild queue + meta inputs have moved to
|
||||
/builds.html (the build lifecycle hub). Default tab: K3PT ST4T3.
|
||||
The section <div> ids (tombstones-section, container-load-section)
|
||||
match what core.js's renderers target. Hive infra containers
|
||||
(`hive-forge`, `hive-gateway`, `hive-matrix`) have no
|
||||
dashboard panel — `hivectl stop`/`start`/`restart` is the only
|
||||
dashboard tab strip stays lean: kept state (tombstones) and the
|
||||
stale permission entries. The section <div> ids (tombstones-section,
|
||||
tombstones-stale-perms) match what core.js's renderers target. Hive
|
||||
infra containers (`hive-forge`, `hive-gateway`, `hive-matrix`) have
|
||||
no dashboard panel — `hivectl stop`/`start`/`restart` is the only
|
||||
control surface. -->
|
||||
<header class="page-header">
|
||||
<a class="page-back" href="/">← home</a>
|
||||
<hive-tab-strip
|
||||
class="hive-tabbar core-tabbar"
|
||||
id="core-tabbar"
|
||||
prefix="core"
|
||||
role="tablist"
|
||||
></hive-tab-strip>
|
||||
<span class="page-title">K3PT ST4T3</span>
|
||||
</header>
|
||||
|
||||
<main class="core-main">
|
||||
<!-- K3PT ST4T3: tombstoned-agent kept state + stale permission entries.
|
||||
tombstones-section shows destroyed agents (purge button).
|
||||
tombstones-stale-perms is lazy-loaded on tab activation and shows
|
||||
agents with explicit capability/tool-group entries but no live
|
||||
container (typically renamed/deleted agents whose JSON entries
|
||||
persisted). Each stale entry gets a "✕ clear perms" button. -->
|
||||
<section
|
||||
class="core-pane"
|
||||
id="core-pane-kept"
|
||||
data-tab-pane="kept"
|
||||
role="tabpanel"
|
||||
aria-labelledby="core-tab-kept"
|
||||
>
|
||||
<p class="meta">
|
||||
kept state from previously tombstoned agents — recreating an agent
|
||||
with the same name reuses it.
|
||||
</p>
|
||||
<div id="tombstones-section">
|
||||
<p class="meta">loading…</p>
|
||||
</div>
|
||||
<div id="tombstones-stale-perms"></div>
|
||||
</section>
|
||||
|
||||
<!-- C0NT41N3R L04D: live cpu + memory per agent container, from
|
||||
cgroup v2 on the host. Polled only while this sub-tab is active. -->
|
||||
<section
|
||||
class="core-pane"
|
||||
id="core-pane-load"
|
||||
data-tab-pane="load"
|
||||
role="tabpanel"
|
||||
aria-labelledby="core-tab-load"
|
||||
>
|
||||
<p class="meta">
|
||||
live cpu + memory per agent container, from cgroup v2 on the host. cpu
|
||||
is % of total host capacity (all cores), sampled over ~200ms each
|
||||
refresh; polled every 5s while this tab is open. network is omitted on
|
||||
purpose — agents share the host netns, so there is no per-container
|
||||
counter (see <code>docs/networking/network.md</code>).
|
||||
</p>
|
||||
<div id="container-load-section">
|
||||
<p class="meta">loading…</p>
|
||||
</div>
|
||||
</section>
|
||||
<!-- tombstones-section shows destroyed agents (purge button).
|
||||
tombstones-stale-perms shows agents with explicit capability/
|
||||
tool-group entries but no live container (typically renamed/deleted
|
||||
agents whose JSON entries persisted). Each stale entry gets a
|
||||
"✕ clear perms" button. -->
|
||||
<p class="meta">
|
||||
kept state from previously tombstoned agents — recreating an agent with
|
||||
the same name reuses it.
|
||||
</p>
|
||||
<div id="tombstones-section">
|
||||
<p class="meta">loading…</p>
|
||||
</div>
|
||||
<div id="tombstones-stale-perms"></div>
|
||||
</main>
|
||||
|
||||
<script type="module" src="/static/core.js" defer></script>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,20 @@
|
|||
// C0R3 page entry (/core.html). The host/coordinator surface, its own
|
||||
// standalone page so the dashboard tab strip stays lean. Two sub-tabs
|
||||
// via <hive-tab-strip> (default = K3PT ST4T3): kept state (tombstones)
|
||||
// and container load.
|
||||
// standalone page so the dashboard tab strip stays lean: kept state
|
||||
// (tombstones) and the stale permission entries.
|
||||
//
|
||||
// Rebuild queue + meta inputs live at /builds.html (the build lifecycle
|
||||
// hub), not here. This page is its own esbuild bundle with its own
|
||||
// runtime: it cold-loads /api/state and subscribes to /dashboard/stream
|
||||
// (the same broker event channel the dashboard uses), maintaining its
|
||||
// own copy of the tombstones state.
|
||||
// This page is its own esbuild bundle with its own runtime: it cold-loads
|
||||
// /api/state and subscribes to /dashboard/stream (the same broker event
|
||||
// channel the dashboard uses), maintaining its own copy of the tombstones
|
||||
// state.
|
||||
|
||||
import { $, form, openStream, initServerWarnings } from "./common.js";
|
||||
import { el } from "@hive/shared/dom.js";
|
||||
import { asyncBtn, bindAsyncForms } from "@hive/shared/forms.js";
|
||||
import "@hive/shared/hive-tab-strip.js";
|
||||
|
||||
// ─── derived state (own copies; this bundle has its own runtime) ──────────
|
||||
let tombstonesState = [];
|
||||
// ContainerView list from the last /api/state snapshot — used by renderContainerLoad
|
||||
// to splice in the configured cpu_quota/memory_max limits alongside live cgroup data.
|
||||
let containersState = [];
|
||||
function syncFromSnapshot(s) {
|
||||
tombstonesState = (s.tombstones || []).slice();
|
||||
containersState = (s.containers || []).slice();
|
||||
}
|
||||
|
||||
// ─── kept state (tombstones) ──────────────────────────────────────────────
|
||||
|
|
@ -187,273 +180,6 @@ async function fetchAndRenderStalePerms() {
|
|||
stalePermsLoaded = true;
|
||||
}
|
||||
|
||||
// ─── container load (live cgroup poll while the LOAD sub-tab is open) ──────
|
||||
let containerLoadTimer = null;
|
||||
|
||||
function cloadFmtBytes(n) {
|
||||
if (!Number.isFinite(n) || n <= 0) return "0";
|
||||
const u = ["B", "KiB", "MiB", "GiB", "TiB"];
|
||||
let i = 0;
|
||||
let v = n;
|
||||
while (v >= 1024 && i < u.length - 1) {
|
||||
v /= 1024;
|
||||
i += 1;
|
||||
}
|
||||
return v.toFixed(v < 10 && i > 0 ? 1 : 0) + " " + u[i];
|
||||
}
|
||||
function cloadMeter(pct) {
|
||||
const p = Math.max(0, Math.min(100, pct));
|
||||
const cls = p >= 90 ? "hot" : p >= 70 ? "warn" : "";
|
||||
const m = document.createElement("span");
|
||||
m.className = "cload-meter";
|
||||
m.title = p.toFixed(0) + "%";
|
||||
const fill = document.createElement("span");
|
||||
fill.className = "fill" + (cls ? " " + cls : "");
|
||||
fill.style.width = p + "%";
|
||||
m.append(fill);
|
||||
return m;
|
||||
}
|
||||
|
||||
// Stash the last load rows so re-renders triggered by SSE state updates can
|
||||
// call renderContainerLoad(lastLoadRows) without waiting for the next poll.
|
||||
let lastLoadRows = [];
|
||||
|
||||
function renderContainerLoad(rows) {
|
||||
lastLoadRows = rows;
|
||||
const root = $("container-load-section");
|
||||
if (!root) return;
|
||||
if (!Array.isArray(rows) || rows.length === 0) {
|
||||
root.replaceChildren();
|
||||
const p = document.createElement("p");
|
||||
p.className = "meta";
|
||||
p.textContent = "no running agent containers";
|
||||
root.append(p);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a name→ContainerView lookup so we can splice in the configured
|
||||
// cpu_quota / memory_max limits (set in meta/resource-limits.json and
|
||||
// resolved by the server) next to the live cgroup readings.
|
||||
const cvByName = new Map(containersState.map((c) => [c.name, c]));
|
||||
|
||||
const table = document.createElement("table");
|
||||
table.className = "hive-stats-table";
|
||||
// "cpu cap" / "mem cap" show the configured ceilings from ContainerView
|
||||
// (effective drop-in values, take effect on next start/restart).
|
||||
// "limit" remains the live cgroup memory ceiling from /api/container-resources.
|
||||
table.innerHTML =
|
||||
"<thead><tr><th>agent</th><th>cpu</th><th>memory</th>" +
|
||||
"<th>peak</th><th>limit</th><th>disk</th>" +
|
||||
'<th class="cload-cap-th" title="configured ceiling — takes effect on next start">cpu cap</th>' +
|
||||
'<th class="cload-cap-th" title="configured ceiling — takes effect on next start">mem cap</th>' +
|
||||
"<th></th></tr></thead>";
|
||||
const tb = document.createElement("tbody");
|
||||
for (const r of rows) {
|
||||
const cv = cvByName.get(r.name);
|
||||
const tr = document.createElement("tr");
|
||||
const name = document.createElement("td");
|
||||
name.textContent = r.name;
|
||||
tr.append(name);
|
||||
const cpu = document.createElement("td");
|
||||
cpu.className = "num";
|
||||
cpu.append(
|
||||
(Number(r.cpu_pct) || 0).toFixed(1) + "%",
|
||||
cloadMeter(Number(r.cpu_pct) || 0),
|
||||
);
|
||||
tr.append(cpu);
|
||||
const mem = document.createElement("td");
|
||||
mem.className = "num";
|
||||
const memCur = Number(r.mem_current_bytes) || 0;
|
||||
if (r.mem_max_bytes) {
|
||||
mem.append(
|
||||
cloadFmtBytes(memCur),
|
||||
cloadMeter((100 * memCur) / r.mem_max_bytes),
|
||||
);
|
||||
} else {
|
||||
mem.textContent = cloadFmtBytes(memCur);
|
||||
}
|
||||
tr.append(mem);
|
||||
const peak = document.createElement("td");
|
||||
peak.className = "num";
|
||||
peak.textContent = r.mem_peak_bytes
|
||||
? cloadFmtBytes(Number(r.mem_peak_bytes))
|
||||
: "—";
|
||||
tr.append(peak);
|
||||
const lim = document.createElement("td");
|
||||
lim.className = "num";
|
||||
lim.textContent = r.mem_max_bytes
|
||||
? cloadFmtBytes(Number(r.mem_max_bytes))
|
||||
: "∞";
|
||||
tr.append(lim);
|
||||
// Disk: on-disk footprint (state/ + work/ + container writable rootfs, shared
|
||||
// nix store excluded). Measured out-of-band every 30 min server-side;
|
||||
// null means unknown (not measured yet, or the measurement failed).
|
||||
const disk = document.createElement("td");
|
||||
disk.className = "num";
|
||||
disk.title =
|
||||
"state/ + work/ + container writable rootfs (shared nix store excluded); measured every 30 min";
|
||||
disk.textContent =
|
||||
r.disk_bytes != null ? cloadFmtBytes(Number(r.disk_bytes)) : "unknown";
|
||||
tr.append(disk);
|
||||
|
||||
// Configured CPU / memory caps from ContainerView (resolved effective
|
||||
// values: per-agent override when set, hive-wide default otherwise).
|
||||
const cpuCap = document.createElement("td");
|
||||
cpuCap.className = "num cload-cap";
|
||||
cpuCap.title = "configured ceiling — takes effect on next start";
|
||||
cpuCap.textContent = cv?.cpu_quota || "—";
|
||||
tr.append(cpuCap);
|
||||
const memCap = document.createElement("td");
|
||||
memCap.className = "num cload-cap";
|
||||
memCap.title = "configured ceiling — takes effect on next start";
|
||||
memCap.textContent = cv?.memory_max || "—";
|
||||
tr.append(memCap);
|
||||
|
||||
// S3T button toggles the inline edit row for this agent.
|
||||
const actTd = document.createElement("td");
|
||||
const setBtn = document.createElement("button");
|
||||
setBtn.type = "button";
|
||||
setBtn.className = "btn btn-sm cload-set-btn";
|
||||
setBtn.textContent = "S3T";
|
||||
setBtn.title = "set CPU / memory cap for " + r.name;
|
||||
tr.append(actTd);
|
||||
actTd.append(setBtn);
|
||||
tb.append(tr);
|
||||
|
||||
// Inline edit row (hidden by default, toggled by the S3T button).
|
||||
const editRow = document.createElement("tr");
|
||||
editRow.className = "cload-edit-row";
|
||||
editRow.hidden = true;
|
||||
const editTd = document.createElement("td");
|
||||
editTd.colSpan = 9;
|
||||
editTd.className = "cload-edit-cell";
|
||||
|
||||
const editForm = document.createElement("form");
|
||||
editForm.className = "cload-edit-form";
|
||||
editForm.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const cpuInput = editForm.querySelector(".cload-cpu-input");
|
||||
const memInput = editForm.querySelector(".cload-mem-input");
|
||||
const errSpan = editForm.querySelector(".cload-edit-err");
|
||||
const submitBtn = editForm.querySelector('[type="submit"]');
|
||||
errSpan.hidden = true;
|
||||
submitBtn.disabled = true;
|
||||
try {
|
||||
const body = new URLSearchParams({
|
||||
cpu_quota: cpuInput.value.trim(),
|
||||
memory_max: memInput.value.trim(),
|
||||
});
|
||||
const resp = await fetch(
|
||||
"/api/resource-limits/" + encodeURIComponent(r.name),
|
||||
{ method: "POST", body },
|
||||
);
|
||||
if (!resp.ok) {
|
||||
errSpan.textContent = await resp
|
||||
.text()
|
||||
.catch(() => "error " + resp.status);
|
||||
errSpan.hidden = false;
|
||||
return;
|
||||
}
|
||||
// Success: collapse the edit row. The SSE rescan will push updated
|
||||
// ContainerView data (cpu_quota/memory_max) to containersState,
|
||||
// triggering a re-render of the cap columns via refreshContainerLoad.
|
||||
editRow.hidden = true;
|
||||
setBtn.textContent = "S3T";
|
||||
} catch (err) {
|
||||
errSpan.textContent = String(err);
|
||||
errSpan.hidden = false;
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
const cpuLabel = document.createElement("label");
|
||||
cpuLabel.className = "cload-edit-label";
|
||||
cpuLabel.textContent = "cpu quota";
|
||||
const cpuInput = document.createElement("input");
|
||||
cpuInput.type = "text";
|
||||
cpuInput.className = "cload-cpu-input";
|
||||
// Pre-fill with the current *effective* value (not just a placeholder)
|
||||
// so submitting after editing only the other field round-trips this one
|
||||
// unchanged. The form always posts both fields, and the server treats
|
||||
// an empty field as "clear this override" — a placeholder-only hint
|
||||
// reads as filled to the eye but posts as empty, silently resetting
|
||||
// whichever field the user didn't touch.
|
||||
cpuInput.value = cv ? cv.cpu_quota : "";
|
||||
cpuInput.placeholder = "e.g. 200%";
|
||||
cpuInput.title =
|
||||
'systemd CPUQuota= value (e.g. "400%"). empty = use hive default';
|
||||
cpuLabel.append(cpuInput);
|
||||
|
||||
const memLabel = document.createElement("label");
|
||||
memLabel.className = "cload-edit-label";
|
||||
memLabel.textContent = "mem max";
|
||||
const memInput = document.createElement("input");
|
||||
memInput.type = "text";
|
||||
memInput.className = "cload-mem-input";
|
||||
// Same reasoning as cpuInput above.
|
||||
memInput.value = cv ? cv.memory_max : "";
|
||||
memInput.placeholder = "e.g. 8G";
|
||||
memInput.title =
|
||||
'systemd MemoryMax= value (e.g. "8G", "50%", "infinity"). empty = use hive default';
|
||||
memLabel.append(memInput);
|
||||
|
||||
const submitBtn = document.createElement("button");
|
||||
submitBtn.type = "submit";
|
||||
submitBtn.className = "btn btn-restart cload-save-btn";
|
||||
submitBtn.textContent = "S4V3";
|
||||
|
||||
const hintSpan = document.createElement("span");
|
||||
hintSpan.className = "meta cload-edit-hint";
|
||||
hintSpan.textContent = "↺ restart to apply to a running container";
|
||||
|
||||
const errSpan = document.createElement("span");
|
||||
errSpan.className = "cload-edit-err";
|
||||
errSpan.hidden = true;
|
||||
|
||||
editForm.append(cpuLabel, memLabel, submitBtn, hintSpan, errSpan);
|
||||
editTd.append(editForm);
|
||||
editRow.append(editTd);
|
||||
tb.append(editRow);
|
||||
|
||||
setBtn.addEventListener("click", () => {
|
||||
const open = !editRow.hidden;
|
||||
editRow.hidden = open;
|
||||
setBtn.textContent = open ? "S3T" : "✕";
|
||||
});
|
||||
}
|
||||
table.append(tb);
|
||||
root.replaceChildren(table);
|
||||
}
|
||||
|
||||
async function refreshContainerLoad() {
|
||||
try {
|
||||
const resp = await fetch("/api/container-resources");
|
||||
if (!resp.ok) throw new Error("http " + resp.status);
|
||||
renderContainerLoad(await resp.json());
|
||||
} catch (e) {
|
||||
const root = $("container-load-section");
|
||||
if (root) {
|
||||
root.replaceChildren();
|
||||
const p = document.createElement("p");
|
||||
p.className = "meta";
|
||||
p.textContent = "container load fetch failed: " + e;
|
||||
root.append(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
function startContainerLoadPolling() {
|
||||
refreshContainerLoad();
|
||||
if (containerLoadTimer) return;
|
||||
containerLoadTimer = setInterval(refreshContainerLoad, 5000);
|
||||
}
|
||||
function stopContainerLoadPolling() {
|
||||
if (containerLoadTimer) {
|
||||
clearInterval(containerLoadTimer);
|
||||
containerLoadTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── render-all (cold load + any full re-render) ──────────────────────────
|
||||
function renderAll() {
|
||||
renderTombstones({ tombstones: tombstonesState });
|
||||
|
|
@ -465,19 +191,6 @@ const SSE_HANDLERS = {
|
|||
tombstonesState = (ev.tombstones || []).slice();
|
||||
renderTombstones({ tombstones: tombstonesState });
|
||||
},
|
||||
// When a container's state changes (e.g. after resource-limits update
|
||||
// triggers rescan_containers_and_emit), update containersState in place
|
||||
// so the cap columns in the LOAD table reflect the new configured values.
|
||||
container_state_changed(ev) {
|
||||
if (!ev.container) return;
|
||||
const idx = containersState.findIndex((c) => c.name === ev.container.name);
|
||||
if (idx >= 0) {
|
||||
containersState[idx] = ev.container;
|
||||
} else {
|
||||
containersState.push(ev.container);
|
||||
}
|
||||
if (lastLoadRows.length) renderContainerLoad(lastLoadRows);
|
||||
},
|
||||
// Refresh the stale-perms sub-section when perm data changes (a ghost
|
||||
// was cleared, or perms were saved for an agent whose name collides).
|
||||
capabilities_changed(_ev) {
|
||||
|
|
@ -511,33 +224,16 @@ async function init() {
|
|||
// to the bare `ok` response page.
|
||||
bindAsyncForms(() => refreshState());
|
||||
|
||||
// Hash-routed sub-tab strip; default K3PT ST4T3. Container-load
|
||||
// polling runs only while the LOAD sub-tab is open (cpu is a short
|
||||
// two-sample read each refresh on the server).
|
||||
document.getElementById("core-tabbar").configure({
|
||||
tabs: [
|
||||
{ id: "kept", label: "K3PT ST4T3" },
|
||||
{ id: "load", label: "C0NT41N3R L04D" },
|
||||
],
|
||||
defaultId: "kept",
|
||||
onShow: (id) => {
|
||||
if (id === "load") startContainerLoadPolling();
|
||||
else stopContainerLoadPolling();
|
||||
// Lazy-load stale-perms on first K3PT ST4T3 activation; always
|
||||
// re-fetch on subsequent visits in case perms changed.
|
||||
if (id === "kept") fetchAndRenderStalePerms();
|
||||
},
|
||||
});
|
||||
|
||||
await refreshState();
|
||||
fetchAndRenderStalePerms();
|
||||
|
||||
// kinds= matches SSE_HANDLERS below verbatim — narrows this from all
|
||||
// 13 wire kinds down to the 4 this page acts on. This page was one
|
||||
// 13 wire kinds down to the 3 this page acts on. This page was one
|
||||
// of 4 unfiltered `/api/dashboard/stream` subscribers before this
|
||||
// (subscription discipline, part 1 of the dashboard-event-stream-
|
||||
// split issue).
|
||||
const es = openStream(
|
||||
"/api/dashboard/stream?kinds=tombstones_changed,container_state_changed," +
|
||||
"/api/dashboard/stream?kinds=tombstones_changed," +
|
||||
"capabilities_changed,tool_groups_changed",
|
||||
);
|
||||
if (es) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
it defines the CSS custom properties, typography, and shared
|
||||
component rules that this file depends on. */
|
||||
|
||||
/* SYST3M panel rules (rebuild queue / meta inputs / container load)
|
||||
/* SYST3M panel rules (rebuild queue / meta inputs / kept state)
|
||||
live in system-sections.css, shared with /core.html. A few are still
|
||||
referenced from the dashboard (`.rebuild-queue`), so the dashboard
|
||||
pulls them in here. */
|
||||
|
|
@ -771,6 +771,4 @@ body.dashboard-shell.has-selection {
|
|||
|
||||
/* ST4TS moved to its own page (`/stats.html`): the
|
||||
window selector / summary chips / bars live in stats.css, and the
|
||||
shared `.hive-stats-table` moved to common.css (the SYST3M ›
|
||||
C0NT41N3R L04D table in system-sections.css / on /core.html still
|
||||
uses it). */
|
||||
shared `.hive-stats-table` moved to common.css. */
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
</section>
|
||||
|
||||
<!-- SYST3M pane moved to /core.html (the standalone "C0R3" page):
|
||||
meta inputs, rebuild queue, kept state, container load. Reached
|
||||
kept state and stale permissions. Reached
|
||||
from the H0M3 hub. -->
|
||||
|
||||
<!-- P3RM1SS10NS: per-agent capability grants + tool-group
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
<span class="home-tile-icon" aria-hidden="true">⬡</span>
|
||||
<span class="home-tile-label">Core</span>
|
||||
</span>
|
||||
<span class="home-tile-desc">kept state · container load</span>
|
||||
<span class="home-tile-desc">kept state · stale permissions</span>
|
||||
</a>
|
||||
|
||||
<!-- API tile: the OpenAPI spec + Swagger UI are always served by
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
// dashboard SPA: the live agent roster.
|
||||
//
|
||||
// The roster is read by nearly every tab (the container tree, the
|
||||
// capabilities + tool-group matrices, the
|
||||
// container-load poll, and the selection bar), so
|
||||
// capabilities + tool-group matrices, and the selection bar), 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.
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
chrome pattern as /flow.html: the back-link header +
|
||||
title (.page-header / .page-back / .page-title) live in
|
||||
@hive/shared/chrome.css.
|
||||
`.hive-stats-table` also lives in common.css — it's shared with the
|
||||
dashboard SYST3M › C0NT41N3R L04D table. Only the ST4TS-specific
|
||||
`.hive-stats-table` lives in common.css. Only the ST4TS-specific
|
||||
window selector, summary chips, and bars are page-specific. */
|
||||
|
||||
body.stats-shell {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* ─── SYST3M/BU1LDS section panels — shared by dashboard, /core.html,
|
||||
and /builds.html ──────────────────────────────────────────────────
|
||||
Rebuild queue, meta inputs, kept state, and container-load panels.
|
||||
Rebuild queue, meta inputs and kept-state panels.
|
||||
Imported by core.css, dashboard.css, and builds.css. */
|
||||
|
||||
/* ─── meta inputs panel ────────────────────────────────────────────── */
|
||||
|
|
@ -198,83 +198,6 @@
|
|||
color: var(--fg);
|
||||
}
|
||||
|
||||
/* ─── SYST3M › C0NT41N3R L04D: live cgroup cpu/mem ─────────────────────────────
|
||||
Reuses the shared `.hive-stats-table` styling (in common.css); only
|
||||
the inline meter bar is new. */
|
||||
.cload-meter {
|
||||
display: inline-block;
|
||||
width: 6em;
|
||||
height: 10px;
|
||||
vertical-align: middle;
|
||||
margin-left: 6px;
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cload-meter .fill {
|
||||
display: block;
|
||||
height: 100%;
|
||||
background: var(--green);
|
||||
}
|
||||
.cload-meter .fill.warn {
|
||||
background: var(--amber);
|
||||
}
|
||||
.cload-meter .fill.hot {
|
||||
background: var(--red);
|
||||
}
|
||||
|
||||
/* Configured-cap columns: muted header so they read apart from live metrics.
|
||||
The S3T button sits in its own column; keep it compact. */
|
||||
.cload-cap-th {
|
||||
color: var(--muted);
|
||||
}
|
||||
.cload-cap {
|
||||
color: var(--muted);
|
||||
}
|
||||
.cload-set-btn {
|
||||
padding: 0.1em 0.5em;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
/* Inline edit row — spans all columns, contains a mini-form. */
|
||||
.cload-edit-row td {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
.cload-edit-cell {
|
||||
padding: 0.2em 0.4em 0.6em 1.2em;
|
||||
}
|
||||
.cload-edit-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.cload-edit-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
font-size: 0.85em;
|
||||
color: var(--muted);
|
||||
}
|
||||
.cload-cpu-input,
|
||||
.cload-mem-input {
|
||||
width: 7em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.cload-save-btn {
|
||||
padding: 0.15em 0.6em;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.cload-edit-hint {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.cload-edit-err {
|
||||
color: var(--red);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
/* Remove the now-dead `.rqe-step` rule (the `step` sub-step label was
|
||||
retired from the wire in `feat(job_queue): retire the now-off-wire step
|
||||
sub-step label` — the rule has had no JS referents since then). */
|
||||
|
|
|
|||
Loading…
Reference in a new issue