@invect/ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/Invect-CWpIwZ5F.js +92738 -0
  4. package/dist/Invect.d.ts +25 -0
  5. package/dist/InvectShell.d.ts +14 -0
  6. package/dist/api/agent-tools.api.d.ts +1 -0
  7. package/dist/api/client.d.ts +207 -0
  8. package/dist/api/credentials.api.d.ts +47 -0
  9. package/dist/api/executions.api.d.ts +43 -0
  10. package/dist/api/flows.api.d.ts +100 -0
  11. package/dist/api/index.d.ts +9 -0
  12. package/dist/api/node-data.api.d.ts +66 -0
  13. package/dist/api/query-keys.d.ts +22 -0
  14. package/dist/api/triggers.api.d.ts +44 -0
  15. package/dist/api/types.d.ts +147 -0
  16. package/dist/api/use-flow-run-stream.d.ts +12 -0
  17. package/dist/assets/invect-branding.d.ts +4 -0
  18. package/dist/assets/provider-icons/index.d.ts +8 -0
  19. package/dist/babel-C9OtljFZ.js +9721 -0
  20. package/dist/components/PageLayout.d.ts +17 -0
  21. package/dist/components/chat/ChatInput.d.ts +17 -0
  22. package/dist/components/chat/ChatMessageList.d.ts +14 -0
  23. package/dist/components/chat/ChatModelSelector.d.ts +11 -0
  24. package/dist/components/chat/ChatPanel.d.ts +19 -0
  25. package/dist/components/chat/ChatPromptOverlay.d.ts +13 -0
  26. package/dist/components/chat/ChatProviderSelector.d.ts +9 -0
  27. package/dist/components/chat/ChatSettingsPanel.d.ts +11 -0
  28. package/dist/components/chat/InlineCredentialSetup.d.ts +9 -0
  29. package/dist/components/chat/MarkdownRenderer.d.ts +7 -0
  30. package/dist/components/chat/chat-memory.d.ts +21 -0
  31. package/dist/components/chat/chat.store.d.ts +416 -0
  32. package/dist/components/chat/index.d.ts +5 -0
  33. package/dist/components/chat/use-chat.d.ts +28 -0
  34. package/dist/components/credentials/CreateCredentialModal.d.ts +13 -0
  35. package/dist/components/credentials/CredentialDetailDialog.d.ts +17 -0
  36. package/dist/components/credentials/EditCredentialModal.d.ts +11 -0
  37. package/dist/components/credentials/OAuth2ConnectButton.d.ts +38 -0
  38. package/dist/components/credentials/OAuth2ProviderSelector.d.ts +15 -0
  39. package/dist/components/credentials/credential-utils.d.ts +12 -0
  40. package/dist/components/credentials/index.d.ts +9 -0
  41. package/dist/components/dashboard/FailedRunsAlert.d.ts +3 -0
  42. package/dist/components/dashboard/FlowCard.d.ts +7 -0
  43. package/dist/components/dashboard/RecentActivityTable.d.ts +9 -0
  44. package/dist/components/dashboard/StatCard.d.ts +10 -0
  45. package/dist/components/dashboard/index.d.ts +5 -0
  46. package/dist/components/dashboard/status-helpers.d.ts +5 -0
  47. package/dist/components/flow-editor/ActionsSidebar.d.ts +2 -0
  48. package/dist/components/flow-editor/FlowEditor.d.ts +21 -0
  49. package/dist/components/flow-editor/FlowHeader.d.ts +9 -0
  50. package/dist/components/flow-editor/FlowLayout.d.ts +24 -0
  51. package/dist/components/flow-editor/ModeSwitcher.d.ts +7 -0
  52. package/dist/components/flow-editor/NodeSidebar.d.ts +24 -0
  53. package/dist/components/flow-editor/RunControls.d.ts +12 -0
  54. package/dist/components/flow-editor/ToolConfigPanel.d.ts +16 -0
  55. package/dist/components/flow-editor/ValidationPanel.d.ts +5 -0
  56. package/dist/components/flow-editor/flow-editor.store.d.ts +1 -0
  57. package/dist/components/flow-editor/index.d.ts +6 -0
  58. package/dist/components/flow-editor/inline-edit.d.ts +10 -0
  59. package/dist/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.d.ts +26 -0
  60. package/dist/components/flow-editor/node-config-panel/CredentialCombobox.d.ts +21 -0
  61. package/dist/components/flow-editor/node-config-panel/CredentialsSection.d.ts +19 -0
  62. package/dist/components/flow-editor/node-config-panel/DroppableInput.d.ts +20 -0
  63. package/dist/components/flow-editor/node-config-panel/DynamicSelectField.d.ts +22 -0
  64. package/dist/components/flow-editor/node-config-panel/JsonPreviewPanel.d.ts +25 -0
  65. package/dist/components/flow-editor/node-config-panel/NodeConfigPanel.d.ts +14 -0
  66. package/dist/components/flow-editor/node-config-panel/NodeConfigPanelHeader.d.ts +15 -0
  67. package/dist/components/flow-editor/node-config-panel/ParametersSection.d.ts +16 -0
  68. package/dist/components/flow-editor/node-config-panel/SearchableSelectField.d.ts +17 -0
  69. package/dist/components/flow-editor/node-config-panel/SwitchCasesField.d.ts +18 -0
  70. package/dist/components/flow-editor/node-config-panel/hooks/index.d.ts +2 -0
  71. package/dist/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.d.ts +24 -0
  72. package/dist/components/flow-editor/node-config-panel/hooks/use-node-execution.d.ts +46 -0
  73. package/dist/components/flow-editor/node-config-panel/hooks/use-upstream-slots.d.ts +16 -0
  74. package/dist/components/flow-editor/node-config-panel/panels/AgentToolsPanel.d.ts +18 -0
  75. package/dist/components/flow-editor/node-config-panel/panels/ConfigurationPanel.d.ts +49 -0
  76. package/dist/components/flow-editor/node-config-panel/panels/DataMapperPane.d.ts +40 -0
  77. package/dist/components/flow-editor/node-config-panel/panels/InputPanel.d.ts +49 -0
  78. package/dist/components/flow-editor/node-config-panel/panels/OutputPanel.d.ts +7 -0
  79. package/dist/components/flow-editor/node-config-panel/panels/index.d.ts +4 -0
  80. package/dist/components/flow-editor/node-config-panel/types.d.ts +19 -0
  81. package/dist/components/flow-editor/node-config-panel/use-node-config-panel-store.d.ts +49 -0
  82. package/dist/components/flow-editor/node-config-panel/use-node-config-state.d.ts +26 -0
  83. package/dist/components/flow-editor/node-config-panel/use-run-node.d.ts +16 -0
  84. package/dist/components/flow-editor/node-config-panel/utils.d.ts +9 -0
  85. package/dist/components/flow-editor/serialize-to-sdk.d.ts +20 -0
  86. package/dist/components/flow-editor/toolbar-context.d.ts +2 -0
  87. package/dist/components/flow-editor/use-copy-paste.d.ts +7 -0
  88. package/dist/components/flow-editor/use-copy-paste.types.d.ts +38 -0
  89. package/dist/components/flow-editor/use-flow-editor.d.ts +44 -0
  90. package/dist/components/flow-runs-table/FlowRunsTable.d.ts +6 -0
  91. package/dist/components/flow-runs-table/index.d.ts +1 -0
  92. package/dist/components/flow-viewer/FlowRunsView.d.ts +7 -0
  93. package/dist/components/flow-viewer/FlowStatusView.d.ts +21 -0
  94. package/dist/components/flow-viewer/RunSelector.d.ts +13 -0
  95. package/dist/components/flow-viewer/RunsSidebar.d.ts +14 -0
  96. package/dist/components/flow-viewer/agent-tool-executions-list.d.ts +7 -0
  97. package/dist/components/flow-viewer/index.d.ts +1 -0
  98. package/dist/components/flow-viewer/logs-panel.d.ts +18 -0
  99. package/dist/components/flow-viewer/use-execution-log-data.d.ts +113 -0
  100. package/dist/components/graph/BatchFlowEdge.d.ts +33 -0
  101. package/dist/components/graph/LayoutSelector.d.ts +9 -0
  102. package/dist/components/graph/index.d.ts +47 -0
  103. package/dist/components/graph/styleUtils.d.ts +124 -0
  104. package/dist/components/nodes/AgentConfigPanel.d.ts +24 -0
  105. package/dist/components/nodes/AgentNode.d.ts +8 -0
  106. package/dist/components/nodes/AgentToolsBox.d.ts +41 -0
  107. package/dist/components/nodes/NodeAppendix.d.ts +19 -0
  108. package/dist/components/nodes/NodeStatusIndicator.d.ts +30 -0
  109. package/dist/components/nodes/NodeViewContext.d.ts +18 -0
  110. package/dist/components/nodes/ToolParamField.d.ts +28 -0
  111. package/dist/components/nodes/ToolSelectorModal.d.ts +80 -0
  112. package/dist/components/nodes/ToolSelectorParts.d.ts +30 -0
  113. package/dist/components/nodes/UniversalNode.d.ts +2 -0
  114. package/dist/components/nodes/createContextAwareNodes.d.ts +6 -0
  115. package/dist/components/nodes/index.d.ts +22 -0
  116. package/dist/components/nodes/nodeRegistry.d.ts +13 -0
  117. package/dist/components/nodes/withNodeContext.d.ts +7 -0
  118. package/dist/components/shared/InvectLoader.d.ts +8 -0
  119. package/dist/components/shared/InvectLogo.d.ts +9 -0
  120. package/dist/components/shared/ProviderIcon.d.ts +23 -0
  121. package/dist/components/side-menu/side-menu.d.ts +4 -0
  122. package/dist/components/sidebar/BaseSidebar.d.ts +17 -0
  123. package/dist/components/sidebar/index.d.ts +1 -0
  124. package/dist/components/triggers/CronPreview.d.ts +12 -0
  125. package/dist/components/triggers/index.d.ts +1 -0
  126. package/dist/components/ui/alert-dialog.d.ts +18 -0
  127. package/dist/components/ui/badge.d.ts +9 -0
  128. package/dist/components/ui/button.d.ts +13 -0
  129. package/dist/components/ui/card.d.ts +9 -0
  130. package/dist/components/ui/codemirror-js-editor.d.ts +25 -0
  131. package/dist/components/ui/codemirror-json-editor.d.ts +18 -0
  132. package/dist/components/ui/codemirror-nunjucks-editor.d.ts +13 -0
  133. package/dist/components/ui/codemirror-vscode-theme.d.ts +24 -0
  134. package/dist/components/ui/collapsible.d.ts +6 -0
  135. package/dist/components/ui/command.d.ts +18 -0
  136. package/dist/components/ui/dialog.d.ts +18 -0
  137. package/dist/components/ui/dropdown-menu.d.ts +25 -0
  138. package/dist/components/ui/empty-state.d.ts +21 -0
  139. package/dist/components/ui/input.d.ts +3 -0
  140. package/dist/components/ui/label.d.ts +4 -0
  141. package/dist/components/ui/popover.d.ts +10 -0
  142. package/dist/components/ui/resizable.d.ts +8 -0
  143. package/dist/components/ui/scroll-area.d.ts +5 -0
  144. package/dist/components/ui/select.d.ts +18 -0
  145. package/dist/components/ui/separator.d.ts +4 -0
  146. package/dist/components/ui/slider.d.ts +4 -0
  147. package/dist/components/ui/switch.d.ts +3 -0
  148. package/dist/components/ui/table.d.ts +10 -0
  149. package/dist/components/ui/textarea.d.ts +3 -0
  150. package/dist/components/ui/tooltip.d.ts +7 -0
  151. package/dist/components/ui/tree-view.d.ts +107 -0
  152. package/dist/contexts/AgentToolCallbacksContext.d.ts +23 -0
  153. package/dist/contexts/ApiContext.d.ts +11 -0
  154. package/dist/contexts/FlowDataContext.d.ts +9 -0
  155. package/dist/contexts/NodeRegistryContext.d.ts +14 -0
  156. package/dist/contexts/PluginRegistryContext.d.ts +39 -0
  157. package/dist/contexts/ThemeProvider.d.ts +18 -0
  158. package/dist/contexts/ValidationContext.d.ts +22 -0
  159. package/dist/demo/DemoInvect.d.ts +11 -0
  160. package/dist/demo/FlowViewer.d.ts +31 -0
  161. package/dist/demo/demo-api-client.d.ts +33 -0
  162. package/dist/demo/index.d.ts +6 -0
  163. package/dist/demo/sample-data.d.ts +1538 -0
  164. package/dist/demo.d.ts +2 -0
  165. package/dist/demo.js +2774 -0
  166. package/dist/estree-ClbRfS-1.js +7076 -0
  167. package/dist/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  168. package/dist/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  169. package/dist/fonts/geist-latin-wght-normal.woff2 +0 -0
  170. package/dist/fonts/iosevka-latin-400-normal.woff2 +0 -0
  171. package/dist/hooks/index.d.ts +1 -0
  172. package/dist/hooks/use-document-title.d.ts +1 -0
  173. package/dist/hooks/use-flow-data.d.ts +22 -0
  174. package/dist/hooks/use-invect-portal-class.d.ts +21 -0
  175. package/dist/hooks/useFlowEditorStore.d.ts +1 -0
  176. package/dist/index.css +3 -0
  177. package/dist/index.d.ts +22 -0
  178. package/dist/index.js +717 -0
  179. package/dist/lib/utils.d.ts +2 -0
  180. package/dist/prettier.d.ts +13 -0
  181. package/dist/routes/all-flow-runs.d.ts +5 -0
  182. package/dist/routes/credentials.d.ts +5 -0
  183. package/dist/routes/flow-route-layout.d.ts +19 -0
  184. package/dist/routes/flow-runs.d.ts +5 -0
  185. package/dist/routes/flow.d.ts +5 -0
  186. package/dist/routes/home.d.ts +5 -0
  187. package/dist/services/index.d.ts +1 -0
  188. package/dist/standalone-C3Df7W52.js +3463 -0
  189. package/dist/stores/executionViewStore.d.ts +64 -0
  190. package/dist/stores/flow-editor.store.d.ts +137 -0
  191. package/dist/stores/flowEditorStore.d.ts +1 -0
  192. package/dist/stores/index.d.ts +2 -0
  193. package/dist/stores/uiStore.d.ts +45 -0
  194. package/dist/types/agent-tools.types.d.ts +53 -0
  195. package/dist/types/index.d.ts +2 -0
  196. package/dist/types/node-definition.types.d.ts +85 -0
  197. package/dist/types/plugin.types.d.ts +100 -0
  198. package/dist/utils/credentialBranding.d.ts +8 -0
  199. package/dist/utils/credentialFiltering.d.ts +20 -0
  200. package/dist/utils/flowTransformations.d.ts +16 -0
  201. package/dist/utils/layoutUtils.d.ts +23 -0
  202. package/dist/utils/nodeReferenceUtils.d.ts +37 -0
  203. package/dist/vendor.d.ts +5 -0
  204. package/package.json +130 -0
  205. package/src/.DS_Store +0 -0
  206. package/src/Invect.tsx +229 -0
  207. package/src/InvectShell.tsx +55 -0
  208. package/src/api/agent-tools.api.ts +23 -0
  209. package/src/api/client.ts +899 -0
  210. package/src/api/credentials.api.ts +197 -0
  211. package/src/api/executions.api.ts +228 -0
  212. package/src/api/flows.api.ts +195 -0
  213. package/src/api/index.ts +17 -0
  214. package/src/api/node-data.api.ts +167 -0
  215. package/src/api/query-keys.ts +44 -0
  216. package/src/api/triggers.api.ts +120 -0
  217. package/src/api/types.ts +212 -0
  218. package/src/api/use-flow-run-stream.ts +206 -0
  219. package/src/app.css +560 -0
  220. package/src/assets/.DS_Store +0 -0
  221. package/src/assets/favicon.ico +0 -0
  222. package/src/assets/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  223. package/src/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  224. package/src/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
  225. package/src/assets/fonts/iosevka-latin-400-normal.woff2 +0 -0
  226. package/src/assets/invect-branding.ts +51 -0
  227. package/src/assets/provider-icons/anthropic.svg +1 -0
  228. package/src/assets/provider-icons/anthropic_light.svg +1 -0
  229. package/src/assets/provider-icons/github.svg +1 -0
  230. package/src/assets/provider-icons/github_light.svg +1 -0
  231. package/src/assets/provider-icons/gmail.svg +1 -0
  232. package/src/assets/provider-icons/google_calendar.svg +1 -0
  233. package/src/assets/provider-icons/google_docs.svg +1 -0
  234. package/src/assets/provider-icons/google_drive.svg +1 -0
  235. package/src/assets/provider-icons/google_sheets.svg +1 -0
  236. package/src/assets/provider-icons/index.ts +55 -0
  237. package/src/assets/provider-icons/linear.svg +1 -0
  238. package/src/assets/provider-icons/openai.svg +1 -0
  239. package/src/assets/provider-icons/postgres.svg +1 -0
  240. package/src/assets/provider-icons/slack.svg +1 -0
  241. package/src/assets/small-loader-dark.svg +22 -0
  242. package/src/assets/small-loader-light.svg +22 -0
  243. package/src/assets/small.svg +7 -0
  244. package/src/components/.DS_Store +0 -0
  245. package/src/components/PageLayout.tsx +55 -0
  246. package/src/components/chat/ChatInput.tsx +115 -0
  247. package/src/components/chat/ChatMessageList.tsx +788 -0
  248. package/src/components/chat/ChatModelSelector.tsx +208 -0
  249. package/src/components/chat/ChatPanel.tsx +243 -0
  250. package/src/components/chat/ChatPromptOverlay.tsx +150 -0
  251. package/src/components/chat/ChatProviderSelector.tsx +135 -0
  252. package/src/components/chat/ChatSettingsPanel.tsx +277 -0
  253. package/src/components/chat/InlineCredentialSetup.tsx +343 -0
  254. package/src/components/chat/MarkdownRenderer.tsx +140 -0
  255. package/src/components/chat/chat-memory.ts +88 -0
  256. package/src/components/chat/chat.store.ts +479 -0
  257. package/src/components/chat/index.ts +5 -0
  258. package/src/components/chat/use-chat.ts +473 -0
  259. package/src/components/credentials/CreateCredentialModal.tsx +609 -0
  260. package/src/components/credentials/CredentialDetailDialog.tsx +882 -0
  261. package/src/components/credentials/EditCredentialModal.tsx +399 -0
  262. package/src/components/credentials/OAuth2ConnectButton.tsx +288 -0
  263. package/src/components/credentials/OAuth2ProviderSelector.tsx +360 -0
  264. package/src/components/credentials/credential-utils.ts +99 -0
  265. package/src/components/credentials/index.ts +10 -0
  266. package/src/components/dashboard/FailedRunsAlert.tsx +67 -0
  267. package/src/components/dashboard/FlowCard.tsx +64 -0
  268. package/src/components/dashboard/RecentActivityTable.tsx +92 -0
  269. package/src/components/dashboard/StatCard.tsx +32 -0
  270. package/src/components/dashboard/index.ts +5 -0
  271. package/src/components/dashboard/status-helpers.tsx +102 -0
  272. package/src/components/flow-editor/ActionsSidebar.tsx +503 -0
  273. package/src/components/flow-editor/FlowEditor.tsx +1002 -0
  274. package/src/components/flow-editor/FlowHeader.tsx +87 -0
  275. package/src/components/flow-editor/FlowLayout.tsx +117 -0
  276. package/src/components/flow-editor/ModeSwitcher.tsx +49 -0
  277. package/src/components/flow-editor/NodeSidebar.tsx +343 -0
  278. package/src/components/flow-editor/RunControls.tsx +109 -0
  279. package/src/components/flow-editor/ToolConfigPanel.tsx +434 -0
  280. package/src/components/flow-editor/ValidationPanel.tsx +167 -0
  281. package/src/components/flow-editor/flow-editor.store.ts +2 -0
  282. package/src/components/flow-editor/index.ts +6 -0
  283. package/src/components/flow-editor/inline-edit.tsx +111 -0
  284. package/src/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.tsx +334 -0
  285. package/src/components/flow-editor/node-config-panel/CredentialCombobox.tsx +217 -0
  286. package/src/components/flow-editor/node-config-panel/CredentialsSection.tsx +154 -0
  287. package/src/components/flow-editor/node-config-panel/DroppableInput.tsx +45 -0
  288. package/src/components/flow-editor/node-config-panel/DynamicSelectField.tsx +223 -0
  289. package/src/components/flow-editor/node-config-panel/JsonPreviewPanel.tsx +134 -0
  290. package/src/components/flow-editor/node-config-panel/NodeConfigPanel.tsx +650 -0
  291. package/src/components/flow-editor/node-config-panel/NodeConfigPanelHeader.tsx +91 -0
  292. package/src/components/flow-editor/node-config-panel/ParametersSection.tsx +144 -0
  293. package/src/components/flow-editor/node-config-panel/SearchableSelectField.tsx +126 -0
  294. package/src/components/flow-editor/node-config-panel/SwitchCasesField.tsx +212 -0
  295. package/src/components/flow-editor/node-config-panel/hooks/index.ts +2 -0
  296. package/src/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.ts +284 -0
  297. package/src/components/flow-editor/node-config-panel/hooks/use-node-execution.ts +287 -0
  298. package/src/components/flow-editor/node-config-panel/hooks/use-upstream-slots.ts +310 -0
  299. package/src/components/flow-editor/node-config-panel/panels/AgentToolsPanel.tsx +837 -0
  300. package/src/components/flow-editor/node-config-panel/panels/ConfigurationPanel.tsx +383 -0
  301. package/src/components/flow-editor/node-config-panel/panels/DataMapperPane.tsx +456 -0
  302. package/src/components/flow-editor/node-config-panel/panels/InputPanel.tsx +338 -0
  303. package/src/components/flow-editor/node-config-panel/panels/OutputPanel.tsx +109 -0
  304. package/src/components/flow-editor/node-config-panel/panels/index.ts +4 -0
  305. package/src/components/flow-editor/node-config-panel/types.ts +20 -0
  306. package/src/components/flow-editor/node-config-panel/use-node-config-panel-store.ts +283 -0
  307. package/src/components/flow-editor/node-config-panel/use-node-config-state.ts +172 -0
  308. package/src/components/flow-editor/node-config-panel/use-run-node.ts +147 -0
  309. package/src/components/flow-editor/node-config-panel/utils.ts +73 -0
  310. package/src/components/flow-editor/serialize-to-sdk.ts +204 -0
  311. package/src/components/flow-editor/toolbar-context.ts +9 -0
  312. package/src/components/flow-editor/use-copy-paste.ts +575 -0
  313. package/src/components/flow-editor/use-copy-paste.types.ts +35 -0
  314. package/src/components/flow-editor/use-flow-editor.ts +241 -0
  315. package/src/components/flow-runs-table/FlowRunsTable.tsx +631 -0
  316. package/src/components/flow-runs-table/index.ts +1 -0
  317. package/src/components/flow-viewer/FlowRunsView.tsx +268 -0
  318. package/src/components/flow-viewer/FlowStatusView.tsx +351 -0
  319. package/src/components/flow-viewer/RunSelector.tsx +422 -0
  320. package/src/components/flow-viewer/RunsSidebar.tsx +125 -0
  321. package/src/components/flow-viewer/agent-tool-executions-list.tsx +298 -0
  322. package/src/components/flow-viewer/index.ts +1 -0
  323. package/src/components/flow-viewer/logs-panel.tsx +567 -0
  324. package/src/components/flow-viewer/use-execution-log-data.ts +374 -0
  325. package/src/components/graph/BatchFlowEdge.tsx +229 -0
  326. package/src/components/graph/LayoutSelector.tsx +42 -0
  327. package/src/components/graph/index.ts +61 -0
  328. package/src/components/graph/styleUtils.ts +375 -0
  329. package/src/components/nodes/.DS_Store +0 -0
  330. package/src/components/nodes/AgentConfigPanel.tsx +1033 -0
  331. package/src/components/nodes/AgentNode.tsx +298 -0
  332. package/src/components/nodes/AgentToolsBox.tsx +193 -0
  333. package/src/components/nodes/NodeAppendix.tsx +98 -0
  334. package/src/components/nodes/NodeStatusIndicator.tsx +74 -0
  335. package/src/components/nodes/NodeViewContext.tsx +45 -0
  336. package/src/components/nodes/ToolParamField.tsx +282 -0
  337. package/src/components/nodes/ToolSelectorModal.tsx +648 -0
  338. package/src/components/nodes/ToolSelectorParts.tsx +505 -0
  339. package/src/components/nodes/UniversalNode.tsx +356 -0
  340. package/src/components/nodes/createContextAwareNodes.ts +19 -0
  341. package/src/components/nodes/index.ts +45 -0
  342. package/src/components/nodes/nodeRegistry.ts +50 -0
  343. package/src/components/nodes/withNodeContext.tsx +55 -0
  344. package/src/components/shared/InvectLoader.tsx +59 -0
  345. package/src/components/shared/InvectLogo.tsx +59 -0
  346. package/src/components/shared/ProviderIcon.tsx +115 -0
  347. package/src/components/side-menu/side-menu.tsx +267 -0
  348. package/src/components/sidebar/BaseSidebar.tsx +148 -0
  349. package/src/components/sidebar/index.ts +1 -0
  350. package/src/components/triggers/CronPreview.tsx +243 -0
  351. package/src/components/triggers/index.ts +1 -0
  352. package/src/components/ui/alert-dialog.tsx +152 -0
  353. package/src/components/ui/badge.tsx +39 -0
  354. package/src/components/ui/button.tsx +58 -0
  355. package/src/components/ui/card.tsx +75 -0
  356. package/src/components/ui/codemirror-js-editor.tsx +432 -0
  357. package/src/components/ui/codemirror-json-editor.tsx +816 -0
  358. package/src/components/ui/codemirror-nunjucks-editor.tsx +451 -0
  359. package/src/components/ui/codemirror-vscode-theme.ts +243 -0
  360. package/src/components/ui/collapsible.tsx +12 -0
  361. package/src/components/ui/command.tsx +162 -0
  362. package/src/components/ui/dialog.tsx +140 -0
  363. package/src/components/ui/dropdown-menu.tsx +232 -0
  364. package/src/components/ui/empty-state.tsx +93 -0
  365. package/src/components/ui/input.tsx +26 -0
  366. package/src/components/ui/label.tsx +19 -0
  367. package/src/components/ui/popover.tsx +53 -0
  368. package/src/components/ui/resizable.tsx +61 -0
  369. package/src/components/ui/scroll-area.tsx +56 -0
  370. package/src/components/ui/select.tsx +179 -0
  371. package/src/components/ui/separator.tsx +26 -0
  372. package/src/components/ui/slider.tsx +58 -0
  373. package/src/components/ui/switch.tsx +22 -0
  374. package/src/components/ui/table.tsx +90 -0
  375. package/src/components/ui/textarea.tsx +23 -0
  376. package/src/components/ui/tooltip.tsx +54 -0
  377. package/src/components/ui/tree-view.tsx +574 -0
  378. package/src/contexts/AgentToolCallbacksContext.tsx +31 -0
  379. package/src/contexts/ApiContext.tsx +51 -0
  380. package/src/contexts/FlowDataContext.tsx +21 -0
  381. package/src/contexts/NodeRegistryContext.tsx +54 -0
  382. package/src/contexts/PluginRegistryContext.tsx +182 -0
  383. package/src/contexts/ThemeProvider.tsx +106 -0
  384. package/src/contexts/ValidationContext.tsx +122 -0
  385. package/src/demo/DemoInvect.tsx +42 -0
  386. package/src/demo/FlowViewer.tsx +294 -0
  387. package/src/demo/demo-api-client.ts +246 -0
  388. package/src/demo/index.ts +28 -0
  389. package/src/demo/sample-data.ts +1980 -0
  390. package/src/hooks/index.ts +1 -0
  391. package/src/hooks/use-document-title.ts +8 -0
  392. package/src/hooks/use-flow-data.ts +144 -0
  393. package/src/hooks/use-invect-portal-class.ts +27 -0
  394. package/src/hooks/useFlowEditorStore.ts +2 -0
  395. package/src/index.ts +70 -0
  396. package/src/lib/utils.ts +6 -0
  397. package/src/prettier.d.ts +13 -0
  398. package/src/routes/all-flow-runs.tsx +27 -0
  399. package/src/routes/credentials.tsx +362 -0
  400. package/src/routes/flow-route-layout.tsx +113 -0
  401. package/src/routes/flow-runs.tsx +22 -0
  402. package/src/routes/flow.tsx +22 -0
  403. package/src/routes/home.tsx +282 -0
  404. package/src/services/index.ts +6 -0
  405. package/src/stores/executionViewStore.ts +211 -0
  406. package/src/stores/flow-editor.store.ts +738 -0
  407. package/src/stores/flowEditorStore.ts +2 -0
  408. package/src/stores/index.ts +10 -0
  409. package/src/stores/uiStore.ts +189 -0
  410. package/src/types/agent-tools.types.ts +64 -0
  411. package/src/types/index.ts +5 -0
  412. package/src/types/node-definition.types.ts +104 -0
  413. package/src/types/plugin.types.ts +123 -0
  414. package/src/utils/credentialBranding.ts +116 -0
  415. package/src/utils/credentialFiltering.ts +68 -0
  416. package/src/utils/flowTransformations.ts +137 -0
  417. package/src/utils/layoutUtils.ts +127 -0
  418. package/src/utils/nodeReferenceUtils.ts +135 -0
  419. package/src/vendor.d.ts +7 -0
