feat: live SSE updates for the SCH3DUL3S tab
Add `SchedulesChanged` to the dashboard event channel so the
operator's schedule list updates in real time without requiring a
tab-activation or form-submit refresh.
Backend:
- `dashboard_events.rs`: new `SchedulesChanged { seq, schedules }`
variant carrying a full `Vec<WireSchedule>` snapshot (same
snapshot-over-diff rationale as `RebuildQueueChanged`).
- `coordinator.rs`: `emit_schedules_snapshot()` helper — queries the
scheduled_prompts list, converts to wire shape, broadcasts the event.
- `dashboard.rs`: call `emit_schedules_snapshot()` at the end of each
operator API handler that mutates a schedule:
`post_schedule_new`, `post_schedule_fire_now`,
`patch_schedule`, `post_schedule_cancel`.
- `scheduled_prompts_worker.rs`: call `emit_schedules_snapshot()`
after each tick that fires schedules, so `last_fired_at_unix`,
`next_fire_at_unix`, and reaped one-shots surface live.
Frontend:
- `tabs.js`: add `applySchedulesChanged(ev)` — replaces
`schedulesState` from the snapshot and calls `renderSchedulesList()`.
Registered in `MUTATION_HANDLERS` as `schedules_changed`.
Tab-activation re-fetch kept as safety net for approval-path
inserts and disconnect windows; comment updated to reflect this.
Docs:
- `docs/web-ui/dashboard.md`: document `schedules_changed` event.
- `CLAUDE.md`: add `SchedulesChanged` to the file-map entry.
This commit is contained in:
parent
b411a81c1a
commit
76c4a67b1c
7 changed files with 78 additions and 9 deletions
|
|
@ -1964,7 +1964,10 @@ async fn post_schedule_new(
|
|||
source: crate::scheduled_prompts::ScheduleSource::Operator,
|
||||
};
|
||||
match state.coord.scheduled_prompts.submit(&new) {
|
||||
Ok(id) => axum::Json(serde_json::json!({"id": id})).into_response(),
|
||||
Ok(id) => {
|
||||
state.coord.emit_schedules_snapshot();
|
||||
axum::Json(serde_json::json!({"id": id})).into_response()
|
||||
}
|
||||
Err(e) => error_response(&format!("schedule submit: {e:#}")),
|
||||
}
|
||||
}
|
||||
|
|
@ -1982,7 +1985,10 @@ async fn post_schedule_fire_now(
|
|||
AxumPath(id): AxumPath<i64>,
|
||||
) -> Response {
|
||||
match crate::scheduled_prompts_worker::fire_now(&state.coord, id).await {
|
||||
Ok(report) => axum::Json(report).into_response(),
|
||||
Ok(report) => {
|
||||
state.coord.emit_schedules_snapshot();
|
||||
axum::Json(report).into_response()
|
||||
}
|
||||
Err(e) => error_response(&format!("fire schedule {id} now: {e:#}")),
|
||||
}
|
||||
}
|
||||
|
|
@ -2093,7 +2099,9 @@ async fn patch_schedule(
|
|||
}
|
||||
match state.coord.scheduled_prompts.get(id) {
|
||||
Ok(Some(s)) => {
|
||||
axum::Json(crate::manager_server::schedule_to_wire_public(s)).into_response()
|
||||
let wire = crate::manager_server::schedule_to_wire_public(s);
|
||||
state.coord.emit_schedules_snapshot();
|
||||
axum::Json(wire).into_response()
|
||||
}
|
||||
Ok(None) => error_response(&format!("edit schedule {id}: row vanished post-update")),
|
||||
Err(e) => error_response(&format!("re-read schedule {id}: {e:#}")),
|
||||
|
|
@ -2117,7 +2125,10 @@ async fn post_schedule_cancel(
|
|||
None => state.coord.scheduled_prompts.cancel_all(id),
|
||||
};
|
||||
match result {
|
||||
Ok(()) => (StatusCode::OK, "ok").into_response(),
|
||||
Ok(()) => {
|
||||
state.coord.emit_schedules_snapshot();
|
||||
(StatusCode::OK, "ok").into_response()
|
||||
}
|
||||
Err(e) => error_response(&format!("cancel schedule {id}: {e:#}")),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue