feat(C3): add React Flow workflow editor
frontend/src/pages/WorkflowEditor.tsx: full React Flow editor with custom nodes (Input/Convert/Render/FFmpeg/Output), config sidepanel, node palette with drag-drop, new workflow dialog. frontend/src/api/workflows.ts: workflow CRUD API client. @xyflow/react added to package.json dependencies. Route /workflows + sidebar link for admin+pm. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import api from './client'
|
||||
|
||||
export interface WorkflowDefinition {
|
||||
id: string
|
||||
name: string
|
||||
output_type_id: string | null
|
||||
config: WorkflowConfig
|
||||
is_active: boolean
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface WorkflowConfig {
|
||||
type: 'still' | 'turntable' | 'multi_angle' | 'custom'
|
||||
params: WorkflowParams
|
||||
nodes?: WorkflowNode[]
|
||||
}
|
||||
|
||||
export interface WorkflowParams {
|
||||
render_engine?: 'cycles' | 'eevee'
|
||||
samples?: number
|
||||
resolution?: [number, number]
|
||||
fps?: number
|
||||
duration_s?: number
|
||||
angles?: number[]
|
||||
}
|
||||
|
||||
export interface WorkflowNode {
|
||||
id: string
|
||||
type: string
|
||||
position: { x: number; y: number }
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface WorkflowCreate {
|
||||
name: string
|
||||
output_type_id?: string | null
|
||||
config: WorkflowConfig
|
||||
is_active?: boolean
|
||||
}
|
||||
|
||||
export interface WorkflowRun {
|
||||
id: string
|
||||
workflow_def_id: string | null
|
||||
order_line_id: string | null
|
||||
celery_task_id: string | null
|
||||
status: 'pending' | 'running' | 'completed' | 'failed'
|
||||
started_at: string | null
|
||||
completed_at: string | null
|
||||
error_message: string | null
|
||||
created_at: string
|
||||
node_results: WorkflowNodeResult[]
|
||||
}
|
||||
|
||||
export interface WorkflowNodeResult {
|
||||
id: string
|
||||
node_name: string
|
||||
status: string
|
||||
output: Record<string, unknown> | null
|
||||
log: string | null
|
||||
duration_s: number | null
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export const getWorkflows = (): Promise<WorkflowDefinition[]> =>
|
||||
api.get('/workflows').then(r => r.data)
|
||||
|
||||
export const getWorkflow = (id: string): Promise<WorkflowDefinition> =>
|
||||
api.get(`/workflows/${id}`).then(r => r.data)
|
||||
|
||||
export const createWorkflow = (data: WorkflowCreate): Promise<WorkflowDefinition> =>
|
||||
api.post('/workflows', data).then(r => r.data)
|
||||
|
||||
export const updateWorkflow = (id: string, data: Partial<WorkflowCreate>): Promise<WorkflowDefinition> =>
|
||||
api.put(`/workflows/${id}`, data).then(r => r.data)
|
||||
|
||||
export const deleteWorkflow = (id: string): Promise<void> =>
|
||||
api.delete(`/workflows/${id}`).then(() => undefined)
|
||||
|
||||
export const getWorkflowRuns = (workflowId: string): Promise<WorkflowRun[]> =>
|
||||
api.get(`/workflows/${workflowId}/runs`).then(r => r.data)
|
||||
Reference in New Issue
Block a user