@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.
- package/README.md +48 -180
- package/client.log +0 -0
- package/dist/client/assets/index-DQeR1ew6.css +1 -0
- package/dist/client/assets/index-LbIVPHbD.js +833 -0
- package/dist/client/assets/index-LbIVPHbD.js.map +1 -0
- package/dist/client/index.html +2 -2
- package/dist/client/marktoflow-logo.png +0 -0
- package/dist/server/index.js +31 -5
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/admin.js +95 -0
- package/dist/server/routes/admin.js.map +1 -0
- package/dist/server/routes/ai.js +2 -2
- package/dist/server/routes/ai.js.map +1 -1
- package/dist/server/routes/collaboration.js +104 -0
- package/dist/server/routes/collaboration.js.map +1 -0
- package/dist/server/routes/execute.js +181 -14
- package/dist/server/routes/execute.js.map +1 -1
- package/dist/server/routes/form.js +160 -0
- package/dist/server/routes/form.js.map +1 -0
- package/dist/server/routes/settings.js +90 -0
- package/dist/server/routes/settings.js.map +1 -0
- package/dist/server/routes/templates.js +106 -0
- package/dist/server/routes/templates.js.map +1 -0
- package/dist/server/routes/versions.js +101 -0
- package/dist/server/routes/versions.js.map +1 -0
- package/dist/server/services/AIService.js +85 -2
- package/dist/server/services/AIService.js.map +1 -1
- package/dist/server/services/ExecutionManager.js +571 -0
- package/dist/server/services/ExecutionManager.js.map +1 -0
- package/dist/server/services/VersionService.js +65 -0
- package/dist/server/services/VersionService.js.map +1 -0
- package/dist/server/services/WorkflowService.js +8 -2
- package/dist/server/services/WorkflowService.js.map +1 -1
- package/dist/server/services/agents/copilot-provider.js +32 -0
- package/dist/server/services/agents/copilot-provider.js.map +1 -1
- package/dist/server/websocket/index.js +42 -0
- package/dist/server/websocket/index.js.map +1 -1
- package/dist/shared/constants.js +9 -0
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/settings.js +51 -0
- package/dist/shared/settings.js.map +1 -0
- package/package.json +14 -10
- package/public/marktoflow-logo.png +0 -0
- package/server.log +0 -0
- package/tests/integration/fixtures/test-workflow.md +6 -0
- package/.turbo/turbo-build.log +0 -42
- package/dist/client/assets/index-CM44OayM.js +0 -704
- package/dist/client/assets/index-CM44OayM.js.map +0 -1
- package/dist/client/assets/index-Dru63gi6.css +0 -1
- package/marktoflow-gui-2.0.0-alpha.5.tgz +0 -0
- package/playwright.config.ts +0 -27
- package/postcss.config.js +0 -6
- package/src/client/App.tsx +0 -520
- package/src/client/components/Canvas/Canvas.tsx +0 -425
- package/src/client/components/Canvas/ExecutionOverlay.tsx +0 -935
- package/src/client/components/Canvas/ForEachNode.tsx +0 -152
- package/src/client/components/Canvas/IfElseNode.tsx +0 -141
- package/src/client/components/Canvas/NodeContextMenu.tsx +0 -192
- package/src/client/components/Canvas/OutputNode.tsx +0 -111
- package/src/client/components/Canvas/ParallelNode.tsx +0 -157
- package/src/client/components/Canvas/StepNode.tsx +0 -106
- package/src/client/components/Canvas/SubWorkflowNode.tsx +0 -141
- package/src/client/components/Canvas/SwitchNode.tsx +0 -185
- package/src/client/components/Canvas/Toolbar.tsx +0 -227
- package/src/client/components/Canvas/TransformNode.tsx +0 -194
- package/src/client/components/Canvas/TriggerNode.tsx +0 -128
- package/src/client/components/Canvas/TryCatchNode.tsx +0 -164
- package/src/client/components/Canvas/WhileNode.tsx +0 -161
- package/src/client/components/Canvas/index.ts +0 -24
- package/src/client/components/Debug/VariableInspector.tsx +0 -148
- package/src/client/components/Editor/InputsEditor.tsx +0 -458
- package/src/client/components/Editor/NewStepWizard.tsx +0 -344
- package/src/client/components/Editor/StepEditor.tsx +0 -532
- package/src/client/components/Editor/YamlEditor.tsx +0 -160
- package/src/client/components/Panels/PropertiesPanel.tsx +0 -589
- package/src/client/components/Prompt/ChangePreview.tsx +0 -281
- package/src/client/components/Prompt/PromptHistoryPanel.tsx +0 -209
- package/src/client/components/Prompt/PromptInput.tsx +0 -110
- package/src/client/components/Settings/ProviderSwitcher.tsx +0 -228
- package/src/client/components/Sidebar/ImportDialog.tsx +0 -257
- package/src/client/components/Sidebar/Sidebar.tsx +0 -362
- package/src/client/components/common/Breadcrumb.tsx +0 -40
- package/src/client/components/common/Button.tsx +0 -68
- package/src/client/components/common/ContextMenu.tsx +0 -202
- package/src/client/components/common/KeyboardShortcuts.tsx +0 -149
- package/src/client/components/common/Modal.tsx +0 -93
- package/src/client/components/common/Tabs.tsx +0 -57
- package/src/client/components/common/ThemeToggle.tsx +0 -63
- package/src/client/components/index.ts +0 -32
- package/src/client/hooks/index.ts +0 -4
- package/src/client/hooks/useAIPrompt.ts +0 -108
- package/src/client/hooks/useCanvas.ts +0 -247
- package/src/client/hooks/useWebSocket.ts +0 -164
- package/src/client/hooks/useWorkflow.ts +0 -138
- package/src/client/main.tsx +0 -10
- package/src/client/stores/agentStore.ts +0 -109
- package/src/client/stores/canvasStore.ts +0 -348
- package/src/client/stores/editorStore.ts +0 -133
- package/src/client/stores/executionStore.ts +0 -502
- package/src/client/stores/index.ts +0 -4
- package/src/client/stores/layoutStore.ts +0 -103
- package/src/client/stores/navigationStore.ts +0 -49
- package/src/client/stores/promptStore.ts +0 -113
- package/src/client/stores/themeStore.ts +0 -75
- package/src/client/stores/workflowStore.ts +0 -185
- package/src/client/styles/globals.css +0 -452
- package/src/client/utils/cn.ts +0 -9
- package/src/client/utils/index.ts +0 -4
- package/src/client/utils/platform.ts +0 -46
- package/src/client/utils/serviceIcons.tsx +0 -97
- package/src/client/utils/stepValidation.ts +0 -155
- package/src/client/utils/workflowToGraph.ts +0 -523
- package/src/server/index.ts +0 -137
- package/src/server/routes/ai.ts +0 -91
- package/src/server/routes/execute.ts +0 -71
- package/src/server/routes/executions.ts +0 -136
- package/src/server/routes/tools.ts +0 -970
- package/src/server/routes/workflows.ts +0 -147
- package/src/server/services/AIService.ts +0 -105
- package/src/server/services/FileWatcher.ts +0 -69
- package/src/server/services/WorkflowService.ts +0 -601
- package/src/server/services/agents/claude-code-provider.ts +0 -320
- package/src/server/services/agents/claude-provider.ts +0 -248
- package/src/server/services/agents/codex-provider.ts +0 -398
- package/src/server/services/agents/copilot-provider.ts +0 -311
- package/src/server/services/agents/demo-provider.ts +0 -184
- package/src/server/services/agents/index.ts +0 -31
- package/src/server/services/agents/ollama-provider.ts +0 -267
- package/src/server/services/agents/prompts.ts +0 -509
- package/src/server/services/agents/registry.ts +0 -310
- package/src/server/services/agents/types.ts +0 -146
- package/src/server/websocket/index.ts +0 -117
- package/src/shared/constants.ts +0 -180
- package/src/shared/types.ts +0 -179
- package/tailwind.config.ts +0 -73
- package/tests/e2e/app.spec.ts +0 -90
- package/tests/e2e/canvas.spec.ts +0 -128
- package/tests/e2e/workflow.spec.ts +0 -185
- package/tests/integration/api.test.ts +0 -452
- package/tests/integration/testApp.ts +0 -31
- package/tests/setup.ts +0 -72
- package/tests/unit/ForEachNode.test.tsx +0 -308
- package/tests/unit/IfElseNode.test.tsx +0 -235
- package/tests/unit/ParallelNode.test.tsx +0 -344
- package/tests/unit/SwitchNode.test.tsx +0 -327
- package/tests/unit/TransformNode.test.tsx +0 -386
- package/tests/unit/TryCatchNode.test.tsx +0 -243
- package/tests/unit/WhileNode.test.tsx +0 -230
- package/tests/unit/agentStore.test.ts +0 -218
- package/tests/unit/canvasStore.test.ts +0 -502
- package/tests/unit/codexProvider.test.ts +0 -399
- package/tests/unit/components.test.tsx +0 -151
- package/tests/unit/executionStore.test.ts +0 -567
- package/tests/unit/layoutStore.test.ts +0 -194
- package/tests/unit/navigationStore.test.ts +0 -152
- package/tests/unit/platform.test.ts +0 -118
- package/tests/unit/serviceIcons.test.ts +0 -197
- package/tests/unit/stepValidation.test.ts +0 -226
- package/tests/unit/themeStore.test.ts +0 -141
- package/tests/unit/workflowToGraph.test.ts +0 -311
- package/tsconfig.json +0 -29
- package/tsconfig.server.json +0 -28
- package/vite.config.ts +0 -31
- package/vitest.config.ts +0 -26
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
import { useCallback, useState, useRef, type DragEvent } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
ReactFlow,
|
|
4
|
-
Background,
|
|
5
|
-
Controls,
|
|
6
|
-
MiniMap,
|
|
7
|
-
BackgroundVariant,
|
|
8
|
-
useReactFlow,
|
|
9
|
-
type NodeMouseHandler,
|
|
10
|
-
type Node,
|
|
11
|
-
} from '@xyflow/react';
|
|
12
|
-
import { Edit, Copy, Trash2, Code, Play } from 'lucide-react';
|
|
13
|
-
import { useCanvasStore } from '../../stores/canvasStore';
|
|
14
|
-
import { useWorkflowStore } from '../../stores/workflowStore';
|
|
15
|
-
import { getModKey } from '../../utils/platform';
|
|
16
|
-
import { StepNode } from './StepNode';
|
|
17
|
-
import { SubWorkflowNode } from './SubWorkflowNode';
|
|
18
|
-
import { TriggerNode } from './TriggerNode';
|
|
19
|
-
import { OutputNode } from './OutputNode';
|
|
20
|
-
import { IfElseNode } from './IfElseNode';
|
|
21
|
-
import { ForEachNode } from './ForEachNode';
|
|
22
|
-
import { WhileNode } from './WhileNode';
|
|
23
|
-
import { SwitchNode } from './SwitchNode';
|
|
24
|
-
import { ParallelNode } from './ParallelNode';
|
|
25
|
-
import { TryCatchNode } from './TryCatchNode';
|
|
26
|
-
import { TransformNode } from './TransformNode';
|
|
27
|
-
import { StepEditor } from '../Editor/StepEditor';
|
|
28
|
-
import { YamlViewer } from '../Editor/YamlEditor';
|
|
29
|
-
import { Modal } from '../common/Modal';
|
|
30
|
-
import {
|
|
31
|
-
ContextMenu,
|
|
32
|
-
ContextMenuContent,
|
|
33
|
-
ContextMenuItem,
|
|
34
|
-
ContextMenuSeparator,
|
|
35
|
-
ContextMenuShortcut,
|
|
36
|
-
ContextMenuTrigger,
|
|
37
|
-
} from '../common/ContextMenu';
|
|
38
|
-
import { useCanvas } from '../../hooks/useCanvas';
|
|
39
|
-
import { type ToolDefinition } from '../Sidebar/Sidebar';
|
|
40
|
-
import type { WorkflowStep } from '@shared/types';
|
|
41
|
-
|
|
42
|
-
// Custom node types
|
|
43
|
-
const nodeTypes = {
|
|
44
|
-
step: StepNode,
|
|
45
|
-
subworkflow: SubWorkflowNode,
|
|
46
|
-
trigger: TriggerNode,
|
|
47
|
-
output: OutputNode,
|
|
48
|
-
if: IfElseNode,
|
|
49
|
-
for_each: ForEachNode,
|
|
50
|
-
while: WhileNode,
|
|
51
|
-
switch: SwitchNode,
|
|
52
|
-
parallel: ParallelNode,
|
|
53
|
-
try: TryCatchNode,
|
|
54
|
-
map: TransformNode,
|
|
55
|
-
filter: TransformNode,
|
|
56
|
-
reduce: TransformNode,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export function Canvas() {
|
|
60
|
-
const { nodes, edges, onNodesChange, onEdgesChange, onConnect, setNodes } =
|
|
61
|
-
useCanvasStore();
|
|
62
|
-
const { autoLayout, deleteSelected, duplicateSelected } = useCanvas();
|
|
63
|
-
const currentWorkflow = useWorkflowStore((s) => s.currentWorkflow);
|
|
64
|
-
const { screenToFlowPosition } = useReactFlow();
|
|
65
|
-
const modKey = getModKey();
|
|
66
|
-
|
|
67
|
-
// Editor state
|
|
68
|
-
const [editingStep, setEditingStep] = useState<WorkflowStep | null>(null);
|
|
69
|
-
const [isEditorOpen, setIsEditorOpen] = useState(false);
|
|
70
|
-
const [yamlViewStep, setYamlViewStep] = useState<WorkflowStep | null>(null);
|
|
71
|
-
const [isYamlViewOpen, setIsYamlViewOpen] = useState(false);
|
|
72
|
-
|
|
73
|
-
// Context menu state
|
|
74
|
-
const [contextMenuNode, setContextMenuNode] = useState<Node | null>(null);
|
|
75
|
-
const contextMenuRef = useRef<HTMLDivElement>(null);
|
|
76
|
-
|
|
77
|
-
// Handle node double-click to open editor or drill down
|
|
78
|
-
const onNodeDoubleClick: NodeMouseHandler = useCallback(
|
|
79
|
-
(event, node) => {
|
|
80
|
-
event.preventDefault();
|
|
81
|
-
|
|
82
|
-
// Sub-workflow nodes handle their own double-click via the drill-down button
|
|
83
|
-
// Don't open editor for special node types that have their own interactions
|
|
84
|
-
if (node.type === 'trigger' || node.type === 'output') {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const step = currentWorkflow?.steps.find((s) => s.id === node.data.id);
|
|
89
|
-
if (step) {
|
|
90
|
-
setEditingStep(step);
|
|
91
|
-
setIsEditorOpen(true);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
[currentWorkflow]
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// Get the currently selected step node (including control flow nodes)
|
|
98
|
-
const getSelectedStep = useCallback((): WorkflowStep | null => {
|
|
99
|
-
if (!currentWorkflow) return null;
|
|
100
|
-
const controlFlowTypes = ['step', 'if', 'for_each', 'while', 'switch', 'parallel', 'try', 'map', 'filter', 'reduce'];
|
|
101
|
-
const selectedNode = nodes.find((n) => n.selected && controlFlowTypes.includes(n.type || ''));
|
|
102
|
-
if (!selectedNode) return null;
|
|
103
|
-
return currentWorkflow.steps.find((s) => s.id === selectedNode.data.id) || null;
|
|
104
|
-
}, [currentWorkflow, nodes]);
|
|
105
|
-
|
|
106
|
-
// Get undo/redo and copy/paste functions from canvas store
|
|
107
|
-
const { undo, redo, canUndo, canRedo, copySelected, paste, canPaste } = useCanvasStore();
|
|
108
|
-
|
|
109
|
-
// Handle keyboard shortcuts
|
|
110
|
-
const onKeyDown = useCallback(
|
|
111
|
-
(event: React.KeyboardEvent) => {
|
|
112
|
-
const isMeta = event.metaKey || event.ctrlKey;
|
|
113
|
-
|
|
114
|
-
// Delete selected nodes
|
|
115
|
-
if (event.key === 'Backspace' || event.key === 'Delete') {
|
|
116
|
-
deleteSelected();
|
|
117
|
-
}
|
|
118
|
-
// Duplicate selected nodes
|
|
119
|
-
if (isMeta && event.key === 'd') {
|
|
120
|
-
event.preventDefault();
|
|
121
|
-
duplicateSelected();
|
|
122
|
-
}
|
|
123
|
-
// Auto-layout
|
|
124
|
-
if (isMeta && event.key === 'l') {
|
|
125
|
-
event.preventDefault();
|
|
126
|
-
autoLayout();
|
|
127
|
-
}
|
|
128
|
-
// Undo (Cmd/Ctrl + Z)
|
|
129
|
-
if (isMeta && event.key === 'z' && !event.shiftKey) {
|
|
130
|
-
event.preventDefault();
|
|
131
|
-
if (canUndo()) {
|
|
132
|
-
undo();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
// Redo (Cmd/Ctrl + Shift + Z or Cmd/Ctrl + Y)
|
|
136
|
-
if ((isMeta && event.shiftKey && event.key === 'z') || (isMeta && event.key === 'y')) {
|
|
137
|
-
event.preventDefault();
|
|
138
|
-
if (canRedo()) {
|
|
139
|
-
redo();
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
// Copy (Cmd/Ctrl + C)
|
|
143
|
-
if (isMeta && event.key === 'c') {
|
|
144
|
-
event.preventDefault();
|
|
145
|
-
copySelected();
|
|
146
|
-
}
|
|
147
|
-
// Paste (Cmd/Ctrl + V)
|
|
148
|
-
if (isMeta && event.key === 'v') {
|
|
149
|
-
event.preventDefault();
|
|
150
|
-
if (canPaste()) {
|
|
151
|
-
paste();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// Edit selected step (E key without modifiers)
|
|
155
|
-
if (event.key === 'e' && !isMeta && !event.shiftKey && !event.altKey) {
|
|
156
|
-
event.preventDefault();
|
|
157
|
-
const step = getSelectedStep();
|
|
158
|
-
if (step) {
|
|
159
|
-
setEditingStep(step);
|
|
160
|
-
setIsEditorOpen(true);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// View YAML (Y key without modifiers)
|
|
164
|
-
if (event.key === 'y' && !isMeta && !event.shiftKey && !event.altKey) {
|
|
165
|
-
event.preventDefault();
|
|
166
|
-
const step = getSelectedStep();
|
|
167
|
-
if (step) {
|
|
168
|
-
setYamlViewStep(step);
|
|
169
|
-
setIsYamlViewOpen(true);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
[deleteSelected, duplicateSelected, autoLayout, getSelectedStep, undo, redo, canUndo, canRedo, copySelected, paste, canPaste]
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
// Handle step save
|
|
177
|
-
const handleStepSave = useCallback(
|
|
178
|
-
(updatedStep: WorkflowStep) => {
|
|
179
|
-
// TODO: Update workflow through store
|
|
180
|
-
console.log('Saving step:', updatedStep);
|
|
181
|
-
setIsEditorOpen(false);
|
|
182
|
-
setEditingStep(null);
|
|
183
|
-
},
|
|
184
|
-
[]
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
// Context menu handlers
|
|
188
|
-
const handleContextEdit = useCallback(() => {
|
|
189
|
-
if (!contextMenuNode || !currentWorkflow) return;
|
|
190
|
-
const step = currentWorkflow.steps.find((s) => s.id === contextMenuNode.data.id);
|
|
191
|
-
if (step) {
|
|
192
|
-
setEditingStep(step);
|
|
193
|
-
setIsEditorOpen(true);
|
|
194
|
-
}
|
|
195
|
-
setContextMenuNode(null);
|
|
196
|
-
}, [contextMenuNode, currentWorkflow]);
|
|
197
|
-
|
|
198
|
-
const handleContextViewYaml = useCallback(() => {
|
|
199
|
-
if (!contextMenuNode || !currentWorkflow) return;
|
|
200
|
-
const step = currentWorkflow.steps.find((s) => s.id === contextMenuNode.data.id);
|
|
201
|
-
if (step) {
|
|
202
|
-
setYamlViewStep(step);
|
|
203
|
-
setIsYamlViewOpen(true);
|
|
204
|
-
}
|
|
205
|
-
setContextMenuNode(null);
|
|
206
|
-
}, [contextMenuNode, currentWorkflow]);
|
|
207
|
-
|
|
208
|
-
const handleContextDuplicate = useCallback(() => {
|
|
209
|
-
if (contextMenuNode) {
|
|
210
|
-
// Select the node first, then duplicate
|
|
211
|
-
duplicateSelected();
|
|
212
|
-
}
|
|
213
|
-
setContextMenuNode(null);
|
|
214
|
-
}, [contextMenuNode, duplicateSelected]);
|
|
215
|
-
|
|
216
|
-
const handleContextDelete = useCallback(() => {
|
|
217
|
-
if (contextMenuNode) {
|
|
218
|
-
deleteSelected();
|
|
219
|
-
}
|
|
220
|
-
setContextMenuNode(null);
|
|
221
|
-
}, [contextMenuNode, deleteSelected]);
|
|
222
|
-
|
|
223
|
-
const handleContextExecute = useCallback(() => {
|
|
224
|
-
if (contextMenuNode) {
|
|
225
|
-
console.log('Execute step:', contextMenuNode.data.id);
|
|
226
|
-
// TODO: Implement single step execution
|
|
227
|
-
}
|
|
228
|
-
setContextMenuNode(null);
|
|
229
|
-
}, [contextMenuNode]);
|
|
230
|
-
|
|
231
|
-
// Handle right-click on node
|
|
232
|
-
const onNodeContextMenu = useCallback(
|
|
233
|
-
(event: React.MouseEvent, node: Node) => {
|
|
234
|
-
event.preventDefault();
|
|
235
|
-
// Show context menu for all control flow nodes
|
|
236
|
-
const controlFlowTypes = ['step', 'if', 'for_each', 'while', 'switch', 'parallel', 'try', 'map', 'filter', 'reduce', 'subworkflow'];
|
|
237
|
-
if (controlFlowTypes.includes(node.type || '')) {
|
|
238
|
-
setContextMenuNode(node);
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
[]
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Handle drag over for drop target
|
|
245
|
-
const onDragOver = useCallback((event: DragEvent) => {
|
|
246
|
-
event.preventDefault();
|
|
247
|
-
event.dataTransfer.dropEffect = 'copy';
|
|
248
|
-
}, []);
|
|
249
|
-
|
|
250
|
-
// Handle drop from tools palette
|
|
251
|
-
const onDrop = useCallback(
|
|
252
|
-
(event: DragEvent) => {
|
|
253
|
-
event.preventDefault();
|
|
254
|
-
|
|
255
|
-
const toolData = event.dataTransfer.getData('application/marktoflow-tool');
|
|
256
|
-
if (!toolData) return;
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
const tool: ToolDefinition = JSON.parse(toolData);
|
|
260
|
-
|
|
261
|
-
// Get the position where the node was dropped
|
|
262
|
-
const position = screenToFlowPosition({
|
|
263
|
-
x: event.clientX,
|
|
264
|
-
y: event.clientY,
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// Create a new node
|
|
268
|
-
const newId = tool.id + '-' + Date.now().toString(36);
|
|
269
|
-
const newNode: Node = {
|
|
270
|
-
id: newId,
|
|
271
|
-
type: 'step',
|
|
272
|
-
position,
|
|
273
|
-
data: {
|
|
274
|
-
id: newId,
|
|
275
|
-
name: tool.name + ' Action',
|
|
276
|
-
action: tool.id + '.' + (tool.actions?.[0] || 'action'),
|
|
277
|
-
status: 'pending',
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
// Add the node to the canvas
|
|
282
|
-
setNodes([...nodes, newNode]);
|
|
283
|
-
} catch (e) {
|
|
284
|
-
console.error('Failed to parse dropped tool data:', e);
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
[nodes, setNodes, screenToFlowPosition]
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
// Get available variables for the editing step
|
|
291
|
-
const getAvailableVariables = useCallback((): string[] => {
|
|
292
|
-
if (!currentWorkflow || !editingStep) return [];
|
|
293
|
-
|
|
294
|
-
const variables: string[] = [];
|
|
295
|
-
|
|
296
|
-
// Add input variables
|
|
297
|
-
if (currentWorkflow.inputs) {
|
|
298
|
-
for (const key of Object.keys(currentWorkflow.inputs)) {
|
|
299
|
-
variables.push(`inputs.${key}`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Add output variables from steps before the editing step
|
|
304
|
-
const stepIndex = currentWorkflow.steps.findIndex(
|
|
305
|
-
(s) => s.id === editingStep.id
|
|
306
|
-
);
|
|
307
|
-
for (let i = 0; i < stepIndex; i++) {
|
|
308
|
-
const step = currentWorkflow.steps[i];
|
|
309
|
-
if (step.outputVariable) {
|
|
310
|
-
variables.push(step.outputVariable);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return variables;
|
|
315
|
-
}, [currentWorkflow, editingStep]);
|
|
316
|
-
|
|
317
|
-
return (
|
|
318
|
-
<ContextMenu>
|
|
319
|
-
<ContextMenuTrigger asChild>
|
|
320
|
-
<div
|
|
321
|
-
ref={contextMenuRef}
|
|
322
|
-
className="w-full h-full"
|
|
323
|
-
onKeyDown={onKeyDown}
|
|
324
|
-
onDragOver={onDragOver}
|
|
325
|
-
onDrop={onDrop}
|
|
326
|
-
tabIndex={0}
|
|
327
|
-
>
|
|
328
|
-
<ReactFlow
|
|
329
|
-
nodes={nodes}
|
|
330
|
-
edges={edges}
|
|
331
|
-
onNodesChange={onNodesChange}
|
|
332
|
-
onEdgesChange={onEdgesChange}
|
|
333
|
-
onConnect={onConnect}
|
|
334
|
-
onNodeDoubleClick={onNodeDoubleClick}
|
|
335
|
-
onNodeContextMenu={onNodeContextMenu}
|
|
336
|
-
nodeTypes={nodeTypes}
|
|
337
|
-
fitView
|
|
338
|
-
snapToGrid
|
|
339
|
-
snapGrid={[16, 16]}
|
|
340
|
-
defaultEdgeOptions={{
|
|
341
|
-
type: 'smoothstep',
|
|
342
|
-
animated: true,
|
|
343
|
-
style: { stroke: '#ff6d5a', strokeWidth: 2 },
|
|
344
|
-
}}
|
|
345
|
-
proOptions={{ hideAttribution: true }}
|
|
346
|
-
>
|
|
347
|
-
<Background
|
|
348
|
-
variant={BackgroundVariant.Dots}
|
|
349
|
-
gap={24}
|
|
350
|
-
size={1}
|
|
351
|
-
color="#3d3d5c"
|
|
352
|
-
/>
|
|
353
|
-
<Controls />
|
|
354
|
-
<MiniMap
|
|
355
|
-
nodeColor={(node) => {
|
|
356
|
-
switch (node.data?.status) {
|
|
357
|
-
case 'running':
|
|
358
|
-
return '#f0ad4e';
|
|
359
|
-
case 'completed':
|
|
360
|
-
return '#5cb85c';
|
|
361
|
-
case 'failed':
|
|
362
|
-
return '#d9534f';
|
|
363
|
-
default:
|
|
364
|
-
return '#2d2d4a';
|
|
365
|
-
}
|
|
366
|
-
}}
|
|
367
|
-
maskColor="rgba(26, 26, 46, 0.8)"
|
|
368
|
-
/>
|
|
369
|
-
</ReactFlow>
|
|
370
|
-
</div>
|
|
371
|
-
</ContextMenuTrigger>
|
|
372
|
-
|
|
373
|
-
{/* Node Context Menu */}
|
|
374
|
-
<ContextMenuContent>
|
|
375
|
-
<ContextMenuItem onClick={handleContextEdit}>
|
|
376
|
-
<Edit className="w-4 h-4 mr-2" />
|
|
377
|
-
Edit Step
|
|
378
|
-
<ContextMenuShortcut>E</ContextMenuShortcut>
|
|
379
|
-
</ContextMenuItem>
|
|
380
|
-
<ContextMenuItem onClick={handleContextViewYaml}>
|
|
381
|
-
<Code className="w-4 h-4 mr-2" />
|
|
382
|
-
View YAML
|
|
383
|
-
<ContextMenuShortcut>Y</ContextMenuShortcut>
|
|
384
|
-
</ContextMenuItem>
|
|
385
|
-
<ContextMenuSeparator />
|
|
386
|
-
<ContextMenuItem onClick={handleContextExecute}>
|
|
387
|
-
<Play className="w-4 h-4 mr-2" />
|
|
388
|
-
Execute Step
|
|
389
|
-
</ContextMenuItem>
|
|
390
|
-
<ContextMenuSeparator />
|
|
391
|
-
<ContextMenuItem onClick={handleContextDuplicate}>
|
|
392
|
-
<Copy className="w-4 h-4 mr-2" />
|
|
393
|
-
Duplicate
|
|
394
|
-
<ContextMenuShortcut>{modKey}D</ContextMenuShortcut>
|
|
395
|
-
</ContextMenuItem>
|
|
396
|
-
<ContextMenuItem onClick={handleContextDelete} destructive>
|
|
397
|
-
<Trash2 className="w-4 h-4 mr-2" />
|
|
398
|
-
Delete
|
|
399
|
-
<ContextMenuShortcut>⌫</ContextMenuShortcut>
|
|
400
|
-
</ContextMenuItem>
|
|
401
|
-
</ContextMenuContent>
|
|
402
|
-
|
|
403
|
-
{/* Step Editor Modal */}
|
|
404
|
-
<StepEditor
|
|
405
|
-
open={isEditorOpen}
|
|
406
|
-
onOpenChange={setIsEditorOpen}
|
|
407
|
-
step={editingStep}
|
|
408
|
-
onSave={handleStepSave}
|
|
409
|
-
availableVariables={getAvailableVariables()}
|
|
410
|
-
/>
|
|
411
|
-
|
|
412
|
-
{/* YAML Viewer Modal */}
|
|
413
|
-
<Modal
|
|
414
|
-
open={isYamlViewOpen}
|
|
415
|
-
onOpenChange={setIsYamlViewOpen}
|
|
416
|
-
title={`YAML: ${yamlViewStep?.name || yamlViewStep?.id}`}
|
|
417
|
-
size="lg"
|
|
418
|
-
>
|
|
419
|
-
<div className="p-4">
|
|
420
|
-
<YamlViewer value={yamlViewStep} />
|
|
421
|
-
</div>
|
|
422
|
-
</Modal>
|
|
423
|
-
</ContextMenu>
|
|
424
|
-
);
|
|
425
|
-
}
|