@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,981 @@
1
+ <!--
2
+ FlowDrop App Component
3
+ Main application wrapper with navbar, sidebars, and workflow editor
4
+ Styled with BEM syntax
5
+ -->
6
+
7
+ <script lang="ts">
8
+ import { onMount } from 'svelte';
9
+ import MainLayout from './layouts/MainLayout.svelte';
10
+ import WorkflowEditor from './WorkflowEditor.svelte';
11
+ import NodeSidebar from './NodeSidebar.svelte';
12
+ import ConfigForm from './ConfigForm.svelte';
13
+ import ConfigPanel from './ConfigPanel.svelte';
14
+ import Navbar from './Navbar.svelte';
15
+ import { api, setEndpointConfig } from '../services/api.js';
16
+ import { EnhancedFlowDropApiClient } from '../api/enhanced-client.js';
17
+ import type {
18
+ NodeMetadata,
19
+ Workflow,
20
+ WorkflowNode,
21
+ ConfigSchema,
22
+ NodeUIExtensions
23
+ } from '../types/index.js';
24
+ import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
25
+ import { createEndpointConfig } from '../config/endpoints.js';
26
+ import type { EndpointConfig } from '../config/endpoints.js';
27
+ import type { AuthProvider } from '../types/auth.js';
28
+ import type { FlowDropEventHandlers, FlowDropFeatures } from '../types/events.js';
29
+ import { mergeFeatures } from '../types/events.js';
30
+ import {
31
+ getWorkflowStore,
32
+ workflowActions,
33
+ getWorkflowName,
34
+ getWorkflowFormat,
35
+ markAsSaved
36
+ } from '../stores/workflowStore.svelte.js';
37
+ import { globalSaveWorkflow, globalExportWorkflow } from '../services/globalSave.js';
38
+ import { apiToasts, dismissToast } from '../services/toastService.js';
39
+ import { initAutoSave } from '../services/autoSaveService.js';
40
+ import { getUiSettings } from '../stores/settingsStore.svelte.js';
41
+ import { initializePortCompatibility } from '../utils/connections.js';
42
+ import { DEFAULT_PORT_CONFIG } from '../config/defaultPortConfig.js';
43
+ import { workflowFormatRegistry } from '../registry/workflowFormatRegistry.js';
44
+ import { logger } from '../utils/logger.js';
45
+ import { validateWorkflowData } from '../utils/validation.js';
46
+
47
+ /**
48
+ * Configuration props for runtime customization
49
+ */
50
+ interface Props {
51
+ /** Initial workflow to load */
52
+ workflow?: Workflow;
53
+ /** Pre-loaded node types (if provided, skips API fetch) */
54
+ nodes?: NodeMetadata[];
55
+ /** Editor height */
56
+ height?: string | number;
57
+ /** Editor width */
58
+ width?: string | number;
59
+ /** Show the navbar */
60
+ showNavbar?: boolean;
61
+ /** Disable the node sidebar */
62
+ disableSidebar?: boolean;
63
+ /** Lock the workflow (prevent changes) */
64
+ lockWorkflow?: boolean;
65
+ /** Read-only mode */
66
+ readOnly?: boolean;
67
+ /** Node execution statuses */
68
+ nodeStatuses?: Record<string, 'pending' | 'running' | 'completed' | 'error'>;
69
+ /** Pipeline ID for fetching node execution info */
70
+ pipelineId?: string;
71
+ /** Custom navbar title */
72
+ navbarTitle?: string;
73
+ /** Custom navbar actions */
74
+ navbarActions?: Array<{
75
+ label: string;
76
+ href: string;
77
+ icon?: string;
78
+ variant?: 'primary' | 'secondary' | 'outline';
79
+ onclick?: (event: Event) => void;
80
+ }>;
81
+ /** Show settings gear icon in navbar */
82
+ showSettings?: boolean;
83
+ /** API base URL */
84
+ apiBaseUrl?: string;
85
+ /** Endpoint configuration */
86
+ endpointConfig?: EndpointConfig;
87
+ /** Authentication provider */
88
+ authProvider?: AuthProvider;
89
+ /** Event handlers */
90
+ eventHandlers?: FlowDropEventHandlers;
91
+ /** Feature configuration */
92
+ features?: FlowDropFeatures;
93
+ }
94
+
95
+ let {
96
+ workflow: initialWorkflow,
97
+ nodes: propNodes,
98
+ height = '100vh',
99
+ width = '100%',
100
+ showNavbar = false,
101
+ disableSidebar = false,
102
+ lockWorkflow = false,
103
+ readOnly = false,
104
+ nodeStatuses = {},
105
+ pipelineId,
106
+ navbarTitle,
107
+ navbarActions = [],
108
+ showSettings = true,
109
+ apiBaseUrl,
110
+ endpointConfig: propEndpointConfig,
111
+ authProvider,
112
+ eventHandlers,
113
+ features: propFeatures
114
+ }: Props = $props();
115
+
116
+ // svelte-ignore state_referenced_locally — feature flags don't change at runtime
117
+ const features = mergeFeatures(propFeatures);
118
+
119
+ // Create breadcrumb-style title - at top level to avoid store subscription issues
120
+ let breadcrumbTitle = $derived(() => {
121
+ // Use custom navbar title if provided
122
+ if (navbarTitle) {
123
+ return navbarTitle;
124
+ }
125
+ // Default workflow title logic
126
+ const wfName = getWorkflowName();
127
+ if (!wfName || wfName === 'Untitled Workflow') {
128
+ return 'Workflow / New Workflow';
129
+ }
130
+ return `Workflow / ${wfName}`;
131
+ });
132
+
133
+ let nodes = $state<NodeMetadata[]>([]);
134
+ // Remove workflow prop - use global store directly
135
+ // let workflow = $derived($workflowStore || initialWorkflow);
136
+ let error = $state<string | null>(null);
137
+ let endpointConfig = $state<EndpointConfig | null>(null);
138
+
139
+ /**
140
+ * Enhanced API client with authProvider support
141
+ * Used when authProvider is provided; otherwise falls back to legacy api service
142
+ */
143
+ let apiClient = $state<EnhancedFlowDropApiClient | null>(null);
144
+
145
+ // ConfigSidebar state
146
+ let isConfigSidebarOpen = $state(false);
147
+ let selectedNodeId = $state<string | null>(null);
148
+
149
+ // Workflow settings sidebar state
150
+ let isWorkflowSettingsOpen = $state(false);
151
+
152
+ // Workflow configuration schema (derived to pick up dynamic format options)
153
+ let workflowConfigSchema: ConfigSchema = $derived({
154
+ type: 'object' as const,
155
+ properties: {
156
+ name: {
157
+ type: 'string',
158
+ title: 'Workflow Name',
159
+ description: 'The name of the workflow',
160
+ default: ''
161
+ },
162
+ description: {
163
+ type: 'string',
164
+ title: 'Description',
165
+ description: 'A description of the workflow',
166
+ format: 'multiline',
167
+ default: ''
168
+ },
169
+ format: {
170
+ type: 'string',
171
+ title: 'Workflow Format',
172
+ description: 'The specification format for this workflow',
173
+ oneOf: workflowFormatRegistry.getOneOfOptions(),
174
+ default: 'flowdrop'
175
+ }
176
+ },
177
+ required: ['name']
178
+ });
179
+
180
+ // Workflow configuration values
181
+ let workflowConfigValues = $derived({
182
+ name: getWorkflowName() || '',
183
+ description: getWorkflowStore()?.description || '',
184
+ format: getWorkflowStore()?.metadata?.format || 'flowdrop'
185
+ });
186
+
187
+ // Get the current node from the workflow store
188
+ let selectedNodeForConfig = $derived(() => {
189
+ const wf = getWorkflowStore();
190
+ if (!selectedNodeId || !wf) return null;
191
+ return wf.nodes.find((node) => node.id === selectedNodeId) || null;
192
+ });
193
+
194
+ // WorkflowEditor reference for save functionality
195
+ let workflowEditorRef: WorkflowEditor | null = null;
196
+
197
+ /**
198
+ * Fetch node types from the server
199
+ *
200
+ * If propNodes is provided, uses those instead of fetching from API.
201
+ * Uses enhanced API client with authProvider support when available.
202
+ */
203
+ async function fetchNodeTypes(): Promise<void> {
204
+ // If nodes were provided as props, use them directly (skip API fetch)
205
+ if (propNodes && propNodes.length > 0) {
206
+ // Merge format-provided nodes with prop nodes (deduplicate by ID, props take priority)
207
+ const formatNodes = workflowFormatRegistry.getAllFormatNodes();
208
+ const existingIds = new Set(propNodes.map((n) => n.id));
209
+ const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
210
+ nodes = [...propNodes, ...uniqueFormatNodes];
211
+ return;
212
+ }
213
+
214
+ // Show loading toast (if toasts are enabled)
215
+ const loadingToast = features.showToasts ? apiToasts.loading('Loading node types') : null;
216
+ try {
217
+ error = null;
218
+
219
+ // Use enhanced client with authProvider if available, otherwise fall back to legacy api
220
+ let fetchedNodes: NodeMetadata[];
221
+ if (apiClient) {
222
+ fetchedNodes = await apiClient.getAvailableNodes();
223
+ } else {
224
+ fetchedNodes = await api.nodes.getNodes();
225
+ }
226
+
227
+ // Merge format-provided nodes with API nodes (deduplicate by ID, API takes priority)
228
+ const formatNodes = workflowFormatRegistry.getAllFormatNodes();
229
+ const existingIds = new Set(fetchedNodes.map((n) => n.id));
230
+ const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
231
+ nodes = [...fetchedNodes, ...uniqueFormatNodes];
232
+ error = null;
233
+
234
+ // Dismiss loading toast
235
+ if (loadingToast) {
236
+ dismissToast(loadingToast);
237
+ }
238
+ } catch (err) {
239
+ // Dismiss loading toast and show error toast
240
+ if (loadingToast) {
241
+ dismissToast(loadingToast);
242
+ }
243
+
244
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
245
+
246
+ // Notify parent via event handler
247
+ if (eventHandlers?.onApiError) {
248
+ const suppressToast = eventHandlers.onApiError(
249
+ err instanceof Error ? err : new Error(errorMessage),
250
+ 'fetchNodes'
251
+ );
252
+ if (suppressToast) {
253
+ // Parent handled the error, keep nodes empty
254
+ nodes = [];
255
+ return;
256
+ }
257
+ }
258
+
259
+ // Show error and set empty nodes array (no fallback to sample data)
260
+ error = `API Error: ${errorMessage}. No node types available.`;
261
+ if (features.showToasts) {
262
+ apiToasts.error('Load node types', errorMessage);
263
+ }
264
+
265
+ // Set empty nodes array instead of fallback data
266
+ nodes = [];
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Retry loading node types
272
+ */
273
+ function retryLoad(): void {
274
+ fetchNodeTypes();
275
+ }
276
+
277
+ /**
278
+ * Test API connection
279
+ */
280
+ async function testApiConnection(): Promise<void> {
281
+ try {
282
+ const baseUrl = endpointConfig?.baseUrl || apiBaseUrl || '/api/flowdrop';
283
+ const testUrl = `${baseUrl}/nodes`;
284
+
285
+ const response = await fetch(testUrl);
286
+ const data = await response.json();
287
+
288
+ if (response.ok && data.success) {
289
+ apiToasts.success('API connection test', 'Connection successful');
290
+ } else {
291
+ apiToasts.error('API connection test', 'Connection failed');
292
+ }
293
+ } catch (err) {
294
+ apiToasts.error('API connection test', err instanceof Error ? err.message : 'Unknown error');
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Initialize API endpoints and create enhanced client if authProvider is available
300
+ * Priority: propEndpointConfig > existingConfig > apiBaseUrl > default
301
+ */
302
+ async function initializeApiEndpoints(): Promise<void> {
303
+ // First priority: Use endpointConfig prop if provided (from mountFlowDropApp)
304
+ if (propEndpointConfig) {
305
+ setEndpointConfig(propEndpointConfig);
306
+ endpointConfig = propEndpointConfig;
307
+
308
+ // Create enhanced API client with authProvider support if provided
309
+ if (authProvider) {
310
+ apiClient = new EnhancedFlowDropApiClient(propEndpointConfig, authProvider);
311
+ }
312
+ return;
313
+ }
314
+
315
+ // Second priority: Check if endpoint config is already set (e.g., by parent layout)
316
+ const { getEndpointConfig } = await import('../services/api.js');
317
+ const existingConfig = getEndpointConfig();
318
+
319
+ // If config already exists and no override provided, use existing
320
+ if (existingConfig && !apiBaseUrl) {
321
+ endpointConfig = existingConfig;
322
+
323
+ // Create enhanced API client with authProvider support if provided
324
+ if (authProvider) {
325
+ apiClient = new EnhancedFlowDropApiClient(existingConfig, authProvider);
326
+ }
327
+ return;
328
+ }
329
+
330
+ // Third priority: Use provided apiBaseUrl or default
331
+ const baseUrl = apiBaseUrl || '/api/flowdrop';
332
+
333
+ const config = createEndpointConfig(baseUrl, {
334
+ auth: {
335
+ type: 'none' // No authentication for now
336
+ },
337
+ timeout: 10000, // 10 second timeout
338
+ retry: {
339
+ enabled: true,
340
+ maxAttempts: 2,
341
+ delay: 1000,
342
+ backoff: 'exponential'
343
+ }
344
+ });
345
+
346
+ setEndpointConfig(config);
347
+ // Store the configuration for passing to WorkflowEditor
348
+ endpointConfig = config;
349
+
350
+ // Create enhanced API client with authProvider support if provided
351
+ if (authProvider) {
352
+ apiClient = new EnhancedFlowDropApiClient(config, authProvider);
353
+ }
354
+ }
355
+
356
+ /**
357
+ * ConfigSidebar functions
358
+ */
359
+ function openConfigSidebar(node: WorkflowNode): void {
360
+ // Close if already open for the same node
361
+ if (isConfigSidebarOpen && selectedNodeId === node.id) {
362
+ closeConfigSidebar();
363
+ return;
364
+ }
365
+ selectedNodeId = node.id;
366
+ isConfigSidebarOpen = true;
367
+ }
368
+
369
+ function closeConfigSidebar(): void {
370
+ isConfigSidebarOpen = false;
371
+ selectedNodeId = null;
372
+ }
373
+
374
+ /**
375
+ * Toggle workflow settings sidebar
376
+ */
377
+ function toggleWorkflowSettings(): void {
378
+ isWorkflowSettingsOpen = !isWorkflowSettingsOpen;
379
+ // Close config sidebar if opening workflow settings
380
+ if (isWorkflowSettingsOpen) {
381
+ closeConfigSidebar();
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Handle workflow configuration save
387
+ */
388
+ async function handleWorkflowSave(config: Record<string, unknown>): Promise<void> {
389
+ // Update the workflow store
390
+ if (getWorkflowStore()) {
391
+ workflowActions.batchUpdate({
392
+ name: config.name as string | undefined,
393
+ description: config.description as string | undefined
394
+ });
395
+ }
396
+
397
+ // Close the sidebar
398
+ isWorkflowSettingsOpen = false;
399
+
400
+ // Also save the workflow to the backend
401
+ try {
402
+ await saveWorkflow();
403
+ } catch (error) {
404
+ logger.error('Failed to save workflow to backend:', error);
405
+ // Note: We don't throw the error here to avoid breaking the UI flow
406
+ // The user can still manually save via the main Save button if needed
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Save workflow - thin wrapper that delegates to globalSaveWorkflow().
412
+ *
413
+ * All save logic (blur flush, metadata construction, API call, event hooks,
414
+ * toast notifications) lives in globalSave.ts — the single source of truth.
415
+ */
416
+ async function saveWorkflow(): Promise<void> {
417
+ await globalSaveWorkflow({
418
+ apiClient: apiClient ?? undefined,
419
+ eventHandlers,
420
+ features,
421
+ onMarkAsSaved: markAsSaved
422
+ });
423
+ }
424
+
425
+ /**
426
+ * Export workflow - thin wrapper that delegates to globalExportWorkflow().
427
+ *
428
+ * All export logic (flush, metadata construction, file download) lives
429
+ * in globalSave.ts — the single source of truth.
430
+ */
431
+ async function exportWorkflow(): Promise<void> {
432
+ await globalExportWorkflow({ features });
433
+ }
434
+
435
+ /**
436
+ * Import workflow from a JSON file
437
+ *
438
+ * Reads the selected file, validates its structure, and loads it into the workflow store.
439
+ */
440
+ function importWorkflow(file: File): void {
441
+ const reader = new FileReader();
442
+ reader.onload = (event) => {
443
+ try {
444
+ const text = event.target?.result;
445
+ if (typeof text !== 'string') {
446
+ throw new Error('Could not read file contents.');
447
+ }
448
+ const data = JSON.parse(text);
449
+ const validation = validateWorkflowData(data);
450
+ if (!validation.valid) {
451
+ if (features.showToasts) {
452
+ apiToasts.error('Import workflow', validation.error ?? 'Invalid workflow JSON');
453
+ }
454
+ logger.warn('Workflow import validation failed:', validation.error);
455
+ return;
456
+ }
457
+ workflowActions.initialize(data as Workflow);
458
+ if (features.showToasts) {
459
+ apiToasts.success('Import workflow', 'Workflow imported successfully');
460
+ }
461
+ if (eventHandlers?.onWorkflowLoad) {
462
+ eventHandlers.onWorkflowLoad(data as Workflow);
463
+ }
464
+ } catch (error) {
465
+ const errorObj = error instanceof Error ? error : new Error('Unknown error occurred');
466
+ logger.error('Workflow import failed:', errorObj);
467
+ if (features.showToasts) {
468
+ apiToasts.error('Import workflow', errorObj.message);
469
+ }
470
+ }
471
+ };
472
+ reader.onerror = () => {
473
+ const message = 'Failed to read the selected file.';
474
+ logger.error(message);
475
+ if (features.showToasts) {
476
+ apiToasts.error('Import workflow', message);
477
+ }
478
+ };
479
+ reader.readAsText(file);
480
+ }
481
+
482
+ /**
483
+ * Handle file input change event for workflow import
484
+ */
485
+ function handleImportFileChange(event: Event): void {
486
+ const input = event.target as HTMLInputElement;
487
+ const file = input.files?.[0];
488
+ if (file) {
489
+ importWorkflow(file);
490
+ }
491
+ // Reset input so same file can be re-imported
492
+ input.value = '';
493
+ }
494
+
495
+ // Function to handle clicks outside the sidebar
496
+ function handleCanvasClick(event: MouseEvent): void {
497
+ // Check if the click is outside the right sidebar
498
+ const rightSidebar = document.querySelector('.flowdrop-main-layout__sidebar--right');
499
+ if (rightSidebar && !rightSidebar.contains(event.target as Node)) {
500
+ // Close sidebar when clicking outside of it
501
+ if (isConfigSidebarOpen) {
502
+ closeConfigSidebar();
503
+ }
504
+ }
505
+ }
506
+
507
+ // Load node types on mount
508
+ onMount(() => {
509
+ (async () => {
510
+ try {
511
+ await initializeApiEndpoints();
512
+
513
+ // Ensure port compatibility checker is initialized (needed for proximity connect, etc.)
514
+ // mountFlowDropApp initializes this before mounting, but SvelteKit routes need it here.
515
+ initializePortCompatibility(DEFAULT_PORT_CONFIG);
516
+
517
+ await fetchNodeTypes();
518
+
519
+ // Initialize the workflow store
520
+ if (initialWorkflow) {
521
+ workflowActions.initialize(initialWorkflow);
522
+
523
+ // Emit onWorkflowLoad event
524
+ if (eventHandlers?.onWorkflowLoad) {
525
+ eventHandlers.onWorkflowLoad(initialWorkflow);
526
+ }
527
+ } else {
528
+ // Initialize with a default empty workflow so the editor is functional
529
+ // (e.g., drag-and-drop requires a non-null workflow in the store)
530
+ const defaultWorkflow: Workflow = {
531
+ id: '',
532
+ name: 'Untitled Workflow',
533
+ nodes: [],
534
+ edges: [],
535
+ metadata: {
536
+ version: '1.0.0',
537
+ format: DEFAULT_WORKFLOW_FORMAT,
538
+ createdAt: new Date().toISOString(),
539
+ updatedAt: new Date().toISOString()
540
+ }
541
+ };
542
+ workflowActions.initialize(defaultWorkflow);
543
+ }
544
+ } catch (error) {
545
+ logger.error('Failed to initialize editor:', error);
546
+ }
547
+ })();
548
+
549
+ // Listen for workflow settings toggle from main navbar
550
+ const handleWorkflowSettingsToggle = () => {
551
+ toggleWorkflowSettings();
552
+ };
553
+
554
+ window.addEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
555
+
556
+ // Initialize auto-save based on user settings
557
+ const cleanupAutoSave = initAutoSave({
558
+ onSave: async () => {
559
+ await saveWorkflow();
560
+ },
561
+ onError: (error) => {
562
+ // Don't show toast for auto-save errors to avoid noise
563
+ logger.warn('Auto-save failed:', error);
564
+ },
565
+ onSuccess: () => {
566
+ logger.debug('Auto-saved workflow');
567
+ }
568
+ });
569
+
570
+ return () => {
571
+ window.removeEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
572
+ cleanupAutoSave();
573
+ };
574
+ });
575
+
576
+ /**
577
+ * Derived value for showing the right config panel
578
+ * Config panel always appears on the right side
579
+ */
580
+ const hasConfigPanelOpen = $derived(isWorkflowSettingsOpen || !!selectedNodeForConfig());
581
+ const showRightPanel = $derived(!disableSidebar && hasConfigPanelOpen);
582
+
583
+ /**
584
+ * Calculate left sidebar width based on collapsed state
585
+ * When collapsed, use 48px; otherwise use user-configured width
586
+ */
587
+ const leftSidebarWidth = $derived(
588
+ getUiSettings().sidebarCollapsed ? 48 : getUiSettings().sidebarWidth
589
+ );
590
+
591
+ // File input reference for workflow import
592
+ let fileInputRef = $state<HTMLInputElement | null>(null);
593
+ </script>
594
+
595
+ <svelte:head>
596
+ <title>FlowDrop - Visual Workflow Manager</title>
597
+ <meta name="description" content="A modern drag-and-drop workflow editor for LLM applications" />
598
+ </svelte:head>
599
+
600
+ <!-- Hidden file input for workflow JSON import -->
601
+ <input
602
+ bind:this={fileInputRef}
603
+ type="file"
604
+ accept=".json,application/json"
605
+ style="display: none;"
606
+ onchange={handleImportFileChange}
607
+ />
608
+
609
+ <!-- MainLayout wrapper for workflow editor -->
610
+ <MainLayout
611
+ showHeader={showNavbar}
612
+ showLeftSidebar={!disableSidebar}
613
+ showRightSidebar={showRightPanel}
614
+ showBottomPanel={false}
615
+ showFooter={false}
616
+ headerHeight={60}
617
+ {leftSidebarWidth}
618
+ rightSidebarWidth={400}
619
+ leftSidebarMinWidth={getUiSettings().sidebarCollapsed ? 48 : 280}
620
+ leftSidebarMaxWidth={getUiSettings().sidebarCollapsed ? 48 : 450}
621
+ rightSidebarMinWidth={320}
622
+ rightSidebarMaxWidth={550}
623
+ enableLeftSplitPane={false}
624
+ enableRightSplitPane={true}
625
+ class="flowdrop-app-layout"
626
+ >
627
+ <!-- Header: Navbar -->
628
+ {#snippet header()}
629
+ <Navbar
630
+ title={breadcrumbTitle()}
631
+ primaryActions={navbarActions.length > 0
632
+ ? navbarActions
633
+ : [
634
+ {
635
+ label: 'Save',
636
+ href: '#save',
637
+ icon: 'heroicons:document-arrow-down',
638
+ variant: 'primary',
639
+ onclick: (e) => {
640
+ e.preventDefault();
641
+ saveWorkflow();
642
+ }
643
+ },
644
+ {
645
+ label: 'Export',
646
+ href: '#export',
647
+ icon: 'heroicons:arrow-down-tray',
648
+ variant: 'outline',
649
+ onclick: (e) => {
650
+ e.preventDefault();
651
+ exportWorkflow();
652
+ }
653
+ },
654
+ {
655
+ label: 'Import',
656
+ href: '#import',
657
+ icon: 'heroicons:arrow-up-tray',
658
+ variant: 'outline',
659
+ onclick: (e) => {
660
+ e.preventDefault();
661
+ fileInputRef?.click();
662
+ }
663
+ },
664
+ {
665
+ label: 'Workflow Settings',
666
+ href: '#settings',
667
+ icon: 'heroicons:cog-6-tooth',
668
+ variant: 'outline',
669
+ onclick: (e) => {
670
+ e.preventDefault();
671
+ toggleWorkflowSettings();
672
+ }
673
+ }
674
+ ]}
675
+ showStatus={true}
676
+ {showSettings}
677
+ />
678
+ {/snippet}
679
+
680
+ <!-- Left Sidebar: Node Components -->
681
+ {#snippet leftSidebar()}
682
+ <NodeSidebar {nodes} activeFormat={getWorkflowFormat()} />
683
+ {/snippet}
684
+
685
+ <!-- Right Sidebar: Configuration or Workflow Settings -->
686
+ {#snippet rightSidebar()}
687
+ {#if isWorkflowSettingsOpen}
688
+ <ConfigPanel
689
+ title="Workflow Settings"
690
+ id={getWorkflowStore()?.id}
691
+ details={[
692
+ { label: 'Nodes', value: String(getWorkflowStore()?.nodes?.length ?? 0) },
693
+ { label: 'Connections', value: String(getWorkflowStore()?.edges?.length ?? 0) }
694
+ ]}
695
+ configTitle="Settings"
696
+ onClose={() => (isWorkflowSettingsOpen = false)}
697
+ >
698
+ <ConfigForm
699
+ {authProvider}
700
+ schema={workflowConfigSchema}
701
+ values={workflowConfigValues}
702
+ showUIExtensions={false}
703
+ onChange={(config) => {
704
+ // Sync workflow settings changes immediately on field blur
705
+ const wf = getWorkflowStore();
706
+ if (wf) {
707
+ const newFormat = (config.format as string) || DEFAULT_WORKFLOW_FORMAT;
708
+ const currentFormat = wf.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
709
+
710
+ // Warn about incompatible nodes when format changes
711
+ if (newFormat !== currentFormat) {
712
+ const incompatibleNodes = wf.nodes?.filter((node) => {
713
+ const formats = node.data?.metadata?.formats;
714
+ return formats && formats.length > 0 && !formats.includes(newFormat);
715
+ });
716
+ if (incompatibleNodes && incompatibleNodes.length > 0) {
717
+ logger.warn(
718
+ `Format changed to '${newFormat}'. ${incompatibleNodes.length} node(s) are not compatible with this format and may not export correctly:`,
719
+ incompatibleNodes.map((n) => n.data?.label || n.type)
720
+ );
721
+ }
722
+ }
723
+
724
+ workflowActions.batchUpdate({
725
+ name: config.name as string,
726
+ description: config.description as string | undefined,
727
+ metadata: {
728
+ ...wf.metadata,
729
+ format: newFormat
730
+ }
731
+ });
732
+ }
733
+ }}
734
+ />
735
+ </ConfigPanel>
736
+ {:else if selectedNodeForConfig()}
737
+ {@const currentNode = selectedNodeForConfig()!}
738
+ <ConfigPanel
739
+ title={currentNode.data.label}
740
+ id={currentNode.id}
741
+ description={currentNode.data.metadata?.description || 'Node configuration'}
742
+ details={[
743
+ { label: 'Type', value: currentNode.data.metadata?.type || currentNode.type },
744
+ { label: 'Category', value: currentNode.data.metadata?.category || 'general' }
745
+ ]}
746
+ onClose={closeConfigSidebar}
747
+ >
748
+ <ConfigForm
749
+ {authProvider}
750
+ node={currentNode}
751
+ workflowId={getWorkflowStore()?.id}
752
+ workflowNodes={getWorkflowStore()?.nodes}
753
+ workflowEdges={getWorkflowStore()?.edges}
754
+ onChange={async (updatedConfig, uiExtensions) => {
755
+ // Sync config changes to workflow immediately on field blur
756
+ if (selectedNodeId && currentNode) {
757
+ // Build the updated node data
758
+ const updatedData = {
759
+ ...currentNode.data,
760
+ config: updatedConfig
761
+ };
762
+
763
+ // Include UI extensions if provided
764
+ if (uiExtensions) {
765
+ updatedData.extensions = {
766
+ ...currentNode.data.extensions,
767
+ ui: uiExtensions
768
+ };
769
+ }
770
+
771
+ // Update the node in the workflow store
772
+ const nodeUpdates: Record<string, unknown> = {
773
+ data: updatedData
774
+ };
775
+
776
+ workflowActions.updateNode(selectedNodeId, nodeUpdates);
777
+
778
+ // Update the local editor state to reflect config changes immediately
779
+ // This is needed for nodeType changes to take effect visually
780
+ workflowEditorRef?.updateNodeData(selectedNodeId, updatedData);
781
+
782
+ // Refresh edge positions in case config changes affect handles
783
+ await workflowEditorRef?.refreshEdgePositions(selectedNodeId);
784
+ }
785
+ }}
786
+ />
787
+ </ConfigPanel>
788
+ {/if}
789
+ {/snippet}
790
+
791
+ <!-- Main Content: Workflow Editor with Error Status -->
792
+ <!-- Status Display: aria-live announces API errors dynamically without requiring focus -->
793
+ {#if error}
794
+ <div class="flowdrop-status flowdrop-status--error" aria-live="polite" aria-atomic="true">
795
+ <div class="flowdrop-status__content">
796
+ <div class="flowdrop-flex flowdrop-gap--3">
797
+ <div class="flowdrop-status__indicator flowdrop-status__indicator--error"></div>
798
+ <span class="flowdrop-text--sm flowdrop-font--medium">Error: {error}</span>
799
+ </div>
800
+ <div class="flowdrop-flex flowdrop-gap--2">
801
+ <button
802
+ class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--primary"
803
+ onclick={retryLoad}
804
+ type="button"
805
+ >
806
+ Retry
807
+ </button>
808
+ <button
809
+ class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
810
+ onclick={() => {
811
+ const defaultUrl = '/api/flowdrop';
812
+ const newUrl = prompt('Enter Backend API URL:', defaultUrl);
813
+ if (newUrl) {
814
+ const endpointConfig = createEndpointConfig(newUrl);
815
+ setEndpointConfig(endpointConfig);
816
+ fetchNodeTypes();
817
+ }
818
+ }}
819
+ type="button"
820
+ >
821
+ Set API URL
822
+ </button>
823
+ <button
824
+ class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
825
+ onclick={testApiConnection}
826
+ type="button"
827
+ >
828
+ Test API
829
+ </button>
830
+ <button
831
+ class="flowdrop-btn flowdrop-btn--ghost flowdrop-btn--sm"
832
+ onclick={() => (error = null)}
833
+ type="button"
834
+ >
835
+
836
+ </button>
837
+ </div>
838
+ </div>
839
+ </div>
840
+ {/if}
841
+
842
+ <!-- Main Editor Area -->
843
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions — interactive workflow canvas region with keyboard support -->
844
+ <div
845
+ class="flowdrop-editor-main"
846
+ class:pipeline-view={!!pipelineId}
847
+ onclick={handleCanvasClick}
848
+ onkeydown={(e) => e.key === 'Escape' && closeConfigSidebar()}
849
+ role="region"
850
+ aria-label="Workflow canvas"
851
+ >
852
+ <WorkflowEditor
853
+ bind:this={workflowEditorRef}
854
+ {nodes}
855
+ {height}
856
+ {width}
857
+ endpointConfig={endpointConfig ?? undefined}
858
+ {isConfigSidebarOpen}
859
+ selectedNodeForConfig={selectedNodeForConfig()}
860
+ {openConfigSidebar}
861
+ {closeConfigSidebar}
862
+ {lockWorkflow}
863
+ {readOnly}
864
+ {nodeStatuses}
865
+ {pipelineId}
866
+ />
867
+ </div>
868
+ </MainLayout>
869
+
870
+ <style>
871
+ /* Status bar styles */
872
+ .flowdrop-status {
873
+ background-color: var(--fd-info-muted);
874
+ border-bottom: 1px solid var(--fd-info);
875
+ padding: 1rem;
876
+ }
877
+
878
+ .flowdrop-status--error {
879
+ background-color: var(--fd-error-muted);
880
+ border-bottom: 1px solid var(--fd-error);
881
+ }
882
+
883
+ .flowdrop-status__content {
884
+ max-width: 80rem;
885
+ margin: 0 auto;
886
+ display: flex;
887
+ align-items: center;
888
+ justify-content: space-between;
889
+ }
890
+
891
+ .flowdrop-status__indicator {
892
+ width: 0.5rem;
893
+ height: 0.5rem;
894
+ border-radius: 50%;
895
+ }
896
+
897
+ .flowdrop-status__indicator--error {
898
+ background-color: var(--fd-error);
899
+ }
900
+
901
+ /* Button styles */
902
+ .flowdrop-btn {
903
+ padding: 0.375rem 0.75rem;
904
+ border-radius: var(--fd-radius-md);
905
+ font-size: 0.75rem;
906
+ font-weight: 500;
907
+ cursor: pointer;
908
+ border: 1px solid transparent;
909
+ transition: all var(--fd-transition-fast);
910
+ }
911
+
912
+ .flowdrop-btn--sm {
913
+ padding: 0.25rem 0.5rem;
914
+ font-size: 0.625rem;
915
+ }
916
+
917
+ .flowdrop-btn--outline {
918
+ background-color: transparent;
919
+ border-color: var(--fd-border);
920
+ color: var(--fd-foreground);
921
+ }
922
+
923
+ .flowdrop-btn--outline:hover {
924
+ background-color: var(--fd-muted);
925
+ border-color: var(--fd-border-strong);
926
+ }
927
+
928
+ .flowdrop-btn--primary {
929
+ background-color: var(--fd-primary);
930
+ border-color: var(--fd-primary);
931
+ color: var(--fd-primary-foreground);
932
+ }
933
+
934
+ .flowdrop-btn--primary:hover {
935
+ background-color: var(--fd-primary-hover);
936
+ border-color: var(--fd-primary-hover);
937
+ }
938
+
939
+ .flowdrop-btn--ghost {
940
+ background-color: transparent;
941
+ border-color: transparent;
942
+ color: var(--fd-muted-foreground);
943
+ }
944
+
945
+ .flowdrop-btn--ghost:hover {
946
+ background-color: var(--fd-muted);
947
+ color: var(--fd-foreground);
948
+ }
949
+
950
+ /* Utility classes */
951
+ .flowdrop-flex {
952
+ display: flex;
953
+ }
954
+
955
+ .flowdrop-gap--2 {
956
+ gap: 0.5rem;
957
+ }
958
+
959
+ .flowdrop-gap--3 {
960
+ gap: 0.75rem;
961
+ }
962
+
963
+ .flowdrop-text--sm {
964
+ font-size: 0.875rem;
965
+ line-height: 1.25rem;
966
+ }
967
+
968
+ .flowdrop-font--medium {
969
+ font-weight: 500;
970
+ }
971
+
972
+ /* Main editor area */
973
+ .flowdrop-editor-main {
974
+ flex: 1;
975
+ position: relative;
976
+ min-width: 0;
977
+ height: 100%;
978
+ overflow: hidden;
979
+ background: var(--fd-layout-background);
980
+ }
981
+ </style>