@flowdrop/flowdrop 1.0.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.
Files changed (403) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +252 -0
  3. package/dist/adapters/WorkflowAdapter.d.ts +167 -0
  4. package/dist/adapters/WorkflowAdapter.js +368 -0
  5. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +96 -0
  6. package/dist/adapters/agentspec/AgentSpecAdapter.js +626 -0
  7. package/dist/adapters/agentspec/agentAdapter.d.ts +59 -0
  8. package/dist/adapters/agentspec/agentAdapter.js +91 -0
  9. package/dist/adapters/agentspec/autoLayout.d.ts +34 -0
  10. package/dist/adapters/agentspec/autoLayout.js +127 -0
  11. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +73 -0
  12. package/dist/adapters/agentspec/componentTypeDefaults.js +238 -0
  13. package/dist/adapters/agentspec/defaultNodeTypes.d.ts +53 -0
  14. package/dist/adapters/agentspec/defaultNodeTypes.js +561 -0
  15. package/dist/adapters/agentspec/index.d.ts +37 -0
  16. package/dist/adapters/agentspec/index.js +39 -0
  17. package/dist/adapters/agentspec/validator.d.ts +34 -0
  18. package/dist/adapters/agentspec/validator.js +169 -0
  19. package/dist/api/enhanced-client.d.ts +183 -0
  20. package/dist/api/enhanced-client.js +430 -0
  21. package/dist/components/App.svelte +981 -0
  22. package/dist/components/App.svelte.d.ts +54 -0
  23. package/dist/components/CanvasBanner.stories.svelte +29 -0
  24. package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
  25. package/dist/components/CanvasBanner.svelte +57 -0
  26. package/dist/components/CanvasBanner.svelte.d.ts +8 -0
  27. package/dist/components/ConfigForm.svelte +1138 -0
  28. package/dist/components/ConfigForm.svelte.d.ts +44 -0
  29. package/dist/components/ConfigModal.svelte +188 -0
  30. package/dist/components/ConfigModal.svelte.d.ts +13 -0
  31. package/dist/components/ConfigPanel.stories.svelte +47 -0
  32. package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
  33. package/dist/components/ConfigPanel.svelte +182 -0
  34. package/dist/components/ConfigPanel.svelte.d.ts +32 -0
  35. package/dist/components/ConnectionLine.svelte +32 -0
  36. package/dist/components/ConnectionLine.svelte.d.ts +3 -0
  37. package/dist/components/EdgeRefresher.svelte +41 -0
  38. package/dist/components/EdgeRefresher.svelte.d.ts +9 -0
  39. package/dist/components/FlowDropZone.svelte +83 -0
  40. package/dist/components/FlowDropZone.svelte.d.ts +13 -0
  41. package/dist/components/LoadingSpinner.stories.svelte +30 -0
  42. package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
  43. package/dist/components/LoadingSpinner.svelte +36 -0
  44. package/dist/components/LoadingSpinner.svelte.d.ts +8 -0
  45. package/dist/components/Logo.stories.svelte +22 -0
  46. package/dist/components/Logo.stories.svelte.d.ts +27 -0
  47. package/dist/components/Logo.svelte +102 -0
  48. package/dist/components/Logo.svelte.d.ts +26 -0
  49. package/dist/components/LogsSidebar.svelte +563 -0
  50. package/dist/components/LogsSidebar.svelte.d.ts +17 -0
  51. package/dist/components/MarkdownDisplay.stories.svelte +36 -0
  52. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
  53. package/dist/components/MarkdownDisplay.svelte +29 -0
  54. package/dist/components/MarkdownDisplay.svelte.d.ts +7 -0
  55. package/dist/components/Navbar.stories.svelte +53 -0
  56. package/dist/components/Navbar.stories.svelte.d.ts +27 -0
  57. package/dist/components/Navbar.svelte +726 -0
  58. package/dist/components/Navbar.svelte.d.ts +29 -0
  59. package/dist/components/NodeSidebar.svelte +762 -0
  60. package/dist/components/NodeSidebar.svelte.d.ts +9 -0
  61. package/dist/components/NodeStatusOverlay.stories.svelte +85 -0
  62. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
  63. package/dist/components/NodeStatusOverlay.svelte +327 -0
  64. package/dist/components/NodeStatusOverlay.svelte.d.ts +11 -0
  65. package/dist/components/PipelineStatus.svelte +314 -0
  66. package/dist/components/PipelineStatus.svelte.d.ts +20 -0
  67. package/dist/components/PortCoordinateTracker.svelte +58 -0
  68. package/dist/components/PortCoordinateTracker.svelte.d.ts +12 -0
  69. package/dist/components/ReadOnlyDetails.svelte +170 -0
  70. package/dist/components/ReadOnlyDetails.svelte.d.ts +25 -0
  71. package/dist/components/SchemaForm.stories.svelte +116 -0
  72. package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
  73. package/dist/components/SchemaForm.svelte +536 -0
  74. package/dist/components/SchemaForm.svelte.d.ts +83 -0
  75. package/dist/components/SettingsModal.svelte +279 -0
  76. package/dist/components/SettingsModal.svelte.d.ts +23 -0
  77. package/dist/components/SettingsPanel.svelte +638 -0
  78. package/dist/components/SettingsPanel.svelte.d.ts +21 -0
  79. package/dist/components/StatusIcon.stories.svelte +60 -0
  80. package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
  81. package/dist/components/StatusIcon.svelte +119 -0
  82. package/dist/components/StatusIcon.svelte.d.ts +10 -0
  83. package/dist/components/StatusLabel.stories.svelte +17 -0
  84. package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
  85. package/dist/components/StatusLabel.svelte +33 -0
  86. package/dist/components/StatusLabel.svelte.d.ts +7 -0
  87. package/dist/components/ThemeToggle.stories.svelte +25 -0
  88. package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
  89. package/dist/components/ThemeToggle.svelte +185 -0
  90. package/dist/components/ThemeToggle.svelte.d.ts +14 -0
  91. package/dist/components/UniversalNode.svelte +155 -0
  92. package/dist/components/UniversalNode.svelte.d.ts +15 -0
  93. package/dist/components/WorkflowEditor.svelte +1035 -0
  94. package/dist/components/WorkflowEditor.svelte.d.ts +23 -0
  95. package/dist/components/form/FormArray.svelte +1049 -0
  96. package/dist/components/form/FormArray.svelte.d.ts +22 -0
  97. package/dist/components/form/FormAutocomplete.svelte +1009 -0
  98. package/dist/components/form/FormAutocomplete.svelte.d.ts +25 -0
  99. package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
  100. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
  101. package/dist/components/form/FormCheckboxGroup.svelte +155 -0
  102. package/dist/components/form/FormCheckboxGroup.svelte.d.ts +17 -0
  103. package/dist/components/form/FormCodeEditor.svelte +458 -0
  104. package/dist/components/form/FormCodeEditor.svelte.d.ts +25 -0
  105. package/dist/components/form/FormField.svelte +417 -0
  106. package/dist/components/form/FormField.svelte.d.ts +29 -0
  107. package/dist/components/form/FormFieldLight.svelte +425 -0
  108. package/dist/components/form/FormFieldLight.svelte.d.ts +18 -0
  109. package/dist/components/form/FormFieldWrapper.stories.svelte +53 -0
  110. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
  111. package/dist/components/form/FormFieldWrapper.svelte +125 -0
  112. package/dist/components/form/FormFieldWrapper.svelte.d.ts +18 -0
  113. package/dist/components/form/FormFieldset.svelte +142 -0
  114. package/dist/components/form/FormFieldset.svelte.d.ts +11 -0
  115. package/dist/components/form/FormMarkdownEditor.svelte +752 -0
  116. package/dist/components/form/FormMarkdownEditor.svelte.d.ts +33 -0
  117. package/dist/components/form/FormNumberField.stories.svelte +36 -0
  118. package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
  119. package/dist/components/form/FormNumberField.svelte +112 -0
  120. package/dist/components/form/FormNumberField.svelte.d.ts +25 -0
  121. package/dist/components/form/FormRangeField.stories.svelte +31 -0
  122. package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
  123. package/dist/components/form/FormRangeField.svelte +246 -0
  124. package/dist/components/form/FormRangeField.svelte.d.ts +23 -0
  125. package/dist/components/form/FormSelect.stories.svelte +50 -0
  126. package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
  127. package/dist/components/form/FormSelect.svelte +129 -0
  128. package/dist/components/form/FormSelect.svelte.d.ts +20 -0
  129. package/dist/components/form/FormTemplateEditor.svelte +825 -0
  130. package/dist/components/form/FormTemplateEditor.svelte.d.ts +41 -0
  131. package/dist/components/form/FormTextField.stories.svelte +30 -0
  132. package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
  133. package/dist/components/form/FormTextField.svelte +91 -0
  134. package/dist/components/form/FormTextField.svelte.d.ts +19 -0
  135. package/dist/components/form/FormTextarea.stories.svelte +34 -0
  136. package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
  137. package/dist/components/form/FormTextarea.svelte +97 -0
  138. package/dist/components/form/FormTextarea.svelte.d.ts +21 -0
  139. package/dist/components/form/FormToggle.stories.svelte +30 -0
  140. package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
  141. package/dist/components/form/FormToggle.svelte +126 -0
  142. package/dist/components/form/FormToggle.svelte.d.ts +19 -0
  143. package/dist/components/form/FormUISchemaRenderer.svelte +136 -0
  144. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +32 -0
  145. package/dist/components/form/index.d.ts +50 -0
  146. package/dist/components/form/index.js +54 -0
  147. package/dist/components/form/templateAutocomplete.d.ts +29 -0
  148. package/dist/components/form/templateAutocomplete.js +254 -0
  149. package/dist/components/form/types.d.ts +485 -0
  150. package/dist/components/form/types.js +73 -0
  151. package/dist/components/interrupt/ChoicePrompt.stories.svelte +52 -0
  152. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
  153. package/dist/components/interrupt/ChoicePrompt.svelte +401 -0
  154. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +23 -0
  155. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +71 -0
  156. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
  157. package/dist/components/interrupt/ConfirmationPrompt.svelte +292 -0
  158. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +25 -0
  159. package/dist/components/interrupt/FormPrompt.svelte +236 -0
  160. package/dist/components/interrupt/FormPrompt.svelte.d.ts +23 -0
  161. package/dist/components/interrupt/InterruptBubble.svelte +601 -0
  162. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
  163. package/dist/components/interrupt/ReviewPrompt.stories.svelte +67 -0
  164. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
  165. package/dist/components/interrupt/ReviewPrompt.svelte +861 -0
  166. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
  167. package/dist/components/interrupt/TextInputPrompt.stories.svelte +47 -0
  168. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
  169. package/dist/components/interrupt/TextInputPrompt.svelte +346 -0
  170. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +23 -0
  171. package/dist/components/interrupt/index.d.ts +13 -0
  172. package/dist/components/interrupt/index.js +15 -0
  173. package/dist/components/layouts/MainLayout.svelte +718 -0
  174. package/dist/components/layouts/MainLayout.svelte.d.ts +62 -0
  175. package/dist/components/nodes/GatewayNode.stories.svelte +108 -0
  176. package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
  177. package/dist/components/nodes/GatewayNode.svelte +591 -0
  178. package/dist/components/nodes/GatewayNode.svelte.d.ts +15 -0
  179. package/dist/components/nodes/IdeaNode.stories.svelte +52 -0
  180. package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
  181. package/dist/components/nodes/IdeaNode.svelte +455 -0
  182. package/dist/components/nodes/IdeaNode.svelte.d.ts +24 -0
  183. package/dist/components/nodes/NotesNode.stories.svelte +76 -0
  184. package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
  185. package/dist/components/nodes/NotesNode.svelte +378 -0
  186. package/dist/components/nodes/NotesNode.svelte.d.ts +24 -0
  187. package/dist/components/nodes/SimpleNode.stories.svelte +159 -0
  188. package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
  189. package/dist/components/nodes/SimpleNode.svelte +451 -0
  190. package/dist/components/nodes/SimpleNode.svelte.d.ts +25 -0
  191. package/dist/components/nodes/SquareNode.stories.svelte +82 -0
  192. package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
  193. package/dist/components/nodes/SquareNode.svelte +407 -0
  194. package/dist/components/nodes/SquareNode.svelte.d.ts +25 -0
  195. package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
  196. package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
  197. package/dist/components/nodes/TerminalNode.svelte +690 -0
  198. package/dist/components/nodes/TerminalNode.svelte.d.ts +25 -0
  199. package/dist/components/nodes/ToolNode.stories.svelte +189 -0
  200. package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
  201. package/dist/components/nodes/ToolNode.svelte +471 -0
  202. package/dist/components/nodes/ToolNode.svelte.d.ts +36 -0
  203. package/dist/components/nodes/WorkflowNode.stories.svelte +55 -0
  204. package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
  205. package/dist/components/nodes/WorkflowNode.svelte +571 -0
  206. package/dist/components/nodes/WorkflowNode.svelte.d.ts +15 -0
  207. package/dist/components/playground/ChatPanel.svelte +905 -0
  208. package/dist/components/playground/ChatPanel.svelte.d.ts +46 -0
  209. package/dist/components/playground/ExecutionLogs.svelte +488 -0
  210. package/dist/components/playground/ExecutionLogs.svelte.d.ts +14 -0
  211. package/dist/components/playground/InputCollector.svelte +444 -0
  212. package/dist/components/playground/InputCollector.svelte.d.ts +16 -0
  213. package/dist/components/playground/MessageBubble.stories.svelte +62 -0
  214. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
  215. package/dist/components/playground/MessageBubble.svelte +633 -0
  216. package/dist/components/playground/MessageBubble.svelte.d.ts +24 -0
  217. package/dist/components/playground/Playground.svelte +1075 -0
  218. package/dist/components/playground/Playground.svelte.d.ts +25 -0
  219. package/dist/components/playground/PlaygroundModal.svelte +220 -0
  220. package/dist/components/playground/PlaygroundModal.svelte.d.ts +25 -0
  221. package/dist/components/playground/SessionManager.svelte +538 -0
  222. package/dist/components/playground/SessionManager.svelte.d.ts +20 -0
  223. package/dist/config/agentSpecEndpoints.d.ts +70 -0
  224. package/dist/config/agentSpecEndpoints.js +65 -0
  225. package/dist/config/constants.d.ts +43 -0
  226. package/dist/config/constants.js +31 -0
  227. package/dist/config/defaultCategories.d.ts +7 -0
  228. package/dist/config/defaultCategories.js +126 -0
  229. package/dist/config/defaultPortConfig.d.ts +6 -0
  230. package/dist/config/defaultPortConfig.js +201 -0
  231. package/dist/config/endpoints.d.ts +160 -0
  232. package/dist/config/endpoints.js +146 -0
  233. package/dist/config/runtimeConfig.d.ts +47 -0
  234. package/dist/config/runtimeConfig.js +80 -0
  235. package/dist/core/index.d.ts +75 -0
  236. package/dist/core/index.js +92 -0
  237. package/dist/display/index.d.ts +29 -0
  238. package/dist/display/index.js +36 -0
  239. package/dist/editor/index.d.ts +95 -0
  240. package/dist/editor/index.js +138 -0
  241. package/dist/form/code.d.ts +101 -0
  242. package/dist/form/code.js +168 -0
  243. package/dist/form/fieldRegistry.d.ts +169 -0
  244. package/dist/form/fieldRegistry.js +152 -0
  245. package/dist/form/full.d.ts +56 -0
  246. package/dist/form/full.js +80 -0
  247. package/dist/form/index.d.ts +77 -0
  248. package/dist/form/index.js +91 -0
  249. package/dist/form/markdown.d.ts +69 -0
  250. package/dist/form/markdown.js +103 -0
  251. package/dist/helpers/nodeLayoutHelper.d.ts +14 -0
  252. package/dist/helpers/nodeLayoutHelper.js +19 -0
  253. package/dist/helpers/proximityConnect.d.ts +94 -0
  254. package/dist/helpers/proximityConnect.js +314 -0
  255. package/dist/helpers/workflowEditorHelper.d.ts +183 -0
  256. package/dist/helpers/workflowEditorHelper.js +595 -0
  257. package/dist/index.d.ts +37 -0
  258. package/dist/index.js +64 -0
  259. package/dist/mocks/app-environment.d.ts +8 -0
  260. package/dist/mocks/app-environment.js +16 -0
  261. package/dist/mocks/app-forms.d.ts +2 -0
  262. package/dist/mocks/app-forms.js +22 -0
  263. package/dist/mocks/app-navigation.d.ts +5 -0
  264. package/dist/mocks/app-navigation.js +36 -0
  265. package/dist/mocks/app-stores.d.ts +14 -0
  266. package/dist/mocks/app-stores.js +26 -0
  267. package/dist/playground/index.d.ts +131 -0
  268. package/dist/playground/index.js +172 -0
  269. package/dist/playground/mount.d.ts +203 -0
  270. package/dist/playground/mount.js +235 -0
  271. package/dist/registry/BaseRegistry.d.ts +92 -0
  272. package/dist/registry/BaseRegistry.js +124 -0
  273. package/dist/registry/builtinFormats.d.ts +23 -0
  274. package/dist/registry/builtinFormats.js +70 -0
  275. package/dist/registry/builtinNodes.d.ts +77 -0
  276. package/dist/registry/builtinNodes.js +211 -0
  277. package/dist/registry/index.d.ts +8 -0
  278. package/dist/registry/index.js +12 -0
  279. package/dist/registry/nodeComponentRegistry.d.ts +276 -0
  280. package/dist/registry/nodeComponentRegistry.js +262 -0
  281. package/dist/registry/plugin.d.ts +215 -0
  282. package/dist/registry/plugin.js +249 -0
  283. package/dist/registry/workflowFormatRegistry.d.ts +122 -0
  284. package/dist/registry/workflowFormatRegistry.js +96 -0
  285. package/dist/schema/index.d.ts +23 -0
  286. package/dist/schema/index.js +23 -0
  287. package/dist/schemas/v1/workflow.schema.json +1078 -0
  288. package/dist/services/agentSpecExecutionService.d.ts +106 -0
  289. package/dist/services/agentSpecExecutionService.js +334 -0
  290. package/dist/services/api.d.ts +115 -0
  291. package/dist/services/api.js +214 -0
  292. package/dist/services/apiVariableService.d.ts +114 -0
  293. package/dist/services/apiVariableService.js +338 -0
  294. package/dist/services/autoSaveService.d.ts +112 -0
  295. package/dist/services/autoSaveService.js +227 -0
  296. package/dist/services/categoriesApi.d.ts +14 -0
  297. package/dist/services/categoriesApi.js +49 -0
  298. package/dist/services/draftStorage.d.ts +171 -0
  299. package/dist/services/draftStorage.js +299 -0
  300. package/dist/services/dynamicSchemaService.d.ts +108 -0
  301. package/dist/services/dynamicSchemaService.js +444 -0
  302. package/dist/services/globalSave.d.ts +69 -0
  303. package/dist/services/globalSave.js +248 -0
  304. package/dist/services/historyService.d.ts +208 -0
  305. package/dist/services/historyService.js +321 -0
  306. package/dist/services/interruptService.d.ts +133 -0
  307. package/dist/services/interruptService.js +280 -0
  308. package/dist/services/nodeExecutionService.d.ts +63 -0
  309. package/dist/services/nodeExecutionService.js +266 -0
  310. package/dist/services/playgroundService.d.ts +130 -0
  311. package/dist/services/playgroundService.js +321 -0
  312. package/dist/services/portConfigApi.d.ts +14 -0
  313. package/dist/services/portConfigApi.js +54 -0
  314. package/dist/services/settingsService.d.ts +92 -0
  315. package/dist/services/settingsService.js +196 -0
  316. package/dist/services/toastService.d.ts +156 -0
  317. package/dist/services/toastService.js +265 -0
  318. package/dist/services/variableService.d.ts +141 -0
  319. package/dist/services/variableService.js +463 -0
  320. package/dist/services/workflowStorage.d.ts +37 -0
  321. package/dist/services/workflowStorage.js +116 -0
  322. package/dist/settings/index.d.ts +25 -0
  323. package/dist/settings/index.js +33 -0
  324. package/dist/stores/categoriesStore.svelte.d.ts +32 -0
  325. package/dist/stores/categoriesStore.svelte.js +77 -0
  326. package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
  327. package/dist/stores/editorStateMachine.svelte.js +132 -0
  328. package/dist/stores/historyStore.svelte.d.ts +136 -0
  329. package/dist/stores/historyStore.svelte.js +207 -0
  330. package/dist/stores/interruptStore.svelte.d.ts +179 -0
  331. package/dist/stores/interruptStore.svelte.js +346 -0
  332. package/dist/stores/playgroundStore.svelte.d.ts +230 -0
  333. package/dist/stores/playgroundStore.svelte.js +515 -0
  334. package/dist/stores/portCoordinateStore.svelte.d.ts +66 -0
  335. package/dist/stores/portCoordinateStore.svelte.js +186 -0
  336. package/dist/stores/settingsStore.svelte.d.ts +158 -0
  337. package/dist/stores/settingsStore.svelte.js +544 -0
  338. package/dist/stores/workflowStore.svelte.d.ts +260 -0
  339. package/dist/stores/workflowStore.svelte.js +649 -0
  340. package/dist/stories/CanvasDecorator.svelte +49 -0
  341. package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
  342. package/dist/stories/NodeDecorator.svelte +73 -0
  343. package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
  344. package/dist/stories/utils.d.ts +93 -0
  345. package/dist/stories/utils.js +122 -0
  346. package/dist/styles/base.css +1300 -0
  347. package/dist/styles/toast.css +35 -0
  348. package/dist/styles/tokens.css +475 -0
  349. package/dist/svelte-app.d.ts +150 -0
  350. package/dist/svelte-app.js +295 -0
  351. package/dist/types/agentspec.d.ts +318 -0
  352. package/dist/types/agentspec.js +48 -0
  353. package/dist/types/auth.d.ts +263 -0
  354. package/dist/types/auth.js +229 -0
  355. package/dist/types/config.d.ts +151 -0
  356. package/dist/types/config.js +7 -0
  357. package/dist/types/events.d.ts +190 -0
  358. package/dist/types/events.js +30 -0
  359. package/dist/types/index.d.ts +1234 -0
  360. package/dist/types/index.js +27 -0
  361. package/dist/types/interrupt.d.ts +390 -0
  362. package/dist/types/interrupt.js +145 -0
  363. package/dist/types/interruptState.d.ts +211 -0
  364. package/dist/types/interruptState.js +308 -0
  365. package/dist/types/playground.d.ts +351 -0
  366. package/dist/types/playground.js +95 -0
  367. package/dist/types/settings.d.ts +189 -0
  368. package/dist/types/settings.js +97 -0
  369. package/dist/types/uischema.d.ts +144 -0
  370. package/dist/types/uischema.js +51 -0
  371. package/dist/utils/colors.d.ts +288 -0
  372. package/dist/utils/colors.js +548 -0
  373. package/dist/utils/config.d.ts +37 -0
  374. package/dist/utils/config.js +226 -0
  375. package/dist/utils/connections.d.ts +125 -0
  376. package/dist/utils/connections.js +414 -0
  377. package/dist/utils/errors.d.ts +28 -0
  378. package/dist/utils/errors.js +44 -0
  379. package/dist/utils/fetchWithAuth.d.ts +25 -0
  380. package/dist/utils/fetchWithAuth.js +34 -0
  381. package/dist/utils/handleIds.d.ts +35 -0
  382. package/dist/utils/handleIds.js +58 -0
  383. package/dist/utils/handlePositioning.d.ts +31 -0
  384. package/dist/utils/handlePositioning.js +35 -0
  385. package/dist/utils/icons.d.ts +106 -0
  386. package/dist/utils/icons.js +157 -0
  387. package/dist/utils/logger.d.ts +47 -0
  388. package/dist/utils/logger.js +72 -0
  389. package/dist/utils/nodeStatus.d.ts +53 -0
  390. package/dist/utils/nodeStatus.js +183 -0
  391. package/dist/utils/nodeTypes.d.ts +117 -0
  392. package/dist/utils/nodeTypes.js +244 -0
  393. package/dist/utils/nodeWrapper.d.ts +39 -0
  394. package/dist/utils/nodeWrapper.js +62 -0
  395. package/dist/utils/performanceUtils.d.ts +30 -0
  396. package/dist/utils/performanceUtils.js +108 -0
  397. package/dist/utils/sanitize.d.ts +19 -0
  398. package/dist/utils/sanitize.js +31 -0
  399. package/dist/utils/uischema.d.ts +52 -0
  400. package/dist/utils/uischema.js +88 -0
  401. package/dist/utils/validation.d.ts +29 -0
  402. package/dist/utils/validation.js +39 -0
  403. package/package.json +292 -0
