frontend: add <hive-tab-strip>, convert logs/credentials/core/builds tabbars

Every sub-page tabbar (logs.html, credentials.html, core.html,
builds.html) hand-wrote the same <nav class="hive-tabbar"><a
class="hive-tab">...</a></nav> boilerplate and then called
createTabStrip() on it after the fact. Add <hive-tab-strip>, a
markup-owning custom element (same reuse-boundary pattern as
<hive-menu>/<hive-side-panel>) that renders that markup from a
declarative tabs list, then wires the existing createTabStrip()
behaviour over what it just rendered — no behaviour duplication.

Convert all four sites to use it: each page's JS now calls
`.configure({ tabs, defaultId, onShow })` on the tabbar element instead
of `createTabStrip(el, opts)`, and configure() returns the identical
{ show, active } shape so nothing downstream changes. builds.js's
rebuild-queue count pill (builds-tab-count-rebuild) is expressed as a
tab's `badgeId` and renders nested in the same spot.

The dashboard's own tabbar and the two no-pane stats time-range
pickers are a different markup/behaviour shape and are intentionally
left alone.
This commit is contained in:
iris 2026-08-02 04:00:40 +02:00 committed by mara
commit 435ef193e1
10 changed files with 103 additions and 75 deletions

View file

@ -1,8 +1,7 @@
// C0R3 page entry (/core.html). The host/coordinator surface carved out
// of the dashboard's old SYST3M tab into its own standalone page so the
// dashboard tab strip stays lean. Two sub-tabs via the shared
// createTabStrip (default = K3PT ST4T3): kept state (tombstones) and
// container load.
// dashboard tab strip stays lean. Two sub-tabs via <hive-tab-strip>
// (default = K3PT ST4T3): kept state (tombstones) and container load.
//
// Rebuild queue + meta inputs have moved to /builds.html (the build
// lifecycle hub). This page is its own esbuild bundle with its own
@ -13,7 +12,7 @@
import { $, form, openStream, initServerWarnings } from './common.js';
import { el } from '@hive/shared/dom.js';
import { asyncBtn, bindAsyncForms } from '@hive/shared/forms.js';
import { createTabStrip } from '@hive/shared/tabs.js';
import '@hive/shared/hive-tab-strip.js';
// ─── derived state (own copies; this bundle has its own runtime) ──────────
let tombstonesState = [];
@ -490,7 +489,12 @@ async function init() {
// 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).
createTabStrip(document.getElementById('core-tabbar'), {
document.getElementById('core-tabbar').configure({
tabs: [
{ id: 'kept', label: 'K3PT ST4T3' },
{ id: 'load', label: 'C0NT41N3R L04D' },
{ id: 'infra', label: '1NFR4' },
],
defaultId: 'kept',
onShow: (id) => {
if (id === 'load') startContainerLoadPolling();