123 lines
3.6 KiB
TypeScript
123 lines
3.6 KiB
TypeScript
|
|
// app/tasks/api.ts
|
||
|
|
// Browser-safe client for the /api/tasks routes.
|
||
|
|
|
||
|
|
import type { TaskStatus, TaskPriority, TaskType } from "./columns";
|
||
|
|
|
||
|
|
export interface Task {
|
||
|
|
id: string;
|
||
|
|
collectionId: string;
|
||
|
|
collectionName: string;
|
||
|
|
created: string;
|
||
|
|
updated: string;
|
||
|
|
title: string;
|
||
|
|
description: string | null;
|
||
|
|
task_type: TaskType;
|
||
|
|
payload: Record<string, unknown> | null;
|
||
|
|
status: TaskStatus;
|
||
|
|
priority: TaskPriority;
|
||
|
|
assignee: string | null;
|
||
|
|
claimed_by: string | null;
|
||
|
|
claimed_at: string | null;
|
||
|
|
started_at: string | null;
|
||
|
|
completed_at: string | null;
|
||
|
|
duration_ms: number | null;
|
||
|
|
result: unknown;
|
||
|
|
error: string | null;
|
||
|
|
log: string[] | null;
|
||
|
|
retry_count: number;
|
||
|
|
created_by: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface ListParams {
|
||
|
|
status?: TaskStatus | "all";
|
||
|
|
task_type?: TaskType;
|
||
|
|
priority?: TaskPriority;
|
||
|
|
include_done?: boolean;
|
||
|
|
limit?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function listTasks(params: ListParams = {}): Promise<Task[]> {
|
||
|
|
const qs = new URLSearchParams();
|
||
|
|
if (params.status) qs.set("status", params.status);
|
||
|
|
if (params.task_type) qs.set("task_type", params.task_type);
|
||
|
|
if (params.priority) qs.set("priority", params.priority);
|
||
|
|
if (params.include_done) qs.set("include_done", "true");
|
||
|
|
if (params.limit) qs.set("limit", String(params.limit));
|
||
|
|
|
||
|
|
const res = await fetch(`/api/tasks?${qs.toString()}`, { cache: "no-store" });
|
||
|
|
if (!res.ok) throw new Error(`list failed (${res.status})`);
|
||
|
|
const data = await res.json();
|
||
|
|
return data.items as Task[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function getTask(id: string): Promise<Task> {
|
||
|
|
const res = await fetch(`/api/tasks/${id}`, { cache: "no-store" });
|
||
|
|
if (!res.ok) throw new Error(`get failed (${res.status})`);
|
||
|
|
return res.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface CreateTaskInput {
|
||
|
|
title: string;
|
||
|
|
description?: string;
|
||
|
|
task_type: TaskType;
|
||
|
|
payload?: Record<string, unknown>;
|
||
|
|
status?: TaskStatus;
|
||
|
|
priority?: TaskPriority;
|
||
|
|
assignee?: string;
|
||
|
|
created_by?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function createTask(input: CreateTaskInput): Promise<Task> {
|
||
|
|
const res = await fetch(`/api/tasks`, {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
body: JSON.stringify(input),
|
||
|
|
});
|
||
|
|
if (!res.ok) {
|
||
|
|
const err = await res.json().catch(() => ({}));
|
||
|
|
throw new Error(err.error ?? `create failed (${res.status})`);
|
||
|
|
}
|
||
|
|
return res.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function patchTask(
|
||
|
|
id: string,
|
||
|
|
fields: Partial<Pick<Task, "title" | "description" | "priority" | "payload" | "assignee" | "status">>,
|
||
|
|
): Promise<Task> {
|
||
|
|
const res = await fetch(`/api/tasks/${id}`, {
|
||
|
|
method: "PATCH",
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
body: JSON.stringify(fields),
|
||
|
|
});
|
||
|
|
if (!res.ok) {
|
||
|
|
const err = await res.json().catch(() => ({}));
|
||
|
|
throw new Error(err.error ?? `patch failed (${res.status})`);
|
||
|
|
}
|
||
|
|
return res.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function deleteTask(id: string): Promise<void> {
|
||
|
|
const res = await fetch(`/api/tasks/${id}`, { method: "DELETE" });
|
||
|
|
if (!res.ok) throw new Error(`delete failed (${res.status})`);
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function retryTask(id: string): Promise<Task> {
|
||
|
|
const res = await fetch(`/api/tasks/${id}/retry`, { method: "POST" });
|
||
|
|
if (!res.ok) {
|
||
|
|
const err = await res.json().catch(() => ({}));
|
||
|
|
throw new Error(err.error ?? `retry failed (${res.status})`);
|
||
|
|
}
|
||
|
|
const data = await res.json();
|
||
|
|
return data.task as Task;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function cancelTask(id: string): Promise<Task> {
|
||
|
|
const res = await fetch(`/api/tasks/${id}/cancel`, { method: "POST" });
|
||
|
|
if (!res.ok) {
|
||
|
|
const err = await res.json().catch(() => ({}));
|
||
|
|
throw new Error(err.error ?? `cancel failed (${res.status})`);
|
||
|
|
}
|
||
|
|
const data = await res.json();
|
||
|
|
return data.task as Task;
|
||
|
|
}
|