@flowdrop/flowdrop 1.14.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.
Files changed (218) hide show
  1. package/CHANGELOG.md +475 -0
  2. package/MIGRATION-2.0.md +472 -0
  3. package/README.md +23 -23
  4. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  5. package/dist/adapters/WorkflowAdapter.js +14 -8
  6. package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
  7. package/dist/chat/batchFeedback.d.ts +39 -0
  8. package/dist/chat/batchFeedback.js +51 -0
  9. package/dist/commands/executor.js +15 -1
  10. package/dist/commands/storeIntegration.svelte.d.ts +4 -1
  11. package/dist/commands/storeIntegration.svelte.js +26 -21
  12. package/dist/commands/types.d.ts +2 -0
  13. package/dist/components/App.svelte +162 -192
  14. package/dist/components/App.svelte.d.ts +47 -8
  15. package/dist/components/ConfigForm.svelte +110 -66
  16. package/dist/components/ConfigModal.svelte +7 -2
  17. package/dist/components/ConnectionLine.svelte +4 -2
  18. package/dist/components/Navbar.svelte +61 -1
  19. package/dist/components/NodeSidebar.svelte +27 -45
  20. package/dist/components/NodeStatusOverlay.svelte +94 -6
  21. package/dist/components/NodeSwapPicker.svelte +10 -8
  22. package/dist/components/PipelineStatus.svelte +16 -67
  23. package/dist/components/PortCoordinateTracker.svelte +5 -6
  24. package/dist/components/SchemaForm.stories.svelte +1 -3
  25. package/dist/components/SchemaForm.svelte +45 -40
  26. package/dist/components/SchemaForm.svelte.d.ts +0 -8
  27. package/dist/components/SettingsModal.svelte +8 -3
  28. package/dist/components/SettingsPanel.svelte +20 -4
  29. package/dist/components/SwapMappingEditor.svelte +67 -49
  30. package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
  31. package/dist/components/UniversalNode.svelte +9 -7
  32. package/dist/components/WorkflowEditor.svelte +118 -111
  33. package/dist/components/WorkflowEditor.svelte.d.ts +18 -10
  34. package/dist/components/chat/AIChatPanel.svelte +93 -89
  35. package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
  36. package/dist/components/chat/CommandPreview.svelte +2 -1
  37. package/dist/components/console/CommandConsole.svelte +7 -5
  38. package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
  39. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
  40. package/dist/components/console/ConsoleInput.svelte +15 -6
  41. package/dist/components/console/ConsoleOutput.svelte +2 -1
  42. package/dist/components/form/FormArray.svelte +5 -9
  43. package/dist/components/form/FormArray.svelte.d.ts +2 -1
  44. package/dist/components/form/FormAutocomplete.svelte +29 -13
  45. package/dist/components/form/FormField.svelte +4 -2
  46. package/dist/components/form/FormFieldLight.svelte +4 -2
  47. package/dist/components/form/FormMarkdownEditor.svelte +9 -4
  48. package/dist/components/form/FormRangeField.svelte +1 -0
  49. package/dist/components/form/FormTemplateEditor.svelte +11 -3
  50. package/dist/components/form/FormToggle.svelte +5 -12
  51. package/dist/components/form/FormToggle.svelte.d.ts +4 -2
  52. package/dist/components/form/templateAutocomplete.js +1 -5
  53. package/dist/components/form/types.d.ts +1 -14
  54. package/dist/components/interrupt/FormPrompt.svelte +3 -2
  55. package/dist/components/interrupt/InterruptBubble.svelte +16 -17
  56. package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
  57. package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
  58. package/dist/components/layouts/MainLayout.svelte +20 -13
  59. package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
  60. package/dist/components/nodes/AtomNode.svelte +292 -0
  61. package/dist/components/nodes/AtomNode.svelte.d.ts +26 -0
  62. package/dist/components/nodes/GatewayNode.svelte +19 -10
  63. package/dist/components/nodes/IdeaNode.svelte +7 -0
  64. package/dist/components/nodes/SimpleNode.svelte +11 -6
  65. package/dist/components/nodes/SquareNode.svelte +15 -8
  66. package/dist/components/nodes/TerminalNode.svelte +9 -4
  67. package/dist/components/nodes/ToolNode.svelte +7 -1
  68. package/dist/components/nodes/WorkflowNode.svelte +16 -7
  69. package/dist/components/playground/ChatInput.svelte +11 -14
  70. package/dist/components/playground/ChatPanel.svelte +6 -49
  71. package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
  72. package/dist/components/playground/ControlPanel.svelte +134 -123
  73. package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
  74. package/dist/components/playground/ExecutionLogs.svelte +11 -9
  75. package/dist/components/playground/InputCollector.svelte +11 -9
  76. package/dist/components/playground/MessageStream.svelte +17 -23
  77. package/dist/components/playground/PipelineKanbanView.svelte +65 -6
  78. package/dist/components/playground/PipelinePanel.svelte +11 -5
  79. package/dist/components/playground/PipelineTableView.svelte +186 -44
  80. package/dist/components/playground/Playground.svelte +95 -92
  81. package/dist/components/playground/Playground.svelte.d.ts +2 -0
  82. package/dist/components/playground/PlaygroundApp.svelte +6 -1
  83. package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
  84. package/dist/components/playground/PlaygroundModal.svelte +13 -3
  85. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
  86. package/dist/components/playground/PlaygroundStudio.svelte +34 -32
  87. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
  88. package/dist/components/playground/SessionManager.svelte +9 -12
  89. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +28 -0
  90. package/dist/components/playground/pipelineViewUtils.svelte.js +38 -1
  91. package/dist/config/endpoints.d.ts +0 -7
  92. package/dist/config/endpoints.js +2 -10
  93. package/dist/core/index.d.ts +4 -4
  94. package/dist/core/index.js +6 -6
  95. package/dist/display/index.d.ts +0 -2
  96. package/dist/display/index.js +0 -6
  97. package/dist/editor/index.d.ts +19 -20
  98. package/dist/editor/index.js +25 -35
  99. package/dist/form/code.d.ts +25 -15
  100. package/dist/form/code.js +44 -41
  101. package/dist/form/fieldRegistry.d.ts +17 -13
  102. package/dist/form/fieldRegistry.js +32 -12
  103. package/dist/form/full.d.ts +17 -13
  104. package/dist/form/full.js +22 -27
  105. package/dist/form/index.d.ts +3 -3
  106. package/dist/form/index.js +3 -3
  107. package/dist/form/markdown.d.ts +13 -8
  108. package/dist/form/markdown.js +22 -23
  109. package/dist/helpers/proximityConnect.d.ts +7 -3
  110. package/dist/helpers/proximityConnect.js +19 -6
  111. package/dist/helpers/workflowEditorHelper.d.ts +12 -5
  112. package/dist/helpers/workflowEditorHelper.js +27 -25
  113. package/dist/index.d.ts +28 -24
  114. package/dist/index.js +27 -50
  115. package/dist/messages/defaults.d.ts +2 -5
  116. package/dist/messages/defaults.js +3 -6
  117. package/dist/messages/index.d.ts +0 -1
  118. package/dist/messages/index.js +0 -1
  119. package/dist/mocks/app-forms.d.ts +6 -2
  120. package/dist/mocks/app-forms.js +11 -4
  121. package/dist/openapi/v1/openapi.yaml +227 -164
  122. package/dist/playground/index.d.ts +2 -3
  123. package/dist/playground/index.js +2 -30
  124. package/dist/playground/mount.d.ts +15 -0
  125. package/dist/playground/mount.js +46 -20
  126. package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
  127. package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
  128. package/dist/registry/builtinFormats.d.ts +9 -18
  129. package/dist/registry/builtinFormats.js +9 -39
  130. package/dist/registry/builtinNodes.d.ts +1 -26
  131. package/dist/registry/builtinNodes.js +14 -50
  132. package/dist/registry/index.d.ts +3 -4
  133. package/dist/registry/index.js +4 -6
  134. package/dist/registry/nodeComponentRegistry.d.ts +182 -15
  135. package/dist/registry/nodeComponentRegistry.js +235 -17
  136. package/dist/registry/workflowFormatRegistry.d.ts +14 -9
  137. package/dist/registry/workflowFormatRegistry.js +24 -8
  138. package/dist/{schema → schemas}/index.d.ts +2 -2
  139. package/dist/{schema → schemas}/index.js +2 -2
  140. package/dist/schemas/v1/workflow.schema.json +53 -6
  141. package/dist/services/agentSpecExecutionService.js +0 -1
  142. package/dist/services/apiVariableService.d.ts +2 -1
  143. package/dist/services/apiVariableService.js +5 -22
  144. package/dist/services/autoSaveService.d.ts +7 -0
  145. package/dist/services/autoSaveService.js +6 -4
  146. package/dist/services/chatService.d.ts +8 -4
  147. package/dist/services/chatService.js +15 -15
  148. package/dist/services/draftStorage.d.ts +129 -13
  149. package/dist/services/draftStorage.js +185 -37
  150. package/dist/services/dynamicSchemaService.d.ts +2 -1
  151. package/dist/services/dynamicSchemaService.js +5 -22
  152. package/dist/services/globalSave.d.ts +13 -12
  153. package/dist/services/globalSave.js +29 -51
  154. package/dist/services/historyService.d.ts +9 -3
  155. package/dist/services/historyService.js +9 -3
  156. package/dist/services/interruptService.d.ts +14 -9
  157. package/dist/services/interruptService.js +27 -27
  158. package/dist/services/nodeExecutionService.d.ts +18 -3
  159. package/dist/services/nodeExecutionService.js +71 -45
  160. package/dist/services/playgroundService.d.ts +14 -9
  161. package/dist/services/playgroundService.js +31 -30
  162. package/dist/services/variableService.d.ts +2 -1
  163. package/dist/services/variableService.js +2 -2
  164. package/dist/services/workflowStorage.js +6 -6
  165. package/dist/stores/apiContext.d.ts +45 -0
  166. package/dist/stores/apiContext.js +65 -0
  167. package/dist/stores/categoriesStore.svelte.d.ts +28 -23
  168. package/dist/stores/categoriesStore.svelte.js +70 -64
  169. package/dist/stores/getInstance.svelte.d.ts +39 -0
  170. package/dist/stores/getInstance.svelte.js +65 -0
  171. package/dist/stores/historyStore.svelte.d.ts +77 -93
  172. package/dist/stores/historyStore.svelte.js +134 -160
  173. package/dist/stores/instanceContainer.svelte.d.ts +111 -0
  174. package/dist/stores/instanceContainer.svelte.js +114 -0
  175. package/dist/stores/interruptStore.svelte.d.ts +112 -82
  176. package/dist/stores/interruptStore.svelte.js +253 -226
  177. package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
  178. package/dist/stores/pipelinePanelStore.svelte.js +61 -14
  179. package/dist/stores/playgroundStore.svelte.d.ts +169 -216
  180. package/dist/stores/playgroundStore.svelte.js +515 -572
  181. package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
  182. package/dist/stores/portCoordinateStore.svelte.js +109 -98
  183. package/dist/stores/settingsStore.svelte.d.ts +4 -1
  184. package/dist/stores/settingsStore.svelte.js +47 -12
  185. package/dist/stores/workflowStore.svelte.d.ts +178 -213
  186. package/dist/stores/workflowStore.svelte.js +449 -501
  187. package/dist/stories/EdgeDecorator.svelte +5 -2
  188. package/dist/stories/NodeDecorator.svelte +5 -3
  189. package/dist/svelte-app.d.ts +60 -10
  190. package/dist/svelte-app.js +157 -53
  191. package/dist/types/events.d.ts +6 -3
  192. package/dist/types/index.d.ts +71 -6
  193. package/dist/types/navbar.d.ts +7 -0
  194. package/dist/types/playground.d.ts +18 -3
  195. package/dist/types/settings.d.ts +13 -0
  196. package/dist/types/settings.js +1 -0
  197. package/dist/utils/colors.d.ts +47 -21
  198. package/dist/utils/colors.js +69 -68
  199. package/dist/utils/connections.d.ts +9 -15
  200. package/dist/utils/connections.js +13 -32
  201. package/dist/utils/duration.d.ts +13 -0
  202. package/dist/utils/duration.js +45 -0
  203. package/dist/utils/formMerge.d.ts +36 -0
  204. package/dist/utils/formMerge.js +70 -0
  205. package/dist/utils/icons.d.ts +5 -2
  206. package/dist/utils/icons.js +6 -5
  207. package/dist/utils/nodeSwap.d.ts +6 -2
  208. package/dist/utils/nodeSwap.js +62 -126
  209. package/dist/utils/nodeTypes.d.ts +17 -8
  210. package/dist/utils/nodeTypes.js +27 -19
  211. package/dist/utils/performanceUtils.js +7 -0
  212. package/package.json +6 -5
  213. package/dist/messages/deprecation.d.ts +0 -20
  214. package/dist/messages/deprecation.js +0 -33
  215. package/dist/registry/plugin.d.ts +0 -215
  216. package/dist/registry/plugin.js +0 -249
  217. package/dist/services/api.d.ts +0 -129
  218. package/dist/services/api.js +0 -217
