dashboard: serve the dashboard at /, fold kept state in as a tab, add a pages menu
Drop the H0M3 tile hub and the core page. The dashboard is now the index; kept state is its fifth tab. A pages menu in the chrome links flow, stats, API docs and the swarm UI. The swarm apex URL comes from services.hyperhive.swarm.domain via HIVE_SWARM_PUBLIC_URL and the new swarm_public_url field of the state snapshot.
This commit is contained in:
parent
265f8a47cc
commit
0622736b30
35 changed files with 661 additions and 986 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// /dashboard.html entry point: tab renderers + tab routing + refreshState.
|
||||
// the dashboard entry point: tab renderers + tab routing + refreshState.
|
||||
// Reads /api/state on cold load and after every async-form submit; live
|
||||
// updates run through `applyXxx` mutation handlers triggered by the
|
||||
// dashboard event stream (subscribed via `openStream` from common.js). See
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
// Pure helpers (DOM, side panel, path linkification)
|
||||
// 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.
|
||||
// `index.html` each load their own bundle.
|
||||
// 4G3NTS (containers) domain lives in `./agents.js`.
|
||||
|
||||
import { marked } from "marked";
|
||||
|
|
@ -36,6 +36,13 @@ import {
|
|||
rebuildCount,
|
||||
syncBuildsFromSnapshot,
|
||||
} from "./builds.js";
|
||||
import {
|
||||
applyTombstonesChanged,
|
||||
keptCount,
|
||||
renderKept,
|
||||
syncKeptFromSnapshot,
|
||||
} from "./kept.js";
|
||||
import { renderLinksMenu } from "./links-menu.js";
|
||||
|
||||
// mdNode (in common.js) reads `window.marked` for the markdown side
|
||||
// panel preview path. Set it here on the dashboard entry so file
|
||||
|
|
@ -44,8 +51,8 @@ window.marked = marked;
|
|||
|
||||
(() => {
|
||||
// ─── async forms ────────────────────────────────────────────────────────
|
||||
// Shared `data-async` submit interceptor (now in common.js so /core.html's
|
||||
// bundle gets it too). On success it re-runs refreshState unless the form
|
||||
// Shared `data-async` submit interceptor (in common.js, shared with the other
|
||||
// pages' bundles). On success it re-runs refreshState unless the form
|
||||
// opts out via `data-no-refresh` (its mutation arrives via an SSE event).
|
||||
bindAsyncForms(() => refreshState());
|
||||
|
||||
|
|
@ -95,6 +102,22 @@ window.marked = marked;
|
|||
});
|
||||
}
|
||||
|
||||
// Rev line in the footer: absent when the flake ref isn't a local path
|
||||
// pin (a bare `github:` url has no on-disk rev to canonicalize), so it
|
||||
// stays hidden rather than showing a placeholder. `hyperhive_rev`
|
||||
// canonicalizes to a nix store path (/nix/store/<hash>-<pname>); the
|
||||
// part that varies between builds is the hash, so slice that out rather
|
||||
// than truncating from the tail. Falls back to a plain head-slice for a
|
||||
// non-store path (e.g. a bare local dir during dev).
|
||||
function renderHiveRev(rev) {
|
||||
const node = $("hive-rev");
|
||||
if (!node || !rev) return;
|
||||
const storeMatch = rev.match(/^\/nix\/store\/([^-]+)/);
|
||||
node.textContent = `rev ${(storeMatch ? storeMatch[1] : rev).slice(0, 12)}`;
|
||||
node.title = rev;
|
||||
node.hidden = false;
|
||||
}
|
||||
|
||||
async function refreshState() {
|
||||
// Don't yank the form out from under the operator. Try again
|
||||
// shortly on the next tick; eventually they'll blur and the
|
||||
|
|
@ -144,7 +167,11 @@ window.marked = marked;
|
|||
// mount's own effect handles the actual fetch.
|
||||
initJobqRollup();
|
||||
syncBuildsFromSnapshot(s);
|
||||
syncKeptFromSnapshot(s);
|
||||
renderContainers(s);
|
||||
renderKept();
|
||||
renderLinksMenu(s);
|
||||
renderHiveRev(s.hyperhive_rev);
|
||||
restoreOpenDetails(openDetails);
|
||||
// No periodic refresh timer. Phase 6 covers every container
|
||||
// mutation with `ContainerStateChanged` / `ContainerRemoved`
|
||||
|
|
@ -181,7 +208,7 @@ window.marked = marked;
|
|||
// lost during the disconnect window (same pattern as flow.js's
|
||||
// onStreamOpen).
|
||||
//
|
||||
// Both /dashboard.html and /flow.html subscribe to `/api/dashboard/stream`
|
||||
// Both the dashboard and /flow.html subscribe to `/api/dashboard/stream`
|
||||
// and filter client-side — the dashboard ignores broker traffic
|
||||
// and FL0W ignores mutation events.
|
||||
const MUTATION_HANDLERS = {
|
||||
|
|
@ -198,6 +225,7 @@ window.marked = marked;
|
|||
},
|
||||
meta_inputs_changed: onMetaInputsChanged,
|
||||
meta_update_running: onMetaUpdateRunning,
|
||||
tombstones_changed: applyTombstonesChanged,
|
||||
};
|
||||
(function bindDashboardStream() {
|
||||
// Route through the SharedWorker so all open hyperhive tabs on the
|
||||
|
|
@ -208,12 +236,12 @@ window.marked = marked;
|
|||
// fallback when SharedWorker isn't supported.
|
||||
//
|
||||
// kinds= matches MUTATION_HANDLERS verbatim, so the stream carries
|
||||
// only the 7 wire kinds this page acts on.
|
||||
// only the 8 wire kinds this page acts on.
|
||||
const es = openStream(
|
||||
"/api/dashboard/stream?kinds=" +
|
||||
"transient_set,transient_cleared," +
|
||||
"container_state_changed,container_removed,rebuild_queue_changed," +
|
||||
"meta_inputs_changed,meta_update_running",
|
||||
"meta_inputs_changed,meta_update_running,tombstones_changed",
|
||||
);
|
||||
es.onmessage = (e) => {
|
||||
let ev;
|
||||
|
|
@ -245,11 +273,11 @@ window.marked = marked;
|
|||
})();
|
||||
|
||||
// ─── tab routing ───────────────────────────────────────────────────────
|
||||
// Hash-based: `#agents` / `#rebuild` / `#meta` / `#buildlogs`
|
||||
// Hash-based: `#agents` / `#rebuild` / `#meta` / `#buildlogs` / `#kept`
|
||||
// activate the matching pane on the dashboard. Empty
|
||||
// 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
|
||||
// the pages menu (links-menu.js). Tab routing only
|
||||
// applies when the tab DOM is present (e.g. not on the flow page
|
||||
// itself, where these elements don't exist and the loop no-ops).
|
||||
// The shared hash-routed tab strip (@hive/shared/tabs.js) owns the
|
||||
|
|
@ -299,6 +327,8 @@ window.marked = marked;
|
|||
setTabCount("agents", stale);
|
||||
// R3BU1LD QU3U3 — rebuilds in flight.
|
||||
setTabCount("rebuild", rebuildCount());
|
||||
// K3PT ST4T3 — entries of kept state.
|
||||
setTabCount("kept", keptCount());
|
||||
}
|
||||
// Poll the state stores on a 1s tick to keep the pill counts in
|
||||
// sync. The state stores are mutated synchronously by every SSE
|
||||
|
|
|
|||
Loading…
Reference in a new issue