@runtypelabs/react-flow 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -130,7 +130,8 @@ const sampleSteps: FlowStep[] = [
130
130
  config: {
131
131
  mode: 'instruction',
132
132
  model: 'gpt-4',
133
- userPrompt: 'Generate detailed premium insights for {{user_data.name}} based on their usage patterns:\n\n{{analysis}}',
133
+ userPrompt:
134
+ 'Generate detailed premium insights for {{user_data.name}} based on their usage patterns:\n\n{{analysis}}',
134
135
  responseFormat: 'json',
135
136
  outputVariable: 'premium_insights',
136
137
  },
@@ -160,7 +161,8 @@ const sampleSteps: FlowStep[] = [
160
161
  config: {
161
162
  mode: 'instruction',
162
163
  model: 'gpt-3.5-turbo',
163
- userPrompt: 'Generate a friendly upgrade pitch for {{user_data.name}} highlighting premium benefits. Keep it short and compelling.',
164
+ userPrompt:
165
+ 'Generate a friendly upgrade pitch for {{user_data.name}} highlighting premium benefits. Keep it short and compelling.',
164
166
  responseFormat: 'text',
165
167
  outputVariable: 'upgrade_pitch',
166
168
  },
@@ -322,7 +324,10 @@ function DispatchPanel({ isOpen, onClose, steps, flowName }: DispatchPanelProps)
322
324
  const client = createClient({ apiKey: 'your-api-key' })
323
325
 
324
326
  // Execute the flow
325
- const response = await client.dispatch.execute(${JSON.stringify(dispatchConfig, null, 2).split('\n').map((line, i) => i === 0 ? line : ' ' + line).join('\n')})
327
+ const response = await client.dispatch.execute(${JSON.stringify(dispatchConfig, null, 2)
328
+ .split('\n')
329
+ .map((line, i) => (i === 0 ? line : ' ' + line))
330
+ .join('\n')})
326
331
 
327
332
  console.log(response)`}</pre>
328
333
  </div>
@@ -330,9 +335,7 @@ console.log(response)`}</pre>
330
335
  </>
331
336
  ) : (
332
337
  <>
333
- <p style={descriptionStyle}>
334
- Individual step configurations in the flow:
335
- </p>
338
+ <p style={descriptionStyle}>Individual step configurations in the flow:</p>
336
339
  {steps.map((step, index) => (
337
340
  <div key={step.id} style={stepCardStyle}>
338
341
  <div style={stepHeaderStyle}>
@@ -353,9 +356,12 @@ console.log(response)`}</pre>
353
356
 
354
357
  {/* Footer */}
355
358
  <div style={panelFooterStyle}>
356
- <button style={copyButtonStyle} onClick={() => {
357
- navigator.clipboard.writeText(JSON.stringify(dispatchConfig, null, 2))
358
- }}>
359
+ <button
360
+ style={copyButtonStyle}
361
+ onClick={() => {
362
+ navigator.clipboard.writeText(JSON.stringify(dispatchConfig, null, 2))
363
+ }}
364
+ >
359
365
  <CopyIcon /> Copy Config
360
366
  </button>
361
367
  </div>
@@ -376,7 +382,13 @@ interface ExecutionPanelProps {
376
382
  onRunFlow: () => void
377
383
  }
378
384
 
379
- function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }: ExecutionPanelProps) {
385
+ function ExecutionPanel({
386
+ isOpen,
387
+ onClose,
388
+ isRunning,
389
+ flowProgress,
390
+ onRunFlow,
391
+ }: ExecutionPanelProps) {
380
392
  if (!isOpen) return null
381
393
 
382
394
  const getStatusIcon = (status: string) => {
@@ -421,17 +433,15 @@ function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }:
421
433
  {!flowProgress && !isRunning && (
422
434
  <div style={{ textAlign: 'center', padding: '40px 20px' }}>
423
435
  <div style={{ fontSize: '48px', marginBottom: '16px' }}>🚀</div>
424
- <h3 style={{ fontSize: '18px', fontWeight: 600, color: '#cdd6f4', marginBottom: '8px' }}>
436
+ <h3
437
+ style={{ fontSize: '18px', fontWeight: 600, color: '#cdd6f4', marginBottom: '8px' }}
438
+ >
425
439
  Ready to Execute
426
440
  </h3>
427
441
  <p style={{ fontSize: '13px', color: '#a6adc8', marginBottom: '24px' }}>
428
442
  Click the button below to run this flow using the Runtype API
429
443
  </p>
430
- <button
431
- style={runButtonStyle}
432
- onClick={onRunFlow}
433
- disabled={isRunning}
434
- >
444
+ <button style={runButtonStyle} onClick={onRunFlow} disabled={isRunning}>
435
445
  <PlayIcon /> Run Flow
436
446
  </button>
437
447
  </div>
@@ -442,7 +452,13 @@ function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }:
442
452
  {/* Progress Header */}
443
453
  <div style={progressHeaderStyle}>
444
454
  <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
445
- {isRunning ? <SpinnerIcon /> : flowProgress?.isError ? <ErrorIcon /> : <CheckIcon />}
455
+ {isRunning ? (
456
+ <SpinnerIcon />
457
+ ) : flowProgress?.isError ? (
458
+ <ErrorIcon />
459
+ ) : (
460
+ <CheckIcon />
461
+ )}
446
462
  <div>
447
463
  <div style={{ fontSize: '14px', fontWeight: 600, color: '#cdd6f4' }}>
448
464
  {flowProgress?.flowName || 'Executing Flow...'}
@@ -451,8 +467,8 @@ function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }:
451
467
  {isRunning
452
468
  ? `Step ${(flowProgress?.currentStepIndex ?? 0) + 1} of ${flowProgress?.totalSteps || '?'}`
453
469
  : flowProgress?.isError
454
- ? 'Execution failed'
455
- : `Completed in ${flowProgress?.executionTime || 0}ms`}
470
+ ? 'Execution failed'
471
+ : `Completed in ${flowProgress?.executionTime || 0}ms`}
456
472
  </div>
457
473
  </div>
458
474
  </div>
@@ -485,7 +501,7 @@ function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }:
485
501
  </span>
486
502
  )}
487
503
  </div>
488
-
504
+
489
505
  {/* Streaming Text Output */}
490
506
  {step.streamingText && (
491
507
  <div style={streamingOutputStyle}>
@@ -494,14 +510,10 @@ function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }:
494
510
  </pre>
495
511
  </div>
496
512
  )}
497
-
513
+
498
514
  {/* Error */}
499
- {step.error && (
500
- <div style={errorOutputStyle}>
501
- {step.error}
502
- </div>
503
- )}
504
-
515
+ {step.error && <div style={errorOutputStyle}>{step.error}</div>}
516
+
505
517
  {/* Result (collapsed by default) */}
506
518
  {step.result && !step.streamingText && (
507
519
  <details style={{ marginTop: '8px' }}>
@@ -510,8 +522,8 @@ function ExecutionPanel({ isOpen, onClose, isRunning, flowProgress, onRunFlow }:
510
522
  </summary>
511
523
  <div style={codeBlockStyle}>
512
524
  <pre style={{ ...preStyle, fontSize: '10px' }}>
513
- {typeof step.result === 'string'
514
- ? step.result
525
+ {typeof step.result === 'string'
526
+ ? step.result
515
527
  : JSON.stringify(step.result, null, 2)}
516
528
  </pre>
517
529
  </div>
@@ -557,7 +569,7 @@ function FlowBrowserPanel({ isOpen, onClose, onLoadFlow }: FlowBrowserPanelProps
557
569
  try {
558
570
  const response = await fetch(`${API_BASE_URL}/flows`, {
559
571
  headers: {
560
- 'Authorization': `Bearer ${API_KEY}`,
572
+ Authorization: `Bearer ${API_KEY}`,
561
573
  },
562
574
  })
563
575
  if (!response.ok) {
@@ -580,7 +592,7 @@ function FlowBrowserPanel({ isOpen, onClose, onLoadFlow }: FlowBrowserPanelProps
580
592
  // Fetch flow details with embedded steps
581
593
  const flowResponse = await fetch(`${API_BASE_URL}/flows/${flowId}`, {
582
594
  headers: {
583
- 'Authorization': `Bearer ${API_KEY}`,
595
+ Authorization: `Bearer ${API_KEY}`,
584
596
  },
585
597
  })
586
598
  if (!flowResponse.ok) {
@@ -634,26 +646,30 @@ function FlowBrowserPanel({ isOpen, onClose, onLoadFlow }: FlowBrowserPanelProps
634
646
  )}
635
647
 
636
648
  {error && (
637
- <div style={{
638
- padding: '16px',
639
- backgroundColor: 'rgba(239, 68, 68, 0.1)',
640
- borderRadius: '8px',
641
- marginBottom: '16px',
642
- border: '1px solid rgba(239, 68, 68, 0.3)'
643
- }}>
644
- <div style={{ color: '#ef4444', fontSize: '13px', fontWeight: 600, marginBottom: '4px' }}>
649
+ <div
650
+ style={{
651
+ padding: '16px',
652
+ backgroundColor: 'rgba(239, 68, 68, 0.1)',
653
+ borderRadius: '8px',
654
+ marginBottom: '16px',
655
+ border: '1px solid rgba(239, 68, 68, 0.3)',
656
+ }}
657
+ >
658
+ <div
659
+ style={{ color: '#ef4444', fontSize: '13px', fontWeight: 600, marginBottom: '4px' }}
660
+ >
645
661
  Error
646
662
  </div>
647
- <div style={{ color: '#fca5a5', fontSize: '12px' }}>
648
- {error}
649
- </div>
663
+ <div style={{ color: '#fca5a5', fontSize: '12px' }}>{error}</div>
650
664
  </div>
651
665
  )}
652
666
 
653
667
  {!isLoading && flows.length === 0 && !error && (
654
668
  <div style={{ textAlign: 'center', padding: '40px 20px' }}>
655
669
  <div style={{ fontSize: '48px', marginBottom: '16px' }}>📁</div>
656
- <h3 style={{ fontSize: '16px', fontWeight: 600, color: '#cdd6f4', marginBottom: '8px' }}>
670
+ <h3
671
+ style={{ fontSize: '16px', fontWeight: 600, color: '#cdd6f4', marginBottom: '8px' }}
672
+ >
657
673
  No Flows Found
658
674
  </h3>
659
675
  <p style={{ fontSize: '13px', color: '#a6adc8' }}>
@@ -685,28 +701,44 @@ function FlowBrowserPanel({ isOpen, onClose, onLoadFlow }: FlowBrowserPanelProps
685
701
  e.currentTarget.style.backgroundColor = '#181825'
686
702
  }}
687
703
  >
688
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
704
+ <div
705
+ style={{
706
+ display: 'flex',
707
+ alignItems: 'center',
708
+ justifyContent: 'space-between',
709
+ }}
710
+ >
689
711
  <div style={{ flex: 1 }}>
690
- <div style={{ fontSize: '14px', fontWeight: 600, color: '#cdd6f4', marginBottom: '4px' }}>
712
+ <div
713
+ style={{
714
+ fontSize: '14px',
715
+ fontWeight: 600,
716
+ color: '#cdd6f4',
717
+ marginBottom: '4px',
718
+ }}
719
+ >
691
720
  {flow.name}
692
721
  </div>
693
722
  <div style={{ fontSize: '11px', color: '#6c7086' }}>
694
723
  {flow.status} • Updated: {new Date(flow.updated_at).toLocaleDateString()}
695
- {flow.last_run_at && ` • Last run: ${new Date(flow.last_run_at).toLocaleDateString()}`}
724
+ {flow.last_run_at &&
725
+ ` • Last run: ${new Date(flow.last_run_at).toLocaleDateString()}`}
696
726
  </div>
697
727
  </div>
698
728
  <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
699
729
  {loadingFlowId === flow.id ? (
700
730
  <SpinnerIcon />
701
731
  ) : (
702
- <div style={{
703
- padding: '6px 12px',
704
- backgroundColor: '#89b4fa',
705
- color: '#1e1e2e',
706
- borderRadius: '6px',
707
- fontSize: '12px',
708
- fontWeight: 600,
709
- }}>
732
+ <div
733
+ style={{
734
+ padding: '6px 12px',
735
+ backgroundColor: '#89b4fa',
736
+ color: '#1e1e2e',
737
+ borderRadius: '6px',
738
+ fontSize: '12px',
739
+ fontWeight: 600,
740
+ }}
741
+ >
710
742
  Load
711
743
  </div>
712
744
  )}
@@ -753,53 +785,59 @@ export default function App() {
753
785
  const [isInitialized, setIsInitialized] = useState(false)
754
786
 
755
787
  // Handler that updates both steps AND nodes
756
- const handleStepChangeWithNodes = useCallback((stepId: string, updates: Partial<FlowStep>) => {
757
- // console.log('[App] handleStepChangeWithNodes:', stepId, updates)
758
- // Update steps state
759
- setSteps((prev) =>
760
- prev.map((step) => {
761
- if (step.id === stepId) {
762
- return {
763
- ...step,
764
- ...updates,
765
- config: updates.config ? { ...step.config, ...updates.config } : step.config,
766
- }
767
- }
768
- return step
769
- })
770
- )
771
-
772
- // Update nodes state to reflect the change
773
- setNodes((nds) =>
774
- nds.map((node) => {
775
- if (node.id === stepId) {
776
- const updatedStep = {
777
- ...node.data.step,
778
- ...updates,
779
- config: updates.config
780
- ? { ...node.data.step.config, ...updates.config }
781
- : node.data.step.config,
788
+ const handleStepChangeWithNodes = useCallback(
789
+ (stepId: string, updates: Partial<FlowStep>) => {
790
+ // console.log('[App] handleStepChangeWithNodes:', stepId, updates)
791
+ // Update steps state
792
+ setSteps((prev) =>
793
+ prev.map((step) => {
794
+ if (step.id === stepId) {
795
+ return {
796
+ ...step,
797
+ ...updates,
798
+ config: updates.config ? { ...step.config, ...updates.config } : step.config,
799
+ }
782
800
  }
783
- return {
784
- ...node,
785
- data: {
786
- ...node.data,
787
- step: updatedStep,
788
- label: updatedStep.name,
789
- },
801
+ return step
802
+ })
803
+ )
804
+
805
+ // Update nodes state to reflect the change
806
+ setNodes((nds) =>
807
+ nds.map((node) => {
808
+ if (node.id === stepId) {
809
+ const updatedStep = {
810
+ ...node.data.step,
811
+ ...updates,
812
+ config: updates.config
813
+ ? { ...node.data.step.config, ...updates.config }
814
+ : node.data.step.config,
815
+ }
816
+ return {
817
+ ...node,
818
+ data: {
819
+ ...node.data,
820
+ step: updatedStep,
821
+ label: updatedStep.name,
822
+ },
823
+ }
790
824
  }
791
- }
792
- return node
793
- })
794
- )
795
- }, [setNodes])
825
+ return node
826
+ })
827
+ )
828
+ },
829
+ [setNodes]
830
+ )
796
831
 
797
832
  // Handler that updates both steps AND nodes for deletion
798
- const handleStepDeleteWithNodes = useCallback((stepId: string) => {
799
- setSteps((prev) => prev.filter((step) => step.id !== stepId))
800
- setNodes((nds) => nds.filter((node) => node.id !== stepId))
801
- setEdges((eds) => eds.filter((edge) => edge.source !== stepId && edge.target !== stepId))
802
- }, [setNodes, setEdges])
833
+ const handleStepDeleteWithNodes = useCallback(
834
+ (stepId: string) => {
835
+ setSteps((prev) => prev.filter((step) => step.id !== stepId))
836
+ setNodes((nds) => nds.filter((node) => node.id !== stepId))
837
+ setEdges((eds) => eds.filter((edge) => edge.source !== stepId && edge.target !== stepId))
838
+ },
839
+ [setNodes, setEdges]
840
+ )
803
841
 
804
842
  // Initialize nodes on first render
805
843
  React.useEffect(() => {
@@ -814,7 +852,14 @@ export default function App() {
814
852
  setEdges(initialEdges)
815
853
  setIsInitialized(true)
816
854
  }
817
- }, [isInitialized, steps, handleStepChangeWithNodes, handleStepDeleteWithNodes, setNodes, setEdges])
855
+ }, [
856
+ isInitialized,
857
+ steps,
858
+ handleStepChangeWithNodes,
859
+ handleStepDeleteWithNodes,
860
+ setNodes,
861
+ setEdges,
862
+ ])
818
863
 
819
864
  // Derive current steps from nodes
820
865
  const currentSteps = useMemo(() => {
@@ -827,7 +872,7 @@ export default function App() {
827
872
  setSteps(flow.steps)
828
873
  setFlowName(flow.name)
829
874
  setLoadedFlowId(flow.id)
830
-
875
+
831
876
  // Reset initialization so nodes get rebuilt
832
877
  setIsInitialized(false)
833
878
  }, [])
@@ -838,38 +883,41 @@ export default function App() {
838
883
  )
839
884
 
840
885
  // Add a new step
841
- const addStep = useCallback((type: FlowStep['type']) => {
842
- const newStep = createDefaultStep(type, nodes.length)
843
- setSteps((prev) => [...prev, newStep])
844
-
845
- const newNode: RuntypeNode = {
846
- id: newStep.id,
847
- type: newStep.type,
848
- position: { x: 400, y: nodes.length * 230 + 50 },
849
- data: {
850
- step: newStep,
851
- label: newStep.name,
852
- onChange: handleStepChangeWithNodes,
853
- onDelete: handleStepDeleteWithNodes,
854
- },
855
- }
856
-
857
- setNodes((nds) => [...nds, newNode])
858
-
859
- // Add edge from last node
860
- if (nodes.length > 0) {
861
- const lastNode = nodes[nodes.length - 1]
862
- setEdges((eds) => [
863
- ...eds,
864
- {
865
- id: `edge-${lastNode.id}-${newNode.id}`,
866
- source: lastNode.id,
867
- target: newNode.id,
868
- type: 'smoothstep',
886
+ const addStep = useCallback(
887
+ (type: FlowStep['type']) => {
888
+ const newStep = createDefaultStep(type, nodes.length)
889
+ setSteps((prev) => [...prev, newStep])
890
+
891
+ const newNode: RuntypeNode = {
892
+ id: newStep.id,
893
+ type: newStep.type,
894
+ position: { x: 400, y: nodes.length * 230 + 50 },
895
+ data: {
896
+ step: newStep,
897
+ label: newStep.name,
898
+ onChange: handleStepChangeWithNodes,
899
+ onDelete: handleStepDeleteWithNodes,
869
900
  },
870
- ])
871
- }
872
- }, [nodes, setNodes, setEdges, handleStepChangeWithNodes, handleStepDeleteWithNodes])
901
+ }
902
+
903
+ setNodes((nds) => [...nds, newNode])
904
+
905
+ // Add edge from last node
906
+ if (nodes.length > 0) {
907
+ const lastNode = nodes[nodes.length - 1]
908
+ setEdges((eds) => [
909
+ ...eds,
910
+ {
911
+ id: `edge-${lastNode.id}-${newNode.id}`,
912
+ source: lastNode.id,
913
+ target: newNode.id,
914
+ type: 'smoothstep',
915
+ },
916
+ ])
917
+ }
918
+ },
919
+ [nodes, setNodes, setEdges, handleStepChangeWithNodes, handleStepDeleteWithNodes]
920
+ )
873
921
 
874
922
  // Execute flow via Runtype API
875
923
  const executeFlow = useCallback(async () => {
@@ -918,7 +966,7 @@ export default function App() {
918
966
  method: 'POST',
919
967
  headers: {
920
968
  'Content-Type': 'application/json',
921
- 'Authorization': `Bearer ${API_KEY}`,
969
+ Authorization: `Bearer ${API_KEY}`,
922
970
  },
923
971
  body: JSON.stringify(dispatchRequest),
924
972
  })
@@ -1004,8 +1052,8 @@ export default function App() {
1004
1052
  setFlowProgress((prev) => {
1005
1053
  if (!prev) return null
1006
1054
  const stepIndex = data.index !== undefined ? data.index : prev.steps.length
1007
- const existingIndex = prev.steps.findIndex(s => s.id === data.id)
1008
-
1055
+ const existingIndex = prev.steps.findIndex((s) => s.id === data.id)
1056
+
1009
1057
  if (existingIndex >= 0) {
1010
1058
  const newSteps = [...prev.steps]
1011
1059
  newSteps[existingIndex] = {
@@ -1019,7 +1067,7 @@ export default function App() {
1019
1067
  currentStepIndex: Math.max(prev.currentStepIndex, stepIndex),
1020
1068
  }
1021
1069
  }
1022
-
1070
+
1023
1071
  return {
1024
1072
  ...prev,
1025
1073
  steps: [
@@ -1039,8 +1087,8 @@ export default function App() {
1039
1087
  case 'step_chunk':
1040
1088
  setFlowProgress((prev) => {
1041
1089
  if (!prev) return null
1042
- const stepIndex = prev.steps.findIndex(s => s.id === data.id)
1043
-
1090
+ const stepIndex = prev.steps.findIndex((s) => s.id === data.id)
1091
+
1044
1092
  if (stepIndex < 0) {
1045
1093
  const chunkStepIndex = data.index !== undefined ? data.index : prev.steps.length
1046
1094
  return {
@@ -1057,11 +1105,12 @@ export default function App() {
1057
1105
  ].sort((a, b) => a.index - b.index),
1058
1106
  }
1059
1107
  }
1060
-
1108
+
1061
1109
  const newSteps = [...prev.steps]
1062
1110
  newSteps[stepIndex] = {
1063
1111
  ...newSteps[stepIndex],
1064
- streamingText: (newSteps[stepIndex].streamingText || '') + (data.text || data.content || ''),
1112
+ streamingText:
1113
+ (newSteps[stepIndex].streamingText || '') + (data.text || data.content || ''),
1065
1114
  }
1066
1115
  return { ...prev, steps: newSteps }
1067
1116
  })
@@ -1070,16 +1119,16 @@ export default function App() {
1070
1119
  case 'step_complete':
1071
1120
  setFlowProgress((prev) => {
1072
1121
  if (!prev) return null
1073
- const stepIndex = prev.steps.findIndex(s => s.id === data.id)
1122
+ const stepIndex = prev.steps.findIndex((s) => s.id === data.id)
1074
1123
  if (stepIndex >= 0) {
1075
1124
  const newSteps = [...prev.steps]
1076
1125
  const step = newSteps[stepIndex]
1077
-
1126
+
1078
1127
  let finalText = step.streamingText
1079
1128
  if (!finalText && data.output?.message) {
1080
1129
  finalText = data.output.message
1081
1130
  }
1082
-
1131
+
1083
1132
  newSteps[stepIndex] = {
1084
1133
  ...step,
1085
1134
  status: 'completed',
@@ -1087,7 +1136,7 @@ export default function App() {
1087
1136
  streamingText: finalText,
1088
1137
  executionTime: data.executionTime,
1089
1138
  }
1090
-
1139
+
1091
1140
  return {
1092
1141
  ...prev,
1093
1142
  steps: newSteps.sort((a, b) => a.index - b.index),
@@ -1100,7 +1149,7 @@ export default function App() {
1100
1149
  case 'step_error':
1101
1150
  setFlowProgress((prev) => {
1102
1151
  if (!prev) return null
1103
- const stepIndex = prev.steps.findIndex(s => s.id === data.id)
1152
+ const stepIndex = prev.steps.findIndex((s) => s.id === data.id)
1104
1153
  if (stepIndex >= 0) {
1105
1154
  const newSteps = [...prev.steps]
1106
1155
  newSteps[stepIndex] = {
@@ -1151,22 +1200,13 @@ export default function App() {
1151
1200
  Flow: <strong style={{ color: '#cdd6f4' }}>{flowName}</strong>
1152
1201
  </span>
1153
1202
  )}
1154
- <button
1155
- style={loadFlowButtonStyle}
1156
- onClick={() => setShowFlowBrowser(true)}
1157
- >
1203
+ <button style={loadFlowButtonStyle} onClick={() => setShowFlowBrowser(true)}>
1158
1204
  <FolderIcon /> Load Flow
1159
1205
  </button>
1160
- <button
1161
- style={runFlowButtonStyle}
1162
- onClick={() => setShowExecutionPanel(true)}
1163
- >
1206
+ <button style={runFlowButtonStyle} onClick={() => setShowExecutionPanel(true)}>
1164
1207
  <PlayIcon /> Run Flow
1165
1208
  </button>
1166
- <button
1167
- style={viewConfigButtonStyle}
1168
- onClick={() => setShowDispatchPanel(true)}
1169
- >
1209
+ <button style={viewConfigButtonStyle} onClick={() => setShowDispatchPanel(true)}>
1170
1210
  <CodeIcon /> View Dispatch Config
1171
1211
  </button>
1172
1212
  </div>
@@ -1268,7 +1308,14 @@ export default function App() {
1268
1308
 
1269
1309
  function CloseIcon() {
1270
1310
  return (
1271
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1311
+ <svg
1312
+ width="18"
1313
+ height="18"
1314
+ viewBox="0 0 24 24"
1315
+ fill="none"
1316
+ stroke="currentColor"
1317
+ strokeWidth="2"
1318
+ >
1272
1319
  <line x1="18" y1="6" x2="6" y2="18" />
1273
1320
  <line x1="6" y1="6" x2="18" y2="18" />
1274
1321
  </svg>
@@ -1277,7 +1324,14 @@ function CloseIcon() {
1277
1324
 
1278
1325
  function CopyIcon() {
1279
1326
  return (
1280
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1327
+ <svg
1328
+ width="14"
1329
+ height="14"
1330
+ viewBox="0 0 24 24"
1331
+ fill="none"
1332
+ stroke="currentColor"
1333
+ strokeWidth="2"
1334
+ >
1281
1335
  <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
1282
1336
  <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
1283
1337
  </svg>
@@ -1286,7 +1340,14 @@ function CopyIcon() {
1286
1340
 
1287
1341
  function CodeIcon() {
1288
1342
  return (
1289
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1343
+ <svg
1344
+ width="16"
1345
+ height="16"
1346
+ viewBox="0 0 24 24"
1347
+ fill="none"
1348
+ stroke="currentColor"
1349
+ strokeWidth="2"
1350
+ >
1290
1351
  <polyline points="16 18 22 12 16 6" />
1291
1352
  <polyline points="8 6 2 12 8 18" />
1292
1353
  </svg>
@@ -1295,7 +1356,14 @@ function CodeIcon() {
1295
1356
 
1296
1357
  function PlayIcon() {
1297
1358
  return (
1298
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1359
+ <svg
1360
+ width="16"
1361
+ height="16"
1362
+ viewBox="0 0 24 24"
1363
+ fill="none"
1364
+ stroke="currentColor"
1365
+ strokeWidth="2"
1366
+ >
1299
1367
  <polygon points="5 3 19 12 5 21 5 3" />
1300
1368
  </svg>
1301
1369
  )
@@ -1303,7 +1371,14 @@ function PlayIcon() {
1303
1371
 
1304
1372
  function FolderIcon() {
1305
1373
  return (
1306
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1374
+ <svg
1375
+ width="16"
1376
+ height="16"
1377
+ viewBox="0 0 24 24"
1378
+ fill="none"
1379
+ stroke="currentColor"
1380
+ strokeWidth="2"
1381
+ >
1307
1382
  <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
1308
1383
  </svg>
1309
1384
  )
@@ -1311,7 +1386,14 @@ function FolderIcon() {
1311
1386
 
1312
1387
  function RefreshIcon() {
1313
1388
  return (
1314
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1389
+ <svg
1390
+ width="14"
1391
+ height="14"
1392
+ viewBox="0 0 24 24"
1393
+ fill="none"
1394
+ stroke="currentColor"
1395
+ strokeWidth="2"
1396
+ >
1315
1397
  <polyline points="23 4 23 10 17 10" />
1316
1398
  <polyline points="1 20 1 14 7 14" />
1317
1399
  <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" />
@@ -1338,7 +1420,14 @@ function SpinnerIcon() {
1338
1420
 
1339
1421
  function CheckIcon() {
1340
1422
  return (
1341
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1423
+ <svg
1424
+ width="16"
1425
+ height="16"
1426
+ viewBox="0 0 24 24"
1427
+ fill="none"
1428
+ stroke="currentColor"
1429
+ strokeWidth="2"
1430
+ >
1342
1431
  <polyline points="20 6 9 17 4 12" />
1343
1432
  </svg>
1344
1433
  )
@@ -1346,7 +1435,14 @@ function CheckIcon() {
1346
1435
 
1347
1436
  function ErrorIcon() {
1348
1437
  return (
1349
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1438
+ <svg
1439
+ width="16"
1440
+ height="16"
1441
+ viewBox="0 0 24 24"
1442
+ fill="none"
1443
+ stroke="currentColor"
1444
+ strokeWidth="2"
1445
+ >
1350
1446
  <circle cx="12" cy="12" r="10" />
1351
1447
  <line x1="15" y1="9" x2="9" y2="15" />
1352
1448
  <line x1="9" y1="9" x2="15" y2="15" />
@@ -1356,7 +1452,14 @@ function ErrorIcon() {
1356
1452
 
1357
1453
  function PendingIcon() {
1358
1454
  return (
1359
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
1455
+ <svg
1456
+ width="16"
1457
+ height="16"
1458
+ viewBox="0 0 24 24"
1459
+ fill="none"
1460
+ stroke="currentColor"
1461
+ strokeWidth="2"
1462
+ >
1360
1463
  <circle cx="12" cy="12" r="10" />
1361
1464
  </svg>
1362
1465
  )
@@ -1679,10 +1782,10 @@ const stepHeaderStyle: React.CSSProperties = {
1679
1782
 
1680
1783
  const stepBadgeStyle = (type: string): React.CSSProperties => {
1681
1784
  const colors: Record<string, { bg: string; text: string }> = {
1682
- 'prompt': { bg: '#cba6f7', text: '#1e1e2e' },
1785
+ prompt: { bg: '#cba6f7', text: '#1e1e2e' },
1683
1786
  'fetch-url': { bg: '#89b4fa', text: '#1e1e2e' },
1684
1787
  'transform-data': { bg: '#f9e2af', text: '#1e1e2e' },
1685
- 'conditional': { bg: '#f5c2e7', text: '#1e1e2e' },
1788
+ conditional: { bg: '#f5c2e7', text: '#1e1e2e' },
1686
1789
  'send-email': { bg: '#a6e3a1', text: '#1e1e2e' },
1687
1790
  }
1688
1791
  const color = colors[type] || { bg: '#6c7086', text: '#cdd6f4' }