feat(dashboard): generic server-warnings banner on every page (#1518)

Per operator request: instead of a disk-specific alert, surface a generic
server-warnings banner at the very top of every page, so new system
warnings can be added backend-side with no frontend change.

- hive-c0re `host_stats`: `server_warnings() -> Vec<ServerWarning>`
  (`{ kind, level, message }`). The threshold logic lives server-side; the
  host disk-pressure check (a `statvfs` probe of `/nix`: ≥85% used → warn,
  ≥95% → crit) is the first and only producer today. No new deps (libc).
- `/api/state` carries `server_warnings` (replaces the disk-specific
  field). Empty when all clear.
- frontend: `renderServerWarnings` / `initServerWarnings` in `common.js`
  inject a sticky top-of-<body> banner and render the list, coloured by
  `level`. Wired on every page — dashboard (live, via refreshState),
  FL0W, L0GS, H0M3. No per-warning frontend code; adding a warning kind
  is a pure backend change.

cargo check/clippy/fmt + npm run build green. Closes #1518.
This commit is contained in:
iris 2026-06-08 19:55:04 +02:00 committed by mara
commit 5d0f3d060b
10 changed files with 241 additions and 6 deletions

View file

@ -260,6 +260,12 @@ struct StateSnapshot {
/// the c0re NixOS module from `services.hyperhive.swarm.peers`).
/// Empty on single-hive deploys. Feeds the P33RS dashboard tab.
peer_hives: Vec<PeerHiveView>,
/// Server-level warnings for the dashboard's top-of-page banner
/// (currently host disk-pressure; more producers can be added
/// backend-side). Empty when all clear. Built by
/// `host_stats::server_warnings`; the frontend renders this list
/// generically, so new warning kinds need no frontend change.
server_warnings: Vec<crate::host_stats::ServerWarning>,
}
/// One peer hive for the P33RS dashboard tab. Derived from
@ -488,6 +494,7 @@ async fn api_state(headers: HeaderMap, State(state): State<AppState>) -> axum::J
.ok()
.filter(|s| !s.is_empty()),
peer_hives: parse_peer_hives(),
server_warnings: crate::host_stats::server_warnings(),
})
}