@@ -0,0 +1,1035 @@
1
+ <!--
2
+ Workflow Editor Component
3
+ Main workflow editor with sidebar and flow canvas
4
+ Styled with BEM syntax
5
+ -->
6
+
7
+ <script lang="ts">
8
+ import {
9
+ SvelteFlow,
10
+ ConnectionLineType,
11
+ Controls,
12
+ Background,
13
+ BackgroundVariant,
14
+ MiniMap,
15
+ SvelteFlowProvider,
16
+ type ColorMode
17
+ } from '@xyflow/svelte';
18
+ import '@xyflow/svelte/dist/style.css';
19
+ import {
20
+ getResolvedTheme,
21
+ getEditorSettings,
22
+ getBehaviorSettings
23
+ } from '../stores/settingsStore.svelte.js';
24
+ import type {
25
+ WorkflowNode as WorkflowNodeType,
26
+ NodeMetadata,
27
+ Workflow,
28
+ WorkflowEdge
29
+ } from '../types/index.js';
30
+ import CanvasBanner from './CanvasBanner.svelte';
31
+ import FlowDropZone from './FlowDropZone.svelte';
32
+ import EdgeRefresher from './EdgeRefresher.svelte';
33
+ import { tick, untrack } from 'svelte';
34
+ import type { EndpointConfig } from '../config/endpoints.js';
35
+ import ConnectionLine from './ConnectionLine.svelte';
36
+ import { getWorkflowStore, workflowActions } from '../stores/workflowStore.svelte.js';
37
+ import { historyActions, setOnRestoreCallback } from '../stores/historyStore.svelte.js';
38
+ import UniversalNode from './UniversalNode.svelte';
39
+ import {
40
+ EdgeStylingHelper,
41
+ NodeOperationsHelper,
42
+ WorkflowOperationsHelper,
43
+ ConfigurationHelper
44
+ } from '../helpers/workflowEditorHelper.js';
45
+ import type { NodeExecutionInfo } from '../types/index.js';
46
+ import { Toaster } from 'svelte-5-french-toast';
47
+ import {
48
+ flowdropToastOptions,
49
+ FLOWDROP_TOASTER_CLASS,
50
+ apiToasts
51
+ } from '../services/toastService.js';
52
+ import {
53
+ ProximityConnectHelper,
54
+ type ProximityEdgeCandidate
55
+ } from '../helpers/proximityConnect.js';
56
+ import PortCoordinateTracker from './PortCoordinateTracker.svelte';
57
+ import { getPortCoordinateSnapshot } from '../stores/portCoordinateStore.svelte.js';
58
+ import { logger } from '../utils/logger.js';
59
+ import { validateWorkflowData } from '../utils/validation.js';
60
+ import { createEditorStateMachine } from '../stores/editorStateMachine.svelte.js';
61
+
62
+ interface Props {
63
+ nodes?: NodeMetadata[];
64
+ endpointConfig?: EndpointConfig;
65
+ height?: string | number;
66
+ width?: string | number;
67
+ isConfigSidebarOpen?: boolean;
68
+ selectedNodeForConfig?: WorkflowNodeType | null;
69
+ openConfigSidebar?: (node: WorkflowNodeType) => void;
70
+ closeConfigSidebar?: () => void;
71
+ // New configuration options for pipeline status mode
72
+ lockWorkflow?: boolean;
73
+ readOnly?: boolean;
74
+ nodeStatuses?: Record<string, 'pending' | 'running' | 'completed' | 'error'>;
75
+ // Pipeline ID for fetching node execution info from jobs
76
+ pipelineId?: string;
77
+ }
78
+
79
+ let props: Props = $props();
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // Editor State Machine
83
+ // Centralizes reactive guards — replaces scattered boolean flags
84
+ // (isDraggingNode, lastEditorStoreValue identity checks, etc.)
85
+ // ---------------------------------------------------------------------------
86
+ const machine = createEditorStateMachine();
87
+
88
+ // Dev-mode transition logging
89
+ if (import.meta.env?.DEV) {
90
+ machine.onTransition((from, event, to) => {
91
+ logger.debug(`[EditorFSM] ${from} --${event}--> ${to}`);
92
+ });
93
+ }
94
+
95
+ // Proximity connect state
96
+ let currentProximityCandidates = $state<ProximityEdgeCandidate[]>([]);
97
+
98
+ // Port coordinate tracker state
99
+ let portCoordNodeToUpdate = $state<WorkflowNodeType | null>(null);
100
+ let portCoordRebuildTrigger = $state(0);
101
+
102
+ // ---------------------------------------------------------------------------
103
+ // Flow state — bound to SvelteFlow via bind:nodes / bind:edges
104
+ // These are $state.raw to prevent deep proxy leaking (SvelteFlow mutates
105
+ // node internals during drag which would cause infinite loops with $state).
106
+ // ---------------------------------------------------------------------------
107
+ let flowNodes = $state.raw<WorkflowNodeType[]>([]);
108
+ let flowEdges = $state.raw<WorkflowEdge[]>([]);
109
+
110
+ // Execution info loading state
111
+ let loadExecutionInfoTimeout: number | null = null;
112
+ let executionInfoAbortController: AbortController | null = null;
113
+
114
+ /**
115
+ * Key for SvelteFlow component — changes when workflow ID changes.
116
+ * Forces SvelteFlow to remount with fresh state, allowing fitView to work correctly.
117
+ */
118
+ let svelteFlowKey = $derived(getWorkflowStore()?.id ?? 'default');
119
+
120
+ /**
121
+ * Derive snap grid configuration from editor settings
122
+ */
123
+ let snapGrid = $derived(
124
+ getEditorSettings().snapToGrid
125
+ ? ([getEditorSettings().gridSize, getEditorSettings().gridSize] as [number, number])
126
+ : undefined
127
+ );
128
+
129
+ /**
130
+ * Derive initial viewport configuration from editor settings
131
+ */
132
+ let initialViewport = $derived({
133
+ zoom: getEditorSettings().defaultZoom,
134
+ x: 0,
135
+ y: 0
136
+ });
137
+
138
+ // ---------------------------------------------------------------------------
139
+ // Helper: derive flowNodes/flowEdges from a Workflow object
140
+ // ---------------------------------------------------------------------------
141
+ function buildFlowNodesFromStore(workflow: Workflow): {
142
+ nodes: WorkflowNodeType[];
143
+ edges: WorkflowEdge[];
144
+ } {
145
+ const nodesWithCallbacks = workflow.nodes.map((node) => ({
146
+ ...node,
147
+ data: {
148
+ ...node.data,
149
+ onConfigOpen: props.openConfigSidebar
150
+ }
151
+ }));
152
+ const styledEdges = EdgeStylingHelper.updateEdgeStyles(workflow.edges, nodesWithCallbacks);
153
+ return { nodes: nodesWithCallbacks, edges: styledEdges };
154
+ }
155
+
156
+ // ---------------------------------------------------------------------------
157
+ // Helper: sync current flowNodes/flowEdges back to the global store
158
+ // ---------------------------------------------------------------------------
159
+ function syncFlowToStore(): void {
160
+ const storeValue = untrack(() => getWorkflowStore());
161
+ if (!storeValue) return;
162
+ const updatedWorkflow = WorkflowOperationsHelper.updateWorkflow(
163
+ storeValue,
164
+ flowNodes,
165
+ flowEdges
166
+ );
167
+ workflowActions.updateWorkflow(updatedWorkflow);
168
+ }
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // Single sync effect: workflowStore → flowNodes / flowEdges
172
+ // Replaces the old Effect A (store→currentWorkflow) + Effect B (currentWorkflow→flow).
173
+ // Suppressed during operations via state machine; handlers update flowNodes directly.
174
+ // ---------------------------------------------------------------------------
175
+ let previousSyncedWorkflowId: string | null = null;
176
+
177
+ $effect(() => {
178
+ const storeValue = getWorkflowStore();
179
+
180
+ // Suppressed during operations — handlers write to flowNodes directly
181
+ if (untrack(() => machine.permissions.suppressEffect)) return;
182
+
183
+ if (!storeValue) {
184
+ if (flowNodes.length > 0 || flowEdges.length > 0) {
185
+ flowNodes = [];
186
+ flowEdges = [];
187
+ previousSyncedWorkflowId = null;
188
+ untrack(() => machine.send('WORKFLOW_CLEARED'));
189
+ }
190
+ return;
191
+ }
192
+
193
+ const isNewWorkflow = storeValue.id !== previousSyncedWorkflowId;
194
+
195
+ if (isNewWorkflow) {
196
+ untrack(() =>
197
+ machine.send(previousSyncedWorkflowId ? 'WORKFLOW_SWITCHED' : 'WORKFLOW_LOADED')
198
+ );
199
+ }
200
+
201
+ // Derive flowNodes/flowEdges from store
202
+ const derived = buildFlowNodesFromStore(storeValue);
203
+ flowNodes = derived.nodes;
204
+ flowEdges = derived.edges;
205
+ previousSyncedWorkflowId = storeValue.id;
206
+
207
+ // Trigger port coordinate rebuild after workflow load
208
+ if (getEditorSettings().proximityConnect) {
209
+ portCoordRebuildTrigger = Date.now();
210
+ }
211
+
212
+ if (isNewWorkflow) {
213
+ untrack(() => machine.send('LOAD_COMPLETE'));
214
+ }
215
+ });
216
+
217
+ // ---------------------------------------------------------------------------
218
+ // Execution info effect (separate — async, depends on workflow + pipeline ID)
219
+ // ---------------------------------------------------------------------------
220
+ let previousExecWorkflowId: string | null = null;
221
+ let previousExecPipelineId: string | undefined = undefined;
222
+
223
+ $effect(() => {
224
+ const storeValue = getWorkflowStore();
225
+ const pipelineId = props.pipelineId;
226
+
227
+ if (!storeValue || !pipelineId) return;
228
+
229
+ const workflowChanged = storeValue.id !== previousExecWorkflowId;
230
+ const pipelineChanged = pipelineId !== previousExecPipelineId;
231
+
232
+ if (!workflowChanged && !pipelineChanged) return;
233
+
234
+ previousExecWorkflowId = storeValue.id;
235
+ previousExecPipelineId = pipelineId;
236
+
237
+ // Cancel any pending timeout / in-flight request
238
+ if (loadExecutionInfoTimeout) {
239
+ clearTimeout(loadExecutionInfoTimeout);
240
+ loadExecutionInfoTimeout = null;
241
+ }
242
+ if (executionInfoAbortController) {
243
+ executionInfoAbortController.abort();
244
+ executionInfoAbortController = null;
245
+ }
246
+
247
+ // Schedule loading with requestIdleCallback (falls back to setTimeout)
248
+ if (typeof requestIdleCallback !== 'undefined') {
249
+ loadExecutionInfoTimeout = requestIdleCallback(
250
+ () => {
251
+ loadNodeExecutionInfo();
252
+ },
253
+ { timeout: 500 }
254
+ ) as unknown as number;
255
+ } else {
256
+ loadExecutionInfoTimeout = setTimeout(() => {
257
+ loadNodeExecutionInfo();
258
+ }, 300) as unknown as number;
259
+ }
260
+ });
261
+
262
+ // ---------------------------------------------------------------------------
263
+ // History restore callback
264
+ // ---------------------------------------------------------------------------
265
+ $effect(() => {
266
+ setOnRestoreCallback((restoredWorkflow: Workflow) => {
267
+ machine.send('START_RESTORE');
268
+ // Update the store (effect is suppressed during 'restoring')
269
+ workflowActions.restoreFromHistory(restoredWorkflow);
270
+ // Derive flowNodes/flowEdges directly for immediate visual update
271
+ const derived = buildFlowNodesFromStore(restoredWorkflow);
272
+ flowNodes = derived.nodes;
273
+ flowEdges = derived.edges;
274
+ machine.send('RESTORE_COMPLETE');
275
+ // After RESTORE_COMPLETE → idle, the sync effect runs but produces
276
+ // the same data (no-op re-derive).
277
+ });
278
+
279
+ return () => {
280
+ setOnRestoreCallback(null);
281
+ };
282
+ });
283
+
284
+ /**
285
+ * Load node execution information for all nodes in the workflow
286
+ */
287
+ async function loadNodeExecutionInfo(): Promise<void> {
288
+ const workflow = untrack(() => getWorkflowStore());
289
+ if (!workflow?.nodes || !props.pipelineId) return;
290
+
291
+ try {
292
+ executionInfoAbortController = new AbortController();
293
+
294
+ const executionInfo = await NodeOperationsHelper.loadNodeExecutionInfo(
295
+ workflow,
296
+ props.pipelineId
297
+ );
298
+
299
+ if (executionInfoAbortController?.signal.aborted) return;
300
+
301
+ const defaultExecutionInfo: NodeExecutionInfo = {
302
+ status: 'idle' as const,
303
+ executionCount: 0,
304
+ isExecuting: false
305
+ };
306
+
307
+ // Update flowNodes with execution info (visual-only, no store sync needed)
308
+ flowNodes = flowNodes.map((node) => ({
309
+ ...node,
310
+ data: {
311
+ ...node.data,
312
+ executionInfo: executionInfo[node.id] || defaultExecutionInfo
313
+ }
314
+ }));
315
+
316
+ executionInfoAbortController = null;
317
+ } catch (error) {
318
+ if (error instanceof Error && error.name !== 'AbortError') {
319
+ logger.error('Failed to load node execution info:', error);
320
+ }
321
+ }
322
+ }
323
+
324
+ // The global store should be initialized by the parent App component
325
+
326
+ // Sidebar is now always visible - removed toggle functionality
327
+
328
+ // Node types for Svelte Flow - using UniversalNode for all node types
329
+ // All nodes use 'universalNode' type, and UniversalNode handles internal switching
330
+ const nodeTypes = {
331
+ universalNode: UniversalNode
332
+ };
333
+
334
+ // Handle arrows in our custom connection handler
335
+ const defaultEdgeOptions = {};
336
+
337
+ /**
338
+ * Handle node drag start
339
+ *
340
+ * Transitions the state machine to 'dragging', which suppresses
341
+ * the sync effect to prevent reactive loops during high-frequency
342
+ * position updates. SvelteFlow mutates flowNodes directly via bind:nodes.
343
+ */
344
+ function handleNodeDragStart(): void {
345
+ machine.send('START_DRAG');
346
+ // Clear any leftover proximity previews
347
+ currentProximityCandidates = [];
348
+ }
349
+
350
+ /**
351
+ * Handle node drag - compute proximity connect preview edges
352
+ * Called continuously during drag if proximity connect is enabled.
353
+ * Uses port-to-port distance via the port coordinate store.
354
+ */
355
+ function handleNodeDrag({
356
+ targetNode
357
+ }: {
358
+ targetNode: WorkflowNodeType | null;
359
+ nodes: WorkflowNodeType[];
360
+ event: MouseEvent | TouchEvent;
361
+ }): void {
362
+ if (
363
+ !getEditorSettings().proximityConnect ||
364
+ !targetNode ||
365
+ props.readOnly ||
366
+ props.lockWorkflow
367
+ ) {
368
+ if (currentProximityCandidates.length > 0) {
369
+ flowEdges = ProximityConnectHelper.removePreviewEdges(flowEdges);
370
+ currentProximityCandidates = [];
371
+ }
372
+ portCoordNodeToUpdate = null;
373
+ return;
374
+ }
375
+
376
+ // Update the dragged node's port coordinates (position changed during drag)
377
+ portCoordNodeToUpdate = targetNode;
378
+
379
+ // Remove previous preview edges
380
+ const baseEdges = ProximityConnectHelper.removePreviewEdges(flowEdges);
381
+
382
+ // Find the best compatible edge using port-to-port distance
383
+ const portCoordinates = getPortCoordinateSnapshot();
384
+ const candidates =
385
+ portCoordinates.size > 0
386
+ ? ProximityConnectHelper.findCompatibleEdgesByPortCoordinates(
387
+ targetNode.id,
388
+ portCoordinates,
389
+ baseEdges,
390
+ getEditorSettings().proximityConnectDistance
391
+ )
392
+ : ProximityConnectHelper.findCompatibleEdges(
393
+ targetNode,
394
+ flowNodes,
395
+ baseEdges,
396
+ getEditorSettings().proximityConnectDistance
397
+ );
398
+
399
+ // Create preview edges
400
+ const previews = ProximityConnectHelper.createPreviewEdges(candidates);
401
+
402
+ // Update state
403
+ currentProximityCandidates = candidates;
404
+ flowEdges = [...baseEdges, ...previews];
405
+ }
406
+
407
+ /**
408
+ * Handle node drag stop
409
+ *
410
+ * Still in 'dragging' state — sync effect suppressed.
411
+ * Syncs final positions to store, pushes history, then transitions to idle.
412
+ */
413
+ function handleNodeDragStop(): void {
414
+ portCoordNodeToUpdate = null;
415
+
416
+ // Finalize proximity connect if there are candidates
417
+ if (getEditorSettings().proximityConnect && currentProximityCandidates.length > 0) {
418
+ const baseEdges = ProximityConnectHelper.removePreviewEdges(flowEdges);
419
+ const permanentEdges = ProximityConnectHelper.createPermanentEdges(
420
+ currentProximityCandidates
421
+ );
422
+
423
+ for (const edge of permanentEdges) {
424
+ const sourceNode = flowNodes.find((n) => n.id === edge.source);
425
+ const targetNode = flowNodes.find((n) => n.id === edge.target);
426
+ if (sourceNode && targetNode) {
427
+ EdgeStylingHelper.applyConnectionStyling(edge, sourceNode, targetNode);
428
+ }
429
+ }
430
+
431
+ flowEdges = [...baseEdges, ...permanentEdges];
432
+ currentProximityCandidates = [];
433
+ }
434
+
435
+ // Sync flowNodes/flowEdges → store
436
+ syncFlowToStore();
437
+
438
+ // Push history AFTER the drag completed
439
+ const storeValue = getWorkflowStore();
440
+ if (storeValue) {
441
+ workflowActions.pushHistory('Move node', storeValue);
442
+ }
443
+
444
+ // Transition to idle — sync effect is now unblocked
445
+ machine.send('STOP_DRAG');
446
+ }
447
+
448
+ /**
449
+ * Handle new connections between nodes
450
+ */
451
+ async function handleConnect(connection: {
452
+ source: string;
453
+ target: string;
454
+ sourceHandle?: string;
455
+ targetHandle?: string;
456
+ }): Promise<void> {
457
+ machine.send('START_CONNECT');
458
+
459
+ // SvelteFlow auto-creates the edge via bind:edges — wait for DOM update
460
+ await tick();
461
+
462
+ // Apply styling to all edges (including the new one)
463
+ flowEdges = EdgeStylingHelper.updateEdgeStyles(flowEdges, flowNodes);
464
+
465
+ // Sync to store
466
+ syncFlowToStore();
467
+
468
+ const storeValue = getWorkflowStore();
469
+ if (storeValue) {
470
+ workflowActions.pushHistory('Add connection', storeValue);
471
+ }
472
+
473
+ machine.send('CONNECTION_MADE');
474
+ }
475
+
476
+ /**
477
+ * Handle before delete - show confirmation dialog if enabled in settings
478
+ *
479
+ * This callback is called before nodes/edges are deleted.
480
+ * Return true to proceed with deletion, false to cancel.
481
+ *
482
+ * @param params - Object containing nodes and edges to be deleted
483
+ * @returns Promise resolving to true if deletion should proceed, false to cancel
484
+ */
485
+ async function handleBeforeDelete(params: {
486
+ nodes: WorkflowNodeType[];
487
+ edges: WorkflowEdge[];
488
+ }): Promise<boolean> {
489
+ // If confirmDelete setting is enabled, show confirmation dialog
490
+ if (getBehaviorSettings().confirmDelete) {
491
+ const nodeCount = params.nodes.length;
492
+ const edgeCount = params.edges.length;
493
+
494
+ // Build a descriptive message
495
+ let message = 'Are you sure you want to delete ';
496
+ const parts: string[] = [];
497
+
498
+ if (nodeCount > 0) {
499
+ parts.push(`${nodeCount} node${nodeCount > 1 ? 's' : ''}`);
500
+ }
501
+ if (edgeCount > 0) {
502
+ parts.push(`${edgeCount} connection${edgeCount > 1 ? 's' : ''}`);
503
+ }
504
+
505
+ message += parts.join(' and ') + '?';
506
+
507
+ // Show native confirmation dialog
508
+ const confirmed = window.confirm(message);
509
+ if (!confirmed) {
510
+ return false;
511
+ }
512
+ }
513
+
514
+ // Don't push to history here - we'll push AFTER deletion in handleNodesDelete
515
+ // This ensures undo will restore the state before deletion
516
+ return true;
517
+ }
518
+
519
+ /**
520
+ * Handle node deletion - automatically remove connected edges and push to history
521
+ */
522
+ function handleNodesDelete(params: { nodes: WorkflowNodeType[]; edges: WorkflowEdge[] }): void {
523
+ machine.send('START_DELETE');
524
+
525
+ const deletedNodeIds = new Set(params.nodes.map((node) => node.id));
526
+
527
+ // Filter out edges connected to deleted nodes
528
+ flowEdges = flowEdges.filter(
529
+ (edge) => !deletedNodeIds.has(edge.source) && !deletedNodeIds.has(edge.target)
530
+ );
531
+
532
+ // Sync to store
533
+ syncFlowToStore();
534
+
535
+ // Push to history AFTER the deletion so undo restores the previous state
536
+ const nodeCount = params.nodes.length;
537
+ const edgeCount = params.edges.length;
538
+ let description = 'Delete';
539
+ if (nodeCount > 0 && edgeCount > 0) {
540
+ description = `Delete ${nodeCount} node${nodeCount > 1 ? 's' : ''} and ${edgeCount} connection${edgeCount > 1 ? 's' : ''}`;
541
+ } else if (nodeCount > 0) {
542
+ description = `Delete ${nodeCount} node${nodeCount > 1 ? 's' : ''}`;
543
+ } else if (edgeCount > 0) {
544
+ description = `Delete ${edgeCount} connection${edgeCount > 1 ? 's' : ''}`;
545
+ }
546
+ const storeValue = getWorkflowStore();
547
+ if (storeValue) {
548
+ workflowActions.pushHistory(description, storeValue);
549
+ }
550
+
551
+ machine.send('DELETE_COMPLETE');
552
+ }
553
+
554
+ // Edge styling will be handled when edges are first created or manually updated
555
+
556
+ // Configure endpoints when props change
557
+ $effect(() => {
558
+ if (props.endpointConfig) {
559
+ ConfigurationHelper.configureEndpoints(props.endpointConfig);
560
+ }
561
+ });
562
+
563
+ /**
564
+ * Check if workflow has cycles
565
+ */
566
+ function checkWorkflowCycles(): boolean {
567
+ return WorkflowOperationsHelper.checkWorkflowCycles(flowNodes, flowEdges);
568
+ }
569
+
570
+ /**
571
+ * Handle drop event and add new node to canvas
572
+ */
573
+ async function handleNodeDrop(
574
+ nodeTypeData: string,
575
+ position: { x: number; y: number }
576
+ ): Promise<void> {
577
+ machine.send('START_DROP');
578
+
579
+ const newNode = NodeOperationsHelper.createNodeFromDrop(nodeTypeData, position, flowNodes);
580
+
581
+ if (newNode) {
582
+ // Add onConfigOpen callback and append to flowNodes for immediate visual feedback
583
+ const nodeWithCallback = {
584
+ ...newNode,
585
+ data: { ...newNode.data, onConfigOpen: props.openConfigSidebar }
586
+ };
587
+ flowNodes = [...flowNodes, nodeWithCallback];
588
+
589
+ // Sync to store
590
+ syncFlowToStore();
591
+
592
+ await tick();
593
+
594
+ const storeValue = getWorkflowStore();
595
+ if (storeValue) {
596
+ workflowActions.pushHistory('Add node', storeValue);
597
+ }
598
+ } else {
599
+ logger.warn('Failed to create node from drop data');
600
+ }
601
+
602
+ machine.send('DROP_COMPLETE');
603
+ }
604
+
605
+ /**
606
+ * Handle a workflow JSON file dropped directly onto the canvas.
607
+ *
608
+ * Validates the JSON against the minimum required Workflow fields and, if valid,
609
+ * loads it into the workflow store. Shows a toast on validation failure or read error.
610
+ */
611
+ function handleWorkflowFileDrop(file: File): void {
612
+ const reader = new FileReader();
613
+ reader.onload = (event) => {
614
+ try {
615
+ const text = event.target?.result;
616
+ if (typeof text !== 'string') {
617
+ throw new Error('Could not read file contents.');
618
+ }
619
+ const data = JSON.parse(text);
620
+ const validation = validateWorkflowData(data);
621
+ if (!validation.valid) {
622
+ apiToasts.error('Import workflow', validation.error ?? 'Invalid workflow JSON');
623
+ logger.warn('Workflow file drop validation failed:', validation.error);
624
+ return;
625
+ }
626
+ workflowActions.initialize(data as Workflow);
627
+ } catch (error) {
628
+ const errorObj = error instanceof Error ? error : new Error('Unknown error occurred');
629
+ logger.error('Workflow file drop import failed:', errorObj);
630
+ apiToasts.error('Import workflow', errorObj.message);
631
+ }
632
+ };
633
+ reader.onerror = () => {
634
+ const message = 'Failed to read the dropped file.';
635
+ logger.error(message);
636
+ apiToasts.error('Import workflow', message);
637
+ };
638
+ reader.readAsText(file);
639
+ }
640
+
641
+ /**
642
+ * Node ID that needs edge refresh - used to trigger EdgeRefresher component
643
+ */
644
+ let nodeIdToRefresh = $state<string | null>(null);
645
+
646
+ /**
647
+ * Update a node's data in the local editor state.
648
+ * Called by App.svelte AFTER it has already updated the global store via
649
+ * workflowActions.updateNode(). We only need to update flowNodes for
650
+ * immediate visual feedback — no store sync needed.
651
+ *
652
+ * @param nodeId - The ID of the node to update
653
+ * @param dataUpdates - Partial data updates to merge into the node's data
654
+ */
655
+ export function updateNodeData(
656
+ nodeId: string,
657
+ dataUpdates: Partial<WorkflowNodeType['data']>
658
+ ): void {
659
+ machine.send('START_NODE_UPDATE');
660
+
661
+ flowNodes = flowNodes.map((node) => {
662
+ if (node.id === nodeId) {
663
+ return {
664
+ ...node,
665
+ data: {
666
+ ...node.data,
667
+ ...dataUpdates
668
+ }
669
+ };
670
+ }
671
+ return node;
672
+ });
673
+
674
+ machine.send('UPDATE_COMPLETE');
675
+ }
676
+
677
+ /**
678
+ * Force edge position recalculation after node config changes
679
+ * This should be called after saving gateway/switch node configs where branches are reordered
680
+ * Svelte Flow doesn't automatically recalculate edge paths when handle positions change
681
+ * @param nodeId - The ID of the node whose handles have changed position
682
+ */
683
+ export async function refreshEdgePositions(nodeId: string): Promise<void> {
684
+ // Wait for DOM to update with new handle positions
685
+ await tick();
686
+
687
+ // Trigger the EdgeRefresher component to call updateNodeInternals
688
+ nodeIdToRefresh = nodeId;
689
+ }
690
+
691
+ /**
692
+ * Callback when edge refresh is complete
693
+ */
694
+ function handleEdgeRefreshComplete(): void {
695
+ nodeIdToRefresh = null;
696
+ }
697
+
698
+ /**
699
+ * Handle keyboard shortcuts for undo/redo
700
+ *
701
+ * - Ctrl+Z (or Cmd+Z on Mac): Undo
702
+ * - Ctrl+Shift+Z (or Cmd+Shift+Z): Redo
703
+ * - Ctrl+Y (or Cmd+Y): Redo (Windows convention)
704
+ */
705
+ function handleKeydown(event: KeyboardEvent): void {
706
+ // Check for Ctrl (Windows/Linux) or Cmd (Mac)
707
+ const isModifierPressed = event.ctrlKey || event.metaKey;
708
+
709
+ if (!isModifierPressed) {
710
+ return;
711
+ }
712
+
713
+ // Don't handle shortcuts if user is typing in an input, textarea, or contenteditable
714
+ const target = event.target as HTMLElement;
715
+ const isInputElement =
716
+ target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
717
+
718
+ if (isInputElement) {
719
+ return;
720
+ }
721
+
722
+ // Undo: Ctrl+Z (without Shift)
723
+ if (event.key === 'z' && !event.shiftKey) {
724
+ event.preventDefault();
725
+ historyActions.undo();
726
+ return;
727
+ }
728
+
729
+ // Redo: Ctrl+Shift+Z or Ctrl+Y
730
+ if ((event.key === 'z' && event.shiftKey) || event.key === 'y') {
731
+ event.preventDefault();
732
+ historyActions.redo();
733
+ return;
734
+ }
735
+ }
736
+ </script>
737
+
738
+ <svelte:window onkeydown={handleKeydown} />
739
+
740
+ <SvelteFlowProvider>
741
+ <!-- EdgeRefresher component - handles updateNodeInternals calls -->
742
+ <EdgeRefresher {nodeIdToRefresh} onRefreshComplete={handleEdgeRefreshComplete} />
743
+
744
+ <!-- Port Coordinate Tracker - maintains port positions for proximity connect -->
745
+ <PortCoordinateTracker
746
+ nodeToUpdate={portCoordNodeToUpdate}
747
+ rebuildTrigger={portCoordRebuildTrigger}
748
+ nodes={flowNodes}
749
+ />
750
+
751
+ <div class="flowdrop-workflow-editor">
752
+ <!-- Main Editor Area -->
753
+ <div class="flowdrop-workflow-editor__main">
754
+ <!-- Flow Canvas -->
755
+ <div class="flowdrop-canvas">
756
+ <FlowDropZone ondrop={handleNodeDrop} onfiledrop={handleWorkflowFileDrop}>
757
+ {#key svelteFlowKey}
758
+ <SvelteFlow
759
+ bind:nodes={flowNodes}
760
+ bind:edges={flowEdges}
761
+ {nodeTypes}
762
+ {defaultEdgeOptions}
763
+ onconnect={(connection) =>
764
+ void handleConnect({
765
+ source: connection.source,
766
+ target: connection.target,
767
+ sourceHandle: connection.sourceHandle ?? undefined,
768
+ targetHandle: connection.targetHandle ?? undefined
769
+ })}
770
+ onbeforedelete={handleBeforeDelete}
771
+ ondelete={handleNodesDelete}
772
+ onnodedragstart={handleNodeDragStart}
773
+ onnodedrag={handleNodeDrag}
774
+ onnodedragstop={handleNodeDragStop}
775
+ minZoom={0.2}
776
+ maxZoom={3}
777
+ clickConnect={true}
778
+ elevateEdgesOnSelect={true}
779
+ connectionLineType={ConnectionLineType.Bezier}
780
+ connectionLineComponent={ConnectionLine}
781
+ {snapGrid}
782
+ {initialViewport}
783
+ colorMode={getResolvedTheme() as ColorMode}
784
+ fitView={getEditorSettings().fitViewOnLoad}
785
+ >
786
+ <Controls />
787
+ <!-- Always render Background for consistent bg color in dark/light mode -->
788
+ <Background
789
+ gap={getEditorSettings().gridSize}
790
+ bgColor="var(--fd-background)"
791
+ variant={BackgroundVariant.Dots}
792
+ patternColor={getEditorSettings().showGrid ? undefined : 'transparent'}
793
+ />
794
+ {#if getEditorSettings().showMinimap}
795
+ <MiniMap />
796
+ {/if}
797
+ </SvelteFlow>
798
+ {/key}
799
+ <!-- Drop Zone Indicator -->
800
+ {#if flowNodes.length === 0}
801
+ <CanvasBanner
802
+ title="Drag components here to start building"
803
+ description="Use the sidebar to add components to your workflow"
804
+ iconName="mdi:graph"
805
+ />
806
+ {/if}
807
+ </FlowDropZone>
808
+ </div>
809
+
810
+ <!-- Status Bar: aria-live announces dynamic changes (node/edge counts, cycle warnings) -->
811
+ <div class="flowdrop-status-bar" aria-live="polite" aria-atomic="true">
812
+ <div class="flowdrop-status-bar__content">
813
+ <div class="flowdrop-flex flowdrop-gap--4">
814
+ <span class="flowdrop-text--xs flowdrop-text--gray">{flowNodes.length} nodes</span>
815
+ <span class="flowdrop-text--xs flowdrop-text--gray">•</span>
816
+ <span class="flowdrop-text--xs flowdrop-text--gray">{flowEdges.length} connections</span
817
+ >
818
+
819
+ {#if checkWorkflowCycles()}
820
+ <span class="flowdrop-text--xs flowdrop-text--gray">•</span>
821
+ <span class="flowdrop-text--xs flowdrop-font--medium flowdrop-text--error"
822
+ >⚠️ Cycles detected</span
823
+ >
824
+ {/if}
825
+ </div>
826
+ </div>
827
+ </div>
828
+ </div>
829
+ </div>
830
+ </SvelteFlowProvider>
831
+
832
+ <!-- Toast notifications container -->
833
+ <!-- aria-live="polite" ensures screen readers announce toast messages without interrupting -->
834
+ <div aria-live="polite" aria-atomic="true">
835
+ <Toaster
836
+ position="bottom-center"
837
+ containerClassName={FLOWDROP_TOASTER_CLASS}
838
+ toastOptions={flowdropToastOptions}
839
+ />
840
+ </div>
841
+
842
+ <style>
843
+ .flowdrop-workflow-editor {
844
+ display: flex;
845
+ flex-direction: row; /* Side by side layout */
846
+ height: 100%;
847
+ position: relative;
848
+ }
849
+
850
+ .flowdrop-workflow-editor__main {
851
+ flex: 1;
852
+ display: flex;
853
+ flex-direction: column;
854
+ min-height: 0;
855
+ transition: margin-left 0.3s ease-in-out;
856
+ }
857
+
858
+ .flowdrop-text--error {
859
+ color: var(--fd-error);
860
+ }
861
+
862
+ .flowdrop-canvas {
863
+ flex: 1;
864
+ min-height: 0;
865
+ position: relative;
866
+ background: transparent;
867
+ }
868
+
869
+ .flowdrop-status-bar {
870
+ background-color: var(--fd-backdrop);
871
+ backdrop-filter: var(--fd-backdrop-blur);
872
+ border-top: 1px solid var(--fd-border);
873
+ padding: 0.75rem;
874
+ height: 40px;
875
+ min-height: 40px;
876
+ max-height: 40px;
877
+ display: flex;
878
+ align-items: center;
879
+ flex-shrink: 0;
880
+ }
881
+
882
+ .flowdrop-status-bar__content {
883
+ display: flex;
884
+ align-items: center;
885
+ justify-content: space-between;
886
+ }
887
+
888
+ :global(.flowdrop-workflow-editor .svelte-flow__node:hover) {
889
+ transform: translateY(-2px);
890
+ }
891
+
892
+ :global(.flowdrop-workflow-editor .svelte-flow__edge) {
893
+ stroke-width: 2 !important;
894
+ cursor: pointer;
895
+ pointer-events: all;
896
+ }
897
+
898
+ :global(.flowdrop-workflow-editor .svelte-flow__edge path) {
899
+ stroke-width: 2 !important;
900
+ }
901
+
902
+ :global(.flowdrop-workflow-editor .svelte-flow__edge:hover) {
903
+ stroke: var(--fd-primary) !important;
904
+ stroke-width: 3 !important;
905
+ }
906
+
907
+ :global(.flowdrop-workflow-editor .svelte-flow__edge:hover path) {
908
+ stroke-width: 3 !important;
909
+ }
910
+
911
+ :global(.flowdrop-workflow-editor .svelte-flow__edge.selected) {
912
+ stroke: var(--fd-primary) !important;
913
+ stroke-width: 3 !important;
914
+ filter: drop-shadow(0 0 4px color-mix(in srgb, var(--fd-primary) 50%, transparent));
915
+ }
916
+
917
+ :global(.flowdrop-workflow-editor .svelte-flow__edge.selected path) {
918
+ stroke-width: 3 !important;
919
+ }
920
+
921
+ /* Ensure edge paths are clickable */
922
+ :global(.flowdrop-workflow-editor .svelte-flow__edge path) {
923
+ pointer-events: all;
924
+ cursor: pointer;
925
+ }
926
+
927
+ /* Handle size/position only; colors come from inline --fd-handle-fill and base.css ::before */
928
+ :global(.flowdrop-workflow-editor .svelte-flow__handle) {
929
+ width: var(--fd-handle-size);
930
+ height: var(--fd-handle-size);
931
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
932
+ z-index: 20;
933
+ }
934
+
935
+ /* Ensure our custom handles are clickable */
936
+ :global(.flowdrop-workflow-editor .svelte-flow__handle) {
937
+ pointer-events: all;
938
+ cursor: crosshair;
939
+ background-color: var(--fd-handle-fill);
940
+ border-color: var(--fd-handle-border-color);
941
+ }
942
+
943
+ /**
944
+ * Edge Styling Based on Source Port Data Type
945
+ * Uses CSS tokens from base.css for consistent theming
946
+ * - Trigger edges: solid dark line (control flow)
947
+ * - Tool edges: dashed amber line (tool connections)
948
+ * - Data edges: normal gray line (data flow)
949
+ */
950
+
951
+ /* Trigger Edge: Solid dark line for control flow */
952
+ :global(.flowdrop--edge--trigger path.svelte-flow__edge-path) {
953
+ stroke: var(--fd-edge-trigger);
954
+ stroke-width: var(--fd-edge-trigger-width);
955
+ }
956
+
957
+ :global(.flowdrop--edge--trigger:hover path.svelte-flow__edge-path) {
958
+ stroke: var(--fd-edge-trigger-hover);
959
+ stroke-width: var(--fd-edge-trigger-width-hover);
960
+ }
961
+
962
+ :global(.flowdrop--edge--trigger.selected path.svelte-flow__edge-path) {
963
+ stroke: var(--fd-edge-trigger-selected);
964
+ stroke-width: var(--fd-edge-trigger-width-hover);
965
+ }
966
+
967
+ /* Tool Edge: Dashed amber line for tool connections */
968
+ :global(.flowdrop--edge--tool path.svelte-flow__edge-path) {
969
+ stroke: var(--fd-edge-tool);
970
+ stroke-dasharray: 5 3;
971
+ }
972
+
973
+ :global(.flowdrop--edge--tool:hover path.svelte-flow__edge-path) {
974
+ stroke: var(--fd-edge-tool-hover);
975
+ stroke-width: 2;
976
+ }
977
+
978
+ :global(.flowdrop--edge--tool.selected path.svelte-flow__edge-path) {
979
+ stroke: var(--fd-edge-tool-selected);
980
+ stroke-dasharray: 5 3;
981
+ stroke-width: 2;
982
+ }
983
+
984
+ /* Data Edge: Normal gray line for data flow (default) */
985
+ :global(.flowdrop--edge--data path.svelte-flow__edge-path) {
986
+ stroke: var(--fd-edge-data);
987
+ }
988
+
989
+ :global(.flowdrop--edge--data:hover path.svelte-flow__edge-path) {
990
+ stroke: var(--fd-edge-data-hover);
991
+ stroke-width: 2;
992
+ }
993
+
994
+ :global(.flowdrop--edge--data.selected path.svelte-flow__edge-path) {
995
+ stroke: var(--fd-edge-data-selected);
996
+ stroke-width: 2;
997
+ }
998
+
999
+ /* Loopback Edge: Dashed gray line for loop iteration connections */
1000
+ :global(.flowdrop--edge--loopback path.svelte-flow__edge-path) {
1001
+ stroke: var(--fd-edge-loopback);
1002
+ stroke-width: var(--fd-edge-loopback-width);
1003
+ stroke-dasharray: var(--fd-edge-loopback-dasharray);
1004
+ opacity: var(--fd-edge-loopback-opacity);
1005
+ }
1006
+
1007
+ :global(.flowdrop--edge--loopback:hover path.svelte-flow__edge-path) {
1008
+ stroke: var(--fd-edge-loopback-hover);
1009
+ stroke-width: var(--fd-edge-loopback-width-hover);
1010
+ opacity: 1;
1011
+ }
1012
+
1013
+ :global(.flowdrop--edge--loopback.selected path.svelte-flow__edge-path) {
1014
+ stroke: var(--fd-edge-loopback-selected);
1015
+ stroke-width: var(--fd-edge-loopback-width-hover);
1016
+ stroke-dasharray: var(--fd-edge-loopback-dasharray);
1017
+ filter: drop-shadow(0 0 3px rgba(139, 92, 246, 0.4));
1018
+ opacity: 1;
1019
+ }
1020
+
1021
+ /* Proximity Connect Preview Edge: animated dashed line */
1022
+ :global(.flowdrop--edge--proximity-preview path.svelte-flow__edge-path) {
1023
+ stroke: var(--fd-primary);
1024
+ stroke-width: 2;
1025
+ stroke-dasharray: 5 5;
1026
+ opacity: 0.6;
1027
+ animation: flowdrop-proximity-dash 0.5s linear infinite;
1028
+ }
1029
+
1030
+ @keyframes flowdrop-proximity-dash {
1031
+ to {
1032
+ stroke-dashoffset: -10;
1033
+ }
1034
+ }
1035
+ </style>