diff options
Diffstat (limited to 'makima/frontend/src/lib')
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index 17cf1d0..f777ba0 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -3597,7 +3597,7 @@ export async function pickUpOrders(directiveId: string): Promise<PickUpOrdersRes // to plain `Contract`. URLs and the user-facing UI already say "contract". // ============================================================================= -export type DirectiveContractStatus = "draft" | "active" | "shipped" | "archived"; +export type DirectiveContractStatus = "draft" | "queued" | "active" | "shipped" | "archived"; /** How a contract's commits land. `shared` (default): on the directive's * branch — multiple contracts feed one PR. `own_pr`: a contract-specific @@ -3700,6 +3700,58 @@ export async function reorderDirectiveContract( return res.json(); } +// ----- Lifecycle transitions ----------------------------------------------- +// +// Lock & Start: draft → queued (if a sibling is active) or active. +// Pause: active → queued; next queued sibling auto-promotes. +// Complete: active → shipped, optionally records pr_url + pr_branch. +// Unlock: queued or active → draft (reactivates editing). +// +// All four reach the same /contracts/{id}/<action> endpoint and surface +// 400 with a plain message string when the transition is invalid. + +async function postContractAction( + contractId: string, + action: "start" | "pause" | "complete" | "unlock", + body?: object, +): Promise<DirectiveContract> { + const res = await authFetch(`${API_BASE}/api/v1/contracts/${contractId}/${action}`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body ?? {}), + }); + if (!res.ok) { + let detail = res.statusText; + try { + const err = await res.json(); + if (err?.message) detail = err.message; + } catch { + /* fall through to statusText */ + } + throw new Error(`Failed to ${action} contract: ${detail}`); + } + return res.json(); +} + +export async function startDirectiveContract(contractId: string): Promise<DirectiveContract> { + return postContractAction(contractId, "start"); +} + +export async function pauseDirectiveContract(contractId: string): Promise<DirectiveContract> { + return postContractAction(contractId, "pause"); +} + +export async function completeDirectiveContract( + contractId: string, + opts: { prUrl?: string; prBranch?: string } = {}, +): Promise<DirectiveContract> { + return postContractAction(contractId, "complete", opts); +} + +export async function unlockDirectiveContract(contractId: string): Promise<DirectiveContract> { + return postContractAction(contractId, "unlock"); +} + /** Steps and tasks attached to a single contract. Drives the per-contract * `tasks/` subfolder in the sidebar — when the contract ships, its * tasks visually move with it. */ |
