import { useEffect, useMemo, useState, type ReactNode } from 'react'; import { copy } from './copy'; import { OperatorCommandBar } from './OperatorCommandBar'; import { routeFromLocation, type RoutePath } from './routes'; import { WORKSPACE_EVENT, isFavorite, readWorkspaceState, recordRecent, removeSavedView, saveCurrentView, toggleFavorite, } from './operatorWorkspace'; type SectionId = 'command' | 'infrastructure' | 'workloads' | 'services' | 'response' | 'manage'; type NavigationDefinition = { path: RoutePath; label: string; icon: string; group: string; section: SectionId; primary: boolean; }; export const navigation = [ { path: '/', label: copy.navigation.overview, icon: '⌂', group: copy.navigation.groups.command, section: 'command', primary: true }, { path: '/dashboards', label: copy.navigation.dashboards, icon: '▦', group: copy.navigation.groups.command, section: 'command', primary: true }, { path: '/explore', label: copy.navigation.explore, icon: '⌁', group: copy.navigation.groups.command, section: 'command', primary: true }, { path: '/host', label: copy.navigation.host, icon: '▣', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: true }, { path: '/processes', label: copy.navigation.processes, icon: '≋', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/storage', label: copy.navigation.storage, icon: '▤', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: true }, { path: '/array', label: copy.navigation.array, icon: '▥', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/disks', label: copy.navigation.disks, icon: '◉', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/pools', label: copy.navigation.pools, icon: '◫', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/shares', label: copy.navigation.shares, icon: '⇄', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/capacity', label: copy.navigation.capacity, icon: '⌁', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/network', label: copy.navigation.network, icon: '⌘', group: copy.navigation.groups.infrastructure, section: 'infrastructure', primary: false }, { path: '/applications', label: copy.navigation.applications, icon: '◆', group: copy.navigation.groups.workloads, section: 'workloads', primary: true }, { path: '/containers', label: copy.navigation.containers, icon: '⬡', group: copy.navigation.groups.workloads, section: 'workloads', primary: false }, { path: '/services', label: copy.navigation.services, icon: '◉', group: copy.navigation.groups.services, section: 'services', primary: true }, { path: '/topology', label: copy.navigation.topology, icon: '⌬', group: copy.navigation.groups.services, section: 'services', primary: false }, { path: '/incidents', label: copy.navigation.incidents, icon: '△', group: copy.navigation.groups.response, section: 'response', primary: true }, { path: '/alerts', label: copy.navigation.alerts, icon: '!', group: copy.navigation.groups.response, section: 'response', primary: false }, { path: '/events', label: copy.navigation.events, icon: '≡', group: copy.navigation.groups.response, section: 'response', primary: false }, { path: '/inventory', label: copy.navigation.inventory, icon: '▥', group: copy.navigation.groups.manage, section: 'manage', primary: true }, { path: '/settings', label: copy.navigation.settings, icon: '⚙', group: copy.navigation.groups.manage, section: 'manage', primary: true }, { path: '/status', label: copy.navigation.status, icon: '♥', group: copy.navigation.groups.manage, section: 'manage', primary: false }, { path: '/onboarding', label: copy.navigation.onboarding, icon: '→', group: copy.navigation.groups.manage, section: 'manage', primary: false }, { path: '/wallboard', label: copy.navigation.wallboard, icon: '▰', group: copy.navigation.groups.manage, section: 'manage', primary: false }, ] as const satisfies ReadonlyArray; export type NavigationItem = (typeof navigation)[number]; const sectionLabels: Record = { command: 'Operator', infrastructure: 'Infrastructuur', workloads: 'Workloads', services: 'Services', response: 'Response', manage: 'Beheer', }; const primaryNavigation = navigation.filter((item) => item.primary); const mobilePrimaryOrder = new Map([['/', 0], ['/incidents', 1], ['/containers', 2], ['/storage', 3], ['/services', 4]]); const mobilePrimaryNavigation = navigation.filter((item) => mobilePrimaryOrder.has(item.path)).sort((left, right) => mobilePrimaryOrder.get(left.path)! - mobilePrimaryOrder.get(right.path)!); const mobileMoreNavigation = navigation.filter((item) => !mobilePrimaryOrder.has(item.path)); const navigationGroups = Array.from(new Set(primaryNavigation.map((item) => item.group))); function matchesRoute(route: RoutePath, path: RoutePath): boolean { return route === path || (path !== '/' && route.startsWith(path + '/')); } function routeDefinition(route: RoutePath): NavigationItem { return [...navigation] .sort((left, right) => right.path.length - left.path.length) .find((item) => matchesRoute(route, item.path)) ?? navigation[0]; } function detailSegment(route: RoutePath, item: NavigationItem): string | null { if (route === item.path) return null; const raw = route.slice(item.path.length + 1).split('/')[0]; if (!raw) return null; try { return decodeURIComponent(raw).slice(0, 80); } catch { return raw.slice(0, 80); } } export function navigate(path: string): void { const from = window.location.pathname + window.location.search; if (path === from) return; window.history.pushState({ pulseFrom: from }, '', path); window.dispatchEvent(new PopStateEvent('popstate')); } function NavigationLink({ item, label = item.label, domain = false }: { item: NavigationItem; label?: string; domain?: boolean }) { const active = matchesRoute(routeFromLocation(window.location.pathname), item.path); return
  • { event.preventDefault(); navigate(item.path); }}>{label}
  • ; } function DesktopNavigation({ route }: { route: RoutePath }) { const activeItem = routeDefinition(route); const activeGroup = activeItem.group; const [openGroups, setOpenGroups] = useState>(() => new Set([navigationGroups[0], activeGroup])); useEffect(() => setOpenGroups((current) => current.has(activeGroup) ? current : new Set([...current, activeGroup])), [activeGroup]); return ; } function ShellStatusBadge({ label, tone }: { label: string; tone: 'unknown' | 'ready' }) { return {label}; } function WorkspaceContext({ route, currentNavigation }: { route: RoutePath; currentNavigation: NavigationItem }) { const [, setVersion] = useState(0); useEffect(() => { const refresh = () => setVersion((value) => value + 1); window.addEventListener(WORKSPACE_EVENT, refresh); return () => window.removeEventListener(WORKSPACE_EVENT, refresh); }, []); const item = routeDefinition(route); const sectionItems = navigation.filter((entry) => entry.section === item.section && entry.path !== '/wallboard'); const detail = detailSegment(route, item); const currentPath = window.location.pathname + window.location.search; const favorite = isFavorite(currentPath); const saved = readWorkspaceState().views.some((entry) => entry.path === currentPath); const from = typeof window.history.state?.pulseFrom === 'string' ? window.history.state.pulseFrom as string : ''; const fallback = sectionItems.find((entry) => entry.primary)?.path ?? '/'; const backTarget = from && from !== currentPath ? from : (route !== fallback ? fallback : ''); const pageLabel = detail ? currentNavigation.label + ' · ' + detail : currentNavigation.label; useEffect(() => { recordRecent(pageLabel, currentPath); }, [pageLabel, currentPath]); return
    {backTarget && }
    ; } export function OperatorAppShell({ route, shellStatus, currentNavigation, children }: { route: RoutePath; shellStatus: { label: string; tone: 'unknown' | 'ready'; detail: string }; currentNavigation: NavigationItem; children: ReactNode }) { const resolved = useMemo(() => routeDefinition(route), [route]); return
    {copy.accessibility.skipToContent}
    {children}
    ; }