@marktoflow/gui 2.0.0-alpha.5 → 2.0.1

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.
Files changed (164) hide show
  1. package/README.md +48 -180
  2. package/client.log +0 -0
  3. package/dist/client/assets/index-DQeR1ew6.css +1 -0
  4. package/dist/client/assets/index-LbIVPHbD.js +833 -0
  5. package/dist/client/assets/index-LbIVPHbD.js.map +1 -0
  6. package/dist/client/index.html +2 -2
  7. package/dist/client/marktoflow-logo.png +0 -0
  8. package/dist/server/index.js +31 -5
  9. package/dist/server/index.js.map +1 -1
  10. package/dist/server/routes/admin.js +95 -0
  11. package/dist/server/routes/admin.js.map +1 -0
  12. package/dist/server/routes/ai.js +2 -2
  13. package/dist/server/routes/ai.js.map +1 -1
  14. package/dist/server/routes/collaboration.js +104 -0
  15. package/dist/server/routes/collaboration.js.map +1 -0
  16. package/dist/server/routes/execute.js +181 -14
  17. package/dist/server/routes/execute.js.map +1 -1
  18. package/dist/server/routes/form.js +160 -0
  19. package/dist/server/routes/form.js.map +1 -0
  20. package/dist/server/routes/settings.js +90 -0
  21. package/dist/server/routes/settings.js.map +1 -0
  22. package/dist/server/routes/templates.js +106 -0
  23. package/dist/server/routes/templates.js.map +1 -0
  24. package/dist/server/routes/versions.js +101 -0
  25. package/dist/server/routes/versions.js.map +1 -0
  26. package/dist/server/services/AIService.js +85 -2
  27. package/dist/server/services/AIService.js.map +1 -1
  28. package/dist/server/services/ExecutionManager.js +571 -0
  29. package/dist/server/services/ExecutionManager.js.map +1 -0
  30. package/dist/server/services/VersionService.js +65 -0
  31. package/dist/server/services/VersionService.js.map +1 -0
  32. package/dist/server/services/WorkflowService.js +8 -2
  33. package/dist/server/services/WorkflowService.js.map +1 -1
  34. package/dist/server/services/agents/copilot-provider.js +32 -0
  35. package/dist/server/services/agents/copilot-provider.js.map +1 -1
  36. package/dist/server/websocket/index.js +42 -0
  37. package/dist/server/websocket/index.js.map +1 -1
  38. package/dist/shared/constants.js +9 -0
  39. package/dist/shared/constants.js.map +1 -1
  40. package/dist/shared/settings.js +51 -0
  41. package/dist/shared/settings.js.map +1 -0
  42. package/package.json +14 -10
  43. package/public/marktoflow-logo.png +0 -0
  44. package/server.log +0 -0
  45. package/tests/integration/fixtures/test-workflow.md +6 -0
  46. package/.turbo/turbo-build.log +0 -42
  47. package/dist/client/assets/index-CM44OayM.js +0 -704
  48. package/dist/client/assets/index-CM44OayM.js.map +0 -1
  49. package/dist/client/assets/index-Dru63gi6.css +0 -1
  50. package/marktoflow-gui-2.0.0-alpha.5.tgz +0 -0
  51. package/playwright.config.ts +0 -27
  52. package/postcss.config.js +0 -6
  53. package/src/client/App.tsx +0 -520
  54. package/src/client/components/Canvas/Canvas.tsx +0 -425
  55. package/src/client/components/Canvas/ExecutionOverlay.tsx +0 -935
  56. package/src/client/components/Canvas/ForEachNode.tsx +0 -152
  57. package/src/client/components/Canvas/IfElseNode.tsx +0 -141
  58. package/src/client/components/Canvas/NodeContextMenu.tsx +0 -192
  59. package/src/client/components/Canvas/OutputNode.tsx +0 -111
  60. package/src/client/components/Canvas/ParallelNode.tsx +0 -157
  61. package/src/client/components/Canvas/StepNode.tsx +0 -106
  62. package/src/client/components/Canvas/SubWorkflowNode.tsx +0 -141
  63. package/src/client/components/Canvas/SwitchNode.tsx +0 -185
  64. package/src/client/components/Canvas/Toolbar.tsx +0 -227
  65. package/src/client/components/Canvas/TransformNode.tsx +0 -194
  66. package/src/client/components/Canvas/TriggerNode.tsx +0 -128
  67. package/src/client/components/Canvas/TryCatchNode.tsx +0 -164
  68. package/src/client/components/Canvas/WhileNode.tsx +0 -161
  69. package/src/client/components/Canvas/index.ts +0 -24
  70. package/src/client/components/Debug/VariableInspector.tsx +0 -148
  71. package/src/client/components/Editor/InputsEditor.tsx +0 -458
  72. package/src/client/components/Editor/NewStepWizard.tsx +0 -344
  73. package/src/client/components/Editor/StepEditor.tsx +0 -532
  74. package/src/client/components/Editor/YamlEditor.tsx +0 -160
  75. package/src/client/components/Panels/PropertiesPanel.tsx +0 -589
  76. package/src/client/components/Prompt/ChangePreview.tsx +0 -281
  77. package/src/client/components/Prompt/PromptHistoryPanel.tsx +0 -209
  78. package/src/client/components/Prompt/PromptInput.tsx +0 -110
  79. package/src/client/components/Settings/ProviderSwitcher.tsx +0 -228
  80. package/src/client/components/Sidebar/ImportDialog.tsx +0 -257
  81. package/src/client/components/Sidebar/Sidebar.tsx +0 -362
  82. package/src/client/components/common/Breadcrumb.tsx +0 -40
  83. package/src/client/components/common/Button.tsx +0 -68
  84. package/src/client/components/common/ContextMenu.tsx +0 -202
  85. package/src/client/components/common/KeyboardShortcuts.tsx +0 -149
  86. package/src/client/components/common/Modal.tsx +0 -93
  87. package/src/client/components/common/Tabs.tsx +0 -57
  88. package/src/client/components/common/ThemeToggle.tsx +0 -63
  89. package/src/client/components/index.ts +0 -32
  90. package/src/client/hooks/index.ts +0 -4
  91. package/src/client/hooks/useAIPrompt.ts +0 -108
  92. package/src/client/hooks/useCanvas.ts +0 -247
  93. package/src/client/hooks/useWebSocket.ts +0 -164
  94. package/src/client/hooks/useWorkflow.ts +0 -138
  95. package/src/client/main.tsx +0 -10
  96. package/src/client/stores/agentStore.ts +0 -109
  97. package/src/client/stores/canvasStore.ts +0 -348
  98. package/src/client/stores/editorStore.ts +0 -133
  99. package/src/client/stores/executionStore.ts +0 -502
  100. package/src/client/stores/index.ts +0 -4
  101. package/src/client/stores/layoutStore.ts +0 -103
  102. package/src/client/stores/navigationStore.ts +0 -49
  103. package/src/client/stores/promptStore.ts +0 -113
  104. package/src/client/stores/themeStore.ts +0 -75
  105. package/src/client/stores/workflowStore.ts +0 -185
  106. package/src/client/styles/globals.css +0 -452
  107. package/src/client/utils/cn.ts +0 -9
  108. package/src/client/utils/index.ts +0 -4
  109. package/src/client/utils/platform.ts +0 -46
  110. package/src/client/utils/serviceIcons.tsx +0 -97
  111. package/src/client/utils/stepValidation.ts +0 -155
  112. package/src/client/utils/workflowToGraph.ts +0 -523
  113. package/src/server/index.ts +0 -137
  114. package/src/server/routes/ai.ts +0 -91
  115. package/src/server/routes/execute.ts +0 -71
  116. package/src/server/routes/executions.ts +0 -136
  117. package/src/server/routes/tools.ts +0 -970
  118. package/src/server/routes/workflows.ts +0 -147
  119. package/src/server/services/AIService.ts +0 -105
  120. package/src/server/services/FileWatcher.ts +0 -69
  121. package/src/server/services/WorkflowService.ts +0 -601
  122. package/src/server/services/agents/claude-code-provider.ts +0 -320
  123. package/src/server/services/agents/claude-provider.ts +0 -248
  124. package/src/server/services/agents/codex-provider.ts +0 -398
  125. package/src/server/services/agents/copilot-provider.ts +0 -311
  126. package/src/server/services/agents/demo-provider.ts +0 -184
  127. package/src/server/services/agents/index.ts +0 -31
  128. package/src/server/services/agents/ollama-provider.ts +0 -267
  129. package/src/server/services/agents/prompts.ts +0 -509
  130. package/src/server/services/agents/registry.ts +0 -310
  131. package/src/server/services/agents/types.ts +0 -146
  132. package/src/server/websocket/index.ts +0 -117
  133. package/src/shared/constants.ts +0 -180
  134. package/src/shared/types.ts +0 -179
  135. package/tailwind.config.ts +0 -73
  136. package/tests/e2e/app.spec.ts +0 -90
  137. package/tests/e2e/canvas.spec.ts +0 -128
  138. package/tests/e2e/workflow.spec.ts +0 -185
  139. package/tests/integration/api.test.ts +0 -452
  140. package/tests/integration/testApp.ts +0 -31
  141. package/tests/setup.ts +0 -72
  142. package/tests/unit/ForEachNode.test.tsx +0 -308
  143. package/tests/unit/IfElseNode.test.tsx +0 -235
  144. package/tests/unit/ParallelNode.test.tsx +0 -344
  145. package/tests/unit/SwitchNode.test.tsx +0 -327
  146. package/tests/unit/TransformNode.test.tsx +0 -386
  147. package/tests/unit/TryCatchNode.test.tsx +0 -243
  148. package/tests/unit/WhileNode.test.tsx +0 -230
  149. package/tests/unit/agentStore.test.ts +0 -218
  150. package/tests/unit/canvasStore.test.ts +0 -502
  151. package/tests/unit/codexProvider.test.ts +0 -399
  152. package/tests/unit/components.test.tsx +0 -151
  153. package/tests/unit/executionStore.test.ts +0 -567
  154. package/tests/unit/layoutStore.test.ts +0 -194
  155. package/tests/unit/navigationStore.test.ts +0 -152
  156. package/tests/unit/platform.test.ts +0 -118
  157. package/tests/unit/serviceIcons.test.ts +0 -197
  158. package/tests/unit/stepValidation.test.ts +0 -226
  159. package/tests/unit/themeStore.test.ts +0 -141
  160. package/tests/unit/workflowToGraph.test.ts +0 -311
  161. package/tsconfig.json +0 -29
  162. package/tsconfig.server.json +0 -28
  163. package/vite.config.ts +0 -31
  164. package/vitest.config.ts +0 -26
