feat(web): add project workspace page with tasks and agent sessions #479
1085
apps/web/src/app/(authenticated)/workspace/page.tsx
Normal file
1085
apps/web/src/app/(authenticated)/workspace/page.tsx
Normal file
File diff suppressed because it is too large
Load Diff
100
apps/web/src/lib/api/runner-jobs.ts
Normal file
100
apps/web/src/lib/api/runner-jobs.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* Runner Jobs API Client
|
||||||
|
* Handles runner-job-related API requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { apiGet, type ApiResponse } from "./client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runner job status enum (matches backend RunnerJobStatus)
|
||||||
|
*/
|
||||||
|
export enum RunnerJobStatus {
|
||||||
|
PENDING = "PENDING",
|
||||||
|
QUEUED = "QUEUED",
|
||||||
|
RUNNING = "RUNNING",
|
||||||
|
COMPLETED = "COMPLETED",
|
||||||
|
FAILED = "FAILED",
|
||||||
|
CANCELLED = "CANCELLED",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runner job response interface (matches Prisma RunnerJob model)
|
||||||
|
*/
|
||||||
|
export interface RunnerJob {
|
||||||
|
id: string;
|
||||||
|
workspaceId: string;
|
||||||
|
agentTaskId: string | null;
|
||||||
|
type: string;
|
||||||
|
status: RunnerJobStatus;
|
||||||
|
priority: number;
|
||||||
|
progressPercent: number;
|
||||||
|
version: number;
|
||||||
|
result: Record<string, unknown> | null;
|
||||||
|
error: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
startedAt: string | null;
|
||||||
|
completedAt: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters for querying runner jobs
|
||||||
|
*/
|
||||||
|
export interface RunnerJobFilters {
|
||||||
|
workspaceId?: string;
|
||||||
|
status?: RunnerJobStatus | RunnerJobStatus[];
|
||||||
|
type?: string;
|
||||||
|
agentTaskId?: string;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paginated runner jobs response
|
||||||
|
*/
|
||||||
|
export interface PaginatedRunnerJobs {
|
||||||
|
data: RunnerJob[];
|
||||||
|
meta?: {
|
||||||
|
total?: number;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch runner jobs with optional filters
|
||||||
|
*/
|
||||||
|
export async function fetchRunnerJobs(filters?: RunnerJobFilters): Promise<RunnerJob[]> {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
|
if (filters?.status) {
|
||||||
|
const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
|
||||||
|
for (const s of statuses) {
|
||||||
|
params.append("status", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filters?.type) {
|
||||||
|
params.append("type", filters.type);
|
||||||
|
}
|
||||||
|
if (filters?.agentTaskId) {
|
||||||
|
params.append("agentTaskId", filters.agentTaskId);
|
||||||
|
}
|
||||||
|
if (filters?.page !== undefined) {
|
||||||
|
params.append("page", String(filters.page));
|
||||||
|
}
|
||||||
|
if (filters?.limit !== undefined) {
|
||||||
|
params.append("limit", String(filters.limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryString = params.toString();
|
||||||
|
const endpoint = queryString ? `/api/runner-jobs?${queryString}` : "/api/runner-jobs";
|
||||||
|
|
||||||
|
const response = await apiGet<ApiResponse<RunnerJob[]>>(endpoint, filters?.workspaceId);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a single runner job by ID
|
||||||
|
*/
|
||||||
|
export async function fetchRunnerJob(id: string, workspaceId?: string): Promise<RunnerJob> {
|
||||||
|
return apiGet<RunnerJob>(`/api/runner-jobs/${id}`, workspaceId);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user