From 582ebe5eeeb6cecaaf0bae7ccb357c7d9313c491 Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 31 Jul 2026 23:00:12 +0200 Subject: [PATCH] hive-c0re: annotate remaining dashboard routes with utoipa --- hive-c0re/src/dashboard/approvals.rs | 27 +++- hive-c0re/src/dashboard/build_logs.rs | 74 ++++++++++- hive-c0re/src/dashboard/extra_forges.rs | 31 ++++- hive-c0re/src/dashboard/infra_containers.rs | 13 ++ hive-c0re/src/dashboard/lifecycle_ops.rs | 125 +++++++++++++++++- hive-c0re/src/dashboard/matrix_accounts.rs | 62 +++++++-- hive-c0re/src/dashboard/meta_inputs.rs | 13 +- hive-c0re/src/dashboard/misc_api.rs | 74 ++++++++++- hive-c0re/src/dashboard/mod.rs | 31 +++++ hive-c0re/src/dashboard/permissions.rs | 89 ++++++++++++- hive-c0re/src/dashboard/questions.rs | 29 +++- hive-c0re/src/dashboard/schedules.rs | 93 ++++++++++++- hive-c0re/src/dashboard/state_files.rs | 17 ++- hive-c0re/src/dashboard/state_snapshot.rs | 15 +++ hive-c0re/src/dashboard/tombstones.rs | 13 ++ hive-c0re/src/dashboard/topology.rs | 23 +++- hive-c0re/src/dashboard/webhook.rs | 37 ++++++ hive-c0re/src/stats/container_stats.rs | 3 +- hive-c0re/src/stats/hive_stats.rs | 7 +- hive-c0re/src/stores/build_logs.rs | 5 +- .../src/workers/scheduled_prompts_worker.rs | 2 +- 21 files changed, 738 insertions(+), 45 deletions(-) diff --git a/hive-c0re/src/dashboard/approvals.rs b/hive-c0re/src/dashboard/approvals.rs index 4239eb6f..be405cf2 100644 --- a/hive-c0re/src/dashboard/approvals.rs +++ b/hive-c0re/src/dashboard/approvals.rs @@ -10,11 +10,23 @@ use axum::{ }; use hive_sh4re::Approval; use serde::Deserialize; +use utoipa::ToSchema; use super::{AppState, error_response}; use crate::actions; use crate::coordinator::Coordinator; +/// `POST /api/approve/{id}` — approve a pending approval row. +#[utoipa::path( + post, + path = "/api/approve/{id}", + params(("id" = i64, Path, description = "approval row id")), + responses( + (status = 200, description = "approved", body = String), + (status = 500, description = "approve failed"), + ), + tag = "approvals" +)] pub(super) async fn post_approve( State(state): State, AxumPath(id): AxumPath, @@ -29,12 +41,25 @@ pub(super) async fn post_approve( } } -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, ToSchema)] pub(super) struct DenyForm { #[serde(default)] note: Option, } +/// `POST /api/deny/{id}` — deny a pending approval row, with an optional +/// note (form field `note`). +#[utoipa::path( + post, + path = "/api/deny/{id}", + params(("id" = i64, Path, description = "approval row id")), + request_body(content = DenyForm, content_type = "application/x-www-form-urlencoded"), + responses( + (status = 200, description = "denied", body = String), + (status = 500, description = "deny failed"), + ), + tag = "approvals" +)] pub(super) async fn post_deny( State(state): State, AxumPath(id): AxumPath, diff --git a/hive-c0re/src/dashboard/build_logs.rs b/hive-c0re/src/dashboard/build_logs.rs index 657557b5..990af3ef 100644 --- a/hive-c0re/src/dashboard/build_logs.rs +++ b/hive-c0re/src/dashboard/build_logs.rs @@ -17,10 +17,12 @@ use axum::{ use serde::{Deserialize, Serialize}; use tokio_stream::Stream; use tokio_stream::wrappers::ReceiverStream; +use utoipa::IntoParams; use super::{AppState, Ident, error_response}; +use crate::build_logs::{BuildLogFull, BuildLogHeader}; -#[derive(Deserialize)] +#[derive(Deserialize, IntoParams)] pub(super) struct BuildLogsAllQuery { /// Max rows to return. Capped at 100. Default 30. #[serde(default)] @@ -29,6 +31,16 @@ pub(super) struct BuildLogsAllQuery { /// `GET /api/build-logs?limit=N` — most-recent build log headers across /// all agents, newest first. Same JSON shape as the per-agent endpoint. +#[utoipa::path( + get, + path = "/api/build-logs", + params(BuildLogsAllQuery), + responses( + (status = 200, description = "recent build log headers, newest first", body = Vec), + (status = 500, description = "sqlite read failed"), + ), + tag = "build_logs" +)] pub(super) async fn get_build_logs_all( State(state): State, axum::extract::Query(q): axum::extract::Query, @@ -40,7 +52,7 @@ pub(super) async fn get_build_logs_all( } } -#[derive(Deserialize)] +#[derive(Deserialize, IntoParams)] pub(super) struct BuildLogsQuery { /// Maximum number of rows to return. Capped server-side at 50 /// (see `build_logs::list_recent_for_agent`). Default 10. @@ -53,6 +65,20 @@ pub(super) struct BuildLogsQuery { /// `Vec` (JSON). Limit defaults to 10, server-side /// cap at 50. Backs the per-agent log chip in the agent card and /// the side-panel header list. +#[utoipa::path( + get, + path = "/api/build-logs/{agent}", + params( + ("agent" = String, Path, description = "agent name"), + BuildLogsQuery, + ), + responses( + (status = 200, description = "recent build log headers for the agent, newest first", body = Vec), + (status = 400, description = "bad agent name"), + (status = 500, description = "sqlite read failed"), + ), + tag = "build_logs" +)] pub(super) async fn get_build_logs_agent( State(state): State, AxumPath(name): AxumPath, @@ -79,6 +105,17 @@ pub(super) async fn get_build_logs_agent( /// stderr concatenated) by id. Returns `BuildLogFull` (JSON), or /// HTTP 404 when the id doesn't exist (vacuum-reaped, or the /// operator passed a stale id from a refresh race). +#[utoipa::path( + get, + path = "/api/build-logs/id/{id}", + params(("id" = i64, Path, description = "build log row id")), + responses( + (status = 200, description = "full build log row", body = BuildLogFull), + (status = 404, description = "no such build log row"), + (status = 500, description = "sqlite read failed"), + ), + tag = "build_logs" +)] pub(super) async fn get_build_log_full( State(state): State, AxumPath(id): AxumPath, @@ -96,6 +133,17 @@ pub(super) async fn get_build_log_full( /// node has no linked log (the client gates the request on `NodeView.has_log`, /// but a vacuum race can still 404). This is the on-demand log fetch the /// raw-graph dashboard uses instead of an inline `build_log_id` on the wire. +#[utoipa::path( + get, + path = "/api/build-log/{node_id}", + params(("node_id" = u64, Path, description = "job-queue node id")), + responses( + (status = 200, description = "full build log row for the node's linked log", body = BuildLogFull), + (status = 404, description = "node has no linked build log, or the log row is gone"), + (status = 500, description = "sqlite read failed"), + ), + tag = "build_logs" +)] pub(super) async fn get_build_log_for_node( State(state): State, AxumPath(node_id): AxumPath, @@ -112,6 +160,17 @@ pub(super) async fn get_build_log_for_node( /// `GET /api/build-log/{node_id}/raw` — the node's build log as `text/plain` /// for download (delegates to `get_build_log_raw` after resolving the node id). +#[utoipa::path( + get, + path = "/api/build-log/{node_id}/raw", + params(("node_id" = u64, Path, description = "job-queue node id")), + responses( + (status = 200, description = "build log text for download", body = String, content_type = "text/plain"), + (status = 404, description = "node has no linked build log, or the log row is gone"), + (status = 500, description = "sqlite read failed"), + ), + tag = "build_logs" +)] pub(super) async fn get_build_log_raw_for_node( State(state): State, AxumPath(node_id): AxumPath, @@ -239,6 +298,17 @@ pub(super) async fn get_build_log_stream( /// separator (same layout the JS side-panel renders). The /// `Content-Disposition` header triggers a browser download with a /// descriptive filename so the operator can save and share the log. +#[utoipa::path( + get, + path = "/api/build-logs/id/{id}/raw", + params(("id" = i64, Path, description = "build log row id")), + responses( + (status = 200, description = "build log text for download", body = String, content_type = "text/plain"), + (status = 404, description = "no such build log row"), + (status = 500, description = "sqlite read failed"), + ), + tag = "build_logs" +)] pub(super) async fn get_build_log_raw( State(state): State, AxumPath(id): AxumPath, diff --git a/hive-c0re/src/dashboard/extra_forges.rs b/hive-c0re/src/dashboard/extra_forges.rs index fcf4e0f2..54bfec0a 100644 --- a/hive-c0re/src/dashboard/extra_forges.rs +++ b/hive-c0re/src/dashboard/extra_forges.rs @@ -22,6 +22,7 @@ use std::path::Path; use axum::extract::{Form, Query}; use axum::response::{IntoResponse, Response}; use serde::{Deserialize, Serialize}; +use utoipa::{IntoParams, ToSchema}; use super::{Ident, error_response}; use crate::coordinator::Coordinator; @@ -41,18 +42,18 @@ fn read_base_url(dir: &Path, label: &str) -> Option { .map(|s| s.base_url) } -#[derive(Serialize)] +#[derive(Serialize, ToSchema)] struct ExtraForgeAccount { label: String, base_url: Option, } -#[derive(Serialize)] +#[derive(Serialize, ToSchema)] struct ExtraForgesResponse { forges: Vec, } -#[derive(Deserialize)] +#[derive(Deserialize, IntoParams)] pub(super) struct ExtraForgesQuery { agent: String, } @@ -62,6 +63,16 @@ pub(super) struct ExtraForgesQuery { /// token` file in its state dir (mirrors `matrix_accounts.rs`'s filename-scan /// listing). `base_url` is backfilled from the matching `forge-