ws: migrate push stream to data streaming

- daemon: send full snapshot on connect; versions/tick now carry the
  full state of one subsystem (subsystem + data); no legacy
  updated/subsystems payloads; refresh_state and POST /status/refresh
  broadcast per-subsystem versions with data
- client: modelSet() patches models in place; onMessage/topic refresh
  retired; 3s initial-load fallback via new POST /api/status/refresh
- schema: lib/schema.py TypedDicts + hoover/schema.js defaults +
  docs/state-model.md as single source of truth for state shapes
- system: poll at 1s, volatile metrics registered, dashboard uses a
  dedicated system model (status model removed)
- firewall: refuse to strip both https and ssh from the default zone
  (409, force override via UI confirm); set_zone_services persists
  services to the declarative config; collector exposes default_zone
- UI: pages migrate to flat state shapes; post-mutation modelFetch
  refreshes removed (WS delta covers it)
- tests: ws snapshot/delta/broadcast, refresh-state, schema types,
  model-set/js ws handler and reconnect fallback
This commit is contained in:
2026-08-20 01:38:00 +00:00
parent 9c9f92ad04
commit 332d14e37d
45 changed files with 2819 additions and 496 deletions
+17
View File
@@ -135,6 +135,23 @@ export function modelFetch(name, signalOrParam, signal) {
return promise;
}
/**
* Set model data from WebSocket. Bypasses fetch cycle, no refreshing flag.
* Directly assigns to reactive proxy → triggers re-render.
* Clears loading unconditionally on arrival of real data.
*
* @param {string} name - Model name
* @param {any} data - State payload from the WS snapshot/delta
*/
export function modelSet(name, data) {
const entry = _models.get(name);
if (!entry) return;
const model = entry.model;
if (model.loading) model.loading = false; // real data ends the initial load
model.data = data;
model.error = null;
}
/**
* Refresh all models whose subsystem topic matches the given topic.
* Topic '*' matches every model. Model subsystem '*' matches every topic.