From b3de779d87450033f1e0361144c621a1d5f1dbf8 Mon Sep 17 00:00:00 2001 From: soryu Date: Mon, 16 Feb 2026 17:59:38 +0000 Subject: Fix contracts page overflow, remove contract link from orders, add directive name (#65) * feat: soryu-co/soryu - makima: Add frontend pick-up-orders button and API integration * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Remove contract link from orders and add directive name to order metadata (frontend) * fix: contracts page overflow - use contained scrolling layout Changed the contracts page to use contained scrolling matching the orders/directives pages, preventing the page from growing beyond viewport height. Co-Authored-By: Claude Opus 4.6 * fix: resolve completion_task_id FK violation and duplicate button The completion_task_id column has an FK to tasks(id), but claim_directive_for_completion was being called with a placeholder UUID that did not exist in the tasks table, causing FK constraint violations. Fix: Create the task FIRST via create_task_for_owner, then use the real task.id when calling claim_directive_for_completion. Applied in all three locations: phase_completion Part 1 (idle directives), Part 3 (verification tasks), and trigger_completion_task (manual PR creation). Also removes a duplicate "Pick Up Orders" button in DirectiveDetail.tsx. * fix: restore Order type changes lost during rebase conflict resolution Re-apply changes from the orders-refactor commit that were dropped when resolving rebase conflicts with --ours: - Replace contractId with directiveName in Order interface - Make directiveId required in CreateOrderRequest - Remove contractId from UpdateOrderRequest - Change listOrders parameter from contractId to search - Remove linkOrderToContract function - Simplify convertOrderToStep to single argument --------- Co-authored-by: Claude Opus 4.6 --- makima/src/server/handlers/orders.rs | 85 +++++------------------------------- 1 file changed, 10 insertions(+), 75 deletions(-) (limited to 'makima/src/server/handlers') diff --git a/makima/src/server/handlers/orders.rs b/makima/src/server/handlers/orders.rs index c43c406..cddf6a6 100644 --- a/makima/src/server/handlers/orders.rs +++ b/makima/src/server/handlers/orders.rs @@ -11,7 +11,7 @@ use axum::{ use uuid::Uuid; use crate::db::models::{ - ConvertToStepRequest, CreateOrderRequest, DirectiveStep, LinkContractRequest, + CreateOrderRequest, DirectiveStep, LinkDirectiveRequest, Order, OrderListQuery, OrderListResponse, UpdateOrderRequest, }; use crate::db::repository; @@ -32,7 +32,7 @@ use crate::server::state::SharedState; ("type" = Option, Query, description = "Filter by order type"), ("priority" = Option, Query, description = "Filter by priority"), ("directive_id" = Option, Query, description = "Filter by directive ID"), - ("contract_id" = Option, Query, description = "Filter by contract ID"), + ("search" = Option, Query, description = "Text search across title, description, and directive name"), ), responses( (status = 200, description = "List of orders", body = OrderListResponse), @@ -62,7 +62,7 @@ pub async fn list_orders( query.order_type.as_deref(), query.priority.as_deref(), query.directive_id, - query.contract_id, + query.search.as_deref(), ) .await { @@ -327,80 +327,13 @@ pub async fn link_to_directive( } } -/// Link an order to a contract. -#[utoipa::path( - post, - path = "/api/v1/orders/{id}/link-contract", - params(("id" = Uuid, Path, description = "Order ID")), - request_body = LinkContractRequest, - responses( - (status = 200, description = "Order linked to contract", body = Order), - (status = 404, description = "Not found", body = ApiError), - (status = 401, description = "Unauthorized", body = ApiError), - (status = 503, description = "Database not configured", body = ApiError), - ), - security(("bearer_auth" = []), ("api_key" = [])), - tag = "Orders" -)] -pub async fn link_to_contract( - State(state): State, - Authenticated(auth): Authenticated, - Path(id): Path, - Json(req): Json, -) -> impl IntoResponse { - let Some(ref pool) = state.db_pool else { - return ( - StatusCode::SERVICE_UNAVAILABLE, - Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")), - ) - .into_response(); - }; - - // Verify the contract exists and belongs to this owner - match repository::get_contract_for_owner(pool, auth.owner_id, req.contract_id).await { - Ok(Some(_)) => {} - Ok(None) => { - return ( - StatusCode::NOT_FOUND, - Json(ApiError::new("NOT_FOUND", "Contract not found")), - ) - .into_response(); - } - Err(e) => { - return ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(ApiError::new("GET_FAILED", &e.to_string())), - ) - .into_response(); - } - } - - match repository::link_order_to_contract(pool, auth.owner_id, id, req.contract_id).await { - Ok(Some(order)) => Json(order).into_response(), - Ok(None) => ( - StatusCode::NOT_FOUND, - Json(ApiError::new("NOT_FOUND", "Order not found")), - ) - .into_response(), - Err(e) => { - tracing::error!("Failed to link order to contract: {}", e); - ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(ApiError::new("LINK_FAILED", &e.to_string())), - ) - .into_response() - } - } -} - /// Convert an order to a directive step. -/// Creates a new step in the specified directive using the order's title/description, -/// and links the order to both the directive and the new step. +/// Creates a new step in the order's linked directive using the order's title/description, +/// and links the order to the new step. The order must have a directive_id set. #[utoipa::path( post, path = "/api/v1/orders/{id}/convert-to-step", params(("id" = Uuid, Path, description = "Order ID")), - request_body = ConvertToStepRequest, responses( (status = 201, description = "Directive step created from order", body = DirectiveStep), (status = 404, description = "Order or directive not found", body = ApiError), @@ -414,7 +347,6 @@ pub async fn convert_to_step( State(state): State, Authenticated(auth): Authenticated, Path(id): Path, - Json(req): Json, ) -> impl IntoResponse { let Some(ref pool) = state.db_pool else { return ( @@ -424,11 +356,14 @@ pub async fn convert_to_step( .into_response(); }; - match repository::convert_order_to_step(pool, auth.owner_id, id, req.directive_id).await { + match repository::convert_order_to_step(pool, auth.owner_id, id).await { Ok(Some(step)) => (StatusCode::CREATED, Json(step)).into_response(), Ok(None) => ( StatusCode::NOT_FOUND, - Json(ApiError::new("NOT_FOUND", "Order or directive not found")), + Json(ApiError::new( + "NOT_FOUND", + "Order not found or has no linked directive", + )), ) .into_response(), Err(e) => { -- cgit v1.2.3