The dashboard is a small single-page application compiled into the jaque binary and served from the same -listen address as the command API and /metrics. It reads projections through the query service and submits commands through the command service; it holds no state of its own beyond an optional API token in the browser. It exists so that knowing what jaque knows never requires a second deployment, and its cost is a poll: every page refreshes by calling ListStatus every 5 seconds, so what is shown is at most 5 seconds behind the event log.

Status: there is no push channel; live updates are on the roadmap, and until then the 5-second poll is the freshness bound. The dashboard does not authenticate users; see section 9 and the status page.

1. Embedded, not a separate service

The assets are compiled into the binary and served directly by it: no node process, no separate deploy, no version to keep in sync with the engine. One flag, -listen, turns the dashboard, the command API and /metrics on or off together. Navigation is hash-based (#/overview, #/hosts, ...), so every view is a URL and a reverse proxy needs no rewrite rules.

The dashboard follows the operating system's color scheme by default: paper in light mode, graphite in dark mode. A toolbar switch can override this; see Theme below. The five state colors are the same ones the documentation uses, and a state is always shown as its color and its word, so a screenshot keeps its meaning without the color.

2. Overview (#/overview)

The landing page. Two rows of state tiles, one for hosts and one for services, counting total, ok, warning, critical, unknown and pending; each tile links to the unfiltered #/hosts or #/services. Below them two tables: Unhandled problems, with no acknowledgement and no active downtime, always visible; and Handled problems, acknowledged or in downtime, inside a disclosure that is closed by default. What needs attention is not buried under what is already being handled.

3. Hosts and services (#/hosts, #/services)

The full object table: name, state with its SOFT, FLAPPING and UNREACHABLE qualifiers, output, last change, and an acknowledgement and downtime glance. Everything is shown by default; a "Problems only" toggle filters and sorts by severity without changing what no filter means.

A selector box above the table takes the same label selector grammar used everywhere else (env=prod, team=redes). Applying it writes the selector into the URL as a query parameter (#/hosts?sel=env%3Dprod), so a filtered table is a shareable link and each apply is its own history entry that the browser's back button undoes. A selector that fails to parse shows the error under the box instead of silently showing the unfiltered table.

With a selector active, both pages show a Bulk actions panel that acknowledges or schedules downtime against every matching object at once. That is one command with a selector target, not one request per row.

4. Object detail (#/object/<host>, #/object/<host>/<service>)

State, output, acknowledgement and downtime detail, and a timeline of recent transitions from ListHistory. The timeline can be filtered by the resulting status and by state type, and re-ordered oldest-first with a toggle on the At column; times are shown in the browser's local time, with the raw timestamp available as a tooltip. The acknowledgement and downtime forms are the same ones the row-level panel uses. A host's detail lists its services; a service's detail links back to its host, so the reader can walk up one level without losing context.

5. Labels as navigation

Every row and every detail view shows the object's labels as clickable chips. Clicking key=value navigates to #/hosts or #/services with that pair applied as a selector. It is the same mechanism as clicking a group link from #/groups: a group in jaque is a selector, and a label is a one-term selector.

6. History (#/history)

The global transition feed from ListHistory, newest first, 100 by default. Filterable by host, by service once a host is set, and by limit; the same 5-second poll as every other page, plus an explicit "Apply" for filter changes so a half-typed filter does not fire. The timeline itself can also be filtered by the resulting status and by state type, and re-ordered oldest-first with a toggle on the At column; times are shown in the browser's local time, with the raw timestamp available as a tooltip.

7. Downtimes (#/downtimes)

Every scheduled downtime and every acknowledgement across all hosts and services in one place, so reviewing or clearing them does not mean visiting each object. Two tables: downtimes with a Delete button that calls DeleteDowntime, and acknowledgements with a Remove button that calls RemoveAcknowledgement. A "New downtime" form targets either one object or a selector, without starting from a row.

8. Contacts and groups (#/contacts, #/groups)

#/contacts lists every configured contact with its type and labels.

#/groups has no native groups to show, because jaque has none: a group is labels and selectors, not a first-class object (see Labels and views). The page shows the saved views with name, selector, description and live member count, and a table of every label seen across the fleet with its object count. Both kinds of count link into #/hosts with that selector applied.

9. Settings and the API token

When jaque runs with -api-token, a "Settings" disclosure holds a token field. The token is saved to the browser's localStorage and sent only as Authorization: Bearer on command POSTs. Reads (ListStatus and the rest of the query service) never require it, matching the API's own posture described in Command and query service. There are no cookies and no session.

10. Sinks

When at least one sink is configured, a "Sinks" disclosure next to Settings lists every sink ListSinks reports: name, type, input (metrics or events) and selector when one is set. It is read-only and shows no runtime state; lag and write errors stay on /metrics, where a collector can see them.

11. Security considerations

The dashboard is served on -listen with no authentication of its own. -api-token protects commands, not reads: anyone who can reach the listener can see every object, its output and its labels. The token lives in the browser's localStorage in clear. Put the listener behind a reverse proxy that terminates TLS and authenticates users, or bind it to an address only that proxy can reach; see Security.

Theme

The toolbar carries a three-state theme switch next to Problems only and Settings: Auto, Light, Dark. Auto follows the operating system's color preference; Light and Dark override it. The choice is stored in the browser and applies immediately, charts included.

Command palette

The palette opens with / or with Ctrl-K (Cmd-K on a Mac), and from the "Search" button in the toolbar. Typing filters views, panels, and every host and service the dashboard currently knows about; arrows move, Enter goes, Escape closes.

What it lists comes from the same 5-second poll as the rest of the page, so an object that appeared seconds ago may not be there yet. It also carries two actions that have no page of their own: toggling Problems only, and cycling the theme.