@d34dman/flowdrop 0.0.57 → 0.0.58
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 +4 -4
- package/dist/adapters/WorkflowAdapter.d.ts +2 -1
- package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +4 -0
- package/dist/adapters/agentspec/AgentSpecAdapter.js +27 -22
- package/dist/adapters/agentspec/componentTypeDefaults.d.ts +73 -0
- package/dist/adapters/agentspec/componentTypeDefaults.js +238 -0
- package/dist/adapters/agentspec/{nodeTypeRegistry.d.ts → defaultNodeTypes.d.ts} +21 -30
- package/dist/adapters/agentspec/{nodeTypeRegistry.js → defaultNodeTypes.js} +31 -59
- package/dist/adapters/agentspec/index.d.ts +3 -1
- package/dist/adapters/agentspec/index.js +4 -2
- package/dist/components/App.svelte +57 -13
- package/dist/components/NodeSidebar.svelte +20 -8
- package/dist/components/NodeSidebar.svelte.d.ts +2 -1
- package/dist/components/WorkflowEditor.svelte +14 -13
- package/dist/components/form/FormMarkdownEditor.svelte +546 -422
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +2 -0
- package/dist/components/form/FormUISchemaRenderer.svelte +4 -8
- package/dist/components/form/types.d.ts +1 -1
- package/dist/components/nodes/WorkflowNode.svelte +1 -2
- package/dist/core/index.d.ts +13 -3
- package/dist/core/index.js +16 -3
- package/dist/form/code.js +6 -1
- package/dist/form/fieldRegistry.d.ts +79 -15
- package/dist/form/fieldRegistry.js +104 -49
- package/dist/form/full.d.ts +2 -2
- package/dist/form/full.js +2 -2
- package/dist/form/index.d.ts +3 -3
- package/dist/form/index.js +6 -2
- package/dist/form/markdown.d.ts +3 -3
- package/dist/form/markdown.js +8 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/registry/BaseRegistry.d.ts +92 -0
- package/dist/registry/BaseRegistry.js +124 -0
- package/dist/registry/builtinFormats.d.ts +23 -0
- package/dist/registry/builtinFormats.js +70 -0
- package/dist/registry/builtinNodes.js +4 -0
- package/dist/registry/index.d.ts +2 -1
- package/dist/registry/index.js +2 -0
- package/dist/registry/nodeComponentRegistry.d.ts +26 -57
- package/dist/registry/nodeComponentRegistry.js +29 -82
- package/dist/registry/workflowFormatRegistry.d.ts +122 -0
- package/dist/registry/workflowFormatRegistry.js +96 -0
- package/dist/schema/index.d.ts +23 -0
- package/dist/schema/index.js +23 -0
- package/dist/stores/portCoordinateStore.js +1 -4
- package/dist/stores/workflowStore.d.ts +3 -0
- package/dist/stores/workflowStore.js +3 -0
- package/dist/svelte-app.d.ts +4 -0
- package/dist/svelte-app.js +9 -1
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.js +4 -0
- package/package.json +231 -225
- package/schemas/v1/workflow.schema.json +952 -0
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agent Spec Node
|
|
2
|
+
* Agent Spec Default Node Types
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Provides optional starter node type definitions for the Agent Spec format.
|
|
5
|
+
* These are full NodeMetadata objects with visual type, category, default ports,
|
|
6
|
+
* config schema, and icon — suitable for populating the sidebar.
|
|
7
|
+
*
|
|
8
|
+
* These definitions are NOT required by the adapter — the adapter uses
|
|
9
|
+
* componentTypeDefaults.ts for import/export infrastructure.
|
|
10
|
+
* Users can provide their own node definitions instead.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { getDefaultAgentSpecNodeTypes } from '@d34dman/flowdrop/core';
|
|
15
|
+
*
|
|
16
|
+
* mountFlowDropApp(container, {
|
|
17
|
+
* nodes: getDefaultAgentSpecNodeTypes(), // or your own definitions
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
7
20
|
*/
|
|
8
|
-
|
|
9
|
-
const AGENTSPEC_NS = 'agentspec';
|
|
10
|
-
/** Standard trigger input port shared by most nodes */
|
|
11
|
-
const TRIGGER_INPUT = {
|
|
12
|
-
id: 'trigger',
|
|
13
|
-
name: 'Trigger',
|
|
14
|
-
type: 'input',
|
|
15
|
-
dataType: 'trigger',
|
|
16
|
-
required: false,
|
|
17
|
-
description: 'Control flow input'
|
|
18
|
-
};
|
|
19
|
-
/** Standard trigger output port shared by most nodes */
|
|
20
|
-
const TRIGGER_OUTPUT = {
|
|
21
|
-
id: 'trigger',
|
|
22
|
-
name: 'Trigger',
|
|
23
|
-
type: 'output',
|
|
24
|
-
dataType: 'trigger',
|
|
25
|
-
required: false,
|
|
26
|
-
description: 'Control flow output'
|
|
27
|
-
};
|
|
21
|
+
import { AGENTSPEC_NAMESPACE as AGENTSPEC_NS, TRIGGER_INPUT, TRIGGER_OUTPUT } from './componentTypeDefaults.js';
|
|
28
22
|
/**
|
|
29
23
|
* Build the full registry of Agent Spec node types.
|
|
30
24
|
*/
|
|
@@ -51,6 +45,7 @@ function buildRegistry() {
|
|
|
51
45
|
type: 'object',
|
|
52
46
|
properties: {}
|
|
53
47
|
},
|
|
48
|
+
formats: ['agentspec'],
|
|
54
49
|
extensions: { 'agentspec:component_type': 'start_node' }
|
|
55
50
|
}
|
|
56
51
|
});
|
|
@@ -75,6 +70,7 @@ function buildRegistry() {
|
|
|
75
70
|
type: 'object',
|
|
76
71
|
properties: {}
|
|
77
72
|
},
|
|
73
|
+
formats: ['agentspec'],
|
|
78
74
|
extensions: { 'agentspec:component_type': 'end_node' }
|
|
79
75
|
}
|
|
80
76
|
});
|
|
@@ -139,6 +135,7 @@ function buildRegistry() {
|
|
|
139
135
|
}
|
|
140
136
|
}
|
|
141
137
|
},
|
|
138
|
+
formats: ['agentspec'],
|
|
142
139
|
extensions: { 'agentspec:component_type': 'llm_node' }
|
|
143
140
|
}
|
|
144
141
|
});
|
|
@@ -206,6 +203,7 @@ function buildRegistry() {
|
|
|
206
203
|
}
|
|
207
204
|
}
|
|
208
205
|
},
|
|
206
|
+
formats: ['agentspec'],
|
|
209
207
|
extensions: { 'agentspec:component_type': 'branching_node' }
|
|
210
208
|
}
|
|
211
209
|
});
|
|
@@ -263,6 +261,7 @@ function buildRegistry() {
|
|
|
263
261
|
}
|
|
264
262
|
}
|
|
265
263
|
},
|
|
264
|
+
formats: ['agentspec'],
|
|
266
265
|
extensions: { 'agentspec:component_type': 'tool_node' }
|
|
267
266
|
}
|
|
268
267
|
});
|
|
@@ -333,6 +332,7 @@ function buildRegistry() {
|
|
|
333
332
|
}
|
|
334
333
|
}
|
|
335
334
|
},
|
|
335
|
+
formats: ['agentspec'],
|
|
336
336
|
extensions: { 'agentspec:component_type': 'api_node' }
|
|
337
337
|
}
|
|
338
338
|
});
|
|
@@ -390,6 +390,7 @@ function buildRegistry() {
|
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
392
|
},
|
|
393
|
+
formats: ['agentspec'],
|
|
393
394
|
extensions: { 'agentspec:component_type': 'agent_node' }
|
|
394
395
|
}
|
|
395
396
|
});
|
|
@@ -440,6 +441,7 @@ function buildRegistry() {
|
|
|
440
441
|
}
|
|
441
442
|
}
|
|
442
443
|
},
|
|
444
|
+
formats: ['agentspec'],
|
|
443
445
|
extensions: { 'agentspec:component_type': 'flow_node' }
|
|
444
446
|
}
|
|
445
447
|
});
|
|
@@ -502,6 +504,7 @@ function buildRegistry() {
|
|
|
502
504
|
}
|
|
503
505
|
}
|
|
504
506
|
},
|
|
507
|
+
formats: ['agentspec'],
|
|
505
508
|
extensions: { 'agentspec:component_type': 'map_node' }
|
|
506
509
|
}
|
|
507
510
|
});
|
|
@@ -528,12 +531,12 @@ export function getAgentSpecNodeMetadata(componentType) {
|
|
|
528
531
|
return registry.get(componentType)?.metadata;
|
|
529
532
|
}
|
|
530
533
|
/**
|
|
531
|
-
* Get all Agent Spec node types as FlowDrop NodeMetadata.
|
|
532
|
-
*
|
|
534
|
+
* Get all default Agent Spec node types as FlowDrop NodeMetadata.
|
|
535
|
+
* These are starter templates — users can provide their own node types instead.
|
|
533
536
|
*
|
|
534
|
-
* @returns Array of NodeMetadata for all 9 Agent Spec node types
|
|
537
|
+
* @returns Array of NodeMetadata for all 9 default Agent Spec node types
|
|
535
538
|
*/
|
|
536
|
-
export function
|
|
539
|
+
export function getDefaultAgentSpecNodeTypes() {
|
|
537
540
|
return Array.from(registry.values()).map((entry) => entry.metadata);
|
|
538
541
|
}
|
|
539
542
|
/**
|
|
@@ -556,34 +559,3 @@ export function createAgentSpecNodeMetadata(componentType, inputs, outputs) {
|
|
|
556
559
|
outputs: outputs ?? base.outputs
|
|
557
560
|
};
|
|
558
561
|
}
|
|
559
|
-
/**
|
|
560
|
-
* Check if a FlowDrop node ID belongs to an Agent Spec node type.
|
|
561
|
-
*
|
|
562
|
-
* @example
|
|
563
|
-
* ```typescript
|
|
564
|
-
* isAgentSpecNodeId('agentspec.llm_node') // true
|
|
565
|
-
* isAgentSpecNodeId('calculator') // false
|
|
566
|
-
* ```
|
|
567
|
-
*/
|
|
568
|
-
export function isAgentSpecNodeId(nodeId) {
|
|
569
|
-
return nodeId.startsWith(`${AGENTSPEC_NS}.`);
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Extract the Agent Spec component_type from a FlowDrop node type ID.
|
|
573
|
-
*
|
|
574
|
-
* @example
|
|
575
|
-
* ```typescript
|
|
576
|
-
* extractComponentType('agentspec.llm_node') // 'llm_node'
|
|
577
|
-
* extractComponentType('calculator') // undefined
|
|
578
|
-
* ```
|
|
579
|
-
*/
|
|
580
|
-
export function extractComponentType(nodeTypeId) {
|
|
581
|
-
if (!isAgentSpecNodeId(nodeTypeId))
|
|
582
|
-
return undefined;
|
|
583
|
-
const componentType = nodeTypeId.slice(AGENTSPEC_NS.length + 1);
|
|
584
|
-
return registry.has(componentType)
|
|
585
|
-
? componentType
|
|
586
|
-
: undefined;
|
|
587
|
-
}
|
|
588
|
-
/** The namespace prefix used for Agent Spec node type IDs */
|
|
589
|
-
export const AGENTSPEC_NAMESPACE = AGENTSPEC_NS;
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
export { AgentSpecAdapter } from './AgentSpecAdapter.js';
|
|
29
29
|
export { AgentSpecAgentAdapter } from './agentAdapter.js';
|
|
30
30
|
export type { AgentConfig, AgentSpecImportResult } from './agentAdapter.js';
|
|
31
|
-
export { getAgentSpecNodeMetadata,
|
|
31
|
+
export { getAgentSpecNodeMetadata, getDefaultAgentSpecNodeTypes, createAgentSpecNodeMetadata } from './defaultNodeTypes.js';
|
|
32
|
+
export { getComponentTypeDefaults, extractComponentType, isAgentSpecNodeId, AGENTSPEC_NAMESPACE } from './componentTypeDefaults.js';
|
|
33
|
+
export type { ComponentTypeDefaults } from './componentTypeDefaults.js';
|
|
32
34
|
export { validateForAgentSpecExport, validateAgentSpecFlow } from './validator.js';
|
|
33
35
|
export type { AgentSpecValidationResult } from './validator.js';
|
|
34
36
|
export { computeAutoLayout } from './autoLayout.js';
|
|
@@ -29,8 +29,10 @@
|
|
|
29
29
|
export { AgentSpecAdapter } from './AgentSpecAdapter.js';
|
|
30
30
|
// Agent-level adapter (wraps flow with agent/tools/LLM config)
|
|
31
31
|
export { AgentSpecAgentAdapter } from './agentAdapter.js';
|
|
32
|
-
//
|
|
33
|
-
export { getAgentSpecNodeMetadata,
|
|
32
|
+
// Default node types (optional starter templates — users can provide their own)
|
|
33
|
+
export { getAgentSpecNodeMetadata, getDefaultAgentSpecNodeTypes, createAgentSpecNodeMetadata } from './defaultNodeTypes.js';
|
|
34
|
+
// Component type defaults (adapter infrastructure)
|
|
35
|
+
export { getComponentTypeDefaults, extractComponentType, isAgentSpecNodeId, AGENTSPEC_NAMESPACE } from './componentTypeDefaults.js';
|
|
34
36
|
// Validation
|
|
35
37
|
export { validateForAgentSpecExport, validateAgentSpecFlow } from './validator.js';
|
|
36
38
|
// Auto-layout
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
ConfigSchema,
|
|
23
23
|
NodeUIExtensions
|
|
24
24
|
} from '../types/index.js';
|
|
25
|
+
import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
|
|
25
26
|
import { createEndpointConfig } from '../config/endpoints.js';
|
|
26
27
|
import type { EndpointConfig } from '../config/endpoints.js';
|
|
27
28
|
import type { AuthProvider } from '../types/auth.js';
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
workflowStore,
|
|
32
33
|
workflowActions,
|
|
33
34
|
workflowName,
|
|
35
|
+
workflowFormat,
|
|
34
36
|
markAsSaved
|
|
35
37
|
} from '../stores/workflowStore.js';
|
|
36
38
|
import { apiToasts, dismissToast } from '../services/toastService.js';
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
import { uiSettings } from '../stores/settingsStore.js';
|
|
39
41
|
import { initializePortCompatibility } from '../utils/connections.js';
|
|
40
42
|
import { DEFAULT_PORT_CONFIG } from '../config/defaultPortConfig.js';
|
|
43
|
+
import { workflowFormatRegistry } from '../registry/workflowFormatRegistry.js';
|
|
41
44
|
|
|
42
45
|
/**
|
|
43
46
|
* Configuration props for runtime customization
|
|
@@ -143,9 +146,9 @@
|
|
|
143
146
|
// Workflow settings sidebar state
|
|
144
147
|
let isWorkflowSettingsOpen = $state(false);
|
|
145
148
|
|
|
146
|
-
// Workflow configuration schema
|
|
147
|
-
|
|
148
|
-
type: 'object',
|
|
149
|
+
// Workflow configuration schema (derived to pick up dynamic format options)
|
|
150
|
+
let workflowConfigSchema: ConfigSchema = $derived({
|
|
151
|
+
type: 'object' as const,
|
|
149
152
|
properties: {
|
|
150
153
|
name: {
|
|
151
154
|
type: 'string',
|
|
@@ -159,15 +162,23 @@
|
|
|
159
162
|
description: 'A description of the workflow',
|
|
160
163
|
format: 'multiline',
|
|
161
164
|
default: ''
|
|
165
|
+
},
|
|
166
|
+
format: {
|
|
167
|
+
type: 'string',
|
|
168
|
+
title: 'Workflow Format',
|
|
169
|
+
description: 'The specification format for this workflow',
|
|
170
|
+
oneOf: workflowFormatRegistry.getOneOfOptions(),
|
|
171
|
+
default: 'flowdrop'
|
|
162
172
|
}
|
|
163
173
|
},
|
|
164
174
|
required: ['name']
|
|
165
|
-
};
|
|
175
|
+
});
|
|
166
176
|
|
|
167
177
|
// Workflow configuration values
|
|
168
178
|
let workflowConfigValues = $derived({
|
|
169
179
|
name: $workflowName || '',
|
|
170
|
-
description: $workflowStore?.description || ''
|
|
180
|
+
description: $workflowStore?.description || '',
|
|
181
|
+
format: $workflowStore?.metadata?.format || 'flowdrop'
|
|
171
182
|
});
|
|
172
183
|
|
|
173
184
|
// Get the current node from the workflow store
|
|
@@ -188,7 +199,11 @@
|
|
|
188
199
|
async function fetchNodeTypes(): Promise<void> {
|
|
189
200
|
// If nodes were provided as props, use them directly (skip API fetch)
|
|
190
201
|
if (propNodes && propNodes.length > 0) {
|
|
191
|
-
nodes
|
|
202
|
+
// Merge format-provided nodes with prop nodes (deduplicate by ID, props take priority)
|
|
203
|
+
const formatNodes = workflowFormatRegistry.getAllFormatNodes();
|
|
204
|
+
const existingIds = new Set(propNodes.map((n) => n.id));
|
|
205
|
+
const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
|
|
206
|
+
nodes = [...propNodes, ...uniqueFormatNodes];
|
|
192
207
|
return;
|
|
193
208
|
}
|
|
194
209
|
|
|
@@ -205,7 +220,11 @@
|
|
|
205
220
|
fetchedNodes = await api.nodes.getNodes();
|
|
206
221
|
}
|
|
207
222
|
|
|
208
|
-
nodes
|
|
223
|
+
// Merge format-provided nodes with API nodes (deduplicate by ID, API takes priority)
|
|
224
|
+
const formatNodes = workflowFormatRegistry.getAllFormatNodes();
|
|
225
|
+
const existingIds = new Set(fetchedNodes.map((n) => n.id));
|
|
226
|
+
const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
|
|
227
|
+
nodes = [...fetchedNodes, ...uniqueFormatNodes];
|
|
209
228
|
error = null;
|
|
210
229
|
|
|
211
230
|
// Dismiss loading toast
|
|
@@ -430,7 +449,7 @@
|
|
|
430
449
|
workflowId = uuidv4();
|
|
431
450
|
}
|
|
432
451
|
|
|
433
|
-
// Create workflow object for saving
|
|
452
|
+
// Create workflow object for saving (spread existing metadata to preserve format, tags, etc.)
|
|
434
453
|
const finalWorkflow: Workflow = {
|
|
435
454
|
id: workflowId,
|
|
436
455
|
name: workflowToSave.name || 'Untitled Workflow',
|
|
@@ -438,7 +457,9 @@
|
|
|
438
457
|
nodes: workflowToSave.nodes || [],
|
|
439
458
|
edges: workflowToSave.edges || [],
|
|
440
459
|
metadata: {
|
|
441
|
-
|
|
460
|
+
...workflowToSave.metadata,
|
|
461
|
+
version: workflowToSave.metadata?.version || '1.0.0',
|
|
462
|
+
format: workflowToSave.metadata?.format || DEFAULT_WORKFLOW_FORMAT,
|
|
442
463
|
createdAt: workflowToSave.metadata?.createdAt || new Date().toISOString(),
|
|
443
464
|
updatedAt: new Date().toISOString()
|
|
444
465
|
}
|
|
@@ -538,14 +559,16 @@
|
|
|
538
559
|
return;
|
|
539
560
|
}
|
|
540
561
|
|
|
541
|
-
// Create workflow object for export
|
|
562
|
+
// Create workflow object for export (spread existing metadata to preserve format, tags, etc.)
|
|
542
563
|
const finalWorkflow = {
|
|
543
564
|
id: workflowToExport.id || 'untitled-workflow',
|
|
544
565
|
name: workflowToExport.name || 'Untitled Workflow',
|
|
545
566
|
nodes: workflowToExport.nodes || [],
|
|
546
567
|
edges: workflowToExport.edges || [],
|
|
547
568
|
metadata: {
|
|
548
|
-
|
|
569
|
+
...workflowToExport.metadata,
|
|
570
|
+
version: workflowToExport.metadata?.version || '1.0.0',
|
|
571
|
+
format: workflowToExport.metadata?.format || DEFAULT_WORKFLOW_FORMAT,
|
|
549
572
|
createdAt: workflowToExport.metadata?.createdAt || new Date().toISOString(),
|
|
550
573
|
updatedAt: new Date().toISOString()
|
|
551
574
|
}
|
|
@@ -722,7 +745,7 @@
|
|
|
722
745
|
|
|
723
746
|
<!-- Left Sidebar: Node Components -->
|
|
724
747
|
{#snippet leftSidebar()}
|
|
725
|
-
<NodeSidebar {nodes} />
|
|
748
|
+
<NodeSidebar {nodes} activeFormat={$workflowFormat} />
|
|
726
749
|
{/snippet}
|
|
727
750
|
|
|
728
751
|
<!-- Right Sidebar: Configuration or Workflow Settings -->
|
|
@@ -746,9 +769,30 @@
|
|
|
746
769
|
onChange={(config) => {
|
|
747
770
|
// Sync workflow settings changes immediately on field blur
|
|
748
771
|
if ($workflowStore) {
|
|
772
|
+
const newFormat = (config.format as string) || DEFAULT_WORKFLOW_FORMAT;
|
|
773
|
+
const currentFormat = $workflowStore.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
|
|
774
|
+
|
|
775
|
+
// Warn about incompatible nodes when format changes
|
|
776
|
+
if (newFormat !== currentFormat) {
|
|
777
|
+
const incompatibleNodes = $workflowStore.nodes?.filter((node) => {
|
|
778
|
+
const formats = node.data?.metadata?.formats;
|
|
779
|
+
return formats && formats.length > 0 && !formats.includes(newFormat);
|
|
780
|
+
});
|
|
781
|
+
if (incompatibleNodes && incompatibleNodes.length > 0) {
|
|
782
|
+
console.warn(
|
|
783
|
+
`Format changed to '${newFormat}'. ${incompatibleNodes.length} node(s) are not compatible with this format and may not export correctly:`,
|
|
784
|
+
incompatibleNodes.map((n) => n.data?.label || n.type)
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
749
789
|
workflowActions.batchUpdate({
|
|
750
790
|
name: config.name as string,
|
|
751
|
-
description: config.description as string | undefined
|
|
791
|
+
description: config.description as string | undefined,
|
|
792
|
+
metadata: {
|
|
793
|
+
...$workflowStore.metadata,
|
|
794
|
+
format: newFormat
|
|
795
|
+
}
|
|
752
796
|
});
|
|
753
797
|
}
|
|
754
798
|
}}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
-->
|
|
6
6
|
|
|
7
7
|
<script lang="ts">
|
|
8
|
-
import type { NodeMetadata, NodeCategory } from '../types/index.js';
|
|
8
|
+
import type { NodeMetadata, NodeCategory, WorkflowFormat } from '../types/index.js';
|
|
9
9
|
import LoadingSpinner from './LoadingSpinner.svelte';
|
|
10
10
|
import Icon from '@iconify/svelte';
|
|
11
11
|
import { getNodeIcon, getCategoryIcon } from '../utils/icons.js';
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
interface Props {
|
|
18
18
|
nodes: NodeMetadata[];
|
|
19
19
|
selectedCategory?: NodeCategory;
|
|
20
|
+
activeFormat?: WorkflowFormat;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
let props: Props = $props();
|
|
@@ -31,6 +32,19 @@
|
|
|
31
32
|
updateSettings({ ui: { sidebarCollapsed: !$uiSettings.sidebarCollapsed } });
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Check if a node is compatible with the active workflow format.
|
|
37
|
+
* Nodes without formats are universal (compatible with all formats).
|
|
38
|
+
*/
|
|
39
|
+
function isNodeCompatibleWithFormat(node: NodeMetadata): boolean {
|
|
40
|
+
if (!props.activeFormat) return true;
|
|
41
|
+
if (!node.formats || node.formats.length === 0) return true;
|
|
42
|
+
return node.formats.includes(props.activeFormat);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Nodes filtered by format compatibility */
|
|
46
|
+
let formatCompatibleNodes = $derived((props.nodes || []).filter(isNodeCompatibleWithFormat));
|
|
47
|
+
|
|
34
48
|
let filteredNodes = $derived(getFilteredNodes());
|
|
35
49
|
let categories = $derived(getCategories());
|
|
36
50
|
|
|
@@ -39,12 +53,11 @@
|
|
|
39
53
|
* Categories appear in the order their first node appears in the API response
|
|
40
54
|
*/
|
|
41
55
|
function getCategories(): NodeCategory[] {
|
|
42
|
-
|
|
43
|
-
if (nodes.length === 0) return [];
|
|
56
|
+
if (formatCompatibleNodes.length === 0) return [];
|
|
44
57
|
// Use a Set to track uniqueness while preserving insertion order
|
|
45
58
|
const seen = new SvelteSet<NodeCategory>();
|
|
46
59
|
const orderedCategories: NodeCategory[] = [];
|
|
47
|
-
for (const node of
|
|
60
|
+
for (const node of formatCompatibleNodes) {
|
|
48
61
|
if (!seen.has(node.category)) {
|
|
49
62
|
seen.add(node.category);
|
|
50
63
|
orderedCategories.push(node.category);
|
|
@@ -58,8 +71,8 @@
|
|
|
58
71
|
* Preserves the API order - no client-side sorting applied
|
|
59
72
|
*/
|
|
60
73
|
function getFilteredNodes(): NodeMetadata[] {
|
|
61
|
-
//
|
|
62
|
-
let filtered =
|
|
74
|
+
// Start with format-compatible nodes
|
|
75
|
+
let filtered = formatCompatibleNodes;
|
|
63
76
|
|
|
64
77
|
// Filter by category
|
|
65
78
|
if (selectedCategory !== 'all') {
|
|
@@ -155,8 +168,7 @@
|
|
|
155
168
|
* Preserves the API order - no client-side sorting applied
|
|
156
169
|
*/
|
|
157
170
|
function getNodesForCategory(category: NodeCategory): NodeMetadata[] {
|
|
158
|
-
|
|
159
|
-
return nodes.filter((node) => node.category === category);
|
|
171
|
+
return formatCompatibleNodes.filter((node) => node.category === category);
|
|
160
172
|
}
|
|
161
173
|
|
|
162
174
|
/**
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { NodeMetadata, NodeCategory } from '../types/index.js';
|
|
1
|
+
import type { NodeMetadata, NodeCategory, WorkflowFormat } from '../types/index.js';
|
|
2
2
|
interface Props {
|
|
3
3
|
nodes: NodeMetadata[];
|
|
4
4
|
selectedCategory?: NodeCategory;
|
|
5
|
+
activeFormat?: WorkflowFormat;
|
|
5
6
|
}
|
|
6
7
|
declare const NodeSidebar: import("svelte").Component<Props, {}, "">;
|
|
7
8
|
type NodeSidebar = ReturnType<typeof NodeSidebar>;
|
|
@@ -387,19 +387,20 @@
|
|
|
387
387
|
|
|
388
388
|
// Find the best compatible edge using port-to-port distance
|
|
389
389
|
const portCoordinates = getPortCoordinateSnapshot();
|
|
390
|
-
const candidates =
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
390
|
+
const candidates =
|
|
391
|
+
portCoordinates.size > 0
|
|
392
|
+
? ProximityConnectHelper.findCompatibleEdgesByPortCoordinates(
|
|
393
|
+
targetNode.id,
|
|
394
|
+
portCoordinates,
|
|
395
|
+
baseEdges,
|
|
396
|
+
$editorSettings.proximityConnectDistance
|
|
397
|
+
)
|
|
398
|
+
: ProximityConnectHelper.findCompatibleEdges(
|
|
399
|
+
targetNode,
|
|
400
|
+
flowNodes,
|
|
401
|
+
baseEdges,
|
|
402
|
+
$editorSettings.proximityConnectDistance
|
|
403
|
+
);
|
|
403
404
|
|
|
404
405
|
// Create preview edges
|
|
405
406
|
const previews = ProximityConnectHelper.createPreviewEdges(candidates);
|