@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,1138 @@
1
+ <!--
2
+ ConfigForm Component
3
+ Handles dynamic form rendering for node or entity configuration
4
+ Supports both node-based config and direct schema/values
5
+ Uses reactive $state for proper Svelte 5 reactivity
6
+
7
+ Features:
8
+ - Dynamic form generation from JSON Schema using modular form components
9
+ - UI Extensions support for display settings (e.g., hide unconnected handles)
10
+ - Extensible architecture for complex schema types (array, object)
11
+ - Admin/Edit support for external configuration links and dynamic schema fetching
12
+
13
+ Accessibility features:
14
+ - Proper label associations with for/id attributes
15
+ - ARIA describedby for field descriptions
16
+ - Focus-visible states for keyboard navigation
17
+ - Required field indicators
18
+ -->
19
+
20
+ <script lang="ts">
21
+ import { setContext } from 'svelte';
22
+ import Icon from '@iconify/svelte';
23
+ import type {
24
+ ConfigSchema,
25
+ WorkflowNode,
26
+ WorkflowEdge,
27
+ NodeUIExtensions,
28
+ ConfigEditOptions,
29
+ AuthProvider
30
+ } from '../types/index.js';
31
+ import type { UISchemaElement } from '../types/uischema.js';
32
+ import { FormField, FormFieldWrapper, FormToggle } from './form/index.js';
33
+ import FormUISchemaRenderer from './form/FormUISchemaRenderer.svelte';
34
+ import type { FieldSchema } from './form/index.js';
35
+ import {
36
+ getEffectiveConfigEditOptions,
37
+ fetchDynamicSchema,
38
+ resolveExternalEditUrl,
39
+ invalidateSchemaCache,
40
+ type DynamicSchemaResult
41
+ } from '../services/dynamicSchemaService.js';
42
+ import { globalSaveWorkflow } from '../services/globalSave.js';
43
+ import { getAvailableVariables } from '../services/variableService.js';
44
+ import { logger } from '../utils/logger.js';
45
+
46
+ interface Props {
47
+ /** Optional workflow node (if provided, schema and values are derived from it) */
48
+ node?: WorkflowNode;
49
+ /** Direct config schema (used when node is not provided) */
50
+ schema?: ConfigSchema;
51
+ /**
52
+ * Optional UI Schema that controls field layout and grouping.
53
+ * When provided, fields render according to the UISchema tree structure.
54
+ * When absent, falls back to node.data.metadata.uiSchema, then flat rendering.
55
+ * @see https://jsonforms.io/docs/uischema
56
+ */
57
+ uiSchema?: UISchemaElement;
58
+ /** Direct config values (used when node is not provided) */
59
+ values?: Record<string, unknown>;
60
+ /** Whether to show UI extension settings section */
61
+ showUIExtensions?: boolean;
62
+ /** Optional workflow ID for context in external links */
63
+ workflowId?: string;
64
+ /** Whether to also save the workflow when saving config */
65
+ saveWorkflowWhenSavingConfig?: boolean;
66
+ /**
67
+ * All workflow nodes (used for deriving template variables from connected nodes).
68
+ * When provided along with workflowEdges, enables autocomplete for template fields.
69
+ */
70
+ workflowNodes?: WorkflowNode[];
71
+ /**
72
+ * All workflow edges (used for finding connections to derive template variables).
73
+ * When provided along with workflowNodes, enables autocomplete for template fields.
74
+ */
75
+ workflowEdges?: WorkflowEdge[];
76
+ /** Auth provider for API requests (used for template variable API mode) */
77
+ authProvider?: AuthProvider;
78
+ /** Callback when any field value changes (fired on blur for immediate sync) */
79
+ onChange?: (config: Record<string, unknown>, uiExtensions?: NodeUIExtensions) => void;
80
+ /** Callback when form is saved (includes both config and extensions if enabled) */
81
+ onSave?: (config: Record<string, unknown>, uiExtensions?: NodeUIExtensions) => void;
82
+ /** Callback when form is cancelled */
83
+ onCancel?: () => void;
84
+ }
85
+
86
+ let {
87
+ node,
88
+ schema,
89
+ uiSchema,
90
+ values,
91
+ showUIExtensions = true,
92
+ workflowId,
93
+ saveWorkflowWhenSavingConfig = false,
94
+ workflowNodes = [],
95
+ workflowEdges = [],
96
+ authProvider,
97
+ onChange,
98
+ onSave,
99
+ onCancel
100
+ }: Props = $props();
101
+
102
+ // Set context for child components (e.g., FormAutocomplete)
103
+ // Use getter functions to ensure child components always get the current prop value,
104
+ // even if the prop changes after initial mount
105
+ setContext<() => AuthProvider | undefined>('flowdrop:getAuthProvider', () => authProvider);
106
+
107
+ /**
108
+ * State for dynamic schema loading
109
+ */
110
+ let dynamicSchemaLoading = $state(false);
111
+ let dynamicSchemaError = $state<string | null>(null);
112
+ let fetchedDynamicSchema = $state<ConfigSchema | null>(null);
113
+
114
+ /**
115
+ * Get the admin edit configuration for the node
116
+ */
117
+ const configEditOptions = $derived.by<ConfigEditOptions | undefined>(() => {
118
+ if (!node) return undefined;
119
+ return getEffectiveConfigEditOptions(node);
120
+ });
121
+
122
+ /**
123
+ * Determine if we should show the external edit link
124
+ */
125
+ const showExternalEditLink = $derived.by(() => {
126
+ if (!configEditOptions?.externalEditLink) return false;
127
+ // Show if no dynamic schema, or if both exist but preferDynamicSchema is false
128
+ if (!configEditOptions.dynamicSchema) return true;
129
+ return !configEditOptions.preferDynamicSchema;
130
+ });
131
+
132
+ /**
133
+ * Determine if we should use/fetch dynamic schema
134
+ */
135
+ const useDynamicSchema = $derived.by(() => {
136
+ if (!configEditOptions?.dynamicSchema) return false;
137
+ // Use if no external link, or if both exist and preferDynamicSchema is true
138
+ if (!configEditOptions.externalEditLink) return true;
139
+ return configEditOptions.preferDynamicSchema === true;
140
+ });
141
+
142
+ /**
143
+ * Get the configuration schema from node metadata, direct prop, or fetched dynamic schema
144
+ * Priority: fetchedDynamicSchema > direct schema prop > node metadata configSchema
145
+ */
146
+ const configSchema = $derived.by<ConfigSchema | undefined>(() => {
147
+ // If we have a fetched dynamic schema, use it
148
+ if (fetchedDynamicSchema) {
149
+ return fetchedDynamicSchema;
150
+ }
151
+ // Otherwise use the direct prop or node metadata
152
+ return schema ?? (node?.data.metadata?.configSchema as ConfigSchema | undefined);
153
+ });
154
+
155
+ /**
156
+ * Get the UI schema from direct prop or node metadata
157
+ * Priority: direct uiSchema prop > node metadata uiSchema
158
+ */
159
+ const configUISchema = $derived.by<UISchemaElement | undefined>(() => {
160
+ return uiSchema ?? (node?.data.metadata?.uiSchema as UISchemaElement | undefined);
161
+ });
162
+
163
+ /**
164
+ * Check if the node needs dynamic schema loading
165
+ * Loads when: no static schema OR preferDynamicSchema is true
166
+ */
167
+ const needsDynamicSchemaLoad = $derived.by(() => {
168
+ if (!node) return false;
169
+ const staticSchema = schema ?? node.data.metadata?.configSchema;
170
+ // Need to load if: (no static schema OR preferDynamicSchema is true) AND dynamic schema is configured
171
+ return (
172
+ (!staticSchema || configEditOptions?.preferDynamicSchema === true) &&
173
+ useDynamicSchema &&
174
+ !fetchedDynamicSchema &&
175
+ !dynamicSchemaLoading
176
+ );
177
+ });
178
+
179
+ /**
180
+ * Get the current configuration from node or direct prop
181
+ */
182
+ const initialConfig = $derived(values ?? node?.data.config ?? {});
183
+
184
+ /**
185
+ * Create reactive configuration values using $state
186
+ * This fixes the Svelte 5 reactivity warnings
187
+ */
188
+ let configValues = $state<Record<string, unknown>>({});
189
+
190
+ /**
191
+ * UI Extension values for display settings
192
+ * Merges node type defaults with instance overrides
193
+ */
194
+ let uiExtensionValues = $state<NodeUIExtensions>({});
195
+
196
+ /**
197
+ * Flag to track if workflow save is in progress
198
+ */
199
+ let isSavingWorkflow = $state(false);
200
+
201
+ /**
202
+ * Get initial UI extensions from node (instance level overrides type level)
203
+ */
204
+ const initialUIExtensions = $derived.by<NodeUIExtensions>(() => {
205
+ if (!node) return {};
206
+ // Merge type-level defaults with instance-level overrides
207
+ const typeDefaults = node.data.metadata?.extensions?.ui ?? {};
208
+ const instanceOverrides = node.data.extensions?.ui ?? {};
209
+ return { ...typeDefaults, ...instanceOverrides };
210
+ });
211
+
212
+ /**
213
+ * Fetch dynamic schema when needed
214
+ */
215
+ async function loadDynamicSchema(): Promise<void> {
216
+ if (!node || !configEditOptions?.dynamicSchema) return;
217
+
218
+ dynamicSchemaLoading = true;
219
+ dynamicSchemaError = null;
220
+
221
+ try {
222
+ const result: DynamicSchemaResult = await fetchDynamicSchema(
223
+ configEditOptions.dynamicSchema,
224
+ node,
225
+ workflowId
226
+ );
227
+
228
+ if (result.success && result.schema) {
229
+ fetchedDynamicSchema = result.schema;
230
+ } else {
231
+ dynamicSchemaError =
232
+ result.error ?? configEditOptions.errorMessage ?? 'Failed to load configuration schema';
233
+ }
234
+ } catch (err) {
235
+ dynamicSchemaError =
236
+ err instanceof Error
237
+ ? err.message
238
+ : (configEditOptions.errorMessage ?? 'Failed to load configuration schema');
239
+ } finally {
240
+ dynamicSchemaLoading = false;
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Refresh the dynamic schema (invalidate cache and reload)
246
+ */
247
+ async function refreshDynamicSchema(): Promise<void> {
248
+ if (!node || !configEditOptions?.dynamicSchema) return;
249
+
250
+ // Invalidate the cache first
251
+ invalidateSchemaCache(node, configEditOptions.dynamicSchema);
252
+ fetchedDynamicSchema = null;
253
+
254
+ // Reload the schema
255
+ await loadDynamicSchema();
256
+ }
257
+
258
+ /**
259
+ * Get the resolved external edit URL
260
+ */
261
+ function getExternalEditUrl(): string {
262
+ if (!node || !configEditOptions?.externalEditLink) return '#';
263
+ return resolveExternalEditUrl(configEditOptions.externalEditLink, node, workflowId);
264
+ }
265
+
266
+ /**
267
+ * Handle opening external edit link
268
+ */
269
+ function handleExternalEditClick(): void {
270
+ if (!node || !configEditOptions?.externalEditLink) return;
271
+
272
+ const url = getExternalEditUrl();
273
+ const openInNewTab = configEditOptions.externalEditLink.openInNewTab !== false;
274
+
275
+ if (openInNewTab) {
276
+ window.open(url, '_blank', 'noopener,noreferrer');
277
+ } else {
278
+ window.location.href = url;
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Auto-load dynamic schema on mount if needed
284
+ */
285
+ $effect(() => {
286
+ if (needsDynamicSchemaLoad) {
287
+ loadDynamicSchema();
288
+ }
289
+ });
290
+
291
+ /**
292
+ * Initialize config values when node/schema changes
293
+ */
294
+ $effect(() => {
295
+ if (configSchema?.properties) {
296
+ const mergedConfig: Record<string, unknown> = {};
297
+ Object.entries(configSchema.properties).forEach(([key, field]) => {
298
+ const fieldConfig = field as Record<string, unknown>;
299
+ // Use existing value if available, otherwise use default
300
+ mergedConfig[key] =
301
+ initialConfig[key] !== undefined ? initialConfig[key] : fieldConfig.default;
302
+ });
303
+ configValues = mergedConfig;
304
+ }
305
+ });
306
+
307
+ /**
308
+ * Initialize UI extension values when node changes
309
+ */
310
+ $effect(() => {
311
+ uiExtensionValues = {
312
+ hideUnconnectedHandles: initialUIExtensions.hideUnconnectedHandles ?? false
313
+ };
314
+ });
315
+
316
+ /**
317
+ * Check if a field is required based on schema
318
+ */
319
+ function isFieldRequired(key: string): boolean {
320
+ if (!configSchema?.required) return false;
321
+ return configSchema.required.includes(key);
322
+ }
323
+
324
+ /**
325
+ * Handle field value changes from FormField components
326
+ */
327
+ function handleFieldChange(key: string, value: unknown): void {
328
+ configValues[key] = value;
329
+ }
330
+
331
+ /**
332
+ * Handle form field blur - sync changes to workflow immediately
333
+ * Uses focusout which bubbles from child elements
334
+ * This enables auto-save behavior without requiring explicit Save button clicks
335
+ */
336
+ function handleFormBlur(): void {
337
+ if (onChange) {
338
+ const extensions = showUIExtensions && node ? uiExtensionValues : undefined;
339
+ onChange({ ...configValues }, extensions);
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Handle form submission
345
+ * Collects both config values and UI extension values
346
+ * Optionally saves the workflow if the option is enabled
347
+ */
348
+ async function handleSave(): Promise<void> {
349
+ // Collect all form values including hidden fields
350
+ const form = document.querySelector('.config-form');
351
+ const updatedConfig: Record<string, unknown> = { ...configValues };
352
+
353
+ if (form) {
354
+ const inputs = form.querySelectorAll('input, select, textarea');
355
+ inputs.forEach((input: Element) => {
356
+ const inputEl = input as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
357
+ // Skip UI extension fields (prefixed with ext-)
358
+ if (inputEl.id && !inputEl.id.startsWith('ext-')) {
359
+ if (inputEl instanceof HTMLInputElement && inputEl.type === 'checkbox') {
360
+ updatedConfig[inputEl.id] = inputEl.checked;
361
+ } else if (
362
+ inputEl instanceof HTMLInputElement &&
363
+ (inputEl.type === 'number' || inputEl.type === 'range')
364
+ ) {
365
+ updatedConfig[inputEl.id] = inputEl.value ? Number(inputEl.value) : inputEl.value;
366
+ } else if (inputEl instanceof HTMLInputElement && inputEl.type === 'hidden') {
367
+ // Parse hidden field values that might be JSON
368
+ try {
369
+ const parsed = JSON.parse(inputEl.value);
370
+ updatedConfig[inputEl.id] = parsed;
371
+ } catch {
372
+ // If not JSON, use raw value
373
+ updatedConfig[inputEl.id] = inputEl.value;
374
+ }
375
+ } else {
376
+ updatedConfig[inputEl.id] = inputEl.value;
377
+ }
378
+ }
379
+ });
380
+ }
381
+
382
+ // Preserve hidden field values from original config if not collected from form
383
+ if (initialConfig && configSchema?.properties) {
384
+ Object.entries(configSchema.properties).forEach(
385
+ ([key, property]: [string, Record<string, unknown>]) => {
386
+ if (property.format === 'hidden' && !(key in updatedConfig) && key in initialConfig) {
387
+ updatedConfig[key] = initialConfig[key];
388
+ }
389
+ }
390
+ );
391
+ }
392
+
393
+ // Pass UI extensions only if enabled
394
+ if (onSave) {
395
+ if (showUIExtensions && node) {
396
+ onSave(updatedConfig, uiExtensionValues);
397
+ } else {
398
+ onSave(updatedConfig);
399
+ }
400
+ }
401
+
402
+ // Save workflow if the option is enabled
403
+ if (saveWorkflowWhenSavingConfig) {
404
+ isSavingWorkflow = true;
405
+ try {
406
+ await globalSaveWorkflow();
407
+ } catch (error) {
408
+ logger.error('Failed to save workflow after config save:', error);
409
+ } finally {
410
+ isSavingWorkflow = false;
411
+ }
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Convert ConfigProperty to FieldSchema for FormField component.
417
+ * Processes template fields to inject computed variable schema.
418
+ *
419
+ * For template fields, the `variables` config controls which input ports
420
+ * provide variables for autocomplete.
421
+ */
422
+ function toFieldSchema(property: Record<string, unknown>): FieldSchema {
423
+ const fieldSchema = property as FieldSchema;
424
+
425
+ // Process template fields to compute variable schema
426
+ if (
427
+ fieldSchema.format === 'template' &&
428
+ node &&
429
+ workflowNodes.length > 0 &&
430
+ workflowEdges.length > 0
431
+ ) {
432
+ // Get the variables config (may be undefined or partially defined)
433
+ const variablesConfig = fieldSchema.variables;
434
+
435
+ // Compute the variable schema with optional port filtering and port name prefixing
436
+ const computedSchema = getAvailableVariables(node, workflowNodes, workflowEdges, {
437
+ targetPortIds: variablesConfig?.ports,
438
+ includePortName: variablesConfig?.includePortName
439
+ });
440
+
441
+ // Merge computed schema with any pre-defined schema
442
+ const mergedSchema = variablesConfig?.schema
443
+ ? {
444
+ variables: {
445
+ ...computedSchema.variables,
446
+ ...variablesConfig.schema.variables
447
+ }
448
+ }
449
+ : computedSchema;
450
+
451
+ return {
452
+ ...fieldSchema,
453
+ variables: {
454
+ ...variablesConfig,
455
+ schema: mergedSchema
456
+ }
457
+ } as FieldSchema;
458
+ }
459
+
460
+ return fieldSchema;
461
+ }
462
+ </script>
463
+
464
+ <!-- External Edit Link Section (shown when configured and preferred) -->
465
+ {#if showExternalEditLink && configEditOptions?.externalEditLink}
466
+ <div class="config-form__admin-edit">
467
+ <div class="config-form__admin-edit-header">
468
+ <Icon icon="heroicons:arrow-top-right-on-square" />
469
+ <span>External Configuration</span>
470
+ </div>
471
+ <div class="config-form__admin-edit-content">
472
+ <p class="config-form__admin-edit-description">
473
+ {configEditOptions.externalEditLink.description ??
474
+ 'This node requires external configuration. Click the button below to open the configuration panel.'}
475
+ </p>
476
+ <button
477
+ type="button"
478
+ class="config-form__button config-form__button--external"
479
+ onclick={handleExternalEditClick}
480
+ >
481
+ <Icon
482
+ icon={configEditOptions.externalEditLink.icon ?? 'heroicons:arrow-top-right-on-square'}
483
+ />
484
+ <span>{configEditOptions.externalEditLink.label ?? 'Configure Externally'}</span>
485
+ </button>
486
+ </div>
487
+ </div>
488
+ {/if}
489
+
490
+ <!-- Dynamic Schema Loading State -->
491
+ {#if dynamicSchemaLoading}
492
+ <div class="config-form__loading">
493
+ <div class="config-form__loading-spinner"></div>
494
+ <p class="config-form__loading-text">
495
+ {configEditOptions?.loadingMessage ?? 'Loading configuration options...'}
496
+ </p>
497
+ </div>
498
+ {:else if dynamicSchemaError}
499
+ <div class="config-form__error">
500
+ <div class="config-form__error-header">
501
+ <Icon icon="heroicons:exclamation-triangle" />
502
+ <span>Configuration Error</span>
503
+ </div>
504
+ <div class="config-form__error-content">
505
+ <p class="config-form__error-message">{dynamicSchemaError}</p>
506
+ <div class="config-form__error-actions">
507
+ <button
508
+ type="button"
509
+ class="config-form__button config-form__button--secondary"
510
+ onclick={refreshDynamicSchema}
511
+ >
512
+ <Icon icon="heroicons:arrow-path" />
513
+ <span>Retry</span>
514
+ </button>
515
+ {#if configEditOptions?.externalEditLink}
516
+ <button
517
+ type="button"
518
+ class="config-form__button config-form__button--external"
519
+ onclick={handleExternalEditClick}
520
+ >
521
+ <Icon
522
+ icon={configEditOptions.externalEditLink.icon ??
523
+ 'heroicons:arrow-top-right-on-square'}
524
+ />
525
+ <span>{configEditOptions.externalEditLink.label ?? 'Use External Editor'}</span>
526
+ </button>
527
+ {/if}
528
+ </div>
529
+ </div>
530
+ </div>
531
+ {:else if configSchema}
532
+ <form
533
+ class="config-form"
534
+ onfocusout={handleFormBlur}
535
+ onsubmit={(e) => {
536
+ e.preventDefault();
537
+ }}
538
+ >
539
+ <!-- Dynamic Schema Refresh Button -->
540
+ {#if fetchedDynamicSchema && configEditOptions?.showRefreshButton !== false}
541
+ <div class="config-form__schema-actions">
542
+ <button
543
+ type="button"
544
+ class="config-form__schema-refresh"
545
+ onclick={refreshDynamicSchema}
546
+ title="Refresh configuration schema"
547
+ >
548
+ <Icon icon="heroicons:arrow-path" />
549
+ <span>Refresh Schema</span>
550
+ </button>
551
+ {#if configEditOptions?.externalEditLink}
552
+ <button
553
+ type="button"
554
+ class="config-form__schema-external"
555
+ onclick={handleExternalEditClick}
556
+ title={configEditOptions.externalEditLink.description ?? 'Open external editor'}
557
+ >
558
+ <Icon
559
+ icon={configEditOptions.externalEditLink.icon ??
560
+ 'heroicons:arrow-top-right-on-square'}
561
+ />
562
+ <span>{configEditOptions.externalEditLink.label ?? 'External Editor'}</span>
563
+ </button>
564
+ {/if}
565
+ </div>
566
+ {/if}
567
+
568
+ {#if configSchema.properties}
569
+ <div class="config-form__fields">
570
+ {#if configUISchema}
571
+ <FormUISchemaRenderer
572
+ element={configUISchema}
573
+ schema={configSchema}
574
+ values={configValues}
575
+ requiredFields={configSchema.required ?? []}
576
+ onFieldChange={handleFieldChange}
577
+ {toFieldSchema}
578
+ {node}
579
+ nodes={workflowNodes}
580
+ edges={workflowEdges}
581
+ {workflowId}
582
+ {authProvider}
583
+ />
584
+ {:else}
585
+ {#each Object.entries(configSchema.properties) as [key, field], index (key)}
586
+ {@const fieldSchema = toFieldSchema(field as Record<string, unknown>)}
587
+ {@const required = isFieldRequired(key)}
588
+
589
+ <FormField
590
+ fieldKey={key}
591
+ schema={fieldSchema}
592
+ value={configValues[key]}
593
+ {required}
594
+ animationIndex={index}
595
+ {node}
596
+ nodes={workflowNodes}
597
+ edges={workflowEdges}
598
+ {workflowId}
599
+ {authProvider}
600
+ onChange={(val) => handleFieldChange(key, val)}
601
+ />
602
+ {/each}
603
+ {/if}
604
+ </div>
605
+ {:else}
606
+ <!-- If no properties, show the raw schema for debugging -->
607
+ <div class="config-form__debug">
608
+ <div class="config-form__debug-header">
609
+ <Icon icon="heroicons:bug-ant" class="config-form__debug-icon" />
610
+ <span>Debug - Config Schema</span>
611
+ </div>
612
+ <pre class="config-form__debug-content">{JSON.stringify(configSchema, null, 2)}</pre>
613
+ </div>
614
+ {/if}
615
+
616
+ <!-- UI Extensions Section -->
617
+ {#if showUIExtensions && node}
618
+ <div class="config-form__extensions">
619
+ <div class="config-form__extensions-header">
620
+ <Icon icon="heroicons:adjustments-horizontal" class="config-form__extensions-icon" />
621
+ <span>Display Settings</span>
622
+ </div>
623
+ <div class="config-form__extensions-content">
624
+ <!-- Hide Unconnected Handles Toggle -->
625
+ <FormFieldWrapper
626
+ id="ext-hideUnconnectedHandles"
627
+ label="Hide Unconnected Ports"
628
+ description="Hide input and output ports that are not connected to reduce visual clutter"
629
+ >
630
+ <FormToggle
631
+ id="ext-hideUnconnectedHandles"
632
+ value={Boolean(uiExtensionValues.hideUnconnectedHandles)}
633
+ onLabel="Hidden"
634
+ offLabel="Visible"
635
+ ariaDescribedBy="ext-hideUnconnectedHandles-description"
636
+ onChange={(val) => {
637
+ uiExtensionValues.hideUnconnectedHandles = val;
638
+ handleFormBlur();
639
+ }}
640
+ />
641
+ </FormFieldWrapper>
642
+ </div>
643
+ </div>
644
+ {/if}
645
+
646
+ <!-- Footer Actions - Only shown when onSave is provided and onChange is not -->
647
+ <!-- With onChange (on-blur sync), changes are saved automatically, so no Save button needed -->
648
+ {#if onSave && !onChange}
649
+ <div class="config-form__footer">
650
+ <button
651
+ type="button"
652
+ class="config-form__button config-form__button--secondary"
653
+ onclick={onCancel}
654
+ disabled={isSavingWorkflow}
655
+ >
656
+ <Icon icon="heroicons:x-mark" class="config-form__button-icon" />
657
+ <span>Cancel</span>
658
+ </button>
659
+ <button
660
+ type="submit"
661
+ class="config-form__button config-form__button--primary"
662
+ onclick={handleSave}
663
+ disabled={isSavingWorkflow}
664
+ >
665
+ {#if isSavingWorkflow}
666
+ <span class="config-form__button-spinner"></span>
667
+ <span>Saving...</span>
668
+ {:else}
669
+ <Icon icon="heroicons:check" class="config-form__button-icon" />
670
+ <span>Save Changes</span>
671
+ {/if}
672
+ </button>
673
+ </div>
674
+ {/if}
675
+ </form>
676
+ {:else if !dynamicSchemaLoading && !showExternalEditLink}
677
+ <div class="config-form__empty">
678
+ <div class="config-form__empty-icon">
679
+ <Icon icon="heroicons:cog-6-tooth" />
680
+ </div>
681
+ <p class="config-form__empty-text">No configuration options available for this node.</p>
682
+ {#if configEditOptions?.externalEditLink}
683
+ <button
684
+ type="button"
685
+ class="config-form__button config-form__button--external config-form__empty-button"
686
+ onclick={handleExternalEditClick}
687
+ >
688
+ <Icon
689
+ icon={configEditOptions.externalEditLink.icon ?? 'heroicons:arrow-top-right-on-square'}
690
+ />
691
+ <span>{configEditOptions.externalEditLink.label ?? 'Configure Externally'}</span>
692
+ </button>
693
+ {/if}
694
+ </div>
695
+ {/if}
696
+
697
+ <style>
698
+ /* ============================================
699
+ CONFIG FORM - Container Styles
700
+ Individual field styles are in form/ components
701
+ ============================================ */
702
+
703
+ .config-form {
704
+ display: flex;
705
+ flex-direction: column;
706
+ gap: var(--fd-space-3xl);
707
+ }
708
+
709
+ .config-form__fields {
710
+ display: flex;
711
+ flex-direction: column;
712
+ gap: var(--fd-space-2xl);
713
+ }
714
+
715
+ /* ============================================
716
+ FOOTER ACTIONS
717
+ Only shown when onSave is provided (legacy mode without onChange)
718
+ ============================================ */
719
+
720
+ .config-form__footer {
721
+ display: flex;
722
+ gap: var(--fd-space-md);
723
+ justify-content: flex-end;
724
+ padding-top: var(--fd-space-xl);
725
+ border-top: 1px solid var(--fd-border-muted);
726
+ margin-top: var(--fd-space-xs);
727
+ }
728
+
729
+ /* Button Spinner */
730
+ .config-form__button-spinner {
731
+ width: 1rem;
732
+ height: 1rem;
733
+ border: 2px solid rgba(255, 255, 255, 0.3);
734
+ border-top-color: #ffffff;
735
+ border-radius: 50%;
736
+ animation: config-form-spin 0.6s linear infinite;
737
+ }
738
+
739
+ /* ============================================
740
+ SHARED BUTTON STYLES
741
+ Used by error actions, external config buttons, and footer
742
+ ============================================ */
743
+
744
+ .config-form__button {
745
+ display: inline-flex;
746
+ align-items: center;
747
+ justify-content: center;
748
+ gap: var(--fd-space-xs);
749
+ padding: 0.625rem var(--fd-space-xl);
750
+ border-radius: var(--fd-radius-lg);
751
+ font-size: var(--fd-text-sm);
752
+ font-weight: 600;
753
+ font-family: inherit;
754
+ cursor: pointer;
755
+ transition: all var(--fd-transition-normal);
756
+ border: 1px solid transparent;
757
+ min-height: 2.5rem;
758
+ }
759
+
760
+ .config-form__button :global(svg) {
761
+ width: 1rem;
762
+ height: 1rem;
763
+ flex-shrink: 0;
764
+ }
765
+
766
+ .config-form__button--secondary {
767
+ background-color: var(--fd-background);
768
+ border-color: var(--fd-border);
769
+ color: var(--fd-foreground);
770
+ box-shadow: var(--fd-shadow-sm);
771
+ }
772
+
773
+ .config-form__button--secondary:hover {
774
+ background-color: var(--fd-muted);
775
+ border-color: var(--fd-border-strong);
776
+ color: var(--fd-foreground);
777
+ }
778
+
779
+ .config-form__button--secondary:focus-visible {
780
+ outline: none;
781
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
782
+ }
783
+
784
+ .config-form__button--primary {
785
+ background: linear-gradient(135deg, var(--fd-primary) 0%, var(--fd-primary-hover) 100%);
786
+ color: var(--fd-primary-foreground);
787
+ box-shadow:
788
+ 0 1px 3px rgba(59, 130, 246, 0.3),
789
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
790
+ }
791
+
792
+ .config-form__button--primary:hover {
793
+ background: linear-gradient(135deg, var(--fd-primary-hover) 0%, var(--fd-primary-hover) 100%);
794
+ box-shadow:
795
+ 0 4px 12px rgba(59, 130, 246, 0.35),
796
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
797
+ transform: translateY(-1px);
798
+ }
799
+
800
+ .config-form__button--primary:active {
801
+ transform: translateY(0);
802
+ }
803
+
804
+ .config-form__button--primary:focus-visible {
805
+ outline: none;
806
+ box-shadow:
807
+ 0 0 0 3px rgba(59, 130, 246, 0.4),
808
+ 0 4px 12px rgba(59, 130, 246, 0.35);
809
+ }
810
+
811
+ /* ============================================
812
+ UI EXTENSIONS SECTION
813
+ ============================================ */
814
+
815
+ .config-form__extensions {
816
+ background-color: var(--fd-muted);
817
+ border: 1px solid var(--fd-border);
818
+ border-radius: var(--fd-radius-lg);
819
+ overflow: hidden;
820
+ margin-top: var(--fd-space-xs);
821
+ }
822
+
823
+ .config-form__extensions-header {
824
+ display: flex;
825
+ align-items: center;
826
+ gap: var(--fd-space-xs);
827
+ padding: var(--fd-space-md) var(--fd-space-xl);
828
+ background-color: var(--fd-subtle);
829
+ border-bottom: 1px solid var(--fd-border);
830
+ font-size: 0.8125rem;
831
+ font-weight: 600;
832
+ color: var(--fd-foreground);
833
+ }
834
+
835
+ .config-form__extensions-header :global(svg) {
836
+ width: 1rem;
837
+ height: 1rem;
838
+ color: var(--fd-muted-foreground);
839
+ }
840
+
841
+ .config-form__extensions-content {
842
+ padding: var(--fd-space-xl);
843
+ display: flex;
844
+ flex-direction: column;
845
+ gap: var(--fd-space-xl);
846
+ }
847
+
848
+ /* ============================================
849
+ DEBUG SECTION
850
+ ============================================ */
851
+
852
+ .config-form__debug {
853
+ background-color: var(--fd-warning-muted);
854
+ border: 1px solid var(--fd-warning);
855
+ border-radius: var(--fd-radius-lg);
856
+ overflow: hidden;
857
+ }
858
+
859
+ .config-form__debug-header {
860
+ display: flex;
861
+ align-items: center;
862
+ gap: var(--fd-space-xs);
863
+ padding: var(--fd-space-md) var(--fd-space-xl);
864
+ background-color: var(--fd-warning-muted);
865
+ border-bottom: 1px solid var(--fd-warning);
866
+ font-size: 0.8125rem;
867
+ font-weight: 600;
868
+ color: var(--fd-warning-hover);
869
+ }
870
+
871
+ .config-form__debug-header :global(svg) {
872
+ width: 1rem;
873
+ height: 1rem;
874
+ }
875
+
876
+ .config-form__debug-content {
877
+ margin: 0;
878
+ padding: var(--fd-space-xl);
879
+ font-size: var(--fd-text-xs);
880
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
881
+ color: var(--fd-foreground);
882
+ overflow-x: auto;
883
+ background-color: var(--fd-background);
884
+ line-height: 1.5;
885
+ }
886
+
887
+ /* ============================================
888
+ EMPTY STATE
889
+ ============================================ */
890
+
891
+ .config-form__empty {
892
+ display: flex;
893
+ flex-direction: column;
894
+ align-items: center;
895
+ justify-content: center;
896
+ padding: var(--fd-space-6xl) var(--fd-space-3xl);
897
+ text-align: center;
898
+ }
899
+
900
+ .config-form__empty-icon {
901
+ width: 3rem;
902
+ height: 3rem;
903
+ margin-bottom: var(--fd-space-xl);
904
+ color: var(--fd-border);
905
+ }
906
+
907
+ .config-form__empty-icon :global(svg) {
908
+ width: 100%;
909
+ height: 100%;
910
+ }
911
+
912
+ .config-form__empty-text {
913
+ margin: 0;
914
+ font-size: var(--fd-text-sm);
915
+ color: var(--fd-muted-foreground);
916
+ font-style: italic;
917
+ line-height: 1.5;
918
+ }
919
+
920
+ .config-form__empty-button {
921
+ margin-top: var(--fd-space-xl);
922
+ }
923
+
924
+ /* ============================================
925
+ ADMIN/EDIT SECTION - External Configuration
926
+ ============================================ */
927
+
928
+ .config-form__admin-edit {
929
+ background: linear-gradient(135deg, var(--fd-info-muted) 0%, var(--fd-primary-muted) 100%);
930
+ border: 1px solid var(--fd-primary);
931
+ border-radius: 0.625rem;
932
+ overflow: hidden;
933
+ margin-bottom: var(--fd-space-xl);
934
+ }
935
+
936
+ .config-form__admin-edit-header {
937
+ display: flex;
938
+ align-items: center;
939
+ gap: var(--fd-space-xs);
940
+ padding: var(--fd-space-md) var(--fd-space-xl);
941
+ background: linear-gradient(135deg, var(--fd-primary-muted) 0%, var(--fd-primary-muted) 100%);
942
+ border-bottom: 1px solid var(--fd-primary);
943
+ font-size: 0.8125rem;
944
+ font-weight: 600;
945
+ color: var(--fd-primary-hover);
946
+ }
947
+
948
+ .config-form__admin-edit-header :global(svg) {
949
+ width: 1rem;
950
+ height: 1rem;
951
+ color: var(--fd-primary);
952
+ }
953
+
954
+ .config-form__admin-edit-content {
955
+ padding: var(--fd-space-xl);
956
+ display: flex;
957
+ flex-direction: column;
958
+ gap: var(--fd-space-md);
959
+ }
960
+
961
+ .config-form__admin-edit-description {
962
+ margin: 0;
963
+ font-size: 0.8125rem;
964
+ color: var(--fd-primary-hover);
965
+ line-height: 1.5;
966
+ }
967
+
968
+ /* ============================================
969
+ LOADING STATE
970
+ ============================================ */
971
+
972
+ .config-form__loading {
973
+ display: flex;
974
+ flex-direction: column;
975
+ align-items: center;
976
+ justify-content: center;
977
+ padding: var(--fd-space-6xl) var(--fd-space-3xl);
978
+ gap: var(--fd-space-xl);
979
+ }
980
+
981
+ .config-form__loading-spinner {
982
+ width: 2.5rem;
983
+ height: 2.5rem;
984
+ border: 3px solid var(--fd-primary-muted);
985
+ border-top-color: var(--fd-primary);
986
+ border-radius: 50%;
987
+ animation: config-form-spin 0.8s linear infinite;
988
+ }
989
+
990
+ @keyframes config-form-spin {
991
+ to {
992
+ transform: rotate(360deg);
993
+ }
994
+ }
995
+
996
+ .config-form__loading-text {
997
+ margin: 0;
998
+ font-size: var(--fd-text-sm);
999
+ color: var(--fd-muted-foreground);
1000
+ }
1001
+
1002
+ /* ============================================
1003
+ ERROR STATE
1004
+ ============================================ */
1005
+
1006
+ .config-form__error {
1007
+ background-color: var(--fd-error-muted);
1008
+ border: 1px solid var(--fd-error);
1009
+ border-radius: var(--fd-radius-lg);
1010
+ overflow: hidden;
1011
+ }
1012
+
1013
+ .config-form__error-header {
1014
+ display: flex;
1015
+ align-items: center;
1016
+ gap: var(--fd-space-xs);
1017
+ padding: var(--fd-space-md) var(--fd-space-xl);
1018
+ background-color: var(--fd-error-muted);
1019
+ border-bottom: 1px solid var(--fd-error);
1020
+ font-size: 0.8125rem;
1021
+ font-weight: 600;
1022
+ color: var(--fd-error-hover);
1023
+ }
1024
+
1025
+ .config-form__error-header :global(svg) {
1026
+ width: 1rem;
1027
+ height: 1rem;
1028
+ color: var(--fd-error);
1029
+ }
1030
+
1031
+ .config-form__error-content {
1032
+ padding: var(--fd-space-xl);
1033
+ display: flex;
1034
+ flex-direction: column;
1035
+ gap: var(--fd-space-md);
1036
+ }
1037
+
1038
+ .config-form__error-message {
1039
+ margin: 0;
1040
+ font-size: 0.8125rem;
1041
+ color: var(--fd-error);
1042
+ line-height: 1.5;
1043
+ }
1044
+
1045
+ .config-form__error-actions {
1046
+ display: flex;
1047
+ gap: var(--fd-space-xs);
1048
+ flex-wrap: wrap;
1049
+ }
1050
+
1051
+ /* ============================================
1052
+ SCHEMA ACTIONS (Refresh, External Editor)
1053
+ ============================================ */
1054
+
1055
+ .config-form__schema-actions {
1056
+ display: flex;
1057
+ gap: var(--fd-space-xs);
1058
+ margin-bottom: var(--fd-space-xl);
1059
+ padding-bottom: var(--fd-space-md);
1060
+ border-bottom: 1px solid var(--fd-border-muted);
1061
+ }
1062
+
1063
+ .config-form__schema-refresh,
1064
+ .config-form__schema-external {
1065
+ display: inline-flex;
1066
+ align-items: center;
1067
+ gap: var(--fd-space-3xs);
1068
+ padding: var(--fd-space-3xs) var(--fd-space-xs);
1069
+ font-size: var(--fd-text-xs);
1070
+ font-weight: 500;
1071
+ font-family: inherit;
1072
+ border-radius: var(--fd-radius-md);
1073
+ cursor: pointer;
1074
+ transition: all var(--fd-transition-fast);
1075
+ border: 1px solid transparent;
1076
+ }
1077
+
1078
+ .config-form__schema-refresh {
1079
+ background-color: var(--fd-muted);
1080
+ border-color: var(--fd-border);
1081
+ color: var(--fd-muted-foreground);
1082
+ }
1083
+
1084
+ .config-form__schema-refresh:hover {
1085
+ background-color: var(--fd-subtle);
1086
+ border-color: var(--fd-border-strong);
1087
+ color: var(--fd-foreground);
1088
+ }
1089
+
1090
+ .config-form__schema-refresh :global(svg),
1091
+ .config-form__schema-external :global(svg) {
1092
+ width: 0.875rem;
1093
+ height: 0.875rem;
1094
+ }
1095
+
1096
+ .config-form__schema-external {
1097
+ background-color: var(--fd-primary-muted);
1098
+ border-color: var(--fd-primary);
1099
+ color: var(--fd-primary-hover);
1100
+ }
1101
+
1102
+ .config-form__schema-external:hover {
1103
+ background-color: var(--fd-primary-muted);
1104
+ border-color: var(--fd-primary-hover);
1105
+ color: var(--fd-primary-hover);
1106
+ }
1107
+
1108
+ /* ============================================
1109
+ EXTERNAL BUTTON STYLE
1110
+ ============================================ */
1111
+
1112
+ .config-form__button--external {
1113
+ background: linear-gradient(135deg, var(--fd-accent) 0%, var(--fd-primary) 100%);
1114
+ color: var(--fd-accent-foreground);
1115
+ box-shadow:
1116
+ 0 1px 3px rgba(99, 102, 241, 0.3),
1117
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
1118
+ }
1119
+
1120
+ .config-form__button--external:hover {
1121
+ background: linear-gradient(135deg, var(--fd-accent-hover) 0%, var(--fd-primary-hover) 100%);
1122
+ box-shadow:
1123
+ 0 4px 12px rgba(99, 102, 241, 0.35),
1124
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
1125
+ transform: translateY(-1px);
1126
+ }
1127
+
1128
+ .config-form__button--external:active {
1129
+ transform: translateY(0);
1130
+ }
1131
+
1132
+ .config-form__button--external:focus-visible {
1133
+ outline: none;
1134
+ box-shadow:
1135
+ 0 0 0 3px rgba(99, 102, 241, 0.4),
1136
+ 0 4px 12px rgba(99, 102, 241, 0.35);
1137
+ }
1138
+ </style>