@flowdrop/flowdrop 1.3.0 → 1.5.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 +68 -24
- package/dist/adapters/WorkflowAdapter.js +2 -22
- package/dist/adapters/agentspec/autoLayout.d.ts +51 -5
- package/dist/adapters/agentspec/autoLayout.js +120 -23
- package/dist/chat/commandClassifier.d.ts +19 -0
- package/dist/chat/commandClassifier.js +30 -0
- package/dist/chat/index.d.ts +27 -0
- package/dist/chat/index.js +32 -0
- package/dist/chat/responseParser.d.ts +21 -0
- package/dist/chat/responseParser.js +87 -0
- package/dist/commands/batch.d.ts +18 -0
- package/dist/commands/batch.js +56 -0
- package/dist/commands/executor.d.ts +37 -0
- package/dist/commands/executor.js +1044 -0
- package/dist/commands/index.d.ts +14 -0
- package/dist/commands/index.js +17 -0
- package/dist/commands/parser.d.ts +16 -0
- package/dist/commands/parser.js +278 -0
- package/dist/commands/positioner.d.ts +19 -0
- package/dist/commands/positioner.js +33 -0
- package/dist/commands/storeIntegration.svelte.d.ts +16 -0
- package/dist/commands/storeIntegration.svelte.js +67 -0
- package/dist/commands/types.d.ts +343 -0
- package/dist/commands/types.js +45 -0
- package/dist/components/App.svelte +431 -17
- package/dist/components/App.svelte.d.ts +10 -0
- package/dist/components/CanvasBanner.stories.svelte +6 -2
- package/dist/components/CanvasController.svelte +38 -0
- package/dist/components/CanvasController.svelte.d.ts +32 -0
- package/dist/components/ConfigMappingRow.svelte +130 -0
- package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
- package/dist/components/ConfigPanel.svelte +56 -7
- package/dist/components/ConfigPanel.svelte.d.ts +2 -0
- package/dist/components/FlowDropEdge.svelte +8 -57
- package/dist/components/Logo.svelte +14 -14
- package/dist/components/LogsSidebar.svelte +5 -5
- package/dist/components/Navbar.svelte +58 -10
- package/dist/components/Navbar.svelte.d.ts +7 -0
- package/dist/components/NodeSidebar.svelte +238 -362
- package/dist/components/NodeSwapPicker.svelte +537 -0
- package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
- package/dist/components/PortMappingRow.svelte +209 -0
- package/dist/components/PortMappingRow.svelte.d.ts +12 -0
- package/dist/components/SwapMappingEditor.svelte +550 -0
- package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
- package/dist/components/WorkflowEditor.svelte +99 -4
- package/dist/components/WorkflowEditor.svelte.d.ts +8 -0
- package/dist/components/chat/AIChatPanel.svelte +658 -0
- package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
- package/dist/components/chat/CommandPreview.svelte +184 -0
- package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
- package/dist/components/console/CommandConsole.stories.svelte +93 -0
- package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
- package/dist/components/console/CommandConsole.svelte +259 -0
- package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
- package/dist/components/console/ConsoleAutocomplete.svelte +139 -0
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
- package/dist/components/console/ConsoleInput.svelte +712 -0
- package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
- package/dist/components/console/ConsoleOutput.svelte +121 -0
- package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
- package/dist/components/console/formatters.d.ts +26 -0
- package/dist/components/console/formatters.js +118 -0
- package/dist/components/interrupt/index.d.ts +1 -0
- package/dist/components/interrupt/index.js +1 -0
- package/dist/components/nodes/SimpleNode.stories.svelte +64 -0
- package/dist/components/nodes/SimpleNode.svelte +27 -11
- package/dist/components/nodes/SquareNode.stories.svelte +45 -0
- package/dist/components/nodes/SquareNode.svelte +27 -11
- package/dist/components/nodes/WorkflowNode.stories.svelte +63 -0
- package/dist/config/endpoints.d.ts +8 -0
- package/dist/config/endpoints.js +5 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +9 -0
- package/dist/editor/index.d.ts +3 -1
- package/dist/editor/index.js +4 -2
- package/dist/helpers/proximityConnect.js +8 -1
- package/dist/helpers/workflowEditorHelper.d.ts +3 -53
- package/dist/helpers/workflowEditorHelper.js +13 -228
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +1 -1
- package/dist/schemas/v1/workflow.schema.json +107 -22
- package/dist/services/chatService.d.ts +65 -0
- package/dist/services/chatService.js +131 -0
- package/dist/services/historyService.d.ts +6 -4
- package/dist/services/historyService.js +21 -6
- package/dist/skins/slate.js +16 -0
- package/dist/stores/interruptStore.svelte.js +6 -1
- package/dist/stores/playgroundStore.svelte.d.ts +1 -1
- package/dist/stores/playgroundStore.svelte.js +11 -2
- package/dist/stores/portCoordinateStore.svelte.d.ts +4 -0
- package/dist/stores/portCoordinateStore.svelte.js +20 -26
- package/dist/stores/workflowStore.svelte.d.ts +31 -2
- package/dist/stores/workflowStore.svelte.js +84 -64
- package/dist/stories/EdgeDecorator.svelte +4 -4
- package/dist/styles/base.css +48 -0
- package/dist/svelte-app.d.ts +7 -1
- package/dist/svelte-app.js +4 -1
- package/dist/types/chat.d.ts +63 -0
- package/dist/types/chat.js +9 -0
- package/dist/types/events.d.ts +28 -2
- package/dist/types/events.js +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/settings.d.ts +6 -0
- package/dist/types/settings.js +3 -0
- package/dist/utils/edgeStyling.d.ts +42 -0
- package/dist/utils/edgeStyling.js +176 -0
- package/dist/utils/nodeIds.d.ts +31 -0
- package/dist/utils/nodeIds.js +42 -0
- package/dist/utils/nodeSwap.d.ts +221 -0
- package/dist/utils/nodeSwap.js +686 -0
- package/package.json +6 -1
- package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
- package/dist/helpers/nodeLayoutHelper.js +0 -19
|
@@ -126,27 +126,19 @@ export function updateNodePortCoordinates(node, getInternalNode) {
|
|
|
126
126
|
const internalNode = getInternalNode(node.id);
|
|
127
127
|
if (!internalNode)
|
|
128
128
|
return;
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const keysToDelete = untrack(() => {
|
|
134
|
-
const keys = [];
|
|
129
|
+
// Build a new map with all entries except this node's, then add recomputed entries.
|
|
130
|
+
// Single assignment fires one reactive notification instead of N deletes + M sets.
|
|
131
|
+
const newMap = new SvelteMap();
|
|
132
|
+
untrack(() => {
|
|
135
133
|
for (const [key, coord] of coordinates) {
|
|
136
|
-
if (coord.nodeId
|
|
137
|
-
|
|
138
|
-
}
|
|
134
|
+
if (coord.nodeId !== node.id)
|
|
135
|
+
newMap.set(key, coord);
|
|
139
136
|
}
|
|
140
|
-
return keys;
|
|
141
137
|
});
|
|
142
|
-
for (const
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
// Add new entries
|
|
146
|
-
const coords = computeNodePortCoordinates(node, internalNode);
|
|
147
|
-
for (const coord of coords) {
|
|
148
|
-
coordinates.set(coord.handleId, coord);
|
|
138
|
+
for (const coord of computeNodePortCoordinates(node, internalNode)) {
|
|
139
|
+
newMap.set(coord.handleId, coord);
|
|
149
140
|
}
|
|
141
|
+
coordinates = newMap;
|
|
150
142
|
}
|
|
151
143
|
/**
|
|
152
144
|
* Remove all coordinates for a node (on node delete).
|
|
@@ -154,18 +146,20 @@ export function updateNodePortCoordinates(node, getInternalNode) {
|
|
|
154
146
|
* @param nodeId - ID of the node to remove
|
|
155
147
|
*/
|
|
156
148
|
export function removeNodePortCoordinates(nodeId) {
|
|
157
|
-
const
|
|
158
|
-
|
|
149
|
+
const newMap = new SvelteMap();
|
|
150
|
+
untrack(() => {
|
|
159
151
|
for (const [key, coord] of coordinates) {
|
|
160
|
-
if (coord.nodeId
|
|
161
|
-
|
|
162
|
-
}
|
|
152
|
+
if (coord.nodeId !== nodeId)
|
|
153
|
+
newMap.set(key, coord);
|
|
163
154
|
}
|
|
164
|
-
return keys;
|
|
165
155
|
});
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
156
|
+
coordinates = newMap;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Clear all port coordinates (lifecycle cleanup).
|
|
160
|
+
*/
|
|
161
|
+
export function clearPortCoordinates() {
|
|
162
|
+
coordinates = new SvelteMap();
|
|
169
163
|
}
|
|
170
164
|
/**
|
|
171
165
|
* Get coordinates for a specific handle.
|
|
@@ -22,6 +22,10 @@ export declare function getWorkflowStore(): Workflow | null;
|
|
|
22
22
|
/**
|
|
23
23
|
* Get the current dirty state reactively
|
|
24
24
|
*
|
|
25
|
+
* Reads both _editVersion and _savedVersion, so Svelte tracks them
|
|
26
|
+
* as reactive dependencies — any component using this will re-render
|
|
27
|
+
* when dirty state changes.
|
|
28
|
+
*
|
|
25
29
|
* @returns true if there are unsaved changes
|
|
26
30
|
*/
|
|
27
31
|
export declare function getIsDirty(): boolean;
|
|
@@ -121,9 +125,10 @@ export declare function setOnDirtyStateChange(callback: ((isDirty: boolean) => v
|
|
|
121
125
|
*/
|
|
122
126
|
export declare function setOnWorkflowChange(callback: ((workflow: Workflow, changeType: WorkflowChangeType) => void) | null): void;
|
|
123
127
|
/**
|
|
124
|
-
* Mark the current workflow state as saved
|
|
128
|
+
* Mark the current workflow state as saved.
|
|
125
129
|
*
|
|
126
|
-
*
|
|
130
|
+
* Captures the current edit version so isDirty becomes false.
|
|
131
|
+
* Call this after a successful backend save.
|
|
127
132
|
*/
|
|
128
133
|
export declare function markAsSaved(): void;
|
|
129
134
|
/**
|
|
@@ -132,6 +137,19 @@ export declare function markAsSaved(): void;
|
|
|
132
137
|
* @returns true if there are unsaved changes
|
|
133
138
|
*/
|
|
134
139
|
export declare function isDirty(): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Get the current edit version.
|
|
142
|
+
*
|
|
143
|
+
* Use this for the save verification protocol:
|
|
144
|
+
* 1. Before save: `const v = getEditVersion()`
|
|
145
|
+
* 2. Include `v` in the save request payload
|
|
146
|
+
* 3. Backend echoes `v` in the response
|
|
147
|
+
* 4. If echoed version matches: `markAsSaved()`
|
|
148
|
+
* 5. If not: the save didn't persist the version you submitted — reset from backend response
|
|
149
|
+
*
|
|
150
|
+
* @returns The current monotonic edit version
|
|
151
|
+
*/
|
|
152
|
+
export declare function getEditVersion(): number;
|
|
135
153
|
/**
|
|
136
154
|
* Enable or disable history recording
|
|
137
155
|
*
|
|
@@ -246,6 +264,17 @@ export declare const workflowActions: {
|
|
|
246
264
|
description?: string;
|
|
247
265
|
metadata?: Partial<Workflow["metadata"]>;
|
|
248
266
|
}) => void;
|
|
267
|
+
/**
|
|
268
|
+
* Swap a node — atomically replaces nodes and edges with a descriptive history entry.
|
|
269
|
+
*
|
|
270
|
+
* Unlike batchUpdate, this uses `"node_swap"` as the change type and
|
|
271
|
+
* records a meaningful description for the undo history.
|
|
272
|
+
*/
|
|
273
|
+
swapNode: (updates: {
|
|
274
|
+
nodes: WorkflowNode[];
|
|
275
|
+
edges: WorkflowEdge[];
|
|
276
|
+
description?: string;
|
|
277
|
+
}) => void;
|
|
249
278
|
/**
|
|
250
279
|
* Push current state to history manually
|
|
251
280
|
*
|
|
@@ -34,21 +34,23 @@ function buildMetadata(existing, updates) {
|
|
|
34
34
|
/** Global workflow state */
|
|
35
35
|
let workflowState = $state(null);
|
|
36
36
|
// =========================================================================
|
|
37
|
-
// Dirty State Tracking
|
|
37
|
+
// Dirty State Tracking (Version Counter)
|
|
38
38
|
// =========================================================================
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* Monotonic edit version — bumps on every mutation action.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* Used for two purposes:
|
|
43
|
+
* 1. O(1) dirty detection: isDirty = _editVersion !== _savedVersion
|
|
44
|
+
* 2. Save verification protocol: include the version in the save request,
|
|
45
|
+
* backend echoes it back. If the echoed version doesn't match, the save
|
|
46
|
+
* didn't persist the version the client submitted.
|
|
44
47
|
*/
|
|
45
|
-
let
|
|
48
|
+
let _editVersion = $state(0);
|
|
46
49
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Used to compare current state with saved state.
|
|
50
|
+
* Edit version captured at the last successful save.
|
|
51
|
+
* When _editVersion === _savedVersion, the workflow is clean.
|
|
50
52
|
*/
|
|
51
|
-
let
|
|
53
|
+
let _savedVersion = $state(0);
|
|
52
54
|
/**
|
|
53
55
|
* Callback for dirty state changes
|
|
54
56
|
*
|
|
@@ -87,10 +89,14 @@ export function getWorkflowStore() {
|
|
|
87
89
|
/**
|
|
88
90
|
* Get the current dirty state reactively
|
|
89
91
|
*
|
|
92
|
+
* Reads both _editVersion and _savedVersion, so Svelte tracks them
|
|
93
|
+
* as reactive dependencies — any component using this will re-render
|
|
94
|
+
* when dirty state changes.
|
|
95
|
+
*
|
|
90
96
|
* @returns true if there are unsaved changes
|
|
91
97
|
*/
|
|
92
98
|
export function getIsDirty() {
|
|
93
|
-
return
|
|
99
|
+
return _editVersion !== _savedVersion;
|
|
94
100
|
}
|
|
95
101
|
/**
|
|
96
102
|
* Get the workflow ID reactively
|
|
@@ -239,53 +245,21 @@ export function setOnWorkflowChange(callback) {
|
|
|
239
245
|
// Internal Helpers
|
|
240
246
|
// =========================================================================
|
|
241
247
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* @param workflow - The workflow to snapshot
|
|
245
|
-
* @returns A JSON string representation for comparison
|
|
246
|
-
*/
|
|
247
|
-
function createSnapshot(workflow) {
|
|
248
|
-
if (!workflow)
|
|
249
|
-
return null;
|
|
250
|
-
// Only include the parts that matter for "dirty" detection
|
|
251
|
-
const toSnapshot = {
|
|
252
|
-
name: workflow.name,
|
|
253
|
-
description: workflow.description,
|
|
254
|
-
nodes: workflow.nodes.map((n) => ({
|
|
255
|
-
id: n.id,
|
|
256
|
-
position: n.position,
|
|
257
|
-
data: {
|
|
258
|
-
label: n.data.label,
|
|
259
|
-
config: n.data.config,
|
|
260
|
-
},
|
|
261
|
-
})),
|
|
262
|
-
edges: workflow.edges.map((e) => ({
|
|
263
|
-
id: e.id,
|
|
264
|
-
source: e.source,
|
|
265
|
-
target: e.target,
|
|
266
|
-
sourceHandle: e.sourceHandle,
|
|
267
|
-
targetHandle: e.targetHandle,
|
|
268
|
-
})),
|
|
269
|
-
};
|
|
270
|
-
return JSON.stringify(toSnapshot);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Update dirty state based on current workflow
|
|
274
|
-
*
|
|
275
|
-
* Compares current workflow with saved snapshot.
|
|
248
|
+
* Bump the edit version and notify dirty state change if needed.
|
|
249
|
+
* Called by every mutation action.
|
|
276
250
|
*/
|
|
277
|
-
function
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (
|
|
281
|
-
isDirtyState = newIsDirty;
|
|
251
|
+
function bumpVersion() {
|
|
252
|
+
_editVersion++;
|
|
253
|
+
// Dirty state just flipped from clean → dirty
|
|
254
|
+
if (_editVersion - 1 === _savedVersion) {
|
|
282
255
|
if (onDirtyStateChangeCallback) {
|
|
283
|
-
onDirtyStateChangeCallback(
|
|
256
|
+
onDirtyStateChangeCallback(true);
|
|
284
257
|
}
|
|
285
258
|
}
|
|
286
259
|
}
|
|
287
260
|
/**
|
|
288
|
-
*
|
|
261
|
+
* Notify external listeners of a workflow change.
|
|
262
|
+
* Does NOT bump the version — callers that mutate must call bumpVersion() explicitly.
|
|
289
263
|
*
|
|
290
264
|
* @param changeType - The type of change that occurred
|
|
291
265
|
*/
|
|
@@ -293,17 +267,17 @@ function notifyWorkflowChange(changeType) {
|
|
|
293
267
|
if (workflowState && onWorkflowChangeCallback) {
|
|
294
268
|
onWorkflowChangeCallback(workflowState, changeType);
|
|
295
269
|
}
|
|
296
|
-
updateDirtyState();
|
|
297
270
|
}
|
|
298
271
|
/**
|
|
299
|
-
* Mark the current workflow state as saved
|
|
272
|
+
* Mark the current workflow state as saved.
|
|
300
273
|
*
|
|
301
|
-
*
|
|
274
|
+
* Captures the current edit version so isDirty becomes false.
|
|
275
|
+
* Call this after a successful backend save.
|
|
302
276
|
*/
|
|
303
277
|
export function markAsSaved() {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (onDirtyStateChangeCallback) {
|
|
278
|
+
const wasDirty = _editVersion !== _savedVersion;
|
|
279
|
+
_savedVersion = _editVersion;
|
|
280
|
+
if (wasDirty && onDirtyStateChangeCallback) {
|
|
307
281
|
onDirtyStateChangeCallback(false);
|
|
308
282
|
}
|
|
309
283
|
}
|
|
@@ -313,7 +287,22 @@ export function markAsSaved() {
|
|
|
313
287
|
* @returns true if there are unsaved changes
|
|
314
288
|
*/
|
|
315
289
|
export function isDirty() {
|
|
316
|
-
return
|
|
290
|
+
return _editVersion !== _savedVersion;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get the current edit version.
|
|
294
|
+
*
|
|
295
|
+
* Use this for the save verification protocol:
|
|
296
|
+
* 1. Before save: `const v = getEditVersion()`
|
|
297
|
+
* 2. Include `v` in the save request payload
|
|
298
|
+
* 3. Backend echoes `v` in the response
|
|
299
|
+
* 4. If echoed version matches: `markAsSaved()`
|
|
300
|
+
* 5. If not: the save didn't persist the version you submitted — reset from backend response
|
|
301
|
+
*
|
|
302
|
+
* @returns The current monotonic edit version
|
|
303
|
+
*/
|
|
304
|
+
export function getEditVersion() {
|
|
305
|
+
return _editVersion;
|
|
317
306
|
}
|
|
318
307
|
/**
|
|
319
308
|
* Enable or disable history recording
|
|
@@ -390,7 +379,7 @@ function hasWorkflowDataChanged(currentWorkflow, newNodes, newEdges) {
|
|
|
390
379
|
if (currentNode.position.x !== newNode.position.x ||
|
|
391
380
|
currentNode.position.y !== newNode.position.y)
|
|
392
381
|
return true;
|
|
393
|
-
if (
|
|
382
|
+
if (currentNode.data !== newNode.data)
|
|
394
383
|
return true;
|
|
395
384
|
}
|
|
396
385
|
// Check if edges have changed
|
|
@@ -426,9 +415,9 @@ export const workflowActions = {
|
|
|
426
415
|
*/
|
|
427
416
|
initialize: (workflow) => {
|
|
428
417
|
workflowState = workflow;
|
|
429
|
-
//
|
|
430
|
-
|
|
431
|
-
|
|
418
|
+
// Reset version counters — workflow is "clean" after initialization
|
|
419
|
+
_editVersion = 0;
|
|
420
|
+
_savedVersion = 0;
|
|
432
421
|
if (onDirtyStateChangeCallback) {
|
|
433
422
|
onDirtyStateChangeCallback(false);
|
|
434
423
|
}
|
|
@@ -443,6 +432,7 @@ export const workflowActions = {
|
|
|
443
432
|
*/
|
|
444
433
|
updateWorkflow: (workflow) => {
|
|
445
434
|
workflowState = workflow;
|
|
435
|
+
bumpVersion();
|
|
446
436
|
notifyWorkflowChange("metadata");
|
|
447
437
|
},
|
|
448
438
|
/**
|
|
@@ -453,6 +443,7 @@ export const workflowActions = {
|
|
|
453
443
|
restoreFromHistory: (workflow) => {
|
|
454
444
|
isRestoringFromHistory = true;
|
|
455
445
|
workflowState = workflow;
|
|
446
|
+
bumpVersion();
|
|
456
447
|
notifyWorkflowChange("metadata");
|
|
457
448
|
isRestoringFromHistory = false;
|
|
458
449
|
},
|
|
@@ -476,6 +467,7 @@ export const workflowActions = {
|
|
|
476
467
|
updateNumber: (workflowState.metadata?.updateNumber ?? 0) + 1,
|
|
477
468
|
}),
|
|
478
469
|
};
|
|
470
|
+
bumpVersion();
|
|
479
471
|
notifyWorkflowChange("node_move");
|
|
480
472
|
},
|
|
481
473
|
/**
|
|
@@ -498,6 +490,7 @@ export const workflowActions = {
|
|
|
498
490
|
updateNumber: (workflowState.metadata?.updateNumber ?? 0) + 1,
|
|
499
491
|
}),
|
|
500
492
|
};
|
|
493
|
+
bumpVersion();
|
|
501
494
|
notifyWorkflowChange("edge_add");
|
|
502
495
|
},
|
|
503
496
|
/**
|
|
@@ -511,6 +504,7 @@ export const workflowActions = {
|
|
|
511
504
|
name,
|
|
512
505
|
metadata: buildMetadata(workflowState.metadata),
|
|
513
506
|
};
|
|
507
|
+
bumpVersion();
|
|
514
508
|
notifyWorkflowChange("name");
|
|
515
509
|
},
|
|
516
510
|
/**
|
|
@@ -525,6 +519,7 @@ export const workflowActions = {
|
|
|
525
519
|
nodes: [...workflowState.nodes, node],
|
|
526
520
|
metadata: buildMetadata(workflowState.metadata),
|
|
527
521
|
};
|
|
522
|
+
bumpVersion();
|
|
528
523
|
notifyWorkflowChange("node_add");
|
|
529
524
|
},
|
|
530
525
|
/**
|
|
@@ -543,6 +538,7 @@ export const workflowActions = {
|
|
|
543
538
|
edges: workflowState.edges.filter((edge) => edge.source !== nodeId && edge.target !== nodeId),
|
|
544
539
|
metadata: buildMetadata(workflowState.metadata),
|
|
545
540
|
};
|
|
541
|
+
bumpVersion();
|
|
546
542
|
notifyWorkflowChange("node_remove");
|
|
547
543
|
},
|
|
548
544
|
/**
|
|
@@ -557,6 +553,7 @@ export const workflowActions = {
|
|
|
557
553
|
edges: [...workflowState.edges, edge],
|
|
558
554
|
metadata: buildMetadata(workflowState.metadata),
|
|
559
555
|
};
|
|
556
|
+
bumpVersion();
|
|
560
557
|
notifyWorkflowChange("edge_add");
|
|
561
558
|
},
|
|
562
559
|
/**
|
|
@@ -571,6 +568,7 @@ export const workflowActions = {
|
|
|
571
568
|
edges: workflowState.edges.filter((edge) => edge.id !== edgeId),
|
|
572
569
|
metadata: buildMetadata(workflowState.metadata),
|
|
573
570
|
};
|
|
571
|
+
bumpVersion();
|
|
574
572
|
notifyWorkflowChange("edge_remove");
|
|
575
573
|
},
|
|
576
574
|
/**
|
|
@@ -587,6 +585,7 @@ export const workflowActions = {
|
|
|
587
585
|
nodes: workflowState.nodes.map((node) => node.id === nodeId ? { ...node, ...updates } : node),
|
|
588
586
|
metadata: buildMetadata(workflowState.metadata),
|
|
589
587
|
};
|
|
588
|
+
bumpVersion();
|
|
590
589
|
notifyWorkflowChange("node_config");
|
|
591
590
|
},
|
|
592
591
|
/**
|
|
@@ -596,8 +595,8 @@ export const workflowActions = {
|
|
|
596
595
|
*/
|
|
597
596
|
clear: () => {
|
|
598
597
|
workflowState = null;
|
|
599
|
-
|
|
600
|
-
|
|
598
|
+
_editVersion = 0;
|
|
599
|
+
_savedVersion = 0;
|
|
601
600
|
historyService.clear();
|
|
602
601
|
if (onDirtyStateChangeCallback) {
|
|
603
602
|
onDirtyStateChangeCallback(false);
|
|
@@ -613,6 +612,7 @@ export const workflowActions = {
|
|
|
613
612
|
...workflowState,
|
|
614
613
|
metadata: buildMetadata(workflowState.metadata, metadata),
|
|
615
614
|
};
|
|
615
|
+
bumpVersion();
|
|
616
616
|
notifyWorkflowChange("metadata");
|
|
617
617
|
},
|
|
618
618
|
/**
|
|
@@ -635,8 +635,28 @@ export const workflowActions = {
|
|
|
635
635
|
}),
|
|
636
636
|
metadata: buildMetadata(workflowState.metadata, updates.metadata ?? undefined),
|
|
637
637
|
};
|
|
638
|
+
bumpVersion();
|
|
638
639
|
notifyWorkflowChange("metadata");
|
|
639
640
|
},
|
|
641
|
+
/**
|
|
642
|
+
* Swap a node — atomically replaces nodes and edges with a descriptive history entry.
|
|
643
|
+
*
|
|
644
|
+
* Unlike batchUpdate, this uses `"node_swap"` as the change type and
|
|
645
|
+
* records a meaningful description for the undo history.
|
|
646
|
+
*/
|
|
647
|
+
swapNode: (updates) => {
|
|
648
|
+
pushToHistory(updates.description ?? "Swap node");
|
|
649
|
+
if (!workflowState)
|
|
650
|
+
return;
|
|
651
|
+
workflowState = {
|
|
652
|
+
...workflowState,
|
|
653
|
+
nodes: updates.nodes,
|
|
654
|
+
edges: updates.edges,
|
|
655
|
+
metadata: buildMetadata(workflowState.metadata),
|
|
656
|
+
};
|
|
657
|
+
bumpVersion();
|
|
658
|
+
notifyWorkflowChange("node_swap");
|
|
659
|
+
},
|
|
640
660
|
/**
|
|
641
661
|
* Push current state to history manually
|
|
642
662
|
*
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
const SOURCE_ID = "source-node";
|
|
47
47
|
const TARGET_ID = "target-node";
|
|
48
48
|
|
|
49
|
-
let nodes = $
|
|
49
|
+
let nodes = $derived<Node[]>([
|
|
50
50
|
{
|
|
51
51
|
id: SOURCE_ID,
|
|
52
52
|
type: "universalNode",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
]);
|
|
63
63
|
|
|
64
64
|
// Handle IDs follow the format: {nodeId}-{input|output}-{portId}
|
|
65
|
-
let edges = $
|
|
65
|
+
let edges = $derived<Edge[]>([
|
|
66
66
|
{
|
|
67
67
|
id: "edge-1",
|
|
68
68
|
source: SOURCE_ID,
|
|
@@ -100,8 +100,8 @@
|
|
|
100
100
|
|
|
101
101
|
<div class="edge-decorator-wrapper">
|
|
102
102
|
<SvelteFlow
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
{nodes}
|
|
104
|
+
{edges}
|
|
105
105
|
{nodeTypes}
|
|
106
106
|
{edgeTypes}
|
|
107
107
|
fitView
|
package/dist/styles/base.css
CHANGED
|
@@ -30,6 +30,54 @@
|
|
|
30
30
|
box-shadow: var(--fd-shadow-md);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/* xyflow Controls & MiniMap: wire up to skin tokens so themes can restyle them */
|
|
34
|
+
.svelte-flow {
|
|
35
|
+
--xy-controls-button-background-color: var(
|
|
36
|
+
--fd-controls-button-bg,
|
|
37
|
+
var(--fd-card)
|
|
38
|
+
);
|
|
39
|
+
--xy-controls-button-background-color-hover: var(
|
|
40
|
+
--fd-controls-button-bg-hover,
|
|
41
|
+
var(--fd-muted)
|
|
42
|
+
);
|
|
43
|
+
--xy-controls-button-color: var(
|
|
44
|
+
--fd-controls-button-color,
|
|
45
|
+
var(--fd-foreground)
|
|
46
|
+
);
|
|
47
|
+
--xy-controls-button-color-hover: var(
|
|
48
|
+
--fd-controls-button-color-hover,
|
|
49
|
+
var(--fd-foreground)
|
|
50
|
+
);
|
|
51
|
+
--xy-controls-button-border-color: var(
|
|
52
|
+
--fd-controls-button-border,
|
|
53
|
+
var(--fd-border)
|
|
54
|
+
);
|
|
55
|
+
--xy-controls-box-shadow: var(
|
|
56
|
+
--fd-controls-box-shadow,
|
|
57
|
+
0 0 2px 1px rgba(0, 0, 0, 0.08)
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
--xy-minimap-background-color: var(--fd-minimap-bg, var(--fd-card));
|
|
61
|
+
--xy-minimap-mask-background-color: var(
|
|
62
|
+
--fd-minimap-mask-bg,
|
|
63
|
+
var(--fd-backdrop)
|
|
64
|
+
);
|
|
65
|
+
--xy-minimap-mask-stroke-color: var(
|
|
66
|
+
--fd-minimap-mask-stroke,
|
|
67
|
+
var(--fd-border)
|
|
68
|
+
);
|
|
69
|
+
--xy-minimap-mask-stroke-width: var(--fd-minimap-mask-stroke-width, 1);
|
|
70
|
+
--xy-minimap-node-background-color: var(
|
|
71
|
+
--fd-minimap-node-bg,
|
|
72
|
+
var(--fd-muted)
|
|
73
|
+
);
|
|
74
|
+
--xy-minimap-node-stroke-color: var(
|
|
75
|
+
--fd-minimap-node-stroke,
|
|
76
|
+
var(--fd-border-muted)
|
|
77
|
+
);
|
|
78
|
+
--xy-minimap-node-stroke-width: var(--fd-minimap-node-stroke-width, 2);
|
|
79
|
+
}
|
|
80
|
+
|
|
33
81
|
/* Flow node handles: 20px connection area, 12px visible circle (::before)
|
|
34
82
|
Override xyflow's default background so port color (--fd-handle-fill from inline style) shows.
|
|
35
83
|
Use `.svelte-flow` parent for higher specificity (0-2-0) to beat xyflow defaults (0-1-0). */
|
package/dist/svelte-app.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ 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
15
|
import "./registry/builtinFormats.js";
|
|
16
|
-
import type { PartialSettings } from "./types/settings.js";
|
|
16
|
+
import type { PartialSettings, SettingsCategory } from "./types/settings.js";
|
|
17
17
|
/**
|
|
18
18
|
* Navbar action configuration
|
|
19
19
|
*/
|
|
@@ -74,6 +74,12 @@ export interface FlowDropMountOptions {
|
|
|
74
74
|
formatAdapters?: WorkflowFormatAdapter[];
|
|
75
75
|
/** Visual theme — named built-in ('default' | 'minimal') or custom theme object */
|
|
76
76
|
theme?: FlowDropTheme | FlowDropThemeName;
|
|
77
|
+
/** Which settings tabs to show in the modal (defaults to all) */
|
|
78
|
+
settingsCategories?: SettingsCategory[];
|
|
79
|
+
/** Show the "Sync to Cloud" button in the settings modal */
|
|
80
|
+
showSettingsSyncButton?: boolean;
|
|
81
|
+
/** Show the reset buttons in the settings modal */
|
|
82
|
+
showSettingsResetButton?: boolean;
|
|
77
83
|
}
|
|
78
84
|
/**
|
|
79
85
|
* Return type for mounted FlowDrop app
|
package/dist/svelte-app.js
CHANGED
|
@@ -47,7 +47,7 @@ import { globalSaveWorkflow, globalExportWorkflow, } from "./services/globalSave
|
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
49
|
export async function mountFlowDropApp(container, options = {}) {
|
|
50
|
-
const { workflow, nodes, endpointConfig, portConfig, categories, height = "100vh", width = "100%", showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey, formatAdapters, theme, } = options;
|
|
50
|
+
const { workflow, nodes, endpointConfig, portConfig, categories, height = "100vh", width = "100%", showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey, formatAdapters, theme, settingsCategories, showSettingsSyncButton, showSettingsResetButton, } = options;
|
|
51
51
|
// Register custom format adapters before mounting
|
|
52
52
|
if (formatAdapters) {
|
|
53
53
|
for (const adapter of formatAdapters) {
|
|
@@ -137,6 +137,9 @@ export async function mountFlowDropApp(container, options = {}) {
|
|
|
137
137
|
eventHandlers,
|
|
138
138
|
features,
|
|
139
139
|
theme,
|
|
140
|
+
settingsCategories,
|
|
141
|
+
showSettingsSyncButton,
|
|
142
|
+
showSettingsResetButton,
|
|
140
143
|
},
|
|
141
144
|
});
|
|
142
145
|
// Set up draft auto-save manager
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Types for FlowDrop LLM Chat Interface
|
|
3
|
+
*
|
|
4
|
+
* Provides type definitions for the chat panel's communication
|
|
5
|
+
* with backend LLM integrations.
|
|
6
|
+
*
|
|
7
|
+
* @module types/chat
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Role for chat history messages
|
|
11
|
+
*/
|
|
12
|
+
export type ChatMessageRole = "user" | "assistant";
|
|
13
|
+
/**
|
|
14
|
+
* A single message in the chat history
|
|
15
|
+
*/
|
|
16
|
+
export interface ChatHistoryMessage {
|
|
17
|
+
role: ChatMessageRole;
|
|
18
|
+
content: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Request payload sent to the chat endpoint
|
|
22
|
+
*/
|
|
23
|
+
export interface ChatRequest {
|
|
24
|
+
/** The user's natural language message */
|
|
25
|
+
message: string;
|
|
26
|
+
/** Serialized current workflow state (nodes + edges) */
|
|
27
|
+
workflowState: unknown;
|
|
28
|
+
/** Optional conversation history for context */
|
|
29
|
+
history?: ChatHistoryMessage[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Response payload from the chat endpoint
|
|
33
|
+
*/
|
|
34
|
+
export interface ChatResponse {
|
|
35
|
+
/** The LLM's response content (may contain markdown and code blocks) */
|
|
36
|
+
content: string;
|
|
37
|
+
/** Optional conversation ID for backend session tracking */
|
|
38
|
+
conversationId?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Result of parsing an LLM response to extract DSL commands
|
|
42
|
+
*/
|
|
43
|
+
export interface ExtractedCommands {
|
|
44
|
+
/** The full explanation text (content outside code blocks) */
|
|
45
|
+
explanation: string;
|
|
46
|
+
/** Extracted DSL command strings */
|
|
47
|
+
commands: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Status of a single command in the preview
|
|
51
|
+
*/
|
|
52
|
+
export type CommandExecutionStatus = "pending" | "executing" | "success" | "error";
|
|
53
|
+
/**
|
|
54
|
+
* A single command shown in the command preview UI
|
|
55
|
+
*/
|
|
56
|
+
export interface CommandPreviewItem {
|
|
57
|
+
/** The raw DSL command string */
|
|
58
|
+
raw: string;
|
|
59
|
+
/** Current execution status */
|
|
60
|
+
status: CommandExecutionStatus;
|
|
61
|
+
/** Optional result or error message after execution */
|
|
62
|
+
result?: string;
|
|
63
|
+
}
|