feat(webui): system-health dashboard (Closes #639)
Phase 1 child of the Web Console epic #631. Adds the operator-facing system-health dashboard on top of the read-only system-health API landed by #634, so runtime problems are visible on a surface instead of being discovered late through failed LLM sessions. - webui/system_health_views.py (new): renders the SystemHealthSnapshot as readiness, stale-runtime parity, version/uptime, dependency, MCP namespace, probe-error, and recovery cards. - webui/app.py: GET /system-health, sharing load_system_health() with the JSON API so page and API cannot disagree. ?deep=1 behaves as on the API. - webui/layout.py: nav entry and health card/badge styles. - tests/test_webui_system_health_dashboard.py (new, 26 cases). - docs/webui-local-dev.md: route, field authority, and redaction split. Readiness honesty is preserved from the API: ready and readiness_complete render separately, a probe that did not run is listed under "Not probed" rather than counted healthy, and mutation safety is never claimed when the runtime is stale or parity is indeterminate. Redaction is split by field kind. Free text (probe details, reasons, probe errors) passes through system_health.redact. Structured fields (commit SHAs, probe names, statuses, timestamps) are HTML-escaped only: redact's opaque-token rule matches any run of 32 or more characters, so routing a 40-character git SHA through it rendered "[redacted]" and blanked the parity evidence the page exists to show. Non-goals honored: no restart or reload controls (Phase 2, #642), no manual process-kill guidance (#630). Read-only throughout. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
NAV_ITEMS = (
|
||||
("/", "Home"),
|
||||
("/system-health", "System health"),
|
||||
("/queue", "Queue"),
|
||||
("/projects", "Projects"),
|
||||
("/prompts", "Prompts"),
|
||||
@@ -161,6 +162,25 @@ def render_page(*, title: str, body_html: str, extra_head: str = "") -> str:
|
||||
.badge-in-review {{ color: #9ec8f0; border-color: #3d5f7a; }}
|
||||
.badge-duplicate {{ color: #e0c27a; border-color: #6b5730; }}
|
||||
.badge-stale {{ color: #c9b8e8; border-color: #5a4a78; }}
|
||||
.badge-health-ok {{ color: #8fd19e; border-color: #3d6b4a; }}
|
||||
.badge-health-degraded {{ color: #e0c27a; border-color: #6b5730; }}
|
||||
.badge-health-down {{ color: #f0a8a8; border-color: #7a3b3b; }}
|
||||
.badge-health-skipped {{ color: var(--muted); }}
|
||||
.badge-health-unproven {{ color: #c9b8e8; border-color: #5a4a78; }}
|
||||
.health-card {{
|
||||
margin: 1.25rem 0;
|
||||
padding: 0.85rem 1rem 1rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
background: var(--surface);
|
||||
}}
|
||||
.health-card h3 {{ margin: 0 0 0.5rem; font-size: 1.05rem; }}
|
||||
.health-card h4 {{ margin: 1rem 0 0.35rem; font-size: 0.92rem; color: var(--muted); }}
|
||||
.health-headline {{ color: var(--text); font-size: 1rem; margin: 0 0 0.5rem; }}
|
||||
.health-degraded {{ border-left-color: #e0c27a; }}
|
||||
.health-stale {{ border-left-color: #f0a8a8; }}
|
||||
ul.reasons {{ margin: 0.35rem 0; padding-left: 1.15rem; color: var(--muted); font-size: 0.9rem; }}
|
||||
ul.reasons li {{ margin-bottom: 0.3rem; }}
|
||||
</style>
|
||||
{extra_head}
|
||||
</head>
|
||||
|
||||
Reference in New Issue
Block a user