use axum::{ Json, Router, extract::{Path, Query, State}, http::StatusCode, response::IntoResponse, routing::{get, post}, }; use serde::Deserialize; use crate::workspace::{Tier, WorkspaceManager}; pub fn router(manager: WorkspaceManager) -> Router { Router::new() .route("/", get(list_workspaces)) .route("/create", post(create_workspace)) .route("/{id}", get(get_workspace)) .route("/{id}/handoff", post(handoff)) .route("/{id}/search", post(add_search)) .route("/{id}/shortlist", post(add_to_shortlist)) .route("/{id}/activity", post(log_activity)) .with_state(manager) } #[derive(Deserialize)] struct ListQuery { owner: Option, tier: Option, } async fn list_workspaces( State(mgr): State, Query(q): Query, ) -> impl IntoResponse { let workspaces = mgr.list(q.owner.as_deref(), q.tier.as_ref()).await; Json(workspaces) } #[derive(Deserialize)] struct CreateRequest { name: String, description: String, owner: String, tier: Tier, } async fn create_workspace( State(mgr): State, Json(req): Json, ) -> impl IntoResponse { match mgr.create(req.name, req.description, req.owner, req.tier).await { Ok(ws) => Ok((StatusCode::CREATED, Json(ws))), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)), } } async fn get_workspace( State(mgr): State, Path(id): Path, ) -> impl IntoResponse { match mgr.get(&id).await { Some(ws) => Ok(Json(ws)), None => Err((StatusCode::NOT_FOUND, format!("workspace not found: {id}"))), } } #[derive(Deserialize)] struct HandoffRequest { to_agent: String, reason: String, } async fn handoff( State(mgr): State, Path(id): Path, Json(req): Json, ) -> impl IntoResponse { match mgr.handoff(&id, &req.to_agent, &req.reason).await { Ok(ws) => Ok(Json(ws)), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)), } } #[derive(Deserialize)] struct SearchRequest { name: String, sql: String, agent: String, } async fn add_search( State(mgr): State, Path(id): Path, Json(req): Json, ) -> impl IntoResponse { match mgr.add_search(&id, req.name, req.sql, &req.agent).await { Ok(()) => Ok((StatusCode::OK, "search saved")), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)), } } #[derive(Deserialize)] struct ShortlistRequest { dataset: String, record_id: String, notes: String, agent: String, } async fn add_to_shortlist( State(mgr): State, Path(id): Path, Json(req): Json, ) -> impl IntoResponse { match mgr.add_to_shortlist(&id, req.dataset, req.record_id, req.notes, &req.agent).await { Ok(()) => Ok((StatusCode::OK, "added to shortlist")), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)), } } #[derive(Deserialize)] struct ActivityRequest { action: String, detail: String, agent: String, } async fn log_activity( State(mgr): State, Path(id): Path, Json(req): Json, ) -> impl IntoResponse { match mgr.log_activity(&id, req.action, req.detail, &req.agent).await { Ok(()) => Ok((StatusCode::OK, "activity logged")), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)), } }