@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,977 +5,1106 @@
|
|
|
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
|
-
|
|
8
|
+
import { onMount } from "svelte";
|
|
9
|
+
import MainLayout from "./layouts/MainLayout.svelte";
|
|
10
|
+
import WorkflowEditor from "./WorkflowEditor.svelte";
|
|
11
|
+
import NodeSidebar from "./NodeSidebar.svelte";
|
|
12
|
+
import ConfigForm from "./ConfigForm.svelte";
|
|
13
|
+
import ConfigPanel from "./ConfigPanel.svelte";
|
|
14
|
+
import Navbar from "./Navbar.svelte";
|
|
15
|
+
import { api, setEndpointConfig } from "../services/api.js";
|
|
16
|
+
import { EnhancedFlowDropApiClient } from "../api/enhanced-client.js";
|
|
17
|
+
import type {
|
|
18
|
+
NodeMetadata,
|
|
19
|
+
Workflow,
|
|
20
|
+
WorkflowNode,
|
|
21
|
+
ConfigSchema,
|
|
22
|
+
NodeUIExtensions,
|
|
23
|
+
} from "../types/index.js";
|
|
24
|
+
import { DEFAULT_WORKFLOW_FORMAT } from "../types/index.js";
|
|
25
|
+
import { createEndpointConfig } from "../config/endpoints.js";
|
|
26
|
+
import type { EndpointConfig } from "../config/endpoints.js";
|
|
27
|
+
import type { AuthProvider } from "../types/auth.js";
|
|
28
|
+
import type {
|
|
29
|
+
FlowDropEventHandlers,
|
|
30
|
+
FlowDropFeatures,
|
|
31
|
+
} from "../types/events.js";
|
|
32
|
+
import { mergeFeatures } from "../types/events.js";
|
|
33
|
+
import type { FlowDropTheme, FlowDropThemeName } from "../types/theme.js";
|
|
34
|
+
import type { FlowDropSkinTokens } from "../types/skin.js";
|
|
35
|
+
import { resolveTheme } from "../themes/index.js";
|
|
36
|
+
import {
|
|
37
|
+
getWorkflowStore,
|
|
38
|
+
workflowActions,
|
|
39
|
+
getWorkflowName,
|
|
40
|
+
getWorkflowFormat,
|
|
41
|
+
markAsSaved,
|
|
42
|
+
} from "../stores/workflowStore.svelte.js";
|
|
43
|
+
import {
|
|
44
|
+
globalSaveWorkflow,
|
|
45
|
+
globalExportWorkflow,
|
|
46
|
+
} from "../services/globalSave.js";
|
|
47
|
+
import { apiToasts, dismissToast } from "../services/toastService.js";
|
|
48
|
+
import { initAutoSave } from "../services/autoSaveService.js";
|
|
49
|
+
import { getUiSettings } from "../stores/settingsStore.svelte.js";
|
|
50
|
+
import { initializePortCompatibility } from "../utils/connections.js";
|
|
51
|
+
import { DEFAULT_PORT_CONFIG } from "../config/defaultPortConfig.js";
|
|
52
|
+
import { workflowFormatRegistry } from "../registry/workflowFormatRegistry.js";
|
|
53
|
+
import { logger } from "../utils/logger.js";
|
|
54
|
+
import { validateWorkflowData } from "../utils/validation.js";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Configuration props for runtime customization
|
|
58
|
+
*/
|
|
59
|
+
interface Props {
|
|
60
|
+
/** Initial workflow to load */
|
|
61
|
+
workflow?: Workflow;
|
|
62
|
+
/** Pre-loaded node types (if provided, skips API fetch) */
|
|
63
|
+
nodes?: NodeMetadata[];
|
|
64
|
+
/** Editor height */
|
|
65
|
+
height?: string | number;
|
|
66
|
+
/** Editor width */
|
|
67
|
+
width?: string | number;
|
|
68
|
+
/** Show the navbar */
|
|
69
|
+
showNavbar?: boolean;
|
|
70
|
+
/** Disable the node sidebar */
|
|
71
|
+
disableSidebar?: boolean;
|
|
72
|
+
/** Lock the workflow (prevent changes) */
|
|
73
|
+
lockWorkflow?: boolean;
|
|
74
|
+
/** Read-only mode */
|
|
75
|
+
readOnly?: boolean;
|
|
76
|
+
/** Node execution statuses */
|
|
77
|
+
nodeStatuses?: Record<
|
|
78
|
+
string,
|
|
79
|
+
"pending" | "running" | "completed" | "error"
|
|
80
|
+
>;
|
|
81
|
+
/** Pipeline ID for fetching node execution info */
|
|
82
|
+
pipelineId?: string;
|
|
83
|
+
/** Custom navbar title */
|
|
84
|
+
navbarTitle?: string;
|
|
85
|
+
/** Custom navbar actions */
|
|
86
|
+
navbarActions?: Array<{
|
|
87
|
+
label: string;
|
|
88
|
+
href: string;
|
|
89
|
+
icon?: string;
|
|
90
|
+
variant?: "primary" | "secondary" | "outline";
|
|
91
|
+
onclick?: (event: Event) => void;
|
|
92
|
+
}>;
|
|
93
|
+
/** Show settings gear icon in navbar */
|
|
94
|
+
showSettings?: boolean;
|
|
95
|
+
/** API base URL */
|
|
96
|
+
apiBaseUrl?: string;
|
|
97
|
+
/** Endpoint configuration */
|
|
98
|
+
endpointConfig?: EndpointConfig;
|
|
99
|
+
/** Authentication provider */
|
|
100
|
+
authProvider?: AuthProvider;
|
|
101
|
+
/** Event handlers */
|
|
102
|
+
eventHandlers?: FlowDropEventHandlers;
|
|
103
|
+
/** Feature configuration */
|
|
104
|
+
features?: FlowDropFeatures;
|
|
105
|
+
/** Visual theme — named built-in ('default' | 'minimal') or custom theme object */
|
|
106
|
+
theme?: FlowDropTheme | FlowDropThemeName;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let {
|
|
110
|
+
workflow: initialWorkflow,
|
|
111
|
+
nodes: propNodes,
|
|
112
|
+
height = "100vh",
|
|
113
|
+
width = "100%",
|
|
114
|
+
showNavbar = false,
|
|
115
|
+
disableSidebar = false,
|
|
116
|
+
lockWorkflow = false,
|
|
117
|
+
readOnly = false,
|
|
118
|
+
nodeStatuses = {},
|
|
119
|
+
pipelineId,
|
|
120
|
+
navbarTitle,
|
|
121
|
+
navbarActions = [],
|
|
122
|
+
showSettings = true,
|
|
123
|
+
apiBaseUrl,
|
|
124
|
+
endpointConfig: propEndpointConfig,
|
|
125
|
+
authProvider,
|
|
126
|
+
eventHandlers,
|
|
127
|
+
features: propFeatures,
|
|
128
|
+
theme: themeProp,
|
|
129
|
+
}: Props = $props();
|
|
130
|
+
|
|
131
|
+
// svelte-ignore state_referenced_locally — feature flags don't change at runtime
|
|
132
|
+
const features = mergeFeatures(propFeatures);
|
|
133
|
+
|
|
134
|
+
// Theme system — resolve named theme or custom object, inject CSS tokens from skin
|
|
135
|
+
// Explicit prop wins; falls back to user's persisted theme preference from settings
|
|
136
|
+
let resolvedTheme = $derived(
|
|
137
|
+
resolveTheme(themeProp ?? getUiSettings().theme),
|
|
138
|
+
);
|
|
139
|
+
let themeConfig = $derived(resolvedTheme.config);
|
|
140
|
+
|
|
141
|
+
// Inject skin tokens as a style tag so light/dark palettes can coexist.
|
|
142
|
+
// tokens → :root { ... } (light mode / base)
|
|
143
|
+
// darkTokens → [data-theme='dark'] { ... } (dark mode override)
|
|
144
|
+
// The tag is appended after tokens.css so it wins via source order.
|
|
145
|
+
$effect(() => {
|
|
146
|
+
const skin = resolvedTheme.skin;
|
|
147
|
+
const tokens = skin?.tokens;
|
|
148
|
+
const darkTokens = skin?.darkTokens;
|
|
149
|
+
if ((!tokens && !darkTokens) || typeof document === "undefined") return;
|
|
150
|
+
|
|
151
|
+
const toRules = (dict: FlowDropSkinTokens) =>
|
|
152
|
+
Object.entries(dict)
|
|
153
|
+
.map(([k, v]) => ` --fd-${k}: ${v};`)
|
|
154
|
+
.join("\n");
|
|
155
|
+
|
|
156
|
+
let css = "";
|
|
157
|
+
if (tokens) css += `:root {\n${toRules(tokens)}\n}\n`;
|
|
158
|
+
if (darkTokens) css += `[data-theme='dark'] {\n${toRules(darkTokens)}\n}\n`;
|
|
159
|
+
|
|
160
|
+
const style = document.createElement("style");
|
|
161
|
+
style.id = "fd-skin-tokens";
|
|
162
|
+
document.head.appendChild(style);
|
|
163
|
+
style.textContent = css;
|
|
164
|
+
|
|
165
|
+
return () => style.remove();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Create breadcrumb-style title - at top level to avoid store subscription issues
|
|
169
|
+
let breadcrumbTitle = $derived(() => {
|
|
170
|
+
// Use custom navbar title if provided
|
|
171
|
+
if (navbarTitle) {
|
|
172
|
+
return navbarTitle;
|
|
173
|
+
}
|
|
174
|
+
// Default workflow title logic
|
|
175
|
+
const wfName = getWorkflowName();
|
|
176
|
+
if (!wfName || wfName === "Untitled Workflow") {
|
|
177
|
+
return "Workflow / New Workflow";
|
|
178
|
+
}
|
|
179
|
+
return `Workflow / ${wfName}`;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
let nodes = $state<NodeMetadata[]>([]);
|
|
183
|
+
let nodeTypesLoading = $state<boolean>(true);
|
|
184
|
+
// Remove workflow prop - use global store directly
|
|
185
|
+
// let workflow = $derived($workflowStore || initialWorkflow);
|
|
186
|
+
let error = $state<string | null>(null);
|
|
187
|
+
let endpointConfig = $state<EndpointConfig | null>(null);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Enhanced API client with authProvider support
|
|
191
|
+
* Used when authProvider is provided; otherwise falls back to legacy api service
|
|
192
|
+
*/
|
|
193
|
+
let apiClient = $state<EnhancedFlowDropApiClient | null>(null);
|
|
194
|
+
|
|
195
|
+
// ConfigSidebar state
|
|
196
|
+
let isConfigSidebarOpen = $state(false);
|
|
197
|
+
let selectedNodeId = $state<string | null>(null);
|
|
198
|
+
|
|
199
|
+
// Workflow settings sidebar state
|
|
200
|
+
let isWorkflowSettingsOpen = $state(false);
|
|
201
|
+
|
|
202
|
+
// Workflow configuration schema (derived to pick up dynamic format options)
|
|
203
|
+
let workflowConfigSchema: ConfigSchema = $derived({
|
|
204
|
+
type: "object" as const,
|
|
205
|
+
properties: {
|
|
206
|
+
name: {
|
|
207
|
+
type: "string",
|
|
208
|
+
title: "Workflow Name",
|
|
209
|
+
description: "The name of the workflow",
|
|
210
|
+
default: "",
|
|
211
|
+
},
|
|
212
|
+
description: {
|
|
213
|
+
type: "string",
|
|
214
|
+
title: "Description",
|
|
215
|
+
description: "A description of the workflow",
|
|
216
|
+
format: "multiline",
|
|
217
|
+
default: "",
|
|
218
|
+
},
|
|
219
|
+
format: {
|
|
220
|
+
type: "string",
|
|
221
|
+
title: "Workflow Format",
|
|
222
|
+
description: "The specification format for this workflow",
|
|
223
|
+
oneOf: workflowFormatRegistry.getOneOfOptions(),
|
|
224
|
+
default: "flowdrop",
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
required: ["name"],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Workflow configuration values
|
|
231
|
+
let workflowConfigValues = $derived({
|
|
232
|
+
name: getWorkflowName() || "",
|
|
233
|
+
description: getWorkflowStore()?.description || "",
|
|
234
|
+
format: getWorkflowStore()?.metadata?.format || "flowdrop",
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Get the current node from the workflow store
|
|
238
|
+
let selectedNodeForConfig = $derived(() => {
|
|
239
|
+
const wf = getWorkflowStore();
|
|
240
|
+
if (!selectedNodeId || !wf) return null;
|
|
241
|
+
return wf.nodes.find((node) => node.id === selectedNodeId) || null;
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// WorkflowEditor reference for save functionality
|
|
245
|
+
let workflowEditorRef: WorkflowEditor | null = null;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Fetch node types from the server
|
|
249
|
+
*
|
|
250
|
+
* If propNodes is provided, uses those instead of fetching from API.
|
|
251
|
+
* Uses enhanced API client with authProvider support when available.
|
|
252
|
+
*/
|
|
253
|
+
async function fetchNodeTypes(): Promise<void> {
|
|
254
|
+
// If nodes were provided as props, use them directly (skip API fetch)
|
|
255
|
+
if (propNodes && propNodes.length > 0) {
|
|
256
|
+
// Merge format-provided nodes with prop nodes (deduplicate by ID, props take priority)
|
|
257
|
+
const formatNodes = workflowFormatRegistry.getAllFormatNodes();
|
|
258
|
+
const existingIds = new Set(propNodes.map((n) => n.id));
|
|
259
|
+
const uniqueFormatNodes = formatNodes.filter(
|
|
260
|
+
(n) => !existingIds.has(n.id),
|
|
261
|
+
);
|
|
262
|
+
nodes = [...propNodes, ...uniqueFormatNodes];
|
|
263
|
+
nodeTypesLoading = false;
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Show loading toast (if toasts are enabled)
|
|
268
|
+
const loadingToast = features.showToasts
|
|
269
|
+
? apiToasts.loading("Loading node types")
|
|
270
|
+
: null;
|
|
271
|
+
try {
|
|
272
|
+
error = null;
|
|
273
|
+
|
|
274
|
+
// Use enhanced client with authProvider if available, otherwise fall back to legacy api
|
|
275
|
+
let fetchedNodes: NodeMetadata[];
|
|
276
|
+
if (apiClient) {
|
|
277
|
+
fetchedNodes = await apiClient.getAvailableNodes();
|
|
278
|
+
} else {
|
|
279
|
+
fetchedNodes = await api.nodes.getNodes();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Merge format-provided nodes with API nodes (deduplicate by ID, API takes priority)
|
|
283
|
+
const formatNodes = workflowFormatRegistry.getAllFormatNodes();
|
|
284
|
+
const existingIds = new Set(fetchedNodes.map((n) => n.id));
|
|
285
|
+
const uniqueFormatNodes = formatNodes.filter(
|
|
286
|
+
(n) => !existingIds.has(n.id),
|
|
287
|
+
);
|
|
288
|
+
nodes = [...fetchedNodes, ...uniqueFormatNodes];
|
|
289
|
+
error = null;
|
|
290
|
+
nodeTypesLoading = false;
|
|
291
|
+
|
|
292
|
+
// Dismiss loading toast
|
|
293
|
+
if (loadingToast) {
|
|
294
|
+
dismissToast(loadingToast);
|
|
295
|
+
}
|
|
296
|
+
} catch (err) {
|
|
297
|
+
// Dismiss loading toast and show error toast
|
|
298
|
+
if (loadingToast) {
|
|
299
|
+
dismissToast(loadingToast);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
|
303
|
+
|
|
304
|
+
// Notify parent via event handler
|
|
305
|
+
if (eventHandlers?.onApiError) {
|
|
306
|
+
const suppressToast = eventHandlers.onApiError(
|
|
307
|
+
err instanceof Error ? err : new Error(errorMessage),
|
|
308
|
+
"fetchNodes",
|
|
309
|
+
);
|
|
310
|
+
if (suppressToast) {
|
|
311
|
+
// Parent handled the error, keep nodes empty
|
|
312
|
+
nodes = [];
|
|
313
|
+
nodeTypesLoading = false;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Show error and set empty nodes array (no fallback to sample data)
|
|
319
|
+
error = `API Error: ${errorMessage}. No node types available.`;
|
|
320
|
+
if (features.showToasts) {
|
|
321
|
+
apiToasts.error("Load node types", errorMessage);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Set empty nodes array instead of fallback data
|
|
325
|
+
nodes = [];
|
|
326
|
+
nodeTypesLoading = false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Retry loading node types
|
|
332
|
+
*/
|
|
333
|
+
function retryLoad(): void {
|
|
334
|
+
fetchNodeTypes();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Test API connection
|
|
339
|
+
*/
|
|
340
|
+
async function testApiConnection(): Promise<void> {
|
|
341
|
+
try {
|
|
342
|
+
const baseUrl = endpointConfig?.baseUrl || apiBaseUrl || "/api/flowdrop";
|
|
343
|
+
const testUrl = `${baseUrl}/nodes`;
|
|
344
|
+
|
|
345
|
+
const response = await fetch(testUrl);
|
|
346
|
+
const data = await response.json();
|
|
347
|
+
|
|
348
|
+
if (response.ok && data.success) {
|
|
349
|
+
apiToasts.success("API connection test", "Connection successful");
|
|
350
|
+
} else {
|
|
351
|
+
apiToasts.error("API connection test", "Connection failed");
|
|
352
|
+
}
|
|
353
|
+
} catch (err) {
|
|
354
|
+
apiToasts.error(
|
|
355
|
+
"API connection test",
|
|
356
|
+
err instanceof Error ? err.message : "Unknown error",
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Initialize API endpoints and create enhanced client if authProvider is available
|
|
363
|
+
* Priority: propEndpointConfig > existingConfig > apiBaseUrl > default
|
|
364
|
+
*/
|
|
365
|
+
async function initializeApiEndpoints(): Promise<void> {
|
|
366
|
+
// First priority: Use endpointConfig prop if provided (from mountFlowDropApp)
|
|
367
|
+
if (propEndpointConfig) {
|
|
368
|
+
setEndpointConfig(propEndpointConfig);
|
|
369
|
+
endpointConfig = propEndpointConfig;
|
|
370
|
+
|
|
371
|
+
// Create enhanced API client with authProvider support if provided
|
|
372
|
+
if (authProvider) {
|
|
373
|
+
apiClient = new EnhancedFlowDropApiClient(
|
|
374
|
+
propEndpointConfig,
|
|
375
|
+
authProvider,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Second priority: Check if endpoint config is already set (e.g., by parent layout)
|
|
382
|
+
const { getEndpointConfig } = await import("../services/api.js");
|
|
383
|
+
const existingConfig = getEndpointConfig();
|
|
384
|
+
|
|
385
|
+
// If config already exists and no override provided, use existing
|
|
386
|
+
if (existingConfig && !apiBaseUrl) {
|
|
387
|
+
endpointConfig = existingConfig;
|
|
388
|
+
|
|
389
|
+
// Create enhanced API client with authProvider support if provided
|
|
390
|
+
if (authProvider) {
|
|
391
|
+
apiClient = new EnhancedFlowDropApiClient(existingConfig, authProvider);
|
|
392
|
+
}
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Third priority: Use provided apiBaseUrl or default
|
|
397
|
+
const baseUrl = apiBaseUrl || "/api/flowdrop";
|
|
398
|
+
|
|
399
|
+
const config = createEndpointConfig(baseUrl, {
|
|
400
|
+
auth: {
|
|
401
|
+
type: "none", // No authentication for now
|
|
402
|
+
},
|
|
403
|
+
timeout: 10000, // 10 second timeout
|
|
404
|
+
retry: {
|
|
405
|
+
enabled: true,
|
|
406
|
+
maxAttempts: 2,
|
|
407
|
+
delay: 1000,
|
|
408
|
+
backoff: "exponential",
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
setEndpointConfig(config);
|
|
413
|
+
// Store the configuration for passing to WorkflowEditor
|
|
414
|
+
endpointConfig = config;
|
|
415
|
+
|
|
416
|
+
// Create enhanced API client with authProvider support if provided
|
|
417
|
+
if (authProvider) {
|
|
418
|
+
apiClient = new EnhancedFlowDropApiClient(config, authProvider);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* ConfigSidebar functions
|
|
424
|
+
*/
|
|
425
|
+
function openConfigSidebar(node: WorkflowNode): void {
|
|
426
|
+
// Close if already open for the same node
|
|
427
|
+
if (isConfigSidebarOpen && selectedNodeId === node.id) {
|
|
428
|
+
closeConfigSidebar();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
selectedNodeId = node.id;
|
|
432
|
+
isConfigSidebarOpen = true;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function closeConfigSidebar(): void {
|
|
436
|
+
isConfigSidebarOpen = false;
|
|
437
|
+
selectedNodeId = null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Toggle workflow settings sidebar
|
|
442
|
+
*/
|
|
443
|
+
function toggleWorkflowSettings(): void {
|
|
444
|
+
isWorkflowSettingsOpen = !isWorkflowSettingsOpen;
|
|
445
|
+
// Close config sidebar if opening workflow settings
|
|
446
|
+
if (isWorkflowSettingsOpen) {
|
|
447
|
+
closeConfigSidebar();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Handle workflow configuration save
|
|
453
|
+
*/
|
|
454
|
+
async function handleWorkflowSave(
|
|
455
|
+
config: Record<string, unknown>,
|
|
456
|
+
): Promise<void> {
|
|
457
|
+
// Update the workflow store
|
|
458
|
+
if (getWorkflowStore()) {
|
|
459
|
+
workflowActions.batchUpdate({
|
|
460
|
+
name: config.name as string | undefined,
|
|
461
|
+
description: config.description as string | undefined,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Close the sidebar
|
|
466
|
+
isWorkflowSettingsOpen = false;
|
|
467
|
+
|
|
468
|
+
// Also save the workflow to the backend
|
|
469
|
+
try {
|
|
470
|
+
await saveWorkflow();
|
|
471
|
+
} catch (error) {
|
|
472
|
+
logger.error("Failed to save workflow to backend:", error);
|
|
473
|
+
// Note: We don't throw the error here to avoid breaking the UI flow
|
|
474
|
+
// The user can still manually save via the main Save button if needed
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Save workflow - thin wrapper that delegates to globalSaveWorkflow().
|
|
480
|
+
*
|
|
481
|
+
* All save logic (blur flush, metadata construction, API call, event hooks,
|
|
482
|
+
* toast notifications) lives in globalSave.ts — the single source of truth.
|
|
483
|
+
*/
|
|
484
|
+
async function saveWorkflow(): Promise<void> {
|
|
485
|
+
await globalSaveWorkflow({
|
|
486
|
+
apiClient: apiClient ?? undefined,
|
|
487
|
+
eventHandlers,
|
|
488
|
+
features,
|
|
489
|
+
onMarkAsSaved: markAsSaved,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Export workflow - thin wrapper that delegates to globalExportWorkflow().
|
|
495
|
+
*
|
|
496
|
+
* All export logic (flush, metadata construction, file download) lives
|
|
497
|
+
* in globalSave.ts — the single source of truth.
|
|
498
|
+
*/
|
|
499
|
+
async function exportWorkflow(): Promise<void> {
|
|
500
|
+
await globalExportWorkflow({ features });
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Import workflow from a JSON file
|
|
505
|
+
*
|
|
506
|
+
* Reads the selected file, validates its structure, and loads it into the workflow store.
|
|
507
|
+
*/
|
|
508
|
+
function importWorkflow(file: File): void {
|
|
509
|
+
const reader = new FileReader();
|
|
510
|
+
reader.onload = (event) => {
|
|
511
|
+
try {
|
|
512
|
+
const text = event.target?.result;
|
|
513
|
+
if (typeof text !== "string") {
|
|
514
|
+
throw new Error("Could not read file contents.");
|
|
515
|
+
}
|
|
516
|
+
const data = JSON.parse(text);
|
|
517
|
+
const validation = validateWorkflowData(data);
|
|
518
|
+
if (!validation.valid) {
|
|
519
|
+
if (features.showToasts) {
|
|
520
|
+
apiToasts.error(
|
|
521
|
+
"Import workflow",
|
|
522
|
+
validation.error ?? "Invalid workflow JSON",
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
logger.warn("Workflow import validation failed:", validation.error);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
workflowActions.initialize(data as Workflow);
|
|
529
|
+
if (features.showToasts) {
|
|
530
|
+
apiToasts.success(
|
|
531
|
+
"Import workflow",
|
|
532
|
+
"Workflow imported successfully",
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
if (eventHandlers?.onWorkflowLoad) {
|
|
536
|
+
eventHandlers.onWorkflowLoad(data as Workflow);
|
|
537
|
+
}
|
|
538
|
+
} catch (error) {
|
|
539
|
+
const errorObj =
|
|
540
|
+
error instanceof Error ? error : new Error("Unknown error occurred");
|
|
541
|
+
logger.error("Workflow import failed:", errorObj);
|
|
542
|
+
if (features.showToasts) {
|
|
543
|
+
apiToasts.error("Import workflow", errorObj.message);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
reader.onerror = () => {
|
|
548
|
+
const message = "Failed to read the selected file.";
|
|
549
|
+
logger.error(message);
|
|
550
|
+
if (features.showToasts) {
|
|
551
|
+
apiToasts.error("Import workflow", message);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
reader.readAsText(file);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Handle file input change event for workflow import
|
|
559
|
+
*/
|
|
560
|
+
function handleImportFileChange(event: Event): void {
|
|
561
|
+
const input = event.target as HTMLInputElement;
|
|
562
|
+
const file = input.files?.[0];
|
|
563
|
+
if (file) {
|
|
564
|
+
importWorkflow(file);
|
|
565
|
+
}
|
|
566
|
+
// Reset input so same file can be re-imported
|
|
567
|
+
input.value = "";
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Function to handle clicks outside the sidebar
|
|
571
|
+
function handleCanvasClick(event: MouseEvent): void {
|
|
572
|
+
// Check if the click is outside the right sidebar
|
|
573
|
+
const rightSidebar = document.querySelector(
|
|
574
|
+
".flowdrop-main-layout__sidebar--right",
|
|
575
|
+
);
|
|
576
|
+
if (rightSidebar && !rightSidebar.contains(event.target as Node)) {
|
|
577
|
+
// Close sidebar when clicking outside of it
|
|
578
|
+
if (isConfigSidebarOpen) {
|
|
579
|
+
closeConfigSidebar();
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Load node types on mount
|
|
585
|
+
onMount(() => {
|
|
586
|
+
(async () => {
|
|
587
|
+
try {
|
|
588
|
+
await initializeApiEndpoints();
|
|
589
|
+
|
|
590
|
+
// Ensure port compatibility checker is initialized (needed for proximity connect, etc.)
|
|
591
|
+
// mountFlowDropApp initializes this before mounting, but SvelteKit routes need it here.
|
|
592
|
+
initializePortCompatibility(DEFAULT_PORT_CONFIG);
|
|
593
|
+
|
|
594
|
+
await fetchNodeTypes();
|
|
595
|
+
|
|
596
|
+
// Initialize the workflow store
|
|
597
|
+
if (initialWorkflow) {
|
|
598
|
+
workflowActions.initialize(initialWorkflow);
|
|
599
|
+
|
|
600
|
+
// Emit onWorkflowLoad event
|
|
601
|
+
if (eventHandlers?.onWorkflowLoad) {
|
|
602
|
+
eventHandlers.onWorkflowLoad(initialWorkflow);
|
|
603
|
+
}
|
|
604
|
+
} else {
|
|
605
|
+
// Initialize with a default empty workflow so the editor is functional
|
|
606
|
+
// (e.g., drag-and-drop requires a non-null workflow in the store)
|
|
607
|
+
const defaultWorkflow: Workflow = {
|
|
608
|
+
id: "",
|
|
609
|
+
name: "Untitled Workflow",
|
|
610
|
+
nodes: [],
|
|
611
|
+
edges: [],
|
|
612
|
+
metadata: {
|
|
613
|
+
version: "1.0.0",
|
|
614
|
+
format: DEFAULT_WORKFLOW_FORMAT,
|
|
615
|
+
createdAt: new Date().toISOString(),
|
|
616
|
+
updatedAt: new Date().toISOString(),
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
workflowActions.initialize(defaultWorkflow);
|
|
620
|
+
}
|
|
621
|
+
} catch (error) {
|
|
622
|
+
logger.error("Failed to initialize editor:", error);
|
|
623
|
+
}
|
|
624
|
+
})();
|
|
625
|
+
|
|
626
|
+
// Listen for workflow settings toggle from main navbar
|
|
627
|
+
const handleWorkflowSettingsToggle = () => {
|
|
628
|
+
toggleWorkflowSettings();
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
window.addEventListener(
|
|
632
|
+
"workflow-settings-toggle",
|
|
633
|
+
handleWorkflowSettingsToggle,
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
// Initialize auto-save based on user settings
|
|
637
|
+
const cleanupAutoSave = initAutoSave({
|
|
638
|
+
onSave: async () => {
|
|
639
|
+
await saveWorkflow();
|
|
640
|
+
},
|
|
641
|
+
onError: (error) => {
|
|
642
|
+
// Don't show toast for auto-save errors to avoid noise
|
|
643
|
+
logger.warn("Auto-save failed:", error);
|
|
644
|
+
},
|
|
645
|
+
onSuccess: () => {
|
|
646
|
+
logger.debug("Auto-saved workflow");
|
|
647
|
+
},
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
return () => {
|
|
651
|
+
window.removeEventListener(
|
|
652
|
+
"workflow-settings-toggle",
|
|
653
|
+
handleWorkflowSettingsToggle,
|
|
654
|
+
);
|
|
655
|
+
cleanupAutoSave();
|
|
656
|
+
};
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Derived value for showing the right config panel
|
|
661
|
+
* Config panel always appears on the right side
|
|
662
|
+
*/
|
|
663
|
+
const hasConfigPanelOpen = $derived(
|
|
664
|
+
isWorkflowSettingsOpen || !!selectedNodeForConfig(),
|
|
665
|
+
);
|
|
666
|
+
const showRightPanel = $derived(!disableSidebar && hasConfigPanelOpen);
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Calculate left sidebar width based on collapsed state
|
|
670
|
+
* When collapsed, use 48px; otherwise use user-configured width
|
|
671
|
+
*/
|
|
672
|
+
const leftSidebarWidth = $derived(
|
|
673
|
+
getUiSettings().sidebarCollapsed ? 48 : getUiSettings().sidebarWidth,
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
// File input reference for workflow import
|
|
677
|
+
let fileInputRef = $state<HTMLInputElement | null>(null);
|
|
593
678
|
</script>
|
|
594
679
|
|
|
595
680
|
<svelte:head>
|
|
596
|
-
|
|
597
|
-
|
|
681
|
+
<title>FlowDrop - Visual Workflow Manager</title>
|
|
682
|
+
<meta
|
|
683
|
+
name="description"
|
|
684
|
+
content="A modern drag-and-drop workflow editor for LLM applications"
|
|
685
|
+
/>
|
|
598
686
|
</svelte:head>
|
|
599
687
|
|
|
600
688
|
<!-- Hidden file input for workflow JSON import -->
|
|
601
689
|
<input
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
690
|
+
bind:this={fileInputRef}
|
|
691
|
+
type="file"
|
|
692
|
+
accept=".json,application/json"
|
|
693
|
+
style="display: none;"
|
|
694
|
+
onchange={handleImportFileChange}
|
|
607
695
|
/>
|
|
608
696
|
|
|
609
697
|
<!-- MainLayout wrapper for workflow editor -->
|
|
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
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
698
|
+
<div class="flowdrop-root">
|
|
699
|
+
<MainLayout
|
|
700
|
+
showHeader={showNavbar}
|
|
701
|
+
showLeftSidebar={!disableSidebar}
|
|
702
|
+
showRightSidebar={showRightPanel}
|
|
703
|
+
showBottomPanel={false}
|
|
704
|
+
showFooter={false}
|
|
705
|
+
headerHeight={60}
|
|
706
|
+
{leftSidebarWidth}
|
|
707
|
+
rightSidebarWidth={400}
|
|
708
|
+
leftSidebarMinWidth={getUiSettings().sidebarCollapsed ? 48 : 280}
|
|
709
|
+
leftSidebarMaxWidth={getUiSettings().sidebarCollapsed ? 48 : 450}
|
|
710
|
+
rightSidebarMinWidth={320}
|
|
711
|
+
rightSidebarMaxWidth={550}
|
|
712
|
+
enableLeftSplitPane={false}
|
|
713
|
+
enableRightSplitPane={true}
|
|
714
|
+
class="flowdrop-app-layout"
|
|
715
|
+
>
|
|
716
|
+
<!-- Header: Navbar -->
|
|
717
|
+
{#snippet header()}
|
|
718
|
+
<Navbar
|
|
719
|
+
title={breadcrumbTitle()}
|
|
720
|
+
primaryActions={navbarActions.length > 0
|
|
721
|
+
? navbarActions
|
|
722
|
+
: [
|
|
723
|
+
{
|
|
724
|
+
label: "Save",
|
|
725
|
+
href: "#save",
|
|
726
|
+
icon: "heroicons:document-arrow-down",
|
|
727
|
+
variant: "primary",
|
|
728
|
+
onclick: (e) => {
|
|
729
|
+
e.preventDefault();
|
|
730
|
+
saveWorkflow();
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
label: "Export",
|
|
735
|
+
href: "#export",
|
|
736
|
+
icon: "heroicons:arrow-down-tray",
|
|
737
|
+
variant: "outline",
|
|
738
|
+
onclick: (e) => {
|
|
739
|
+
e.preventDefault();
|
|
740
|
+
exportWorkflow();
|
|
741
|
+
},
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
label: "Import",
|
|
745
|
+
href: "#import",
|
|
746
|
+
icon: "heroicons:arrow-up-tray",
|
|
747
|
+
variant: "outline",
|
|
748
|
+
onclick: (e) => {
|
|
749
|
+
e.preventDefault();
|
|
750
|
+
fileInputRef?.click();
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
label: "Workflow Settings",
|
|
755
|
+
href: "#settings",
|
|
756
|
+
icon: "heroicons:cog-6-tooth",
|
|
757
|
+
variant: "outline",
|
|
758
|
+
onclick: (e) => {
|
|
759
|
+
e.preventDefault();
|
|
760
|
+
toggleWorkflowSettings();
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
]}
|
|
764
|
+
showStatus={true}
|
|
765
|
+
{showSettings}
|
|
766
|
+
/>
|
|
767
|
+
{/snippet}
|
|
768
|
+
|
|
769
|
+
<!-- Left Sidebar: Node Components -->
|
|
770
|
+
{#snippet leftSidebar()}
|
|
771
|
+
<NodeSidebar
|
|
772
|
+
{nodes}
|
|
773
|
+
loading={nodeTypesLoading}
|
|
774
|
+
activeFormat={getWorkflowFormat()}
|
|
775
|
+
categoriesDefaultOpen={themeConfig?.sidebar?.categoriesDefaultOpen ??
|
|
776
|
+
false}
|
|
777
|
+
/>
|
|
778
|
+
{/snippet}
|
|
779
|
+
|
|
780
|
+
<!-- Right Sidebar: Configuration or Workflow Settings -->
|
|
781
|
+
{#snippet rightSidebar()}
|
|
782
|
+
{#if isWorkflowSettingsOpen}
|
|
783
|
+
<ConfigPanel
|
|
784
|
+
title="Workflow Settings"
|
|
785
|
+
id={getWorkflowStore()?.id}
|
|
786
|
+
details={[
|
|
787
|
+
{
|
|
788
|
+
label: "Nodes",
|
|
789
|
+
value: String(getWorkflowStore()?.nodes?.length ?? 0),
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
label: "Connections",
|
|
793
|
+
value: String(getWorkflowStore()?.edges?.length ?? 0),
|
|
794
|
+
},
|
|
795
|
+
]}
|
|
796
|
+
configTitle="Settings"
|
|
797
|
+
onClose={() => (isWorkflowSettingsOpen = false)}
|
|
798
|
+
>
|
|
799
|
+
<ConfigForm
|
|
800
|
+
{authProvider}
|
|
801
|
+
schema={workflowConfigSchema}
|
|
802
|
+
values={workflowConfigValues}
|
|
803
|
+
showUIExtensions={false}
|
|
804
|
+
onChange={(config) => {
|
|
805
|
+
// Sync workflow settings changes immediately on field blur
|
|
806
|
+
const wf = getWorkflowStore();
|
|
807
|
+
if (wf) {
|
|
808
|
+
const newFormat =
|
|
809
|
+
(config.format as string) || DEFAULT_WORKFLOW_FORMAT;
|
|
810
|
+
const currentFormat =
|
|
811
|
+
wf.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
|
|
812
|
+
|
|
813
|
+
// Warn about incompatible nodes when format changes
|
|
814
|
+
if (newFormat !== currentFormat) {
|
|
815
|
+
const incompatibleNodes = wf.nodes?.filter((node) => {
|
|
816
|
+
const formats = node.data?.metadata?.formats;
|
|
817
|
+
return (
|
|
818
|
+
formats &&
|
|
819
|
+
formats.length > 0 &&
|
|
820
|
+
!formats.includes(newFormat)
|
|
821
|
+
);
|
|
822
|
+
});
|
|
823
|
+
if (incompatibleNodes && incompatibleNodes.length > 0) {
|
|
824
|
+
logger.warn(
|
|
825
|
+
`Format changed to '${newFormat}'. ${incompatibleNodes.length} node(s) are not compatible with this format and may not export correctly:`,
|
|
826
|
+
incompatibleNodes.map((n) => n.data?.label || n.type),
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
workflowActions.batchUpdate({
|
|
832
|
+
name: config.name as string,
|
|
833
|
+
description: config.description as string | undefined,
|
|
834
|
+
metadata: {
|
|
835
|
+
...wf.metadata,
|
|
836
|
+
format: newFormat,
|
|
837
|
+
},
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
}}
|
|
841
|
+
/>
|
|
842
|
+
</ConfigPanel>
|
|
843
|
+
{:else if selectedNodeForConfig()}
|
|
844
|
+
{@const currentNode = selectedNodeForConfig()!}
|
|
845
|
+
<ConfigPanel
|
|
846
|
+
title={currentNode.data.label}
|
|
847
|
+
id={currentNode.id}
|
|
848
|
+
description={currentNode.data.metadata?.description ||
|
|
849
|
+
"Node configuration"}
|
|
850
|
+
details={[
|
|
851
|
+
{
|
|
852
|
+
label: "Type",
|
|
853
|
+
value: currentNode.data.metadata?.type || currentNode.type,
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
label: "Category",
|
|
857
|
+
value: currentNode.data.metadata?.category || "general",
|
|
858
|
+
},
|
|
859
|
+
]}
|
|
860
|
+
onClose={closeConfigSidebar}
|
|
861
|
+
>
|
|
862
|
+
<ConfigForm
|
|
863
|
+
{authProvider}
|
|
864
|
+
node={currentNode}
|
|
865
|
+
workflowId={getWorkflowStore()?.id}
|
|
866
|
+
workflowNodes={getWorkflowStore()?.nodes}
|
|
867
|
+
workflowEdges={getWorkflowStore()?.edges}
|
|
868
|
+
onChange={async (updatedConfig, uiExtensions) => {
|
|
869
|
+
// Sync config changes to workflow immediately on field blur
|
|
870
|
+
if (selectedNodeId && currentNode) {
|
|
871
|
+
// Build the updated node data
|
|
872
|
+
const updatedData = {
|
|
873
|
+
...currentNode.data,
|
|
874
|
+
config: updatedConfig,
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
// Include UI extensions if provided
|
|
878
|
+
if (uiExtensions) {
|
|
879
|
+
updatedData.extensions = {
|
|
880
|
+
...currentNode.data.extensions,
|
|
881
|
+
ui: uiExtensions,
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Update the node in the workflow store
|
|
886
|
+
const nodeUpdates: Record<string, unknown> = {
|
|
887
|
+
data: updatedData,
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
workflowActions.updateNode(selectedNodeId, nodeUpdates);
|
|
891
|
+
|
|
892
|
+
// Update the local editor state to reflect config changes immediately
|
|
893
|
+
// This is needed for nodeType changes to take effect visually
|
|
894
|
+
workflowEditorRef?.updateNodeData(selectedNodeId, updatedData);
|
|
895
|
+
|
|
896
|
+
// Refresh edge positions in case config changes affect handles
|
|
897
|
+
await workflowEditorRef?.refreshEdgePositions(selectedNodeId);
|
|
898
|
+
}
|
|
899
|
+
}}
|
|
900
|
+
/>
|
|
901
|
+
</ConfigPanel>
|
|
902
|
+
{/if}
|
|
903
|
+
{/snippet}
|
|
904
|
+
|
|
905
|
+
<!-- Main Content: Workflow Editor with Error Status -->
|
|
906
|
+
<!-- Status Display: aria-live announces API errors dynamically without requiring focus -->
|
|
907
|
+
{#if error}
|
|
908
|
+
<div
|
|
909
|
+
class="flowdrop-status flowdrop-status--error"
|
|
910
|
+
aria-live="polite"
|
|
911
|
+
aria-atomic="true"
|
|
912
|
+
>
|
|
913
|
+
<div class="flowdrop-status__content">
|
|
914
|
+
<div class="flowdrop-flex flowdrop-gap--3">
|
|
915
|
+
<div
|
|
916
|
+
class="flowdrop-status__indicator flowdrop-status__indicator--error"
|
|
917
|
+
></div>
|
|
918
|
+
<span class="flowdrop-text--sm flowdrop-font--medium"
|
|
919
|
+
>Error: {error}</span
|
|
920
|
+
>
|
|
921
|
+
</div>
|
|
922
|
+
<div class="flowdrop-flex flowdrop-gap--2">
|
|
923
|
+
<button
|
|
924
|
+
class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--primary"
|
|
925
|
+
onclick={retryLoad}
|
|
926
|
+
type="button"
|
|
927
|
+
>
|
|
928
|
+
Retry
|
|
929
|
+
</button>
|
|
930
|
+
<button
|
|
931
|
+
class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
|
|
932
|
+
onclick={() => {
|
|
933
|
+
const defaultUrl = "/api/flowdrop";
|
|
934
|
+
const newUrl = prompt("Enter Backend API URL:", defaultUrl);
|
|
935
|
+
if (newUrl) {
|
|
936
|
+
const endpointConfig = createEndpointConfig(newUrl);
|
|
937
|
+
setEndpointConfig(endpointConfig);
|
|
938
|
+
fetchNodeTypes();
|
|
939
|
+
}
|
|
940
|
+
}}
|
|
941
|
+
type="button"
|
|
942
|
+
>
|
|
943
|
+
Set API URL
|
|
944
|
+
</button>
|
|
945
|
+
<button
|
|
946
|
+
class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
|
|
947
|
+
onclick={testApiConnection}
|
|
948
|
+
type="button"
|
|
949
|
+
>
|
|
950
|
+
Test API
|
|
951
|
+
</button>
|
|
952
|
+
<button
|
|
953
|
+
class="flowdrop-btn flowdrop-btn--ghost flowdrop-btn--sm"
|
|
954
|
+
onclick={() => (error = null)}
|
|
955
|
+
type="button"
|
|
956
|
+
>
|
|
957
|
+
✕
|
|
958
|
+
</button>
|
|
959
|
+
</div>
|
|
960
|
+
</div>
|
|
961
|
+
</div>
|
|
962
|
+
{/if}
|
|
963
|
+
|
|
964
|
+
<!-- Main Editor Area -->
|
|
965
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions — interactive workflow canvas region with keyboard support -->
|
|
966
|
+
<div
|
|
967
|
+
class="flowdrop-editor-main"
|
|
968
|
+
class:pipeline-view={!!pipelineId}
|
|
969
|
+
style="--fd-canvas-left-offset: {!disableSidebar
|
|
970
|
+
? leftSidebarWidth + 'px'
|
|
971
|
+
: '0px'}"
|
|
972
|
+
onclick={handleCanvasClick}
|
|
973
|
+
onkeydown={(e) => e.key === "Escape" && closeConfigSidebar()}
|
|
974
|
+
role="region"
|
|
975
|
+
aria-label="Workflow canvas"
|
|
976
|
+
>
|
|
977
|
+
<WorkflowEditor
|
|
978
|
+
bind:this={workflowEditorRef}
|
|
979
|
+
{nodes}
|
|
980
|
+
{height}
|
|
981
|
+
{width}
|
|
982
|
+
endpointConfig={endpointConfig ?? undefined}
|
|
983
|
+
{isConfigSidebarOpen}
|
|
984
|
+
selectedNodeForConfig={selectedNodeForConfig()}
|
|
985
|
+
{openConfigSidebar}
|
|
986
|
+
{closeConfigSidebar}
|
|
987
|
+
{lockWorkflow}
|
|
988
|
+
{readOnly}
|
|
989
|
+
{nodeStatuses}
|
|
990
|
+
{pipelineId}
|
|
991
|
+
/>
|
|
992
|
+
</div>
|
|
993
|
+
</MainLayout>
|
|
994
|
+
</div>
|
|
869
995
|
|
|
870
996
|
<style>
|
|
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
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
997
|
+
.flowdrop-root {
|
|
998
|
+
display: contents;
|
|
999
|
+
}
|
|
1000
|
+
/* Status bar styles */
|
|
1001
|
+
.flowdrop-status {
|
|
1002
|
+
background-color: var(--fd-info-muted);
|
|
1003
|
+
border-bottom: 1px solid var(--fd-info);
|
|
1004
|
+
padding: 1rem;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.flowdrop-status--error {
|
|
1008
|
+
background-color: var(--fd-error-muted);
|
|
1009
|
+
border-bottom: 1px solid var(--fd-error);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
.flowdrop-status__content {
|
|
1013
|
+
max-width: 80rem;
|
|
1014
|
+
margin: 0 auto;
|
|
1015
|
+
display: flex;
|
|
1016
|
+
align-items: center;
|
|
1017
|
+
justify-content: space-between;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.flowdrop-status__indicator {
|
|
1021
|
+
width: 0.5rem;
|
|
1022
|
+
height: 0.5rem;
|
|
1023
|
+
border-radius: 50%;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.flowdrop-status__indicator--error {
|
|
1027
|
+
background-color: var(--fd-error);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/* Button styles */
|
|
1031
|
+
.flowdrop-btn {
|
|
1032
|
+
padding: 0.375rem 0.75rem;
|
|
1033
|
+
border-radius: var(--fd-radius-md);
|
|
1034
|
+
font-size: 0.75rem;
|
|
1035
|
+
font-weight: 500;
|
|
1036
|
+
cursor: pointer;
|
|
1037
|
+
border: 1px solid transparent;
|
|
1038
|
+
transition: all var(--fd-transition-fast);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
.flowdrop-btn--sm {
|
|
1042
|
+
padding: 0.25rem 0.5rem;
|
|
1043
|
+
font-size: 0.625rem;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
.flowdrop-btn--outline {
|
|
1047
|
+
background-color: transparent;
|
|
1048
|
+
border-color: var(--fd-border);
|
|
1049
|
+
color: var(--fd-foreground);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
.flowdrop-btn--outline:hover {
|
|
1053
|
+
background-color: var(--fd-muted);
|
|
1054
|
+
border-color: var(--fd-border-strong);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
.flowdrop-btn--primary {
|
|
1058
|
+
background-color: var(--fd-primary);
|
|
1059
|
+
border-color: var(--fd-primary);
|
|
1060
|
+
color: var(--fd-primary-foreground);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
.flowdrop-btn--primary:hover {
|
|
1064
|
+
background-color: var(--fd-primary-hover);
|
|
1065
|
+
border-color: var(--fd-primary-hover);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
.flowdrop-btn--ghost {
|
|
1069
|
+
background-color: transparent;
|
|
1070
|
+
border-color: transparent;
|
|
1071
|
+
color: var(--fd-muted-foreground);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.flowdrop-btn--ghost:hover {
|
|
1075
|
+
background-color: var(--fd-muted);
|
|
1076
|
+
color: var(--fd-foreground);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/* Utility classes */
|
|
1080
|
+
.flowdrop-flex {
|
|
1081
|
+
display: flex;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
.flowdrop-gap--2 {
|
|
1085
|
+
gap: 0.5rem;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
.flowdrop-gap--3 {
|
|
1089
|
+
gap: 0.75rem;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
.flowdrop-text--sm {
|
|
1093
|
+
font-size: 0.875rem;
|
|
1094
|
+
line-height: 1.25rem;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
.flowdrop-font--medium {
|
|
1098
|
+
font-weight: 500;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/* Main editor area */
|
|
1102
|
+
.flowdrop-editor-main {
|
|
1103
|
+
flex: 1;
|
|
1104
|
+
position: relative;
|
|
1105
|
+
min-width: 0;
|
|
1106
|
+
height: 100%;
|
|
1107
|
+
overflow: hidden;
|
|
1108
|
+
background: var(--fd-layout-background);
|
|
1109
|
+
}
|
|
981
1110
|
</style>
|