@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,87 @@
1
+ import { Button } from '../ui/button';
2
+ import { Badge } from '../ui/badge';
3
+ import { Save, Settings, Share2, Loader2 } from 'lucide-react';
4
+ import { InlineEdit } from './inline-edit';
5
+ import { cn } from '../../lib/utils';
6
+ import { usePluginRegistry } from '../../contexts/PluginRegistryContext';
7
+ import { useParams } from 'react-router';
8
+
9
+ interface FlowHeaderProps {
10
+ flowName: string;
11
+ onFlowNameChange: (name: string) => void;
12
+ isDirty?: boolean;
13
+ onSave?: () => Promise<boolean | void>;
14
+ isSaving?: boolean;
15
+ }
16
+
17
+ export function FlowHeader({
18
+ flowName,
19
+ onFlowNameChange,
20
+ isDirty = false,
21
+ onSave,
22
+ isSaving = false,
23
+ }: FlowHeaderProps) {
24
+ const { flowId } = useParams();
25
+ const registry = usePluginRegistry();
26
+ const flowHeaderActions = registry.headerActions['flowHeader'] ?? [];
27
+
28
+ return (
29
+ <header className="flex items-center justify-between px-6 border-b h-14 border-border bg-imp-background text-card-foreground">
30
+ <div className="flex items-center gap-4">
31
+ <InlineEdit
32
+ value={flowName}
33
+ onChange={onFlowNameChange}
34
+ placeholder="Enter flow name"
35
+ displayClassName="text-lg font-semibold text-card-foreground"
36
+ inputClassName="h-8 w-64 text-lg font-semibold"
37
+ />
38
+ {isDirty ? (
39
+ <Badge
40
+ variant="secondary"
41
+ className="gap-1.5 text-xs border-warning/40 bg-warning-muted text-warning"
42
+ >
43
+ <span className="h-1.5 w-1.5 rounded-full bg-warning" />
44
+ Unsaved Changes
45
+ </Badge>
46
+ ) : (
47
+ <span className="px-3 py-1 text-xs font-medium rounded-full bg-muted text-muted-foreground">
48
+ Draft
49
+ </span>
50
+ )}
51
+ </div>
52
+ <div className="flex items-center gap-2">
53
+ <Button variant="ghost" size="icon-sm" title="Settings" aria-label="Settings">
54
+ <Settings className="w-4 h-4" />
55
+ </Button>
56
+ {/* Plugin-contributed header actions (e.g. Share button from RBAC) */}
57
+ {flowHeaderActions
58
+ .filter((a) => !a.permission || registry.checkPermission(a.permission, { flowId }))
59
+ .map((action, i) => (
60
+ <action.component key={`plugin-action-${i}`} flowId={flowId} basePath="" />
61
+ ))}
62
+ {/* Fallback Share button when no plugin provides one */}
63
+ {flowHeaderActions.length === 0 && (
64
+ <Button variant="ghost" size="icon-sm" title="Share" aria-label="Share">
65
+ <Share2 className="w-4 h-4" />
66
+ </Button>
67
+ )}
68
+ <Button
69
+ variant="outline"
70
+ size="sm"
71
+ onClick={onSave}
72
+ disabled={!isDirty || isSaving || !onSave}
73
+ className={cn(
74
+ isDirty && 'border-primary/40 bg-primary/5 text-primary hover:bg-primary/10',
75
+ )}
76
+ >
77
+ {isSaving ? (
78
+ <Loader2 className="w-4 h-4 mr-2 animate-spin" />
79
+ ) : (
80
+ <Save className="w-4 h-4 mr-2" />
81
+ )}
82
+ Save
83
+ </Button>
84
+ </div>
85
+ </header>
86
+ );
87
+ }
@@ -0,0 +1,117 @@
1
+ import type React from 'react';
2
+ import { Plus, PanelLeftClose, PanelLeftOpen } from 'lucide-react';
3
+ import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '../ui/tooltip';
4
+ import { useUIStore } from '../../stores/uiStore';
5
+ import { ToolbarCollapsedProvider } from './toolbar-context';
6
+
7
+ interface FlowLayoutProps {
8
+ sidebar: React.ReactNode;
9
+ viewport: React.ReactNode;
10
+ modeSwitcher: React.ReactNode;
11
+ layoutSelector?: React.ReactNode;
12
+ viewportRef?: React.RefObject<HTMLDivElement | null>;
13
+ /** Panel that appears on the right side (e.g. tool config, node config) */
14
+ rightPanel?: React.ReactNode;
15
+ /** Chat toggle button rendered in the top-right toolbar */
16
+ chatToggle?: React.ReactNode;
17
+ /** Chat panel rendered as a right sidebar */
18
+ chatPanel?: React.ReactNode;
19
+ /** Floating chat overlay rendered above the viewport (for empty flows) */
20
+ chatOverlay?: React.ReactNode;
21
+ /** Extra controls rendered in the bottom toolbar (e.g. Run button, Active/Inactive) */
22
+ toolbarExtra?: React.ReactNode;
23
+ /** Whether the sidebar is open */
24
+ sidebarOpen?: boolean;
25
+ /** Called to toggle sidebar visibility */
26
+ onToggleSidebar?: () => void;
27
+ }
28
+
29
+ export function FlowLayout({
30
+ sidebar,
31
+ viewport,
32
+ modeSwitcher,
33
+ layoutSelector,
34
+ viewportRef,
35
+ rightPanel,
36
+ chatToggle,
37
+ chatPanel,
38
+ chatOverlay,
39
+ toolbarExtra,
40
+ sidebarOpen = true,
41
+ onToggleSidebar,
42
+ }: FlowLayoutProps) {
43
+ const collapsed = useUIStore((s) => s.toolbarCollapsed);
44
+ const toggleCollapsed = useUIStore((s) => s.toggleToolbarCollapsed);
45
+
46
+ return (
47
+ <div className="flex flex-1 min-h-0">
48
+ {sidebarOpen && sidebar}
49
+ <div
50
+ className="relative flex flex-col flex-1 min-h-0 overflow-hidden"
51
+ ref={viewportRef as React.RefObject<HTMLDivElement>}
52
+ >
53
+ {/* Mode switcher - top center */}
54
+ <div className="absolute left-1/2 -translate-x-1/2 top-4 z-10">{modeSwitcher}</div>
55
+
56
+ {viewport}
57
+ {chatOverlay}
58
+
59
+ {/* Bottom toolbar - Figma-style */}
60
+ {(onToggleSidebar || layoutSelector || chatToggle || toolbarExtra) && (
61
+ <TooltipProvider>
62
+ <ToolbarCollapsedProvider value={collapsed}>
63
+ <div className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-1 rounded-lg border border-border bg-card/90 backdrop-blur-sm shadow-md p-1">
64
+ {/* Collapse / expand toggle */}
65
+ <Tooltip>
66
+ <TooltipTrigger asChild>
67
+ <button
68
+ onClick={toggleCollapsed}
69
+ className="flex items-center justify-center w-7 h-7 rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
70
+ >
71
+ {collapsed ? (
72
+ <PanelLeftOpen className="w-3.5 h-3.5" />
73
+ ) : (
74
+ <PanelLeftClose className="w-3.5 h-3.5" />
75
+ )}
76
+ </button>
77
+ </TooltipTrigger>
78
+ <TooltipContent side="top">
79
+ {collapsed ? 'Expand toolbar' : 'Collapse toolbar'}
80
+ </TooltipContent>
81
+ </Tooltip>
82
+
83
+ {onToggleSidebar && (
84
+ <Tooltip>
85
+ <TooltipTrigger asChild>
86
+ <button
87
+ onClick={onToggleSidebar}
88
+ className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md text-card-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
89
+ title={sidebarOpen ? 'Close node panel' : 'Open node panel'}
90
+ >
91
+ <Plus className="w-3.5 h-3.5" />
92
+ {!collapsed && 'Add nodes'}
93
+ </button>
94
+ </TooltipTrigger>
95
+ {collapsed && <TooltipContent side="top">Add nodes</TooltipContent>}
96
+ </Tooltip>
97
+ )}
98
+ {layoutSelector}
99
+ {chatToggle}
100
+ {toolbarExtra && (
101
+ <>
102
+ <div className="w-px h-4 bg-border mx-0.5" />
103
+ {toolbarExtra}
104
+ </>
105
+ )}
106
+ </div>
107
+ </ToolbarCollapsedProvider>
108
+ </TooltipProvider>
109
+ )}
110
+ </div>
111
+ {rightPanel}
112
+ {chatPanel}
113
+ </div>
114
+ );
115
+ }
116
+
117
+ export default FlowLayout;
@@ -0,0 +1,49 @@
1
+ import { cn } from '../../lib/utils';
2
+ import { Button } from '../ui/button';
3
+ import { Edit3, History } from 'lucide-react';
4
+
5
+ export type ViewMode = 'edit' | 'runs';
6
+
7
+ interface ModeSwitcherProps {
8
+ mode: ViewMode;
9
+ onModeChange: (mode: ViewMode) => void;
10
+ }
11
+
12
+ export function ModeSwitcher({ mode, onModeChange }: ModeSwitcherProps) {
13
+ const isEditMode = mode === 'edit';
14
+
15
+ return (
16
+ <div className="inline-flex items-center rounded-md border border-border bg-muted/40 p-0.5">
17
+ <Button
18
+ variant="ghost"
19
+ size="sm"
20
+ onClick={() => onModeChange('edit')}
21
+ className={cn(
22
+ 'h-7 gap-1.5 rounded-sm px-2.5 text-xs',
23
+ isEditMode
24
+ ? 'bg-card text-foreground shadow-sm hover:bg-card'
25
+ : 'text-muted-foreground hover:text-foreground',
26
+ )}
27
+ >
28
+ <Edit3 className="h-3.5 w-3.5" />
29
+ Edit
30
+ </Button>
31
+ <Button
32
+ variant="ghost"
33
+ size="sm"
34
+ onClick={() => onModeChange('runs')}
35
+ className={cn(
36
+ 'h-7 gap-1.5 rounded-sm px-2.5 text-xs',
37
+ !isEditMode
38
+ ? 'bg-card text-foreground shadow-sm hover:bg-card'
39
+ : 'text-muted-foreground hover:text-foreground',
40
+ )}
41
+ >
42
+ <History className="h-3.5 w-3.5" />
43
+ Runs
44
+ </Button>
45
+ </div>
46
+ );
47
+ }
48
+
49
+ export default ModeSwitcher;
@@ -0,0 +1,343 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { Button } from '../ui/button';
3
+
4
+ import { ScrollArea } from '../ui/scroll-area';
5
+ import { useNodeRegistry } from '../../contexts/NodeRegistryContext';
6
+ import type { NodeDefinition } from '../../types/node-definition.types';
7
+ import type { ToolDefinition, AddedToolInstance } from '../nodes/ToolSelectorModal';
8
+ import { ProviderIcon } from '../shared/ProviderIcon';
9
+ import { useFlowEditorStore } from './flow-editor.store';
10
+ import { ActionsSidebar } from './ActionsSidebar';
11
+ import { Search, Plus, X, ChevronRight, PanelLeftClose } from 'lucide-react';
12
+ import { cn } from '../../lib/utils';
13
+ import { InvectLoader } from '../shared/InvectLoader';
14
+
15
+ // ─── Types ─────────────────────────────────────────────────────────
16
+
17
+ export type SidebarMode = 'nodes' | 'actions';
18
+
19
+ export interface NodeSidebarProps {
20
+ /** Current display mode */
21
+ mode: SidebarMode;
22
+
23
+ // ─── Nodes mode props ────────────────────
24
+ onAddNode: (type: string) => void;
25
+ /** Called to collapse/hide the sidebar */
26
+ onCollapse?: () => void;
27
+
28
+ // ─── Actions mode props ──────────────────
29
+ /** Close the actions panel (returns to nodes mode) */
30
+ onClose?: () => void;
31
+ /** All available tools from API */
32
+ availableTools?: ToolDefinition[];
33
+ /** Currently added tool instances on the agent node */
34
+ addedTools?: AddedToolInstance[];
35
+ /** Called when a tool is added. Returns the new instance ID. */
36
+ onAddTool?: (toolId: string) => string;
37
+ /** Called when a tool instance is removed */
38
+ onRemoveTool?: (instanceId: string) => void;
39
+ /** Called when an added tool instance is clicked (to open config panel) */
40
+ onSelectTool?: (instance: AddedToolInstance) => void;
41
+ /** Currently selected instance (to highlight) */
42
+ selectedInstanceId?: string | null;
43
+ }
44
+
45
+ // ═══════════════════════════════════════════════════════════════════
46
+ // Main Component
47
+ // ═══════════════════════════════════════════════════════════════════
48
+
49
+ export function NodeSidebar(props: NodeSidebarProps) {
50
+ if (props.mode === 'actions') {
51
+ return <ActionsSidebar {...props} />;
52
+ }
53
+ return <NodesSidebar onAddNode={props.onAddNode} onCollapse={props.onCollapse} />;
54
+ }
55
+
56
+ // ═══════════════════════════════════════════════════════════════════
57
+ // Nodes Mode
58
+ // ═══════════════════════════════════════════════════════════════════
59
+
60
+ function NodesSidebar({
61
+ onAddNode,
62
+ onCollapse,
63
+ }: {
64
+ onAddNode: (type: string) => void;
65
+ onCollapse?: () => void;
66
+ }) {
67
+ const [search, setSearch] = useState('');
68
+ // Tracks which groups the user has manually expanded (all start collapsed)
69
+ const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
70
+ const { isLoading, nodeDefinitions } = useNodeRegistry();
71
+
72
+ const isSearching = search.trim().length > 0;
73
+
74
+ const toggleGroup = (providerId: string) => {
75
+ setExpandedGroups((prev) => {
76
+ const next = new Set(prev);
77
+ if (next.has(providerId)) {
78
+ next.delete(providerId);
79
+ } else {
80
+ next.add(providerId);
81
+ }
82
+ return next;
83
+ });
84
+ };
85
+
86
+ const totalVisible = useMemo(
87
+ () => nodeDefinitions.filter((n) => !n.hidden).length,
88
+ [nodeDefinitions],
89
+ );
90
+
91
+ const getNodeSortRank = (providerId: string, node: NodeDefinition) => {
92
+ if (providerId === 'core') {
93
+ if (node.type === 'AGENT') {
94
+ return 0;
95
+ }
96
+ if (node.type === 'core.model') {
97
+ return 1;
98
+ }
99
+ }
100
+
101
+ return 2;
102
+ };
103
+
104
+ // Filter nodes by search, then group by provider
105
+ const { providerGroups, totalFiltered } = useMemo(() => {
106
+ const lowerSearch = search.toLowerCase();
107
+
108
+ const filtered = nodeDefinitions.filter((n) => {
109
+ // Never show hidden (deprecated) nodes in the palette
110
+ if (n.hidden) {
111
+ return false;
112
+ }
113
+ if (search) {
114
+ return (
115
+ n.label.toLowerCase().includes(lowerSearch) ||
116
+ n.description.toLowerCase().includes(lowerSearch)
117
+ );
118
+ }
119
+ return true;
120
+ });
121
+
122
+ // Group by provider id
123
+ const byProvider: Record<
124
+ string,
125
+ { name: string; icon?: string; svgIcon?: string; nodes: NodeDefinition[] }
126
+ > = {};
127
+ for (const node of filtered) {
128
+ const providerId = node.provider?.id ?? 'other';
129
+ if (!byProvider[providerId]) {
130
+ byProvider[providerId] = {
131
+ name: node.provider?.name ?? 'Other',
132
+ icon: node.provider?.icon,
133
+ svgIcon: node.provider?.svgIcon,
134
+ nodes: [],
135
+ };
136
+ }
137
+ byProvider[providerId].nodes.push(node);
138
+ }
139
+
140
+ for (const [providerId, group] of Object.entries(byProvider)) {
141
+ group.nodes.sort((a, b) => {
142
+ const rankDiff = getNodeSortRank(providerId, a) - getNodeSortRank(providerId, b);
143
+ if (rankDiff !== 0) {
144
+ return rankDiff;
145
+ }
146
+
147
+ return a.label.localeCompare(b.label);
148
+ });
149
+ }
150
+
151
+ return { providerGroups: byProvider, totalFiltered: filtered.length };
152
+ }, [nodeDefinitions, search]);
153
+
154
+ // Sort providers: triggers first, then core, then rest alphabetical
155
+ const providerOrder = ['triggers', 'core', 'ai', 'logic', 'data', 'io'];
156
+ const sortedProviderIds = useMemo(
157
+ () =>
158
+ Object.keys(providerGroups).sort((a, b) => {
159
+ const idxA = providerOrder.indexOf(a);
160
+ const idxB = providerOrder.indexOf(b);
161
+ if (idxA !== -1 && idxB !== -1) {
162
+ return idxA - idxB;
163
+ }
164
+ if (idxA !== -1) {
165
+ return -1;
166
+ }
167
+ if (idxB !== -1) {
168
+ return 1;
169
+ }
170
+ return providerGroups[a].name.localeCompare(providerGroups[b].name);
171
+ }),
172
+ [providerGroups],
173
+ );
174
+
175
+ if (isLoading) {
176
+ return (
177
+ <div className="flex flex-col items-center justify-center border-r w-96 border-border bg-imp-background text-card-foreground">
178
+ <InvectLoader iconClassName="h-14" label="Loading nodes..." />
179
+ </div>
180
+ );
181
+ }
182
+
183
+ return (
184
+ <div className="flex flex-col min-h-0 overflow-hidden duration-200 border-r w-96 border-border bg-imp-background text-card-foreground animate-in slide-in-from-left fade-in">
185
+ {/* Header */}
186
+ <div className="flex items-center justify-between px-4 py-3 border-b border-border">
187
+ <h2 className="text-sm font-semibold text-card-foreground">Nodes</h2>
188
+ {onCollapse && (
189
+ <Button
190
+ variant="ghost"
191
+ size="sm"
192
+ className="p-0 w-7 h-7 text-muted-foreground hover:text-foreground"
193
+ onClick={onCollapse}
194
+ title="Collapse sidebar"
195
+ >
196
+ <PanelLeftClose className="w-4 h-4" />
197
+ </Button>
198
+ )}
199
+ </div>
200
+
201
+ {/* Search & Filters */}
202
+ <div className="px-4 pt-3 pb-2 space-y-2 border-b border-border">
203
+ <div className="relative">
204
+ <Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 pointer-events-none text-muted-foreground" />
205
+ <input
206
+ type="text"
207
+ placeholder="Search nodes…"
208
+ value={search}
209
+ onChange={(e) => setSearch(e.target.value)}
210
+ className="h-8 w-full rounded-lg border border-border bg-transparent pl-9 pr-3 text-xs outline-none placeholder:text-muted-foreground focus:border-primary/50"
211
+ />
212
+ {search && (
213
+ <button
214
+ onClick={() => setSearch('')}
215
+ className="absolute -translate-y-1/2 right-3 top-1/2 text-muted-foreground hover:text-foreground"
216
+ >
217
+ <X className="w-3 h-3" />
218
+ </button>
219
+ )}
220
+ </div>
221
+ </div>
222
+
223
+ {/* List — grouped by provider */}
224
+ <ScrollArea className="flex-1 min-h-0 overflow-hidden">
225
+ <div className="p-3 space-y-4">
226
+ {sortedProviderIds.map((providerId) => {
227
+ const group = providerGroups[providerId];
228
+ const isCollapsed = isSearching ? false : !expandedGroups.has(providerId);
229
+ return (
230
+ <div key={providerId}>
231
+ <button
232
+ type="button"
233
+ onClick={() => toggleGroup(providerId)}
234
+ className="flex items-center gap-1.5 mb-2 w-full text-[11px] font-semibold tracking-wider uppercase text-muted-foreground hover:text-foreground transition-colors"
235
+ >
236
+ <ChevronRight
237
+ className={cn(
238
+ 'w-3 h-3 shrink-0 transition-transform duration-200',
239
+ !isCollapsed && 'rotate-90',
240
+ )}
241
+ />
242
+ <ProviderIcon
243
+ providerId={providerId}
244
+ svgIcon={group.svgIcon}
245
+ icon={group.icon}
246
+ className="w-4 h-4"
247
+ />
248
+ <span className="flex-1 text-left">{group.name}</span>
249
+ <span className="text-[10px] font-normal tabular-nums">{group.nodes.length}</span>
250
+ </button>
251
+ {!isCollapsed && (
252
+ <div className="space-y-1.5">
253
+ {group.nodes.map((node) => (
254
+ <NodeCard key={node.type} node={node} onAddNode={onAddNode} />
255
+ ))}
256
+ </div>
257
+ )}
258
+ </div>
259
+ );
260
+ })}
261
+ {sortedProviderIds.length === 0 && (
262
+ <div className="py-8 text-center text-muted-foreground">
263
+ <Search className="w-6 h-6 mx-auto mb-2 opacity-20" />
264
+ <p className="text-xs">No nodes found matching &ldquo;{search}&rdquo;</p>
265
+ </div>
266
+ )}
267
+ </div>
268
+ </ScrollArea>
269
+
270
+ <div className="px-4 py-2 text-xs border-t border-border text-muted-foreground">
271
+ {totalFiltered} of {totalVisible} nodes
272
+ </div>
273
+ </div>
274
+ );
275
+ }
276
+
277
+ function NodeCard({
278
+ node,
279
+ onAddNode,
280
+ }: {
281
+ node: NodeDefinition;
282
+ onAddNode: (type: string) => void;
283
+ }) {
284
+ const bgColor =
285
+ node.provider?.id === 'core' || node.provider?.id === 'triggers'
286
+ ? 'bg-accent text-primary'
287
+ : 'bg-muted text-muted-foreground';
288
+
289
+ // Check if this node type has reached its maxInstances limit
290
+ const storeNodes = useFlowEditorStore((s) => s.nodes);
291
+ const isAtLimit = useMemo(() => {
292
+ if (node.maxInstances === null || node.maxInstances === undefined) {
293
+ return false;
294
+ }
295
+ const count = storeNodes.filter(
296
+ (n) => (n.data as Record<string, unknown>)?.type === node.type,
297
+ ).length;
298
+ return count >= node.maxInstances;
299
+ }, [node.maxInstances, node.type, storeNodes]);
300
+
301
+ return (
302
+ <div
303
+ className={cn(
304
+ 'relative flex items-center gap-2.5 p-2.5 transition-all border rounded-lg group border-border',
305
+ isAtLimit
306
+ ? 'opacity-50 cursor-not-allowed'
307
+ : 'cursor-pointer hover:border-muted-foreground/50 hover:bg-muted/50',
308
+ )}
309
+ onClick={() => !isAtLimit && onAddNode(node.type)}
310
+ title={
311
+ isAtLimit ? `Only ${node.maxInstances} ${node.label} allowed per flow` : node.description
312
+ }
313
+ >
314
+ <div className={cn('flex h-8 w-8 shrink-0 items-center justify-center rounded-md', bgColor)}>
315
+ <ProviderIcon
316
+ providerId={node.provider?.id}
317
+ svgIcon={node.provider?.svgIcon}
318
+ icon={node.icon}
319
+ className="w-5 h-5"
320
+ />
321
+ </div>
322
+ <div className="flex-1 min-w-0">
323
+ <div className="text-sm font-medium truncate">{node.label}</div>
324
+ <p className="overflow-hidden text-xs text-muted-foreground line-clamp-1 text-ellipsis">
325
+ {isAtLimit ? 'Already added to flow' : node.description}
326
+ </p>
327
+ </div>
328
+ {!isAtLimit && (
329
+ <Button
330
+ size="sm"
331
+ variant="ghost"
332
+ className="w-6 h-6 p-0 transition-opacity opacity-0 shrink-0 group-hover:opacity-100 hover:bg-primary/10 hover:text-primary"
333
+ onClick={(e) => {
334
+ e.stopPropagation();
335
+ onAddNode(node.type);
336
+ }}
337
+ >
338
+ <Plus className="w-3 h-3" />
339
+ </Button>
340
+ )}
341
+ </div>
342
+ );
343
+ }