Skip to content

UI

Partial

The console is one renderer over the same views the rest of the platform reads. This page is the renderer / page / dashboard model and the information architecture; the stack and the concrete primitives are the design system.

The renderer contract: ViewResult and the views BFF

Section titled “The renderer contract: ViewResult and the views BFF”

The dense-ops layout is an architectural pattern: facet summary over the full set, keyboard chip filter, tree/list table, click-row detail blade plus a full detail page, the summary staying whole so click-to-filter is stable. The inventory tier realizes it as the config-driven ListShell and its primitives (design system); the analytical surfaces will reuse it.

An operator surface carries no inline explanatory text (ADR-0127): every explainer rides its label’s (i) tooltip (InfoTip; Eyebrow for section labels), so the pedagogy doctrine is satisfied by hover and the page itself stays scannable. The standard-editor’s vocabulary (choices, alternates, accepted types) never leads an operator view, and a system’s body renders components-first: one card per component with its role as a badge, role-level chrome only where it says something a badge cannot (a quorum beyond one, a shortfall, an unstaffed role). The platform-wide sweep of the older pages is tracked in #784. The system zoom is growing into the workspace #788 defines: facets as ?tab= URL facts (TabRail), the Map tab rendering the standard’s declared room (ADR-0128) with live occupant state on each marker. Since ADR-0129 these faces ARE the identity routes’ default, and since #800 they are the ONLY faces: one way to look, one altitude rule (locations drill, systems open full screen, components open in blades), editing on each workspace’s Configure tab, and flat tables surviving as a list-density toggle for bulk work. The classic detail face is retired; ?view=detail is ignored and ?edit=1 lands Configure already editing.

One renderer library, two composition modes

Section titled “One renderer library, two composition modes”

Coded pages and dashboards share one view layer

Section titled “Coded pages and dashboards share one view layer”

Live data is query polling (a refetch interval; slow-changing config uses a long stale time).

CRUD forms over the typed resource API, one per primitive (components, templates, types, tags, rules, config, groups, schedules, severity levels, the IAM resources). The type registries each hold their own page: location types (CRUD; Catalog, under Locations: Types) and secret types (read-only, at /secret-types by URL with no subrail entry), the former tabbed Types page having split with the system and component kinds already moved to Standards and Products (build log). Editing a setting is editing config, an audited mutation, not a separate prop store (audit).

Two layers, deliberately decoupled:

  1. Routes are flat and identity-based. Every entity page is a top-level path (/systems, /components, /templates, /config); a URL addresses the entity, never its place in the menu, so deep links stay stable however the menu is reorganized. No taxonomy-nested routes, no redirects to maintain.
  2. The sidebar groups those flat routes into clusters for browsing: Home, Fleet (the one canvas, #633), Dashboards, Alarms, Inventory (locations, systems, components, nodes), Values (variables, secrets, config, files), Catalog (a single entry opening the catalog shell, next), Explore, Learn, Admin (users, roles, groups, audit, and the Settings leaf). A cluster is pure presentation, not a destination: rearrangeable and user-customizable without touching a route.

The mode rides the URL too (ADR-0120 established the rule; ADR-0132 retargets it): ?edit=1 beside a fleet address lands the workspace’s Configure tab already editing, and beside an identity blade’s id param (?u=<id>&edit=1) opens that blade editing, both behind the same <resource>:update permission the Edit button is behind; without it the link lands read-only. Leaving edit (Cancel or Save) strips the param via history replace, so a refresh mid-edit keeps the mode while Back never re-enters an edit the operator left. One hook (web/src/lib/editurl.ts) owns both directions, the create-as-route and row-pencil handoffs are those URLs rather than in-memory signals, and the name-to-uuid redirect keeps its query string so a name-shaped edit link survives resolution. Every URL-reachable state is also a state the docs screenshot pipeline can declare and capture, which is what retired the one-shot handoffs.

Catalog is one rail entry opening a shell. Clicking Catalog opens a two-column catalog area: a grouped subrail (Telemetry, Actions, Components, Systems, Locations, Metadata) whose entries navigate to the registries’ own canonical flat routes (/products, /metrics, …), each real page rendering in the pane beside it, and an Overview landing at /catalog with one card per group and live registry counts, the learning-tool answer to “what is all this”. Subrail and cards derive from one group table judged through the same permission filter the rail uses, so a gated entry drops from both surfaces at once and a group whose entries are all gated away disappears with its header; secret types holds no subrail entry at all (/secret-types stays routed and gated, rendering in the pane). The naming rule (ADR-0083) carries into the subrail: a group is named for the fleet noun it serves, an entry keeps the registry’s own word, and where the registry’s only word is “type” the entry is Types with the group completing the sentence (Catalog, under Locations: Types). The organizing line the groups teach: Telemetry is what you receive, Actions is what you send or run; an event is a record of a happening (caught from the fleet or caused by the platform), never an outbound message, which is why Events sits in Telemetry while Rules, Commands, and the future Notifications sit in Actions.

Values is its own top-level group, beside Inventory: values set on fleet entities and resolved down the cascade, a distinct genus from the entities themselves. Config is the CI store (desired configuration, optionally observed back to detect drift and reconcile), distinct from platform Settings (preferences: severity scales, schedules, retention, defaults) and Variables (free interpolated values, no observed side); the full split is config, secrets, and variables.

Inventory holds the fleet entities: locations, systems, components, and nodes, the collection daemons, monitored and scope-controlled (live, gated on node:read plus ABAC scope), so a node sits in Inventory, not Admin. Interfaces and tasks are not nav items: an interface is a panel on a component, a task a panel on a node, facets of the owning entity’s detail page.

Admin is the renamed Settings group: Users, Roles, Groups, Audit, plus the live Settings leaf, the platform-preferences page.

The theme is dark-first (the NOC aesthetic) on the brand palette (teal #21CAB9, navy #080c16), semantic tokens only, no hardcoded colors in components.