The flow page showed the raw broker message stream and had a compose box. This removes the page and its bundle, its link in the pages menu, and the styles only it used. The history endpoint that backfilled it and the operator-send endpoint behind the compose box had no other caller, so they go too, along with the broker query behind the history endpoint. The stream endpoint stays: the dashboard tabs still subscribe to it. The docs lose the FL0W section and the references to the two endpoints.
84 lines
2.7 KiB
Rust
84 lines
2.7 KiB
Rust
//! Remaining single-endpoint dashboard handlers: mark-all-read,
|
|
//! spawn-request and hive-wide turn stats.
|
|
|
|
use axum::{
|
|
extract::{Path as AxumPath, State},
|
|
http::StatusCode,
|
|
response::{IntoResponse, Response},
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use utoipa::{IntoParams, ToSchema};
|
|
|
|
use super::{AppState, Ident, error_response};
|
|
use crate::hive_stats::HiveStats;
|
|
|
|
#[derive(Deserialize, IntoParams)]
|
|
pub(super) struct StatsHiveQuery {
|
|
/// Stats window; defaults to `24h`.
|
|
window: Option<String>,
|
|
}
|
|
|
|
/// Hive-wide turn-stats rollup for the dashboard swarm-stats view.
|
|
///
|
|
/// Aggregates every agent's `hyperhive-turn-stats.sqlite` read-only
|
|
/// (skips missing/unreadable ones).
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/api/stats-hive",
|
|
params(StatsHiveQuery),
|
|
responses((status = 200, description = "hive-wide turn-stats rollup", body = HiveStats)),
|
|
tag = "misc_api"
|
|
)]
|
|
pub(super) async fn api_stats_hive(
|
|
State(state): State<AppState>,
|
|
axum::extract::Query(q): axum::extract::Query<StatsHiveQuery>,
|
|
) -> Response {
|
|
let window = crate::hive_stats::Window::parse(q.window.as_deref().unwrap_or("24h"));
|
|
axum::Json(crate::hive_stats::hive_snapshot(
|
|
window,
|
|
&state.coord.model_prices,
|
|
))
|
|
.into_response()
|
|
}
|
|
|
|
#[derive(Serialize, ToSchema)]
|
|
pub(super) struct MarkAllReadBody {
|
|
marked: u64,
|
|
}
|
|
|
|
/// Operator-driven "clear this agent's inbox" — backs the side-panel
|
|
/// "mark all read" button.
|
|
///
|
|
/// Marks every message addressed to the agent as acked (backfilling
|
|
/// `delivered_at` for any still-pending rows so vacuum can collect
|
|
/// them). `marked` lets the frontend show "cleared N messages"
|
|
/// feedback without an extra fetch.
|
|
#[utoipa::path(
|
|
post,
|
|
path = "/api/agent/{name}/mark-all-read",
|
|
params(("name" = String, Path, description = "agent name")),
|
|
responses(
|
|
(status = 200, description = "count of messages marked read", body = MarkAllReadBody),
|
|
(status = 400, description = "bad agent name"),
|
|
(status = 500, description = "broker write failed"),
|
|
),
|
|
tag = "misc_api"
|
|
)]
|
|
pub(super) async fn post_mark_all_read(
|
|
State(state): State<AppState>,
|
|
AxumPath(name): AxumPath<String>,
|
|
) -> Response {
|
|
let name = match Ident::parse(&name) {
|
|
Ok(n) => n,
|
|
Err(reason) => {
|
|
return (StatusCode::BAD_REQUEST, format!("bad agent name: {reason}")).into_response();
|
|
}
|
|
};
|
|
match state.coord.broker.mark_all_read(name.as_str()) {
|
|
Ok(marked) => {
|
|
tracing::info!(%name, marked, "operator marked all messages read");
|
|
axum::Json(MarkAllReadBody { marked }).into_response()
|
|
}
|
|
Err(e) => error_response(&format!("mark-all-read {name} failed: {e:#}")),
|
|
}
|
|
}
|