@foresthubai/workflow-builder 0.3.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 (496) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +16 -0
  3. package/README.md +93 -0
  4. package/dist/BuilderLayout.d.ts +34 -0
  5. package/dist/BuilderLayout.d.ts.map +1 -0
  6. package/dist/BuilderLayout.js +172 -0
  7. package/dist/BuilderLayout.js.map +1 -0
  8. package/dist/Canvas.d.ts +23 -0
  9. package/dist/Canvas.d.ts.map +1 -0
  10. package/dist/Canvas.js +141 -0
  11. package/dist/Canvas.js.map +1 -0
  12. package/dist/CanvasEditor.d.ts +46 -0
  13. package/dist/CanvasEditor.d.ts.map +1 -0
  14. package/dist/CanvasEditor.js +57 -0
  15. package/dist/CanvasEditor.js.map +1 -0
  16. package/dist/CanvasTabsToolbar.d.ts +11 -0
  17. package/dist/CanvasTabsToolbar.d.ts.map +1 -0
  18. package/dist/CanvasTabsToolbar.js +101 -0
  19. package/dist/CanvasTabsToolbar.js.map +1 -0
  20. package/dist/RightConfigPanel.d.ts +27 -0
  21. package/dist/RightConfigPanel.d.ts.map +1 -0
  22. package/dist/RightConfigPanel.js +102 -0
  23. package/dist/RightConfigPanel.js.map +1 -0
  24. package/dist/WorkflowBuilder.d.ts +62 -0
  25. package/dist/WorkflowBuilder.d.ts.map +1 -0
  26. package/dist/WorkflowBuilder.js +275 -0
  27. package/dist/WorkflowBuilder.js.map +1 -0
  28. package/dist/cn.d.ts +3 -0
  29. package/dist/cn.d.ts.map +1 -0
  30. package/dist/cn.js +6 -0
  31. package/dist/cn.js.map +1 -0
  32. package/dist/components/ui/add-button.d.ts +16 -0
  33. package/dist/components/ui/add-button.d.ts.map +1 -0
  34. package/dist/components/ui/add-button.js +21 -0
  35. package/dist/components/ui/add-button.js.map +1 -0
  36. package/dist/components/ui/alert-dialog.d.ts +21 -0
  37. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  38. package/dist/components/ui/alert-dialog.js +30 -0
  39. package/dist/components/ui/alert-dialog.js.map +1 -0
  40. package/dist/components/ui/alert.d.ts +9 -0
  41. package/dist/components/ui/alert.d.ts.map +1 -0
  42. package/dist/components/ui/alert.js +23 -0
  43. package/dist/components/ui/alert.js.map +1 -0
  44. package/dist/components/ui/badge.d.ts +10 -0
  45. package/dist/components/ui/badge.d.ts.map +1 -0
  46. package/dist/components/ui/badge.js +21 -0
  47. package/dist/components/ui/badge.js.map +1 -0
  48. package/dist/components/ui/button.d.ts +13 -0
  49. package/dist/components/ui/button.d.ts.map +1 -0
  50. package/dist/components/ui/button.js +40 -0
  51. package/dist/components/ui/button.js.map +1 -0
  52. package/dist/components/ui/card.d.ts +9 -0
  53. package/dist/components/ui/card.d.ts.map +1 -0
  54. package/dist/components/ui/card.js +17 -0
  55. package/dist/components/ui/card.js.map +1 -0
  56. package/dist/components/ui/checkbox.d.ts +5 -0
  57. package/dist/components/ui/checkbox.d.ts.map +1 -0
  58. package/dist/components/ui/checkbox.js +9 -0
  59. package/dist/components/ui/checkbox.js.map +1 -0
  60. package/dist/components/ui/collapsible.d.ts +6 -0
  61. package/dist/components/ui/collapsible.d.ts.map +1 -0
  62. package/dist/components/ui/collapsible.js +6 -0
  63. package/dist/components/ui/collapsible.js.map +1 -0
  64. package/dist/components/ui/command.d.ts +82 -0
  65. package/dist/components/ui/command.d.ts.map +1 -0
  66. package/dist/components/ui/command.js +29 -0
  67. package/dist/components/ui/command.js.map +1 -0
  68. package/dist/components/ui/delete-button.d.ts +11 -0
  69. package/dist/components/ui/delete-button.d.ts.map +1 -0
  70. package/dist/components/ui/delete-button.js +14 -0
  71. package/dist/components/ui/delete-button.js.map +1 -0
  72. package/dist/components/ui/dialog.d.ts +22 -0
  73. package/dist/components/ui/dialog.d.ts.map +1 -0
  74. package/dist/components/ui/dialog.js +27 -0
  75. package/dist/components/ui/dialog.js.map +1 -0
  76. package/dist/components/ui/dropdown-menu.d.ts +28 -0
  77. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  78. package/dist/components/ui/dropdown-menu.js +36 -0
  79. package/dist/components/ui/dropdown-menu.js.map +1 -0
  80. package/dist/components/ui/input.d.ts +13 -0
  81. package/dist/components/ui/input.d.ts.map +1 -0
  82. package/dist/components/ui/input.js +34 -0
  83. package/dist/components/ui/input.js.map +1 -0
  84. package/dist/components/ui/label.d.ts +6 -0
  85. package/dist/components/ui/label.d.ts.map +1 -0
  86. package/dist/components/ui/label.js +10 -0
  87. package/dist/components/ui/label.js.map +1 -0
  88. package/dist/components/ui/readonly-banner.d.ts +7 -0
  89. package/dist/components/ui/readonly-banner.d.ts.map +1 -0
  90. package/dist/components/ui/readonly-banner.js +12 -0
  91. package/dist/components/ui/readonly-banner.js.map +1 -0
  92. package/dist/components/ui/resizable.d.ts +24 -0
  93. package/dist/components/ui/resizable.d.ts.map +1 -0
  94. package/dist/components/ui/resizable.js +9 -0
  95. package/dist/components/ui/resizable.js.map +1 -0
  96. package/dist/components/ui/scroll-area.d.ts +45 -0
  97. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  98. package/dist/components/ui/scroll-area.js +27 -0
  99. package/dist/components/ui/scroll-area.js.map +1 -0
  100. package/dist/components/ui/select.d.ts +14 -0
  101. package/dist/components/ui/select.d.ts.map +1 -0
  102. package/dist/components/ui/select.js +30 -0
  103. package/dist/components/ui/select.js.map +1 -0
  104. package/dist/components/ui/separator.d.ts +5 -0
  105. package/dist/components/ui/separator.d.ts.map +1 -0
  106. package/dist/components/ui/separator.js +8 -0
  107. package/dist/components/ui/separator.js.map +1 -0
  108. package/dist/components/ui/switch.d.ts +5 -0
  109. package/dist/components/ui/switch.d.ts.map +1 -0
  110. package/dist/components/ui/switch.js +8 -0
  111. package/dist/components/ui/switch.js.map +1 -0
  112. package/dist/components/ui/textarea.d.ts +12 -0
  113. package/dist/components/ui/textarea.d.ts.map +1 -0
  114. package/dist/components/ui/textarea.js +34 -0
  115. package/dist/components/ui/textarea.js.map +1 -0
  116. package/dist/components/ui/toast.d.ts +16 -0
  117. package/dist/components/ui/toast.d.ts.map +1 -0
  118. package/dist/components/ui/toast.js +34 -0
  119. package/dist/components/ui/toast.js.map +1 -0
  120. package/dist/components/ui/toaster.d.ts +2 -0
  121. package/dist/components/ui/toaster.d.ts.map +1 -0
  122. package/dist/components/ui/toaster.js +10 -0
  123. package/dist/components/ui/toaster.js.map +1 -0
  124. package/dist/components/ui/toggle-group.d.ts +13 -0
  125. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  126. package/dist/components/ui/toggle-group.js +21 -0
  127. package/dist/components/ui/toggle-group.js.map +1 -0
  128. package/dist/components/ui/toggle.d.ts +13 -0
  129. package/dist/components/ui/toggle.d.ts.map +1 -0
  130. package/dist/components/ui/toggle.js +26 -0
  131. package/dist/components/ui/toggle.js.map +1 -0
  132. package/dist/components/ui/tooltip.d.ts +8 -0
  133. package/dist/components/ui/tooltip.d.ts.map +1 -0
  134. package/dist/components/ui/tooltip.js +14 -0
  135. package/dist/components/ui/tooltip.js.map +1 -0
  136. package/dist/dialogs/NodePickerDialog.d.ts +10 -0
  137. package/dist/dialogs/NodePickerDialog.d.ts.map +1 -0
  138. package/dist/dialogs/NodePickerDialog.js +39 -0
  139. package/dist/dialogs/NodePickerDialog.js.map +1 -0
  140. package/dist/dialogs/ValidationDialog.d.ts +17 -0
  141. package/dist/dialogs/ValidationDialog.d.ts.map +1 -0
  142. package/dist/dialogs/ValidationDialog.js +29 -0
  143. package/dist/dialogs/ValidationDialog.js.map +1 -0
  144. package/dist/graph/BaseNode.d.ts +9 -0
  145. package/dist/graph/BaseNode.d.ts.map +1 -0
  146. package/dist/graph/BaseNode.js +318 -0
  147. package/dist/graph/BaseNode.js.map +1 -0
  148. package/dist/graph/CustomEdge.d.ts +14 -0
  149. package/dist/graph/CustomEdge.d.ts.map +1 -0
  150. package/dist/graph/CustomEdge.js +107 -0
  151. package/dist/graph/CustomEdge.js.map +1 -0
  152. package/dist/graph/CustomNode.d.ts +3 -0
  153. package/dist/graph/CustomNode.d.ts.map +1 -0
  154. package/dist/graph/CustomNode.js +15 -0
  155. package/dist/graph/CustomNode.js.map +1 -0
  156. package/dist/graph/FunctionCallNode.d.ts +3 -0
  157. package/dist/graph/FunctionCallNode.d.ts.map +1 -0
  158. package/dist/graph/FunctionCallNode.js +25 -0
  159. package/dist/graph/FunctionCallNode.js.map +1 -0
  160. package/dist/graph/PortHandle.d.ts +21 -0
  161. package/dist/graph/PortHandle.d.ts.map +1 -0
  162. package/dist/graph/PortHandle.js +113 -0
  163. package/dist/graph/PortHandle.js.map +1 -0
  164. package/dist/graph/reactFlowRegistry.d.ts +65 -0
  165. package/dist/graph/reactFlowRegistry.d.ts.map +1 -0
  166. package/dist/graph/reactFlowRegistry.js +24 -0
  167. package/dist/graph/reactFlowRegistry.js.map +1 -0
  168. package/dist/hooks/use-toast.d.ts +47 -0
  169. package/dist/hooks/use-toast.d.ts.map +1 -0
  170. package/dist/hooks/use-toast.js +95 -0
  171. package/dist/hooks/use-toast.js.map +1 -0
  172. package/dist/hooks/useAvailableVariables.d.ts +12 -0
  173. package/dist/hooks/useAvailableVariables.d.ts.map +1 -0
  174. package/dist/hooks/useAvailableVariables.js +16 -0
  175. package/dist/hooks/useAvailableVariables.js.map +1 -0
  176. package/dist/hooks/useCanvasHistory.d.ts +14 -0
  177. package/dist/hooks/useCanvasHistory.d.ts.map +1 -0
  178. package/dist/hooks/useCanvasHistory.js +20 -0
  179. package/dist/hooks/useCanvasHistory.js.map +1 -0
  180. package/dist/hooks/useCanvasTabs.d.ts +23 -0
  181. package/dist/hooks/useCanvasTabs.d.ts.map +1 -0
  182. package/dist/hooks/useCanvasTabs.js +136 -0
  183. package/dist/hooks/useCanvasTabs.js.map +1 -0
  184. package/dist/hooks/useFunctionDiagnosticsSync.d.ts +14 -0
  185. package/dist/hooks/useFunctionDiagnosticsSync.d.ts.map +1 -0
  186. package/dist/hooks/useFunctionDiagnosticsSync.js +38 -0
  187. package/dist/hooks/useFunctionDiagnosticsSync.js.map +1 -0
  188. package/dist/hooks/useFunctionRegistry.d.ts +15 -0
  189. package/dist/hooks/useFunctionRegistry.d.ts.map +1 -0
  190. package/dist/hooks/useFunctionRegistry.js +22 -0
  191. package/dist/hooks/useFunctionRegistry.js.map +1 -0
  192. package/dist/hooks/useFunctions.d.ts +15 -0
  193. package/dist/hooks/useFunctions.d.ts.map +1 -0
  194. package/dist/hooks/useFunctions.js +34 -0
  195. package/dist/hooks/useFunctions.js.map +1 -0
  196. package/dist/hooks/useGraph.d.ts +40 -0
  197. package/dist/hooks/useGraph.d.ts.map +1 -0
  198. package/dist/hooks/useGraph.js +102 -0
  199. package/dist/hooks/useGraph.js.map +1 -0
  200. package/dist/hooks/useNodeDefinitions.d.ts +17 -0
  201. package/dist/hooks/useNodeDefinitions.d.ts.map +1 -0
  202. package/dist/hooks/useNodeDefinitions.js +65 -0
  203. package/dist/hooks/useNodeDefinitions.js.map +1 -0
  204. package/dist/hooks/useParamErrors.d.ts +12 -0
  205. package/dist/hooks/useParamErrors.d.ts.map +1 -0
  206. package/dist/hooks/useParamErrors.js +28 -0
  207. package/dist/hooks/useParamErrors.js.map +1 -0
  208. package/dist/hooks/useResolvedTheme.d.ts +10 -0
  209. package/dist/hooks/useResolvedTheme.d.ts.map +1 -0
  210. package/dist/hooks/useResolvedTheme.js +29 -0
  211. package/dist/hooks/useResolvedTheme.js.map +1 -0
  212. package/dist/hooks/useResourceDiagnosticsSync.d.ts +40 -0
  213. package/dist/hooks/useResourceDiagnosticsSync.d.ts.map +1 -0
  214. package/dist/hooks/useResourceDiagnosticsSync.js +39 -0
  215. package/dist/hooks/useResourceDiagnosticsSync.js.map +1 -0
  216. package/dist/hooks/useSuppressThemeTransition.d.ts +32 -0
  217. package/dist/hooks/useSuppressThemeTransition.d.ts.map +1 -0
  218. package/dist/hooks/useSuppressThemeTransition.js +75 -0
  219. package/dist/hooks/useSuppressThemeTransition.js.map +1 -0
  220. package/dist/hooks/useWorkflowSerialization.d.ts +24 -0
  221. package/dist/hooks/useWorkflowSerialization.d.ts.map +1 -0
  222. package/dist/hooks/useWorkflowSerialization.js +113 -0
  223. package/dist/hooks/useWorkflowSerialization.js.map +1 -0
  224. package/dist/i18n/index.d.ts +4 -0
  225. package/dist/i18n/index.d.ts.map +1 -0
  226. package/dist/i18n/index.js +46 -0
  227. package/dist/i18n/index.js.map +1 -0
  228. package/dist/i18n/locales/de.json +501 -0
  229. package/dist/i18n/locales/en.json +557 -0
  230. package/dist/index.d.ts +9 -0
  231. package/dist/index.d.ts.map +1 -0
  232. package/dist/index.js +12 -0
  233. package/dist/index.js.map +1 -0
  234. package/dist/inputs/ExpressionInput.d.ts +12 -0
  235. package/dist/inputs/ExpressionInput.d.ts.map +1 -0
  236. package/dist/inputs/ExpressionInput.js +203 -0
  237. package/dist/inputs/ExpressionInput.js.map +1 -0
  238. package/dist/inputs/ParameterEditor.d.ts +13 -0
  239. package/dist/inputs/ParameterEditor.d.ts.map +1 -0
  240. package/dist/inputs/ParameterEditor.js +204 -0
  241. package/dist/inputs/ParameterEditor.js.map +1 -0
  242. package/dist/inputs/PortSection.d.ts +31 -0
  243. package/dist/inputs/PortSection.d.ts.map +1 -0
  244. package/dist/inputs/PortSection.js +26 -0
  245. package/dist/inputs/PortSection.js.map +1 -0
  246. package/dist/panels/BuilderSidebar.d.ts +24 -0
  247. package/dist/panels/BuilderSidebar.d.ts.map +1 -0
  248. package/dist/panels/BuilderSidebar.js +202 -0
  249. package/dist/panels/BuilderSidebar.js.map +1 -0
  250. package/dist/panels/ChannelConfigPanel.d.ts +8 -0
  251. package/dist/panels/ChannelConfigPanel.d.ts.map +1 -0
  252. package/dist/panels/ChannelConfigPanel.js +26 -0
  253. package/dist/panels/ChannelConfigPanel.js.map +1 -0
  254. package/dist/panels/ChannelsPanel.d.ts +2 -0
  255. package/dist/panels/ChannelsPanel.d.ts.map +1 -0
  256. package/dist/panels/ChannelsPanel.js +16 -0
  257. package/dist/panels/ChannelsPanel.js.map +1 -0
  258. package/dist/panels/DebugConsolePanel.d.ts +2 -0
  259. package/dist/panels/DebugConsolePanel.d.ts.map +1 -0
  260. package/dist/panels/DebugConsolePanel.js +32 -0
  261. package/dist/panels/DebugConsolePanel.js.map +1 -0
  262. package/dist/panels/DebugContextPanel.d.ts +2 -0
  263. package/dist/panels/DebugContextPanel.d.ts.map +1 -0
  264. package/dist/panels/DebugContextPanel.js +32 -0
  265. package/dist/panels/DebugContextPanel.js.map +1 -0
  266. package/dist/panels/DebugExternalIOPanel.d.ts +9 -0
  267. package/dist/panels/DebugExternalIOPanel.d.ts.map +1 -0
  268. package/dist/panels/DebugExternalIOPanel.js +66 -0
  269. package/dist/panels/DebugExternalIOPanel.js.map +1 -0
  270. package/dist/panels/DiagnosticsPanel.d.ts +8 -0
  271. package/dist/panels/DiagnosticsPanel.d.ts.map +1 -0
  272. package/dist/panels/DiagnosticsPanel.js +86 -0
  273. package/dist/panels/DiagnosticsPanel.js.map +1 -0
  274. package/dist/panels/EdgeConfigPanel.d.ts +14 -0
  275. package/dist/panels/EdgeConfigPanel.d.ts.map +1 -0
  276. package/dist/panels/EdgeConfigPanel.js +34 -0
  277. package/dist/panels/EdgeConfigPanel.js.map +1 -0
  278. package/dist/panels/FunctionConfigPanel.d.ts +16 -0
  279. package/dist/panels/FunctionConfigPanel.d.ts.map +1 -0
  280. package/dist/panels/FunctionConfigPanel.js +62 -0
  281. package/dist/panels/FunctionConfigPanel.js.map +1 -0
  282. package/dist/panels/FunctionListPanel.d.ts +14 -0
  283. package/dist/panels/FunctionListPanel.d.ts.map +1 -0
  284. package/dist/panels/FunctionListPanel.js +25 -0
  285. package/dist/panels/FunctionListPanel.js.map +1 -0
  286. package/dist/panels/MemoryConfigPanel.d.ts +8 -0
  287. package/dist/panels/MemoryConfigPanel.d.ts.map +1 -0
  288. package/dist/panels/MemoryConfigPanel.js +22 -0
  289. package/dist/panels/MemoryConfigPanel.js.map +1 -0
  290. package/dist/panels/MemoryPanel.d.ts +2 -0
  291. package/dist/panels/MemoryPanel.d.ts.map +1 -0
  292. package/dist/panels/MemoryPanel.js +25 -0
  293. package/dist/panels/MemoryPanel.js.map +1 -0
  294. package/dist/panels/ModelConfigPanel.d.ts +8 -0
  295. package/dist/panels/ModelConfigPanel.d.ts.map +1 -0
  296. package/dist/panels/ModelConfigPanel.js +14 -0
  297. package/dist/panels/ModelConfigPanel.js.map +1 -0
  298. package/dist/panels/ModelsPanel.d.ts +8 -0
  299. package/dist/panels/ModelsPanel.d.ts.map +1 -0
  300. package/dist/panels/ModelsPanel.js +24 -0
  301. package/dist/panels/ModelsPanel.js.map +1 -0
  302. package/dist/panels/NodeConfigPanel.d.ts +16 -0
  303. package/dist/panels/NodeConfigPanel.d.ts.map +1 -0
  304. package/dist/panels/NodeConfigPanel.js +248 -0
  305. package/dist/panels/NodeConfigPanel.js.map +1 -0
  306. package/dist/panels/NodeLibrary.d.ts +16 -0
  307. package/dist/panels/NodeLibrary.d.ts.map +1 -0
  308. package/dist/panels/NodeLibrary.js +125 -0
  309. package/dist/panels/NodeLibrary.js.map +1 -0
  310. package/dist/panels/ResourceConfigPanel.d.ts +37 -0
  311. package/dist/panels/ResourceConfigPanel.d.ts.map +1 -0
  312. package/dist/panels/ResourceConfigPanel.js +35 -0
  313. package/dist/panels/ResourceConfigPanel.js.map +1 -0
  314. package/dist/panels/ResourceListPanel.d.ts +35 -0
  315. package/dist/panels/ResourceListPanel.d.ts.map +1 -0
  316. package/dist/panels/ResourceListPanel.js +35 -0
  317. package/dist/panels/ResourceListPanel.js.map +1 -0
  318. package/dist/panels/VariableConfigPanel.d.ts +9 -0
  319. package/dist/panels/VariableConfigPanel.d.ts.map +1 -0
  320. package/dist/panels/VariableConfigPanel.js +50 -0
  321. package/dist/panels/VariableConfigPanel.js.map +1 -0
  322. package/dist/panels/VariablesPanel.d.ts +7 -0
  323. package/dist/panels/VariablesPanel.d.ts.map +1 -0
  324. package/dist/panels/VariablesPanel.js +56 -0
  325. package/dist/panels/VariablesPanel.js.map +1 -0
  326. package/dist/stores/canvasStore.d.ts +41 -0
  327. package/dist/stores/canvasStore.d.ts.map +1 -0
  328. package/dist/stores/canvasStore.js +187 -0
  329. package/dist/stores/canvasStore.js.map +1 -0
  330. package/dist/stores/debugStore.d.ts +42 -0
  331. package/dist/stores/debugStore.d.ts.map +1 -0
  332. package/dist/stores/debugStore.js +22 -0
  333. package/dist/stores/debugStore.js.map +1 -0
  334. package/dist/stores/diagnosticsStore.d.ts +41 -0
  335. package/dist/stores/diagnosticsStore.d.ts.map +1 -0
  336. package/dist/stores/diagnosticsStore.js +67 -0
  337. package/dist/stores/diagnosticsStore.js.map +1 -0
  338. package/dist/stores/editorStore.d.ts +76 -0
  339. package/dist/stores/editorStore.d.ts.map +1 -0
  340. package/dist/stores/editorStore.js +116 -0
  341. package/dist/stores/editorStore.js.map +1 -0
  342. package/dist/utils/categoryConstants.d.ts +4 -0
  343. package/dist/utils/categoryConstants.d.ts.map +1 -0
  344. package/dist/utils/categoryConstants.js +24 -0
  345. package/dist/utils/categoryConstants.js.map +1 -0
  346. package/dist/utils/channelOperations.d.ts +21 -0
  347. package/dist/utils/channelOperations.d.ts.map +1 -0
  348. package/dist/utils/channelOperations.js +84 -0
  349. package/dist/utils/channelOperations.js.map +1 -0
  350. package/dist/utils/connectionRules.d.ts +15 -0
  351. package/dist/utils/connectionRules.d.ts.map +1 -0
  352. package/dist/utils/connectionRules.js +113 -0
  353. package/dist/utils/connectionRules.js.map +1 -0
  354. package/dist/utils/functionOperations.d.ts +27 -0
  355. package/dist/utils/functionOperations.d.ts.map +1 -0
  356. package/dist/utils/functionOperations.js +140 -0
  357. package/dist/utils/functionOperations.js.map +1 -0
  358. package/dist/utils/graphOperations.d.ts +54 -0
  359. package/dist/utils/graphOperations.d.ts.map +1 -0
  360. package/dist/utils/graphOperations.js +461 -0
  361. package/dist/utils/graphOperations.js.map +1 -0
  362. package/dist/utils/history.d.ts +76 -0
  363. package/dist/utils/history.d.ts.map +1 -0
  364. package/dist/utils/history.js +93 -0
  365. package/dist/utils/history.js.map +1 -0
  366. package/dist/utils/memoryOperations.d.ts +14 -0
  367. package/dist/utils/memoryOperations.d.ts.map +1 -0
  368. package/dist/utils/memoryOperations.js +55 -0
  369. package/dist/utils/memoryOperations.js.map +1 -0
  370. package/dist/utils/migrateFunctionNodes.d.ts +9 -0
  371. package/dist/utils/migrateFunctionNodes.d.ts.map +1 -0
  372. package/dist/utils/migrateFunctionNodes.js +89 -0
  373. package/dist/utils/migrateFunctionNodes.js.map +1 -0
  374. package/dist/utils/modelOperations.d.ts +13 -0
  375. package/dist/utils/modelOperations.d.ts.map +1 -0
  376. package/dist/utils/modelOperations.js +53 -0
  377. package/dist/utils/modelOperations.js.map +1 -0
  378. package/dist/utils/paramDisplay.d.ts +12 -0
  379. package/dist/utils/paramDisplay.d.ts.map +1 -0
  380. package/dist/utils/paramDisplay.js +56 -0
  381. package/dist/utils/paramDisplay.js.map +1 -0
  382. package/dist/utils/resourceHelpers.d.ts +17 -0
  383. package/dist/utils/resourceHelpers.d.ts.map +1 -0
  384. package/dist/utils/resourceHelpers.js +32 -0
  385. package/dist/utils/resourceHelpers.js.map +1 -0
  386. package/dist/utils/translation.d.ts +20 -0
  387. package/dist/utils/translation.d.ts.map +1 -0
  388. package/dist/utils/translation.js +23 -0
  389. package/dist/utils/translation.js.map +1 -0
  390. package/dist/utils/variableOperations.d.ts +15 -0
  391. package/dist/utils/variableOperations.d.ts.map +1 -0
  392. package/dist/utils/variableOperations.js +71 -0
  393. package/dist/utils/variableOperations.js.map +1 -0
  394. package/package.json +79 -0
  395. package/src/BuilderLayout.tsx +345 -0
  396. package/src/Canvas.tsx +261 -0
  397. package/src/CanvasEditor.tsx +142 -0
  398. package/src/CanvasTabsToolbar.tsx +176 -0
  399. package/src/RightConfigPanel.tsx +266 -0
  400. package/src/WorkflowBuilder.tsx +412 -0
  401. package/src/cn.ts +6 -0
  402. package/src/components/ui/add-button.tsx +39 -0
  403. package/src/components/ui/alert-dialog.tsx +141 -0
  404. package/src/components/ui/alert.tsx +59 -0
  405. package/src/components/ui/badge.tsx +36 -0
  406. package/src/components/ui/button.tsx +85 -0
  407. package/src/components/ui/card.tsx +79 -0
  408. package/src/components/ui/checkbox.tsx +28 -0
  409. package/src/components/ui/collapsible.tsx +9 -0
  410. package/src/components/ui/command.tsx +153 -0
  411. package/src/components/ui/delete-button.tsx +23 -0
  412. package/src/components/ui/dialog.tsx +125 -0
  413. package/src/components/ui/dropdown-menu.tsx +198 -0
  414. package/src/components/ui/input.tsx +55 -0
  415. package/src/components/ui/label.tsx +24 -0
  416. package/src/components/ui/readonly-banner.tsx +15 -0
  417. package/src/components/ui/resizable.tsx +43 -0
  418. package/src/components/ui/scroll-area.tsx +102 -0
  419. package/src/components/ui/select.tsx +160 -0
  420. package/src/components/ui/separator.tsx +29 -0
  421. package/src/components/ui/switch.tsx +27 -0
  422. package/src/components/ui/textarea.tsx +51 -0
  423. package/src/components/ui/toast.tsx +127 -0
  424. package/src/components/ui/toaster.tsx +33 -0
  425. package/src/components/ui/toggle-group.tsx +59 -0
  426. package/src/components/ui/toggle.tsx +43 -0
  427. package/src/components/ui/tooltip.tsx +32 -0
  428. package/src/dialogs/NodePickerDialog.tsx +84 -0
  429. package/src/dialogs/ValidationDialog.tsx +184 -0
  430. package/src/graph/BaseNode.tsx +557 -0
  431. package/src/graph/CustomEdge.tsx +185 -0
  432. package/src/graph/CustomNode.tsx +16 -0
  433. package/src/graph/FunctionCallNode.tsx +30 -0
  434. package/src/graph/PortHandle.tsx +189 -0
  435. package/src/graph/reactFlowRegistry.ts +26 -0
  436. package/src/hooks/use-toast.ts +125 -0
  437. package/src/hooks/useAvailableVariables.ts +20 -0
  438. package/src/hooks/useCanvasHistory.ts +22 -0
  439. package/src/hooks/useCanvasTabs.ts +168 -0
  440. package/src/hooks/useFunctionDiagnosticsSync.ts +40 -0
  441. package/src/hooks/useFunctionRegistry.ts +26 -0
  442. package/src/hooks/useFunctions.ts +44 -0
  443. package/src/hooks/useGraph.ts +161 -0
  444. package/src/hooks/useNodeDefinitions.ts +82 -0
  445. package/src/hooks/useParamErrors.ts +26 -0
  446. package/src/hooks/useResolvedTheme.ts +30 -0
  447. package/src/hooks/useResourceDiagnosticsSync.ts +58 -0
  448. package/src/hooks/useSuppressThemeTransition.ts +79 -0
  449. package/src/hooks/useWorkflowSerialization.ts +127 -0
  450. package/src/i18n/index.ts +53 -0
  451. package/src/i18n/locales/de.json +501 -0
  452. package/src/i18n/locales/en.json +557 -0
  453. package/src/index.ts +27 -0
  454. package/src/inputs/ExpressionInput.tsx +297 -0
  455. package/src/inputs/ParameterEditor.tsx +515 -0
  456. package/src/inputs/PortSection.tsx +144 -0
  457. package/src/panels/BuilderSidebar.tsx +301 -0
  458. package/src/panels/ChannelConfigPanel.tsx +49 -0
  459. package/src/panels/ChannelsPanel.tsx +28 -0
  460. package/src/panels/DebugConsolePanel.tsx +73 -0
  461. package/src/panels/DebugContextPanel.tsx +77 -0
  462. package/src/panels/DebugExternalIOPanel.tsx +180 -0
  463. package/src/panels/DiagnosticsPanel.tsx +170 -0
  464. package/src/panels/EdgeConfigPanel.tsx +104 -0
  465. package/src/panels/FunctionConfigPanel.tsx +179 -0
  466. package/src/panels/FunctionListPanel.tsx +45 -0
  467. package/src/panels/MemoryConfigPanel.tsx +55 -0
  468. package/src/panels/MemoryPanel.tsx +40 -0
  469. package/src/panels/ModelConfigPanel.tsx +41 -0
  470. package/src/panels/ModelsPanel.tsx +36 -0
  471. package/src/panels/NodeConfigPanel.tsx +630 -0
  472. package/src/panels/NodeLibrary.tsx +288 -0
  473. package/src/panels/ResourceConfigPanel.tsx +132 -0
  474. package/src/panels/ResourceListPanel.tsx +113 -0
  475. package/src/panels/VariableConfigPanel.tsx +161 -0
  476. package/src/panels/VariablesPanel.tsx +145 -0
  477. package/src/stores/canvasStore.test.ts +44 -0
  478. package/src/stores/canvasStore.ts +245 -0
  479. package/src/stores/debugStore.ts +74 -0
  480. package/src/stores/diagnosticsStore.ts +130 -0
  481. package/src/stores/editorStore.ts +202 -0
  482. package/src/styles/index.css +526 -0
  483. package/src/utils/categoryConstants.ts +26 -0
  484. package/src/utils/channelOperations.ts +86 -0
  485. package/src/utils/connectionRules.ts +137 -0
  486. package/src/utils/functionOperations.ts +179 -0
  487. package/src/utils/graphOperations.ts +550 -0
  488. package/src/utils/history.ts +207 -0
  489. package/src/utils/memoryOperations.ts +57 -0
  490. package/src/utils/migrateFunctionNodes.ts +107 -0
  491. package/src/utils/modelOperations.ts +55 -0
  492. package/src/utils/paramDisplay.ts +71 -0
  493. package/src/utils/resourceHelpers.ts +32 -0
  494. package/src/utils/translation.ts +28 -0
  495. package/src/utils/variableOperations.ts +75 -0
  496. package/tailwind-preset.ts +166 -0
