agent web UI: bulk mark-done for the todos flyout
The per-agent web UI todos flyout (loose-ends v2) had no mark-done affordance at all — dismissing a todo was only possible via the cancel_loose_end MCP tool, one id at a time. Add a checkbox per row, a select-all/select-none/mark-done bulk row, and a new POST /api/todos/mark-done handler that loops the existing single-id MarkTodoDone request over the in-agent socket (no new wire request type needed — the todos list is small, so N same-host round-trips is cheap). Fixes #2917
This commit is contained in:
parent
ff2721cc0f
commit
41c1b1a3fb
4 changed files with 119 additions and 7 deletions
|
|
@ -1,4 +1,5 @@
|
|||
//! Operator action POST handlers (send, cancel, compact, model, effort, reset).
|
||||
//! Operator action POST handlers (send, cancel, compact, model, effort,
|
||||
//! reset, todos mark-done).
|
||||
|
||||
use axum::{
|
||||
Form,
|
||||
|
|
@ -162,3 +163,41 @@ pub(super) async fn post_set_effort(
|
|||
tracing::info!(%level, "operator set effort");
|
||||
(axum::http::StatusCode::OK, "ok").into_response()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub(super) struct MarkTodosDoneForm {
|
||||
/// Comma-separated todo ids. Same "one field, JS joins the checked
|
||||
/// boxes" shape as `hive-c0re`'s `meta_inputs::MetaUpdateForm` — axum's
|
||||
/// `Form` extractor doesn't natively decode repeated same-name keys.
|
||||
ids: String,
|
||||
}
|
||||
|
||||
/// `POST /api/todos/mark-done` — dismiss one or more of this agent's own
|
||||
/// todos (loose-ends v2) from the todos flyout. Loops a `MarkTodoDone` call
|
||||
/// per id over the in-agent socket rather than adding a new bulk request to
|
||||
/// `hive-agent-sock`: the todos list is small (single-digit rows most of the
|
||||
/// time), so N same-host socket round-trips isn't a real cost, and it keeps
|
||||
/// the wire protocol's `Request` enum — already used by the `cancel_loose_end`
|
||||
/// MCP tool — unchanged. Unknown/already-acked ids just don't add to the
|
||||
/// `acked` count (same "acking twice is not a new action" semantics as the
|
||||
/// single-id path); a request with no ids or where every id fails to parse
|
||||
/// is rejected as a client error rather than silently acking nothing.
|
||||
pub(super) async fn post_mark_todos_done(Form(form): Form<MarkTodosDoneForm>) -> Response {
|
||||
let ids: Vec<i64> = form
|
||||
.ids
|
||||
.split(',')
|
||||
.filter_map(|s| s.trim().parse::<i64>().ok())
|
||||
.collect();
|
||||
if ids.is_empty() {
|
||||
return error_response(StatusCode::BAD_REQUEST, "mark-done: no todo ids selected");
|
||||
}
|
||||
let mut acked = 0u64;
|
||||
for id in ids {
|
||||
if let Some(hive_agent_sock::Response::Acked { count }) =
|
||||
crate::todo_server::dial(&hive_agent_sock::Request::MarkTodoDone { id }).await
|
||||
{
|
||||
acked += count;
|
||||
}
|
||||
}
|
||||
axum::Json(serde_json::json!({ "acked": acked })).into_response()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ pub async fn serve(
|
|||
.route("/api/new-session", post(actions::post_new_session))
|
||||
.route("/api/logout", post(auth::post_logout))
|
||||
.route("/api/todos", get(stats::api_todos))
|
||||
.route("/api/todos/mark-done", post(actions::post_mark_todos_done))
|
||||
.route("/api/stats", get(stats::api_stats))
|
||||
.route("/screen/ws", get(screen::screen_ws))
|
||||
.route("/icon", get(screen::serve_icon));
|
||||
|
|
|
|||
Loading…
Reference in a new issue