-
+
-
@@ -133,7 +123,7 @@
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. -->
-
-
@@ -201,7 +191,7 @@
(GET /api/capabilities, GET /api/tool-groups) so new entries
require no UI change. Saving POSTs to the respective
/{agent} endpoint and queues a rebuild. -->
-
@@ -233,7 +223,7 @@
`schedules_changed` SSE; tab activation re-fetches as a
safety net for disconnect windows.
See docs/web-ui.md::SCH3DUL3S tab. -->
-
@@ -262,7 +252,7 @@
/api/stats-hive?window=, fetched on tab activation + on
window change. Per-agent trend charts stay on each agent's
own /stats page. -->
-
@@ -297,7 +287,7 @@
The same IDs that used to live in the tab strip migrated
here unchanged so `NOTIF.bind()` in common.js wires them
without any JS change. -->
-
diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js
index ca53f56d..f773987e 100644
--- a/frontend/packages/dashboard/src/tabs.js
+++ b/frontend/packages/dashboard/src/tabs.js
@@ -18,6 +18,7 @@ import {
makePathLink, appendText, appendLinkified,
openStream, renderServerWarnings,
} from './common.js';
+import { createTabStrip } from '@hive/shared/tabs.js';
// mdNode (in common.js) reads `window.marked` for the markdown side
// panel preview path. Set it here on the dashboard entry so file
@@ -4057,28 +4058,20 @@ window.marked = marked;
// (`/flow.html`) reached via the tab-strip link. 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).
- const TABS = ['swarm', 'call', 'system', 'permissions', 'schedules', 'stats', 'settings'];
- function activateTab(name) {
- const target = TABS.includes(name) ? name : TABS[0];
- for (const t of TABS) {
- const tab = $('tab-' + t);
- const pane = $('tab-pane-' + t);
- if (tab) tab.classList.toggle('active', t === target);
- if (pane) pane.classList.toggle('tab-pane-active', t === target);
- }
+ // The shared hash-routed tab strip (@hive/shared/tabs.js) owns the
+ // tab/pane toggle + aria-selected + routing; `activateTab` runs the
+ // per-tab side-effects via the strip's onShow. Constructed below (after
+ // the lazy-load fns it calls are defined). The responsive overflow ⋮
+ // menu was dropped — if the strip ever runs out of room we move panes
+ // 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).
- // Re-render the bar so the toggle takes effect immediately
- // on hashchange without waiting for the next SSE update.
document.body.dataset.activeTab = target;
renderSelectionBar(Array.from(containersState.values()));
- // Keep overflow button active state in sync after tab change.
- updateTabbarOverflow();
- // Re-fetch schedules on activation as a safety net (SSE covers
- // live mutations but re-sync ensures consistency after disconnect
- // windows or approval-path inserts that don't yet emit). Also
- // re-fetch reminders on SCH3DUL3S activation since both sections
- // live on the same tab.
+ // Re-fetch on activation as a safety net: SSE covers live mutations,
+ // re-sync covers disconnect windows / approval-path inserts that
+ // don't yet emit. SCH3DUL3S also re-fetches reminders (same tab).
if (target === 'schedules') { refreshSchedules(); refreshReminders(); }
// Permissions tables: SSE covers worker-applied changes
// (capabilities_changed / tool_groups_changed); re-fetch on
@@ -4095,25 +4088,6 @@ window.marked = marked;
// open (cpu needs a short two-sample read each refresh).
if (target === 'system') { startContainerLoadPolling(); } else { stopContainerLoadPolling(); }
}
- // ─── tabbar overflow menu ────────────────────────────────────────────────
- // Tabs with `data-overflow="default"` (LOGS, SETTINGS) always live in
- // the ⋮ dropdown. When the bar is too narrow to show all remaining tabs,
- // rightmost tabs spill into the dropdown too (right-to-left).
- //
- // Implementation: all tabs stay in the DOM. The ⋮ wrapper sits at the
- // flex end. `tab-overflowed` hides a tab from the bar (display:none).
- // The dropdown is rebuilt from scratch on every call — it holds cloned
- // /