@@ -1,227 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import {
3
- Plus,
4
- Play,
5
- Pause,
6
- Layout,
7
- ZoomIn,
8
- ZoomOut,
9
- Maximize,
10
- Save,
11
- Undo,
12
- Redo,
13
- Copy,
14
- Trash2,
15
- Bot,
16
- ChevronDown,
17
- } from 'lucide-react';
18
- import { useCanvas } from '../../hooks/useCanvas';
19
- import { useEditorStore } from '../../stores/editorStore';
20
- import { useReactFlow } from '@xyflow/react';
21
- import { getModKey } from '../../utils/platform';
22
- import { useAgentStore } from '../../stores/agentStore';
23
- import { ProviderSwitcher } from '../Settings/ProviderSwitcher';
24
-
25
- interface ToolbarProps {
26
- onAddStep: () => void;
27
- onExecute?: () => void;
28
- onSave?: () => void;
29
- isExecuting?: boolean;
30
- }
31
-
32
- export function Toolbar({
33
- onAddStep,
34
- onExecute,
35
- onSave,
36
- isExecuting = false,
37
- }: ToolbarProps) {
38
- const { autoLayout, fitView, selectedNodes, deleteSelected, duplicateSelected } =
39
- useCanvas();
40
- const { undo, redo, undoStack, redoStack } = useEditorStore();
41
- const { zoomIn, zoomOut } = useReactFlow();
42
- const modKey = getModKey();
43
- const { providers, activeProviderId, loadProviders } = useAgentStore();
44
- const [showProviderSwitcher, setShowProviderSwitcher] = useState(false);
45
-
46
- const canUndo = undoStack.length > 0;
47
- const canRedo = redoStack.length > 0;
48
- const hasSelection = selectedNodes.length > 0;
49
-
50
- // Load providers on mount
51
- useEffect(() => {
52
- loadProviders();
53
- }, [loadProviders]);
54
-
55
- const activeProvider = providers.find((p) => p.id === activeProviderId);
56
-
57
- return (
58
- <div className="absolute top-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-1 px-2 py-1.5 bg-panel-bg/95 backdrop-blur border border-node-border rounded-lg shadow-lg">
59
- {/* Add Step */}
60
- <ToolbarButton
61
- icon={<Plus className="w-4 h-4" />}
62
- label="Add Step"
63
- onClick={onAddStep}
64
- shortcut="N"
65
- />
66
-
67
- <ToolbarDivider />
68
-
69
- {/* Undo/Redo */}
70
- <ToolbarButton
71
- icon={<Undo className="w-4 h-4" />}
72
- label="Undo"
73
- onClick={() => undo()}
74
- disabled={!canUndo}
75
- shortcut={`${modKey}Z`}
76
- />
77
- <ToolbarButton
78
- icon={<Redo className="w-4 h-4" />}
79
- label="Redo"
80
- onClick={() => redo()}
81
- disabled={!canRedo}
82
- shortcut={`${modKey}⇧Z`}
83
- />
84
-
85
- <ToolbarDivider />
86
-
87
- {/* Selection actions */}
88
- <ToolbarButton
89
- icon={<Copy className="w-4 h-4" />}
90
- label="Duplicate"
91
- onClick={duplicateSelected}
92
- disabled={!hasSelection}
93
- shortcut={`${modKey}D`}
94
- />
95
- <ToolbarButton
96
- icon={<Trash2 className="w-4 h-4" />}
97
- label="Delete"
98
- onClick={deleteSelected}
99
- disabled={!hasSelection}
100
- shortcut="⌫"
101
- />
102
-
103
- <ToolbarDivider />
104
-
105
- {/* Layout & Zoom */}
106
- <ToolbarButton
107
- icon={<Layout className="w-4 h-4" />}
108
- label="Auto Layout"
109
- onClick={autoLayout}
110
- shortcut={`${modKey}L`}
111
- />
112
- <ToolbarButton
113
- icon={<ZoomIn className="w-4 h-4" />}
114
- label="Zoom In"
115
- onClick={() => zoomIn()}
116
- shortcut={`${modKey}+`}
117
- />
118
- <ToolbarButton
119
- icon={<ZoomOut className="w-4 h-4" />}
120
- label="Zoom Out"
121
- onClick={() => zoomOut()}
122
- shortcut={`${modKey}-`}
123
- />
124
- <ToolbarButton
125
- icon={<Maximize className="w-4 h-4" />}
126
- label="Fit View"
127
- onClick={fitView}
128
- shortcut={`${modKey}0`}
129
- />
130
-
131
- <ToolbarDivider />
132
-
133
- {/* AI Provider */}
134
- <button
135
- onClick={() => setShowProviderSwitcher(true)}
136
- className="flex items-center gap-1.5 px-2 py-1.5 rounded text-sm text-gray-300 hover:text-white hover:bg-white/10 transition-colors"
137
- title="Select AI Provider"
138
- >
139
- <Bot className="w-4 h-4" />
140
- <span className="hidden sm:inline text-xs">
141
- {activeProvider?.name || 'No Provider'}
142
- </span>
143
- <ChevronDown className="w-3 h-3" />
144
- </button>
145
-
146
- {/* Execute */}
147
- {onExecute && (
148
- <>
149
- <ToolbarDivider />
150
- <ToolbarButton
151
- icon={
152
- isExecuting ? (
153
- <Pause className="w-4 h-4" />
154
- ) : (
155
- <Play className="w-4 h-4" />
156
- )
157
- }
158
- label={isExecuting ? 'Stop' : 'Execute'}
159
- onClick={onExecute}
160
- variant={isExecuting ? 'destructive' : 'primary'}
161
- shortcut={`${modKey}⏎`}
162
- />
163
- </>
164
- )}
165
-
166
- {/* Save */}
167
- {onSave && (
168
- <ToolbarButton
169
- icon={<Save className="w-4 h-4" />}
170
- label="Save"
171
- onClick={onSave}
172
- shortcut={`${modKey}S`}
173
- />
174
- )}
175
-
176
- {/* Provider Switcher Modal */}
177
- <ProviderSwitcher
178
- open={showProviderSwitcher}
179
- onOpenChange={setShowProviderSwitcher}
180
- />
181
- </div>
182
- );
183
- }
184
-
185
- interface ToolbarButtonProps {
186
- icon: React.ReactNode;
187
- label: string;
188
- onClick: () => void;
189
- disabled?: boolean;
190
- shortcut?: string;
191
- variant?: 'default' | 'primary' | 'destructive';
192
- }
193
-
194
- function ToolbarButton({
195
- icon,
196
- label,
197
- onClick,
198
- disabled,
199
- shortcut,
200
- variant = 'default',
201
- }: ToolbarButtonProps) {
202
- const variantClasses = {
203
- default: 'text-gray-300 hover:text-white hover:bg-white/10',
204
- primary: 'text-primary hover:text-primary-light hover:bg-primary/10',
205
- destructive: 'text-error hover:text-error hover:bg-error/10',
206
- };
207
-
208
- return (
209
- <button
210
- onClick={onClick}
211
- disabled={disabled}
212
- className={`relative group p-2 rounded transition-colors disabled:opacity-40 disabled:cursor-not-allowed ${variantClasses[variant]}`}
213
- title={`${label}${shortcut ? ` (${shortcut})` : ''}`}
214
- >
215
- {icon}
216
- {/* Tooltip */}
217
- <div className="absolute top-full left-1/2 -translate-x-1/2 mt-2 px-2 py-1 bg-black/90 rounded text-xs text-white whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
218
- {label}
219
- {shortcut && <span className="ml-2 text-gray-400">{shortcut}</span>}
220
- </div>
221
- </button>
222
- );
223
- }
224
-
225
- function ToolbarDivider() {
226
- return <div className="w-px h-6 bg-node-border mx-1" />;
227
- }
@@ -1,194 +0,0 @@
1
- import { memo } from 'react';
2
- import { Handle, Position, type Node, type NodeProps } from '@xyflow/react';
3
- import {
4
- ArrowRight,
5
- Filter,
6
- Minimize2,
7
- CheckCircle,
8
- XCircle,
9
- Clock,
10
- } from 'lucide-react';
11
-
12
- export interface TransformNodeData extends Record<string, unknown> {
13
- id: string;
14
- name?: string;
15
- transformType: 'map' | 'filter' | 'reduce';
16
- items: string;
17
- itemVariable?: string;
18
- expression?: string;
19
- condition?: string;
20
- accumulatorVariable?: string;
21
- initialValue?: unknown;
22
- status?: 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
23
- inputCount?: number;
24
- outputCount?: number;
25
- }
26
-
27
- export type TransformNodeType = Node<TransformNodeData, 'map' | 'filter' | 'reduce'>;
28
-
29
- function TransformNodeComponent({ data, selected }: NodeProps<TransformNodeType>) {
30
- const transformConfig: Record<
31
- NonNullable<TransformNodeData['transformType']>,
32
- { icon: typeof ArrowRight; label: string; color: string }
33
- > = {
34
- map: { icon: ArrowRight, label: 'Map', color: '#14b8a6' },
35
- filter: { icon: Filter, label: 'Filter', color: '#10b981' },
36
- reduce: { icon: Minimize2, label: 'Reduce', color: '#06b6d4' },
37
- };
38
-
39
- const statusConfig: Record<
40
- NonNullable<TransformNodeData['status']>,
41
- { icon: typeof Clock; color: string; bgColor: string; animate?: boolean }
42
- > = {
43
- pending: { icon: Clock, color: 'text-gray-400', bgColor: 'bg-gray-400/10' },
44
- running: {
45
- icon: transformConfig[data.transformType].icon,
46
- color: 'text-teal-400',
47
- bgColor: 'bg-teal-400/10',
48
- animate: true,
49
- },
50
- completed: {
51
- icon: CheckCircle,
52
- color: 'text-success',
53
- bgColor: 'bg-success/10',
54
- },
55
- failed: { icon: XCircle, color: 'text-error', bgColor: 'bg-error/10' },
56
- skipped: {
57
- icon: XCircle,
58
- color: 'text-gray-500',
59
- bgColor: 'bg-gray-500/10',
60
- },
61
- };
62
-
63
- const status = data.status || 'pending';
64
- const statusCfg = statusConfig[status];
65
- const StatusIcon = statusCfg.icon;
66
-
67
- const transformCfg = transformConfig[data.transformType];
68
- const TransformIcon = transformCfg.icon;
69
-
70
- const displayExpression =
71
- data.transformType === 'filter'
72
- ? data.condition
73
- : data.transformType === 'reduce'
74
- ? `${data.accumulatorVariable || 'acc'}: ${data.expression || 'Not set'}`
75
- : data.expression;
76
-
77
- return (
78
- <div
79
- className={`control-flow-node transform-node p-0 ${selected ? 'selected' : ''} ${status === 'running' ? 'running' : ''}`}
80
- style={{
81
- background: 'linear-gradient(135deg, #14b8a6 0%, #06b6d4 100%)',
82
- }}
83
- >
84
- {/* Input handle */}
85
- <Handle
86
- type="target"
87
- position={Position.Top}
88
- className="!w-3 !h-3 !bg-primary !border-2 !border-node-bg"
89
- />
90
-
91
- {/* Node header */}
92
- <div className="flex items-center gap-3 p-3 border-b border-white/20">
93
- <div className="w-8 h-8 rounded-lg bg-white/20 flex items-center justify-center">
94
- <TransformIcon className="w-5 h-5 text-white" />
95
- </div>
96
- <div className="flex-1 min-w-0">
97
- <div className="text-sm font-medium text-white">
98
- {data.name || transformCfg.label}
99
- </div>
100
- <div className="text-xs text-white/70">Transform</div>
101
- </div>
102
- <div
103
- className={`w-6 h-6 rounded-full ${statusCfg.bgColor} flex items-center justify-center`}
104
- >
105
- <StatusIcon
106
- className={`w-4 h-4 ${statusCfg.color} ${statusCfg.animate ? 'animate-pulse' : ''}`}
107
- />
108
- </div>
109
- </div>
110
-
111
- {/* Node body */}
112
- <div className="p-3 bg-white/10">
113
- {/* Items source */}
114
- <div className="text-xs text-white/90 mb-2">
115
- <span className="text-white/60">Items:</span>{' '}
116
- <span className="font-mono">{data.items || 'Not set'}</span>
117
- </div>
118
-
119
- {/* Variable */}
120
- <div className="text-xs text-white/90 mb-3">
121
- <span className="text-white/60">Variable:</span>{' '}
122
- <span className="font-mono">{data.itemVariable || 'item'}</span>
123
- </div>
124
-
125
- {/* Expression/Condition */}
126
- <div className="mb-3 p-2 bg-white/5 rounded">
127
- <div className="text-xs text-white/60 mb-1">
128
- {data.transformType === 'filter'
129
- ? 'Condition'
130
- : data.transformType === 'reduce'
131
- ? 'Reducer'
132
- : 'Expression'}
133
- </div>
134
- <div className="text-xs text-white font-mono break-all">
135
- {displayExpression || 'Not set'}
136
- </div>
137
- </div>
138
-
139
- {/* Initial value for reduce */}
140
- {data.transformType === 'reduce' && data.initialValue !== undefined && (
141
- <div className="text-xs text-white/90 mb-3">
142
- <span className="text-white/60">Initial:</span>{' '}
143
- <span className="font-mono">{JSON.stringify(data.initialValue)}</span>
144
- </div>
145
- )}
146
-
147
- {/* Input/Output count */}
148
- {(data.inputCount !== undefined || data.outputCount !== undefined) && (
149
- <div className="mt-3 p-2 bg-white/5 rounded flex items-center justify-between">
150
- <div className="text-xs">
151
- <span className="text-white/60">In:</span>{' '}
152
- <span className="text-white font-medium">{data.inputCount ?? '?'}</span>
153
- </div>
154
- <div className="text-white/40">→</div>
155
- <div className="text-xs">
156
- <span className="text-white/60">Out:</span>{' '}
157
- <span className="text-white font-medium">{data.outputCount ?? '?'}</span>
158
- </div>
159
- </div>
160
- )}
161
-
162
- {/* Transform type indicator */}
163
- <div className="mt-3 text-xs text-white/50 flex items-center gap-2">
164
- <span>ℹ️</span>
165
- <span>
166
- {data.transformType === 'map'
167
- ? 'Transforms each item'
168
- : data.transformType === 'filter'
169
- ? 'Selects matching items'
170
- : 'Aggregates to single value'}
171
- </span>
172
- </div>
173
- </div>
174
-
175
- {/* Output handle */}
176
- <Handle
177
- type="source"
178
- position={Position.Bottom}
179
- className="!w-3 !h-3 !bg-primary !border-2 !border-node-bg"
180
- />
181
-
182
- {/* Loop-back handle for iteration visualization */}
183
- <Handle
184
- id="loop-back"
185
- type="source"
186
- position={Position.Left}
187
- className="!w-3 !h-3 !bg-teal-500 !border-2 !border-node-bg"
188
- style={{ top: '50%', left: '-6px' }}
189
- />
190
- </div>
191
- );
192
- }
193
-
194
- export const TransformNode = memo(TransformNodeComponent);
@@ -1,128 +0,0 @@
1
- import { memo } from 'react';
2
- import { Handle, Position, type Node, type NodeProps } from '@xyflow/react';
3
- import { Webhook, FolderOpen, Play, Zap, Calendar } from 'lucide-react';
4
-
5
- export interface TriggerNodeData extends Record<string, unknown> {
6
- id: string;
7
- name?: string;
8
- type: 'manual' | 'schedule' | 'webhook' | 'file' | 'event';
9
- // Schedule trigger
10
- cron?: string;
11
- // Webhook trigger
12
- path?: string;
13
- method?: string;
14
- // File watcher trigger
15
- pattern?: string;
16
- // Event trigger
17
- events?: string[];
18
- // Status
19
- active?: boolean;
20
- lastTriggered?: string;
21
- }
22
-
23
- export type TriggerNodeType = Node<TriggerNodeData, 'trigger'>;
24
-
25
- const triggerConfig = {
26
- manual: {
27
- icon: Play,
28
- color: 'text-primary',
29
- bgColor: 'bg-primary/10',
30
- borderColor: 'border-primary',
31
- label: 'Manual Trigger',
32
- },
33
- schedule: {
34
- icon: Calendar,
35
- color: 'text-info',
36
- bgColor: 'bg-info/10',
37
- borderColor: 'border-info',
38
- label: 'Schedule',
39
- },
40
- webhook: {
41
- icon: Webhook,
42
- color: 'text-success',
43
- bgColor: 'bg-success/10',
44
- borderColor: 'border-success',
45
- label: 'Webhook',
46
- },
47
- file: {
48
- icon: FolderOpen,
49
- color: 'text-warning',
50
- bgColor: 'bg-warning/10',
51
- borderColor: 'border-warning',
52
- label: 'File Watcher',
53
- },
54
- event: {
55
- icon: Zap,
56
- color: 'text-purple-400',
57
- bgColor: 'bg-purple-400/10',
58
- borderColor: 'border-purple-400',
59
- label: 'Event',
60
- },
61
- };
62
-
63
- function TriggerNodeComponent({ data, selected }: NodeProps<TriggerNodeType>) {
64
- const config = triggerConfig[data.type] || triggerConfig.manual;
65
- const Icon = config.icon;
66
-
67
- const getSubtitle = () => {
68
- switch (data.type) {
69
- case 'schedule':
70
- return data.cron || 'No schedule set';
71
- case 'webhook':
72
- return `${data.method || 'POST'} ${data.path || '/webhook'}`;
73
- case 'file':
74
- return data.pattern || '**/*';
75
- case 'event':
76
- return data.events?.join(', ') || 'No events';
77
- default:
78
- return 'Click to run';
79
- }
80
- };
81
-
82
- return (
83
- <div
84
- className={`min-w-[180px] rounded-lg border-2 ${config.borderColor} ${config.bgColor} ${
85
- selected ? 'ring-2 ring-primary ring-offset-2 ring-offset-canvas-bg' : ''
86
- } transition-all duration-200`}
87
- >
88
- {/* Header */}
89
- <div className="px-3 py-2 flex items-center gap-2">
90
- <div className={`w-8 h-8 rounded-full ${config.bgColor} flex items-center justify-center`}>
91
- <Icon className={`w-4 h-4 ${config.color}`} />
92
- </div>
93
- <div className="flex-1 min-w-0">
94
- <div className="text-xs font-medium text-gray-400 uppercase tracking-wider">
95
- {config.label}
96
- </div>
97
- <div className="text-sm font-medium text-white truncate">
98
- {data.name || 'Trigger'}
99
- </div>
100
- </div>
101
- {data.active !== false && (
102
- <div className="w-2 h-2 rounded-full bg-success animate-pulse" title="Active" />
103
- )}
104
- </div>
105
-
106
- {/* Details */}
107
- <div className="px-3 py-2 border-t border-white/10">
108
- <div className="text-xs text-gray-400 font-mono truncate" title={getSubtitle()}>
109
- {getSubtitle()}
110
- </div>
111
- {data.lastTriggered && (
112
- <div className="text-xs text-gray-500 mt-1">
113
- Last: {new Date(data.lastTriggered).toLocaleString()}
114
- </div>
115
- )}
116
- </div>
117
-
118
- {/* Output handle */}
119
- <Handle
120
- type="source"
121
- position={Position.Bottom}
122
- className="!w-3 !h-3 !bg-primary !border-2 !border-canvas-bg"
123
- />
124
- </div>
125
- );
126
- }
127
-
128
- export const TriggerNode = memo(TriggerNodeComponent);