@@ -0,0 +1,180 @@
1
+ import { Button } from "../components/ui/button";
2
+ import { Input } from "../components/ui/input";
3
+ import { Label } from "../components/ui/label";
4
+ import { Switch } from "../components/ui/switch";
5
+ import { Loader2, Play } from "lucide-react";
6
+ import { useCallback, useMemo, useState } from "react";
7
+ import { useTranslation } from "react-i18next";
8
+ import { NodeCategory, getInput, type NodeData, type ExternalInput } from "@foresthubai/workflow-core/node";
9
+ import { getOrCreateCanvasStore } from "../stores/canvasStore";
10
+ import { useDebugStore, type DebugSessionPhase } from "../stores/debugStore";
11
+
12
+ interface DebugExternalIOPanelProps {
13
+ canvasId: string;
14
+ onStep: (nodeId?: string) => void;
15
+ getNodeCategory: (node: NodeData) => NodeCategory | undefined;
16
+ }
17
+
18
+ export const DebugExternalIOPanel = ({ canvasId, onStep, getNodeCategory }: DebugExternalIOPanelProps) => {
19
+ const { t } = useTranslation();
20
+ const phase = useDebugStore((s) => s.phase);
21
+
22
+ const cursorNodeId = getCursorNodeId(phase);
23
+ const canvasStore = getOrCreateCanvasStore(canvasId);
24
+ const cursorNode = canvasStore((s) =>
25
+ cursorNodeId ? (s.nodes.find((n) => n.id === cursorNodeId)?.data ?? null) : null,
26
+ );
27
+
28
+ const requirements = useMemo(() => (cursorNode ? getInput(cursorNode as NodeData) : []), [cursorNode]);
29
+
30
+ const isTrigger = cursorNode ? getNodeCategory(cursorNode as NodeData) === NodeCategory.Trigger : false;
31
+ const isStepping = phase.status === "stepping";
32
+ const canStep = phase.status === "paused" || (phase.status === "idle" && cursorNodeId);
33
+
34
+ // Local state for mock values
35
+ const [gpioValues, setGpioValues] = useState<Record<string, number>>({});
36
+ const [serialValues, setSerialValues] = useState<string[]>([""]);
37
+
38
+ const handleStep = useCallback(() => {
39
+ // External-state injection (gpio/serial) is part of the not-yet-implemented
40
+ // debug contract (DebugExternalState). For now we only signal which node to
41
+ // step; the collected input values below are not yet wired to the engine.
42
+ onStep(cursorNodeId ?? undefined);
43
+ }, [cursorNodeId, onStep]);
44
+
45
+ if (!cursorNodeId) {
46
+ return <div className="text-sm text-muted-foreground text-center py-4">{t("debug.selectNode")}</div>;
47
+ }
48
+
49
+ if (isTrigger) {
50
+ return (
51
+ <div className="space-y-3">
52
+ <div className="text-sm text-muted-foreground bg-muted/50 rounded px-3 py-2">
53
+ {t("debug.triggerNotSteppable")}
54
+ </div>
55
+ </div>
56
+ );
57
+ }
58
+
59
+ return (
60
+ <div className="space-y-4">
61
+ {/* Node label */}
62
+ <div className="text-sm font-medium">
63
+ {(cursorNode as NodeData)?.label || (cursorNode as NodeData)?.type}
64
+ </div>
65
+
66
+ {/* Requirements */}
67
+ {requirements.length === 0 ? (
68
+ <div className="text-xs text-muted-foreground">{t("debug.noInputsNeeded")}</div>
69
+ ) : (
70
+ <div className="space-y-3">
71
+ {requirements.map((req, i) => (
72
+ <ExternalInputField
73
+ key={i}
74
+ requirement={req}
75
+ gpioValues={gpioValues}
76
+ setGpioValues={setGpioValues}
77
+ serialValues={serialValues}
78
+ setSerialValues={setSerialValues}
79
+ serialIndex={requirements.slice(0, i).filter((r) => r.kind === "serial").length}
80
+ />
81
+ ))}
82
+ </div>
83
+ )}
84
+
85
+ {/* Step button */}
86
+ <Button className="w-full gap-2" onClick={handleStep} disabled={!canStep || isStepping}>
87
+ {isStepping ? (
88
+ <>
89
+ <Loader2 className="w-4 h-4 animate-spin" />
90
+ {t("debug.stepping")}
91
+ </>
92
+ ) : (
93
+ <>
94
+ <Play className="w-4 h-4" />
95
+ {t("debug.step")}
96
+ </>
97
+ )}
98
+ </Button>
99
+ </div>
100
+ );
101
+ };
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // Sub-components
105
+ // ---------------------------------------------------------------------------
106
+
107
+ function ExternalInputField({
108
+ requirement,
109
+ gpioValues,
110
+ setGpioValues,
111
+ serialValues,
112
+ setSerialValues,
113
+ serialIndex,
114
+ }: {
115
+ requirement: ExternalInput;
116
+ gpioValues: Record<string, number>;
117
+ setGpioValues: React.Dispatch<React.SetStateAction<Record<string, number>>>;
118
+ serialValues: string[];
119
+ setSerialValues: React.Dispatch<React.SetStateAction<string[]>>;
120
+ serialIndex: number;
121
+ }) {
122
+ const { t } = useTranslation();
123
+
124
+ if (requirement.kind === "gpio") {
125
+ const pinKey = String(requirement.pinReference ?? "?");
126
+ const value = gpioValues[pinKey] ?? 0;
127
+
128
+ return (
129
+ <div className="space-y-1">
130
+ <Label className="text-xs font-medium">
131
+ {t("debug.gpioPin", { pin: requirement.pinReference ?? "?" })}
132
+ <span className="text-muted-foreground ml-1">({requirement.dataType})</span>
133
+ </Label>
134
+ {requirement.dataType === "bool" ? (
135
+ <Switch
136
+ checked={!!value}
137
+ onCheckedChange={(checked) => setGpioValues((prev) => ({ ...prev, [pinKey]: checked ? 1 : 0 }))}
138
+ />
139
+ ) : (
140
+ <Input
141
+ type="number"
142
+ value={value}
143
+ onChange={(e) => setGpioValues((prev) => ({ ...prev, [pinKey]: parseInt(e.target.value) || 0 }))}
144
+ className="h-8 font-mono text-sm"
145
+ min={0}
146
+ max={4095}
147
+ />
148
+ )}
149
+ </div>
150
+ );
151
+ }
152
+
153
+ // Serial input
154
+ return (
155
+ <div className="space-y-1">
156
+ <Label className="text-xs font-medium">{t("debug.serialInput")}</Label>
157
+ <Input
158
+ value={serialValues[serialIndex] ?? ""}
159
+ onChange={(e) => {
160
+ setSerialValues((prev) => {
161
+ const next = [...prev];
162
+ next[serialIndex] = e.target.value;
163
+ return next;
164
+ });
165
+ }}
166
+ placeholder={t("debug.serialPlaceholder")}
167
+ className="h-8 font-mono text-sm"
168
+ />
169
+ </div>
170
+ );
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Helpers
175
+ // ---------------------------------------------------------------------------
176
+
177
+ function getCursorNodeId(phase: DebugSessionPhase): string | null {
178
+ if (phase.status === "paused" || phase.status === "stepping") return phase.cursorNodeId;
179
+ return null;
180
+ }
@@ -0,0 +1,170 @@
1
+ import { useState } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Badge } from "../components/ui/badge";
4
+ import { AlertCircle, AlertTriangle, CheckCircle2, ChevronDown } from "lucide-react";
5
+ import { cn } from "../cn";
6
+ import { useDiagnosticsStore } from "../stores/diagnosticsStore";
7
+ import { getOrCreateCanvasStore } from "../stores/canvasStore";
8
+ import { useNodeDefinitions } from "../hooks/useNodeDefinitions";
9
+ import type { Diagnostic } from "@foresthubai/workflow-core/diagnostics";
10
+
11
+ interface DiagnosticsPanelProps {
12
+ canvasId: string;
13
+ onSelectNode: (nodeId: string) => void;
14
+ onSelectEdge: (edgeId: string) => void;
15
+ }
16
+
17
+ interface DiagnosticGroup {
18
+ entityId: string;
19
+ entityType: "node" | "edge";
20
+ label: string;
21
+ diagnostics: Diagnostic[];
22
+ errorCount: number;
23
+ warningCount: number;
24
+ }
25
+
26
+ export const DiagnosticsPanel = ({ canvasId, onSelectNode, onSelectEdge }: DiagnosticsPanelProps) => {
27
+ const { t } = useTranslation();
28
+ const { getNodeDefinition } = useNodeDefinitions();
29
+
30
+ const byNodeId = useDiagnosticsStore((s) => s.byNodeId);
31
+ const byEdgeId = useDiagnosticsStore((s) => s.byEdgeId);
32
+ const useCanvasStore = getOrCreateCanvasStore(canvasId);
33
+ const nodes = useCanvasStore((s) => s.nodes);
34
+ const edges = useCanvasStore((s) => s.edges);
35
+
36
+ // Build groups
37
+ const groups: DiagnosticGroup[] = [];
38
+
39
+ // Node groups
40
+ for (const [nodeId, diags] of Object.entries(byNodeId)) {
41
+ if (diags.length === 0) continue;
42
+ const node = nodes.find((n) => n.id === nodeId);
43
+ const nodeDef = node ? getNodeDefinition(node.data) : undefined;
44
+ const label = (node?.data?.label as string) || nodeDef?.label || nodeId;
45
+ groups.push({
46
+ entityId: nodeId,
47
+ entityType: "node",
48
+ label,
49
+ diagnostics: diags,
50
+ errorCount: diags.filter((d) => d.severity === "error").length,
51
+ warningCount: diags.filter((d) => d.severity === "warning").length,
52
+ });
53
+ }
54
+
55
+ // Edge groups
56
+ for (const [edgeId, diags] of Object.entries(byEdgeId)) {
57
+ if (diags.length === 0) continue;
58
+ const edge = edges.find((e) => e.id === edgeId);
59
+ const sourceNode = edge ? nodes.find((n) => n.id === edge.source) : undefined;
60
+ const targetNode = edge ? nodes.find((n) => n.id === edge.target) : undefined;
61
+ const sourceDef = sourceNode ? getNodeDefinition(sourceNode.data) : undefined;
62
+ const targetDef = targetNode ? getNodeDefinition(targetNode.data) : undefined;
63
+ const sourceLabel = (sourceNode?.data?.label as string) || sourceDef?.label || "?";
64
+ const targetLabel = (targetNode?.data?.label as string) || targetDef?.label || "?";
65
+ const label = `${sourceLabel} → ${targetLabel}`;
66
+ groups.push({
67
+ entityId: edgeId,
68
+ entityType: "edge",
69
+ label,
70
+ diagnostics: diags,
71
+ errorCount: diags.filter((d) => d.severity === "error").length,
72
+ warningCount: diags.filter((d) => d.severity === "warning").length,
73
+ });
74
+ }
75
+
76
+ // IO variable diagnostics are surfaced on the IO sidebar tab itself
77
+ // (red ring on cards + count badge on the tab icon) — not duplicated here.
78
+
79
+ // Sort: errors first, then warnings; within same severity, nodes before edges;
80
+ // within same type, alphabetical by label so the panel order stays stable
81
+ // regardless of which nodes ReactFlow currently has mounted (virtualization
82
+ // can reshuffle the diagnostics store's insertion order on pan/select).
83
+ groups.sort((a, b) => {
84
+ const aHasError = a.errorCount > 0 ? 0 : 1;
85
+ const bHasError = b.errorCount > 0 ? 0 : 1;
86
+ if (aHasError !== bHasError) return aHasError - bHasError;
87
+ const aType = a.entityType === "node" ? 0 : 1;
88
+ const bType = b.entityType === "node" ? 0 : 1;
89
+ if (aType !== bType) return aType - bType;
90
+ return a.label.localeCompare(b.label);
91
+ });
92
+
93
+ if (groups.length === 0) {
94
+ return (
95
+ <div className="flex flex-col items-center justify-center gap-2 py-12 text-muted-foreground">
96
+ <CheckCircle2 className="w-8 h-8 text-success" />
97
+ <span className="text-sm">{t("noIssuesFound")}</span>
98
+ </div>
99
+ );
100
+ }
101
+
102
+ return (
103
+ <div className="flex flex-col gap-1">
104
+ {groups.map((group) => (
105
+ <DiagnosticGroupItem
106
+ key={`${group.entityType}-${group.entityId}`}
107
+ group={group}
108
+ onSelect={() => (group.entityType === "node" ? onSelectNode(group.entityId) : onSelectEdge(group.entityId))}
109
+ />
110
+ ))}
111
+ </div>
112
+ );
113
+ };
114
+
115
+ function DiagnosticGroupItem({ group, onSelect }: { group: DiagnosticGroup; onSelect: () => void }) {
116
+ const [open, setOpen] = useState(true);
117
+
118
+ return (
119
+ <div>
120
+ <button
121
+ type="button"
122
+ onClick={() => {
123
+ setOpen((v) => !v);
124
+ onSelect();
125
+ }}
126
+ className="flex items-center gap-2 w-full px-2 py-1.5 rounded-md hover:bg-muted/50 text-left text-sm"
127
+ >
128
+ <ChevronDown className={cn("w-3.5 h-3.5 shrink-0 transition-transform", !open && "-rotate-90")} />
129
+ <span className="truncate flex-1 font-medium">{group.label}</span>
130
+ <div className="flex items-center gap-1">
131
+ {group.errorCount > 0 && (
132
+ <Badge
133
+ variant="outline"
134
+ className="text-[10px] px-1.5 py-0 h-4 leading-4 border-destructive/40 text-destructive bg-destructive/10"
135
+ >
136
+ {group.errorCount}
137
+ </Badge>
138
+ )}
139
+ {group.warningCount > 0 && (
140
+ <Badge
141
+ variant="outline"
142
+ className="text-[10px] px-1.5 py-0 h-4 leading-4 border-warning/40 text-warning bg-warning/10"
143
+ >
144
+ {group.warningCount}
145
+ </Badge>
146
+ )}
147
+ </div>
148
+ </button>
149
+ {open && (
150
+ <div className="ml-3 border-l border-border/50 pl-2 flex flex-col gap-0.5 pb-1">
151
+ {group.diagnostics.map((diag, i) => (
152
+ <button
153
+ key={i}
154
+ type="button"
155
+ onClick={onSelect}
156
+ className="flex items-start gap-1.5 px-2 py-1 rounded text-xs text-left hover:bg-muted/50 transition-colors w-full"
157
+ >
158
+ {diag.severity === "error" ? (
159
+ <AlertTriangle className="w-3.5 h-3.5 text-destructive shrink-0 mt-0.5" />
160
+ ) : (
161
+ <AlertCircle className="w-3.5 h-3.5 text-warning shrink-0 mt-0.5" />
162
+ )}
163
+ <span className="text-muted-foreground">{diag.message}</span>
164
+ </button>
165
+ ))}
166
+ </div>
167
+ )}
168
+ </div>
169
+ );
170
+ }
@@ -0,0 +1,104 @@
1
+ import { useCallback } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Button } from "../components/ui/button";
4
+ import { Separator } from "../components/ui/separator";
5
+ import { ChevronRight } from "lucide-react";
6
+ import { getEdgeDefinition } from "@foresthubai/workflow-core/edge";
7
+ import type { EdgeData, EdgeType } from "@foresthubai/workflow-core/edge";
8
+ import ParameterEditor from "../inputs/ParameterEditor";
9
+ import { useEditorStore } from "../stores/editorStore";
10
+ import { isReadOnly } from "../WorkflowBuilder";
11
+ import { useDiagnosticsStore } from "../stores/diagnosticsStore";
12
+ import { useParamErrors } from "../hooks/useParamErrors";
13
+ import { ReadOnlyBanner } from "../components/ui/readonly-banner";
14
+ import { DeleteButton } from "../components/ui/delete-button";
15
+ import { getEdgeDescription } from "../utils/translation";
16
+
17
+ interface EdgeConfigPanelProps {
18
+ canvasId: string;
19
+ edgeId: string;
20
+ edgeType: EdgeType;
21
+ edgeData: EdgeData;
22
+ sourceControlEdgeCount: number;
23
+ onEdgeUpdate: (edgeId: string, updates: Record<string, unknown>) => void;
24
+ onEdgeDelete: (edgeId: string) => void;
25
+ onClose: () => void;
26
+ }
27
+
28
+ export const EdgeConfigPanel = ({
29
+ canvasId,
30
+ edgeId,
31
+ edgeType,
32
+ edgeData,
33
+ sourceControlEdgeCount,
34
+ onEdgeUpdate,
35
+ onEdgeDelete,
36
+ onClose,
37
+ }: EdgeConfigPanelProps) => {
38
+ const { t } = useTranslation();
39
+ const readOnly = useEditorStore((s) => isReadOnly(s.builderMode));
40
+ const definition = getEdgeDefinition(edgeType);
41
+
42
+ // Read per-parameter error state from diagnostics store
43
+ const edgeDiags = useDiagnosticsStore((s) => s.byEdgeId[edgeId]);
44
+ const paramErrors = useParamErrors(edgeDiags);
45
+
46
+ const handleParamChange = useCallback(
47
+ (paramId: string, value: unknown) => {
48
+ onEdgeUpdate(edgeId, { [paramId]: value });
49
+ },
50
+ [edgeId, onEdgeUpdate],
51
+ );
52
+
53
+ return (
54
+ <div className="p-4 space-y-4">
55
+ {/* Header - matches NodeConfigPanel layout */}
56
+ <div className="flex items-center justify-between">
57
+ <div>
58
+ <h3 className="font-semibold text-lg">{definition.label}</h3>
59
+ <p className="text-sm text-muted-foreground">{getEdgeDescription(t, definition, edgeType)}</p>
60
+ </div>
61
+ <Button variant="ghost" size="icon" onClick={onClose}>
62
+ <ChevronRight className="h-4 w-4" />
63
+ </Button>
64
+ </div>
65
+ {readOnly && <ReadOnlyBanner />}
66
+
67
+ <Separator />
68
+
69
+ <div className={readOnly ? "pointer-events-none opacity-60" : ""}>
70
+ {definition.parameters.length > 0 ? (
71
+ definition.parameters.map((param) => {
72
+ const isDescriptionOptional =
73
+ param.id === "description" &&
74
+ sourceControlEdgeCount <= 1 &&
75
+ (edgeType === "agentChoice" || edgeType === "agentDelegate");
76
+ const effectiveParam = isDescriptionOptional ? { ...param, optional: true } : param;
77
+
78
+ return (
79
+ <ParameterEditor
80
+ key={param.id}
81
+ canvasId={canvasId}
82
+ parameter={effectiveParam}
83
+ value={edgeData[param.id]}
84
+ allArguments={edgeData}
85
+ onChange={(value) => handleParamChange(param.id, value)}
86
+ errors={paramErrors.get(param.id)}
87
+ translationPrefix={`edges.${edgeType}`}
88
+ />
89
+ );
90
+ })
91
+ ) : (
92
+ <p className="text-sm text-muted-foreground">{t("noEdgeParams")}</p>
93
+ )}
94
+ </div>
95
+
96
+ {!readOnly && (
97
+ <>
98
+ <Separator />
99
+ <DeleteButton onClick={() => onEdgeDelete(edgeId)}>{t("deleteEdge")}</DeleteButton>
100
+ </>
101
+ )}
102
+ </div>
103
+ );
104
+ };
@@ -0,0 +1,179 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Button } from "../components/ui/button";
4
+ import { Separator } from "../components/ui/separator";
5
+ import {
6
+ AlertDialog,
7
+ AlertDialogAction,
8
+ AlertDialogCancel,
9
+ AlertDialogContent,
10
+ AlertDialogDescription,
11
+ AlertDialogFooter,
12
+ AlertDialogHeader,
13
+ AlertDialogTitle,
14
+ } from "../components/ui/alert-dialog";
15
+ import { ChevronRight } from "lucide-react";
16
+ import type { FunctionDeclaration } from "@foresthubai/workflow-core/function";
17
+ import { useEditorStore } from "../stores/editorStore";
18
+ import { useDiagnosticsStore } from "../stores/diagnosticsStore";
19
+ import { isReadOnly } from "../WorkflowBuilder";
20
+ import { ReadOnlyBanner } from "../components/ui/readonly-banner";
21
+ import { DeleteButton } from "../components/ui/delete-button";
22
+ import { PortSection } from "../inputs/PortSection";
23
+ import ExpressionInput from "../inputs/ExpressionInput";
24
+ import { useAvailableVariables } from "../hooks/useAvailableVariables";
25
+ import {
26
+ renameFunction,
27
+ addArgument,
28
+ updateArgument,
29
+ removeArgument,
30
+ addOutput,
31
+ updateOutput,
32
+ removeOutput,
33
+ setOutputExpression,
34
+ deleteFunction,
35
+ } from "../utils/functionOperations";
36
+
37
+ interface FunctionConfigPanelProps {
38
+ func: FunctionDeclaration;
39
+ onClose: () => void;
40
+ }
41
+
42
+ /**
43
+ * Right-side editor for a project-scoped function declaration, styled like the other
44
+ * config panels: an editable title, then Inputs and Outputs sections (strong label +
45
+ * description) whose rows are the same `bg-card` declaration cards the node Outputs
46
+ * section uses. Each output bundles its declaration with the expression that produces
47
+ * it; those expressions resolve against the function body's scope (the body canvas is
48
+ * active, since selectFunction switched to it). Edits are non-undo-tracked.
49
+ */
50
+ export const FunctionConfigPanel = ({ func, onClose }: FunctionConfigPanelProps) => {
51
+ const { t } = useTranslation();
52
+ const readOnly = useEditorStore((s) => isReadOnly(s.builderMode));
53
+ const { id, arguments: fnArgs, outputs } = func;
54
+
55
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
56
+
57
+ // Local name state preserves cursor position; resets when a different function opens.
58
+ const [localName, setLocalName] = useState(func.name);
59
+ useEffect(() => {
60
+ setLocalName(func.name);
61
+ }, [id, func.name]);
62
+
63
+ // Output expressions resolve against the function body's variable scope.
64
+ const { lookup: availableVariables } = useAvailableVariables(id);
65
+
66
+ // Per-output error messages come from the same byFunctionId slot that rings the
67
+ // sidebar tab badge + list row, so panel, badge, and list always agree.
68
+ const fnDiags = useDiagnosticsStore((s) => s.byFunctionId[id]);
69
+ const outputErrors = useMemo(() => {
70
+ const byUid = new Map<string, string[]>();
71
+ for (const d of fnDiags ?? []) {
72
+ if (!d.outputId) continue;
73
+ const list = byUid.get(d.outputId);
74
+ if (list) list.push(d.message);
75
+ else byUid.set(d.outputId, [d.message]);
76
+ }
77
+ return byUid;
78
+ }, [fnDiags]);
79
+
80
+ return (
81
+ <div className="p-4">
82
+ <div className="space-y-4">
83
+ <div className="flex items-center justify-between gap-2">
84
+ <div className="flex-1 min-w-0">
85
+ <div className="group flex items-center gap-1.5 rounded-md border border-transparent px-1.5 -mx-1.5 hover:border-input focus-within:border-input transition-colors">
86
+ <input
87
+ type="text"
88
+ title={t("functionName")}
89
+ className="font-semibold text-lg bg-transparent w-full outline-none cursor-text py-0.5 font-mono"
90
+ value={localName}
91
+ readOnly={readOnly}
92
+ placeholder={t("functionNamePlaceholder")}
93
+ onChange={(e) => {
94
+ setLocalName(e.target.value);
95
+ renameFunction(id, e.target.value);
96
+ }}
97
+ />
98
+ </div>
99
+ <p className="text-sm text-muted-foreground">{t("functionDefinition")}</p>
100
+ </div>
101
+ <Button variant="ghost" size="icon" className="shrink-0" onClick={onClose}>
102
+ <ChevronRight className="h-4 w-4" />
103
+ </Button>
104
+ </div>
105
+
106
+ {readOnly && <ReadOnlyBanner />}
107
+
108
+ <div className={`space-y-4 ${readOnly ? "pointer-events-none opacity-60" : ""}`}>
109
+ <Separator />
110
+
111
+ <PortSection
112
+ title={t("inputs")}
113
+ description={t("functionInputsDesc")}
114
+ addLabel={t("add")}
115
+ emptyText={t("noInputs")}
116
+ ports={fnArgs}
117
+ onAdd={() => addArgument(id)}
118
+ onUpdate={(index, patch) => updateArgument(id, index, patch)}
119
+ onRemove={(index) => removeArgument(id, index)}
120
+ />
121
+
122
+ <Separator />
123
+
124
+ <PortSection
125
+ title={t("outputs")}
126
+ description={t("functionOutputsDesc")}
127
+ addLabel={t("add")}
128
+ emptyText={t("noOutputs")}
129
+ ports={outputs}
130
+ onAdd={() => addOutput(id)}
131
+ onUpdate={(index, patch) => updateOutput(id, index, patch)}
132
+ onRemove={(index) => removeOutput(id, index)}
133
+ errorsFor={(out) => outputErrors.get(out.uid) ?? []}
134
+ renderExtra={(out, index) => (
135
+ <ExpressionInput
136
+ value={out.expression}
137
+ onChange={(expr) => setOutputExpression(id, index, expr)}
138
+ expressionType={out.dataType}
139
+ availableVariables={availableVariables}
140
+ placeholder={`${t("expressionFor")} ${out.name}...`}
141
+ />
142
+ )}
143
+ />
144
+ </div>
145
+
146
+ {!readOnly && (
147
+ <>
148
+ <Separator />
149
+ <DeleteButton onClick={() => setShowDeleteConfirm(true)}>{t("deleteFunction")}</DeleteButton>
150
+ </>
151
+ )}
152
+ </div>
153
+
154
+ {/* Functions carry a body + call sites, so deletion is confirmed (unlike the
155
+ leaf resources, which delete inline). */}
156
+ <AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
157
+ <AlertDialogContent>
158
+ <AlertDialogHeader>
159
+ <AlertDialogTitle>{t("deleteFunctionTitle")}</AlertDialogTitle>
160
+ <AlertDialogDescription>{t("deleteFunctionDesc")}</AlertDialogDescription>
161
+ </AlertDialogHeader>
162
+ <AlertDialogFooter>
163
+ <AlertDialogCancel>{t("cancel")}</AlertDialogCancel>
164
+ <AlertDialogAction
165
+ className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
166
+ onClick={() => {
167
+ deleteFunction(id);
168
+ setShowDeleteConfirm(false);
169
+ onClose();
170
+ }}
171
+ >
172
+ {t("delete")}
173
+ </AlertDialogAction>
174
+ </AlertDialogFooter>
175
+ </AlertDialogContent>
176
+ </AlertDialog>
177
+ </div>
178
+ );
179
+ };
@@ -0,0 +1,45 @@
1
+ import { useTranslation } from "react-i18next";
2
+ import { FunctionSquare, Plus } from "lucide-react";
3
+ import { useDiagnosticsStore } from "../stores/diagnosticsStore";
4
+ import { useEditorStore } from "../stores/editorStore";
5
+ import { ResourceListPanel } from "./ResourceListPanel";
6
+
7
+ interface FunctionListPanelProps {
8
+ /** Open + select an existing function (switches to its canvas). */
9
+ onOpenFunction: (id: string) => void;
10
+ /** Create a new function and open it. */
11
+ onCreateFunction: () => string;
12
+ }
13
+
14
+ /**
15
+ * Always-present sidebar list of project-scoped functions, mirroring the
16
+ * channels/memory/models panels. Selecting a row opens the function (its canvas +
17
+ * the definition config on the right); the badge shows the in→out port counts.
18
+ */
19
+ export const FunctionListPanel = ({ onOpenFunction, onCreateFunction }: FunctionListPanelProps) => {
20
+ const { t } = useTranslation();
21
+ const functions = useEditorStore((s) => s.functions);
22
+ const selection = useEditorStore((s) => s.selection);
23
+ const byFunctionId = useDiagnosticsStore((s) => s.byFunctionId);
24
+
25
+ const items = Object.values(functions).map((f) => ({
26
+ id: f.id,
27
+ label: f.name,
28
+ inputs: f.arguments.length,
29
+ outputs: f.outputs.length,
30
+ }));
31
+
32
+ return (
33
+ <ResourceListPanel
34
+ items={items}
35
+ selectedId={selection.kind === "function" ? selection.id : null}
36
+ onSelect={onOpenFunction}
37
+ diagnosticsSlot={byFunctionId}
38
+ badge={(f) => `${f.inputs}→${f.outputs}`}
39
+ emptyIcon={FunctionSquare}
40
+ emptyText={t("noFunctions")}
41
+ emptyHint={t("addFunctionHint")}
42
+ addActions={[{ label: t("addFunction"), icon: Plus, onAdd: () => onCreateFunction() }]}
43
+ />
44
+ );
45
+ };