swarm-ui: show the swarm's name as the page title and top-left brand
New GET /api/swarm on swarm-controller, backed by services.hyperhive.swarm.name (SWARM_CONTROLLER_NAME env var, same optionalAttrs-gated-on-option-resolving shape queueEnv/forgeEnv/etc. already use). swarm-ui's <Shell> fetches it once and sets both document.title and the header's brand text; falls back to the existing static "hyperhive swarm" label when the operator never set a name or the fetch fails. Extracted the swarm-queue connect block out of main() into its own connect_status_reader() fn to keep main() under clippy's line-count lint after adding the new field wiring — no behavior change, same comments moved as-is.
This commit is contained in:
parent
d14963ad2b
commit
3643eccf22
3 changed files with 161 additions and 44 deletions
|
|
@ -12,6 +12,7 @@
|
|||
// has exactly one place that needs to know its own nav, and this is
|
||||
// it. Grows additively as real routes land (a swarm-wide agent roster
|
||||
// is next); no speculative entries.
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
import type { ComponentChildren } from 'preact';
|
||||
import { Link, useRoute } from 'wouter-preact';
|
||||
import { LinksMenu } from './LinksMenu.js';
|
||||
|
|
@ -24,6 +25,12 @@ const NAV_ITEMS: { href: string; label: string }[] = [
|
|||
{ href: '/components', label: 'components' },
|
||||
];
|
||||
|
||||
// Static fallback — matches `index.html`'s `<title>` default, so a page
|
||||
// never flashes something else before the fetch below resolves, and an
|
||||
// operator who never set `services.hyperhive.swarm.name` sees the exact
|
||||
// same generic label the pre-fetch page already showed, not a blank.
|
||||
const DEFAULT_BRAND = 'hyperhive swarm';
|
||||
|
||||
function NavLink({ href, label }: { href: string; label: string }) {
|
||||
const [active] = useRoute(href);
|
||||
return (
|
||||
|
|
@ -34,10 +41,34 @@ function NavLink({ href, label }: { href: string; label: string }) {
|
|||
}
|
||||
|
||||
export function Shell({ children }: { children: ComponentChildren }) {
|
||||
const [swarmName, setSwarmName] = useState<string | null>(null);
|
||||
|
||||
// Fetched once here, not per-page: every route mounts inside one
|
||||
// `<Shell>`, and the swarm's name doesn't change within a page
|
||||
// visit. A fetch failure is silently ignored — `swarmName` just stays
|
||||
// `null` and the header/title fall back to `DEFAULT_BRAND`, same as
|
||||
// an operator who never configured a name; this label is cosmetic,
|
||||
// not worth an `ApiErrorPanel`.
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const r = await fetch('/api/swarm');
|
||||
if (!r.ok) return;
|
||||
const data = (await r.json()) as { name: string | null };
|
||||
if (data.name) setSwarmName(data.name);
|
||||
})().catch(() => {
|
||||
/* cosmetic only — see comment above */
|
||||
});
|
||||
}, []);
|
||||
|
||||
const brand = swarmName ?? DEFAULT_BRAND;
|
||||
useEffect(() => {
|
||||
document.title = brand;
|
||||
}, [brand]);
|
||||
|
||||
return (
|
||||
<div class="shell">
|
||||
<header class="shell-header">
|
||||
<span class="shell-brand">hyperhive swarm</span>
|
||||
<span class="shell-brand">{brand}</span>
|
||||
<nav class="shell-nav">
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<NavLink key={item.href} href={item.href} label={item.label} />
|
||||
|
|
|
|||
Loading…
Reference in a new issue