dashboard: transient_set / transient_cleared mutation events + client derived state

This commit is contained in:
müde 2026-05-17 14:20:51 +02:00
parent 1879b2f485
commit 7956e1c627
3 changed files with 103 additions and 7 deletions

View file

@ -105,6 +105,21 @@ pub enum TransientKind {
Destroying,
}
impl TransientKind {
/// Wire/UI label. Matches the strings the dashboard already
/// renders in the transient spinner.
pub fn as_str(self) -> &'static str {
match self {
TransientKind::Spawning => "spawning",
TransientKind::Starting => "starting",
TransientKind::Stopping => "stopping",
TransientKind::Restarting => "restarting",
TransientKind::Rebuilding => "rebuilding",
TransientKind::Destroying => "destroying",
}
}
}
impl Coordinator {
pub fn open(
db_path: &Path,
@ -318,10 +333,30 @@ impl Coordinator {
since: std::time::Instant::now(),
},
);
// Live-update dashboards. `since_unix` is wall-clock so the
// browser can tick "Ns spawning…" without polling. The
// intra-process map keeps using `Instant` for monotonicity.
let since_unix = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.ok()
.and_then(|d| i64::try_from(d.as_secs()).ok())
.unwrap_or(0);
self.emit_dashboard_event(DashboardEvent::TransientSet {
seq: self.next_seq(),
name: name.to_owned(),
transient_kind: kind.as_str(),
since_unix,
});
}
pub fn clear_transient(&self, name: &str) {
self.transient.lock().unwrap().remove(name);
let removed = self.transient.lock().unwrap().remove(name).is_some();
if removed {
self.emit_dashboard_event(DashboardEvent::TransientCleared {
seq: self.next_seq(),
name: name.to_owned(),
});
}
}
/// Set a transient state and return a guard that clears it on drop.