feat(workflows): M6 — dashboard run-history + DAG view
A per-app "Workflows" tab: list definitions, browse run history, and inspect a run's per-step progress with a static layered DAG. - API: the run-detail endpoint now returns each step's `depends_on` (loaded from the definition via a new `get_workflow_by_id` reader) so the dashboard can draw the graph edges — the run's step rows don't carry them. - dashboard `$lib/api`: a `workflows` namespace (list / runs / start / run) + the matching types. - `apps/[slug]/workflows/+page.svelte`: workflow table → drill into runs → drill into a run. The run view renders a step table plus an SVG DAG (nodes = steps colored by status, laid out by longest-path level; edges = depends_on, arrowed) and a "Start run" button. Nested/parked steps show their child run. - AppTabBar + the per-app layout gain the Workflows tab (admin-only). Tests: `npm run check` clean (0 errors); two Playwright smoke tests (navigation tabs — workflows loads cleanly + renders its empty state) pass against the full stack. With M6 the v1.2 Workflows track (M1 schema/validation → M2 durable orchestrator → M3 when/templating → M4 nested → M5 SDK/API/CLI → M6 dashboard) is COMPLETE. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -444,6 +444,57 @@ export interface CreateQueueTriggerInput {
|
||||
retry_base_ms?: number;
|
||||
}
|
||||
|
||||
// v1.2 Workflows — read/run types (admin workflows API).
|
||||
export interface WorkflowSummary {
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
steps: number;
|
||||
}
|
||||
|
||||
export type WorkflowRunStatus =
|
||||
| 'pending'
|
||||
| 'running'
|
||||
| 'succeeded'
|
||||
| 'failed'
|
||||
| 'canceled';
|
||||
|
||||
export interface WorkflowRun {
|
||||
id: string;
|
||||
workflow_id?: string;
|
||||
status: WorkflowRunStatus;
|
||||
error?: string | null;
|
||||
workflow_depth: number;
|
||||
created_at: string;
|
||||
input?: unknown;
|
||||
output?: unknown;
|
||||
started_at?: string | null;
|
||||
finished_at?: string | null;
|
||||
}
|
||||
|
||||
export type WorkflowStepStatus =
|
||||
| 'pending'
|
||||
| 'ready'
|
||||
| 'running'
|
||||
| 'succeeded'
|
||||
| 'failed'
|
||||
| 'skipped';
|
||||
|
||||
export interface WorkflowRunStep {
|
||||
name: string;
|
||||
status: WorkflowStepStatus;
|
||||
attempt: number;
|
||||
max_attempts: number;
|
||||
error?: string | null;
|
||||
child_run_id?: string | null;
|
||||
depends_on: string[];
|
||||
output?: unknown;
|
||||
}
|
||||
|
||||
export interface WorkflowRunDetail {
|
||||
run: WorkflowRun;
|
||||
steps: WorkflowRunStep[];
|
||||
}
|
||||
|
||||
// v1.1.9 — read-only queue inspection types (admin queues API).
|
||||
export interface QueueSummary {
|
||||
queue_name: string;
|
||||
@@ -1214,6 +1265,26 @@ export const api = {
|
||||
)
|
||||
},
|
||||
|
||||
workflows: {
|
||||
list: (idOrSlug: string) =>
|
||||
adminRequest<WorkflowSummary[]>(
|
||||
`/api/v1/admin/apps/${encodeURIComponent(idOrSlug)}/workflows`
|
||||
),
|
||||
runs: (idOrSlug: string, name: string) =>
|
||||
adminRequest<WorkflowRun[]>(
|
||||
`/api/v1/admin/apps/${encodeURIComponent(idOrSlug)}/workflows/${encodeURIComponent(name)}/runs`
|
||||
),
|
||||
start: (idOrSlug: string, name: string, input: unknown) =>
|
||||
adminRequest<WorkflowRun>(
|
||||
`/api/v1/admin/apps/${encodeURIComponent(idOrSlug)}/workflows/${encodeURIComponent(name)}/runs`,
|
||||
{ method: 'POST', body: JSON.stringify({ input }) }
|
||||
),
|
||||
run: (idOrSlug: string, runId: string) =>
|
||||
adminRequest<WorkflowRunDetail>(
|
||||
`/api/v1/admin/apps/${encodeURIComponent(idOrSlug)}/workflow-runs/${encodeURIComponent(runId)}`
|
||||
)
|
||||
},
|
||||
|
||||
topics: {
|
||||
list: (idOrSlug: string) =>
|
||||
adminRequest<{ topics: Topic[] }>(
|
||||
|
||||
Reference in New Issue
Block a user