@flowdrop/flowdrop 1.0.1 → 1.2.0
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 +50 -50
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +25 -25
- package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
- package/dist/adapters/agentspec/AgentSpecAdapter.js +133 -122
- package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
- package/dist/adapters/agentspec/agentAdapter.js +10 -10
- package/dist/adapters/agentspec/autoLayout.d.ts +1 -1
- package/dist/adapters/agentspec/autoLayout.js +2 -2
- package/dist/adapters/agentspec/componentTypeDefaults.d.ts +1 -1
- package/dist/adapters/agentspec/componentTypeDefaults.js +120 -120
- package/dist/adapters/agentspec/defaultNodeTypes.d.ts +2 -2
- package/dist/adapters/agentspec/defaultNodeTypes.js +307 -307
- package/dist/adapters/agentspec/index.d.ts +10 -10
- package/dist/adapters/agentspec/index.js +6 -6
- package/dist/adapters/agentspec/validator.d.ts +2 -2
- package/dist/adapters/agentspec/validator.js +22 -20
- package/dist/api/enhanced-client.d.ts +3 -3
- package/dist/api/enhanced-client.js +73 -72
- package/dist/components/App.svelte +1090 -961
- package/dist/components/App.svelte.d.ts +9 -6
- package/dist/components/CanvasBanner.stories.svelte +23 -20
- package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
- package/dist/components/CanvasBanner.svelte +52 -46
- package/dist/components/ConfigForm.svelte +1164 -1065
- package/dist/components/ConfigForm.svelte.d.ts +2 -2
- package/dist/components/ConfigModal.svelte +180 -180
- package/dist/components/ConfigModal.svelte.d.ts +1 -1
- package/dist/components/ConfigPanel.stories.svelte +35 -35
- package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
- package/dist/components/ConfigPanel.svelte +178 -167
- package/dist/components/ConfigPanel.svelte.d.ts +1 -1
- package/dist/components/ConnectionLine.svelte +25 -25
- package/dist/components/EdgeRefresher.svelte +26 -26
- package/dist/components/FlowDropEdge.stories.svelte +179 -143
- package/dist/components/FlowDropEdge.svelte +147 -147
- package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
- package/dist/components/FlowDropZone.svelte +63 -60
- package/dist/components/FlowDropZone.svelte.d.ts +1 -1
- package/dist/components/LoadingSpinner.stories.svelte +19 -19
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
- package/dist/components/LoadingSpinner.svelte +21 -21
- package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
- package/dist/components/Logo.stories.svelte +13 -13
- package/dist/components/Logo.stories.svelte.d.ts +1 -1
- package/dist/components/Logo.svelte +101 -95
- package/dist/components/LogsSidebar.svelte +553 -546
- package/dist/components/LogsSidebar.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.stories.svelte +29 -23
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.svelte +16 -14
- package/dist/components/Navbar.stories.svelte +43 -38
- package/dist/components/Navbar.stories.svelte.d.ts +1 -1
- package/dist/components/Navbar.svelte +760 -706
- package/dist/components/Navbar.svelte.d.ts +1 -1
- package/dist/components/NodeSidebar.svelte +905 -746
- package/dist/components/NodeSidebar.svelte.d.ts +5 -1
- package/dist/components/NodeStatusOverlay.stories.svelte +82 -70
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
- package/dist/components/NodeStatusOverlay.svelte +295 -280
- package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
- package/dist/components/PipelineStatus.svelte +326 -300
- package/dist/components/PipelineStatus.svelte.d.ts +4 -4
- package/dist/components/PortCoordinateTracker.svelte +49 -47
- package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
- package/dist/components/ReadOnlyDetails.svelte +156 -156
- package/dist/components/SchemaForm.stories.svelte +106 -98
- package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
- package/dist/components/SchemaForm.svelte +490 -463
- package/dist/components/SchemaForm.svelte.d.ts +2 -2
- package/dist/components/SettingsModal.svelte +226 -223
- package/dist/components/SettingsModal.svelte.d.ts +1 -1
- package/dist/components/SettingsPanel.svelte +637 -601
- package/dist/components/SettingsPanel.svelte.d.ts +1 -1
- package/dist/components/StatusIcon.stories.svelte +62 -49
- package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
- package/dist/components/StatusIcon.svelte +87 -87
- package/dist/components/StatusIcon.svelte.d.ts +2 -2
- package/dist/components/StatusLabel.stories.svelte +12 -12
- package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
- package/dist/components/StatusLabel.svelte +19 -19
- package/dist/components/ThemeToggle.stories.svelte +16 -16
- package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
- package/dist/components/ThemeToggle.svelte +180 -169
- package/dist/components/ThemeToggle.svelte.d.ts +1 -1
- package/dist/components/UniversalNode.svelte +150 -138
- package/dist/components/UniversalNode.svelte.d.ts +3 -3
- package/dist/components/WorkflowEditor.svelte +1069 -1014
- package/dist/components/WorkflowEditor.svelte.d.ts +4 -4
- package/dist/components/form/FormArray.svelte +1034 -973
- package/dist/components/form/FormArray.svelte.d.ts +1 -1
- package/dist/components/form/FormAutocomplete.svelte +1021 -978
- package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
- package/dist/components/form/FormCheckboxGroup.stories.svelte +23 -20
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormCheckboxGroup.svelte +136 -136
- package/dist/components/form/FormCodeEditor.svelte +452 -434
- package/dist/components/form/FormField.svelte +366 -355
- package/dist/components/form/FormField.svelte.d.ts +2 -2
- package/dist/components/form/FormFieldLight.svelte +400 -384
- package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.stories.svelte +42 -42
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.svelte +100 -93
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldset.svelte +108 -108
- package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
- package/dist/components/form/FormMarkdownEditor.svelte +758 -725
- package/dist/components/form/FormNumberField.stories.svelte +25 -25
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormNumberField.svelte +88 -88
- package/dist/components/form/FormRangeField.stories.svelte +20 -20
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormRangeField.svelte +234 -226
- package/dist/components/form/FormSelect.stories.svelte +38 -38
- package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormSelect.svelte +101 -101
- package/dist/components/form/FormSelect.svelte.d.ts +1 -1
- package/dist/components/form/FormTemplateEditor.svelte +847 -798
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
- package/dist/components/form/FormTextField.stories.svelte +29 -23
- package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormTextField.svelte +68 -68
- package/dist/components/form/FormTextarea.stories.svelte +28 -25
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormTextarea.svelte +74 -74
- package/dist/components/form/FormToggle.stories.svelte +23 -20
- package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormToggle.svelte +98 -98
- package/dist/components/form/FormUISchemaRenderer.svelte +120 -113
- package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
- package/dist/components/form/index.d.ts +19 -19
- package/dist/components/form/index.js +18 -18
- package/dist/components/form/templateAutocomplete.d.ts +2 -2
- package/dist/components/form/templateAutocomplete.js +64 -55
- package/dist/components/form/types.d.ts +6 -6
- package/dist/components/form/types.js +9 -4
- package/dist/components/icons/AlertCircleIcon.svelte +11 -0
- package/dist/components/icons/AlertCircleIcon.svelte.d.ts +26 -0
- package/dist/components/icons/CogIcon.svelte +11 -0
- package/dist/components/icons/CogIcon.svelte.d.ts +26 -0
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +54 -38
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ChoicePrompt.svelte +407 -383
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +48 -48
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -274
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/FormPrompt.svelte +223 -218
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/InterruptBubble.svelte +617 -583
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +66 -56
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ReviewPrompt.svelte +861 -841
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +38 -33
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/TextInputPrompt.svelte +333 -328
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/index.d.ts +5 -5
- package/dist/components/interrupt/index.js +5 -5
- package/dist/components/layouts/MainLayout.svelte +724 -691
- package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
- package/dist/components/nodes/GatewayNode.stories.svelte +100 -99
- package/dist/components/nodes/GatewayNode.svelte +605 -571
- package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
- package/dist/components/nodes/IdeaNode.stories.svelte +44 -43
- package/dist/components/nodes/IdeaNode.svelte +451 -437
- package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
- package/dist/components/nodes/NotesNode.stories.svelte +65 -64
- package/dist/components/nodes/NotesNode.svelte +380 -369
- package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SimpleNode.stories.svelte +145 -144
- package/dist/components/nodes/SimpleNode.svelte +486 -424
- package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SquareNode.stories.svelte +73 -73
- package/dist/components/nodes/SquareNode.svelte +439 -380
- package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
- package/dist/components/nodes/TerminalNode.stories.svelte +13 -13
- package/dist/components/nodes/TerminalNode.svelte +709 -670
- package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
- package/dist/components/nodes/ToolNode.stories.svelte +181 -180
- package/dist/components/nodes/ToolNode.svelte +505 -447
- package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
- package/dist/components/nodes/WorkflowNode.stories.svelte +70 -46
- package/dist/components/nodes/WorkflowNode.svelte +621 -551
- package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
- package/dist/components/playground/ChatPanel.svelte +945 -889
- package/dist/components/playground/ExecutionLogs.svelte +495 -472
- package/dist/components/playground/InputCollector.svelte +449 -428
- package/dist/components/playground/MessageBubble.stories.svelte +47 -47
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
- package/dist/components/playground/MessageBubble.svelte +626 -610
- package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
- package/dist/components/playground/Playground.svelte +1088 -1057
- package/dist/components/playground/Playground.svelte.d.ts +3 -3
- package/dist/components/playground/PlaygroundModal.svelte +208 -204
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
- package/dist/components/playground/SessionManager.svelte +527 -521
- package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
- package/dist/config/agentSpecEndpoints.d.ts +1 -1
- package/dist/config/agentSpecEndpoints.js +20 -20
- package/dist/config/constants.js +2 -2
- package/dist/config/defaultCategories.d.ts +1 -1
- package/dist/config/defaultCategories.js +86 -86
- package/dist/config/defaultPortConfig.d.ts +1 -1
- package/dist/config/defaultPortConfig.js +144 -144
- package/dist/config/endpoints.d.ts +4 -4
- package/dist/config/endpoints.js +65 -65
- package/dist/config/runtimeConfig.d.ts +2 -2
- package/dist/config/runtimeConfig.js +8 -8
- package/dist/core/index.d.ts +63 -59
- package/dist/core/index.js +35 -33
- package/dist/display/index.d.ts +2 -2
- package/dist/display/index.js +2 -2
- package/dist/editor/index.d.ts +62 -62
- package/dist/editor/index.js +53 -53
- package/dist/form/code.d.ts +5 -5
- package/dist/form/code.js +14 -14
- package/dist/form/fieldRegistry.d.ts +3 -3
- package/dist/form/fieldRegistry.js +11 -9
- package/dist/form/full.d.ts +8 -8
- package/dist/form/full.js +9 -9
- package/dist/form/index.d.ts +18 -18
- package/dist/form/index.js +16 -16
- package/dist/form/markdown.d.ts +4 -4
- package/dist/form/markdown.js +8 -8
- package/dist/helpers/proximityConnect.d.ts +3 -3
- package/dist/helpers/proximityConnect.js +34 -32
- package/dist/helpers/workflowEditorHelper.d.ts +5 -5
- package/dist/helpers/workflowEditorHelper.js +108 -96
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/mocks/app-environment.js +2 -2
- package/dist/mocks/app-forms.js +9 -9
- package/dist/mocks/app-navigation.js +11 -11
- package/dist/mocks/app-stores.js +8 -8
- package/dist/playground/index.d.ts +19 -19
- package/dist/playground/index.js +16 -16
- package/dist/playground/mount.d.ts +3 -3
- package/dist/playground/mount.js +24 -24
- package/dist/registry/builtinFormats.js +13 -13
- package/dist/registry/builtinNodes.d.ts +2 -2
- package/dist/registry/builtinNodes.js +77 -77
- package/dist/registry/index.d.ts +4 -4
- package/dist/registry/index.js +4 -4
- package/dist/registry/nodeComponentRegistry.d.ts +8 -8
- package/dist/registry/nodeComponentRegistry.js +11 -9
- package/dist/registry/plugin.d.ts +2 -2
- package/dist/registry/plugin.js +11 -11
- package/dist/registry/workflowFormatRegistry.d.ts +3 -3
- package/dist/registry/workflowFormatRegistry.js +2 -2
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +2 -2
- package/dist/services/agentSpecExecutionService.d.ts +3 -3
- package/dist/services/agentSpecExecutionService.js +59 -55
- package/dist/services/api.d.ts +2 -2
- package/dist/services/api.js +37 -37
- package/dist/services/apiVariableService.d.ts +1 -1
- package/dist/services/apiVariableService.js +41 -34
- package/dist/services/autoSaveService.js +8 -8
- package/dist/services/categoriesApi.d.ts +2 -2
- package/dist/services/categoriesApi.js +8 -8
- package/dist/services/draftStorage.d.ts +1 -1
- package/dist/services/draftStorage.js +11 -11
- package/dist/services/dynamicSchemaService.d.ts +1 -1
- package/dist/services/dynamicSchemaService.js +41 -39
- package/dist/services/globalSave.d.ts +2 -2
- package/dist/services/globalSave.js +41 -38
- package/dist/services/historyService.d.ts +1 -1
- package/dist/services/historyService.js +8 -8
- package/dist/services/interruptService.d.ts +1 -1
- package/dist/services/interruptService.js +35 -29
- package/dist/services/nodeExecutionService.d.ts +1 -1
- package/dist/services/nodeExecutionService.js +45 -44
- package/dist/services/playgroundService.d.ts +1 -1
- package/dist/services/playgroundService.js +29 -29
- package/dist/services/portConfigApi.d.ts +2 -2
- package/dist/services/portConfigApi.js +8 -8
- package/dist/services/settingsService.d.ts +2 -2
- package/dist/services/settingsService.js +25 -19
- package/dist/services/toastService.d.ts +4 -4
- package/dist/services/toastService.js +33 -33
- package/dist/services/variableService.d.ts +1 -1
- package/dist/services/variableService.js +36 -36
- package/dist/services/workflowStorage.d.ts +2 -2
- package/dist/services/workflowStorage.js +13 -13
- package/dist/settings/index.d.ts +7 -7
- package/dist/settings/index.js +6 -6
- package/dist/skins/default.d.ts +2 -0
- package/dist/skins/default.js +1 -0
- package/dist/skins/index.d.ts +13 -0
- package/dist/skins/index.js +30 -0
- package/dist/skins/slate.d.ts +2 -0
- package/dist/skins/slate.js +78 -0
- package/dist/stores/categoriesStore.svelte.d.ts +1 -1
- package/dist/stores/categoriesStore.svelte.js +5 -5
- package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
- package/dist/stores/editorStateMachine.svelte.js +65 -33
- package/dist/stores/historyStore.svelte.d.ts +4 -4
- package/dist/stores/historyStore.svelte.js +4 -4
- package/dist/stores/interruptStore.svelte.d.ts +3 -3
- package/dist/stores/interruptStore.svelte.js +21 -21
- package/dist/stores/playgroundStore.svelte.d.ts +2 -2
- package/dist/stores/playgroundStore.svelte.js +25 -18
- package/dist/stores/portCoordinateStore.svelte.d.ts +2 -2
- package/dist/stores/portCoordinateStore.svelte.js +15 -8
- package/dist/stores/settingsStore.svelte.d.ts +2 -2
- package/dist/stores/settingsStore.svelte.js +62 -57
- package/dist/stores/workflowStore.svelte.d.ts +3 -3
- package/dist/stores/workflowStore.svelte.js +50 -47
- package/dist/stories/CanvasDecorator.svelte +35 -32
- package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
- package/dist/stories/EdgeDecorator.svelte +102 -99
- package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
- package/dist/stories/NodeDecorator.svelte +59 -53
- package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
- package/dist/stories/utils.d.ts +2 -2
- package/dist/stories/utils.js +105 -67
- package/dist/styles/base.css +599 -595
- package/dist/styles/toast.css +14 -14
- package/dist/styles/tokens.css +409 -378
- package/dist/svelte-app.d.ts +12 -9
- package/dist/svelte-app.js +40 -39
- package/dist/themes/default.d.ts +2 -0
- package/dist/themes/default.js +9 -0
- package/dist/themes/index.d.ts +13 -0
- package/dist/themes/index.js +44 -0
- package/dist/themes/minimal.d.ts +2 -0
- package/dist/themes/minimal.js +11 -0
- package/dist/types/agentspec.d.ts +18 -18
- package/dist/types/agentspec.js +2 -2
- package/dist/types/auth.d.ts +1 -1
- package/dist/types/auth.js +6 -6
- package/dist/types/config.d.ts +6 -6
- package/dist/types/events.d.ts +2 -2
- package/dist/types/events.js +2 -2
- package/dist/types/index.d.ts +32 -32
- package/dist/types/index.js +6 -6
- package/dist/types/interrupt.d.ts +6 -6
- package/dist/types/interrupt.js +21 -21
- package/dist/types/interruptState.d.ts +12 -12
- package/dist/types/interruptState.js +66 -66
- package/dist/types/playground.d.ts +7 -7
- package/dist/types/playground.js +14 -14
- package/dist/types/settings.d.ts +5 -3
- package/dist/types/settings.js +25 -18
- package/dist/types/skin.d.ts +31 -0
- package/dist/types/skin.js +1 -0
- package/dist/types/theme.d.ts +35 -0
- package/dist/types/theme.js +1 -0
- package/dist/types/uischema.d.ts +4 -4
- package/dist/types/uischema.js +3 -3
- package/dist/utils/colors.d.ts +1 -1
- package/dist/utils/colors.js +97 -95
- package/dist/utils/config.d.ts +2 -2
- package/dist/utils/config.js +48 -48
- package/dist/utils/connections.d.ts +2 -2
- package/dist/utils/connections.js +15 -15
- package/dist/utils/errors.js +3 -3
- package/dist/utils/fetchWithAuth.d.ts +1 -1
- package/dist/utils/fetchWithAuth.js +2 -2
- package/dist/utils/handleIds.d.ts +2 -2
- package/dist/utils/handleIds.js +8 -8
- package/dist/utils/handlePositioning.d.ts +1 -1
- package/dist/utils/handlePositioning.js +2 -2
- package/dist/utils/icons.d.ts +1 -1
- package/dist/utils/icons.js +74 -74
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +7 -7
- package/dist/utils/nodeStatus.d.ts +1 -1
- package/dist/utils/nodeStatus.js +48 -48
- package/dist/utils/nodeTypes.d.ts +1 -1
- package/dist/utils/nodeTypes.js +21 -20
- package/dist/utils/nodeWrapper.d.ts +7 -7
- package/dist/utils/nodeWrapper.js +21 -19
- package/dist/utils/performanceUtils.d.ts +1 -1
- package/dist/utils/performanceUtils.js +2 -1
- package/dist/utils/sanitize.js +1 -1
- package/dist/utils/uischema.d.ts +2 -2
- package/dist/utils/uischema.js +8 -8
- package/dist/utils/validation.js +20 -8
- package/package.json +1 -1
|
@@ -5,949 +5,1004 @@
|
|
|
5
5
|
-->
|
|
6
6
|
|
|
7
7
|
<script lang="ts">
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
8
|
+
import {
|
|
9
|
+
SvelteFlow,
|
|
10
|
+
ConnectionLineType,
|
|
11
|
+
Controls,
|
|
12
|
+
Background,
|
|
13
|
+
BackgroundVariant,
|
|
14
|
+
MiniMap,
|
|
15
|
+
SvelteFlowProvider,
|
|
16
|
+
type ColorMode,
|
|
17
|
+
} from "@xyflow/svelte";
|
|
18
|
+
import "@xyflow/svelte/dist/style.css";
|
|
19
|
+
import {
|
|
20
|
+
getResolvedTheme,
|
|
21
|
+
getEditorSettings,
|
|
22
|
+
getBehaviorSettings,
|
|
23
|
+
} from "../stores/settingsStore.svelte.js";
|
|
24
|
+
import type {
|
|
25
|
+
WorkflowNode as WorkflowNodeType,
|
|
26
|
+
NodeMetadata,
|
|
27
|
+
Workflow,
|
|
28
|
+
WorkflowEdge,
|
|
29
|
+
} from "../types/index.js";
|
|
30
|
+
import CanvasBanner from "./CanvasBanner.svelte";
|
|
31
|
+
import FlowDropZone from "./FlowDropZone.svelte";
|
|
32
|
+
import EdgeRefresher from "./EdgeRefresher.svelte";
|
|
33
|
+
import { tick, untrack } from "svelte";
|
|
34
|
+
import type { EndpointConfig } from "../config/endpoints.js";
|
|
35
|
+
import ConnectionLine from "./ConnectionLine.svelte";
|
|
36
|
+
import FlowDropEdge from "./FlowDropEdge.svelte";
|
|
37
|
+
import {
|
|
38
|
+
getWorkflowStore,
|
|
39
|
+
workflowActions,
|
|
40
|
+
} from "../stores/workflowStore.svelte.js";
|
|
41
|
+
import {
|
|
42
|
+
historyActions,
|
|
43
|
+
setOnRestoreCallback,
|
|
44
|
+
} from "../stores/historyStore.svelte.js";
|
|
45
|
+
import UniversalNode from "./UniversalNode.svelte";
|
|
46
|
+
import {
|
|
47
|
+
EdgeStylingHelper,
|
|
48
|
+
NodeOperationsHelper,
|
|
49
|
+
WorkflowOperationsHelper,
|
|
50
|
+
ConfigurationHelper,
|
|
51
|
+
} from "../helpers/workflowEditorHelper.js";
|
|
52
|
+
import type { NodeExecutionInfo } from "../types/index.js";
|
|
53
|
+
import { Toaster } from "svelte-5-french-toast";
|
|
54
|
+
import {
|
|
55
|
+
flowdropToastOptions,
|
|
56
|
+
FLOWDROP_TOASTER_CLASS,
|
|
57
|
+
apiToasts,
|
|
58
|
+
} from "../services/toastService.js";
|
|
59
|
+
import {
|
|
60
|
+
ProximityConnectHelper,
|
|
61
|
+
type ProximityEdgeCandidate,
|
|
62
|
+
} from "../helpers/proximityConnect.js";
|
|
63
|
+
import PortCoordinateTracker from "./PortCoordinateTracker.svelte";
|
|
64
|
+
import { getPortCoordinateSnapshot } from "../stores/portCoordinateStore.svelte.js";
|
|
65
|
+
import { logger } from "../utils/logger.js";
|
|
66
|
+
import { validateWorkflowData } from "../utils/validation.js";
|
|
67
|
+
import { createEditorStateMachine } from "../stores/editorStateMachine.svelte.js";
|
|
68
|
+
|
|
69
|
+
interface Props {
|
|
70
|
+
nodes?: NodeMetadata[];
|
|
71
|
+
endpointConfig?: EndpointConfig;
|
|
72
|
+
height?: string | number;
|
|
73
|
+
width?: string | number;
|
|
74
|
+
isConfigSidebarOpen?: boolean;
|
|
75
|
+
selectedNodeForConfig?: WorkflowNodeType | null;
|
|
76
|
+
openConfigSidebar?: (node: WorkflowNodeType) => void;
|
|
77
|
+
closeConfigSidebar?: () => void;
|
|
78
|
+
// New configuration options for pipeline status mode
|
|
79
|
+
lockWorkflow?: boolean;
|
|
80
|
+
readOnly?: boolean;
|
|
81
|
+
nodeStatuses?: Record<
|
|
82
|
+
string,
|
|
83
|
+
"pending" | "running" | "completed" | "error"
|
|
84
|
+
>;
|
|
85
|
+
// Pipeline ID for fetching node execution info from jobs
|
|
86
|
+
pipelineId?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let props: Props = $props();
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Editor State Machine
|
|
93
|
+
// Centralizes reactive guards — replaces scattered boolean flags
|
|
94
|
+
// (isDraggingNode, lastEditorStoreValue identity checks, etc.)
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
const machine = createEditorStateMachine();
|
|
97
|
+
|
|
98
|
+
// Dev-mode transition logging
|
|
99
|
+
if (import.meta.env?.DEV) {
|
|
100
|
+
machine.onTransition((from, event, to) => {
|
|
101
|
+
logger.debug(`[EditorFSM] ${from} --${event}--> ${to}`);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Proximity connect state
|
|
106
|
+
let currentProximityCandidates = $state<ProximityEdgeCandidate[]>([]);
|
|
107
|
+
|
|
108
|
+
// Port coordinate tracker state
|
|
109
|
+
let portCoordNodeToUpdate = $state<WorkflowNodeType | null>(null);
|
|
110
|
+
let portCoordRebuildTrigger = $state(0);
|
|
111
|
+
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Flow state — bound to SvelteFlow via bind:nodes / bind:edges
|
|
114
|
+
// These are $state.raw to prevent deep proxy leaking (SvelteFlow mutates
|
|
115
|
+
// node internals during drag which would cause infinite loops with $state).
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
let flowNodes = $state.raw<WorkflowNodeType[]>([]);
|
|
118
|
+
let flowEdges = $state.raw<WorkflowEdge[]>([]);
|
|
119
|
+
|
|
120
|
+
// Execution info loading state
|
|
121
|
+
let loadExecutionInfoTimeout: number | null = null;
|
|
122
|
+
let executionInfoAbortController: AbortController | null = null;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Key for SvelteFlow component — changes when workflow ID changes.
|
|
126
|
+
* Forces SvelteFlow to remount with fresh state, allowing fitView to work correctly.
|
|
127
|
+
*/
|
|
128
|
+
let svelteFlowKey = $derived(getWorkflowStore()?.id ?? "default");
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Derive snap grid configuration from editor settings
|
|
132
|
+
*/
|
|
133
|
+
let snapGrid = $derived(
|
|
134
|
+
getEditorSettings().snapToGrid
|
|
135
|
+
? ([getEditorSettings().gridSize, getEditorSettings().gridSize] as [
|
|
136
|
+
number,
|
|
137
|
+
number,
|
|
138
|
+
])
|
|
139
|
+
: undefined,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Derive initial viewport configuration from editor settings
|
|
144
|
+
*/
|
|
145
|
+
let initialViewport = $derived({
|
|
146
|
+
zoom: getEditorSettings().defaultZoom,
|
|
147
|
+
x: 0,
|
|
148
|
+
y: 0,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Helper: derive flowNodes/flowEdges from a Workflow object
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
function buildFlowNodesFromStore(workflow: Workflow): {
|
|
155
|
+
nodes: WorkflowNodeType[];
|
|
156
|
+
edges: WorkflowEdge[];
|
|
157
|
+
} {
|
|
158
|
+
const nodesWithCallbacks = workflow.nodes.map((node) => ({
|
|
159
|
+
...node,
|
|
160
|
+
data: {
|
|
161
|
+
...node.data,
|
|
162
|
+
onConfigOpen: props.openConfigSidebar,
|
|
163
|
+
},
|
|
164
|
+
}));
|
|
165
|
+
const styledEdges = EdgeStylingHelper.updateEdgeStyles(
|
|
166
|
+
workflow.edges,
|
|
167
|
+
nodesWithCallbacks,
|
|
168
|
+
);
|
|
169
|
+
return { nodes: nodesWithCallbacks, edges: styledEdges };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// Helper: sync current flowNodes/flowEdges back to the global store
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
function syncFlowToStore(): void {
|
|
176
|
+
const storeValue = untrack(() => getWorkflowStore());
|
|
177
|
+
if (!storeValue) return;
|
|
178
|
+
const updatedWorkflow = WorkflowOperationsHelper.updateWorkflow(
|
|
179
|
+
storeValue,
|
|
180
|
+
flowNodes,
|
|
181
|
+
flowEdges,
|
|
182
|
+
);
|
|
183
|
+
workflowActions.updateWorkflow(updatedWorkflow);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Single sync effect: workflowStore → flowNodes / flowEdges
|
|
188
|
+
// Replaces the old Effect A (store→currentWorkflow) + Effect B (currentWorkflow→flow).
|
|
189
|
+
// Suppressed during operations via state machine; handlers update flowNodes directly.
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
let previousSyncedWorkflowId: string | null = null;
|
|
192
|
+
|
|
193
|
+
$effect(() => {
|
|
194
|
+
const storeValue = getWorkflowStore();
|
|
195
|
+
|
|
196
|
+
// Suppressed during operations — handlers write to flowNodes directly
|
|
197
|
+
if (untrack(() => machine.permissions.suppressEffect)) return;
|
|
198
|
+
|
|
199
|
+
if (!storeValue) {
|
|
200
|
+
if (flowNodes.length > 0 || flowEdges.length > 0) {
|
|
201
|
+
flowNodes = [];
|
|
202
|
+
flowEdges = [];
|
|
203
|
+
previousSyncedWorkflowId = null;
|
|
204
|
+
untrack(() => machine.send("WORKFLOW_CLEARED"));
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const isNewWorkflow = storeValue.id !== previousSyncedWorkflowId;
|
|
210
|
+
|
|
211
|
+
if (isNewWorkflow) {
|
|
212
|
+
untrack(() =>
|
|
213
|
+
machine.send(
|
|
214
|
+
previousSyncedWorkflowId ? "WORKFLOW_SWITCHED" : "WORKFLOW_LOADED",
|
|
215
|
+
),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Derive flowNodes/flowEdges from store
|
|
220
|
+
const derived = buildFlowNodesFromStore(storeValue);
|
|
221
|
+
flowNodes = derived.nodes;
|
|
222
|
+
flowEdges = derived.edges;
|
|
223
|
+
previousSyncedWorkflowId = storeValue.id;
|
|
224
|
+
|
|
225
|
+
// Trigger port coordinate rebuild after workflow load
|
|
226
|
+
if (getEditorSettings().proximityConnect) {
|
|
227
|
+
portCoordRebuildTrigger = Date.now();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (isNewWorkflow) {
|
|
231
|
+
untrack(() => machine.send("LOAD_COMPLETE"));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// Execution info effect (separate — async, depends on workflow + pipeline ID)
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
let previousExecWorkflowId: string | null = null;
|
|
239
|
+
let previousExecPipelineId: string | undefined = undefined;
|
|
240
|
+
|
|
241
|
+
$effect(() => {
|
|
242
|
+
const storeValue = getWorkflowStore();
|
|
243
|
+
const pipelineId = props.pipelineId;
|
|
244
|
+
|
|
245
|
+
if (!storeValue || !pipelineId) return;
|
|
246
|
+
|
|
247
|
+
const workflowChanged = storeValue.id !== previousExecWorkflowId;
|
|
248
|
+
const pipelineChanged = pipelineId !== previousExecPipelineId;
|
|
249
|
+
|
|
250
|
+
if (!workflowChanged && !pipelineChanged) return;
|
|
251
|
+
|
|
252
|
+
previousExecWorkflowId = storeValue.id;
|
|
253
|
+
previousExecPipelineId = pipelineId;
|
|
254
|
+
|
|
255
|
+
// Cancel any pending timeout / in-flight request
|
|
256
|
+
if (loadExecutionInfoTimeout) {
|
|
257
|
+
clearTimeout(loadExecutionInfoTimeout);
|
|
258
|
+
loadExecutionInfoTimeout = null;
|
|
259
|
+
}
|
|
260
|
+
if (executionInfoAbortController) {
|
|
261
|
+
executionInfoAbortController.abort();
|
|
262
|
+
executionInfoAbortController = null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Schedule loading with requestIdleCallback (falls back to setTimeout)
|
|
266
|
+
if (typeof requestIdleCallback !== "undefined") {
|
|
267
|
+
loadExecutionInfoTimeout = requestIdleCallback(
|
|
268
|
+
() => {
|
|
269
|
+
loadNodeExecutionInfo();
|
|
270
|
+
},
|
|
271
|
+
{ timeout: 500 },
|
|
272
|
+
) as unknown as number;
|
|
273
|
+
} else {
|
|
274
|
+
loadExecutionInfoTimeout = setTimeout(() => {
|
|
275
|
+
loadNodeExecutionInfo();
|
|
276
|
+
}, 300) as unknown as number;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
// History restore callback
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
$effect(() => {
|
|
284
|
+
setOnRestoreCallback((restoredWorkflow: Workflow) => {
|
|
285
|
+
machine.send("START_RESTORE");
|
|
286
|
+
// Update the store (effect is suppressed during 'restoring')
|
|
287
|
+
workflowActions.restoreFromHistory(restoredWorkflow);
|
|
288
|
+
// Derive flowNodes/flowEdges directly for immediate visual update
|
|
289
|
+
const derived = buildFlowNodesFromStore(restoredWorkflow);
|
|
290
|
+
flowNodes = derived.nodes;
|
|
291
|
+
flowEdges = derived.edges;
|
|
292
|
+
machine.send("RESTORE_COMPLETE");
|
|
293
|
+
// After RESTORE_COMPLETE → idle, the sync effect runs but produces
|
|
294
|
+
// the same data (no-op re-derive).
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return () => {
|
|
298
|
+
setOnRestoreCallback(null);
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Load node execution information for all nodes in the workflow
|
|
304
|
+
*/
|
|
305
|
+
async function loadNodeExecutionInfo(): Promise<void> {
|
|
306
|
+
const workflow = untrack(() => getWorkflowStore());
|
|
307
|
+
if (!workflow?.nodes || !props.pipelineId) return;
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
executionInfoAbortController = new AbortController();
|
|
311
|
+
|
|
312
|
+
const executionInfo = await NodeOperationsHelper.loadNodeExecutionInfo(
|
|
313
|
+
workflow,
|
|
314
|
+
props.pipelineId,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
if (executionInfoAbortController?.signal.aborted) return;
|
|
318
|
+
|
|
319
|
+
const defaultExecutionInfo: NodeExecutionInfo = {
|
|
320
|
+
status: "idle" as const,
|
|
321
|
+
executionCount: 0,
|
|
322
|
+
isExecuting: false,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// Update flowNodes with execution info (visual-only, no store sync needed)
|
|
326
|
+
flowNodes = flowNodes.map((node) => ({
|
|
327
|
+
...node,
|
|
328
|
+
data: {
|
|
329
|
+
...node.data,
|
|
330
|
+
executionInfo: executionInfo[node.id] || defaultExecutionInfo,
|
|
331
|
+
},
|
|
332
|
+
}));
|
|
333
|
+
|
|
334
|
+
executionInfoAbortController = null;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
if (error instanceof Error && error.name !== "AbortError") {
|
|
337
|
+
logger.error("Failed to load node execution info:", error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// The global store should be initialized by the parent App component
|
|
343
|
+
|
|
344
|
+
// Sidebar is now always visible - removed toggle functionality
|
|
345
|
+
|
|
346
|
+
// Node types for Svelte Flow - using UniversalNode for all node types
|
|
347
|
+
// All nodes use 'universalNode' type, and UniversalNode handles internal switching
|
|
348
|
+
const nodeTypes = {
|
|
349
|
+
universalNode: UniversalNode,
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// Use custom edge that shortens the path so the stroke ends at the arrow base
|
|
353
|
+
const edgeTypes = {
|
|
354
|
+
default: FlowDropEdge,
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
// Handle arrows in our custom connection handler
|
|
358
|
+
const defaultEdgeOptions = {};
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Handle node drag start
|
|
362
|
+
*
|
|
363
|
+
* Transitions the state machine to 'dragging', which suppresses
|
|
364
|
+
* the sync effect to prevent reactive loops during high-frequency
|
|
365
|
+
* position updates. SvelteFlow mutates flowNodes directly via bind:nodes.
|
|
366
|
+
*/
|
|
367
|
+
function handleNodeDragStart(): void {
|
|
368
|
+
machine.send("START_DRAG");
|
|
369
|
+
// Clear any leftover proximity previews
|
|
370
|
+
currentProximityCandidates = [];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Handle node drag - compute proximity connect preview edges
|
|
375
|
+
* Called continuously during drag if proximity connect is enabled.
|
|
376
|
+
* Uses port-to-port distance via the port coordinate store.
|
|
377
|
+
*/
|
|
378
|
+
function handleNodeDrag({
|
|
379
|
+
targetNode,
|
|
380
|
+
}: {
|
|
381
|
+
targetNode: WorkflowNodeType | null;
|
|
382
|
+
nodes: WorkflowNodeType[];
|
|
383
|
+
event: MouseEvent | TouchEvent;
|
|
384
|
+
}): void {
|
|
385
|
+
if (
|
|
386
|
+
!getEditorSettings().proximityConnect ||
|
|
387
|
+
!targetNode ||
|
|
388
|
+
props.readOnly ||
|
|
389
|
+
props.lockWorkflow
|
|
390
|
+
) {
|
|
391
|
+
if (currentProximityCandidates.length > 0) {
|
|
392
|
+
flowEdges = ProximityConnectHelper.removePreviewEdges(flowEdges);
|
|
393
|
+
currentProximityCandidates = [];
|
|
394
|
+
}
|
|
395
|
+
portCoordNodeToUpdate = null;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Update the dragged node's port coordinates (position changed during drag)
|
|
400
|
+
portCoordNodeToUpdate = targetNode;
|
|
401
|
+
|
|
402
|
+
// Remove previous preview edges
|
|
403
|
+
const baseEdges = ProximityConnectHelper.removePreviewEdges(flowEdges);
|
|
404
|
+
|
|
405
|
+
// Find the best compatible edge using port-to-port distance
|
|
406
|
+
const portCoordinates = getPortCoordinateSnapshot();
|
|
407
|
+
const candidates =
|
|
408
|
+
portCoordinates.size > 0
|
|
409
|
+
? ProximityConnectHelper.findCompatibleEdgesByPortCoordinates(
|
|
410
|
+
targetNode.id,
|
|
411
|
+
portCoordinates,
|
|
412
|
+
baseEdges,
|
|
413
|
+
getEditorSettings().proximityConnectDistance,
|
|
414
|
+
)
|
|
415
|
+
: ProximityConnectHelper.findCompatibleEdges(
|
|
416
|
+
targetNode,
|
|
417
|
+
flowNodes,
|
|
418
|
+
baseEdges,
|
|
419
|
+
getEditorSettings().proximityConnectDistance,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
// Create preview edges
|
|
423
|
+
const previews = ProximityConnectHelper.createPreviewEdges(candidates);
|
|
424
|
+
|
|
425
|
+
// Update state
|
|
426
|
+
currentProximityCandidates = candidates;
|
|
427
|
+
flowEdges = [...baseEdges, ...previews];
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Handle node drag stop
|
|
432
|
+
*
|
|
433
|
+
* Still in 'dragging' state — sync effect suppressed.
|
|
434
|
+
* Syncs final positions to store, pushes history, then transitions to idle.
|
|
435
|
+
*/
|
|
436
|
+
function handleNodeDragStop(): void {
|
|
437
|
+
portCoordNodeToUpdate = null;
|
|
438
|
+
|
|
439
|
+
// Finalize proximity connect if there are candidates
|
|
440
|
+
if (
|
|
441
|
+
getEditorSettings().proximityConnect &&
|
|
442
|
+
currentProximityCandidates.length > 0
|
|
443
|
+
) {
|
|
444
|
+
const baseEdges = ProximityConnectHelper.removePreviewEdges(flowEdges);
|
|
445
|
+
const permanentEdges = ProximityConnectHelper.createPermanentEdges(
|
|
446
|
+
currentProximityCandidates,
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
for (const edge of permanentEdges) {
|
|
450
|
+
const sourceNode = flowNodes.find((n) => n.id === edge.source);
|
|
451
|
+
const targetNode = flowNodes.find((n) => n.id === edge.target);
|
|
452
|
+
if (sourceNode && targetNode) {
|
|
453
|
+
EdgeStylingHelper.applyConnectionStyling(
|
|
454
|
+
edge,
|
|
455
|
+
sourceNode,
|
|
456
|
+
targetNode,
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
flowEdges = [...baseEdges, ...permanentEdges];
|
|
462
|
+
currentProximityCandidates = [];
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Sync flowNodes/flowEdges → store
|
|
466
|
+
syncFlowToStore();
|
|
467
|
+
|
|
468
|
+
// Push history AFTER the drag completed
|
|
469
|
+
const storeValue = getWorkflowStore();
|
|
470
|
+
if (storeValue) {
|
|
471
|
+
workflowActions.pushHistory("Move node", storeValue);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Transition to idle — sync effect is now unblocked
|
|
475
|
+
machine.send("STOP_DRAG");
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Handle new connections between nodes
|
|
480
|
+
*/
|
|
481
|
+
async function handleConnect(connection: {
|
|
482
|
+
source: string;
|
|
483
|
+
target: string;
|
|
484
|
+
sourceHandle?: string;
|
|
485
|
+
targetHandle?: string;
|
|
486
|
+
}): Promise<void> {
|
|
487
|
+
machine.send("START_CONNECT");
|
|
488
|
+
|
|
489
|
+
// SvelteFlow auto-creates the edge via bind:edges — wait for DOM update
|
|
490
|
+
await tick();
|
|
491
|
+
|
|
492
|
+
// Apply styling to all edges (including the new one)
|
|
493
|
+
flowEdges = EdgeStylingHelper.updateEdgeStyles(flowEdges, flowNodes);
|
|
494
|
+
|
|
495
|
+
// Sync to store
|
|
496
|
+
syncFlowToStore();
|
|
497
|
+
|
|
498
|
+
const storeValue = getWorkflowStore();
|
|
499
|
+
if (storeValue) {
|
|
500
|
+
workflowActions.pushHistory("Add connection", storeValue);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
machine.send("CONNECTION_MADE");
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Handle before delete - show confirmation dialog if enabled in settings
|
|
508
|
+
*
|
|
509
|
+
* This callback is called before nodes/edges are deleted.
|
|
510
|
+
* Return true to proceed with deletion, false to cancel.
|
|
511
|
+
*
|
|
512
|
+
* @param params - Object containing nodes and edges to be deleted
|
|
513
|
+
* @returns Promise resolving to true if deletion should proceed, false to cancel
|
|
514
|
+
*/
|
|
515
|
+
async function handleBeforeDelete(params: {
|
|
516
|
+
nodes: WorkflowNodeType[];
|
|
517
|
+
edges: WorkflowEdge[];
|
|
518
|
+
}): Promise<boolean> {
|
|
519
|
+
// If confirmDelete setting is enabled, show confirmation dialog
|
|
520
|
+
if (getBehaviorSettings().confirmDelete) {
|
|
521
|
+
const nodeCount = params.nodes.length;
|
|
522
|
+
const edgeCount = params.edges.length;
|
|
523
|
+
|
|
524
|
+
// Build a descriptive message
|
|
525
|
+
let message = "Are you sure you want to delete ";
|
|
526
|
+
const parts: string[] = [];
|
|
527
|
+
|
|
528
|
+
if (nodeCount > 0) {
|
|
529
|
+
parts.push(`${nodeCount} node${nodeCount > 1 ? "s" : ""}`);
|
|
530
|
+
}
|
|
531
|
+
if (edgeCount > 0) {
|
|
532
|
+
parts.push(`${edgeCount} connection${edgeCount > 1 ? "s" : ""}`);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
message += parts.join(" and ") + "?";
|
|
536
|
+
|
|
537
|
+
// Show native confirmation dialog
|
|
538
|
+
const confirmed = window.confirm(message);
|
|
539
|
+
if (!confirmed) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Don't push to history here - we'll push AFTER deletion in handleNodesDelete
|
|
545
|
+
// This ensures undo will restore the state before deletion
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Handle node deletion - automatically remove connected edges and push to history
|
|
551
|
+
*/
|
|
552
|
+
function handleNodesDelete(params: {
|
|
553
|
+
nodes: WorkflowNodeType[];
|
|
554
|
+
edges: WorkflowEdge[];
|
|
555
|
+
}): void {
|
|
556
|
+
machine.send("START_DELETE");
|
|
557
|
+
|
|
558
|
+
const deletedNodeIds = new Set(params.nodes.map((node) => node.id));
|
|
559
|
+
|
|
560
|
+
// Filter out edges connected to deleted nodes
|
|
561
|
+
flowEdges = flowEdges.filter(
|
|
562
|
+
(edge) =>
|
|
563
|
+
!deletedNodeIds.has(edge.source) && !deletedNodeIds.has(edge.target),
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
// Sync to store
|
|
567
|
+
syncFlowToStore();
|
|
568
|
+
|
|
569
|
+
// Push to history AFTER the deletion so undo restores the previous state
|
|
570
|
+
const nodeCount = params.nodes.length;
|
|
571
|
+
const edgeCount = params.edges.length;
|
|
572
|
+
let description = "Delete";
|
|
573
|
+
if (nodeCount > 0 && edgeCount > 0) {
|
|
574
|
+
description = `Delete ${nodeCount} node${nodeCount > 1 ? "s" : ""} and ${edgeCount} connection${edgeCount > 1 ? "s" : ""}`;
|
|
575
|
+
} else if (nodeCount > 0) {
|
|
576
|
+
description = `Delete ${nodeCount} node${nodeCount > 1 ? "s" : ""}`;
|
|
577
|
+
} else if (edgeCount > 0) {
|
|
578
|
+
description = `Delete ${edgeCount} connection${edgeCount > 1 ? "s" : ""}`;
|
|
579
|
+
}
|
|
580
|
+
const storeValue = getWorkflowStore();
|
|
581
|
+
if (storeValue) {
|
|
582
|
+
workflowActions.pushHistory(description, storeValue);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
machine.send("DELETE_COMPLETE");
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Edge styling will be handled when edges are first created or manually updated
|
|
589
|
+
|
|
590
|
+
// Configure endpoints when props change
|
|
591
|
+
$effect(() => {
|
|
592
|
+
if (props.endpointConfig) {
|
|
593
|
+
ConfigurationHelper.configureEndpoints(props.endpointConfig);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Check if workflow has cycles
|
|
599
|
+
*/
|
|
600
|
+
function checkWorkflowCycles(): boolean {
|
|
601
|
+
return WorkflowOperationsHelper.checkWorkflowCycles(flowNodes, flowEdges);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Handle drop event and add new node to canvas
|
|
606
|
+
*/
|
|
607
|
+
async function handleNodeDrop(
|
|
608
|
+
nodeTypeData: string,
|
|
609
|
+
position: { x: number; y: number },
|
|
610
|
+
): Promise<void> {
|
|
611
|
+
machine.send("START_DROP");
|
|
612
|
+
|
|
613
|
+
const newNode = NodeOperationsHelper.createNodeFromDrop(
|
|
614
|
+
nodeTypeData,
|
|
615
|
+
position,
|
|
616
|
+
flowNodes,
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
if (newNode) {
|
|
620
|
+
// Add onConfigOpen callback and append to flowNodes for immediate visual feedback
|
|
621
|
+
const nodeWithCallback = {
|
|
622
|
+
...newNode,
|
|
623
|
+
data: { ...newNode.data, onConfigOpen: props.openConfigSidebar },
|
|
624
|
+
};
|
|
625
|
+
flowNodes = [...flowNodes, nodeWithCallback];
|
|
626
|
+
|
|
627
|
+
// Sync to store
|
|
628
|
+
syncFlowToStore();
|
|
629
|
+
|
|
630
|
+
await tick();
|
|
631
|
+
|
|
632
|
+
const storeValue = getWorkflowStore();
|
|
633
|
+
if (storeValue) {
|
|
634
|
+
workflowActions.pushHistory("Add node", storeValue);
|
|
635
|
+
}
|
|
636
|
+
} else {
|
|
637
|
+
logger.warn("Failed to create node from drop data");
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
machine.send("DROP_COMPLETE");
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Handle a workflow JSON file dropped directly onto the canvas.
|
|
645
|
+
*
|
|
646
|
+
* Validates the JSON against the minimum required Workflow fields and, if valid,
|
|
647
|
+
* loads it into the workflow store. Shows a toast on validation failure or read error.
|
|
648
|
+
*/
|
|
649
|
+
function handleWorkflowFileDrop(file: File): void {
|
|
650
|
+
const reader = new FileReader();
|
|
651
|
+
reader.onload = (event) => {
|
|
652
|
+
try {
|
|
653
|
+
const text = event.target?.result;
|
|
654
|
+
if (typeof text !== "string") {
|
|
655
|
+
throw new Error("Could not read file contents.");
|
|
656
|
+
}
|
|
657
|
+
const data = JSON.parse(text);
|
|
658
|
+
const validation = validateWorkflowData(data);
|
|
659
|
+
if (!validation.valid) {
|
|
660
|
+
apiToasts.error(
|
|
661
|
+
"Import workflow",
|
|
662
|
+
validation.error ?? "Invalid workflow JSON",
|
|
663
|
+
);
|
|
664
|
+
logger.warn(
|
|
665
|
+
"Workflow file drop validation failed:",
|
|
666
|
+
validation.error,
|
|
667
|
+
);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
workflowActions.initialize(data as Workflow);
|
|
671
|
+
} catch (error) {
|
|
672
|
+
const errorObj =
|
|
673
|
+
error instanceof Error ? error : new Error("Unknown error occurred");
|
|
674
|
+
logger.error("Workflow file drop import failed:", errorObj);
|
|
675
|
+
apiToasts.error("Import workflow", errorObj.message);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
reader.onerror = () => {
|
|
679
|
+
const message = "Failed to read the dropped file.";
|
|
680
|
+
logger.error(message);
|
|
681
|
+
apiToasts.error("Import workflow", message);
|
|
682
|
+
};
|
|
683
|
+
reader.readAsText(file);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Node ID that needs edge refresh - used to trigger EdgeRefresher component
|
|
688
|
+
*/
|
|
689
|
+
let nodeIdToRefresh = $state<string | null>(null);
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Update a node's data in the local editor state.
|
|
693
|
+
* Called by App.svelte AFTER it has already updated the global store via
|
|
694
|
+
* workflowActions.updateNode(). We only need to update flowNodes for
|
|
695
|
+
* immediate visual feedback — no store sync needed.
|
|
696
|
+
*
|
|
697
|
+
* @param nodeId - The ID of the node to update
|
|
698
|
+
* @param dataUpdates - Partial data updates to merge into the node's data
|
|
699
|
+
*/
|
|
700
|
+
export function updateNodeData(
|
|
701
|
+
nodeId: string,
|
|
702
|
+
dataUpdates: Partial<WorkflowNodeType["data"]>,
|
|
703
|
+
): void {
|
|
704
|
+
machine.send("START_NODE_UPDATE");
|
|
705
|
+
|
|
706
|
+
flowNodes = flowNodes.map((node) => {
|
|
707
|
+
if (node.id === nodeId) {
|
|
708
|
+
return {
|
|
709
|
+
...node,
|
|
710
|
+
data: {
|
|
711
|
+
...node.data,
|
|
712
|
+
...dataUpdates,
|
|
713
|
+
},
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
return node;
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
machine.send("UPDATE_COMPLETE");
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Force edge position recalculation after node config changes
|
|
724
|
+
* This should be called after saving gateway/switch node configs where branches are reordered
|
|
725
|
+
* Svelte Flow doesn't automatically recalculate edge paths when handle positions change
|
|
726
|
+
* @param nodeId - The ID of the node whose handles have changed position
|
|
727
|
+
*/
|
|
728
|
+
export async function refreshEdgePositions(nodeId: string): Promise<void> {
|
|
729
|
+
// Wait for DOM to update with new handle positions
|
|
730
|
+
await tick();
|
|
731
|
+
|
|
732
|
+
// Trigger the EdgeRefresher component to call updateNodeInternals
|
|
733
|
+
nodeIdToRefresh = nodeId;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Callback when edge refresh is complete
|
|
738
|
+
*/
|
|
739
|
+
function handleEdgeRefreshComplete(): void {
|
|
740
|
+
nodeIdToRefresh = null;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Handle keyboard shortcuts for undo/redo
|
|
745
|
+
*
|
|
746
|
+
* - Ctrl+Z (or Cmd+Z on Mac): Undo
|
|
747
|
+
* - Ctrl+Shift+Z (or Cmd+Shift+Z): Redo
|
|
748
|
+
* - Ctrl+Y (or Cmd+Y): Redo (Windows convention)
|
|
749
|
+
*/
|
|
750
|
+
function handleKeydown(event: KeyboardEvent): void {
|
|
751
|
+
// Check for Ctrl (Windows/Linux) or Cmd (Mac)
|
|
752
|
+
const isModifierPressed = event.ctrlKey || event.metaKey;
|
|
753
|
+
|
|
754
|
+
if (!isModifierPressed) {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Don't handle shortcuts if user is typing in an input, textarea, or contenteditable
|
|
759
|
+
const target = event.target as HTMLElement;
|
|
760
|
+
const isInputElement =
|
|
761
|
+
target.tagName === "INPUT" ||
|
|
762
|
+
target.tagName === "TEXTAREA" ||
|
|
763
|
+
target.isContentEditable;
|
|
764
|
+
|
|
765
|
+
if (isInputElement) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Undo: Ctrl+Z (without Shift)
|
|
770
|
+
if (event.key === "z" && !event.shiftKey) {
|
|
771
|
+
event.preventDefault();
|
|
772
|
+
historyActions.undo();
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Redo: Ctrl+Shift+Z or Ctrl+Y
|
|
777
|
+
if ((event.key === "z" && event.shiftKey) || event.key === "y") {
|
|
778
|
+
event.preventDefault();
|
|
779
|
+
historyActions.redo();
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
742
783
|
</script>
|
|
743
784
|
|
|
744
785
|
<svelte:window onkeydown={handleKeydown} />
|
|
745
786
|
|
|
746
787
|
<SvelteFlowProvider>
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
788
|
+
<!-- EdgeRefresher component - handles updateNodeInternals calls -->
|
|
789
|
+
<EdgeRefresher
|
|
790
|
+
{nodeIdToRefresh}
|
|
791
|
+
onRefreshComplete={handleEdgeRefreshComplete}
|
|
792
|
+
/>
|
|
793
|
+
|
|
794
|
+
<!-- Port Coordinate Tracker - maintains port positions for proximity connect -->
|
|
795
|
+
<PortCoordinateTracker
|
|
796
|
+
nodeToUpdate={portCoordNodeToUpdate}
|
|
797
|
+
rebuildTrigger={portCoordRebuildTrigger}
|
|
798
|
+
nodes={flowNodes}
|
|
799
|
+
/>
|
|
800
|
+
|
|
801
|
+
<div class="flowdrop-workflow-editor">
|
|
802
|
+
<!-- Main Editor Area -->
|
|
803
|
+
<div class="flowdrop-workflow-editor__main">
|
|
804
|
+
<!-- Flow Canvas -->
|
|
805
|
+
<div class="flowdrop-canvas">
|
|
806
|
+
<FlowDropZone
|
|
807
|
+
ondrop={handleNodeDrop}
|
|
808
|
+
onfiledrop={handleWorkflowFileDrop}
|
|
809
|
+
>
|
|
810
|
+
{#key svelteFlowKey}
|
|
811
|
+
<SvelteFlow
|
|
812
|
+
bind:nodes={flowNodes}
|
|
813
|
+
bind:edges={flowEdges}
|
|
814
|
+
{nodeTypes}
|
|
815
|
+
{edgeTypes}
|
|
816
|
+
{defaultEdgeOptions}
|
|
817
|
+
onconnect={(connection) =>
|
|
818
|
+
void handleConnect({
|
|
819
|
+
source: connection.source,
|
|
820
|
+
target: connection.target,
|
|
821
|
+
sourceHandle: connection.sourceHandle ?? undefined,
|
|
822
|
+
targetHandle: connection.targetHandle ?? undefined,
|
|
823
|
+
})}
|
|
824
|
+
onbeforedelete={handleBeforeDelete}
|
|
825
|
+
ondelete={handleNodesDelete}
|
|
826
|
+
onnodedragstart={handleNodeDragStart}
|
|
827
|
+
onnodedrag={handleNodeDrag}
|
|
828
|
+
onnodedragstop={handleNodeDragStop}
|
|
829
|
+
minZoom={0.2}
|
|
830
|
+
maxZoom={3}
|
|
831
|
+
clickConnect={true}
|
|
832
|
+
elevateEdgesOnSelect={true}
|
|
833
|
+
connectionLineType={ConnectionLineType.Bezier}
|
|
834
|
+
connectionLineComponent={ConnectionLine}
|
|
835
|
+
{snapGrid}
|
|
836
|
+
{initialViewport}
|
|
837
|
+
colorMode={getResolvedTheme() as ColorMode}
|
|
838
|
+
fitView={getEditorSettings().fitViewOnLoad}
|
|
839
|
+
>
|
|
840
|
+
<Controls />
|
|
841
|
+
<!-- Always render Background for consistent bg color in dark/light mode -->
|
|
842
|
+
<Background
|
|
843
|
+
gap={getEditorSettings().gridSize}
|
|
844
|
+
bgColor="var(--fd-background)"
|
|
845
|
+
variant={BackgroundVariant.Dots}
|
|
846
|
+
patternColor={getEditorSettings().showGrid
|
|
847
|
+
? undefined
|
|
848
|
+
: "transparent"}
|
|
849
|
+
/>
|
|
850
|
+
{#if getEditorSettings().showMinimap}
|
|
851
|
+
<MiniMap />
|
|
852
|
+
{/if}
|
|
853
|
+
</SvelteFlow>
|
|
854
|
+
{/key}
|
|
855
|
+
<!-- Drop Zone Indicator -->
|
|
856
|
+
{#if flowNodes.length === 0}
|
|
857
|
+
<CanvasBanner
|
|
858
|
+
title="Drag components here to start building"
|
|
859
|
+
description="Use the sidebar to add components to your workflow"
|
|
860
|
+
iconName="mdi:graph"
|
|
861
|
+
/>
|
|
862
|
+
{/if}
|
|
863
|
+
</FlowDropZone>
|
|
864
|
+
</div>
|
|
865
|
+
|
|
866
|
+
<!-- Status Bar: aria-live announces dynamic changes (node/edge counts, cycle warnings) -->
|
|
867
|
+
<div class="flowdrop-status-bar" aria-live="polite" aria-atomic="true">
|
|
868
|
+
<div class="flowdrop-status-bar__content">
|
|
869
|
+
<div class="flowdrop-flex flowdrop-gap--4">
|
|
870
|
+
<span class="flowdrop-text--xs flowdrop-text--gray"
|
|
871
|
+
>{flowNodes.length} nodes</span
|
|
872
|
+
>
|
|
873
|
+
<span class="flowdrop-text--xs flowdrop-text--gray">•</span>
|
|
874
|
+
<span class="flowdrop-text--xs flowdrop-text--gray"
|
|
875
|
+
>{flowEdges.length} connections</span
|
|
876
|
+
>
|
|
877
|
+
|
|
878
|
+
{#if checkWorkflowCycles()}
|
|
879
|
+
<span class="flowdrop-text--xs flowdrop-text--gray">•</span>
|
|
880
|
+
<span
|
|
881
|
+
class="flowdrop-text--xs flowdrop-font--medium flowdrop-text--error"
|
|
882
|
+
>⚠️ Cycles detected</span
|
|
883
|
+
>
|
|
884
|
+
{/if}
|
|
885
|
+
</div>
|
|
886
|
+
</div>
|
|
887
|
+
</div>
|
|
888
|
+
</div>
|
|
889
|
+
</div>
|
|
837
890
|
</SvelteFlowProvider>
|
|
838
891
|
|
|
839
892
|
<!-- Toast notifications container -->
|
|
840
893
|
<!-- aria-live="polite" ensures screen readers announce toast messages without interrupting -->
|
|
841
894
|
<div aria-live="polite" aria-atomic="true">
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
895
|
+
<Toaster
|
|
896
|
+
position="bottom-center"
|
|
897
|
+
containerClassName={FLOWDROP_TOASTER_CLASS}
|
|
898
|
+
toastOptions={flowdropToastOptions}
|
|
899
|
+
/>
|
|
847
900
|
</div>
|
|
848
901
|
|
|
849
902
|
<style>
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
903
|
+
.flowdrop-workflow-editor {
|
|
904
|
+
display: flex;
|
|
905
|
+
flex-direction: row; /* Side by side layout */
|
|
906
|
+
height: 100%;
|
|
907
|
+
position: relative;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.flowdrop-workflow-editor__main {
|
|
911
|
+
flex: 1;
|
|
912
|
+
display: flex;
|
|
913
|
+
flex-direction: column;
|
|
914
|
+
min-height: 0;
|
|
915
|
+
transition: margin-left 0.3s ease-in-out;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.flowdrop-text--error {
|
|
919
|
+
color: var(--fd-error);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.flowdrop-canvas {
|
|
923
|
+
flex: 1;
|
|
924
|
+
min-height: 0;
|
|
925
|
+
position: relative;
|
|
926
|
+
background: transparent;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.flowdrop-status-bar {
|
|
930
|
+
background-color: var(--fd-backdrop);
|
|
931
|
+
backdrop-filter: var(--fd-backdrop-blur);
|
|
932
|
+
border-top: 1px solid var(--fd-border);
|
|
933
|
+
padding: 0.75rem;
|
|
934
|
+
height: 40px;
|
|
935
|
+
min-height: 40px;
|
|
936
|
+
max-height: 40px;
|
|
937
|
+
display: flex;
|
|
938
|
+
align-items: center;
|
|
939
|
+
flex-shrink: 0;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
.flowdrop-status-bar__content {
|
|
943
|
+
display: flex;
|
|
944
|
+
align-items: center;
|
|
945
|
+
justify-content: space-between;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
:global(.flowdrop-workflow-editor .svelte-flow__node:hover) {
|
|
949
|
+
transform: translateY(-2px);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge) {
|
|
953
|
+
stroke-width: 2 !important;
|
|
954
|
+
cursor: pointer;
|
|
955
|
+
pointer-events: all;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge path) {
|
|
959
|
+
stroke-width: 2 !important;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge:hover) {
|
|
963
|
+
stroke: var(--fd-primary) !important;
|
|
964
|
+
stroke-width: 3 !important;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge:hover path) {
|
|
968
|
+
stroke-width: 3 !important;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge.selected) {
|
|
972
|
+
stroke: var(--fd-primary) !important;
|
|
973
|
+
stroke-width: 3 !important;
|
|
974
|
+
filter: drop-shadow(
|
|
975
|
+
0 0 4px color-mix(in srgb, var(--fd-primary) 50%, transparent)
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge.selected path) {
|
|
980
|
+
stroke-width: 3 !important;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/* Ensure edge paths are clickable */
|
|
984
|
+
:global(.flowdrop-workflow-editor .svelte-flow__edge path) {
|
|
985
|
+
pointer-events: all;
|
|
986
|
+
cursor: pointer;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/* Handle size/position only; colors come from inline --fd-handle-fill and base.css ::before */
|
|
990
|
+
:global(.flowdrop-workflow-editor .svelte-flow__handle) {
|
|
991
|
+
width: var(--fd-handle-size);
|
|
992
|
+
height: var(--fd-handle-size);
|
|
993
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
994
|
+
z-index: 20;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/* Ensure our custom handles are clickable */
|
|
998
|
+
:global(.flowdrop-workflow-editor .svelte-flow__handle) {
|
|
999
|
+
pointer-events: all;
|
|
1000
|
+
cursor: crosshair;
|
|
1001
|
+
background-color: var(--fd-handle-fill);
|
|
1002
|
+
border-color: var(--fd-handle-border-color);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
951
1006
|
* Edge Styling Based on Source Port Data Type
|
|
952
1007
|
* Uses CSS tokens from base.css for consistent theming
|
|
953
1008
|
* - Trigger edges: solid dark line (control flow)
|
|
@@ -955,88 +1010,88 @@
|
|
|
955
1010
|
* - Data edges: normal gray line (data flow)
|
|
956
1011
|
*/
|
|
957
1012
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1013
|
+
/* Trigger Edge: Solid dark line for control flow */
|
|
1014
|
+
:global(.flowdrop--edge--trigger path.svelte-flow__edge-path) {
|
|
1015
|
+
stroke: var(--fd-edge-trigger);
|
|
1016
|
+
stroke-width: var(--fd-edge-trigger-width);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
:global(.flowdrop--edge--trigger:hover path.svelte-flow__edge-path) {
|
|
1020
|
+
stroke: var(--fd-edge-trigger-hover);
|
|
1021
|
+
stroke-width: var(--fd-edge-trigger-width-hover);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
:global(.flowdrop--edge--trigger.selected path.svelte-flow__edge-path) {
|
|
1025
|
+
stroke: var(--fd-edge-trigger-selected);
|
|
1026
|
+
stroke-width: var(--fd-edge-trigger-width-hover);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/* Tool Edge: Dashed amber line for tool connections */
|
|
1030
|
+
:global(.flowdrop--edge--tool path.svelte-flow__edge-path) {
|
|
1031
|
+
stroke: var(--fd-edge-tool);
|
|
1032
|
+
stroke-dasharray: 5 3;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
:global(.flowdrop--edge--tool:hover path.svelte-flow__edge-path) {
|
|
1036
|
+
stroke: var(--fd-edge-tool-hover);
|
|
1037
|
+
stroke-width: 2;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
:global(.flowdrop--edge--tool.selected path.svelte-flow__edge-path) {
|
|
1041
|
+
stroke: var(--fd-edge-tool-selected);
|
|
1042
|
+
stroke-dasharray: 5 3;
|
|
1043
|
+
stroke-width: 2;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/* Data Edge: Normal gray line for data flow (default) */
|
|
1047
|
+
:global(.flowdrop--edge--data path.svelte-flow__edge-path) {
|
|
1048
|
+
stroke: var(--fd-edge-data);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
:global(.flowdrop--edge--data:hover path.svelte-flow__edge-path) {
|
|
1052
|
+
stroke: var(--fd-edge-data-hover);
|
|
1053
|
+
stroke-width: 2;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
:global(.flowdrop--edge--data.selected path.svelte-flow__edge-path) {
|
|
1057
|
+
stroke: var(--fd-edge-data-selected);
|
|
1058
|
+
stroke-width: 2;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/* Loopback Edge: Dashed gray line for loop iteration connections */
|
|
1062
|
+
:global(.flowdrop--edge--loopback path.svelte-flow__edge-path) {
|
|
1063
|
+
stroke: var(--fd-edge-loopback);
|
|
1064
|
+
stroke-width: var(--fd-edge-loopback-width);
|
|
1065
|
+
stroke-dasharray: var(--fd-edge-loopback-dasharray);
|
|
1066
|
+
opacity: var(--fd-edge-loopback-opacity);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
:global(.flowdrop--edge--loopback:hover path.svelte-flow__edge-path) {
|
|
1070
|
+
stroke: var(--fd-edge-loopback-hover);
|
|
1071
|
+
stroke-width: var(--fd-edge-loopback-width-hover);
|
|
1072
|
+
opacity: 1;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
:global(.flowdrop--edge--loopback.selected path.svelte-flow__edge-path) {
|
|
1076
|
+
stroke: var(--fd-edge-loopback-selected);
|
|
1077
|
+
stroke-width: var(--fd-edge-loopback-width-hover);
|
|
1078
|
+
stroke-dasharray: var(--fd-edge-loopback-dasharray);
|
|
1079
|
+
filter: drop-shadow(0 0 3px rgba(139, 92, 246, 0.4));
|
|
1080
|
+
opacity: 1;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/* Proximity Connect Preview Edge: animated dashed line */
|
|
1084
|
+
:global(.flowdrop--edge--proximity-preview path.svelte-flow__edge-path) {
|
|
1085
|
+
stroke: var(--fd-primary);
|
|
1086
|
+
stroke-width: 2;
|
|
1087
|
+
stroke-dasharray: 5 5;
|
|
1088
|
+
opacity: 0.6;
|
|
1089
|
+
animation: flowdrop-proximity-dash 0.5s linear infinite;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
@keyframes flowdrop-proximity-dash {
|
|
1093
|
+
to {
|
|
1094
|
+
stroke-dashoffset: -10;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1042
1097
|
</style>
|