import { useMemo } from 'react'; import { ReactFlow, Controls, Background, BackgroundVariant, MarkerType, type Node, type Edge, } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import type { NodeDef, EdgeDef } from '../../api/workflowDefinitions'; const NODE_TYPE_STYLES: Record = { StartEvent: { color: '#52c41a', radius: 50, width: 100 }, EndEvent: { color: '#ff4d4f', radius: 50, width: 100 }, UserTask: { color: '#1890ff', radius: 6, width: 160 }, ServiceTask: { color: '#722ed1', radius: 6, width: 160 }, ExclusiveGateway: { color: '#fa8c16', radius: 0, width: 100 }, ParallelGateway: { color: '#13c2c2', radius: 0, width: 100 }, }; interface ProcessViewerProps { nodes: NodeDef[]; edges: EdgeDef[]; activeNodeIds?: string[]; } export default function ProcessViewer({ nodes, edges, activeNodeIds = [] }: ProcessViewerProps) { const flowNodes: Node[] = useMemo(() => nodes.map((n, i) => { const style = NODE_TYPE_STYLES[n.type] || NODE_TYPE_STYLES.UserTask; const isActive = activeNodeIds.includes(n.id); return { id: n.id, type: 'default', position: n.position || { x: 200, y: i * 120 + 50 }, data: { label: n.name }, style: { background: isActive ? '#fff3cd' : style.color, color: isActive ? '#856404' : '#fff', padding: '8px 16px', borderRadius: style.radius, fontSize: 13, fontWeight: 500, border: isActive ? '3px solid #ffc107' : '2px solid rgba(255,255,255,0.3)', width: style.width, textAlign: 'center' as const, boxShadow: isActive ? '0 0 8px rgba(255,193,7,0.5)' : 'none', }, }; }), [nodes, activeNodeIds], ); const flowEdges: Edge[] = useMemo(() => edges.map((e) => ({ id: e.id, source: e.source, target: e.target, label: e.label || e.condition, markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#999' }, })), [edges], ); return (
); }