@flowdrop/flowdrop 1.15.0 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +475 -0
- package/MIGRATION-2.0.md +472 -0
- package/README.md +23 -23
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +14 -8
- package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
- package/dist/chat/batchFeedback.d.ts +39 -0
- package/dist/chat/batchFeedback.js +51 -0
- package/dist/commands/executor.js +15 -1
- package/dist/commands/storeIntegration.svelte.d.ts +4 -1
- package/dist/commands/storeIntegration.svelte.js +26 -21
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/App.svelte +162 -192
- package/dist/components/App.svelte.d.ts +47 -8
- package/dist/components/ConfigForm.svelte +71 -47
- package/dist/components/ConfigModal.svelte +7 -2
- package/dist/components/ConnectionLine.svelte +4 -2
- package/dist/components/Navbar.svelte +61 -1
- package/dist/components/NodeSidebar.svelte +27 -45
- package/dist/components/NodeStatusOverlay.svelte +94 -6
- package/dist/components/NodeSwapPicker.svelte +10 -8
- package/dist/components/PipelineStatus.svelte +16 -67
- package/dist/components/PortCoordinateTracker.svelte +5 -6
- package/dist/components/SchemaForm.stories.svelte +1 -3
- package/dist/components/SchemaForm.svelte +18 -25
- package/dist/components/SchemaForm.svelte.d.ts +0 -8
- package/dist/components/SettingsModal.svelte +8 -3
- package/dist/components/SettingsPanel.svelte +20 -4
- package/dist/components/SwapMappingEditor.svelte +67 -49
- package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
- package/dist/components/UniversalNode.svelte +9 -7
- package/dist/components/WorkflowEditor.svelte +118 -111
- package/dist/components/WorkflowEditor.svelte.d.ts +18 -10
- package/dist/components/chat/AIChatPanel.svelte +93 -89
- package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
- package/dist/components/chat/CommandPreview.svelte +2 -1
- package/dist/components/console/CommandConsole.svelte +7 -5
- package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
- package/dist/components/console/ConsoleInput.svelte +15 -6
- package/dist/components/console/ConsoleOutput.svelte +2 -1
- package/dist/components/form/FormArray.svelte +5 -9
- package/dist/components/form/FormArray.svelte.d.ts +2 -1
- package/dist/components/form/FormAutocomplete.svelte +8 -6
- package/dist/components/form/FormField.svelte +4 -2
- package/dist/components/form/FormFieldLight.svelte +4 -2
- package/dist/components/form/FormMarkdownEditor.svelte +9 -4
- package/dist/components/form/FormRangeField.svelte +1 -0
- package/dist/components/form/FormTemplateEditor.svelte +11 -3
- package/dist/components/form/FormToggle.svelte +5 -12
- package/dist/components/form/FormToggle.svelte.d.ts +4 -2
- package/dist/components/form/templateAutocomplete.js +1 -5
- package/dist/components/form/types.d.ts +1 -14
- package/dist/components/interrupt/FormPrompt.svelte +3 -2
- package/dist/components/interrupt/InterruptBubble.svelte +16 -17
- package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
- package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
- package/dist/components/layouts/MainLayout.svelte +20 -13
- package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
- package/dist/components/nodes/AtomNode.svelte +17 -5
- package/dist/components/nodes/GatewayNode.svelte +19 -10
- package/dist/components/nodes/IdeaNode.svelte +7 -0
- package/dist/components/nodes/SimpleNode.svelte +11 -6
- package/dist/components/nodes/SquareNode.svelte +15 -8
- package/dist/components/nodes/TerminalNode.svelte +9 -4
- package/dist/components/nodes/ToolNode.svelte +7 -1
- package/dist/components/nodes/WorkflowNode.svelte +16 -7
- package/dist/components/playground/ChatInput.svelte +11 -14
- package/dist/components/playground/ChatPanel.svelte +6 -49
- package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
- package/dist/components/playground/ControlPanel.svelte +134 -123
- package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
- package/dist/components/playground/ExecutionLogs.svelte +11 -9
- package/dist/components/playground/InputCollector.svelte +11 -9
- package/dist/components/playground/MessageStream.svelte +17 -23
- package/dist/components/playground/PipelineKanbanView.svelte +65 -6
- package/dist/components/playground/PipelinePanel.svelte +11 -5
- package/dist/components/playground/PipelineTableView.svelte +186 -44
- package/dist/components/playground/Playground.svelte +90 -92
- package/dist/components/playground/Playground.svelte.d.ts +2 -0
- package/dist/components/playground/PlaygroundApp.svelte +6 -1
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
- package/dist/components/playground/PlaygroundModal.svelte +13 -3
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
- package/dist/components/playground/PlaygroundStudio.svelte +34 -32
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
- package/dist/components/playground/SessionManager.svelte +9 -12
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +28 -0
- package/dist/components/playground/pipelineViewUtils.svelte.js +38 -1
- package/dist/config/endpoints.d.ts +0 -7
- package/dist/config/endpoints.js +2 -10
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +6 -6
- package/dist/display/index.d.ts +0 -2
- package/dist/display/index.js +0 -6
- package/dist/editor/index.d.ts +19 -20
- package/dist/editor/index.js +25 -35
- package/dist/form/code.d.ts +25 -15
- package/dist/form/code.js +44 -41
- package/dist/form/fieldRegistry.d.ts +17 -13
- package/dist/form/fieldRegistry.js +32 -12
- package/dist/form/full.d.ts +17 -13
- package/dist/form/full.js +22 -27
- package/dist/form/index.d.ts +3 -3
- package/dist/form/index.js +3 -3
- package/dist/form/markdown.d.ts +13 -8
- package/dist/form/markdown.js +22 -23
- package/dist/helpers/proximityConnect.d.ts +3 -2
- package/dist/helpers/proximityConnect.js +2 -5
- package/dist/helpers/workflowEditorHelper.d.ts +12 -5
- package/dist/helpers/workflowEditorHelper.js +27 -25
- package/dist/index.d.ts +28 -24
- package/dist/index.js +27 -50
- package/dist/messages/defaults.d.ts +2 -5
- package/dist/messages/defaults.js +3 -6
- package/dist/messages/index.d.ts +0 -1
- package/dist/messages/index.js +0 -1
- package/dist/mocks/app-forms.d.ts +6 -2
- package/dist/mocks/app-forms.js +11 -4
- package/dist/openapi/v1/openapi.yaml +3 -3
- package/dist/playground/index.d.ts +2 -3
- package/dist/playground/index.js +2 -30
- package/dist/playground/mount.d.ts +15 -0
- package/dist/playground/mount.js +46 -20
- package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
- package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
- package/dist/registry/builtinFormats.d.ts +9 -18
- package/dist/registry/builtinFormats.js +9 -39
- package/dist/registry/builtinNodes.d.ts +0 -25
- package/dist/registry/builtinNodes.js +1 -50
- package/dist/registry/index.d.ts +3 -4
- package/dist/registry/index.js +4 -6
- package/dist/registry/nodeComponentRegistry.d.ts +182 -15
- package/dist/registry/nodeComponentRegistry.js +235 -17
- package/dist/registry/workflowFormatRegistry.d.ts +14 -9
- package/dist/registry/workflowFormatRegistry.js +24 -8
- package/dist/{schema → schemas}/index.d.ts +2 -2
- package/dist/{schema → schemas}/index.js +2 -2
- package/dist/schemas/v1/workflow.schema.json +3 -3
- package/dist/services/agentSpecExecutionService.js +0 -1
- package/dist/services/apiVariableService.d.ts +2 -1
- package/dist/services/apiVariableService.js +5 -22
- package/dist/services/autoSaveService.d.ts +7 -0
- package/dist/services/autoSaveService.js +6 -4
- package/dist/services/chatService.d.ts +8 -4
- package/dist/services/chatService.js +15 -15
- package/dist/services/draftStorage.d.ts +129 -13
- package/dist/services/draftStorage.js +185 -37
- package/dist/services/dynamicSchemaService.d.ts +2 -1
- package/dist/services/dynamicSchemaService.js +5 -22
- package/dist/services/globalSave.d.ts +13 -12
- package/dist/services/globalSave.js +29 -51
- package/dist/services/historyService.d.ts +9 -3
- package/dist/services/historyService.js +9 -3
- package/dist/services/interruptService.d.ts +14 -9
- package/dist/services/interruptService.js +27 -27
- package/dist/services/nodeExecutionService.d.ts +18 -3
- package/dist/services/nodeExecutionService.js +71 -45
- package/dist/services/playgroundService.d.ts +14 -9
- package/dist/services/playgroundService.js +31 -30
- package/dist/services/variableService.d.ts +2 -1
- package/dist/services/variableService.js +2 -2
- package/dist/services/workflowStorage.js +6 -6
- package/dist/stores/apiContext.d.ts +45 -0
- package/dist/stores/apiContext.js +65 -0
- package/dist/stores/categoriesStore.svelte.d.ts +28 -23
- package/dist/stores/categoriesStore.svelte.js +70 -64
- package/dist/stores/getInstance.svelte.d.ts +39 -0
- package/dist/stores/getInstance.svelte.js +65 -0
- package/dist/stores/historyStore.svelte.d.ts +77 -93
- package/dist/stores/historyStore.svelte.js +134 -160
- package/dist/stores/instanceContainer.svelte.d.ts +111 -0
- package/dist/stores/instanceContainer.svelte.js +114 -0
- package/dist/stores/interruptStore.svelte.d.ts +112 -82
- package/dist/stores/interruptStore.svelte.js +253 -226
- package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
- package/dist/stores/pipelinePanelStore.svelte.js +61 -14
- package/dist/stores/playgroundStore.svelte.d.ts +169 -222
- package/dist/stores/playgroundStore.svelte.js +515 -580
- package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
- package/dist/stores/portCoordinateStore.svelte.js +109 -98
- package/dist/stores/settingsStore.svelte.d.ts +4 -1
- package/dist/stores/settingsStore.svelte.js +47 -12
- package/dist/stores/workflowStore.svelte.d.ts +178 -213
- package/dist/stores/workflowStore.svelte.js +449 -501
- package/dist/stories/EdgeDecorator.svelte +5 -2
- package/dist/stories/NodeDecorator.svelte +5 -3
- package/dist/svelte-app.d.ts +60 -10
- package/dist/svelte-app.js +157 -53
- package/dist/types/events.d.ts +6 -3
- package/dist/types/index.d.ts +33 -3
- package/dist/types/navbar.d.ts +7 -0
- package/dist/types/playground.d.ts +18 -3
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.js +1 -0
- package/dist/utils/colors.d.ts +47 -21
- package/dist/utils/colors.js +69 -68
- package/dist/utils/connections.d.ts +9 -15
- package/dist/utils/connections.js +13 -32
- package/dist/utils/duration.d.ts +13 -0
- package/dist/utils/duration.js +45 -0
- package/dist/utils/icons.d.ts +5 -2
- package/dist/utils/icons.js +6 -5
- package/dist/utils/nodeSwap.d.ts +6 -2
- package/dist/utils/nodeSwap.js +62 -126
- package/dist/utils/nodeTypes.d.ts +17 -8
- package/dist/utils/nodeTypes.js +26 -19
- package/dist/utils/performanceUtils.js +7 -0
- package/package.json +6 -5
- package/dist/messages/deprecation.d.ts +0 -20
- package/dist/messages/deprecation.js +0 -33
- package/dist/registry/plugin.d.ts +0 -215
- package/dist/registry/plugin.js +0 -249
- package/dist/services/api.d.ts +0 -129
- package/dist/services/api.js +0 -217
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
import '@xyflow/svelte/dist/style.css';
|
|
9
9
|
import UniversalNode from '../components/UniversalNode.svelte';
|
|
10
10
|
import FlowDropEdge from '../components/FlowDropEdge.svelte';
|
|
11
|
-
import {
|
|
11
|
+
import { getDefaultInstance } from '../stores/instanceContainer.svelte.js';
|
|
12
|
+
import { provideInstance } from '../stores/getInstance.svelte.js';
|
|
12
13
|
import { EDGE_MARKER_SIZES } from '../config/constants.js';
|
|
13
14
|
|
|
14
15
|
interface Props {
|
|
@@ -33,7 +34,9 @@
|
|
|
33
34
|
targetHandleId = 'input'
|
|
34
35
|
}: Props = $props();
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
// Provide an instance so UniversalNode can resolve built-in node components
|
|
38
|
+
// (the registry is seeded with BUILTIN_NODE_COMPONENTS at construction).
|
|
39
|
+
provideInstance(getDefaultInstance());
|
|
37
40
|
|
|
38
41
|
const nodeTypes = {
|
|
39
42
|
universalNode: UniversalNode
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
import type { Node, ColorMode } from '@xyflow/svelte';
|
|
8
8
|
import '@xyflow/svelte/dist/style.css';
|
|
9
9
|
import UniversalNode from '../components/UniversalNode.svelte';
|
|
10
|
-
import {
|
|
10
|
+
import { getDefaultInstance } from '../stores/instanceContainer.svelte.js';
|
|
11
|
+
import { provideInstance } from '../stores/getInstance.svelte.js';
|
|
11
12
|
|
|
12
13
|
let { data, selected = false }: { data: Record<string, unknown>; selected?: boolean } = $props();
|
|
13
14
|
|
|
14
|
-
//
|
|
15
|
-
|
|
15
|
+
// Provide an instance so UniversalNode can resolve built-in node components
|
|
16
|
+
// (the registry is seeded with BUILTIN_NODE_COMPONENTS at construction).
|
|
17
|
+
provideInstance(getDefaultInstance());
|
|
16
18
|
|
|
17
19
|
const nodeTypes = {
|
|
18
20
|
universalNode: UniversalNode
|
package/dist/svelte-app.d.ts
CHANGED
|
@@ -12,7 +12,8 @@ import type { AuthProvider } from './types/auth.js';
|
|
|
12
12
|
import type { FlowDropEventHandlers, FlowDropFeatures } from './types/events.js';
|
|
13
13
|
import type { FlowDropTheme, FlowDropThemeName } from './types/theme.js';
|
|
14
14
|
import type { WorkflowFormatAdapter } from './registry/workflowFormatRegistry.js';
|
|
15
|
-
import './
|
|
15
|
+
import { type FlowDropInstance } from './stores/instanceContainer.svelte.js';
|
|
16
|
+
import { type DraftStorageOption } from './services/draftStorage.js';
|
|
16
17
|
import type { PartialSettings, SettingsCategory } from './types/settings.js';
|
|
17
18
|
import type { NavbarAction } from './types/navbar.js';
|
|
18
19
|
export type { NavbarAction };
|
|
@@ -38,20 +39,25 @@ export interface FlowDropMountOptions {
|
|
|
38
39
|
showNavbar?: boolean;
|
|
39
40
|
/** Disable the node sidebar */
|
|
40
41
|
disableSidebar?: boolean;
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Editor interaction mode. Replaces the former `readOnly` + `lockWorkflow`
|
|
44
|
+
* mount options (2.0). `'edit'` (default) allows editing; `'readonly'` and
|
|
45
|
+
* `'locked'` disable all canvas interaction (identical behavior today — see
|
|
46
|
+
* App's `mode` prop JSDoc for the full matrix). Migration: `readOnly: true`
|
|
47
|
+
* → `mode: 'readonly'`; `lockWorkflow: true` → `mode: 'locked'`.
|
|
48
|
+
* @default 'edit'
|
|
49
|
+
*/
|
|
50
|
+
mode?: 'edit' | 'readonly' | 'locked';
|
|
45
51
|
/** Pipeline ID for status display */
|
|
46
52
|
pipelineId?: string;
|
|
47
|
-
/** Node execution statuses */
|
|
48
|
-
nodeStatuses?: Record<string, 'pending' | 'running' | 'completed' | 'error'>;
|
|
49
53
|
/** Custom navbar title */
|
|
50
54
|
navbarTitle?: string;
|
|
51
55
|
/** Custom navbar actions */
|
|
52
56
|
navbarActions?: NavbarAction[];
|
|
53
57
|
/** Show settings gear icon in navbar */
|
|
54
58
|
showSettings?: boolean;
|
|
59
|
+
/** Show the "Connected" status indicator in the navbar (default: true) */
|
|
60
|
+
showStatus?: boolean;
|
|
55
61
|
/** Authentication provider for API requests */
|
|
56
62
|
authProvider?: AuthProvider;
|
|
57
63
|
/** Event handlers for workflow lifecycle */
|
|
@@ -60,8 +66,28 @@ export interface FlowDropMountOptions {
|
|
|
60
66
|
features?: FlowDropFeatures;
|
|
61
67
|
/** Initial settings overrides (theme, behavior, editor, ui, api) */
|
|
62
68
|
settings?: PartialSettings;
|
|
63
|
-
/** Custom storage key for
|
|
69
|
+
/** Custom storage key for workflow drafts */
|
|
64
70
|
draftStorageKey?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Where workflow drafts are persisted.
|
|
73
|
+
*
|
|
74
|
+
* - `'local'` (default): `localStorage` — drafts survive reloads and remain
|
|
75
|
+
* stored on the device even after the tab or browser is closed, until
|
|
76
|
+
* saved or cleared. Call `clearAllDrafts()` on logout for shared devices.
|
|
77
|
+
* - `'session'`: `sessionStorage` — drafts are scoped to the tab and removed
|
|
78
|
+
* when it closes (they do not survive crash-and-reopen).
|
|
79
|
+
* - A custom `DraftStorageAdapter` — note the adapter interface is
|
|
80
|
+
* synchronous, so it suits in-memory stores and write-through caches;
|
|
81
|
+
* async backends (IndexedDB, network) need a sync cache in front.
|
|
82
|
+
*
|
|
83
|
+
* The resolved adapter is captured per mount, so multiple FlowDrop
|
|
84
|
+
* instances on one page can use different backends.
|
|
85
|
+
*
|
|
86
|
+
* Note: neither built-in backend protects against same-origin script access
|
|
87
|
+
* (XSS). End users can additionally opt out of draft persistence at runtime
|
|
88
|
+
* via the "Store Drafts in Browser" behavior setting.
|
|
89
|
+
*/
|
|
90
|
+
draftStorage?: DraftStorageOption;
|
|
65
91
|
/** Custom workflow format adapters to register */
|
|
66
92
|
formatAdapters?: WorkflowFormatAdapter[];
|
|
67
93
|
/** Visual theme — named built-in ('default' | 'minimal') or custom theme object */
|
|
@@ -72,11 +98,32 @@ export interface FlowDropMountOptions {
|
|
|
72
98
|
showSettingsSyncButton?: boolean;
|
|
73
99
|
/** Show the reset buttons in the settings modal */
|
|
74
100
|
showSettingsResetButton?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Identifier for this FlowDrop instance.
|
|
103
|
+
*
|
|
104
|
+
* When omitted, the first mount on the page becomes the *default* instance
|
|
105
|
+
* (id `default`). Additional mounts get auto-generated ids (`fd-1`,
|
|
106
|
+
* `fd-2`, …). Every instance scopes its draft/panel storage keys by id
|
|
107
|
+
* (`flowdrop:draft:<id>:…`); the default instance migrates 1.x bare keys
|
|
108
|
+
* on first read.
|
|
109
|
+
*
|
|
110
|
+
* Pass an explicit id whenever you mount more than one editor with drafts
|
|
111
|
+
* enabled, so keys stay stable across page loads.
|
|
112
|
+
*/
|
|
113
|
+
instanceId?: string;
|
|
75
114
|
}
|
|
76
115
|
/**
|
|
77
116
|
* Return type for mounted FlowDrop app
|
|
78
117
|
*/
|
|
79
118
|
export interface MountedFlowDropApp {
|
|
119
|
+
/**
|
|
120
|
+
* This mount's state container — workflow, history, playground, interrupts,
|
|
121
|
+
* categories, and the rest. The 2.0 replacement for the removed
|
|
122
|
+
* module-level store APIs: where 1.x called `workflowActions.addNode(...)`
|
|
123
|
+
* or `historyService.undo()`, call `app.instance.workflow.addNode(...)` /
|
|
124
|
+
* `app.instance.history.undo()` on the mount that owns the editor.
|
|
125
|
+
*/
|
|
126
|
+
instance: FlowDropInstance;
|
|
80
127
|
/**
|
|
81
128
|
* Destroy the app and clean up resources
|
|
82
129
|
*/
|
|
@@ -102,7 +149,8 @@ export interface MountedFlowDropApp {
|
|
|
102
149
|
*/
|
|
103
150
|
export: () => void;
|
|
104
151
|
/**
|
|
105
|
-
* Clear all FlowDrop workflow drafts from
|
|
152
|
+
* Clear all FlowDrop workflow drafts from the configured draft storage
|
|
153
|
+
* (`localStorage` unless changed via the `draftStorage` mount option).
|
|
106
154
|
*
|
|
107
155
|
* Removes every key beginning with `flowdrop:draft:` plus the custom
|
|
108
156
|
* `draftStorageKey` configured at mount time (if any). Call this from
|
|
@@ -148,12 +196,14 @@ export declare function mountFlowDropApp(container: HTMLElement, options?: FlowD
|
|
|
148
196
|
* @returns Promise resolving to a MountedFlowDropApp instance
|
|
149
197
|
*/
|
|
150
198
|
export declare function mountWorkflowEditor(container: HTMLElement, options?: {
|
|
199
|
+
/** Initial workflow to load into the editor */
|
|
151
200
|
workflow?: Workflow;
|
|
152
|
-
nodes?: NodeMetadata[];
|
|
153
201
|
endpointConfig?: EndpointConfig;
|
|
154
202
|
portConfig?: PortConfig;
|
|
155
203
|
categories?: CategoryDefinition[];
|
|
156
204
|
authProvider?: AuthProvider;
|
|
205
|
+
/** Instance identifier — see {@link FlowDropMountOptions.instanceId}. */
|
|
206
|
+
instanceId?: string;
|
|
157
207
|
}): Promise<MountedFlowDropApp>;
|
|
158
208
|
/**
|
|
159
209
|
* Unmount a FlowDrop app
|
package/dist/svelte-app.js
CHANGED
|
@@ -9,19 +9,52 @@
|
|
|
9
9
|
import { mount, unmount } from 'svelte';
|
|
10
10
|
import WorkflowEditor from './components/WorkflowEditor.svelte';
|
|
11
11
|
import App from './components/App.svelte';
|
|
12
|
-
import { workflowFormatRegistry } from './registry/workflowFormatRegistry.js';
|
|
13
|
-
import './registry/builtinFormats.js';
|
|
14
|
-
import { initializePortCompatibility } from './utils/connections.js';
|
|
15
12
|
import { DEFAULT_PORT_CONFIG } from './config/defaultPortConfig.js';
|
|
16
13
|
import { fetchPortConfig } from './services/portConfigApi.js';
|
|
17
14
|
import { fetchCategories } from './services/categoriesApi.js';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { DraftAutoSaveManager, getDraftStorageKey, clearAllDrafts as clearAllDraftsFromStorage } from './services/draftStorage.js';
|
|
15
|
+
import { createFlowDropInstance, getDefaultInstance, DEFAULT_DRAFT_PREFIX } from './stores/instanceContainer.svelte.js';
|
|
16
|
+
import { DraftAutoSaveManager, getDraftStorageKey, migrateLegacyDraftKey, setDraftStorage, resolveDraftStorage, clearAllDrafts as clearAllDraftsFromStorage } from './services/draftStorage.js';
|
|
21
17
|
import { mergeFeatures } from './types/events.js';
|
|
22
|
-
import { initializeSettings } from './stores/settingsStore.svelte.js';
|
|
18
|
+
import { initializeSettings, getBehaviorSettings, onSettingsChange } from './stores/settingsStore.svelte.js';
|
|
23
19
|
import { logger } from './utils/logger.js';
|
|
24
20
|
import { globalSaveWorkflow, globalExportWorkflow } from './services/globalSave.js';
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Instance acquisition
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/** Whether a mount currently owns the page-default instance. */
|
|
25
|
+
let defaultInstanceClaimed = false;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the FlowDrop instance for a new mount.
|
|
28
|
+
*
|
|
29
|
+
* No `instanceId` + default unclaimed → the page-default instance (legacy
|
|
30
|
+
* storage keys, reachable via the module-level store APIs). Everything else
|
|
31
|
+
* gets its own isolated instance.
|
|
32
|
+
*/
|
|
33
|
+
function acquireInstance(instanceId) {
|
|
34
|
+
if (!instanceId && !defaultInstanceClaimed) {
|
|
35
|
+
defaultInstanceClaimed = true;
|
|
36
|
+
return { fd: getDefaultInstance(), isDefault: true };
|
|
37
|
+
}
|
|
38
|
+
return { fd: createFlowDropInstance({ id: instanceId }), isDefault: false };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Release a mount's instance on destroy.
|
|
42
|
+
*
|
|
43
|
+
* Non-default instances are fully destroyed (subscriptions, effect roots,
|
|
44
|
+
* callbacks). The default instance is only *released* — its callbacks are
|
|
45
|
+
* cleared but its reactive wiring stays alive, matching the pre-multi-instance
|
|
46
|
+
* behavior where module stores survived unmount and a later mount reused them.
|
|
47
|
+
*/
|
|
48
|
+
function releaseInstance(fd, isDefault) {
|
|
49
|
+
if (isDefault) {
|
|
50
|
+
fd.workflow.setOnDirtyStateChange(null);
|
|
51
|
+
fd.workflow.setOnWorkflowChange(null);
|
|
52
|
+
defaultInstanceClaimed = false;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
fd.destroy();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
25
58
|
/**
|
|
26
59
|
* Mount the full FlowDrop App with navbar, sidebars, and workflow editor
|
|
27
60
|
*
|
|
@@ -47,15 +80,25 @@ import { globalSaveWorkflow, globalExportWorkflow } from './services/globalSave.
|
|
|
47
80
|
* ```
|
|
48
81
|
*/
|
|
49
82
|
export async function mountFlowDropApp(container, options = {}) {
|
|
50
|
-
const { workflow, nodes, endpointConfig, portConfig, categories, height = '100vh', width = '100%', showNavbar = false, disableSidebar,
|
|
83
|
+
const { workflow, nodes, endpointConfig, portConfig, categories, height = '100vh', width = '100%', showNavbar = false, disableSidebar, mode, pipelineId, navbarTitle, navbarActions, showSettings, showStatus, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey, draftStorage, formatAdapters, theme, settingsCategories, showSettingsSyncButton, showSettingsResetButton, instanceId } = options;
|
|
84
|
+
// Per-instance state container — this is what allows multiple FlowDrop
|
|
85
|
+
// editors to coexist on one page without sharing workflow/history state.
|
|
86
|
+
const { fd, isDefault } = acquireInstance(instanceId);
|
|
51
87
|
// Register custom format adapters before mounting
|
|
52
88
|
if (formatAdapters) {
|
|
53
89
|
for (const adapter of formatAdapters) {
|
|
54
|
-
|
|
90
|
+
fd.formats.register(adapter);
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
// Merge features with defaults
|
|
58
94
|
const features = mergeFeatures(userFeatures);
|
|
95
|
+
// Resolve this instance's draft storage backend. The adapter is captured
|
|
96
|
+
// here and threaded into the draft manager and clearAllDrafts, so a later
|
|
97
|
+
// mount with a different backend cannot retarget this instance. The
|
|
98
|
+
// module-level default is also updated for the standalone helpers
|
|
99
|
+
// (last mount wins there — instance paths do not depend on it).
|
|
100
|
+
const draftStorageAdapter = resolveDraftStorage(draftStorage ?? 'local');
|
|
101
|
+
setDraftStorage(draftStorageAdapter);
|
|
59
102
|
// Apply initial settings overrides and initialize theme
|
|
60
103
|
await initializeSettings({
|
|
61
104
|
defaults: initialSettings
|
|
@@ -94,47 +137,64 @@ export async function mountFlowDropApp(container, options = {}) {
|
|
|
94
137
|
else if (!finalPortConfig) {
|
|
95
138
|
finalPortConfig = DEFAULT_PORT_CONFIG;
|
|
96
139
|
}
|
|
97
|
-
|
|
98
|
-
//
|
|
140
|
+
// Configure this instance's API context (endpoints + auth provider) so
|
|
141
|
+
// <App> and services resolve it via getInstance().api.
|
|
142
|
+
if (config) {
|
|
143
|
+
fd.api.configure(config, authProvider);
|
|
144
|
+
}
|
|
145
|
+
// Re-initialize this instance's port compatibility checker with the resolved
|
|
146
|
+
// config (it was seeded with DEFAULT_PORT_CONFIG at construction).
|
|
147
|
+
fd.portCompatibility.reinitialize(finalPortConfig);
|
|
148
|
+
// Initialize this instance's categories
|
|
99
149
|
if (categories) {
|
|
100
|
-
|
|
150
|
+
fd.categories.initialize(categories);
|
|
101
151
|
}
|
|
102
152
|
else if (config) {
|
|
103
153
|
try {
|
|
104
154
|
const fetchedCategories = await fetchCategories(config, authProvider);
|
|
105
|
-
|
|
155
|
+
fd.categories.initialize(fetchedCategories);
|
|
106
156
|
}
|
|
107
157
|
catch (error) {
|
|
108
158
|
logger.warn('Failed to fetch categories from API, using defaults:', error);
|
|
109
159
|
}
|
|
110
160
|
}
|
|
111
|
-
// Set up event handler callbacks in
|
|
161
|
+
// Set up event handler callbacks in this instance's store
|
|
112
162
|
if (eventHandlers?.onDirtyStateChange) {
|
|
113
|
-
setOnDirtyStateChange(eventHandlers.onDirtyStateChange);
|
|
163
|
+
fd.workflow.setOnDirtyStateChange(eventHandlers.onDirtyStateChange);
|
|
114
164
|
}
|
|
115
165
|
if (eventHandlers?.onWorkflowChange) {
|
|
116
|
-
setOnWorkflowChange(eventHandlers.onWorkflowChange);
|
|
166
|
+
fd.workflow.setOnWorkflowChange(eventHandlers.onWorkflowChange);
|
|
117
167
|
}
|
|
118
168
|
// Create the Svelte App component with configuration
|
|
119
169
|
const svelteApp = mount(App, {
|
|
120
170
|
target: container,
|
|
121
171
|
props: {
|
|
172
|
+
instance: fd,
|
|
122
173
|
workflow,
|
|
123
174
|
nodes,
|
|
124
175
|
height,
|
|
125
176
|
width,
|
|
126
177
|
showNavbar,
|
|
127
178
|
disableSidebar,
|
|
128
|
-
|
|
129
|
-
readOnly,
|
|
130
|
-
nodeStatuses,
|
|
179
|
+
mode,
|
|
131
180
|
pipelineId,
|
|
132
181
|
navbarTitle,
|
|
133
182
|
navbarActions,
|
|
134
183
|
showSettings,
|
|
184
|
+
showStatus,
|
|
135
185
|
endpointConfig: config,
|
|
136
186
|
authProvider,
|
|
137
|
-
eventHandlers
|
|
187
|
+
// App's event-handler props are flat (the grouped `eventHandlers` option
|
|
188
|
+
// is a mount-API convenience). onDirtyStateChange / onWorkflowChange are
|
|
189
|
+
// wired into the instance store above; onBeforeUnmount is handled in
|
|
190
|
+
// unmount() below; the remaining handlers map 1:1 to App props.
|
|
191
|
+
onBeforeSave: eventHandlers?.onBeforeSave,
|
|
192
|
+
onAfterSave: eventHandlers?.onAfterSave,
|
|
193
|
+
onSaveError: eventHandlers?.onSaveError,
|
|
194
|
+
onApiError: eventHandlers?.onApiError,
|
|
195
|
+
onWorkflowLoad: eventHandlers?.onWorkflowLoad,
|
|
196
|
+
onBeforeSwap: eventHandlers?.onBeforeSwap,
|
|
197
|
+
onAfterSwap: eventHandlers?.onAfterSwap,
|
|
138
198
|
features,
|
|
139
199
|
theme,
|
|
140
200
|
settingsCategories,
|
|
@@ -144,88 +204,119 @@ export async function mountFlowDropApp(container, options = {}) {
|
|
|
144
204
|
});
|
|
145
205
|
// Set up draft auto-save manager
|
|
146
206
|
let draftManager = null;
|
|
207
|
+
let unsubscribeDraftSettings = null;
|
|
147
208
|
if (features.autoSaveDraft) {
|
|
148
|
-
|
|
209
|
+
// Instance-scoped prefix: every instance (including the default) gets
|
|
210
|
+
// 'flowdrop:draft:<id>' sub-keys.
|
|
211
|
+
const storageKey = getDraftStorageKey(workflow?.id, customDraftKey, fd.storagePrefix);
|
|
212
|
+
// One-time migration: 1.x stored the page-default instance's drafts under
|
|
213
|
+
// the bare 'flowdrop:draft:<workflowId>' key. Move an existing draft to
|
|
214
|
+
// the scoped key so an upgrade mid-edit doesn't lose work.
|
|
215
|
+
if (fd.isDefault && !customDraftKey) {
|
|
216
|
+
migrateLegacyDraftKey(getDraftStorageKey(workflow?.id, undefined, DEFAULT_DRAFT_PREFIX), storageKey, draftStorageAdapter);
|
|
217
|
+
}
|
|
149
218
|
draftManager = new DraftAutoSaveManager({
|
|
150
219
|
storageKey,
|
|
151
220
|
interval: features.autoSaveDraftInterval,
|
|
152
221
|
enabled: features.autoSaveDraft,
|
|
153
|
-
getWorkflow:
|
|
154
|
-
isDirty
|
|
222
|
+
getWorkflow: () => fd.workflow.current,
|
|
223
|
+
isDirty: () => fd.workflow.isDirty,
|
|
224
|
+
// User-facing opt-out: the "Store Drafts in Browser" behavior setting.
|
|
225
|
+
// Checked on every save so toggling it takes effect immediately.
|
|
226
|
+
isPersistenceAllowed: () => getBehaviorSettings().storeDraftsInBrowser,
|
|
227
|
+
storage: draftStorageAdapter
|
|
155
228
|
});
|
|
156
229
|
draftManager.start();
|
|
230
|
+
// When the user opts out, also remove the draft already in storage.
|
|
231
|
+
unsubscribeDraftSettings = onSettingsChange((event) => {
|
|
232
|
+
if (event.category === 'behavior' &&
|
|
233
|
+
event.key === 'storeDraftsInBrowser' &&
|
|
234
|
+
event.newValue === false) {
|
|
235
|
+
draftManager?.clearDraft();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
157
238
|
}
|
|
158
239
|
// Store state for cleanup
|
|
159
240
|
const state = {
|
|
160
241
|
svelteApp,
|
|
161
242
|
draftManager,
|
|
162
|
-
eventHandlers: eventHandlers ?? null
|
|
243
|
+
eventHandlers: eventHandlers ?? null,
|
|
244
|
+
unsubscribeDraftSettings
|
|
163
245
|
};
|
|
164
246
|
// Create the mounted app interface
|
|
165
247
|
const mountedApp = {
|
|
248
|
+
instance: fd,
|
|
166
249
|
destroy: () => {
|
|
167
250
|
// Call onBeforeUnmount if provided
|
|
168
251
|
if (state.eventHandlers?.onBeforeUnmount) {
|
|
169
|
-
const currentWorkflow =
|
|
252
|
+
const currentWorkflow = fd.workflow.current;
|
|
170
253
|
if (currentWorkflow) {
|
|
171
|
-
state.eventHandlers.onBeforeUnmount(currentWorkflow, isDirty
|
|
254
|
+
state.eventHandlers.onBeforeUnmount(currentWorkflow, fd.workflow.isDirty);
|
|
172
255
|
}
|
|
173
256
|
}
|
|
174
257
|
// Stop draft manager
|
|
175
258
|
if (state.draftManager) {
|
|
176
|
-
// Save one final draft if dirty
|
|
177
|
-
if (isDirty
|
|
259
|
+
// Save one final draft if dirty (no-op when the user opted out)
|
|
260
|
+
if (fd.workflow.isDirty) {
|
|
178
261
|
state.draftManager.forceSave();
|
|
179
262
|
}
|
|
180
263
|
state.draftManager.stop();
|
|
181
264
|
}
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
265
|
+
// Stop listening for the draft opt-out setting
|
|
266
|
+
if (state.unsubscribeDraftSettings) {
|
|
267
|
+
state.unsubscribeDraftSettings();
|
|
268
|
+
state.unsubscribeDraftSettings = null;
|
|
269
|
+
}
|
|
270
|
+
// Release this mount's instance: clears its callbacks (and, for
|
|
271
|
+
// non-default instances, all subscriptions/effect roots) without
|
|
272
|
+
// touching sibling instances on the same page.
|
|
273
|
+
releaseInstance(fd, isDefault);
|
|
185
274
|
// Unmount Svelte app
|
|
186
275
|
unmount(state.svelteApp);
|
|
187
276
|
},
|
|
188
|
-
isDirty: () => isDirty
|
|
277
|
+
isDirty: () => fd.workflow.isDirty,
|
|
189
278
|
markAsSaved: () => {
|
|
190
|
-
markAsSaved();
|
|
279
|
+
fd.workflow.markAsSaved();
|
|
191
280
|
if (state.draftManager) {
|
|
192
281
|
// Migrate the draft key when the host confirms a save. New workflows start
|
|
193
|
-
// on '
|
|
282
|
+
// on '<prefix>:new', a key shared across all tabs. If the host has
|
|
194
283
|
// written the server-assigned ID back into the store before calling
|
|
195
284
|
// markAsSaved(), we can move to a unique per-workflow key and stop
|
|
196
285
|
// competing with other tabs that may also have unsaved new workflows.
|
|
197
286
|
// Skip when customDraftKey is set — the host manages that key explicitly.
|
|
198
287
|
if (!customDraftKey) {
|
|
199
|
-
const currentWorkflow =
|
|
288
|
+
const currentWorkflow = fd.workflow.current;
|
|
200
289
|
if (currentWorkflow?.id) {
|
|
201
|
-
state.draftManager.updateStorageKey(getDraftStorageKey(currentWorkflow.id));
|
|
290
|
+
state.draftManager.updateStorageKey(getDraftStorageKey(currentWorkflow.id, undefined, fd.storagePrefix));
|
|
202
291
|
}
|
|
203
292
|
}
|
|
204
293
|
state.draftManager.markAsSaved();
|
|
205
294
|
}
|
|
206
295
|
},
|
|
207
|
-
getWorkflow: () =>
|
|
296
|
+
getWorkflow: () => fd.workflow.current,
|
|
208
297
|
save: async () => {
|
|
209
298
|
await globalSaveWorkflow({
|
|
299
|
+
instance: fd,
|
|
210
300
|
onSaved: (saved) => {
|
|
211
301
|
// globalSaveWorkflow does not write the server-assigned ID back to the
|
|
212
|
-
// workflow store, so we cannot read it from
|
|
302
|
+
// workflow store, so we cannot read it from the store here.
|
|
213
303
|
// Instead we use the savedWorkflow returned by the API directly.
|
|
214
|
-
// This migrates '
|
|
304
|
+
// This migrates '<prefix>:new' to a unique per-workflow key
|
|
215
305
|
// immediately after the first save, preventing cross-tab collisions
|
|
216
306
|
// when multiple new workflows are open simultaneously.
|
|
217
307
|
if (state.draftManager && !customDraftKey && saved.id) {
|
|
218
|
-
state.draftManager.updateStorageKey(getDraftStorageKey(saved.id));
|
|
308
|
+
state.draftManager.updateStorageKey(getDraftStorageKey(saved.id, undefined, fd.storagePrefix));
|
|
219
309
|
}
|
|
220
310
|
}
|
|
221
311
|
});
|
|
222
312
|
},
|
|
223
313
|
export: () => {
|
|
224
|
-
globalExportWorkflow();
|
|
314
|
+
globalExportWorkflow({ instance: fd });
|
|
225
315
|
},
|
|
226
316
|
clearAllDrafts: () => {
|
|
227
317
|
const extras = customDraftKey ? [customDraftKey] : [];
|
|
228
|
-
|
|
318
|
+
// Clear this instance's backend, not whatever the module default is now
|
|
319
|
+
const removed = clearAllDraftsFromStorage(extras, draftStorageAdapter);
|
|
229
320
|
if (state.draftManager) {
|
|
230
321
|
state.draftManager.markAsSaved();
|
|
231
322
|
}
|
|
@@ -244,7 +335,9 @@ export async function mountFlowDropApp(container, options = {}) {
|
|
|
244
335
|
* @returns Promise resolving to a MountedFlowDropApp instance
|
|
245
336
|
*/
|
|
246
337
|
export async function mountWorkflowEditor(container, options = {}) {
|
|
247
|
-
const {
|
|
338
|
+
const { workflow, endpointConfig, portConfig, categories, authProvider, instanceId } = options;
|
|
339
|
+
// Per-instance state container (see mountFlowDropApp)
|
|
340
|
+
const { fd, isDefault } = acquireInstance(instanceId);
|
|
248
341
|
// Create endpoint configuration
|
|
249
342
|
let config;
|
|
250
343
|
if (endpointConfig) {
|
|
@@ -279,41 +372,52 @@ export async function mountWorkflowEditor(container, options = {}) {
|
|
|
279
372
|
else if (!finalPortConfig) {
|
|
280
373
|
finalPortConfig = DEFAULT_PORT_CONFIG;
|
|
281
374
|
}
|
|
282
|
-
|
|
283
|
-
|
|
375
|
+
// Configure this instance's API context and port compatibility checker.
|
|
376
|
+
if (config) {
|
|
377
|
+
fd.api.configure(config, authProvider);
|
|
378
|
+
}
|
|
379
|
+
fd.portCompatibility.reinitialize(finalPortConfig);
|
|
380
|
+
// Initialize this instance's categories
|
|
284
381
|
if (categories) {
|
|
285
|
-
|
|
382
|
+
fd.categories.initialize(categories);
|
|
286
383
|
}
|
|
287
384
|
else if (config) {
|
|
288
385
|
try {
|
|
289
386
|
const fetchedCategories = await fetchCategories(config, authProvider);
|
|
290
|
-
|
|
387
|
+
fd.categories.initialize(fetchedCategories);
|
|
291
388
|
}
|
|
292
389
|
catch (error) {
|
|
293
390
|
logger.warn('Failed to fetch categories from API, using defaults:', error);
|
|
294
391
|
}
|
|
295
392
|
}
|
|
393
|
+
// Seed the instance's workflow before mounting so the editor renders it
|
|
394
|
+
// immediately. (1.x accepted this option but silently ignored it.)
|
|
395
|
+
if (workflow) {
|
|
396
|
+
fd.workflow.initialize(workflow);
|
|
397
|
+
}
|
|
296
398
|
// Create the Svelte component
|
|
297
399
|
const svelteApp = mount(WorkflowEditor, {
|
|
298
400
|
target: container,
|
|
299
401
|
props: {
|
|
300
|
-
|
|
402
|
+
instance: fd,
|
|
301
403
|
endpointConfig: config
|
|
302
404
|
}
|
|
303
405
|
});
|
|
304
406
|
// Create the mounted app interface (simpler version)
|
|
305
407
|
const mountedApp = {
|
|
408
|
+
instance: fd,
|
|
306
409
|
destroy: () => {
|
|
410
|
+
releaseInstance(fd, isDefault);
|
|
307
411
|
unmount(svelteApp);
|
|
308
412
|
},
|
|
309
|
-
isDirty: () => isDirty
|
|
310
|
-
markAsSaved: () => markAsSaved(),
|
|
311
|
-
getWorkflow: () =>
|
|
413
|
+
isDirty: () => fd.workflow.isDirty,
|
|
414
|
+
markAsSaved: () => fd.workflow.markAsSaved(),
|
|
415
|
+
getWorkflow: () => fd.workflow.current,
|
|
312
416
|
save: async () => {
|
|
313
|
-
await globalSaveWorkflow();
|
|
417
|
+
await globalSaveWorkflow({ instance: fd });
|
|
314
418
|
},
|
|
315
419
|
export: () => {
|
|
316
|
-
globalExportWorkflow();
|
|
420
|
+
globalExportWorkflow({ instance: fd });
|
|
317
421
|
},
|
|
318
422
|
clearAllDrafts: () => clearAllDraftsFromStorage()
|
|
319
423
|
};
|
package/dist/types/events.d.ts
CHANGED
|
@@ -166,10 +166,13 @@ export interface FlowDropEventHandlers {
|
|
|
166
166
|
*/
|
|
167
167
|
export interface FlowDropFeatures {
|
|
168
168
|
/**
|
|
169
|
-
* Save drafts to
|
|
169
|
+
* Save drafts to browser storage automatically
|
|
170
170
|
*
|
|
171
171
|
* When enabled, FlowDrop will periodically save the current workflow
|
|
172
|
-
* to
|
|
172
|
+
* to draft storage (localStorage by default, configurable via the
|
|
173
|
+
* `draftStorage` mount option). This helps prevent data loss. End users
|
|
174
|
+
* can additionally opt out at runtime via the "Store Drafts in Browser"
|
|
175
|
+
* behavior setting.
|
|
173
176
|
*
|
|
174
177
|
* @default true
|
|
175
178
|
*/
|
|
@@ -177,7 +180,7 @@ export interface FlowDropFeatures {
|
|
|
177
180
|
/**
|
|
178
181
|
* Auto-save interval in milliseconds
|
|
179
182
|
*
|
|
180
|
-
* How often to save drafts to
|
|
183
|
+
* How often to save drafts to storage when autoSaveDraft is enabled.
|
|
181
184
|
*
|
|
182
185
|
* @default 30000 (30 seconds)
|
|
183
186
|
*/
|
package/dist/types/index.d.ts
CHANGED
|
@@ -208,7 +208,7 @@ export type BuiltinNodeType = 'note' | 'simple' | 'square' | 'atom' | 'tool' | '
|
|
|
208
208
|
* Includes built-in types and allows custom registered types.
|
|
209
209
|
*
|
|
210
210
|
* Built-in types: note, simple, square, tool, gateway, terminal, default
|
|
211
|
-
* Custom types: Any string registered via
|
|
211
|
+
* Custom types: Any string registered via fd.nodes
|
|
212
212
|
*
|
|
213
213
|
* @example
|
|
214
214
|
* ```typescript
|
|
@@ -1188,8 +1188,9 @@ export interface Workflow {
|
|
|
1188
1188
|
description?: string;
|
|
1189
1189
|
nodes: WorkflowNode[];
|
|
1190
1190
|
edges: WorkflowEdge[];
|
|
1191
|
-
metadata
|
|
1192
|
-
version
|
|
1191
|
+
metadata: {
|
|
1192
|
+
/** Workflow schema format version — identifies the document format, not the workflow's own revision. */
|
|
1193
|
+
schemaVersion: string;
|
|
1193
1194
|
createdAt: string;
|
|
1194
1195
|
updatedAt: string;
|
|
1195
1196
|
author?: string;
|
|
@@ -1243,6 +1244,31 @@ export interface PipelineViewDef {
|
|
|
1243
1244
|
/** Svelte component that receives PipelineViewProps */
|
|
1244
1245
|
component: Component<PipelineViewProps>;
|
|
1245
1246
|
}
|
|
1247
|
+
/**
|
|
1248
|
+
* One job execution of a node within a pipeline run.
|
|
1249
|
+
*
|
|
1250
|
+
* Loop-orchestrated workflows create one job per iteration for the same
|
|
1251
|
+
* node (labels carry an iteration suffix, e.g. "Invoke tool #2"), so a node
|
|
1252
|
+
* can have several of these per run.
|
|
1253
|
+
*/
|
|
1254
|
+
export interface NodeJobExecution {
|
|
1255
|
+
/** Job entity ID */
|
|
1256
|
+
id?: string;
|
|
1257
|
+
/** Job label, carries the iteration suffix (e.g. "Invoke tool #2") */
|
|
1258
|
+
label?: string;
|
|
1259
|
+
/** Job status */
|
|
1260
|
+
status: NodeExecutionStatus;
|
|
1261
|
+
/** ISO timestamp the job started, if it ran */
|
|
1262
|
+
started?: string;
|
|
1263
|
+
/** ISO timestamp the job completed, if it finished */
|
|
1264
|
+
completed?: string;
|
|
1265
|
+
/** Execution duration in milliseconds, if the job ran to completion */
|
|
1266
|
+
executionTime?: number;
|
|
1267
|
+
/** Precise execution duration in microseconds, when the backend provides it */
|
|
1268
|
+
executionTimeUs?: number;
|
|
1269
|
+
/** Error message if the job failed */
|
|
1270
|
+
error?: string;
|
|
1271
|
+
}
|
|
1246
1272
|
/**
|
|
1247
1273
|
* Node execution tracking information
|
|
1248
1274
|
*/
|
|
@@ -1255,12 +1281,16 @@ export interface NodeExecutionInfo {
|
|
|
1255
1281
|
lastExecuted?: string;
|
|
1256
1282
|
/** Last execution duration in milliseconds */
|
|
1257
1283
|
lastExecutionDuration?: number;
|
|
1284
|
+
/** Precise last execution duration in microseconds, when the backend provides it */
|
|
1285
|
+
lastExecutionDurationUs?: number;
|
|
1258
1286
|
/** Last error message if execution failed */
|
|
1259
1287
|
lastError?: string;
|
|
1260
1288
|
/** Whether the node is currently being executed */
|
|
1261
1289
|
isExecuting: boolean;
|
|
1262
1290
|
/** Execution output data (e.g., active branches for gateway nodes) */
|
|
1263
1291
|
output?: Record<string, unknown>;
|
|
1292
|
+
/** Per-job execution history (loop iterations), in pipeline order */
|
|
1293
|
+
jobs?: NodeJobExecution[];
|
|
1264
1294
|
}
|
|
1265
1295
|
/**
|
|
1266
1296
|
* Workflow execution status
|
package/dist/types/navbar.d.ts
CHANGED
|
@@ -11,4 +11,11 @@ export interface NavbarAction {
|
|
|
11
11
|
onclick?: (event: Event) => void;
|
|
12
12
|
/** If true, opens link in new tab with `rel="noopener noreferrer"`. */
|
|
13
13
|
external?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Optional group label. Items sharing the same `group` cluster together
|
|
16
|
+
* under a header inside the flyout dropdown. Ungrouped items render first.
|
|
17
|
+
* Group order follows first occurrence in the array. Ignored when the
|
|
18
|
+
* navbar is in split mode (the inline row of buttons).
|
|
19
|
+
*/
|
|
20
|
+
group?: string;
|
|
14
21
|
}
|