Introduce a single nav-config module (webui/nav.py) driving grouped navigation across the epic #631 Phase 1 information architecture: Health, Traffic, Runtime/Sessions, Projects, Inventory, Timeline, Policy (placeholder), and Insights (placeholder). The shell header now carries a read-only environment badge (local/remote from WEBUI_HOST), a mode: read-only badge, and a Docs link. Home summarizes the console purpose, lists the Phase 1 surfaces by group, and links the MVP legacy pages. Not-yet-implemented surfaces (/sessions, /inventory, /timeline, /policy, /insights) resolve to graceful read-only stub pages rather than 404s; their backing views land in later child issues of #631 (inventory surfaces backed by #636). Mutating methods on stub routes still fail closed with read-only-mvp. No privileged action controls are added. Adds tests/test_webui_shell.py covering nav groups, badge presence, environment classification, docs link, stub routes (200 + read-only), and home content. Updates docs/webui-local-dev.md with the new routes and a Phase 1 shell section. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
112 lines
3.3 KiB
Python
112 lines
3.3 KiB
Python
"""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())
|