# TASK-FE-011: Workflow Configuration UI **ID:** TASK-FE-011 **Title:** Workflow DSL Builder & Configuration UI **Category:** Administration **Priority:** P2 (Medium) **Effort:** 5-7 days **Dependencies:** TASK-FE-010, TASK-BE-006 **Assigned To:** Frontend Developer --- ## ๐Ÿ“‹ Overview Build UI for configuring and managing workflows using the DSL-based workflow engine, including visual workflow builder, DSL editor, and workflow testing interface. --- ## ๐ŸŽฏ Objectives 1. Create workflow list and management interface 2. Build DSL editor with syntax highlighting 3. Implement visual workflow builder (drag-and-drop) 4. Add workflow validation and testing tools 5. Create workflow template library 6. Implement workflow versioning UI --- ## โœ… Acceptance Criteria - [ ] List all workflows with status - [ ] Create/edit workflows with DSL editor - [ ] Visual workflow builder functional - [ ] DSL validation shows errors - [ ] Test workflow with sample data - [ ] Workflow templates available - [ ] Version history viewable --- ## ๐Ÿ”ง Implementation Steps ### Step 1: Workflow List Page ```typescript // File: src/app/(admin)/admin/workflows/page.tsx 'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Plus, Edit, Copy, Trash } from 'lucide-react'; import Link from 'next/link'; export default function WorkflowsPage() { const [workflows, setWorkflows] = useState([]); return (

Workflow Configuration

Manage workflow definitions and routing rules

{workflows.map((workflow: any) => (

{workflow.workflow_name}

{workflow.is_active ? 'Active' : 'Inactive'} v{workflow.version}

{workflow.description}

Type: {workflow.workflow_type} Steps: {workflow.step_count} Updated:{' '} {new Date(workflow.updated_at).toLocaleDateString()}
))}
); } ``` ### Step 2: DSL Editor Component ```typescript // File: src/components/workflows/dsl-editor.tsx 'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { CheckCircle, AlertCircle, Play } from 'lucide-react'; import Editor from '@monaco-editor/react'; interface DSLEditorProps { initialValue?: string; onChange?: (value: string) => void; } export function DSLEditor({ initialValue = '', onChange }: DSLEditorProps) { const [dsl, setDsl] = useState(initialValue); const [validationResult, setValidationResult] = useState(null); const [isValidating, setIsValidating] = useState(false); const handleEditorChange = (value: string | undefined) => { const newValue = value || ''; setDsl(newValue); onChange?.(newValue); setValidationResult(null); // Clear validation on change }; const validateDSL = async () => { setIsValidating(true); try { const response = await fetch('/api/workflows/validate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ dsl }), }); const result = await response.json(); setValidationResult(result); } catch (error) { setValidationResult({ valid: false, errors: ['Validation failed'] }); } finally { setIsValidating(false); } }; const testWorkflow = async () => { // Open test dialog }; return (

Workflow DSL

{validationResult && ( {validationResult.valid ? ( ) : ( )} {validationResult.valid ? ( 'DSL is valid โœ“' ) : (

Validation Errors:

    {validationResult.errors?.map((error: string, i: number) => (
  • {error}
  • ))}
)}
)}
); } ``` ### Step 3: Visual Workflow Builder ```typescript // File: src/components/workflows/visual-builder.tsx 'use client'; import { useState, useCallback } from 'react'; import ReactFlow, { Node, Edge, Controls, Background, useNodesState, useEdgesState, addEdge, Connection, } from 'reactflow'; import 'reactflow/dist/style.css'; import { Card } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; const nodeTypes = { start: { color: '#10b981' }, step: { color: '#3b82f6' }, condition: { color: '#f59e0b' }, end: { color: '#ef4444' }, }; export function VisualWorkflowBuilder() { const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); const onConnect = useCallback( (params: Connection) => setEdges((eds) => addEdge(params, eds)), [setEdges] ); const addNode = (type: string) => { const newNode: Node = { id: `${type}-${Date.now()}`, type: 'default', position: { x: Math.random() * 400, y: Math.random() * 400 }, data: { label: `${type} Node` }, style: { background: nodeTypes[type]?.color || '#gray', color: 'white', padding: 10, }, }; setNodes((nds) => [...nds, newNode]); }; const generateDSL = () => { // Convert visual workflow to DSL const dsl = { name: 'Generated Workflow', steps: nodes.map((node) => ({ step_name: node.data.label, step_type: 'APPROVAL', })), }; return JSON.stringify(dsl, null, 2); }; return (
); } ``` ### Step 4: Workflow Editor Page ```typescript // File: src/app/(admin)/admin/workflows/[id]/edit/page.tsx 'use client'; import { useState } from 'react'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { DSLEditor } from '@/components/workflows/dsl-editor'; import { VisualWorkflowBuilder } from '@/components/workflows/visual-builder'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Card } from '@/components/ui/card'; export default function WorkflowEditPage() { const [workflowData, setWorkflowData] = useState({ workflow_name: '', description: '', workflow_type: 'CORRESPONDENCE', dsl_definition: '', }); const handleSave = async () => { // Save workflow console.log('Saving workflow:', workflowData); }; return (

Edit Workflow

setWorkflowData({ ...workflowData, workflow_name: e.target.value, }) } />