#406 was the JS-split refactor: pull shared helpers into common.js (step 1), pull the flow-only IIFEs into flow.js (step 2), then rename the legacy combined entry from app.js to tabs.js (step 3 — this commit) to reflect that the bundle now owns the dashboard tabs surface only. What moved: - `frontend/packages/dashboard/src/app.js` → `tabs.js` - `build.mjs` entry: `src('app.js')` → `src('tabs.js')`; output is now `static/tabs.js` - `index.html` `<script>` src: `/static/app.js` → `/static/tabs.js`; the FL0W-section comment retouched - `flow.html` reference from `/static/app.js`-as-tabs to `/static/tabs.js`; notif + offscreen-inbox comments rewired to point at the correct owners (common.js for NOTIF, flow.js for renderInbox) - `common.js`, `flow.js`, `tabs.js` headers: scrub stale "app.js" references; document that #406 steps 2 + 3 are done and both pages import directly from common.js - `dashboard.css` comments: every "by app.js" → "by tabs.js" - `docs/web-ui.md`, `docs/conventions.md`: legacy `assets/app.js` → `assets/tabs.js` (the path prefix is itself stale from a much-earlier rename, but consistent with the rest of those docs) - `CLAUDE.md` file map: refresh the dashboard package's src/ and dist/ layouts to reflect the post-split shape (tabs.js, flow.js, common.js, stream-worker.js) What did NOT move: - `frontend/packages/agent/src/app.js` (per-agent UI entry) stays named `app.js` — it's a separate package, has only one entry point, no split happened there - The two "no-op when target absent" guards in renderContainers and renderQuestions are kept as belt-and-suspenders for any future page that adds tabs.js without the corresponding sections; comments updated to note this rather than the pre-split flow.html reason Functional behaviour identical; this is a pure rename + comment sweep.
226 lines
12 KiB
HTML
226 lines
12 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>hyperhive // h1ve-c0re</title>
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
<link rel="stylesheet" href="/static/dashboard.css">
|
|
</head>
|
|
<body class="dashboard-shell">
|
|
|
|
<!-- Sticky chrome — just the tab strip now (#389 follow-up: the
|
|
"WE ARE THE WIRED" slug moved out of chrome entirely and lives
|
|
at the page footer below `<main>`; chrome is navigation only).
|
|
Tabs route via the URL hash so F5 / back-button / shared links
|
|
keep you on the same view. JS owns the actual show/hide; this
|
|
is just the menu. -->
|
|
<header class="dashboard-chrome">
|
|
<nav class="tabbar" id="tabbar" role="tablist">
|
|
<a class="tab" id="tab-swarm" href="#swarm" role="tab"
|
|
aria-controls="tab-pane-swarm"
|
|
data-tab="swarm">
|
|
<span class="tab-label">◆ SW4RM ◆</span>
|
|
<span class="tab-count" id="tab-count-swarm" hidden></span>
|
|
</a>
|
|
<a class="tab" id="tab-call" href="#call" role="tab"
|
|
aria-controls="tab-pane-call"
|
|
data-tab="call">
|
|
<span class="tab-label">◆ Y3R C4LL ◆</span>
|
|
<span class="tab-count tab-count-attn" id="tab-count-call" hidden></span>
|
|
</a>
|
|
<a class="tab" id="tab-system" href="#system" role="tab"
|
|
aria-controls="tab-pane-system"
|
|
data-tab="system">
|
|
<span class="tab-label">◆ SYST3M ◆</span>
|
|
<span class="tab-count" id="tab-count-system" hidden></span>
|
|
</a>
|
|
<!-- SCH3DUL3S (#459): scheduled-prompts surface. List of
|
|
queued schedules + an operator-direct creation form.
|
|
Count pill mirrors the active (non-cancelled) schedule
|
|
count; hidden when zero. -->
|
|
<a class="tab" id="tab-schedules" href="#schedules" role="tab"
|
|
aria-controls="tab-pane-schedules"
|
|
data-tab="schedules">
|
|
<span class="tab-label">◆ SCH3DUL3S ◆</span>
|
|
<span class="tab-count" id="tab-count-schedules" hidden></span>
|
|
</a>
|
|
|
|
<!-- FL0W is its own page (`/flow.html`), not a tab — per
|
|
operator @ #369#issuecomment-3437 ("yes terminal can be a
|
|
separate page"). The link lives in the tab strip so it
|
|
reads as a peer surface; clicking navigates rather than
|
|
swapping panes in place. Count pill mirrors the dashboard's
|
|
operator-inbox length and is hidden when zero. -->
|
|
<a class="tab tab-link" id="tab-flow" href="/flow.html"
|
|
title="open the all-agents chat in a dedicated full-page terminal">
|
|
<span class="tab-label">◆ FL0W ◆ →</span>
|
|
<span class="tab-count" id="tab-count-flow" hidden></span>
|
|
</a>
|
|
|
|
<!-- Notification controls live in the chrome (always-on
|
|
ergonomics; not tab-specific). -->
|
|
<div id="notif-row" class="notif-row">
|
|
<button type="button" id="notif-enable" class="btn btn-notif" hidden>🔔 enable notifications</button>
|
|
<button type="button" id="notif-mute" class="btn btn-notif" hidden>🔕 mute</button>
|
|
<button type="button" id="notif-unmute" class="btn btn-notif" hidden>🔔 unmute</button>
|
|
<span id="notif-status" class="meta" hidden></span>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<!-- Tab panes. Exactly one is `.tab-pane-active` at a time;
|
|
JS toggles based on the URL hash + `hashchange` events. -->
|
|
<main class="dashboard-main">
|
|
|
|
<!-- SW4RM: the swarm itself. Container cards (the central thing
|
|
the operator looks at) and rebuild queue / cascade visualisation
|
|
that drives them. The tab label itself reads SW4RM, so the
|
|
inline C0NTAINERS h2 heading + divider would be redundant —
|
|
dropped per #385. -->
|
|
<section class="tab-pane" id="tab-pane-swarm"
|
|
role="tabpanel" aria-labelledby="tab-swarm">
|
|
<div id="containers-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Y3R C4LL: things blocked on operator decision. Approvals +
|
|
questions read as the same concept ("something is waiting on
|
|
you"); both surface their full bodies inline so the operator
|
|
can decide without leaving the pane. -->
|
|
<section class="tab-pane" id="tab-pane-call"
|
|
role="tabpanel" aria-labelledby="tab-call">
|
|
<h2>◆ P3NDING APPR0VALS ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<div id="approvals-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
|
|
<h2>◆ M1ND H4S QU3STI0NS ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<div id="questions-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- SYST3M: passive / rare-interaction state. Meta inputs (lock
|
|
bumps), rebuild queue (watch only), kept state from previous
|
|
tombstoned agents. Queued reminders moved to the SCH3DUL3S
|
|
tab in #460 — they're conceptually "fire X at time Y" too,
|
|
just self-scheduled by agents instead of operator-set.
|
|
Headings stay; the per-section content auto-compresses to a
|
|
one-line summary when empty (separate JS toggle). -->
|
|
<section class="tab-pane" id="tab-pane-system"
|
|
role="tabpanel" aria-labelledby="tab-system">
|
|
<h2>◆ M3T4 1NPUTS ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<p class="meta">select inputs to <code>nix flake update</code> in <code>/meta/</code>. selected agents rebuild in sequence after the lock bump; manager learns each outcome via the usual <code>rebuilt</code> system event.</p>
|
|
<div id="meta-inputs-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
|
|
<h2>◆ R3BU1LD QU3U3 ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<p class="meta">pending + running rebuilds, meta-updates, and first-spawns. one runs at a time; meta-update cascades nest under their parent. dedup: re-enqueueing a still-queued op collapses into the existing entry.</p>
|
|
<div id="rebuild-queue-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
|
|
<h2>◆ K3PT ST4T3 ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<div id="tombstones-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- SCH3DUL3S (#459): scheduled prompts. operator-direct creation
|
|
form at the top (POST /api/schedules, no approval gate), live
|
|
schedules list below (GET /api/schedules) with per-target
|
|
last-fired timestamps + result, plus per-target / whole-row
|
|
cancel buttons (POST /api/schedules/{id}/cancel). #444 backend
|
|
doesn't emit a SchedulesChanged dashboard event yet, so the
|
|
list re-fetches on tab activation + after each form/cancel
|
|
submit. Live SSE wiring is the future PR C. -->
|
|
<section class="tab-pane" id="tab-pane-schedules"
|
|
role="tabpanel" aria-labelledby="tab-schedules">
|
|
<h2>◆ N3W SCH3DUL3 ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<p class="meta">queue a prompt to fire at a future time. operator-direct (no approval gate); recurring when an interval is set. targets are any known agent name or <code>operator</code> / <code>manager</code>.</p>
|
|
<div id="schedule-new-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
|
|
<h2>◆ QU3U3D SCH3DUL3S ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<p class="meta">all schedules currently in the table. expand each card to see per-target firing history. cancel a single target with the row button or the whole schedule with <code>✕ cancel all</code>.</p>
|
|
<div id="schedules-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
|
|
<!-- QU3U3D R3M1ND3RS (#460): self-scheduled agent reminders.
|
|
Moved here from the SYST3M tab so the operator has one
|
|
place for everything that fires at a future time —
|
|
operator-set schedules above, agent-self reminders here.
|
|
Backed by GET /api/reminders; refresh handled by
|
|
refreshReminders() (called from refreshState). -->
|
|
<h2>◆ QU3U3D R3M1ND3RS ◆</h2>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<p class="meta">reminders agents have queued for themselves but not yet delivered. cancel to drop a stuck or unwanted entry.</p>
|
|
<div id="reminders-section">
|
|
<p class="meta">loading…</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- FL0W: lives on its own page now (`/flow.html`). The
|
|
message-flow + inbox + compose DOM only exists there — when
|
|
tabs.js boots on this page the corresponding renderers
|
|
no-op silently (each guard is `if (!el) return`). -->
|
|
|
|
</main>
|
|
|
|
<footer>
|
|
<pre class="banner banner-thin">░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░</pre>
|
|
<div class="divider">══════════════════════════════════════════════════════════════</div>
|
|
<p>▲△▲ <a href="https://git.berlin.ccc.de/vinzenz/hyperhive">hyperhive</a> ▲△▲ hive-c0re on this host ▲△▲</p>
|
|
</footer>
|
|
|
|
<!-- Slide-in detail panel. Long content (clicked file previews,
|
|
approval diffs, journald logs, applied config) opens here
|
|
instead of expanding inline. Singleton — JS swaps the title +
|
|
body and toggles `.open`. Lives outside the tab panes so it
|
|
overlays any active tab. -->
|
|
<div id="side-panel" class="side-panel" aria-hidden="true">
|
|
<div class="side-panel-backdrop" id="side-panel-backdrop"></div>
|
|
<aside class="side-panel-drawer" role="dialog" aria-modal="true"
|
|
aria-labelledby="side-panel-title">
|
|
<header class="side-panel-head">
|
|
<span class="side-panel-title" id="side-panel-title"></span>
|
|
<button type="button" class="side-panel-close" id="side-panel-close"
|
|
title="close (esc)">✕</button>
|
|
</header>
|
|
<div class="side-panel-body" id="side-panel-body"></div>
|
|
</aside>
|
|
</div>
|
|
|
|
<!-- Selection action bar (#443). Sticky-bottom strip that slides
|
|
into view when one or more agent cards is selected (click the
|
|
icon to toggle). Shows the selection count + actions that
|
|
apply to ALL selected; disabled-with-tooltip for actions that
|
|
don't (mara picked option B). Hidden when selection is empty. -->
|
|
<div id="selection-bar" class="selection-bar" hidden role="toolbar"
|
|
aria-label="bulk agent actions">
|
|
<span class="selection-count" id="selection-count"></span>
|
|
<span class="selection-names" id="selection-names"></span>
|
|
<span class="selection-actions" id="selection-actions"></span>
|
|
<button type="button" class="btn selection-clear" id="selection-clear"
|
|
title="clear selection (esc)">✕ clear</button>
|
|
</div>
|
|
|
|
<!-- Single bundled entry (#406 step 3 — renamed from app.js to
|
|
tabs.js since this bundle is the dashboard *tabs* surface only;
|
|
flow.html has its own flow.js bundle). esbuild folds
|
|
@hive/shared/terminal.js and the marked npm package into
|
|
tabs.js; load order is preserved by the module bundler. -->
|
|
<script type="module" src="/static/tabs.js" defer></script>
|
|
</body>
|
|
</html>
|