@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,648 @@
1
+ 'use client';
2
+
3
+ import { memo, useState, useMemo, useEffect, useCallback } from 'react';
4
+ import { useQueryClient } from '@tanstack/react-query';
5
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '../ui/dialog';
6
+
7
+ import { Button } from '../ui/button';
8
+ import { ScrollArea } from '../ui/scroll-area';
9
+ import { Badge } from '../ui/badge';
10
+ import { Search, X, Tag } from 'lucide-react';
11
+ import { cn } from '../../lib/utils';
12
+ import { ProviderIcon } from '../shared/ProviderIcon';
13
+ import { CreateCredentialModal } from '../credentials/CreateCredentialModal';
14
+ import { OAuth2ProviderSelector } from '../credentials/OAuth2ProviderSelector';
15
+ import { useCreateCredential } from '../../api/credentials.api';
16
+ import type { AddCredentialRequest } from './ToolParamField';
17
+ import type { CreateCredentialInput, Credential } from '../../api/types';
18
+ import {
19
+ BrowseToolCard,
20
+ AddedToolTile,
21
+ ToolDetailsPanel,
22
+ categoryConfig,
23
+ categoryOrder,
24
+ } from './ToolSelectorParts';
25
+
26
+ /**
27
+ * Tool category for organization in UI
28
+ */
29
+ export type ToolCategory = 'data' | 'web' | 'code' | 'utility' | 'custom';
30
+
31
+ /**
32
+ * Full tool definition with schema information
33
+ */
34
+ export interface ToolDefinition {
35
+ id: string;
36
+ name: string;
37
+ description: string;
38
+ category: ToolCategory;
39
+ /** Tags for filtering */
40
+ tags?: string[];
41
+ /** JSON Schema for tool inputs */
42
+ inputSchema?: Record<string, unknown>;
43
+ /** Documentation URL */
44
+ docsUrl?: string;
45
+ /** Whether this tool is enabled by default */
46
+ enabledByDefault?: boolean;
47
+ /** If this tool is backed by a node, this is the node type */
48
+ nodeType?: string;
49
+ /** Provider information for grouping and branding */
50
+ provider?: {
51
+ id: string;
52
+ name: string;
53
+ icon: string;
54
+ /** Raw SVG markup for custom provider branding */
55
+ svgIcon?: string;
56
+ };
57
+ }
58
+
59
+ /**
60
+ * An instance of a tool that has been added to the agent.
61
+ * Multiple instances of the same tool can exist with different configurations.
62
+ */
63
+ export interface AddedToolInstance {
64
+ /** Unique instance ID */
65
+ instanceId: string;
66
+ /** Reference to the base tool definition */
67
+ toolId: string;
68
+ /** Custom name for this instance (defaults to tool name) */
69
+ name: string;
70
+ /** Custom description for this instance (defaults to tool description) */
71
+ description: string;
72
+ /** Tool-specific configuration parameters */
73
+ params: Record<string, unknown>;
74
+ }
75
+
76
+ interface ToolSelectorModalProps {
77
+ open: boolean;
78
+ onOpenChange: (open: boolean) => void;
79
+ /** All available tools */
80
+ availableTools: ToolDefinition[];
81
+ /** Currently added tool instances */
82
+ addedTools: AddedToolInstance[];
83
+ /** Called when a tool is added. Returns the new instance ID. */
84
+ onAddTool: (toolId: string) => string;
85
+ /** Called when a tool instance is removed */
86
+ onRemoveTool: (instanceId: string) => void;
87
+ /** Called when a tool instance is updated */
88
+ onUpdateTool: (
89
+ instanceId: string,
90
+ updates: Partial<Omit<AddedToolInstance, 'instanceId' | 'toolId'>>,
91
+ ) => void;
92
+ /** Portal container for rendering the modal (needed when inside ReactFlow) */
93
+ portalContainer?: HTMLElement | null;
94
+ /** If true, start with focus on added tools section */
95
+ initialShowSelected?: boolean;
96
+ /** If provided, auto-select this tool instance when modal opens */
97
+ initialSelectedInstanceId?: string | null;
98
+ }
99
+
100
+ /**
101
+ * Custom hook for debounced value
102
+ */
103
+ function useDebounce<T>(value: T, delay: number): T {
104
+ const [debouncedValue, setDebouncedValue] = useState<T>(value);
105
+
106
+ useEffect(() => {
107
+ const handler = setTimeout(() => {
108
+ setDebouncedValue(value);
109
+ }, delay);
110
+
111
+ return () => {
112
+ clearTimeout(handler);
113
+ };
114
+ }, [value, delay]);
115
+
116
+ return debouncedValue;
117
+ }
118
+ /**
119
+ * ToolSelectorModal - Modal for managing agent tools
120
+ *
121
+ * Layout:
122
+ * - Left side (60%):
123
+ * - Top: Search bar + category tabs + tag filters
124
+ * - Middle: Browse available tools grid
125
+ * - Horizontal divider (when tools added)
126
+ * - Bottom: Added tools (horizontally scrollable)
127
+ * - Right side (40%): Tool details/configuration panel
128
+ */
129
+ export const ToolSelectorModal = memo(function ToolSelectorModal({
130
+ open,
131
+ onOpenChange,
132
+ availableTools,
133
+ addedTools,
134
+ onAddTool,
135
+ onRemoveTool,
136
+ onUpdateTool,
137
+ portalContainer,
138
+ initialShowSelected: _initialShowSelected = false,
139
+ initialSelectedInstanceId = null,
140
+ }: ToolSelectorModalProps) {
141
+ const queryClient = useQueryClient();
142
+ const [searchQuery, setSearchQuery] = useState('');
143
+ // Selection can be either a browse tool (toolId) or an added instance (instanceId)
144
+ const [selectedBrowseToolId, setSelectedBrowseToolId] = useState<string | null>(null);
145
+ const [selectedInstanceId, setSelectedInstanceId] = useState<string | null>(null);
146
+ const [selectedCategory, setSelectedCategory] = useState<ToolCategory | 'all'>('all');
147
+ const [selectedTags, setSelectedTags] = useState<string[]>([]);
148
+
149
+ // Credential modal state
150
+ const [isCreateCredentialOpen, setIsCreateCredentialOpen] = useState(false);
151
+ const [isOAuth2SelectorOpen, setIsOAuth2SelectorOpen] = useState(false);
152
+ const [activeCredentialField, setActiveCredentialField] = useState<string | null>(null);
153
+ const [activeOAuth2Providers, setActiveOAuth2Providers] = useState<string[] | null>(null);
154
+ const createCredentialMutation = useCreateCredential();
155
+
156
+ // Debounce search query (300ms delay)
157
+ const debouncedSearchQuery = useDebounce(searchQuery, 300);
158
+
159
+ // Extract all unique tags from tools
160
+ const allTags = useMemo(() => {
161
+ const tagSet = new Set<string>();
162
+ for (const tool of availableTools) {
163
+ if (tool.tags) {
164
+ for (const tag of tool.tags) {
165
+ tagSet.add(tag);
166
+ }
167
+ }
168
+ }
169
+ return Array.from(tagSet).sort();
170
+ }, [availableTools]);
171
+
172
+ // Toggle tag selection
173
+ const toggleTag = useCallback((tag: string) => {
174
+ setSelectedTags((prev) =>
175
+ prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag],
176
+ );
177
+ }, []);
178
+
179
+ // Clear all tag filters
180
+ const clearTagFilters = useCallback(() => {
181
+ setSelectedTags([]);
182
+ }, []);
183
+
184
+ // Filter tools based on search, category, and tags
185
+ const filteredBrowseTools = useMemo(() => {
186
+ let tools = availableTools;
187
+
188
+ // Filter by category
189
+ if (selectedCategory !== 'all') {
190
+ tools = tools.filter((t) => t.category === selectedCategory);
191
+ }
192
+
193
+ // Filter by tags (must match ALL selected tags)
194
+ if (selectedTags.length > 0) {
195
+ tools = tools.filter((t) => {
196
+ if (!t.tags) {
197
+ return false;
198
+ }
199
+ return selectedTags.every((tag) => t.tags?.includes(tag) ?? false);
200
+ });
201
+ }
202
+
203
+ // Filter by debounced search query
204
+ if (debouncedSearchQuery.trim()) {
205
+ const query = debouncedSearchQuery.toLowerCase();
206
+ tools = tools.filter(
207
+ (t) =>
208
+ t.name.toLowerCase().includes(query) ||
209
+ t.description.toLowerCase().includes(query) ||
210
+ t.id.toLowerCase().includes(query) ||
211
+ (t.tags && t.tags.some((tag) => tag.toLowerCase().includes(query))),
212
+ );
213
+ }
214
+
215
+ return tools;
216
+ }, [availableTools, debouncedSearchQuery, selectedCategory, selectedTags]);
217
+
218
+ // Group browse tools by provider for display (matching NodeSidebar pattern)
219
+ const { providerGroups, sortedProviderIds } = useMemo(() => {
220
+ const byProvider: Record<
221
+ string,
222
+ { name: string; icon?: string; svgIcon?: string; tools: ToolDefinition[] }
223
+ > = {};
224
+ for (const tool of filteredBrowseTools) {
225
+ const providerId = tool.provider?.id ?? tool.category;
226
+ if (!byProvider[providerId]) {
227
+ byProvider[providerId] = {
228
+ name: tool.provider?.name ?? categoryConfig[tool.category]?.label ?? tool.category,
229
+ icon: tool.provider?.icon,
230
+ svgIcon: tool.provider?.svgIcon,
231
+ tools: [],
232
+ };
233
+ }
234
+ byProvider[providerId].tools.push(tool);
235
+ }
236
+
237
+ // Sort: core-like providers first, then alphabetical
238
+ const providerOrder = ['core', 'ai', 'logic', 'data', 'utility', 'io'];
239
+ const sorted = Object.keys(byProvider).sort((a, b) => {
240
+ const idxA = providerOrder.indexOf(a);
241
+ const idxB = providerOrder.indexOf(b);
242
+ if (idxA !== -1 && idxB !== -1) {
243
+ return idxA - idxB;
244
+ }
245
+ if (idxA !== -1) {
246
+ return -1;
247
+ }
248
+ if (idxB !== -1) {
249
+ return 1;
250
+ }
251
+ return byProvider[a].name.localeCompare(byProvider[b].name);
252
+ });
253
+
254
+ return { providerGroups: byProvider, sortedProviderIds: sorted };
255
+ }, [filteredBrowseTools]);
256
+
257
+ // Get selected tool/instance for details panel
258
+ const selectedBrowseTool = selectedBrowseToolId
259
+ ? (availableTools.find((t) => t.id === selectedBrowseToolId) ?? null)
260
+ : null;
261
+ const selectedInstance = selectedInstanceId
262
+ ? (addedTools.find((t) => t.instanceId === selectedInstanceId) ?? null)
263
+ : null;
264
+ const selectedInstanceToolDef = selectedInstance
265
+ ? (availableTools.find((t) => t.id === selectedInstance.toolId) ?? null)
266
+ : null;
267
+
268
+ // Count tools per category (for tabs)
269
+ const categoryCounts = useMemo(() => {
270
+ const counts: Record<ToolCategory | 'all', number> = {
271
+ all: availableTools.length,
272
+ data: 0,
273
+ web: 0,
274
+ code: 0,
275
+ utility: 0,
276
+ custom: 0,
277
+ };
278
+ for (const tool of availableTools) {
279
+ counts[tool.category]++;
280
+ }
281
+ return counts;
282
+ }, [availableTools]);
283
+
284
+ // Handle selecting a browse tool (clears instance selection)
285
+ const handleSelectBrowseTool = useCallback((toolId: string) => {
286
+ setSelectedBrowseToolId(toolId);
287
+ setSelectedInstanceId(null);
288
+ }, []);
289
+
290
+ // Handle selecting an added instance (clears browse selection)
291
+ const handleSelectInstance = useCallback((instanceId: string) => {
292
+ setSelectedInstanceId(instanceId);
293
+ setSelectedBrowseToolId(null);
294
+ }, []);
295
+
296
+ // Handle adding a tool and auto-selecting it
297
+ const handleAddTool = useCallback(
298
+ (toolId: string) => {
299
+ const instanceId = onAddTool(toolId);
300
+ // Auto-select the newly added tool to show config
301
+ setSelectedInstanceId(instanceId);
302
+ setSelectedBrowseToolId(null);
303
+ },
304
+ [onAddTool],
305
+ );
306
+
307
+ // Handle opening credential modal (either OAuth2 or regular)
308
+ const handleAddCredential = useCallback((request: AddCredentialRequest) => {
309
+ setActiveCredentialField(request.fieldName);
310
+
311
+ if (request.oauth2Providers && request.oauth2Providers.length > 0) {
312
+ // OAuth2 credential - open OAuth2 provider selector
313
+ setActiveOAuth2Providers(request.oauth2Providers);
314
+ setIsOAuth2SelectorOpen(true);
315
+ } else {
316
+ // Regular credential - open standard create modal
317
+ setIsCreateCredentialOpen(true);
318
+ }
319
+ }, []);
320
+
321
+ // Handle closing credential modal
322
+ const handleCloseCredentialModal = useCallback(() => {
323
+ setIsCreateCredentialOpen(false);
324
+ setActiveCredentialField(null);
325
+ }, []);
326
+
327
+ // Handle closing OAuth2 selector
328
+ const handleCloseOAuth2Selector = useCallback(() => {
329
+ setIsOAuth2SelectorOpen(false);
330
+ setActiveCredentialField(null);
331
+ setActiveOAuth2Providers(null);
332
+ }, []);
333
+
334
+ // Handle credential created (from either modal)
335
+ const handleCredentialCreated = useCallback(
336
+ async (createdCredential: Credential) => {
337
+ // Explicitly refetch credentials to ensure the list is up-to-date
338
+ // This is needed because the ToolParamField's useCredentials hook may have stale data
339
+ await queryClient.refetchQueries({ queryKey: ['credentials'] });
340
+
341
+ // If we have a selected instance and active field, update it with the new credential
342
+ // Note: We capture these values before closing modals which clear them
343
+ const fieldToUpdate = activeCredentialField;
344
+ const instanceToUpdate = selectedInstanceId;
345
+
346
+ if (instanceToUpdate && fieldToUpdate) {
347
+ const instance = addedTools.find((t) => t.instanceId === instanceToUpdate);
348
+ if (instance) {
349
+ onUpdateTool(instanceToUpdate, {
350
+ params: { ...instance.params, [fieldToUpdate]: createdCredential.id },
351
+ });
352
+ }
353
+ }
354
+ // Close whichever modal is open (this clears activeCredentialField)
355
+ setIsCreateCredentialOpen(false);
356
+ setIsOAuth2SelectorOpen(false);
357
+ setActiveCredentialField(null);
358
+ setActiveOAuth2Providers(null);
359
+ },
360
+ [queryClient, selectedInstanceId, activeCredentialField, addedTools, onUpdateTool],
361
+ );
362
+
363
+ // Handle creating a regular credential (non-OAuth2)
364
+ const handleCreateCredential = useCallback(
365
+ (input: CreateCredentialInput) => {
366
+ createCredentialMutation.mutate(input, {
367
+ onSuccess: (createdCredential) => {
368
+ handleCredentialCreated(createdCredential);
369
+ },
370
+ });
371
+ },
372
+ [createCredentialMutation, handleCredentialCreated],
373
+ );
374
+
375
+ // Set initial selected instance when modal opens
376
+ useEffect(() => {
377
+ if (open && initialSelectedInstanceId) {
378
+ setSelectedInstanceId(initialSelectedInstanceId);
379
+ setSelectedBrowseToolId(null);
380
+ }
381
+ }, [open, initialSelectedInstanceId]);
382
+
383
+ // Reset state when modal closes
384
+ useEffect(() => {
385
+ if (!open) {
386
+ setSearchQuery('');
387
+ setSelectedBrowseToolId(null);
388
+ setSelectedInstanceId(null);
389
+ setSelectedCategory('all');
390
+ setSelectedTags([]);
391
+ }
392
+ }, [open]);
393
+
394
+ // Determine what to show in details panel
395
+ const detailsTool = selectedInstance ? selectedInstanceToolDef : selectedBrowseTool;
396
+ const detailsInstance = selectedInstance;
397
+
398
+ return (
399
+ <Dialog open={open} onOpenChange={onOpenChange}>
400
+ <DialogContent
401
+ container={portalContainer}
402
+ className="h-[90vh] max-h-[90vh] sm:max-w-[95vw] w-[95vw] p-0 gap-0 flex flex-col bg-card border-border"
403
+ >
404
+ <DialogHeader className="p-4 pb-0 shrink-0">
405
+ <DialogTitle>Manage Agent Tools</DialogTitle>
406
+ <DialogDescription className="sr-only">
407
+ Add, configure, and manage tools for your AI agent
408
+ </DialogDescription>
409
+ </DialogHeader>
410
+
411
+ {/* Main content area */}
412
+ <div className="flex flex-1 min-h-0">
413
+ {/* Left side: Browse tools */}
414
+ <div className="flex flex-col flex-1 min-w-0 border-r">
415
+ {/* Search and filters */}
416
+ <div className="p-4 space-y-3 border-b shrink-0">
417
+ {/* Search bar */}
418
+ <div className="flex gap-3">
419
+ <div className="relative flex-1">
420
+ <Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 pointer-events-none text-muted-foreground" />
421
+ <input
422
+ type="text"
423
+ placeholder="Search tools by name, description, or tag…"
424
+ value={searchQuery}
425
+ onChange={(e) => setSearchQuery(e.target.value)}
426
+ className="w-full rounded-lg border border-border bg-transparent py-2 pl-9 pr-3 text-sm outline-none placeholder:text-muted-foreground focus:border-primary/50"
427
+ />
428
+ {searchQuery && (
429
+ <button
430
+ onClick={() => setSearchQuery('')}
431
+ className="absolute -translate-y-1/2 right-3 top-1/2 text-muted-foreground hover:text-foreground"
432
+ >
433
+ <X className="w-4 h-4" />
434
+ </button>
435
+ )}
436
+ </div>
437
+ </div>
438
+
439
+ {/* Category tabs */}
440
+ <div className="flex gap-2 pb-1 overflow-x-auto">
441
+ <Button
442
+ size="sm"
443
+ variant={selectedCategory === 'all' ? 'default' : 'ghost'}
444
+ onClick={() => setSelectedCategory('all')}
445
+ className="shrink-0"
446
+ >
447
+ All ({categoryCounts.all})
448
+ </Button>
449
+ {categoryOrder.map((cat) => {
450
+ const config = categoryConfig[cat];
451
+ const Icon = config.icon;
452
+ const count = categoryCounts[cat];
453
+ if (count === 0) {
454
+ return null;
455
+ }
456
+ return (
457
+ <Button
458
+ key={cat}
459
+ size="sm"
460
+ variant={selectedCategory === cat ? 'default' : 'ghost'}
461
+ onClick={() => setSelectedCategory(cat)}
462
+ className="shrink-0 gap-1.5"
463
+ >
464
+ <Icon className="h-3.5 w-3.5" />
465
+ {config.label} ({count})
466
+ </Button>
467
+ );
468
+ })}
469
+ </div>
470
+
471
+ {/* Tag filters */}
472
+ {allTags.length > 0 && (
473
+ <div className="flex flex-wrap items-center gap-2">
474
+ <div className="flex items-center gap-1 text-xs text-muted-foreground shrink-0">
475
+ <Tag className="w-3 h-3" />
476
+ <span>Tags:</span>
477
+ </div>
478
+ {allTags.map((tag) => (
479
+ <Badge
480
+ key={tag}
481
+ variant={selectedTags.includes(tag) ? 'default' : 'outline'}
482
+ className={cn(
483
+ 'cursor-pointer text-xs transition-colors',
484
+ selectedTags.includes(tag)
485
+ ? 'bg-primary text-primary-foreground hover:bg-primary/90'
486
+ : 'hover:bg-muted',
487
+ )}
488
+ onClick={() => toggleTag(tag)}
489
+ >
490
+ {tag}
491
+ {selectedTags.includes(tag) && <X className="w-3 h-3 ml-1" />}
492
+ </Badge>
493
+ ))}
494
+ {selectedTags.length > 0 && (
495
+ <Button
496
+ variant="ghost"
497
+ size="sm"
498
+ onClick={clearTagFilters}
499
+ className="h-6 px-2 text-xs"
500
+ >
501
+ Clear all
502
+ </Button>
503
+ )}
504
+ </div>
505
+ )}
506
+
507
+ {/* Active filters summary */}
508
+ {(selectedTags.length > 0 || debouncedSearchQuery || selectedCategory !== 'all') && (
509
+ <div className="text-xs text-muted-foreground">
510
+ Showing {filteredBrowseTools.length} of {availableTools.length} tools
511
+ </div>
512
+ )}
513
+ </div>
514
+
515
+ {/* Browse tools grid — grouped by provider */}
516
+ <ScrollArea className="flex-1">
517
+ <div className="p-4 space-y-6">
518
+ {filteredBrowseTools.length === 0 ? (
519
+ <div className="py-8 text-center text-muted-foreground">
520
+ <Search className="w-8 h-8 mx-auto mb-2 opacity-20" />
521
+ <p className="text-sm">No tools found</p>
522
+ </div>
523
+ ) : (
524
+ sortedProviderIds.map((providerId) => {
525
+ const group = providerGroups[providerId];
526
+ return (
527
+ <div key={providerId}>
528
+ <h3 className="flex items-center gap-2 mb-3 text-sm font-medium text-muted-foreground">
529
+ <ProviderIcon
530
+ providerId={providerId}
531
+ svgIcon={group.svgIcon}
532
+ icon={group.icon}
533
+ className="w-5 h-5"
534
+ />
535
+ {group.name}
536
+ </h3>
537
+ <div className="grid grid-cols-2 gap-3 xl:grid-cols-3">
538
+ {group.tools.map((tool) => (
539
+ <BrowseToolCard
540
+ key={tool.id}
541
+ tool={tool}
542
+ isActive={selectedBrowseToolId === tool.id}
543
+ onAdd={() => handleAddTool(tool.id)}
544
+ onPreview={() => handleSelectBrowseTool(tool.id)}
545
+ />
546
+ ))}
547
+ </div>
548
+ </div>
549
+ );
550
+ })
551
+ )}
552
+ </div>
553
+ </ScrollArea>
554
+ </div>
555
+
556
+ {/* Middle: Added tools vertical list */}
557
+ <div className="flex flex-col w-48 min-h-0 border-r shrink-0 bg-muted/10">
558
+ <div className="p-3 border-b shrink-0">
559
+ <div className="flex items-center gap-2">
560
+ <span className="text-xs font-medium">Added Tools</span>
561
+ <span className="flex items-center justify-center w-5 h-5 text-xs rounded-full bg-primary/10 text-primary">
562
+ {addedTools.length}
563
+ </span>
564
+ </div>
565
+ </div>
566
+ <ScrollArea className="flex-1">
567
+ <div className="p-2 space-y-2">
568
+ {addedTools.length === 0 ? (
569
+ <div className="py-6 text-center">
570
+ <div className="text-xs text-muted-foreground">No tools added yet</div>
571
+ <div className="mt-1 text-[10px] text-muted-foreground/60">
572
+ Click + on a tool to add it
573
+ </div>
574
+ </div>
575
+ ) : (
576
+ addedTools.map((instance) => {
577
+ const toolDef = availableTools.find((t) => t.id === instance.toolId);
578
+ return (
579
+ <AddedToolTile
580
+ key={instance.instanceId}
581
+ instance={instance}
582
+ toolDef={toolDef}
583
+ isActive={selectedInstanceId === instance.instanceId}
584
+ onSelect={() => handleSelectInstance(instance.instanceId)}
585
+ onRemove={() => onRemoveTool(instance.instanceId)}
586
+ />
587
+ );
588
+ })
589
+ )}
590
+ </div>
591
+ </ScrollArea>
592
+ </div>
593
+
594
+ {/* Right side: Tool details/config panel */}
595
+ <div className="flex flex-col flex-1 min-h-0 min-w-0 bg-muted/30">
596
+ <ToolDetailsPanel
597
+ tool={detailsTool}
598
+ instance={detailsInstance}
599
+ onAdd={selectedBrowseTool ? () => handleAddTool(selectedBrowseTool.id) : undefined}
600
+ onUpdate={
601
+ selectedInstance
602
+ ? (updates) => onUpdateTool(selectedInstance.instanceId, updates)
603
+ : undefined
604
+ }
605
+ onRemove={
606
+ selectedInstance ? () => onRemoveTool(selectedInstance.instanceId) : undefined
607
+ }
608
+ onAddCredential={handleAddCredential}
609
+ portalContainer={portalContainer}
610
+ />
611
+ </div>
612
+ </div>
613
+
614
+ {/* Footer */}
615
+ <div className="flex items-center justify-between p-4 border-t shrink-0">
616
+ <div className="text-sm text-muted-foreground">
617
+ {addedTools.length} tool{addedTools.length !== 1 ? 's' : ''} added
618
+ </div>
619
+ <Button onClick={() => onOpenChange(false)}>Done</Button>
620
+ </div>
621
+ </DialogContent>
622
+
623
+ {/* Regular credential creation modal (for non-OAuth2) */}
624
+ <CreateCredentialModal
625
+ open={isCreateCredentialOpen}
626
+ onClose={handleCloseCredentialModal}
627
+ onSubmit={handleCreateCredential}
628
+ isLoading={createCredentialMutation.isPending}
629
+ portalContainer={portalContainer}
630
+ />
631
+
632
+ {/* OAuth2 provider selector modal */}
633
+ <OAuth2ProviderSelector
634
+ open={isOAuth2SelectorOpen}
635
+ onOpenChange={(open) => {
636
+ if (!open) {
637
+ handleCloseOAuth2Selector();
638
+ }
639
+ }}
640
+ onCredentialCreated={handleCredentialCreated}
641
+ portalContainer={portalContainer}
642
+ filterProviders={activeOAuth2Providers ?? undefined}
643
+ />
644
+ </Dialog>
645
+ );
646
+ });
647
+
648
+ ToolSelectorModal.displayName = 'ToolSelectorModal';