dashboard: POST /api/rebuild-queue/{id}/cancel for queued entries (closes #447)

This commit is contained in:
damocles 2026-05-26 13:35:18 +02:00 committed by Mara
commit 0072946ea3

View file

@ -77,6 +77,7 @@ pub async fn serve(port: u16, coord: Arc<Coordinator>) -> Result<()> {
.route("/api/schedules", get(api_schedules).post(post_schedule_new))
.route("/api/schedules/{id}/cancel", post(post_schedule_cancel))
.route("/api/schedules/{id}/fire-now", post(post_schedule_fire_now))
.route("/api/rebuild-queue/{id}/cancel", post(post_rebuild_queue_cancel))
.route("/dashboard/stream", get(dashboard_stream))
.route("/dashboard/history", get(dashboard_history))
// Anything not matched by the dynamic routes above falls
@ -1459,6 +1460,28 @@ async fn post_schedule_fire_now(
}
}
/// `POST /api/rebuild-queue/{id}/cancel` — drop a `Queued` entry
/// from the rebuild queue (#447). Refuses `Running` / terminal
/// entries: an in-flight rebuild owns the agent's nix store +
/// nixos-container update lock and can't be safely interrupted
/// from the queue side. Always returns 200; the body is
/// `{"cancelled": true}` on a successful flip from Queued →
/// Cancelled, `{"cancelled": false}` when the row was Running /
/// terminal / gone. On success a fresh `RebuildQueueChanged`
/// snapshot fires so the row's state flip surfaces live.
async fn post_rebuild_queue_cancel(
State(state): State<AppState>,
AxumPath(id): AxumPath<u64>,
) -> Response {
let cancelled = state.coord.rebuild_queue.cancel(id);
if cancelled {
state.coord.emit_rebuild_queue_snapshot();
axum::Json(serde_json::json!({"cancelled": true})).into_response()
} else {
axum::Json(serde_json::json!({"cancelled": false})).into_response()
}
}
#[derive(serde::Deserialize, Default)]
struct CancelScheduleForm {
/// `None` / absent / empty array → cancel whole schedule.