@@ -3,9 +3,6 @@
3
3
  * Ensures consistent category colors across sidebar and canvas
4
4
  * Uses BEM syntax for CSS classes
5
5
  */
6
- import { getPortCompatibilityChecker } from './connections.js';
7
- import { getCategoryColor as getCategoryColorFromStore } from '../stores/categoriesStore.svelte.js';
8
- import { logger } from './logger.js';
9
6
  /**
10
7
  * Category color mapping to design tokens (CSS variables)
11
8
  * Uses --fd-node-* tokens from tokens.css
@@ -67,51 +64,38 @@ const DEFAULT_DATA_TYPE_COLORS = {
67
64
  * Get the design token for a category color.
68
65
  * Checks the categories store first (which includes API overrides),
69
66
  * then falls back to the static CATEGORY_COLOR_TOKENS map, then to slate.
67
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
68
+ * @param category - The node category
70
69
  */
71
- export function getCategoryColorToken(category) {
72
- return getCategoryColorFromStore(category);
70
+ export function getCategoryColorToken(categories, category) {
71
+ return categories.getColor(category);
73
72
  }
74
73
  /**
75
74
  * Get the reference color token for a data type (configurable version)
75
+ * @param checker - The instance's port compatibility checker (provides data-type config)
76
+ * @param dataType - The data type
76
77
  */
77
- export function getDataTypeColorToken(dataType) {
78
- try {
79
- const checker = getPortCompatibilityChecker();
80
- const config = checker.getDataTypeConfig(dataType);
81
- if (config?.color) {
82
- return config.color;
83
- }
84
- }
85
- catch {
86
- // Fallback to static color mapping if port checker not initialized
78
+ export function getDataTypeColorToken(checker, dataType) {
79
+ const config = checker.getDataTypeConfig(dataType);
80
+ if (config?.color) {
81
+ return config.color;
87
82
  }
88
83
  return DEFAULT_DATA_TYPE_COLORS[dataType.toLowerCase()] || 'var(--fd-node-slate)';
89
84
  }
90
85
  /**
91
86
  * Get data type configuration from port config
87
+ * @param checker - The instance's port compatibility checker
88
+ * @param dataType - The data type
92
89
  */
93
- export function getDataTypeConfig(dataType) {
94
- try {
95
- const checker = getPortCompatibilityChecker();
96
- return checker.getDataTypeConfig(dataType);
97
- }
98
- catch (error) {
99
- logger.warn('Port compatibility checker not initialized:', error);
100
- return undefined;
101
- }
90
+ export function getDataTypeConfig(checker, dataType) {
91
+ return checker.getDataTypeConfig(dataType);
102
92
  }
103
93
  /**
104
94
  * Get all available data types from port configuration
95
+ * @param checker - The instance's port compatibility checker
105
96
  */
106
- export function getAvailableDataTypes() {
107
- try {
108
- const checker = getPortCompatibilityChecker();
109
- return checker.getEnabledDataTypes();
110
- }
111
- catch (error) {
112
- logger.warn('Port compatibility checker not initialized:', error);
113
- return [];
114
- }
97
+ export function getAvailableDataTypes(checker) {
98
+ return checker.getEnabledDataTypes();
115
99
  }
116
100
  /**
117
101
  * Default colors for fallback cases
@@ -124,54 +108,60 @@ export const DEFAULT_COLORS = {
124
108
  };
125
109
  /**
126
110
  * Get category colors
111
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
127
112
  * @param category - The node category
128
113
  * @returns The color configuration for the category
129
114
  */
130
- export function getCategoryColors(category) {
131
- return getCategoryColorFromStore(category);
115
+ export function getCategoryColors(categories, category) {
116
+ return categories.getColor(category);
132
117
  }
133
118
  /**
134
119
  * Get category background color
120
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
135
121
  * @param category - The node category
136
122
  * @returns The background color class
137
123
  */
138
- export function getCategoryBackground(category) {
139
- return getCategoryColors(category);
124
+ export function getCategoryBackground(categories, category) {
125
+ return getCategoryColors(categories, category);
140
126
  }
141
127
  /**
142
128
  * Get category accent color
129
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
143
130
  * @param category - The node category
144
131
  * @returns The accent color class
145
132
  */
146
- export function getCategoryAccent(category) {
147
- return getCategoryColors(category);
133
+ export function getCategoryAccent(categories, category) {
134
+ return getCategoryColors(categories, category);
148
135
  }
149
136
  /**
150
137
  * Get category text color
138
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
151
139
  * @param category - The node category
152
140
  * @returns The text color class
153
141
  */
154
- export function getCategoryText(category) {
155
- return getCategoryColors(category);
142
+ export function getCategoryText(categories, category) {
143
+ return getCategoryColors(categories, category);
156
144
  }
157
145
  /**
158
146
  * Get category border color
147
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
159
148
  * @param category - The node category
160
149
  * @returns The border color class
161
150
  */
162
- export function getCategoryBorder(category) {
163
- return getCategoryColors(category);
151
+ export function getCategoryBorder(categories, category) {
152
+ return getCategoryColors(categories, category);
164
153
  }
165
154
  /**
166
155
  * Get node colors based on category and state
156
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
167
157
  * @param category - The node category
168
158
  * @param isError - Whether the node is in error state
169
159
  * @param isProcessing - Whether the node is processing
170
160
  * @param isSelected - Whether the node is selected
171
161
  * @returns The color configuration object
172
162
  */
173
- export function getNodeColors(category, isError = false, isProcessing = false, isSelected = false) {
174
- const baseColor = getCategoryColors(category);
163
+ export function getNodeColors(categories, category, isError = false, isProcessing = false, isSelected = false) {
164
+ const baseColor = getCategoryColors(categories, category);
175
165
  if (isError) {
176
166
  return {
177
167
  background: 'var(--fd-error-muted)',
@@ -205,67 +195,73 @@ export function getNodeColors(category, isError = false, isProcessing = false, i
205
195
  }
206
196
  /**
207
197
  * Get node background color
198
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
208
199
  * @param category - The node category
209
200
  * @param isError - Whether the node is in error state
210
201
  * @param isProcessing - Whether the node is processing
211
202
  * @param isSelected - Whether the node is selected
212
203
  * @returns The background color
213
204
  */
214
- export function getNodeBackground(category, isError = false, isProcessing = false, isSelected = false) {
215
- return getNodeColors(category, isError, isProcessing, isSelected).background;
205
+ export function getNodeBackground(categories, category, isError = false, isProcessing = false, isSelected = false) {
206
+ return getNodeColors(categories, category, isError, isProcessing, isSelected).background;
216
207
  }
217
208
  /**
218
209
  * Get node accent color
210
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
219
211
  * @param category - The node category
220
212
  * @param isError - Whether the node is in error state
221
213
  * @param isProcessing - Whether the node is processing
222
214
  * @param isSelected - Whether the node is selected
223
215
  * @returns The accent color
224
216
  */
225
- export function getNodeAccent(category, isError = false, isProcessing = false, isSelected = false) {
226
- return getNodeColors(category, isError, isProcessing, isSelected).accent;
217
+ export function getNodeAccent(categories, category, isError = false, isProcessing = false, isSelected = false) {
218
+ return getNodeColors(categories, category, isError, isProcessing, isSelected).accent;
227
219
  }
228
220
  /**
229
221
  * Get node text color
222
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
230
223
  * @param category - The node category
231
224
  * @param isError - Whether the node is in error state
232
225
  * @param isProcessing - Whether the node is processing
233
226
  * @param isSelected - Whether the node is selected
234
227
  * @returns The text color
235
228
  */
236
- export function getNodeText(category, isError = false, isProcessing = false, isSelected = false) {
237
- return getNodeColors(category, isError, isProcessing, isSelected).text;
229
+ export function getNodeText(categories, category, isError = false, isProcessing = false, isSelected = false) {
230
+ return getNodeColors(categories, category, isError, isProcessing, isSelected).text;
238
231
  }
239
232
  /**
240
233
  * Get node border color
234
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
241
235
  * @param category - The node category
242
236
  * @param isError - Whether the node is in error state
243
237
  * @param isProcessing - Whether the node is processing
244
238
  * @param isSelected - Whether the node is selected
245
239
  * @returns The border color
246
240
  */
247
- export function getNodeBorder(category, isError = false, isProcessing = false, isSelected = false) {
248
- return getNodeColors(category, isError, isProcessing, isSelected).border;
241
+ export function getNodeBorder(categories, category, isError = false, isProcessing = false, isSelected = false) {
242
+ return getNodeColors(categories, category, isError, isProcessing, isSelected).border;
249
243
  }
250
244
  /**
251
245
  * Get data type color
246
+ * @param checker - The instance's port compatibility checker
252
247
  * @param dataType - The data type
253
248
  * @returns The color for the data type
254
249
  */
255
- export function getDataTypeColor(dataType) {
256
- return getDataTypeColorToken(dataType);
250
+ export function getDataTypeColor(checker, dataType) {
251
+ return getDataTypeColorToken(checker, dataType);
257
252
  }
258
253
  /**
259
254
  * Parse typed array notation and get display information
255
+ * @param checker - The instance's port compatibility checker
260
256
  * @param dataType - The data type (e.g., "string[]", "number", "object[]")
261
257
  * @returns Object with display information
262
258
  */
263
- export function parseDataTypeDisplay(dataType) {
259
+ export function parseDataTypeDisplay(checker, dataType) {
264
260
  // Check if it's a typed array (ends with [])
265
261
  const isArray = dataType.endsWith('[]');
266
262
  if (isArray) {
267
263
  const elementType = dataType.slice(0, -2); // Remove []
268
- const config = getDataTypeConfig(dataType);
264
+ const config = getDataTypeConfig(checker, dataType);
269
265
  return {
270
266
  baseType: dataType,
271
267
  isArray: true,
@@ -274,7 +270,7 @@ export function parseDataTypeDisplay(dataType) {
274
270
  };
275
271
  }
276
272
  else {
277
- const config = getDataTypeConfig(dataType);
273
+ const config = getDataTypeConfig(checker, dataType);
278
274
  return {
279
275
  baseType: dataType,
280
276
  isArray: false,
@@ -284,11 +280,12 @@ export function parseDataTypeDisplay(dataType) {
284
280
  }
285
281
  /**
286
282
  * Get formatted display text for a data type
283
+ * @param checker - The instance's port compatibility checker
287
284
  * @param dataType - The data type
288
285
  * @returns Formatted display text
289
286
  */
290
- export function getDataTypeDisplayText(dataType) {
291
- const parsed = parseDataTypeDisplay(dataType);
287
+ export function getDataTypeDisplayText(checker, dataType) {
288
+ const parsed = parseDataTypeDisplay(checker, dataType);
292
289
  return parsed.displayName;
293
290
  }
294
291
  /**
@@ -391,42 +388,46 @@ export function resolveColorToken(token) {
391
388
  }
392
389
  /**
393
390
  * Get the appropriate contrast text color for a data type badge
391
+ * @param checker - The instance's port compatibility checker
394
392
  * @param dataType - The data type (e.g., "array", "string", "number")
395
393
  * @returns CSS color value for text that provides good contrast on the data type's background
396
394
  */
397
- export function getContrastTextColorForDataType(dataType) {
398
- const colorToken = getDataTypeColorToken(dataType);
395
+ export function getContrastTextColorForDataType(checker, dataType) {
396
+ const colorToken = getDataTypeColorToken(checker, dataType);
399
397
  const hexColor = resolveColorToken(colorToken);
400
398
  return getContrastTextColor(hexColor);
401
399
  }
402
400
  /**
403
401
  * Get the appropriate contrast text color for a category badge
402
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
404
403
  * @param category - The node category
405
404
  * @returns CSS color value for text that provides good contrast on the category's background
406
405
  */
407
- export function getContrastTextColorForCategory(category) {
408
- const colorToken = getCategoryColorToken(category);
406
+ export function getContrastTextColorForCategory(categories, category) {
407
+ const colorToken = getCategoryColorToken(categories, category);
409
408
  const hexColor = resolveColorToken(colorToken);
410
409
  return getContrastTextColor(hexColor);
411
410
  }
412
411
  /**
413
412
  * Get a semi-transparent tinted background color for ports
414
413
  * Creates a cohesive look with the icon wrapper styling
414
+ * @param checker - The instance's port compatibility checker
415
415
  * @param dataType - The data type
416
416
  * @param opacity - Opacity percentage (default 25%)
417
417
  * @returns CSS color-mix expression for the tinted background
418
418
  */
419
- export function getPortBackgroundColor(dataType, opacity = 25) {
420
- const colorToken = getDataTypeColorToken(dataType);
419
+ export function getPortBackgroundColor(checker, dataType, opacity = 25) {
420
+ const colorToken = getDataTypeColorToken(checker, dataType);
421
421
  return `color-mix(in srgb, ${colorToken} ${opacity}%, transparent)`;
422
422
  }
423
423
  /**
424
424
  * Get the border color for ports (solid data type color)
425
+ * @param checker - The instance's port compatibility checker
425
426
  * @param dataType - The data type
426
427
  * @returns CSS color value for the port border
427
428
  */
428
- export function getPortBorderColor(dataType) {
429
- return getDataTypeColorToken(dataType);
429
+ export function getPortBorderColor(checker, dataType) {
430
+ return getDataTypeColorToken(checker, dataType);
430
431
  }
431
432
  /**
432
433
  * Convert RGB components to hex color string
@@ -32,6 +32,12 @@ export declare class PortCompatibilityChecker {
32
32
  private portConfig;
33
33
  private compatibilityMap;
34
34
  constructor(portConfig: PortConfig);
35
+ /**
36
+ * Replace the port configuration and rebuild the compatibility map in place.
37
+ * Used by mount to apply the backend-fetched port config to an instance's
38
+ * checker without swapping the instance field.
39
+ */
40
+ reinitialize(portConfig: PortConfig): void;
35
41
  /**
36
42
  * Build the compatibility map from configuration rules
37
43
  */
@@ -53,22 +59,10 @@ export declare class PortCompatibilityChecker {
53
59
  */
54
60
  getEnabledDataTypes(): PortDataTypeConfig[];
55
61
  }
56
- /**
57
- * Initialize the global port compatibility checker
58
- */
59
- export declare function initializePortCompatibility(portConfig: PortConfig): void;
60
- /**
61
- * Returns true if the port compatibility checker has been initialized.
62
- */
63
- export declare function isPortCompatibilityInitialized(): boolean;
64
- /**
65
- * Get the global port compatibility checker
66
- */
67
- export declare function getPortCompatibilityChecker(): PortCompatibilityChecker;
68
62
  /**
69
63
  * Get all possible connections from a source node to target nodes
70
64
  */
71
- export declare function getPossibleConnections(sourceNode: WorkflowNode, targetNodes: WorkflowNode[], nodeTypes: NodeMetadata[]): Array<{
65
+ export declare function getPossibleConnections(checker: PortCompatibilityChecker, sourceNode: WorkflowNode, targetNodes: WorkflowNode[], nodeTypes: NodeMetadata[]): Array<{
72
66
  sourceNodeId: string;
73
67
  sourcePortId: string;
74
68
  sourcePort: NodePort;
@@ -80,14 +74,14 @@ export declare function getPossibleConnections(sourceNode: WorkflowNode, targetN
80
74
  /**
81
75
  * Validate if a specific connection is valid
82
76
  */
83
- export declare function validateConnection(sourceNodeId: string, sourcePortId: string, targetNodeId: string, targetPortId: string, nodes: WorkflowNode[], nodeTypes: NodeMetadata[]): {
77
+ export declare function validateConnection(checker: PortCompatibilityChecker, sourceNodeId: string, sourcePortId: string, targetNodeId: string, targetPortId: string, nodes: WorkflowNode[], nodeTypes: NodeMetadata[]): {
84
78
  valid: boolean;
85
79
  error?: string;
86
80
  };
87
81
  /**
88
82
  * Get connection suggestions for a node
89
83
  */
90
- export declare function getConnectionSuggestions(nodeId: string, nodes: WorkflowNode[], nodeTypes: NodeMetadata[]): Array<{
84
+ export declare function getConnectionSuggestions(checker: PortCompatibilityChecker, nodeId: string, nodes: WorkflowNode[], nodeTypes: NodeMetadata[]): Array<{
91
85
  nodeId: string;
92
86
  nodeName: string;
93
87
  portId: string;
@@ -45,6 +45,15 @@ export class PortCompatibilityChecker {
45
45
  this.compatibilityMap = new Map();
46
46
  this.buildCompatibilityMap();
47
47
  }
48
+ /**
49
+ * Replace the port configuration and rebuild the compatibility map in place.
50
+ * Used by mount to apply the backend-fetched port config to an instance's
51
+ * checker without swapping the instance field.
52
+ */
53
+ reinitialize(portConfig) {
54
+ this.portConfig = portConfig;
55
+ this.buildCompatibilityMap();
56
+ }
48
57
  /**
49
58
  * Build the compatibility map from configuration rules
50
59
  */
@@ -106,41 +115,16 @@ export class PortCompatibilityChecker {
106
115
  return this.portConfig.dataTypes.filter((dt) => dt.enabled !== false);
107
116
  }
108
117
  }
109
- // Global instance - will be initialized with configuration
110
- let globalCompatibilityChecker = null;
111
- /**
112
- * Initialize the global port compatibility checker
113
- */
114
- export function initializePortCompatibility(portConfig) {
115
- globalCompatibilityChecker = new PortCompatibilityChecker(portConfig);
116
- }
117
- /**
118
- * Returns true if the port compatibility checker has been initialized.
119
- */
120
- export function isPortCompatibilityInitialized() {
121
- return globalCompatibilityChecker !== null;
122
- }
123
- /**
124
- * Get the global port compatibility checker
125
- */
126
- export function getPortCompatibilityChecker() {
127
- if (!globalCompatibilityChecker) {
128
- throw new Error('Port compatibility checker not initialized. Call initializePortCompatibility() first.');
129
- }
130
- return globalCompatibilityChecker;
131
- }
132
118
  /**
133
119
  * Get all possible connections from a source node to target nodes
134
120
  */
135
- export function getPossibleConnections(sourceNode, targetNodes, nodeTypes) {
121
+ export function getPossibleConnections(checker, sourceNode, targetNodes, nodeTypes) {
136
122
  const sourceMetadata = nodeTypes.find((nt) => nt.id === sourceNode.data.metadata.id);
137
123
  if (!sourceMetadata)
138
124
  return [];
139
125
  const possibleConnections = [];
140
126
  // Get all output ports from source node
141
127
  const sourceOutputs = sourceMetadata.outputs;
142
- // Get the compatibility checker instance
143
- const checker = getPortCompatibilityChecker();
144
128
  // Check each target node
145
129
  for (const targetNode of targetNodes) {
146
130
  if (targetNode.id === sourceNode.id)
@@ -171,7 +155,7 @@ export function getPossibleConnections(sourceNode, targetNodes, nodeTypes) {
171
155
  /**
172
156
  * Validate if a specific connection is valid
173
157
  */
174
- export function validateConnection(sourceNodeId, sourcePortId, targetNodeId, targetPortId, nodes, nodeTypes) {
158
+ export function validateConnection(checker, sourceNodeId, sourcePortId, targetNodeId, targetPortId, nodes, nodeTypes) {
175
159
  // Check if nodes exist
176
160
  const sourceNode = nodes.find((n) => n.id === sourceNodeId);
177
161
  const targetNode = nodes.find((n) => n.id === targetNodeId);
@@ -200,8 +184,7 @@ export function validateConnection(sourceNodeId, sourcePortId, targetNodeId, tar
200
184
  if (!targetPort) {
201
185
  return { valid: false, error: 'Target port not found' };
202
186
  }
203
- // Check data type compatibility using the global checker
204
- const checker = getPortCompatibilityChecker();
187
+ // Check data type compatibility using the instance's checker
205
188
  if (!checker.areDataTypesCompatible(sourcePort.dataType, targetPort.dataType)) {
206
189
  return {
207
190
  valid: false,
@@ -213,7 +196,7 @@ export function validateConnection(sourceNodeId, sourcePortId, targetNodeId, tar
213
196
  /**
214
197
  * Get connection suggestions for a node
215
198
  */
216
- export function getConnectionSuggestions(nodeId, nodes, nodeTypes) {
199
+ export function getConnectionSuggestions(checker, nodeId, nodes, nodeTypes) {
217
200
  const node = nodes.find((n) => n.id === nodeId);
218
201
  if (!node)
219
202
  return [];
@@ -223,8 +206,6 @@ export function getConnectionSuggestions(nodeId, nodes, nodeTypes) {
223
206
  const suggestions = [];
224
207
  // Get all other nodes
225
208
  const otherNodes = nodes.filter((n) => n.id !== nodeId);
226
- // Get the compatibility checker instance
227
- const checker = getPortCompatibilityChecker();
228
209
  for (const otherNode of otherNodes) {
229
210
  const otherMetadata = nodeTypes.find((nt) => nt.id === otherNode.data.metadata.id);
230
211
  if (!otherMetadata)
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Duration formatting helpers.
3
+ *
4
+ * Mirrors the backend `Drupal\flowdrop\Utility\Duration::formatMicroseconds()`
5
+ * tiers so the playground and the Drupal admin pages render identical values.
6
+ */
7
+ /**
8
+ * Formats a duration in human-readable form from microseconds.
9
+ *
10
+ * Examples: `150µs`, `2.5ms`, `25.1ms`, `250ms`, `1.23s`, `45s`,
11
+ * `2m 30s`, `1h 30m`.
12
+ */
13
+ export declare function formatMicroseconds(microseconds: number | null | undefined): string | null;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Duration formatting helpers.
3
+ *
4
+ * Mirrors the backend `Drupal\flowdrop\Utility\Duration::formatMicroseconds()`
5
+ * tiers so the playground and the Drupal admin pages render identical values.
6
+ */
7
+ /**
8
+ * Formats a duration in human-readable form from microseconds.
9
+ *
10
+ * Examples: `150µs`, `2.5ms`, `25.1ms`, `250ms`, `1.23s`, `45s`,
11
+ * `2m 30s`, `1h 30m`.
12
+ */
13
+ export function formatMicroseconds(microseconds) {
14
+ if (microseconds == null || !Number.isFinite(microseconds) || microseconds < 0)
15
+ return null;
16
+ const us = Math.round(microseconds);
17
+ if (us < 1000) {
18
+ return `${us}µs`;
19
+ }
20
+ if (us < 1_000_000) {
21
+ const ms = us / 1000;
22
+ if (us < 100_000) {
23
+ // 2 decimals below 10ms, 1 decimal below 100ms — matches PHP round().
24
+ const decimals = us < 10_000 ? 2 : 1;
25
+ // Drop trailing zeros the way PHP round() renders (2.50 → 2.5, 3.00 → 3).
26
+ return `${parseFloat(ms.toFixed(decimals))}ms`;
27
+ }
28
+ return `${Math.round(ms)}ms`;
29
+ }
30
+ if (us < 10_000_000) {
31
+ return `${parseFloat((us / 1_000_000).toFixed(2))}s`;
32
+ }
33
+ if (us < 60_000_000) {
34
+ return `${Math.floor(us / 1_000_000)}s`;
35
+ }
36
+ const totalSeconds = Math.floor(us / 1_000_000);
37
+ if (us < 3_600_000_000) {
38
+ const minutes = Math.floor(totalSeconds / 60);
39
+ const secs = totalSeconds % 60;
40
+ return secs > 0 ? `${minutes}m ${secs}s` : `${minutes}m`;
41
+ }
42
+ const hours = Math.floor(totalSeconds / 3600);
43
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
44
+ return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
45
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Form value merge — shared by `SchemaForm` and `ConfigForm`.
3
+ *
4
+ * Produces the view of form values that children read via context. Precedence
5
+ * per key:
6
+ *
7
+ * 1. `key in edits` → use the user's local edit
8
+ * 2. `source[key] !== undefined` → use the prop value (including null/0/false/'')
9
+ * 3. otherwise → use the schema field's `default`
10
+ *
11
+ * Keeping this separate from the host components means the test pins the same
12
+ * function the components run, not a parallel implementation.
13
+ */
14
+ export declare function mergeWithDefaults(schema: {
15
+ properties?: Record<string, unknown>;
16
+ } | undefined, source: Record<string, unknown>, edits: Record<string, unknown>): Record<string, unknown>;
17
+ /**
18
+ * Compute the cascade-clear set when a single field changes — shared by
19
+ * `SchemaForm` and `ConfigForm`.
20
+ *
21
+ * When `changedKey` changes, any property whose `autocomplete.params` references
22
+ * `changedKey` (directly or transitively) should have its value cleared: the
23
+ * old dependent value was computed against the old parent value and is now
24
+ * stale.
25
+ *
26
+ * Returns a map of `{ dependentKey -> clearValue }` to apply on top of the
27
+ * caller's edits buffer. Single-value autocompletes clear to `''`; ones with
28
+ * `multiple: true` clear to `[]`.
29
+ *
30
+ * This logic lives in the parent form (not in `FormAutocomplete`) so it only
31
+ * runs on user-driven changes via `handleFieldChange`, not on undo/redo,
32
+ * programmatic resets, or collaborative edits (#33).
33
+ */
34
+ export declare function cascadeClearAutocompleteDependents(schema: {
35
+ properties?: Record<string, unknown>;
36
+ } | undefined, changedKey: string): Record<string, unknown>;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Form value merge — shared by `SchemaForm` and `ConfigForm`.
3
+ *
4
+ * Produces the view of form values that children read via context. Precedence
5
+ * per key:
6
+ *
7
+ * 1. `key in edits` → use the user's local edit
8
+ * 2. `source[key] !== undefined` → use the prop value (including null/0/false/'')
9
+ * 3. otherwise → use the schema field's `default`
10
+ *
11
+ * Keeping this separate from the host components means the test pins the same
12
+ * function the components run, not a parallel implementation.
13
+ */
14
+ export function mergeWithDefaults(schema, source, edits) {
15
+ if (!schema?.properties)
16
+ return {};
17
+ const merged = {};
18
+ for (const [key, field] of Object.entries(schema.properties)) {
19
+ if (key in edits) {
20
+ merged[key] = edits[key];
21
+ }
22
+ else {
23
+ const fieldConfig = field;
24
+ merged[key] = source[key] !== undefined ? source[key] : fieldConfig.default;
25
+ }
26
+ }
27
+ return merged;
28
+ }
29
+ /**
30
+ * Compute the cascade-clear set when a single field changes — shared by
31
+ * `SchemaForm` and `ConfigForm`.
32
+ *
33
+ * When `changedKey` changes, any property whose `autocomplete.params` references
34
+ * `changedKey` (directly or transitively) should have its value cleared: the
35
+ * old dependent value was computed against the old parent value and is now
36
+ * stale.
37
+ *
38
+ * Returns a map of `{ dependentKey -> clearValue }` to apply on top of the
39
+ * caller's edits buffer. Single-value autocompletes clear to `''`; ones with
40
+ * `multiple: true` clear to `[]`.
41
+ *
42
+ * This logic lives in the parent form (not in `FormAutocomplete`) so it only
43
+ * runs on user-driven changes via `handleFieldChange`, not on undo/redo,
44
+ * programmatic resets, or collaborative edits (#33).
45
+ */
46
+ export function cascadeClearAutocompleteDependents(schema, changedKey) {
47
+ if (!schema?.properties)
48
+ return {};
49
+ const cleared = new Set([changedKey]);
50
+ const result = {};
51
+ let added = true;
52
+ while (added) {
53
+ added = false;
54
+ for (const [depKey, depField] of Object.entries(schema.properties)) {
55
+ if (cleared.has(depKey))
56
+ continue;
57
+ const field = depField;
58
+ const params = field.autocomplete?.params;
59
+ if (!params)
60
+ continue;
61
+ const dependsOnCleared = Object.values(params).some((fieldName) => cleared.has(fieldName));
62
+ if (dependsOnCleared) {
63
+ result[depKey] = field.autocomplete?.multiple ? [] : '';
64
+ cleared.add(depKey);
65
+ added = true;
66
+ }
67
+ }
68
+ }
69
+ return result;
70
+ }
@@ -3,6 +3,7 @@
3
3
  * Ensures consistent icon usage across all components
4
4
  */
5
5
  import type { NodeCategory } from '../types/index.js';
6
+ import type { CategoriesStore } from '../stores/categoriesStore.svelte.js';
6
7
  /**
7
8
  * Default icons for different contexts
8
9
  */
@@ -72,19 +73,21 @@ export declare const DEFAULT_ICONS: {
72
73
  export declare const CATEGORY_ICONS: Record<string, string>;
73
74
  /**
74
75
  * Get the appropriate icon for a node
76
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
75
77
  * @param nodeIcon - The node's specific icon
76
78
  * @param category - The node's category
77
79
  * @returns The icon to use
78
80
  */
79
- export declare function getNodeIcon(nodeIcon?: string, category?: NodeCategory): string;
81
+ export declare function getNodeIcon(categories: CategoriesStore, nodeIcon?: string, category?: NodeCategory): string;
80
82
  /**
81
83
  * Get the appropriate icon for a category.
82
84
  * Checks the categories store first (which includes API overrides),
83
85
  * then falls back to the static CATEGORY_ICONS map, then to the default.
86
+ * @param categories - The instance's categories store (e.g. `fd.categories`)
84
87
  * @param category - The category
85
88
  * @returns The icon to use
86
89
  */
87
- export declare function getCategoryIcon(category: NodeCategory): string;
90
+ export declare function getCategoryIcon(categories: CategoriesStore, category: NodeCategory): string;
88
91
  /**
89
92
  * Get a default icon by key
90
93
  * @param key - The icon key from DEFAULT_ICONS