"""Navigation IA for the Phase 1 operator console shell (#638). Single source of truth for the console navigation so ``webui/layout.py`` and the ``webui/app.py`` route table stay aligned with epic #631. Read-only: every destination is a GET view or a Phase 1 placeholder. No mutation links. Nav groups follow the #631 Phase 1 information architecture: Health, Traffic, Runtime/Sessions, Projects, Inventory, Timeline, Policy (placeholder), and Insights (placeholder). Later-phase surfaces are declared as ``stub`` items and backed by ``STUB_PAGES`` so their nav links resolve to a graceful placeholder instead of a 404. """ from __future__ import annotations from dataclasses import dataclass @dataclass(frozen=True) class NavItem: """A single navigation destination. ``status`` is ``"live"`` for implemented views and ``"stub"`` for Phase 1 placeholders whose backing view lands in a later child issue. """ href: str label: str status: str = "live" @dataclass(frozen=True) class NavGroup: label: str items: tuple[NavItem, ...] NAV_GROUPS: tuple[NavGroup, ...] = ( NavGroup("Health", ( NavItem("/health", "Liveness"), )), NavGroup("Traffic", ( NavItem("/queue", "Queue"), NavItem("/leases", "Leases"), NavItem("/actions", "Actions"), )), NavGroup("Runtime/Sessions", ( NavItem("/runtime", "Runtime health"), NavItem("/sessions", "Sessions", "stub"), )), NavGroup("Projects", ( NavItem("/projects", "Projects"), )), NavGroup("Inventory", ( NavItem("/inventory", "Inventory", "stub"), NavItem("/worktrees", "Worktrees"), )), NavGroup("Timeline", ( NavItem("/timeline", "Timeline", "stub"), )), NavGroup("Policy", ( NavItem("/policy", "Policy", "stub"), NavItem("/prompts", "Prompts"), )), NavGroup("Insights", ( NavItem("/insights", "Insights", "stub"), NavItem("/audit", "Audit"), )), ) # Phase 1 placeholder destinations whose backing views land in later child # issues of epic #631. Each maps a path to (title, description). Routes are # registered so nav links resolve to a graceful, read-only stub page. STUB_PAGES: dict[str, tuple[str, str]] = { "/sessions": ( "Sessions", "Active session, capability, and role inventory. Backed by the unified " "inventory API (#636) once it lands.", ), "/inventory": ( "Inventory", "Unified sessions, leases, locks, namespaces, and worktree inventory. " "Backed by the Phase 1 inventory API (#636).", ), "/timeline": ( "Timeline", "Workflow event timeline across issues and PRs. A later Phase 1 surface.", ), "/policy": ( "Policy", "Capability and role policy surface. Placeholder until a later phase.", ), "/insights": ( "Insights", "Aggregate operational insights and trends. Placeholder until a later " "phase.", ), } def iter_nav_items(): """Yield every ``NavItem`` across all groups in declared order.""" for group in NAV_GROUPS: for item in group.items: yield item def nav_hrefs() -> tuple[str, ...]: """Return every navigation href in declared order.""" return tuple(item.href for item in iter_nav_items())