@flowdrop/flowdrop 1.4.0 → 1.6.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 +94 -51
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +27 -47
- package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
- package/dist/adapters/agentspec/AgentSpecAdapter.js +122 -133
- package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
- package/dist/adapters/agentspec/agentAdapter.js +10 -10
- package/dist/adapters/agentspec/autoLayout.d.ts +52 -6
- package/dist/adapters/agentspec/autoLayout.js +118 -23
- 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 +20 -22
- package/dist/api/enhanced-client.d.ts +3 -3
- package/dist/api/enhanced-client.js +72 -73
- package/dist/chat/commandClassifier.d.ts +19 -0
- package/dist/chat/commandClassifier.js +30 -0
- package/dist/chat/index.d.ts +27 -0
- package/dist/chat/index.js +32 -0
- package/dist/chat/responseParser.d.ts +21 -0
- package/dist/chat/responseParser.js +91 -0
- package/dist/commands/batch.d.ts +18 -0
- package/dist/commands/batch.js +54 -0
- package/dist/commands/executor.d.ts +37 -0
- package/dist/commands/executor.js +1133 -0
- package/dist/commands/index.d.ts +14 -0
- package/dist/commands/index.js +17 -0
- package/dist/commands/parser.d.ts +16 -0
- package/dist/commands/parser.js +295 -0
- package/dist/commands/positioner.d.ts +19 -0
- package/dist/commands/positioner.js +33 -0
- package/dist/commands/storeIntegration.svelte.d.ts +16 -0
- package/dist/commands/storeIntegration.svelte.js +67 -0
- package/dist/commands/types.d.ts +343 -0
- package/dist/commands/types.js +45 -0
- package/dist/components/App.svelte +522 -237
- package/dist/components/App.svelte.d.ts +11 -8
- package/dist/components/CanvasBanner.stories.svelte +10 -16
- package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
- package/dist/components/CanvasBanner.svelte +2 -2
- package/dist/components/CanvasBanner.svelte.d.ts +1 -1
- package/dist/components/CanvasController.svelte +37 -0
- package/dist/components/CanvasController.svelte.d.ts +32 -0
- package/dist/components/ConfigForm.svelte +118 -256
- package/dist/components/ConfigForm.svelte.d.ts +2 -2
- package/dist/components/ConfigMappingRow.svelte +128 -0
- package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
- package/dist/components/ConfigModal.svelte +3 -3
- package/dist/components/ConfigModal.svelte.d.ts +1 -1
- package/dist/components/ConfigPanel.stories.svelte +19 -19
- package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
- package/dist/components/ConfigPanel.svelte +57 -19
- package/dist/components/ConfigPanel.svelte.d.ts +3 -1
- package/dist/components/ConnectionLine.svelte +4 -4
- package/dist/components/EdgeRefresher.svelte +1 -1
- package/dist/components/FlowDropEdge.stories.svelte +110 -110
- package/dist/components/FlowDropEdge.svelte +11 -19
- package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
- package/dist/components/FlowDropZone.svelte +6 -9
- package/dist/components/FlowDropZone.svelte.d.ts +1 -1
- package/dist/components/LoadingSpinner.stories.svelte +13 -13
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
- package/dist/components/LoadingSpinner.svelte +3 -3
- package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
- package/dist/components/Logo.stories.svelte +4 -4
- package/dist/components/Logo.stories.svelte.d.ts +1 -1
- package/dist/components/Logo.svelte +3 -9
- package/dist/components/LogsSidebar.svelte +46 -53
- package/dist/components/LogsSidebar.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.stories.svelte +10 -14
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.svelte +4 -6
- package/dist/components/Navbar.stories.svelte +19 -19
- package/dist/components/Navbar.stories.svelte.d.ts +1 -1
- package/dist/components/Navbar.svelte +28 -49
- package/dist/components/Navbar.svelte.d.ts +2 -2
- package/dist/components/NodeSidebar.svelte +55 -135
- package/dist/components/NodeSidebar.svelte.d.ts +1 -1
- package/dist/components/NodeStatusOverlay.stories.svelte +19 -31
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
- package/dist/components/NodeStatusOverlay.svelte +40 -55
- package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
- package/dist/components/NodeSwapPicker.svelte +493 -0
- package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
- package/dist/components/PipelineStatus.svelte +63 -89
- package/dist/components/PipelineStatus.svelte.d.ts +4 -4
- package/dist/components/PortCoordinateTracker.svelte +5 -7
- package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
- package/dist/components/PortMappingRow.svelte +205 -0
- package/dist/components/PortMappingRow.svelte.d.ts +12 -0
- package/dist/components/ReadOnlyDetails.svelte +1 -1
- package/dist/components/SchemaForm.stories.svelte +53 -53
- package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
- package/dist/components/SchemaForm.svelte +24 -51
- package/dist/components/SchemaForm.svelte.d.ts +2 -2
- package/dist/components/SettingsModal.svelte +6 -9
- package/dist/components/SettingsModal.svelte.d.ts +1 -1
- package/dist/components/SettingsPanel.svelte +138 -158
- package/dist/components/SettingsPanel.svelte.d.ts +1 -1
- package/dist/components/StatusIcon.stories.svelte +16 -29
- package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
- package/dist/components/StatusIcon.svelte +19 -19
- package/dist/components/StatusIcon.svelte.d.ts +2 -2
- package/dist/components/StatusLabel.stories.svelte +8 -8
- package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
- package/dist/components/SwapMappingEditor.svelte +529 -0
- package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
- package/dist/components/ThemeToggle.stories.svelte +10 -10
- package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
- package/dist/components/ThemeToggle.svelte +22 -33
- package/dist/components/ThemeToggle.svelte.d.ts +1 -1
- package/dist/components/UniversalNode.svelte +29 -41
- package/dist/components/UniversalNode.svelte.d.ts +3 -3
- package/dist/components/WorkflowEditor.svelte +210 -170
- package/dist/components/WorkflowEditor.svelte.d.ts +12 -4
- package/dist/components/chat/AIChatPanel.svelte +797 -0
- package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
- package/dist/components/chat/CommandPreview.svelte +234 -0
- package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
- package/dist/components/console/CommandConsole.stories.svelte +111 -0
- package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
- package/dist/components/console/CommandConsole.svelte +263 -0
- package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
- package/dist/components/console/ConsoleAutocomplete.svelte +142 -0
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
- package/dist/components/console/ConsoleInput.svelte +771 -0
- package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
- package/dist/components/console/ConsoleOutput.svelte +116 -0
- package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
- package/dist/components/console/formatters.d.ts +26 -0
- package/dist/components/console/formatters.js +116 -0
- package/dist/components/form/FormArray.svelte +75 -132
- package/dist/components/form/FormArray.svelte.d.ts +1 -1
- package/dist/components/form/FormAutocomplete.svelte +65 -108
- package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
- package/dist/components/form/FormCheckboxGroup.stories.svelte +13 -16
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormCheckboxGroup.svelte +2 -2
- package/dist/components/form/FormCodeEditor.svelte +42 -56
- package/dist/components/form/FormField.svelte +79 -90
- package/dist/components/form/FormField.svelte.d.ts +2 -2
- package/dist/components/form/FormFieldLight.svelte +72 -88
- package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.stories.svelte +14 -14
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.svelte +2 -9
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldset.svelte +3 -3
- package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
- package/dist/components/form/FormMarkdownEditor.svelte +123 -156
- package/dist/components/form/FormNumberField.stories.svelte +18 -18
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormNumberField.svelte +6 -6
- package/dist/components/form/FormRangeField.stories.svelte +13 -13
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormRangeField.svelte +4 -12
- package/dist/components/form/FormSelect.stories.svelte +21 -21
- package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormSelect.svelte +5 -5
- package/dist/components/form/FormSelect.svelte.d.ts +1 -1
- package/dist/components/form/FormTemplateEditor.svelte +126 -175
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
- package/dist/components/form/FormTextField.stories.svelte +17 -23
- package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormTextField.svelte +4 -4
- package/dist/components/form/FormTextarea.stories.svelte +18 -21
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormTextarea.svelte +4 -4
- package/dist/components/form/FormToggle.stories.svelte +13 -16
- package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormToggle.svelte +3 -3
- package/dist/components/form/FormUISchemaRenderer.svelte +12 -19
- 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 +55 -64
- package/dist/components/form/types.d.ts +6 -6
- package/dist/components/form/types.js +4 -9
- package/dist/components/icons/AlertCircleIcon.svelte +1 -6
- package/dist/components/icons/CogIcon.svelte +1 -6
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +27 -27
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ChoicePrompt.svelte +17 -41
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +17 -17
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ConfirmationPrompt.svelte +10 -16
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/FormPrompt.svelte +10 -15
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/InterruptBubble.svelte +87 -121
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +37 -37
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ReviewPrompt.svelte +55 -75
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +16 -17
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/TextInputPrompt.svelte +13 -18
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/index.d.ts +6 -5
- package/dist/components/interrupt/index.js +6 -5
- package/dist/components/layouts/MainLayout.svelte +46 -84
- package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
- package/dist/components/nodes/GatewayNode.stories.svelte +64 -65
- package/dist/components/nodes/GatewayNode.svelte +37 -70
- package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
- package/dist/components/nodes/IdeaNode.stories.svelte +25 -26
- package/dist/components/nodes/IdeaNode.svelte +22 -36
- package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
- package/dist/components/nodes/NotesNode.stories.svelte +37 -38
- package/dist/components/nodes/NotesNode.svelte +28 -39
- package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SimpleNode.stories.svelte +137 -138
- package/dist/components/nodes/SimpleNode.svelte +44 -74
- package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SquareNode.stories.svelte +75 -75
- package/dist/components/nodes/SquareNode.svelte +42 -68
- package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
- package/dist/components/nodes/TerminalNode.stories.svelte +10 -10
- package/dist/components/nodes/TerminalNode.svelte +74 -112
- package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
- package/dist/components/nodes/ToolNode.stories.svelte +115 -116
- package/dist/components/nodes/ToolNode.svelte +31 -64
- package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
- package/dist/components/nodes/WorkflowNode.stories.svelte +84 -89
- package/dist/components/nodes/WorkflowNode.svelte +50 -103
- package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
- package/dist/components/playground/ChatPanel.svelte +47 -103
- package/dist/components/playground/ExecutionLogs.svelte +45 -68
- package/dist/components/playground/InputCollector.svelte +32 -51
- package/dist/components/playground/MessageBubble.stories.svelte +25 -25
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
- package/dist/components/playground/MessageBubble.svelte +54 -70
- package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
- package/dist/components/playground/Playground.svelte +60 -91
- package/dist/components/playground/Playground.svelte.d.ts +3 -3
- package/dist/components/playground/PlaygroundModal.svelte +8 -12
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
- package/dist/components/playground/SessionManager.svelte +34 -40
- 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 +12 -4
- package/dist/config/endpoints.js +70 -65
- package/dist/config/runtimeConfig.d.ts +2 -2
- package/dist/config/runtimeConfig.js +8 -8
- package/dist/core/index.d.ts +68 -63
- package/dist/core/index.js +44 -35
- package/dist/display/index.d.ts +2 -2
- package/dist/display/index.js +2 -2
- package/dist/editor/index.d.ts +64 -62
- package/dist/editor/index.js +57 -55
- 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 +9 -11
- 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 +40 -35
- package/dist/helpers/workflowEditorHelper.d.ts +8 -58
- package/dist/helpers/workflowEditorHelper.js +73 -292
- 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 +1 -1
- package/dist/mocks/app-navigation.js +2 -2
- package/dist/mocks/app-stores.js +3 -3
- 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 +9 -11
- 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/schemas/v1/workflow.schema.json +107 -22
- package/dist/services/agentSpecExecutionService.d.ts +3 -3
- package/dist/services/agentSpecExecutionService.js +55 -56
- 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 +34 -41
- 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/chatService.d.ts +65 -0
- package/dist/services/chatService.js +131 -0
- 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 +39 -41
- package/dist/services/globalSave.d.ts +2 -2
- package/dist/services/globalSave.js +38 -41
- package/dist/services/historyService.d.ts +7 -5
- package/dist/services/historyService.js +29 -14
- package/dist/services/interruptService.d.ts +1 -1
- package/dist/services/interruptService.js +29 -35
- package/dist/services/nodeExecutionService.d.ts +1 -1
- package/dist/services/nodeExecutionService.js +44 -45
- 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 +19 -25
- 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 +1 -1
- package/dist/skins/default.js +1 -1
- package/dist/skins/index.d.ts +3 -3
- package/dist/skins/index.js +7 -7
- package/dist/skins/slate.d.ts +1 -1
- package/dist/skins/slate.js +69 -69
- 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 +34 -34
- 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 +27 -22
- package/dist/stores/playgroundStore.svelte.d.ts +3 -3
- package/dist/stores/playgroundStore.svelte.js +29 -23
- package/dist/stores/portCoordinateStore.svelte.d.ts +6 -2
- package/dist/stores/portCoordinateStore.svelte.js +30 -39
- package/dist/stores/settingsStore.svelte.d.ts +2 -2
- package/dist/stores/settingsStore.svelte.js +57 -62
- package/dist/stores/workflowStore.svelte.d.ts +34 -5
- package/dist/stores/workflowStore.svelte.js +127 -108
- package/dist/stories/CanvasDecorator.svelte +7 -10
- package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
- package/dist/stories/EdgeDecorator.svelte +28 -31
- package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
- package/dist/stories/NodeDecorator.svelte +14 -20
- package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
- package/dist/stories/utils.d.ts +2 -2
- package/dist/stories/utils.js +89 -93
- package/dist/styles/base.css +16 -50
- package/dist/styles/tokens.css +10 -28
- package/dist/svelte-app.d.ts +10 -10
- package/dist/svelte-app.js +39 -39
- package/dist/themes/default.d.ts +1 -1
- package/dist/themes/default.js +4 -4
- package/dist/themes/index.d.ts +3 -3
- package/dist/themes/index.js +11 -11
- package/dist/themes/minimal.d.ts +1 -1
- package/dist/themes/minimal.js +5 -5
- 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/chat.d.ts +63 -0
- package/dist/types/chat.js +9 -0
- package/dist/types/config.d.ts +6 -6
- package/dist/types/events.d.ts +28 -2
- package/dist/types/events.js +2 -1
- package/dist/types/index.d.ts +40 -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 +12 -4
- package/dist/types/settings.js +21 -23
- package/dist/types/skin.d.ts +1 -1
- package/dist/types/theme.d.ts +2 -2
- 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 +95 -97
- 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/edgeStyling.d.ts +42 -0
- package/dist/utils/edgeStyling.js +173 -0
- 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/nodeIds.d.ts +31 -0
- package/dist/utils/nodeIds.js +42 -0
- package/dist/utils/nodeStatus.d.ts +1 -1
- package/dist/utils/nodeStatus.js +48 -48
- package/dist/utils/nodeSwap.d.ts +221 -0
- package/dist/utils/nodeSwap.js +680 -0
- package/dist/utils/nodeTypes.d.ts +1 -1
- package/dist/utils/nodeTypes.js +20 -21
- package/dist/utils/nodeWrapper.d.ts +7 -7
- package/dist/utils/nodeWrapper.js +19 -21
- package/dist/utils/performanceUtils.d.ts +1 -1
- package/dist/utils/performanceUtils.js +1 -2
- package/dist/utils/portUtils.d.ts +2 -2
- package/dist/utils/portUtils.js +1 -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 +8 -8
- package/package.json +12 -11
- package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
- package/dist/helpers/nodeLayoutHelper.js +0 -19
|
@@ -5,58 +5,65 @@
|
|
|
5
5
|
-->
|
|
6
6
|
|
|
7
7
|
<script lang="ts">
|
|
8
|
-
import { onMount } from
|
|
9
|
-
import MainLayout from
|
|
10
|
-
import WorkflowEditor from
|
|
11
|
-
import NodeSidebar from
|
|
12
|
-
import Icon from
|
|
13
|
-
import ConfigForm from
|
|
14
|
-
import ConfigPanel from
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
8
|
+
import { onMount, tick } from 'svelte';
|
|
9
|
+
import MainLayout from './layouts/MainLayout.svelte';
|
|
10
|
+
import WorkflowEditor from './WorkflowEditor.svelte';
|
|
11
|
+
import NodeSidebar from './NodeSidebar.svelte';
|
|
12
|
+
import Icon from '@iconify/svelte';
|
|
13
|
+
import ConfigForm from './ConfigForm.svelte';
|
|
14
|
+
import ConfigPanel from './ConfigPanel.svelte';
|
|
15
|
+
import CommandConsole from './console/CommandConsole.svelte';
|
|
16
|
+
import AIChatPanel from './chat/AIChatPanel.svelte';
|
|
17
|
+
import type { UIAction } from '../commands/index.js';
|
|
18
|
+
import NodeSwapPicker from './NodeSwapPicker.svelte';
|
|
19
|
+
import SwapMappingEditor from './SwapMappingEditor.svelte';
|
|
20
|
+
import Navbar from './Navbar.svelte';
|
|
21
|
+
import { api, setEndpointConfig } from '../services/api.js';
|
|
22
|
+
import { EnhancedFlowDropApiClient } from '../api/enhanced-client.js';
|
|
18
23
|
import type {
|
|
19
24
|
NodeMetadata,
|
|
20
25
|
Workflow,
|
|
21
26
|
WorkflowNode,
|
|
22
27
|
ConfigSchema,
|
|
23
|
-
NodeUIExtensions
|
|
24
|
-
} from
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from
|
|
33
|
-
import {
|
|
34
|
-
import
|
|
35
|
-
import type {
|
|
36
|
-
import {
|
|
28
|
+
NodeUIExtensions
|
|
29
|
+
} from '../types/index.js';
|
|
30
|
+
import type { InteractiveSwapState, SwapEventContext } from '../utils/nodeSwap.js';
|
|
31
|
+
import {
|
|
32
|
+
computeInteractiveState,
|
|
33
|
+
buildSwapPreviewFromState,
|
|
34
|
+
executeSwap,
|
|
35
|
+
validateSwapResult
|
|
36
|
+
} from '../utils/nodeSwap.js';
|
|
37
|
+
import type { SwapStrategy } from '../utils/nodeSwap.js';
|
|
38
|
+
import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
|
|
39
|
+
import { createEndpointConfig } from '../config/endpoints.js';
|
|
40
|
+
import type { EndpointConfig } from '../config/endpoints.js';
|
|
41
|
+
import type { AuthProvider } from '../types/auth.js';
|
|
42
|
+
import type { FlowDropEventHandlers, FlowDropFeatures } from '../types/events.js';
|
|
43
|
+
import { mergeFeatures } from '../types/events.js';
|
|
44
|
+
import type { FlowDropTheme, FlowDropThemeName } from '../types/theme.js';
|
|
45
|
+
import type { FlowDropSkinTokens } from '../types/skin.js';
|
|
46
|
+
import { resolveTheme } from '../themes/index.js';
|
|
37
47
|
import {
|
|
38
48
|
getWorkflowStore,
|
|
39
49
|
workflowActions,
|
|
40
50
|
getWorkflowName,
|
|
41
51
|
getWorkflowFormat,
|
|
42
|
-
markAsSaved
|
|
43
|
-
} from
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} from
|
|
48
|
-
import { apiToasts, dismissToast } from "../services/toastService.js";
|
|
49
|
-
import { initAutoSave } from "../services/autoSaveService.js";
|
|
52
|
+
markAsSaved
|
|
53
|
+
} from '../stores/workflowStore.svelte.js';
|
|
54
|
+
import { globalSaveWorkflow, globalExportWorkflow } from '../services/globalSave.js';
|
|
55
|
+
import { apiToasts, dismissToast } from '../services/toastService.js';
|
|
56
|
+
import { initAutoSave } from '../services/autoSaveService.js';
|
|
57
|
+
import { getUiSettings, updateSettings } from '../stores/settingsStore.svelte.js';
|
|
50
58
|
import {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} from
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
58
|
-
import {
|
|
59
|
-
import type { SettingsCategory } from "../types/settings.js";
|
|
59
|
+
initializePortCompatibility,
|
|
60
|
+
getPortCompatibilityChecker
|
|
61
|
+
} from '../utils/connections.js';
|
|
62
|
+
import { DEFAULT_PORT_CONFIG } from '../config/defaultPortConfig.js';
|
|
63
|
+
import { workflowFormatRegistry } from '../registry/workflowFormatRegistry.js';
|
|
64
|
+
import { logger } from '../utils/logger.js';
|
|
65
|
+
import { validateWorkflowData } from '../utils/validation.js';
|
|
66
|
+
import type { SettingsCategory } from '../types/settings.js';
|
|
60
67
|
|
|
61
68
|
/**
|
|
62
69
|
* Configuration props for runtime customization
|
|
@@ -79,10 +86,7 @@
|
|
|
79
86
|
/** Read-only mode */
|
|
80
87
|
readOnly?: boolean;
|
|
81
88
|
/** Node execution statuses */
|
|
82
|
-
nodeStatuses?: Record<
|
|
83
|
-
string,
|
|
84
|
-
"pending" | "running" | "completed" | "error"
|
|
85
|
-
>;
|
|
89
|
+
nodeStatuses?: Record<string, 'pending' | 'running' | 'completed' | 'error'>;
|
|
86
90
|
/** Pipeline ID for fetching node execution info */
|
|
87
91
|
pipelineId?: string;
|
|
88
92
|
/** Custom navbar title */
|
|
@@ -92,7 +96,7 @@
|
|
|
92
96
|
label: string;
|
|
93
97
|
href: string;
|
|
94
98
|
icon?: string;
|
|
95
|
-
variant?:
|
|
99
|
+
variant?: 'primary' | 'secondary' | 'outline';
|
|
96
100
|
onclick?: (event: Event) => void;
|
|
97
101
|
}>;
|
|
98
102
|
/** Show settings gear icon in navbar */
|
|
@@ -115,13 +119,15 @@
|
|
|
115
119
|
showSettingsSyncButton?: boolean;
|
|
116
120
|
/** Show the reset buttons in the settings modal */
|
|
117
121
|
showSettingsResetButton?: boolean;
|
|
122
|
+
/** Pluggable swap strategies — instance-scoped, checked in order */
|
|
123
|
+
swapStrategies?: SwapStrategy[];
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
let {
|
|
121
127
|
workflow: initialWorkflow,
|
|
122
128
|
nodes: propNodes,
|
|
123
|
-
height =
|
|
124
|
-
width =
|
|
129
|
+
height = '100vh',
|
|
130
|
+
width = '100%',
|
|
125
131
|
showNavbar = false,
|
|
126
132
|
disableSidebar = false,
|
|
127
133
|
lockWorkflow = false,
|
|
@@ -140,6 +146,7 @@
|
|
|
140
146
|
settingsCategories,
|
|
141
147
|
showSettingsSyncButton,
|
|
142
148
|
showSettingsResetButton,
|
|
149
|
+
swapStrategies
|
|
143
150
|
}: Props = $props();
|
|
144
151
|
|
|
145
152
|
// svelte-ignore state_referenced_locally — feature flags don't change at runtime
|
|
@@ -147,9 +154,7 @@
|
|
|
147
154
|
|
|
148
155
|
// Theme system — resolve named theme or custom object, inject CSS tokens from skin
|
|
149
156
|
// Explicit prop wins; falls back to user's persisted theme preference from settings
|
|
150
|
-
let resolvedTheme = $derived(
|
|
151
|
-
resolveTheme(themeProp ?? getUiSettings().theme),
|
|
152
|
-
);
|
|
157
|
+
let resolvedTheme = $derived(resolveTheme(themeProp ?? getUiSettings().theme));
|
|
153
158
|
let themeConfig = $derived(resolvedTheme.config);
|
|
154
159
|
|
|
155
160
|
// Inject skin tokens as a style tag so light/dark palettes can coexist.
|
|
@@ -160,19 +165,19 @@
|
|
|
160
165
|
const skin = resolvedTheme.skin;
|
|
161
166
|
const tokens = skin?.tokens;
|
|
162
167
|
const darkTokens = skin?.darkTokens;
|
|
163
|
-
if ((!tokens && !darkTokens) || typeof document ===
|
|
168
|
+
if ((!tokens && !darkTokens) || typeof document === 'undefined') return;
|
|
164
169
|
|
|
165
170
|
const toRules = (dict: FlowDropSkinTokens) =>
|
|
166
171
|
Object.entries(dict)
|
|
167
172
|
.map(([k, v]) => ` --fd-${k}: ${v};`)
|
|
168
|
-
.join(
|
|
173
|
+
.join('\n');
|
|
169
174
|
|
|
170
|
-
let css =
|
|
175
|
+
let css = '';
|
|
171
176
|
if (tokens) css += `:root {\n${toRules(tokens)}\n}\n`;
|
|
172
177
|
if (darkTokens) css += `[data-theme='dark'] {\n${toRules(darkTokens)}\n}\n`;
|
|
173
178
|
|
|
174
|
-
const style = document.createElement(
|
|
175
|
-
style.id =
|
|
179
|
+
const style = document.createElement('style');
|
|
180
|
+
style.id = 'fd-skin-tokens';
|
|
176
181
|
document.head.appendChild(style);
|
|
177
182
|
style.textContent = css;
|
|
178
183
|
|
|
@@ -180,15 +185,15 @@
|
|
|
180
185
|
});
|
|
181
186
|
|
|
182
187
|
// Create breadcrumb-style title - at top level to avoid store subscription issues
|
|
183
|
-
let breadcrumbTitle = $derived(() => {
|
|
188
|
+
let breadcrumbTitle = $derived.by(() => {
|
|
184
189
|
// Use custom navbar title if provided
|
|
185
190
|
if (navbarTitle) {
|
|
186
191
|
return navbarTitle;
|
|
187
192
|
}
|
|
188
193
|
// Default workflow title logic
|
|
189
194
|
const wfName = getWorkflowName();
|
|
190
|
-
if (!wfName || wfName ===
|
|
191
|
-
return
|
|
195
|
+
if (!wfName || wfName === 'Untitled Workflow') {
|
|
196
|
+
return 'Workflow / New Workflow';
|
|
192
197
|
}
|
|
193
198
|
return `Workflow / ${wfName}`;
|
|
194
199
|
});
|
|
@@ -213,43 +218,48 @@
|
|
|
213
218
|
// Workflow settings sidebar state
|
|
214
219
|
let isWorkflowSettingsOpen = $state(false);
|
|
215
220
|
|
|
221
|
+
// Node swap state
|
|
222
|
+
let swapMode = $state<'idle' | 'picking' | 'mapping'>('idle');
|
|
223
|
+
let swapTargetMetadata = $state<NodeMetadata | null>(null);
|
|
224
|
+
let swapInteractiveState = $state<InteractiveSwapState | null>(null);
|
|
225
|
+
|
|
216
226
|
// Workflow configuration schema (derived to pick up dynamic format options)
|
|
217
227
|
let workflowConfigSchema: ConfigSchema = $derived({
|
|
218
|
-
type:
|
|
228
|
+
type: 'object' as const,
|
|
219
229
|
properties: {
|
|
220
230
|
name: {
|
|
221
|
-
type:
|
|
222
|
-
title:
|
|
223
|
-
description:
|
|
224
|
-
default:
|
|
231
|
+
type: 'string',
|
|
232
|
+
title: 'Workflow Name',
|
|
233
|
+
description: 'The name of the workflow',
|
|
234
|
+
default: ''
|
|
225
235
|
},
|
|
226
236
|
description: {
|
|
227
|
-
type:
|
|
228
|
-
title:
|
|
229
|
-
description:
|
|
230
|
-
format:
|
|
231
|
-
default:
|
|
237
|
+
type: 'string',
|
|
238
|
+
title: 'Description',
|
|
239
|
+
description: 'A description of the workflow',
|
|
240
|
+
format: 'multiline',
|
|
241
|
+
default: ''
|
|
232
242
|
},
|
|
233
243
|
format: {
|
|
234
|
-
type:
|
|
235
|
-
title:
|
|
236
|
-
description:
|
|
244
|
+
type: 'string',
|
|
245
|
+
title: 'Workflow Format',
|
|
246
|
+
description: 'The specification format for this workflow',
|
|
237
247
|
oneOf: workflowFormatRegistry.getOneOfOptions(),
|
|
238
|
-
default:
|
|
239
|
-
}
|
|
248
|
+
default: 'flowdrop'
|
|
249
|
+
}
|
|
240
250
|
},
|
|
241
|
-
required: [
|
|
251
|
+
required: ['name']
|
|
242
252
|
});
|
|
243
253
|
|
|
244
254
|
// Workflow configuration values
|
|
245
255
|
let workflowConfigValues = $derived({
|
|
246
|
-
name: getWorkflowName() ||
|
|
247
|
-
description: getWorkflowStore()?.description ||
|
|
248
|
-
format: getWorkflowStore()?.metadata?.format ||
|
|
256
|
+
name: getWorkflowName() || '',
|
|
257
|
+
description: getWorkflowStore()?.description || '',
|
|
258
|
+
format: getWorkflowStore()?.metadata?.format || 'flowdrop'
|
|
249
259
|
});
|
|
250
260
|
|
|
251
261
|
// Get the current node from the workflow store
|
|
252
|
-
let selectedNodeForConfig = $derived(() => {
|
|
262
|
+
let selectedNodeForConfig = $derived.by(() => {
|
|
253
263
|
const wf = getWorkflowStore();
|
|
254
264
|
if (!selectedNodeId || !wf) return null;
|
|
255
265
|
return wf.nodes.find((node) => node.id === selectedNodeId) || null;
|
|
@@ -270,18 +280,14 @@
|
|
|
270
280
|
// Merge format-provided nodes with prop nodes (deduplicate by ID, props take priority)
|
|
271
281
|
const formatNodes = workflowFormatRegistry.getAllFormatNodes();
|
|
272
282
|
const existingIds = new Set(propNodes.map((n) => n.id));
|
|
273
|
-
const uniqueFormatNodes = formatNodes.filter(
|
|
274
|
-
(n) => !existingIds.has(n.id),
|
|
275
|
-
);
|
|
283
|
+
const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
|
|
276
284
|
nodes = [...propNodes, ...uniqueFormatNodes];
|
|
277
285
|
nodeTypesLoading = false;
|
|
278
286
|
return;
|
|
279
287
|
}
|
|
280
288
|
|
|
281
289
|
// Show loading toast (if toasts are enabled)
|
|
282
|
-
const loadingToast = features.showToasts
|
|
283
|
-
? apiToasts.loading("Loading node types")
|
|
284
|
-
: null;
|
|
290
|
+
const loadingToast = features.showToasts ? apiToasts.loading('Loading node types') : null;
|
|
285
291
|
try {
|
|
286
292
|
error = null;
|
|
287
293
|
|
|
@@ -296,9 +302,7 @@
|
|
|
296
302
|
// Merge format-provided nodes with API nodes (deduplicate by ID, API takes priority)
|
|
297
303
|
const formatNodes = workflowFormatRegistry.getAllFormatNodes();
|
|
298
304
|
const existingIds = new Set(fetchedNodes.map((n) => n.id));
|
|
299
|
-
const uniqueFormatNodes = formatNodes.filter(
|
|
300
|
-
(n) => !existingIds.has(n.id),
|
|
301
|
-
);
|
|
305
|
+
const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
|
|
302
306
|
nodes = [...fetchedNodes, ...uniqueFormatNodes];
|
|
303
307
|
error = null;
|
|
304
308
|
nodeTypesLoading = false;
|
|
@@ -313,13 +317,13 @@
|
|
|
313
317
|
dismissToast(loadingToast);
|
|
314
318
|
}
|
|
315
319
|
|
|
316
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
320
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
317
321
|
|
|
318
322
|
// Notify parent via event handler
|
|
319
323
|
if (eventHandlers?.onApiError) {
|
|
320
324
|
const suppressToast = eventHandlers.onApiError(
|
|
321
325
|
err instanceof Error ? err : new Error(errorMessage),
|
|
322
|
-
|
|
326
|
+
'fetchNodes'
|
|
323
327
|
);
|
|
324
328
|
if (suppressToast) {
|
|
325
329
|
// Parent handled the error, keep nodes empty
|
|
@@ -332,7 +336,7 @@
|
|
|
332
336
|
// Show error and set empty nodes array (no fallback to sample data)
|
|
333
337
|
error = `API Error: ${errorMessage}. No node types available.`;
|
|
334
338
|
if (features.showToasts) {
|
|
335
|
-
apiToasts.error(
|
|
339
|
+
apiToasts.error('Load node types', errorMessage);
|
|
336
340
|
}
|
|
337
341
|
|
|
338
342
|
// Set empty nodes array instead of fallback data
|
|
@@ -353,22 +357,19 @@
|
|
|
353
357
|
*/
|
|
354
358
|
async function testApiConnection(): Promise<void> {
|
|
355
359
|
try {
|
|
356
|
-
const baseUrl = endpointConfig?.baseUrl || apiBaseUrl ||
|
|
360
|
+
const baseUrl = endpointConfig?.baseUrl || apiBaseUrl || '/api/flowdrop';
|
|
357
361
|
const testUrl = `${baseUrl}/nodes`;
|
|
358
362
|
|
|
359
363
|
const response = await fetch(testUrl);
|
|
360
364
|
const data = await response.json();
|
|
361
365
|
|
|
362
366
|
if (response.ok && data.success) {
|
|
363
|
-
apiToasts.success(
|
|
367
|
+
apiToasts.success('API connection test', 'Connection successful');
|
|
364
368
|
} else {
|
|
365
|
-
apiToasts.error(
|
|
369
|
+
apiToasts.error('API connection test', 'Connection failed');
|
|
366
370
|
}
|
|
367
371
|
} catch (err) {
|
|
368
|
-
apiToasts.error(
|
|
369
|
-
"API connection test",
|
|
370
|
-
err instanceof Error ? err.message : "Unknown error",
|
|
371
|
-
);
|
|
372
|
+
apiToasts.error('API connection test', err instanceof Error ? err.message : 'Unknown error');
|
|
372
373
|
}
|
|
373
374
|
}
|
|
374
375
|
|
|
@@ -384,16 +385,13 @@
|
|
|
384
385
|
|
|
385
386
|
// Create enhanced API client with authProvider support if provided
|
|
386
387
|
if (authProvider) {
|
|
387
|
-
apiClient = new EnhancedFlowDropApiClient(
|
|
388
|
-
propEndpointConfig,
|
|
389
|
-
authProvider,
|
|
390
|
-
);
|
|
388
|
+
apiClient = new EnhancedFlowDropApiClient(propEndpointConfig, authProvider);
|
|
391
389
|
}
|
|
392
390
|
return;
|
|
393
391
|
}
|
|
394
392
|
|
|
395
393
|
// Second priority: Check if endpoint config is already set (e.g., by parent layout)
|
|
396
|
-
const { getEndpointConfig } = await import(
|
|
394
|
+
const { getEndpointConfig } = await import('../services/api.js');
|
|
397
395
|
const existingConfig = getEndpointConfig();
|
|
398
396
|
|
|
399
397
|
// If config already exists and no override provided, use existing
|
|
@@ -408,19 +406,19 @@
|
|
|
408
406
|
}
|
|
409
407
|
|
|
410
408
|
// Third priority: Use provided apiBaseUrl or default
|
|
411
|
-
const baseUrl = apiBaseUrl ||
|
|
409
|
+
const baseUrl = apiBaseUrl || '/api/flowdrop';
|
|
412
410
|
|
|
413
411
|
const config = createEndpointConfig(baseUrl, {
|
|
414
412
|
auth: {
|
|
415
|
-
type:
|
|
413
|
+
type: 'none' // No authentication for now
|
|
416
414
|
},
|
|
417
415
|
timeout: 10000, // 10 second timeout
|
|
418
416
|
retry: {
|
|
419
417
|
enabled: true,
|
|
420
418
|
maxAttempts: 2,
|
|
421
419
|
delay: 1000,
|
|
422
|
-
backoff:
|
|
423
|
-
}
|
|
420
|
+
backoff: 'exponential'
|
|
421
|
+
}
|
|
424
422
|
});
|
|
425
423
|
|
|
426
424
|
setEndpointConfig(config);
|
|
@@ -444,11 +442,19 @@
|
|
|
444
442
|
}
|
|
445
443
|
selectedNodeId = node.id;
|
|
446
444
|
isConfigSidebarOpen = true;
|
|
445
|
+
// Reset swap state when switching nodes
|
|
446
|
+
swapMode = 'idle';
|
|
447
|
+
swapTargetMetadata = null;
|
|
448
|
+
swapInteractiveState = null;
|
|
447
449
|
}
|
|
448
450
|
|
|
449
451
|
function closeConfigSidebar(): void {
|
|
450
452
|
isConfigSidebarOpen = false;
|
|
451
453
|
selectedNodeId = null;
|
|
454
|
+
// Reset swap state when closing
|
|
455
|
+
swapMode = 'idle';
|
|
456
|
+
swapTargetMetadata = null;
|
|
457
|
+
swapInteractiveState = null;
|
|
452
458
|
}
|
|
453
459
|
|
|
454
460
|
/**
|
|
@@ -462,17 +468,144 @@
|
|
|
462
468
|
}
|
|
463
469
|
}
|
|
464
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Start swap mode — transitions the right sidebar to the node picker
|
|
473
|
+
*/
|
|
474
|
+
function startSwap(): void {
|
|
475
|
+
swapMode = 'picking';
|
|
476
|
+
swapTargetMetadata = null;
|
|
477
|
+
swapInteractiveState = null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Handle selection of a target node type for swap
|
|
482
|
+
*/
|
|
483
|
+
function handleSwapSelect(metadata: NodeMetadata): void {
|
|
484
|
+
const node = selectedNodeForConfig;
|
|
485
|
+
if (!node) return;
|
|
486
|
+
|
|
487
|
+
const wf = getWorkflowStore();
|
|
488
|
+
if (!wf) return;
|
|
489
|
+
|
|
490
|
+
// Format compatibility guard — defence-in-depth behind picker's own filter
|
|
491
|
+
const currentFormat = getWorkflowFormat();
|
|
492
|
+
if (metadata.formats?.length && !metadata.formats.includes(currentFormat)) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Get port compatibility checker (may be null if not initialized)
|
|
497
|
+
let checker: import('../utils/connections.js').PortCompatibilityChecker | null = null;
|
|
498
|
+
try {
|
|
499
|
+
checker = getPortCompatibilityChecker();
|
|
500
|
+
} catch {
|
|
501
|
+
// Checker not initialized — computeSwapPreview will use exact dataType matching
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const interactive = computeInteractiveState(node, metadata, wf.edges, wf.nodes, {
|
|
505
|
+
checker,
|
|
506
|
+
strategies: swapStrategies
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
swapTargetMetadata = metadata;
|
|
510
|
+
swapInteractiveState = interactive;
|
|
511
|
+
swapMode = 'mapping';
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Execute the confirmed node swap
|
|
516
|
+
*/
|
|
517
|
+
async function executeNodeSwap(finalState?: InteractiveSwapState): Promise<void> {
|
|
518
|
+
const state = finalState ?? swapInteractiveState;
|
|
519
|
+
if (!state) return;
|
|
520
|
+
|
|
521
|
+
const wf = getWorkflowStore();
|
|
522
|
+
if (!wf) return;
|
|
523
|
+
|
|
524
|
+
const oldLabel = state.oldNode.data.label;
|
|
525
|
+
const newLabel = state.newMetadata.name;
|
|
526
|
+
|
|
527
|
+
// Convert interactive state to swap preview
|
|
528
|
+
const preview = buildSwapPreviewFromState(state, wf.edges);
|
|
529
|
+
|
|
530
|
+
// Execute the swap
|
|
531
|
+
const result = executeSwap(state.oldNode, state.newMetadata, preview, wf.nodes, wf.edges);
|
|
532
|
+
|
|
533
|
+
// Post-swap validation
|
|
534
|
+
const validation = validateSwapResult(result);
|
|
535
|
+
if (!validation.valid) {
|
|
536
|
+
logger.error('Swap validation failed:', validation.error);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// onBeforeSwap hook — abort if returns false
|
|
541
|
+
if (eventHandlers?.onBeforeSwap) {
|
|
542
|
+
const swapEventCtx: SwapEventContext = {
|
|
543
|
+
oldNode: state.oldNode,
|
|
544
|
+
newMetadata: state.newMetadata,
|
|
545
|
+
preview,
|
|
546
|
+
portOverrides: [],
|
|
547
|
+
configOverrides: []
|
|
548
|
+
};
|
|
549
|
+
const shouldProceed = await eventHandlers.onBeforeSwap(swapEventCtx);
|
|
550
|
+
if (shouldProceed === false) return;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Apply as a single atomic swap with descriptive history entry
|
|
554
|
+
workflowActions.swapNode({
|
|
555
|
+
nodes: result.updatedNodes,
|
|
556
|
+
edges: result.updatedEdges,
|
|
557
|
+
description: `Swap node: ${oldLabel} → ${newLabel}`
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// onAfterSwap hook (fire-and-forget — swap is already applied)
|
|
561
|
+
if (eventHandlers?.onAfterSwap) {
|
|
562
|
+
try {
|
|
563
|
+
eventHandlers.onAfterSwap(result, state.oldNode, state.newNodeId);
|
|
564
|
+
} catch (err) {
|
|
565
|
+
logger.error('onAfterSwap hook error:', err);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Select the new node in the sidebar
|
|
570
|
+
const newNodeId = state.newNodeId;
|
|
571
|
+
selectedNodeId = newNodeId;
|
|
572
|
+
|
|
573
|
+
// Reset swap state
|
|
574
|
+
swapMode = 'idle';
|
|
575
|
+
swapTargetMetadata = null;
|
|
576
|
+
swapInteractiveState = null;
|
|
577
|
+
|
|
578
|
+
// Wait for SvelteFlow to process the new node before updating visual state
|
|
579
|
+
await tick();
|
|
580
|
+
|
|
581
|
+
// Refresh the editor visual state
|
|
582
|
+
if (workflowEditorRef) {
|
|
583
|
+
const newNode = result.updatedNodes.find((n) => n.id === newNodeId);
|
|
584
|
+
if (newNode) {
|
|
585
|
+
workflowEditorRef.updateNodeData(newNodeId, newNode.data);
|
|
586
|
+
await workflowEditorRef.refreshEdgePositions(newNodeId);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Cancel swap and return to normal config view
|
|
593
|
+
*/
|
|
594
|
+
function cancelSwap(): void {
|
|
595
|
+
swapMode = 'idle';
|
|
596
|
+
swapTargetMetadata = null;
|
|
597
|
+
swapInteractiveState = null;
|
|
598
|
+
}
|
|
599
|
+
|
|
465
600
|
/**
|
|
466
601
|
* Handle workflow configuration save
|
|
467
602
|
*/
|
|
468
|
-
async function handleWorkflowSave(
|
|
469
|
-
config: Record<string, unknown>,
|
|
470
|
-
): Promise<void> {
|
|
603
|
+
async function handleWorkflowSave(config: Record<string, unknown>): Promise<void> {
|
|
471
604
|
// Update the workflow store
|
|
472
605
|
if (getWorkflowStore()) {
|
|
473
606
|
workflowActions.batchUpdate({
|
|
474
607
|
name: config.name as string | undefined,
|
|
475
|
-
description: config.description as string | undefined
|
|
608
|
+
description: config.description as string | undefined
|
|
476
609
|
});
|
|
477
610
|
}
|
|
478
611
|
|
|
@@ -483,7 +616,7 @@
|
|
|
483
616
|
try {
|
|
484
617
|
await saveWorkflow();
|
|
485
618
|
} catch (error) {
|
|
486
|
-
logger.error(
|
|
619
|
+
logger.error('Failed to save workflow to backend:', error);
|
|
487
620
|
// Note: We don't throw the error here to avoid breaking the UI flow
|
|
488
621
|
// The user can still manually save via the main Save button if needed
|
|
489
622
|
}
|
|
@@ -500,7 +633,7 @@
|
|
|
500
633
|
apiClient: apiClient ?? undefined,
|
|
501
634
|
eventHandlers,
|
|
502
635
|
features,
|
|
503
|
-
onMarkAsSaved: markAsSaved
|
|
636
|
+
onMarkAsSaved: markAsSaved
|
|
504
637
|
});
|
|
505
638
|
}
|
|
506
639
|
|
|
@@ -524,45 +657,38 @@
|
|
|
524
657
|
reader.onload = (event) => {
|
|
525
658
|
try {
|
|
526
659
|
const text = event.target?.result;
|
|
527
|
-
if (typeof text !==
|
|
528
|
-
throw new Error(
|
|
660
|
+
if (typeof text !== 'string') {
|
|
661
|
+
throw new Error('Could not read file contents.');
|
|
529
662
|
}
|
|
530
663
|
const data = JSON.parse(text);
|
|
531
664
|
const validation = validateWorkflowData(data);
|
|
532
665
|
if (!validation.valid) {
|
|
533
666
|
if (features.showToasts) {
|
|
534
|
-
apiToasts.error(
|
|
535
|
-
"Import workflow",
|
|
536
|
-
validation.error ?? "Invalid workflow JSON",
|
|
537
|
-
);
|
|
667
|
+
apiToasts.error('Import workflow', validation.error ?? 'Invalid workflow JSON');
|
|
538
668
|
}
|
|
539
|
-
logger.warn(
|
|
669
|
+
logger.warn('Workflow import validation failed:', validation.error);
|
|
540
670
|
return;
|
|
541
671
|
}
|
|
542
672
|
workflowActions.initialize(data as Workflow);
|
|
543
673
|
if (features.showToasts) {
|
|
544
|
-
apiToasts.success(
|
|
545
|
-
"Import workflow",
|
|
546
|
-
"Workflow imported successfully",
|
|
547
|
-
);
|
|
674
|
+
apiToasts.success('Import workflow', 'Workflow imported successfully');
|
|
548
675
|
}
|
|
549
676
|
if (eventHandlers?.onWorkflowLoad) {
|
|
550
677
|
eventHandlers.onWorkflowLoad(data as Workflow);
|
|
551
678
|
}
|
|
552
679
|
} catch (error) {
|
|
553
|
-
const errorObj =
|
|
554
|
-
|
|
555
|
-
logger.error("Workflow import failed:", errorObj);
|
|
680
|
+
const errorObj = error instanceof Error ? error : new Error('Unknown error occurred');
|
|
681
|
+
logger.error('Workflow import failed:', errorObj);
|
|
556
682
|
if (features.showToasts) {
|
|
557
|
-
apiToasts.error(
|
|
683
|
+
apiToasts.error('Import workflow', errorObj.message);
|
|
558
684
|
}
|
|
559
685
|
}
|
|
560
686
|
};
|
|
561
687
|
reader.onerror = () => {
|
|
562
|
-
const message =
|
|
688
|
+
const message = 'Failed to read the selected file.';
|
|
563
689
|
logger.error(message);
|
|
564
690
|
if (features.showToasts) {
|
|
565
|
-
apiToasts.error(
|
|
691
|
+
apiToasts.error('Import workflow', message);
|
|
566
692
|
}
|
|
567
693
|
};
|
|
568
694
|
reader.readAsText(file);
|
|
@@ -578,15 +704,13 @@
|
|
|
578
704
|
importWorkflow(file);
|
|
579
705
|
}
|
|
580
706
|
// Reset input so same file can be re-imported
|
|
581
|
-
input.value =
|
|
707
|
+
input.value = '';
|
|
582
708
|
}
|
|
583
709
|
|
|
584
710
|
// Function to handle clicks outside the sidebar
|
|
585
711
|
function handleCanvasClick(event: MouseEvent): void {
|
|
586
712
|
// Check if the click is outside the right sidebar
|
|
587
|
-
const rightSidebar = document.querySelector(
|
|
588
|
-
".flowdrop-main-layout__sidebar--right",
|
|
589
|
-
);
|
|
713
|
+
const rightSidebar = document.querySelector('.flowdrop-main-layout__sidebar--right');
|
|
590
714
|
if (rightSidebar && !rightSidebar.contains(event.target as Node)) {
|
|
591
715
|
// Close sidebar when clicking outside of it
|
|
592
716
|
if (isConfigSidebarOpen) {
|
|
@@ -619,21 +743,21 @@
|
|
|
619
743
|
// Initialize with a default empty workflow so the editor is functional
|
|
620
744
|
// (e.g., drag-and-drop requires a non-null workflow in the store)
|
|
621
745
|
const defaultWorkflow: Workflow = {
|
|
622
|
-
id:
|
|
623
|
-
name:
|
|
746
|
+
id: '',
|
|
747
|
+
name: 'Untitled Workflow',
|
|
624
748
|
nodes: [],
|
|
625
749
|
edges: [],
|
|
626
750
|
metadata: {
|
|
627
|
-
version:
|
|
751
|
+
version: '1.0.0',
|
|
628
752
|
format: DEFAULT_WORKFLOW_FORMAT,
|
|
629
753
|
createdAt: new Date().toISOString(),
|
|
630
|
-
updatedAt: new Date().toISOString()
|
|
631
|
-
}
|
|
754
|
+
updatedAt: new Date().toISOString()
|
|
755
|
+
}
|
|
632
756
|
};
|
|
633
757
|
workflowActions.initialize(defaultWorkflow);
|
|
634
758
|
}
|
|
635
759
|
} catch (error) {
|
|
636
|
-
logger.error(
|
|
760
|
+
logger.error('Failed to initialize editor:', error);
|
|
637
761
|
}
|
|
638
762
|
})();
|
|
639
763
|
|
|
@@ -642,10 +766,7 @@
|
|
|
642
766
|
toggleWorkflowSettings();
|
|
643
767
|
};
|
|
644
768
|
|
|
645
|
-
window.addEventListener(
|
|
646
|
-
"workflow-settings-toggle",
|
|
647
|
-
handleWorkflowSettingsToggle,
|
|
648
|
-
);
|
|
769
|
+
window.addEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
|
|
649
770
|
|
|
650
771
|
// Initialize auto-save based on user settings
|
|
651
772
|
const cleanupAutoSave = initAutoSave({
|
|
@@ -654,18 +775,15 @@
|
|
|
654
775
|
},
|
|
655
776
|
onError: (error) => {
|
|
656
777
|
// Don't show toast for auto-save errors to avoid noise
|
|
657
|
-
logger.warn(
|
|
778
|
+
logger.warn('Auto-save failed:', error);
|
|
658
779
|
},
|
|
659
780
|
onSuccess: () => {
|
|
660
|
-
logger.debug(
|
|
661
|
-
}
|
|
781
|
+
logger.debug('Auto-saved workflow');
|
|
782
|
+
}
|
|
662
783
|
});
|
|
663
784
|
|
|
664
785
|
return () => {
|
|
665
|
-
window.removeEventListener(
|
|
666
|
-
"workflow-settings-toggle",
|
|
667
|
-
handleWorkflowSettingsToggle,
|
|
668
|
-
);
|
|
786
|
+
window.removeEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
|
|
669
787
|
cleanupAutoSave();
|
|
670
788
|
};
|
|
671
789
|
});
|
|
@@ -675,7 +793,7 @@
|
|
|
675
793
|
* Config panel always appears on the right side
|
|
676
794
|
*/
|
|
677
795
|
const hasConfigPanelOpen = $derived(
|
|
678
|
-
isWorkflowSettingsOpen || !!selectedNodeForConfig
|
|
796
|
+
isWorkflowSettingsOpen || !!selectedNodeForConfig || swapMode !== 'idle'
|
|
679
797
|
);
|
|
680
798
|
const showRightPanel = $derived(!disableSidebar && hasConfigPanelOpen);
|
|
681
799
|
|
|
@@ -684,7 +802,7 @@
|
|
|
684
802
|
* When collapsed, use 0; otherwise use user-configured width
|
|
685
803
|
*/
|
|
686
804
|
const leftSidebarWidth = $derived(
|
|
687
|
-
getUiSettings().sidebarCollapsed ? 0 : getUiSettings().sidebarWidth
|
|
805
|
+
getUiSettings().sidebarCollapsed ? 0 : getUiSettings().sidebarWidth
|
|
688
806
|
);
|
|
689
807
|
|
|
690
808
|
/** Whether the sidebar is collapsed */
|
|
@@ -693,20 +811,82 @@
|
|
|
693
811
|
/** Toggle sidebar collapsed state */
|
|
694
812
|
function toggleSidebar(): void {
|
|
695
813
|
updateSettings({
|
|
696
|
-
ui: { sidebarCollapsed: !getUiSettings().sidebarCollapsed }
|
|
814
|
+
ui: { sidebarCollapsed: !getUiSettings().sidebarCollapsed }
|
|
697
815
|
});
|
|
698
816
|
}
|
|
699
817
|
|
|
700
818
|
// File input reference for workflow import
|
|
701
819
|
let fileInputRef = $state<HTMLInputElement | null>(null);
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Handle global keyboard shortcut for console toggle.
|
|
823
|
+
* Backtick (`) toggles the console open/closed unless user is typing in an input.
|
|
824
|
+
*/
|
|
825
|
+
function handleGlobalKeydown(event: KeyboardEvent): void {
|
|
826
|
+
// Dead key on international keyboards — do not intercept
|
|
827
|
+
if (event.key === 'Dead') return;
|
|
828
|
+
|
|
829
|
+
if (event.key !== '`') return;
|
|
830
|
+
|
|
831
|
+
// Don't intercept when user is typing in an input, textarea, or contenteditable
|
|
832
|
+
const target = event.target as HTMLElement;
|
|
833
|
+
const isInputElement =
|
|
834
|
+
target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
|
|
835
|
+
|
|
836
|
+
if (isInputElement) return;
|
|
837
|
+
|
|
838
|
+
event.preventDefault();
|
|
839
|
+
toggleConsole();
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function handleConsoleUIAction(action: UIAction): void {
|
|
843
|
+
if (action.type === 'open_config') {
|
|
844
|
+
const wf = getWorkflowStore();
|
|
845
|
+
if (!wf) return;
|
|
846
|
+
const node = wf.nodes.find((n) => n.id === action.nodeId);
|
|
847
|
+
if (node) openConfigSidebar(node);
|
|
848
|
+
} else if (action.type === 'select_node') {
|
|
849
|
+
selectedNodeId = action.nodeId;
|
|
850
|
+
} else if (action.type === 'canvas_fit_view') {
|
|
851
|
+
workflowEditorRef?.canvasFitView();
|
|
852
|
+
} else if (action.type === 'canvas_zoom_in') {
|
|
853
|
+
workflowEditorRef?.canvasZoomIn();
|
|
854
|
+
} else if (action.type === 'canvas_zoom_out') {
|
|
855
|
+
workflowEditorRef?.canvasZoomOut();
|
|
856
|
+
} else if (action.type === 'canvas_zoom_to') {
|
|
857
|
+
workflowEditorRef?.canvasZoomTo(action.level);
|
|
858
|
+
} else if (action.type === 'canvas_pan_to') {
|
|
859
|
+
workflowEditorRef?.canvasPanTo(action.position.x, action.position.y);
|
|
860
|
+
} else if (action.type === 'canvas_reset_view') {
|
|
861
|
+
workflowEditorRef?.canvasResetView();
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function toggleConsole(): void {
|
|
866
|
+
const currentOpen = getUiSettings().consoleOpen;
|
|
867
|
+
updateSettings({ ui: { consoleOpen: !currentOpen } });
|
|
868
|
+
|
|
869
|
+
// Focus management after DOM update
|
|
870
|
+
tick().then(() => {
|
|
871
|
+
if (currentOpen) {
|
|
872
|
+
// Console was open, now closing — focus the canvas
|
|
873
|
+
const canvas = document.querySelector<HTMLElement>('.flowdrop-editor-main');
|
|
874
|
+
canvas?.focus();
|
|
875
|
+
} else {
|
|
876
|
+
// Console was closed, now opening — focus first focusable element inside console
|
|
877
|
+
const consoleEl = document.querySelector<HTMLElement>('.command-console');
|
|
878
|
+
const focusTarget = consoleEl?.querySelector<HTMLElement>('input, button, [tabindex]');
|
|
879
|
+
focusTarget?.focus();
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
}
|
|
702
883
|
</script>
|
|
703
884
|
|
|
885
|
+
<svelte:window onkeydown={handleGlobalKeydown} />
|
|
886
|
+
|
|
704
887
|
<svelte:head>
|
|
705
888
|
<title>FlowDrop - Visual Workflow Manager</title>
|
|
706
|
-
<meta
|
|
707
|
-
name="description"
|
|
708
|
-
content="A modern drag-and-drop workflow editor for LLM applications"
|
|
709
|
-
/>
|
|
889
|
+
<meta name="description" content="A modern drag-and-drop workflow editor for LLM applications" />
|
|
710
890
|
</svelte:head>
|
|
711
891
|
|
|
712
892
|
<!-- Hidden file input for workflow JSON import -->
|
|
@@ -724,7 +904,8 @@
|
|
|
724
904
|
showHeader={showNavbar}
|
|
725
905
|
showLeftSidebar={!disableSidebar}
|
|
726
906
|
showRightSidebar={showRightPanel}
|
|
727
|
-
showBottomPanel={
|
|
907
|
+
showBottomPanel={getUiSettings().consoleOpen && !readOnly && !lockWorkflow}
|
|
908
|
+
bottomPanelHeight={getUiSettings().consoleHeight}
|
|
728
909
|
showFooter={false}
|
|
729
910
|
headerHeight={60}
|
|
730
911
|
{leftSidebarWidth}
|
|
@@ -740,50 +921,50 @@
|
|
|
740
921
|
<!-- Header: Navbar -->
|
|
741
922
|
{#snippet header()}
|
|
742
923
|
<Navbar
|
|
743
|
-
title={breadcrumbTitle
|
|
924
|
+
title={breadcrumbTitle}
|
|
744
925
|
primaryActions={navbarActions.length > 0
|
|
745
926
|
? navbarActions
|
|
746
927
|
: [
|
|
747
928
|
{
|
|
748
|
-
label:
|
|
749
|
-
href:
|
|
750
|
-
icon:
|
|
751
|
-
variant:
|
|
929
|
+
label: 'Save',
|
|
930
|
+
href: '#save',
|
|
931
|
+
icon: 'heroicons:document-arrow-down',
|
|
932
|
+
variant: 'primary',
|
|
752
933
|
onclick: (e) => {
|
|
753
934
|
e.preventDefault();
|
|
754
935
|
saveWorkflow();
|
|
755
|
-
}
|
|
936
|
+
}
|
|
756
937
|
},
|
|
757
938
|
{
|
|
758
|
-
label:
|
|
759
|
-
href:
|
|
760
|
-
icon:
|
|
761
|
-
variant:
|
|
939
|
+
label: 'Export',
|
|
940
|
+
href: '#export',
|
|
941
|
+
icon: 'heroicons:arrow-down-tray',
|
|
942
|
+
variant: 'outline',
|
|
762
943
|
onclick: (e) => {
|
|
763
944
|
e.preventDefault();
|
|
764
945
|
exportWorkflow();
|
|
765
|
-
}
|
|
946
|
+
}
|
|
766
947
|
},
|
|
767
948
|
{
|
|
768
|
-
label:
|
|
769
|
-
href:
|
|
770
|
-
icon:
|
|
771
|
-
variant:
|
|
949
|
+
label: 'Import',
|
|
950
|
+
href: '#import',
|
|
951
|
+
icon: 'heroicons:arrow-up-tray',
|
|
952
|
+
variant: 'outline',
|
|
772
953
|
onclick: (e) => {
|
|
773
954
|
e.preventDefault();
|
|
774
955
|
fileInputRef?.click();
|
|
775
|
-
}
|
|
956
|
+
}
|
|
776
957
|
},
|
|
777
958
|
{
|
|
778
|
-
label:
|
|
779
|
-
href:
|
|
780
|
-
icon:
|
|
781
|
-
variant:
|
|
959
|
+
label: 'Workflow Settings',
|
|
960
|
+
href: '#settings',
|
|
961
|
+
icon: 'heroicons:cog-6-tooth',
|
|
962
|
+
variant: 'outline',
|
|
782
963
|
onclick: (e) => {
|
|
783
964
|
e.preventDefault();
|
|
784
965
|
toggleWorkflowSettings();
|
|
785
|
-
}
|
|
786
|
-
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
787
968
|
]}
|
|
788
969
|
showStatus={true}
|
|
789
970
|
{showSettings}
|
|
@@ -799,26 +980,51 @@
|
|
|
799
980
|
{nodes}
|
|
800
981
|
loading={nodeTypesLoading}
|
|
801
982
|
activeFormat={getWorkflowFormat()}
|
|
802
|
-
categoriesDefaultOpen={themeConfig?.sidebar?.categoriesDefaultOpen ??
|
|
803
|
-
false}
|
|
983
|
+
categoriesDefaultOpen={themeConfig?.sidebar?.categoriesDefaultOpen ?? false}
|
|
804
984
|
/>
|
|
805
985
|
{/snippet}
|
|
806
986
|
|
|
807
|
-
<!-- Right Sidebar: Configuration or Workflow Settings -->
|
|
987
|
+
<!-- Right Sidebar: Configuration, Swap, or Workflow Settings -->
|
|
808
988
|
{#snippet rightSidebar()}
|
|
809
|
-
{#if
|
|
989
|
+
{#if swapMode === 'mapping' && swapInteractiveState && selectedNodeForConfig}
|
|
990
|
+
{@const swapChecker = (() => {
|
|
991
|
+
try {
|
|
992
|
+
return getPortCompatibilityChecker();
|
|
993
|
+
} catch {
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
})()}
|
|
997
|
+
<SwapMappingEditor
|
|
998
|
+
interactiveState={swapInteractiveState}
|
|
999
|
+
checker={swapChecker}
|
|
1000
|
+
onConfirm={executeNodeSwap}
|
|
1001
|
+
onCancel={cancelSwap}
|
|
1002
|
+
onBack={() => {
|
|
1003
|
+
swapMode = 'picking';
|
|
1004
|
+
swapInteractiveState = null;
|
|
1005
|
+
}}
|
|
1006
|
+
/>
|
|
1007
|
+
{:else if swapMode === 'picking' && selectedNodeForConfig}
|
|
1008
|
+
<NodeSwapPicker
|
|
1009
|
+
currentNode={selectedNodeForConfig}
|
|
1010
|
+
availableNodes={nodes}
|
|
1011
|
+
activeFormat={getWorkflowFormat()}
|
|
1012
|
+
onSelect={handleSwapSelect}
|
|
1013
|
+
onCancel={cancelSwap}
|
|
1014
|
+
/>
|
|
1015
|
+
{:else if isWorkflowSettingsOpen}
|
|
810
1016
|
<ConfigPanel
|
|
811
1017
|
title="Workflow Settings"
|
|
812
1018
|
id={getWorkflowStore()?.id}
|
|
813
1019
|
details={[
|
|
814
1020
|
{
|
|
815
|
-
label:
|
|
816
|
-
value: String(getWorkflowStore()?.nodes?.length ?? 0)
|
|
1021
|
+
label: 'Nodes',
|
|
1022
|
+
value: String(getWorkflowStore()?.nodes?.length ?? 0)
|
|
817
1023
|
},
|
|
818
1024
|
{
|
|
819
|
-
label:
|
|
820
|
-
value: String(getWorkflowStore()?.edges?.length ?? 0)
|
|
821
|
-
}
|
|
1025
|
+
label: 'Connections',
|
|
1026
|
+
value: String(getWorkflowStore()?.edges?.length ?? 0)
|
|
1027
|
+
}
|
|
822
1028
|
]}
|
|
823
1029
|
configTitle="Settings"
|
|
824
1030
|
onClose={() => (isWorkflowSettingsOpen = false)}
|
|
@@ -832,25 +1038,19 @@
|
|
|
832
1038
|
// Sync workflow settings changes immediately on field blur
|
|
833
1039
|
const wf = getWorkflowStore();
|
|
834
1040
|
if (wf) {
|
|
835
|
-
const newFormat =
|
|
836
|
-
|
|
837
|
-
const currentFormat =
|
|
838
|
-
wf.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
|
|
1041
|
+
const newFormat = (config.format as string) || DEFAULT_WORKFLOW_FORMAT;
|
|
1042
|
+
const currentFormat = wf.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
|
|
839
1043
|
|
|
840
1044
|
// Warn about incompatible nodes when format changes
|
|
841
1045
|
if (newFormat !== currentFormat) {
|
|
842
1046
|
const incompatibleNodes = wf.nodes?.filter((node) => {
|
|
843
1047
|
const formats = node.data?.metadata?.formats;
|
|
844
|
-
return (
|
|
845
|
-
formats &&
|
|
846
|
-
formats.length > 0 &&
|
|
847
|
-
!formats.includes(newFormat)
|
|
848
|
-
);
|
|
1048
|
+
return formats && formats.length > 0 && !formats.includes(newFormat);
|
|
849
1049
|
});
|
|
850
1050
|
if (incompatibleNodes && incompatibleNodes.length > 0) {
|
|
851
1051
|
logger.warn(
|
|
852
1052
|
`Format changed to '${newFormat}'. ${incompatibleNodes.length} node(s) are not compatible with this format and may not export correctly:`,
|
|
853
|
-
incompatibleNodes.map((n) => n.data?.label || n.type)
|
|
1053
|
+
incompatibleNodes.map((n) => n.data?.label || n.type)
|
|
854
1054
|
);
|
|
855
1055
|
}
|
|
856
1056
|
}
|
|
@@ -860,31 +1060,31 @@
|
|
|
860
1060
|
description: config.description as string | undefined,
|
|
861
1061
|
metadata: {
|
|
862
1062
|
...wf.metadata,
|
|
863
|
-
format: newFormat
|
|
864
|
-
}
|
|
1063
|
+
format: newFormat
|
|
1064
|
+
}
|
|
865
1065
|
});
|
|
866
1066
|
}
|
|
867
1067
|
}}
|
|
868
1068
|
/>
|
|
869
1069
|
</ConfigPanel>
|
|
870
|
-
{:else if selectedNodeForConfig
|
|
871
|
-
{@const currentNode = selectedNodeForConfig
|
|
1070
|
+
{:else if selectedNodeForConfig}
|
|
1071
|
+
{@const currentNode = selectedNodeForConfig}
|
|
872
1072
|
<ConfigPanel
|
|
873
1073
|
title={currentNode.data.label}
|
|
874
1074
|
id={currentNode.id}
|
|
875
|
-
description={currentNode.data.metadata?.description ||
|
|
876
|
-
"Node configuration"}
|
|
1075
|
+
description={currentNode.data.metadata?.description || 'Node configuration'}
|
|
877
1076
|
details={[
|
|
878
1077
|
{
|
|
879
|
-
label:
|
|
880
|
-
value: currentNode.data.metadata?.type || currentNode.type
|
|
1078
|
+
label: 'Type',
|
|
1079
|
+
value: currentNode.data.metadata?.type || currentNode.type
|
|
881
1080
|
},
|
|
882
1081
|
{
|
|
883
|
-
label:
|
|
884
|
-
value: currentNode.data.metadata?.category ||
|
|
885
|
-
}
|
|
1082
|
+
label: 'Category',
|
|
1083
|
+
value: currentNode.data.metadata?.category || 'general'
|
|
1084
|
+
}
|
|
886
1085
|
]}
|
|
887
1086
|
onClose={closeConfigSidebar}
|
|
1087
|
+
onSwap={!readOnly && !lockWorkflow && features.enableNodeSwap ? startSwap : undefined}
|
|
888
1088
|
>
|
|
889
1089
|
<ConfigForm
|
|
890
1090
|
{authProvider}
|
|
@@ -898,20 +1098,20 @@
|
|
|
898
1098
|
// Build the updated node data
|
|
899
1099
|
const updatedData = {
|
|
900
1100
|
...currentNode.data,
|
|
901
|
-
config: updatedConfig
|
|
1101
|
+
config: updatedConfig
|
|
902
1102
|
};
|
|
903
1103
|
|
|
904
1104
|
// Include UI extensions if provided
|
|
905
1105
|
if (uiExtensions) {
|
|
906
1106
|
updatedData.extensions = {
|
|
907
1107
|
...currentNode.data.extensions,
|
|
908
|
-
ui: uiExtensions
|
|
1108
|
+
ui: uiExtensions
|
|
909
1109
|
};
|
|
910
1110
|
}
|
|
911
1111
|
|
|
912
1112
|
// Update the node in the workflow store
|
|
913
1113
|
const nodeUpdates: Record<string, unknown> = {
|
|
914
|
-
data: updatedData
|
|
1114
|
+
data: updatedData
|
|
915
1115
|
};
|
|
916
1116
|
|
|
917
1117
|
workflowActions.updateNode(selectedNodeId, nodeUpdates);
|
|
@@ -929,22 +1129,57 @@
|
|
|
929
1129
|
{/if}
|
|
930
1130
|
{/snippet}
|
|
931
1131
|
|
|
1132
|
+
<!-- Bottom Panel: Tabbed Console / AI Chat -->
|
|
1133
|
+
{#snippet bottomPanel()}
|
|
1134
|
+
<div class="bottom-panel-tabs">
|
|
1135
|
+
<div class="bottom-panel-tabs__bar">
|
|
1136
|
+
<button
|
|
1137
|
+
class="bottom-panel-tabs__tab {getUiSettings().bottomPanelTab === 'console'
|
|
1138
|
+
? 'bottom-panel-tabs__tab--active'
|
|
1139
|
+
: ''}"
|
|
1140
|
+
onclick={() => updateSettings({ ui: { bottomPanelTab: 'console' } })}
|
|
1141
|
+
>
|
|
1142
|
+
Console
|
|
1143
|
+
</button>
|
|
1144
|
+
<button
|
|
1145
|
+
class="bottom-panel-tabs__tab {getUiSettings().bottomPanelTab === 'chat'
|
|
1146
|
+
? 'bottom-panel-tabs__tab--active'
|
|
1147
|
+
: ''}"
|
|
1148
|
+
onclick={() => updateSettings({ ui: { bottomPanelTab: 'chat' } })}
|
|
1149
|
+
>
|
|
1150
|
+
AI Chat
|
|
1151
|
+
</button>
|
|
1152
|
+
</div>
|
|
1153
|
+
<div class="bottom-panel-tabs__content">
|
|
1154
|
+
<div
|
|
1155
|
+
class="bottom-panel-tabs__panel"
|
|
1156
|
+
style:display={getUiSettings().bottomPanelTab === 'console' ? 'contents' : 'none'}
|
|
1157
|
+
>
|
|
1158
|
+
<CommandConsole nodeTypes={nodes} onUIAction={handleConsoleUIAction} />
|
|
1159
|
+
</div>
|
|
1160
|
+
<div
|
|
1161
|
+
class="bottom-panel-tabs__panel"
|
|
1162
|
+
style:display={getUiSettings().bottomPanelTab === 'chat' ? 'flex' : 'none'}
|
|
1163
|
+
>
|
|
1164
|
+
<AIChatPanel
|
|
1165
|
+
nodeTypes={nodes}
|
|
1166
|
+
workflowId={getWorkflowStore()?.id}
|
|
1167
|
+
onUIAction={handleConsoleUIAction}
|
|
1168
|
+
{endpointConfig}
|
|
1169
|
+
/>
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1172
|
+
</div>
|
|
1173
|
+
{/snippet}
|
|
1174
|
+
|
|
932
1175
|
<!-- Main Content: Workflow Editor with Error Status -->
|
|
933
1176
|
<!-- Status Display: aria-live announces API errors dynamically without requiring focus -->
|
|
934
1177
|
{#if error}
|
|
935
|
-
<div
|
|
936
|
-
class="flowdrop-status flowdrop-status--error"
|
|
937
|
-
aria-live="polite"
|
|
938
|
-
aria-atomic="true"
|
|
939
|
-
>
|
|
1178
|
+
<div class="flowdrop-status flowdrop-status--error" aria-live="polite" aria-atomic="true">
|
|
940
1179
|
<div class="flowdrop-status__content">
|
|
941
1180
|
<div class="flowdrop-flex flowdrop-gap--3">
|
|
942
|
-
<div
|
|
943
|
-
|
|
944
|
-
></div>
|
|
945
|
-
<span class="flowdrop-text--sm flowdrop-font--medium"
|
|
946
|
-
>Error: {error}</span
|
|
947
|
-
>
|
|
1181
|
+
<div class="flowdrop-status__indicator flowdrop-status__indicator--error"></div>
|
|
1182
|
+
<span class="flowdrop-text--sm flowdrop-font--medium">Error: {error}</span>
|
|
948
1183
|
</div>
|
|
949
1184
|
<div class="flowdrop-flex flowdrop-gap--2">
|
|
950
1185
|
<button
|
|
@@ -957,8 +1192,8 @@
|
|
|
957
1192
|
<button
|
|
958
1193
|
class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
|
|
959
1194
|
onclick={() => {
|
|
960
|
-
const defaultUrl =
|
|
961
|
-
const newUrl = prompt(
|
|
1195
|
+
const defaultUrl = '/api/flowdrop';
|
|
1196
|
+
const newUrl = prompt('Enter Backend API URL:', defaultUrl);
|
|
962
1197
|
if (newUrl) {
|
|
963
1198
|
const endpointConfig = createEndpointConfig(newUrl);
|
|
964
1199
|
setEndpointConfig(endpointConfig);
|
|
@@ -993,11 +1228,9 @@
|
|
|
993
1228
|
<div
|
|
994
1229
|
class="flowdrop-editor-main"
|
|
995
1230
|
class:pipeline-view={!!pipelineId}
|
|
996
|
-
style="--fd-canvas-left-offset: {!disableSidebar
|
|
997
|
-
? leftSidebarWidth + 'px'
|
|
998
|
-
: '0px'}"
|
|
1231
|
+
style="--fd-canvas-left-offset: {!disableSidebar ? leftSidebarWidth + 'px' : '0px'}"
|
|
999
1232
|
onclick={handleCanvasClick}
|
|
1000
|
-
onkeydown={(e) => e.key ===
|
|
1233
|
+
onkeydown={(e) => e.key === 'Escape' && closeConfigSidebar()}
|
|
1001
1234
|
role="region"
|
|
1002
1235
|
aria-label="Workflow canvas"
|
|
1003
1236
|
>
|
|
@@ -1006,12 +1239,10 @@
|
|
|
1006
1239
|
<button
|
|
1007
1240
|
class="flowdrop-sidebar-fab"
|
|
1008
1241
|
onclick={toggleSidebar}
|
|
1009
|
-
aria-label={isSidebarCollapsed
|
|
1010
|
-
|
|
1011
|
-
: "Collapse sidebar"}
|
|
1012
|
-
title={isSidebarCollapsed ? "Expand sidebar" : "Collapse sidebar"}
|
|
1242
|
+
aria-label={isSidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
1243
|
+
title={isSidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
1013
1244
|
>
|
|
1014
|
-
<Icon icon={isSidebarCollapsed ?
|
|
1245
|
+
<Icon icon={isSidebarCollapsed ? 'mdi:menu' : 'mdi:menu-open'} />
|
|
1015
1246
|
</button>
|
|
1016
1247
|
{/if}
|
|
1017
1248
|
|
|
@@ -1022,13 +1253,15 @@
|
|
|
1022
1253
|
{width}
|
|
1023
1254
|
endpointConfig={endpointConfig ?? undefined}
|
|
1024
1255
|
{isConfigSidebarOpen}
|
|
1025
|
-
|
|
1256
|
+
{selectedNodeForConfig}
|
|
1026
1257
|
{openConfigSidebar}
|
|
1027
1258
|
{closeConfigSidebar}
|
|
1028
1259
|
{lockWorkflow}
|
|
1029
1260
|
{readOnly}
|
|
1030
1261
|
{nodeStatuses}
|
|
1031
1262
|
{pipelineId}
|
|
1263
|
+
consoleOpen={getUiSettings().consoleOpen}
|
|
1264
|
+
onToggleConsole={toggleConsole}
|
|
1032
1265
|
/>
|
|
1033
1266
|
</div>
|
|
1034
1267
|
</MainLayout>
|
|
@@ -1182,4 +1415,56 @@
|
|
|
1182
1415
|
overflow: hidden;
|
|
1183
1416
|
background: var(--fd-layout-background);
|
|
1184
1417
|
}
|
|
1418
|
+
|
|
1419
|
+
/* Bottom panel tab system */
|
|
1420
|
+
.bottom-panel-tabs {
|
|
1421
|
+
display: flex;
|
|
1422
|
+
flex-direction: column;
|
|
1423
|
+
height: 100%;
|
|
1424
|
+
overflow: hidden;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
.bottom-panel-tabs__bar {
|
|
1428
|
+
display: flex;
|
|
1429
|
+
gap: 0;
|
|
1430
|
+
background: var(--fd-muted);
|
|
1431
|
+
border-bottom: 1px solid var(--fd-border);
|
|
1432
|
+
flex-shrink: 0;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
.bottom-panel-tabs__tab {
|
|
1436
|
+
padding: 0.375rem 0.75rem;
|
|
1437
|
+
font-size: 0.75rem;
|
|
1438
|
+
font-weight: 500;
|
|
1439
|
+
cursor: pointer;
|
|
1440
|
+
border: none;
|
|
1441
|
+
border-bottom: 2px solid transparent;
|
|
1442
|
+
background: transparent;
|
|
1443
|
+
color: var(--fd-muted-foreground);
|
|
1444
|
+
transition: all var(--fd-transition-fast);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
.bottom-panel-tabs__tab:hover {
|
|
1448
|
+
color: var(--fd-foreground);
|
|
1449
|
+
background: var(--fd-background);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
.bottom-panel-tabs__tab--active {
|
|
1453
|
+
color: var(--fd-foreground);
|
|
1454
|
+
border-bottom-color: var(--fd-primary);
|
|
1455
|
+
background: var(--fd-background);
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
.bottom-panel-tabs__content {
|
|
1459
|
+
flex: 1;
|
|
1460
|
+
overflow: hidden;
|
|
1461
|
+
display: flex;
|
|
1462
|
+
flex-direction: column;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.bottom-panel-tabs__panel {
|
|
1466
|
+
flex: 1;
|
|
1467
|
+
overflow: hidden;
|
|
1468
|
+
flex-direction: column;
|
|
1469
|
+
}
|
|
1185
1470
|
</style>
|