@@ -0,0 +1,738 @@
1
+ import { create, type StoreApi, type UseBoundStore } from 'zustand';
2
+ import { devtools, subscribeWithSelector } from 'zustand/middleware';
3
+ import { immer } from 'zustand/middleware/immer';
4
+ import type { Node, Edge, NodeChange, EdgeChange } from '@xyflow/react';
5
+ import { applyNodeChanges, applyEdgeChanges, addEdge, type Connection } from '@xyflow/react';
6
+ import type { LayoutAlgorithm } from '~/utils/layoutUtils';
7
+ import type { ReactFlowNodeData } from '@invect/core/types';
8
+ import { computeSnapshot } from '~/utils/flowTransformations';
9
+
10
+ export type LayoutDirection = 'TB' | 'LR' | 'BT' | 'RL';
11
+
12
+ // Re-export for convenience
13
+ export type { LayoutAlgorithm } from '~/utils/layoutUtils';
14
+
15
+ // Type alias for flow nodes with proper data typing
16
+ // We use Node<ReactFlowNodeData> for type safety while maintaining React Flow compatibility
17
+ export type FlowNode = Node<ReactFlowNodeData>;
18
+
19
+ // Helper type guard to check if a node has properly typed data
20
+ export function isFlowNode(node: Node): node is FlowNode {
21
+ const data = node.data as Record<string, unknown>;
22
+ return (
23
+ typeof data?.id === 'string' &&
24
+ typeof data?.type === 'string' &&
25
+ typeof data?.display_name === 'string' &&
26
+ typeof data?.reference_id === 'string'
27
+ );
28
+ }
29
+
30
+ // Helper to safely get typed node data
31
+ export function getNodeData(node: Node): ReactFlowNodeData | null {
32
+ if (isFlowNode(node)) {
33
+ return node.data;
34
+ }
35
+ return null;
36
+ }
37
+
38
+ export interface FlowEditorState {
39
+ // Flow identity
40
+ flowId: string | null;
41
+ flowVersion: string | null;
42
+ flowName: string;
43
+
44
+ // Local working copy (derived from React Query, modified locally)
45
+ // Using Node[] for React Flow compatibility, but data should be ReactFlowNodeData
46
+ nodes: Node[];
47
+ edges: Edge[];
48
+
49
+ // Edge rendering control - prevents "Couldn't create edge for source handle" errors
50
+ // Edges are only rendered when this is true (after nodes + definitions are ready)
51
+ edgesReady: boolean;
52
+
53
+ // Node initialization tracking for edge readiness
54
+ registryLoading: boolean;
55
+ nodesInitialized: boolean; // From React Flow's useNodesInitialized
56
+ allNodesHaveDefinitions: boolean;
57
+ nodesReinitializedAfterRegistry: boolean;
58
+ definitionsLoadedTime: number | null;
59
+
60
+ // Dirty tracking (content-based)
61
+ // currentSnapshot: serialized InvectDefinition from the latest structural mutation
62
+ // lastSavedSnapshot: serialized InvectDefinition from the last save or server sync
63
+ // isDirty is derived: currentSnapshot !== lastSavedSnapshot
64
+ currentSnapshot: string | null;
65
+ lastSavedSnapshot: string | null;
66
+ lastSavedVersionId: string | null;
67
+ initialDataLoaded: boolean;
68
+
69
+ // Selection state
70
+ selectedNodeId: string | null;
71
+ configPanelOpen: boolean;
72
+
73
+ // Tool panel state (Agent nodes)
74
+ toolSelectorOpen: boolean;
75
+ toolConfigOpen: boolean;
76
+ toolPanelNodeId: string | null;
77
+ selectedToolInstanceId: string | null;
78
+ configPanelToolInstanceId: string | null;
79
+
80
+ // Layout state
81
+ currentLayout: LayoutAlgorithm;
82
+ layoutDirection: LayoutDirection;
83
+ initialLayoutApplied: boolean; // Track if we've applied initial layout for this flow
84
+
85
+ // Loading states
86
+ isLoading: boolean;
87
+ error: string | null;
88
+
89
+ // Execution tracking - for showing running state in editor
90
+ activeFlowRunId: string | null;
91
+ }
92
+
93
+ export interface FlowEditorActions {
94
+ // Flow identity
95
+ setFlowId: (flowId: string | null, version?: string | null) => void;
96
+ setFlowName: (name: string) => void;
97
+
98
+ // Node operations
99
+ setNodes: (nodes: Node[]) => void;
100
+ applyNodeChanges: (changes: NodeChange[]) => void;
101
+ updateNodeData: (nodeId: string, data: Partial<ReactFlowNodeData>) => void;
102
+ addNode: (node: Node) => void;
103
+ removeNode: (nodeId: string) => void;
104
+ removeNodes: (nodeIds: string[]) => void;
105
+
106
+ // Batch operations
107
+ pasteNodesAndEdges: (newNodes: Node[], newEdges: Edge[]) => void;
108
+
109
+ // Edge operations
110
+ setEdges: (edges: Edge[]) => void;
111
+ applyEdgeChanges: (changes: EdgeChange[]) => void;
112
+ addEdge: (edge: Edge) => void;
113
+ onConnect: (connection: Connection) => void;
114
+ removeEdge: (edgeId: string) => void;
115
+ removeEdgesBySourceHandle: (nodeId: string, handleId: string) => void;
116
+ setEdgesReady: (ready: boolean) => void;
117
+
118
+ // Edge readiness tracking
119
+ setRegistryLoading: (loading: boolean) => void;
120
+ setNodesInitialized: (initialized: boolean) => void;
121
+ setAllNodesHaveDefinitions: (hasDefinitions: boolean) => void;
122
+ checkAndUpdateEdgesReady: () => void;
123
+
124
+ // Selection
125
+ selectNode: (nodeId: string | null) => void;
126
+ openConfigPanel: (nodeId: string) => void;
127
+ closeConfigPanel: () => void;
128
+
129
+ // Tool panel (Agent nodes)
130
+ openToolSelector: (nodeId: string) => void;
131
+ closeToolSelector: () => void;
132
+ openToolConfig: (nodeId: string, instanceId: string) => void;
133
+ closeToolConfig: () => void;
134
+ setConfigPanelToolInstanceId: (id: string | null) => void;
135
+
136
+ // Sync with server data
137
+ syncFromServer: (nodes: Node[], edges: Edge[], versionId: string, flowName?: string) => void;
138
+ markSaved: (versionId: string) => void;
139
+ markDirty: () => void;
140
+ resetDirty: (savedVersionId?: string) => void;
141
+
142
+ // Layout
143
+ setLayout: (layout: LayoutAlgorithm, direction?: LayoutDirection) => void;
144
+ setLayoutedNodes: (nodes: Node[]) => void;
145
+ markInitialLayoutApplied: () => void;
146
+
147
+ // Computed helpers
148
+ needsInitialLayout: () => boolean;
149
+
150
+ // Loading states
151
+ setLoading: (loading: boolean) => void;
152
+ setError: (error: string | null) => void;
153
+
154
+ // Execution tracking
155
+ setActiveFlowRunId: (flowRunId: string | null) => void;
156
+ updateNodeExecutionStatus: (
157
+ nodeId: string,
158
+ status: string,
159
+ output?: unknown,
160
+ error?: string,
161
+ ) => void;
162
+ clearAllExecutionStatus: () => void;
163
+
164
+ // Run data population (from runs view "Edit" button)
165
+ populateFromRunData: (
166
+ nodeExecutionMap: Record<string, { inputs?: unknown; outputs?: unknown }>,
167
+ ) => void;
168
+
169
+ // Reset
170
+ reset: () => void;
171
+ }
172
+
173
+ export type FlowEditorStore = FlowEditorState & FlowEditorActions;
174
+
175
+ const initialState: FlowEditorState = {
176
+ flowId: null,
177
+ flowVersion: null,
178
+ flowName: 'Untitled Flow',
179
+ nodes: [],
180
+ edges: [],
181
+ edgesReady: false,
182
+ registryLoading: true,
183
+ nodesInitialized: false,
184
+ allNodesHaveDefinitions: false,
185
+ nodesReinitializedAfterRegistry: false,
186
+ definitionsLoadedTime: null,
187
+ currentSnapshot: null,
188
+ lastSavedSnapshot: null,
189
+ lastSavedVersionId: null,
190
+ initialDataLoaded: false,
191
+ selectedNodeId: null,
192
+ configPanelOpen: false,
193
+ toolSelectorOpen: false,
194
+ toolConfigOpen: false,
195
+ toolPanelNodeId: null,
196
+ selectedToolInstanceId: null,
197
+ configPanelToolInstanceId: null,
198
+ currentLayout: 'elkjs',
199
+ layoutDirection: 'LR',
200
+ initialLayoutApplied: false,
201
+ isLoading: false,
202
+ error: null,
203
+ activeFlowRunId: null,
204
+ };
205
+
206
+ // Explicit type annotation for Zustand store to prevent immer inference issues
207
+ export const useFlowEditorStore: UseBoundStore<StoreApi<FlowEditorStore>> =
208
+ create<FlowEditorStore>()(
209
+ devtools(
210
+ subscribeWithSelector(
211
+ immer((set, _get) => ({
212
+ ...initialState,
213
+
214
+ // Flow identity
215
+ setFlowId: (flowId, version = null) =>
216
+ set((state) => {
217
+ // Reset state when changing flows
218
+ if (state.flowId !== flowId) {
219
+ return { ...initialState, flowId, flowVersion: version };
220
+ }
221
+ state.flowId = flowId;
222
+ state.flowVersion = version;
223
+ }),
224
+
225
+ setFlowName: (name) =>
226
+ set((state) => {
227
+ state.flowName = name;
228
+ }),
229
+
230
+ // Node operations
231
+ setNodes: (nodes) =>
232
+ set((state) => {
233
+ state.nodes = nodes;
234
+ if (state.initialDataLoaded) {
235
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
236
+ }
237
+ }),
238
+
239
+ applyNodeChanges: (changes) =>
240
+ set((state) => {
241
+ state.nodes = applyNodeChanges(changes, state.nodes) as Node[];
242
+ if (state.initialDataLoaded) {
243
+ // Only recompute snapshot for structural changes (not select/dimensions)
244
+ const hasStructural = changes.some(
245
+ (c) => c.type !== 'select' && c.type !== 'dimensions',
246
+ );
247
+ if (hasStructural) {
248
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
249
+ }
250
+ }
251
+ }),
252
+
253
+ updateNodeData: (nodeId, data) =>
254
+ set((state) => {
255
+ const nodeIndex = state.nodes.findIndex((n) => n.id === nodeId);
256
+ if (nodeIndex !== -1) {
257
+ state.nodes[nodeIndex] = {
258
+ ...state.nodes[nodeIndex],
259
+ data: { ...state.nodes[nodeIndex].data, ...data },
260
+ };
261
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
262
+ }
263
+ }),
264
+
265
+ addNode: (node) =>
266
+ set((state) => {
267
+ state.nodes.push(node);
268
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
269
+ }),
270
+
271
+ removeNode: (nodeId) =>
272
+ set((state) => {
273
+ state.nodes = state.nodes.filter((n) => n.id !== nodeId);
274
+ // Also remove connected edges
275
+ state.edges = state.edges.filter((e) => e.source !== nodeId && e.target !== nodeId);
276
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
277
+ if (state.selectedNodeId === nodeId) {
278
+ state.selectedNodeId = null;
279
+ state.configPanelOpen = false;
280
+ }
281
+ }),
282
+
283
+ removeNodes: (nodeIds) =>
284
+ set((state) => {
285
+ const idSet = new Set(nodeIds);
286
+ state.nodes = state.nodes.filter((n) => !idSet.has(n.id));
287
+ state.edges = state.edges.filter((e) => !idSet.has(e.source) && !idSet.has(e.target));
288
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
289
+ if (state.selectedNodeId && idSet.has(state.selectedNodeId)) {
290
+ state.selectedNodeId = null;
291
+ state.configPanelOpen = false;
292
+ }
293
+ }),
294
+
295
+ pasteNodesAndEdges: (newNodes, newEdges) =>
296
+ set((state) => {
297
+ // Deselect all existing nodes
298
+ state.nodes = state.nodes.map((n) => ({ ...n, selected: false }));
299
+ // Add new nodes (already marked selected: true by caller)
300
+ state.nodes.push(...newNodes);
301
+ // Add new edges
302
+ state.edges.push(...newEdges);
303
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
304
+ state.selectedNodeId = null;
305
+ state.configPanelOpen = false;
306
+ }),
307
+
308
+ // Edge operations
309
+ setEdges: (edges) =>
310
+ set((state) => {
311
+ state.edges = edges;
312
+ if (state.initialDataLoaded) {
313
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
314
+ }
315
+ }),
316
+
317
+ applyEdgeChanges: (changes) =>
318
+ set((state) => {
319
+ state.edges = applyEdgeChanges(changes, state.edges) as Edge[];
320
+ if (state.initialDataLoaded) {
321
+ // Only recompute for structural changes (not select)
322
+ const hasStructural = changes.some((c) => c.type !== 'select');
323
+ if (hasStructural) {
324
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
325
+ }
326
+ }
327
+ }),
328
+
329
+ addEdge: (edge) =>
330
+ set((state) => {
331
+ state.edges.push(edge);
332
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
333
+ }),
334
+
335
+ onConnect: (connection) =>
336
+ set((state) => {
337
+ state.edges = addEdge(connection, state.edges);
338
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
339
+ }),
340
+
341
+ removeEdge: (edgeId) =>
342
+ set((state) => {
343
+ state.edges = state.edges.filter((e) => e.id !== edgeId);
344
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
345
+ }),
346
+
347
+ removeEdgesBySourceHandle: (nodeId: string, handleId: string) =>
348
+ set((state) => {
349
+ state.edges = state.edges.filter(
350
+ (e) => !(e.source === nodeId && e.sourceHandle === handleId),
351
+ );
352
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
353
+ }),
354
+
355
+ setEdgesReady: (ready) =>
356
+ set((state) => {
357
+ state.edgesReady = ready;
358
+ }),
359
+
360
+ // Edge readiness tracking
361
+ setRegistryLoading: (loading) =>
362
+ set((state) => {
363
+ state.registryLoading = loading;
364
+ // When registry finishes loading, check edge readiness
365
+ if (!loading) {
366
+ // Will be checked via checkAndUpdateEdgesReady
367
+ }
368
+ }),
369
+
370
+ setNodesInitialized: (initialized) =>
371
+ set((state) => {
372
+ state.nodesInitialized = initialized;
373
+ }),
374
+
375
+ setAllNodesHaveDefinitions: (hasDefinitions) =>
376
+ set((state) => {
377
+ const prevHadDefinitions = state.allNodesHaveDefinitions;
378
+ state.allNodesHaveDefinitions = hasDefinitions;
379
+
380
+ // When definitions become available, record the time and reset reinit flag
381
+ if (hasDefinitions && !prevHadDefinitions) {
382
+ state.definitionsLoadedTime = Date.now();
383
+ state.nodesReinitializedAfterRegistry = false;
384
+
385
+ // Schedule re-init confirmation after delay for handles to mount
386
+ const MINIMUM_DELAY = 250;
387
+ setTimeout(() => {
388
+ const currentState = _get();
389
+ if (
390
+ currentState.allNodesHaveDefinitions &&
391
+ !currentState.nodesReinitializedAfterRegistry
392
+ ) {
393
+ set((s) => {
394
+ s.nodesReinitializedAfterRegistry = true;
395
+ });
396
+ }
397
+ }, MINIMUM_DELAY);
398
+ }
399
+ }),
400
+
401
+ checkAndUpdateEdgesReady: () =>
402
+ set((state) => {
403
+ const shouldBeReady =
404
+ !state.registryLoading &&
405
+ state.nodes.length > 0 &&
406
+ state.nodesInitialized &&
407
+ state.allNodesHaveDefinitions &&
408
+ state.nodesReinitializedAfterRegistry;
409
+
410
+ if (shouldBeReady !== state.edgesReady) {
411
+ state.edgesReady = shouldBeReady;
412
+ }
413
+ }),
414
+
415
+ // Selection
416
+ selectNode: (nodeId) =>
417
+ set((state) => {
418
+ state.selectedNodeId = nodeId;
419
+ }),
420
+
421
+ openConfigPanel: (nodeId) =>
422
+ set((state) => {
423
+ state.selectedNodeId = nodeId;
424
+ state.configPanelOpen = true;
425
+ }),
426
+
427
+ closeConfigPanel: () =>
428
+ set((state) => {
429
+ state.configPanelOpen = false;
430
+ }),
431
+
432
+ // Tool panel (Agent nodes)
433
+ openToolSelector: (nodeId) =>
434
+ set((state) => {
435
+ state.toolSelectorOpen = true;
436
+ state.toolPanelNodeId = nodeId;
437
+ }),
438
+
439
+ closeToolSelector: () =>
440
+ set((state) => {
441
+ state.toolSelectorOpen = false;
442
+ state.toolConfigOpen = false;
443
+ state.selectedToolInstanceId = null;
444
+ state.toolPanelNodeId = null;
445
+ }),
446
+
447
+ openToolConfig: (nodeId, instanceId) =>
448
+ set((state) => {
449
+ state.toolPanelNodeId = nodeId;
450
+ state.selectedToolInstanceId = instanceId;
451
+ state.toolConfigOpen = true;
452
+ }),
453
+
454
+ closeToolConfig: () =>
455
+ set((state) => {
456
+ state.toolConfigOpen = false;
457
+ state.selectedToolInstanceId = null;
458
+ }),
459
+
460
+ setConfigPanelToolInstanceId: (id) =>
461
+ set((state) => {
462
+ state.configPanelToolInstanceId = id;
463
+ }),
464
+
465
+ // Sync with server data - called when React Query fetches new data
466
+ syncFromServer: (nodes, edges, versionId, flowName) =>
467
+ set((state) => {
468
+ const incomingSnapshot = computeSnapshot(nodes, edges);
469
+
470
+ // Only sync if:
471
+ // 1. We haven't loaded initial data yet
472
+ // 2. OR this is a different version than what we have AND we haven't diverged
473
+ // (content-based: current snapshot still matches last saved = no local changes)
474
+ const isDirty =
475
+ state.currentSnapshot !== null && state.currentSnapshot !== state.lastSavedSnapshot;
476
+ const shouldSync =
477
+ !state.initialDataLoaded || (state.lastSavedVersionId !== versionId && !isDirty);
478
+
479
+ if (shouldSync) {
480
+ state.nodes = nodes;
481
+ state.edges = edges;
482
+ state.currentSnapshot = incomingSnapshot;
483
+ state.lastSavedSnapshot = incomingSnapshot;
484
+ state.lastSavedVersionId = versionId;
485
+ state.initialDataLoaded = true;
486
+ if (flowName) {
487
+ state.flowName = flowName;
488
+ }
489
+ }
490
+ }),
491
+
492
+ markSaved: (versionId) =>
493
+ set((state) => {
494
+ state.lastSavedSnapshot = state.currentSnapshot;
495
+ state.lastSavedVersionId = versionId;
496
+ }),
497
+
498
+ markDirty: () =>
499
+ set((state) => {
500
+ if (state.initialDataLoaded) {
501
+ // Force snapshot recomputation (for cases where external code
502
+ // needs to explicitly mark dirty without a structural mutation)
503
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
504
+ }
505
+ }),
506
+
507
+ resetDirty: (savedVersionId) =>
508
+ set((state) => {
509
+ // Align snapshots so isDirty becomes false
510
+ state.lastSavedSnapshot = state.currentSnapshot;
511
+ if (savedVersionId) {
512
+ state.lastSavedVersionId = savedVersionId;
513
+ }
514
+ }),
515
+
516
+ // Layout
517
+ setLayout: (layout, direction) =>
518
+ set((state) => {
519
+ state.currentLayout = layout;
520
+ if (direction) {
521
+ state.layoutDirection = direction;
522
+ }
523
+ }),
524
+
525
+ setLayoutedNodes: (nodes) =>
526
+ set((state) => {
527
+ state.nodes = nodes;
528
+ // Layout changes are saved, so recompute snapshot
529
+ state.currentSnapshot = computeSnapshot(state.nodes, state.edges);
530
+ }),
531
+
532
+ markInitialLayoutApplied: () =>
533
+ set((state) => {
534
+ state.initialLayoutApplied = true;
535
+ }),
536
+
537
+ // Computed helpers
538
+ needsInitialLayout: () => {
539
+ const state = _get();
540
+ if (state.initialLayoutApplied || state.nodes.length === 0) {
541
+ return false;
542
+ }
543
+ // Check if all nodes are at (0, 0)
544
+ return state.nodes.every((node) => node.position.x === 0 && node.position.y === 0);
545
+ },
546
+
547
+ // Loading states
548
+ setLoading: (loading) =>
549
+ set((state) => {
550
+ state.isLoading = loading;
551
+ }),
552
+
553
+ setError: (error) =>
554
+ set((state) => {
555
+ state.error = error;
556
+ }),
557
+
558
+ // Execution tracking
559
+ setActiveFlowRunId: (flowRunId) =>
560
+ set((state) => {
561
+ state.activeFlowRunId = flowRunId;
562
+ }),
563
+
564
+ updateNodeExecutionStatus: (nodeId, status, output, error) =>
565
+ set((state) => {
566
+ const nodeIndex = state.nodes.findIndex((n) => n.id === nodeId);
567
+ if (nodeIndex !== -1) {
568
+ state.nodes[nodeIndex] = {
569
+ ...state.nodes[nodeIndex],
570
+ data: {
571
+ ...state.nodes[nodeIndex].data,
572
+ executionStatus: status,
573
+ ...(output !== undefined && { executionOutput: output }),
574
+ ...(error !== undefined && { executionError: error }),
575
+ },
576
+ };
577
+ }
578
+ }),
579
+
580
+ clearAllExecutionStatus: () =>
581
+ set((state) => {
582
+ state.nodes = state.nodes.map((node) => ({
583
+ ...node,
584
+ data: {
585
+ ...node.data,
586
+ executionStatus: undefined,
587
+ executionOutput: undefined,
588
+ executionError: undefined,
589
+ },
590
+ }));
591
+ state.activeFlowRunId = null;
592
+ }),
593
+
594
+ // Run data population — fills preview data from a past flow run
595
+ // without marking the flow as dirty (no structural changes).
596
+ populateFromRunData: (nodeExecutionMap) =>
597
+ set((state) => {
598
+ state.nodes = state.nodes.map((node) => {
599
+ const exec = nodeExecutionMap[node.id];
600
+ if (!exec) {
601
+ return node;
602
+ }
603
+ return {
604
+ ...node,
605
+ data: {
606
+ ...node.data,
607
+ ...(exec.inputs !== undefined && { previewInput: exec.inputs }),
608
+ ...(exec.outputs !== undefined && { previewOutput: exec.outputs }),
609
+ },
610
+ };
611
+ });
612
+ }),
613
+
614
+ // Reset
615
+ reset: () => set(() => ({ ...initialState })),
616
+ })),
617
+ ),
618
+ { name: 'flow-editor' },
619
+ ),
620
+ );
621
+
622
+ // Subscribe to state changes that affect edge readiness
623
+ // This automatically calls checkAndUpdateEdgesReady when relevant state changes
624
+ const _unsubscribeEdgeReadiness = useFlowEditorStore.subscribe((state, prevState) => {
625
+ const changed =
626
+ state.registryLoading !== prevState.registryLoading ||
627
+ state.nodes.length !== prevState.nodes.length ||
628
+ state.nodesInitialized !== prevState.nodesInitialized ||
629
+ state.allNodesHaveDefinitions !== prevState.allNodesHaveDefinitions ||
630
+ state.nodesReinitializedAfterRegistry !== prevState.nodesReinitializedAfterRegistry;
631
+
632
+ if (changed) {
633
+ // Debounce slightly to batch rapid state changes
634
+ setTimeout(() => {
635
+ useFlowEditorStore.getState().checkAndUpdateEdgesReady();
636
+ }, 0);
637
+ }
638
+ });
639
+
640
+ // Selector hooks for performance - components only re-render when their specific slice changes
641
+ export const useNodes = () => useFlowEditorStore((s) => s.nodes);
642
+ export const useEdges = () => useFlowEditorStore((s) => s.edges);
643
+ export const useEdgesReady = () => useFlowEditorStore((s) => s.edgesReady);
644
+ export const useIsDirty = () =>
645
+ useFlowEditorStore(
646
+ (s) => s.currentSnapshot !== null && s.currentSnapshot !== s.lastSavedSnapshot,
647
+ );
648
+ export const useSelectedNodeId = () => useFlowEditorStore((s) => s.selectedNodeId);
649
+ export const useConfigPanelOpen = () => useFlowEditorStore((s) => s.configPanelOpen);
650
+ export const useToolSelectorOpen = () => useFlowEditorStore((s) => s.toolSelectorOpen);
651
+ export const useToolConfigOpen = () => useFlowEditorStore((s) => s.toolConfigOpen);
652
+ export const useToolPanelNodeId = () => useFlowEditorStore((s) => s.toolPanelNodeId);
653
+ export const useSelectedToolInstanceId = () => useFlowEditorStore((s) => s.selectedToolInstanceId);
654
+ export const useConfigPanelToolInstanceId = () =>
655
+ useFlowEditorStore((s) => s.configPanelToolInstanceId);
656
+ export const useFlowName = () => useFlowEditorStore((s) => s.flowName);
657
+ export const useCurrentLayout = () => useFlowEditorStore((s) => s.currentLayout);
658
+ export const useLayoutDirection = () => useFlowEditorStore((s) => s.layoutDirection);
659
+ export const useInitialLayoutApplied = () => useFlowEditorStore((s) => s.initialLayoutApplied);
660
+ export const useIsLoading = () => useFlowEditorStore((s) => s.isLoading);
661
+ export const useFlowError = () => useFlowEditorStore((s) => s.error);
662
+
663
+ // Combined selectors for common use cases
664
+ export const useFlowEditorSelection = () =>
665
+ useFlowEditorStore((s) => ({
666
+ selectedNodeId: s.selectedNodeId,
667
+ configPanelOpen: s.configPanelOpen,
668
+ selectNode: s.selectNode,
669
+ openConfigPanel: s.openConfigPanel,
670
+ closeConfigPanel: s.closeConfigPanel,
671
+ }));
672
+
673
+ export const useFlowEditorLayout = () =>
674
+ useFlowEditorStore((s) => ({
675
+ currentLayout: s.currentLayout,
676
+ layoutDirection: s.layoutDirection,
677
+ initialLayoutApplied: s.initialLayoutApplied,
678
+ setLayout: s.setLayout,
679
+ setLayoutedNodes: s.setLayoutedNodes,
680
+ markInitialLayoutApplied: s.markInitialLayoutApplied,
681
+ needsInitialLayout: s.needsInitialLayout,
682
+ }));
683
+
684
+ // Get node by ID
685
+ export const useNode = (nodeId: string | null) =>
686
+ useFlowEditorStore((s) => (nodeId ? (s.nodes.find((n) => n.id === nodeId) ?? null) : null));
687
+
688
+ // Get node metadata for logs/display (safely accesses typed data)
689
+ export const useNodeMetadata = () =>
690
+ useFlowEditorStore((s) =>
691
+ s.nodes.reduce<Record<string, { name: string; type?: string }>>((acc, node) => {
692
+ const data = getNodeData(node);
693
+ acc[node.id] = {
694
+ name: data?.display_name ?? node.id,
695
+ type: node.type,
696
+ };
697
+ return acc;
698
+ }, {}),
699
+ );
700
+
701
+ // Get incoming edges for a node (edges where this node is the target)
702
+ export const useIncomingEdges = (nodeId: string | null) =>
703
+ useFlowEditorStore((s) => (nodeId ? s.edges.filter((e) => e.target === nodeId) : []));
704
+
705
+ // Get outgoing edges for a node (edges where this node is the source)
706
+ export const useOutgoingEdges = (nodeId: string | null) =>
707
+ useFlowEditorStore((s) => (nodeId ? s.edges.filter((e) => e.source === nodeId) : []));
708
+
709
+ // Get upstream nodes (nodes connected as sources to this node)
710
+ export const useUpstreamNodes = (nodeId: string | null) =>
711
+ useFlowEditorStore((s) => {
712
+ if (!nodeId) {
713
+ return [];
714
+ }
715
+ const incomingEdges = s.edges.filter((e) => e.target === nodeId);
716
+ const sourceIds = new Set(incomingEdges.map((e) => e.source));
717
+ return s.nodes.filter((n) => sourceIds.has(n.id));
718
+ });
719
+
720
+ // Get downstream nodes (nodes connected as targets from this node)
721
+ export const useDownstreamNodes = (nodeId: string | null) =>
722
+ useFlowEditorStore((s) => {
723
+ if (!nodeId) {
724
+ return [];
725
+ }
726
+ const outgoingEdges = s.edges.filter((e) => e.source === nodeId);
727
+ const targetIds = new Set(outgoingEdges.map((e) => e.target));
728
+ return s.nodes.filter((n) => targetIds.has(n.id));
729
+ });
730
+
731
+ // Get flow statistics
732
+ export const useFlowStats = () =>
733
+ useFlowEditorStore((s) => ({
734
+ nodeCount: s.nodes.length,
735
+ edgeCount: s.edges.length,
736
+ isDirty: s.currentSnapshot !== null && s.currentSnapshot !== s.lastSavedSnapshot,
737
+ isLoading: s.isLoading,
738
+ }));