@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,882 @@
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import {
3
+ Edit,
4
+ Trash2,
5
+ CheckCircle2,
6
+ AlertTriangle,
7
+ Database,
8
+ Globe,
9
+ Loader2,
10
+ PlayCircle,
11
+ Bot,
12
+ ExternalLink,
13
+ } from 'lucide-react';
14
+ import { Button } from '../ui/button';
15
+ import { Badge } from '../ui/badge';
16
+ import { Input } from '../ui/input';
17
+ import { Label } from '../ui/label';
18
+ import { Textarea } from '../ui/textarea';
19
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
20
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../ui/dialog';
21
+ import { ProviderIcon } from '../shared/ProviderIcon';
22
+ import { getCredentialBranding, getCredentialProviderLabel } from '../../utils/credentialBranding';
23
+
24
+ import {
25
+ AUTH_TYPE_CONFIG,
26
+ formatFullDate,
27
+ isTokenExpired,
28
+ getAuthTypesForType,
29
+ } from './credential-utils';
30
+ import type {
31
+ Credential,
32
+ UpdateCredentialInput,
33
+ CredentialAuthType,
34
+ CredentialType,
35
+ } from '../../api/types';
36
+ import {
37
+ useStartOAuth2Flow,
38
+ useHandleOAuth2Callback,
39
+ useOAuth2Providers,
40
+ useCredential,
41
+ } from '../../api/credentials.api';
42
+
43
+ type DetailSection = 'details' | 'edit';
44
+
45
+ interface CredentialDetailDialogProps {
46
+ credential: Credential | null;
47
+ onClose: () => void;
48
+ onDelete: (credential: Credential) => void;
49
+ onTest: (id: string) => void;
50
+ testingId: string | null;
51
+ testResult: { success: boolean; error?: string } | null;
52
+ onUpdate: (id: string, data: UpdateCredentialInput) => void;
53
+ isUpdating: boolean;
54
+ portalContainer: HTMLElement | null;
55
+ }
56
+
57
+ export function CredentialDetailDialog({
58
+ credential,
59
+ onClose,
60
+ onDelete,
61
+ onTest,
62
+ testingId,
63
+ testResult,
64
+ onUpdate,
65
+ isUpdating,
66
+ portalContainer,
67
+ }: CredentialDetailDialogProps) {
68
+ const [detailSection, setDetailSection] = useState<DetailSection>('details');
69
+ const [editFormData, setEditFormData] = useState<UpdateCredentialInput>({});
70
+
71
+ // Reset state when credential changes
72
+ React.useEffect(() => {
73
+ if (credential) {
74
+ setDetailSection('details');
75
+ setEditFormData({
76
+ name: credential.name,
77
+ type: credential.type,
78
+ authType: credential.authType,
79
+ description: credential.description,
80
+ isActive: credential.isActive,
81
+ config: credential.config || {},
82
+ metadata: credential.metadata || {},
83
+ });
84
+ }
85
+ }, [credential?.id]);
86
+
87
+ const handleEditSubmit = (e: React.FormEvent) => {
88
+ e.preventDefault();
89
+ if (!credential) {
90
+ return;
91
+ }
92
+ onUpdate(credential.id, editFormData);
93
+ setDetailSection('details');
94
+ };
95
+
96
+ const updateConfig = (key: string, value: string) => {
97
+ setEditFormData((prev) => ({
98
+ ...prev,
99
+ config: { ...prev.config, [key]: value },
100
+ }));
101
+ };
102
+
103
+ // Fetch the full credential with decrypted config (list endpoint strips config)
104
+ const { data: fullCredential } = useCredential(credential?.id ?? '');
105
+
106
+ if (!credential) {
107
+ return null;
108
+ }
109
+
110
+ const iconInfo = getCredentialBranding(credential);
111
+ const authConfig = AUTH_TYPE_CONFIG[credential.authType];
112
+ const expired = isTokenExpired(credential);
113
+
114
+ return (
115
+ <Dialog open={!!credential} onOpenChange={(open) => !open && onClose()}>
116
+ <DialogContent
117
+ container={portalContainer}
118
+ className="max-w-2xl h-160 flex flex-col gap-0 p-0 overflow-hidden"
119
+ >
120
+ <div className="flex flex-col h-full">
121
+ {/* Fixed header */}
122
+ <div className="px-6 pt-6 pb-0 shrink-0">
123
+ <DialogHeader>
124
+ <div className="flex items-center gap-3">
125
+ <div className="flex items-center justify-center w-10 h-10 rounded-lg bg-muted/60 shrink-0">
126
+ <ProviderIcon
127
+ providerId={iconInfo.providerId}
128
+ icon={iconInfo.icon}
129
+ className="w-6 h-6"
130
+ />
131
+ </div>
132
+ <div className="min-w-0">
133
+ <DialogTitle className="truncate">{credential.name}</DialogTitle>
134
+ <DialogDescription className="truncate">
135
+ {getCredentialProviderLabel(credential) ??
136
+ credential.description ??
137
+ 'Manage this credential'}
138
+ </DialogDescription>
139
+ </div>
140
+ </div>
141
+ </DialogHeader>
142
+
143
+ {/* Section nav */}
144
+ <div className="flex gap-1 border-b border-border -mx-6 px-6 mt-4">
145
+ {(['details', 'edit'] as const).map((section) => (
146
+ <button
147
+ key={section}
148
+ onClick={() => setDetailSection(section)}
149
+ className={`px-3 py-2 text-sm font-medium border-b-2 transition-colors -mb-px ${
150
+ detailSection === section
151
+ ? 'border-foreground text-foreground'
152
+ : 'border-transparent text-muted-foreground hover:text-foreground'
153
+ }`}
154
+ >
155
+ {section === 'details' && 'Overview'}
156
+ {section === 'edit' && 'Edit'}
157
+ </button>
158
+ ))}
159
+ </div>
160
+ </div>
161
+
162
+ {/* Scrollable tab content */}
163
+ <div className="flex-1 overflow-y-auto px-6 pb-6">
164
+ {/* ── Details section ── */}
165
+ {detailSection === 'details' && (
166
+ <DetailsSection
167
+ credential={fullCredential ?? credential}
168
+ authConfig={authConfig}
169
+ expired={expired}
170
+ onTest={onTest}
171
+ testingId={testingId}
172
+ testResult={testResult}
173
+ onEdit={() => setDetailSection('edit')}
174
+ onDelete={() => onDelete(credential)}
175
+ />
176
+ )}
177
+
178
+ {/* ── Edit section ── */}
179
+ {detailSection === 'edit' && (
180
+ <EditSection
181
+ editFormData={editFormData}
182
+ setEditFormData={setEditFormData}
183
+ updateConfig={updateConfig}
184
+ onSubmit={handleEditSubmit}
185
+ onCancel={() => setDetailSection('details')}
186
+ isUpdating={isUpdating}
187
+ />
188
+ )}
189
+ </div>
190
+ </div>
191
+ </DialogContent>
192
+ </Dialog>
193
+ );
194
+ }
195
+
196
+ // ── Details Section ────────────────────────────────────────────────────
197
+
198
+ function DetailsSection({
199
+ credential,
200
+ authConfig,
201
+ expired,
202
+ onTest,
203
+ testingId,
204
+ testResult,
205
+ onEdit,
206
+ onDelete,
207
+ }: {
208
+ credential: Credential;
209
+ authConfig: { label: string; color: string } | undefined;
210
+ expired: boolean;
211
+ onTest: (id: string) => void;
212
+ testingId: string | null;
213
+ testResult: { success: boolean; error?: string } | null;
214
+ onEdit: () => void;
215
+ onDelete: () => void;
216
+ }) {
217
+ return (
218
+ <div className="space-y-5 pt-4">
219
+ {/* Status + meta */}
220
+ <div className="grid grid-cols-2 gap-4">
221
+ <div className="space-y-1">
222
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
223
+ Status
224
+ </p>
225
+ <div className="flex items-center gap-1.5">
226
+ {expired ? (
227
+ <Badge variant="secondary" className="bg-warning-muted text-warning">
228
+ <AlertTriangle className="w-3 h-3 mr-1" />
229
+ Token Expired
230
+ </Badge>
231
+ ) : credential.isActive ? (
232
+ <Badge variant="secondary" className="bg-success-muted text-success">
233
+ <CheckCircle2 className="w-3 h-3 mr-1" />
234
+ Active
235
+ </Badge>
236
+ ) : (
237
+ <Badge variant="secondary" className="bg-muted text-muted-foreground">
238
+ Inactive
239
+ </Badge>
240
+ )}
241
+ </div>
242
+ </div>
243
+ <div className="space-y-1">
244
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
245
+ Auth Type
246
+ </p>
247
+ <Badge
248
+ variant="secondary"
249
+ className={authConfig?.color ?? 'bg-muted text-muted-foreground'}
250
+ >
251
+ {authConfig?.label ?? credential.authType}
252
+ </Badge>
253
+ </div>
254
+ <div className="space-y-1">
255
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">Type</p>
256
+ <div className="flex items-center gap-1.5 text-sm text-foreground">
257
+ {credential.type === 'database' ? (
258
+ <Database className="w-3.5 h-3.5 text-muted-foreground" />
259
+ ) : credential.type === 'llm' ? (
260
+ <Bot className="w-3.5 h-3.5 text-muted-foreground" />
261
+ ) : (
262
+ <Globe className="w-3.5 h-3.5 text-muted-foreground" />
263
+ )}
264
+ {credential.type === 'database'
265
+ ? 'Database'
266
+ : credential.type === 'llm'
267
+ ? 'LLM Provider'
268
+ : 'HTTP API'}
269
+ </div>
270
+ </div>
271
+ <div className="space-y-1">
272
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
273
+ Last Used
274
+ </p>
275
+ <p className="text-sm text-foreground">{formatFullDate(credential.lastUsedAt)}</p>
276
+ </div>
277
+ <div className="space-y-1">
278
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
279
+ Created
280
+ </p>
281
+ <p className="text-sm text-foreground">{formatFullDate(credential.createdAt)}</p>
282
+ </div>
283
+ <div className="space-y-1">
284
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
285
+ Updated
286
+ </p>
287
+ <p className="text-sm text-foreground">{formatFullDate(credential.updatedAt)}</p>
288
+ </div>
289
+ </div>
290
+
291
+ {credential.description && (
292
+ <div className="space-y-1">
293
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
294
+ Description
295
+ </p>
296
+ <p className="text-sm text-foreground">{credential.description}</p>
297
+ </div>
298
+ )}
299
+
300
+ {/* Test connection / OAuth connect */}
301
+ <OAuth2AwareTestSection
302
+ credential={credential}
303
+ onTest={onTest}
304
+ testingId={testingId}
305
+ testResult={testResult}
306
+ />
307
+
308
+ {/* Actions */}
309
+ <div className="flex items-center gap-2 pt-2">
310
+ <Button variant="outline" size="sm" onClick={onEdit}>
311
+ <Edit className="w-3.5 h-3.5 mr-1.5" />
312
+ Edit Credential
313
+ </Button>
314
+ <div className="flex-1" />
315
+ <Button
316
+ variant="outline"
317
+ size="sm"
318
+ onClick={onDelete}
319
+ className="text-destructive hover:text-destructive"
320
+ >
321
+ <Trash2 className="w-3.5 h-3.5 mr-1.5" />
322
+ Delete
323
+ </Button>
324
+ </div>
325
+ </div>
326
+ );
327
+ }
328
+
329
+ // ── Edit Section ───────────────────────────────────────────────────────
330
+
331
+ function EditSection({
332
+ editFormData,
333
+ setEditFormData,
334
+ updateConfig,
335
+ onSubmit,
336
+ onCancel,
337
+ isUpdating,
338
+ }: {
339
+ editFormData: UpdateCredentialInput;
340
+ setEditFormData: React.Dispatch<React.SetStateAction<UpdateCredentialInput>>;
341
+ updateConfig: (key: string, value: string) => void;
342
+ onSubmit: (e: React.FormEvent) => void;
343
+ onCancel: () => void;
344
+ isUpdating: boolean;
345
+ }) {
346
+ return (
347
+ <form
348
+ onSubmit={onSubmit}
349
+ className="space-y-4 pt-4"
350
+ autoComplete="one-time-code"
351
+ data-lpignore="true"
352
+ >
353
+ <div className="space-y-2">
354
+ <Label htmlFor="edit-name">Name *</Label>
355
+ <Input
356
+ id="edit-name"
357
+ value={editFormData.name ?? ''}
358
+ onChange={(e) => setEditFormData({ ...editFormData, name: e.target.value })}
359
+ required
360
+ />
361
+ </div>
362
+
363
+ <div className="grid grid-cols-2 gap-4">
364
+ <div className="space-y-2">
365
+ <Label htmlFor="edit-type">Credential Type</Label>
366
+ <Select
367
+ value={editFormData.type ?? 'http-api'}
368
+ onValueChange={(value) => {
369
+ const newType = value as CredentialType;
370
+ if (newType === 'llm') {
371
+ setEditFormData({ ...editFormData, type: newType, authType: 'apiKey' });
372
+ } else {
373
+ const available = getAuthTypesForType(newType);
374
+ const nextAuthType = available.some((t) => t.value === editFormData.authType)
375
+ ? editFormData.authType
376
+ : available[0]?.value || 'basic';
377
+ setEditFormData({ ...editFormData, type: newType, authType: nextAuthType });
378
+ }
379
+ }}
380
+ >
381
+ <SelectTrigger className="w-full">
382
+ <SelectValue />
383
+ </SelectTrigger>
384
+ <SelectContent>
385
+ <SelectItem value="http-api">HTTP API</SelectItem>
386
+ <SelectItem value="llm">LLM Provider</SelectItem>
387
+ <SelectItem value="database">Database</SelectItem>
388
+ </SelectContent>
389
+ </Select>
390
+ </div>
391
+ {editFormData.type !== 'llm' && (
392
+ <div className="space-y-2">
393
+ <Label htmlFor="edit-authType">Auth Type</Label>
394
+ <Select
395
+ value={editFormData.authType ?? 'bearer'}
396
+ onValueChange={(value) =>
397
+ setEditFormData({
398
+ ...editFormData,
399
+ authType: value as CredentialAuthType,
400
+ })
401
+ }
402
+ >
403
+ <SelectTrigger className="w-full">
404
+ <SelectValue />
405
+ </SelectTrigger>
406
+ <SelectContent>
407
+ {getAuthTypesForType(editFormData.type || 'http-api').map((type) => (
408
+ <SelectItem key={type.value} value={type.value}>
409
+ {type.label}
410
+ </SelectItem>
411
+ ))}
412
+ </SelectContent>
413
+ </Select>
414
+ </div>
415
+ )}
416
+ </div>
417
+
418
+ <div className="flex items-center gap-2">
419
+ <input
420
+ type="checkbox"
421
+ id="edit-isActive"
422
+ checked={editFormData.isActive ?? true}
423
+ onChange={(e) => setEditFormData({ ...editFormData, isActive: e.target.checked })}
424
+ className="h-4 w-4 rounded border-border"
425
+ />
426
+ <Label htmlFor="edit-isActive" className="cursor-pointer">
427
+ Active
428
+ </Label>
429
+ </div>
430
+
431
+ {/* LLM Provider selector */}
432
+ {editFormData.type === 'llm' && (
433
+ <div className="space-y-2">
434
+ <Label htmlFor="edit-llmProvider">LLM Provider</Label>
435
+ <Select
436
+ value={(editFormData.metadata?.provider as string) || ''}
437
+ onValueChange={(value) =>
438
+ setEditFormData({
439
+ ...editFormData,
440
+ metadata: { ...editFormData.metadata, provider: value },
441
+ })
442
+ }
443
+ >
444
+ <SelectTrigger className="w-full">
445
+ <SelectValue placeholder="Select a provider…" />
446
+ </SelectTrigger>
447
+ <SelectContent>
448
+ <SelectItem value="openai">OpenAI</SelectItem>
449
+ <SelectItem value="anthropic">Anthropic</SelectItem>
450
+ <SelectItem value="openrouter">OpenRouter</SelectItem>
451
+ </SelectContent>
452
+ </Select>
453
+ </div>
454
+ )}
455
+
456
+ {/* Config fields */}
457
+ <div className="space-y-3 p-3 bg-muted/50 rounded-lg">
458
+ <div className="flex items-center justify-between">
459
+ <h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
460
+ Credentials
461
+ </h4>
462
+ <span className="text-xs text-muted-foreground">Leave empty to keep current</span>
463
+ </div>
464
+
465
+ {editFormData.type === 'llm' && (
466
+ <div className="space-y-2">
467
+ <Label htmlFor="edit-apiKey">API Key</Label>
468
+ <Input
469
+ id="edit-apiKey"
470
+ type="text"
471
+ style={{ WebkitTextSecurity: 'disc' }}
472
+ value={(editFormData.config?.apiKey as string) || ''}
473
+ onChange={(e) => updateConfig('apiKey', e.target.value)}
474
+ placeholder="Enter API key or leave empty to keep current"
475
+ autoComplete="one-time-code"
476
+ data-1p-ignore
477
+ data-lpignore="true"
478
+ />
479
+ </div>
480
+ )}
481
+
482
+ {editFormData.type !== 'llm' && editFormData.authType === 'bearer' && (
483
+ <div className="space-y-2">
484
+ <Label htmlFor="edit-token">Token</Label>
485
+ <Input
486
+ id="edit-token"
487
+ type="text"
488
+ style={{ WebkitTextSecurity: 'disc' }}
489
+ value={(editFormData.config?.token as string) || ''}
490
+ onChange={(e) => updateConfig('token', e.target.value)}
491
+ placeholder="Enter bearer token"
492
+ autoComplete="one-time-code"
493
+ data-1p-ignore
494
+ data-lpignore="true"
495
+ />
496
+ </div>
497
+ )}
498
+
499
+ {editFormData.type !== 'llm' && editFormData.authType === 'apiKey' && (
500
+ <>
501
+ <div className="space-y-2">
502
+ <Label htmlFor="edit-apiKey">API Key</Label>
503
+ <Input
504
+ id="edit-apiKey"
505
+ type="text"
506
+ style={{ WebkitTextSecurity: 'disc' }}
507
+ value={(editFormData.config?.apiKey as string) || ''}
508
+ onChange={(e) => updateConfig('apiKey', e.target.value)}
509
+ placeholder="Enter API key"
510
+ autoComplete="one-time-code"
511
+ data-1p-ignore
512
+ data-lpignore="true"
513
+ />
514
+ </div>
515
+ <div className="grid grid-cols-2 gap-3">
516
+ <div className="space-y-2">
517
+ <Label htmlFor="edit-location">Location</Label>
518
+ <select
519
+ id="edit-location"
520
+ value={(editFormData.config?.location as string) || 'header'}
521
+ onChange={(e) => updateConfig('location', e.target.value)}
522
+ className="flex h-9 w-full rounded-md border border-input bg-background dark:bg-input/30 px-3 py-1 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
523
+ >
524
+ <option value="header">Header</option>
525
+ <option value="query">Query Parameter</option>
526
+ </select>
527
+ </div>
528
+ <div className="space-y-2">
529
+ <Label htmlFor="edit-paramName">Parameter Name</Label>
530
+ <Input
531
+ id="edit-paramName"
532
+ value={(editFormData.config?.paramName as string) || ''}
533
+ onChange={(e) => updateConfig('paramName', e.target.value)}
534
+ placeholder="X-API-Key"
535
+ />
536
+ </div>
537
+ </div>
538
+ </>
539
+ )}
540
+
541
+ {editFormData.authType === 'connectionString' && (
542
+ <div className="space-y-2">
543
+ <Label htmlFor="edit-connStr">Connection String</Label>
544
+ <Input
545
+ id="edit-connStr"
546
+ type="text"
547
+ style={{ WebkitTextSecurity: 'disc' }}
548
+ value={(editFormData.config?.connectionString as string) || ''}
549
+ onChange={(e) => updateConfig('connectionString', e.target.value)}
550
+ placeholder="postgres://user:pass@host:5432/db"
551
+ autoComplete="one-time-code"
552
+ data-1p-ignore
553
+ data-lpignore="true"
554
+ />
555
+ </div>
556
+ )}
557
+
558
+ {editFormData.authType === 'basic' && (
559
+ <div className="grid grid-cols-2 gap-3">
560
+ <div className="space-y-2">
561
+ <Label htmlFor="edit-username">Username</Label>
562
+ <Input
563
+ id="edit-username"
564
+ value={(editFormData.config?.username as string) || ''}
565
+ onChange={(e) => updateConfig('username', e.target.value)}
566
+ placeholder="Username"
567
+ autoComplete="one-time-code"
568
+ data-1p-ignore
569
+ data-lpignore="true"
570
+ />
571
+ </div>
572
+ <div className="space-y-2">
573
+ <Label htmlFor="edit-password">Password</Label>
574
+ <Input
575
+ id="edit-password"
576
+ type="text"
577
+ style={{ WebkitTextSecurity: 'disc' }}
578
+ value={(editFormData.config?.password as string) || ''}
579
+ onChange={(e) => updateConfig('password', e.target.value)}
580
+ placeholder="Password"
581
+ autoComplete="one-time-code"
582
+ data-1p-ignore
583
+ data-lpignore="true"
584
+ />
585
+ </div>
586
+ </div>
587
+ )}
588
+
589
+ {editFormData.authType === 'oauth2' && (
590
+ <div className="grid grid-cols-2 gap-3">
591
+ <div className="space-y-2">
592
+ <Label htmlFor="edit-clientId">Client ID</Label>
593
+ <Input
594
+ id="edit-clientId"
595
+ value={(editFormData.config?.clientId as string) || ''}
596
+ onChange={(e) => updateConfig('clientId', e.target.value)}
597
+ placeholder="Client ID"
598
+ autoComplete="one-time-code"
599
+ data-1p-ignore
600
+ data-lpignore="true"
601
+ />
602
+ </div>
603
+ <div className="space-y-2">
604
+ <Label htmlFor="edit-clientSecret">Client Secret</Label>
605
+ <Input
606
+ id="edit-clientSecret"
607
+ type="text"
608
+ style={{ WebkitTextSecurity: 'disc' }}
609
+ value={(editFormData.config?.clientSecret as string) || ''}
610
+ onChange={(e) => updateConfig('clientSecret', e.target.value)}
611
+ placeholder="Client secret"
612
+ autoComplete="one-time-code"
613
+ data-1p-ignore
614
+ data-lpignore="true"
615
+ />
616
+ </div>
617
+ </div>
618
+ )}
619
+ </div>
620
+
621
+ <div className="space-y-2">
622
+ <Label htmlFor="edit-description">Description</Label>
623
+ <Textarea
624
+ id="edit-description"
625
+ value={editFormData.description || ''}
626
+ onChange={(e) => setEditFormData({ ...editFormData, description: e.target.value })}
627
+ placeholder="Optional description"
628
+ rows={2}
629
+ />
630
+ </div>
631
+
632
+ <div className="flex justify-end gap-2 pt-2">
633
+ <Button type="button" variant="outline" size="sm" onClick={onCancel}>
634
+ Cancel
635
+ </Button>
636
+ <Button type="submit" size="sm" disabled={isUpdating}>
637
+ {isUpdating ? 'Saving…' : 'Save Changes'}
638
+ </Button>
639
+ </div>
640
+ </form>
641
+ );
642
+ }
643
+
644
+ // ── OAuth2-aware test / connect section ──────────────────────────────
645
+
646
+ function OAuth2AwareTestSection({
647
+ credential,
648
+ onTest,
649
+ testingId,
650
+ testResult,
651
+ }: {
652
+ credential: Credential;
653
+ onTest: (id: string) => void;
654
+ testingId: string | null;
655
+ testResult: { success: boolean; error?: string } | null;
656
+ }) {
657
+ const needsOAuth2Connect =
658
+ credential.authType === 'oauth2' &&
659
+ credential.config?.oauth2Provider &&
660
+ credential.config?.clientId &&
661
+ !credential.config?.accessToken;
662
+
663
+ if (needsOAuth2Connect) {
664
+ return (
665
+ <OAuth2ConnectSection
666
+ credential={credential}
667
+ onTest={onTest}
668
+ testingId={testingId}
669
+ testResult={testResult}
670
+ />
671
+ );
672
+ }
673
+
674
+ return (
675
+ <div className="rounded-lg border border-border p-4 space-y-3">
676
+ <div className="flex items-center justify-between">
677
+ <div>
678
+ <p className="text-sm font-medium text-foreground">Test Connection</p>
679
+ <p className="text-xs text-muted-foreground">
680
+ Verify this credential is working correctly.
681
+ </p>
682
+ </div>
683
+ <Button
684
+ variant="outline"
685
+ size="sm"
686
+ onClick={() => onTest(credential.id)}
687
+ disabled={testingId === credential.id}
688
+ >
689
+ {testingId === credential.id ? (
690
+ <>
691
+ <Loader2 className="w-3.5 h-3.5 mr-1.5 animate-spin" />
692
+ Testing…
693
+ </>
694
+ ) : (
695
+ <>
696
+ <PlayCircle className="w-3.5 h-3.5 mr-1.5" />
697
+ Test
698
+ </>
699
+ )}
700
+ </Button>
701
+ </div>
702
+ {testResult && (
703
+ <div
704
+ className={`rounded-md px-3 py-2 text-sm ${
705
+ testResult.success ? 'bg-success/10 text-success' : 'bg-destructive/10 text-destructive'
706
+ }`}
707
+ >
708
+ {testResult.success
709
+ ? '✓ Connection successful'
710
+ : `✗ Failed: ${testResult.error ?? 'Unknown error'}`}
711
+ </div>
712
+ )}
713
+ </div>
714
+ );
715
+ }
716
+
717
+ function OAuth2ConnectSection({
718
+ credential,
719
+ onTest: _onTest,
720
+ testingId: _testingId,
721
+ testResult: _testResult,
722
+ }: {
723
+ credential: Credential;
724
+ onTest: (id: string) => void;
725
+ testingId: string | null;
726
+ testResult: { success: boolean; error?: string } | null;
727
+ }) {
728
+ const startOAuth2Flow = useStartOAuth2Flow();
729
+ const handleOAuth2Callback = useHandleOAuth2Callback();
730
+ const { data: providers } = useOAuth2Providers();
731
+ const [status, setStatus] = useState<'idle' | 'connecting' | 'success' | 'error'>('idle');
732
+ const [errorMessage, setErrorMessage] = useState<string | null>(null);
733
+ const [popupWindow, setPopupWindow] = useState<Window | null>(null);
734
+
735
+ // Listen for OAuth callback message from popup
736
+ useEffect(() => {
737
+ const handleMessage = async (event: MessageEvent) => {
738
+ if (event.origin !== window.location.origin) {
739
+ return;
740
+ }
741
+ const { type, code, state, error } = event.data;
742
+ if (type !== 'oauth2_callback') {
743
+ return;
744
+ }
745
+
746
+ if (popupWindow && !popupWindow.closed) {
747
+ popupWindow.close();
748
+ }
749
+ setPopupWindow(null);
750
+
751
+ if (error) {
752
+ setStatus('error');
753
+ setErrorMessage(error);
754
+ return;
755
+ }
756
+
757
+ if (!code || !state) {
758
+ setStatus('error');
759
+ setErrorMessage('Invalid OAuth callback — missing code or state');
760
+ return;
761
+ }
762
+
763
+ try {
764
+ await handleOAuth2Callback.mutateAsync({
765
+ code,
766
+ state,
767
+ // No secrets — backend resolves them from pending state
768
+ redirectUri: `${window.location.origin}/oauth/callback`,
769
+ });
770
+ setStatus('success');
771
+ setTimeout(() => setStatus('idle'), 2000);
772
+ } catch (err) {
773
+ setStatus('error');
774
+ setErrorMessage(err instanceof Error ? err.message : 'Failed to exchange OAuth code');
775
+ }
776
+ };
777
+
778
+ window.addEventListener('message', handleMessage);
779
+ return () => window.removeEventListener('message', handleMessage);
780
+ }, [popupWindow, handleOAuth2Callback]);
781
+
782
+ // Check if popup was closed without completing
783
+ useEffect(() => {
784
+ if (!popupWindow) {
785
+ return;
786
+ }
787
+ const check = setInterval(() => {
788
+ if (popupWindow.closed) {
789
+ clearInterval(check);
790
+ setPopupWindow(null);
791
+ if (status === 'connecting') {
792
+ setStatus('idle');
793
+ }
794
+ }
795
+ }, 500);
796
+ return () => clearInterval(check);
797
+ }, [popupWindow, status]);
798
+
799
+ const handleConnect = useCallback(async () => {
800
+ setStatus('connecting');
801
+ setErrorMessage(null);
802
+
803
+ try {
804
+ const result = await startOAuth2Flow.mutateAsync({
805
+ existingCredentialId: credential.id,
806
+ redirectUri: `${window.location.origin}/oauth/callback`,
807
+ returnUrl: window.location.href,
808
+ });
809
+
810
+ const width = 600;
811
+ const height = 700;
812
+ const left = window.screenX + (window.outerWidth - width) / 2;
813
+ const top = window.screenY + (window.outerHeight - height) / 2;
814
+
815
+ const popup = window.open(
816
+ result.authorizationUrl,
817
+ `oauth2_${credential.id}`,
818
+ `width=${width},height=${height},left=${left},top=${top},menubar=no,toolbar=no,location=no,status=no`,
819
+ );
820
+
821
+ if (!popup) {
822
+ throw new Error('Failed to open popup window. Please allow popups for this site.');
823
+ }
824
+
825
+ setPopupWindow(popup);
826
+ } catch (err) {
827
+ setStatus('error');
828
+ setErrorMessage(err instanceof Error ? err.message : 'Failed to start OAuth flow');
829
+ }
830
+ }, [credential, startOAuth2Flow]);
831
+
832
+ const providerName =
833
+ providers?.find((p) => p.id === credential.config?.oauth2Provider)?.name ??
834
+ (credential.config?.oauth2Provider as string) ??
835
+ 'OAuth2';
836
+
837
+ return (
838
+ <div className="rounded-lg border border-border p-4 space-y-3">
839
+ <div className="flex items-center justify-between">
840
+ <div>
841
+ <p className="text-sm font-medium text-foreground">Connect Account</p>
842
+ <p className="text-xs text-muted-foreground">
843
+ Authorize with {providerName} to obtain an access token.
844
+ </p>
845
+ </div>
846
+ <Button
847
+ variant="outline"
848
+ size="sm"
849
+ onClick={handleConnect}
850
+ disabled={status === 'connecting'}
851
+ >
852
+ {status === 'connecting' ? (
853
+ <>
854
+ <Loader2 className="w-3.5 h-3.5 mr-1.5 animate-spin" />
855
+ Connecting…
856
+ </>
857
+ ) : status === 'success' ? (
858
+ <>
859
+ <CheckCircle2 className="w-3.5 h-3.5 mr-1.5" />
860
+ Connected
861
+ </>
862
+ ) : (
863
+ <>
864
+ <ExternalLink className="w-3.5 h-3.5 mr-1.5" />
865
+ Connect
866
+ </>
867
+ )}
868
+ </Button>
869
+ </div>
870
+ {status === 'error' && errorMessage && (
871
+ <div className="rounded-md px-3 py-2 text-sm bg-destructive/10 text-destructive">
872
+ ✗ {errorMessage}
873
+ </div>
874
+ )}
875
+ {status === 'success' && (
876
+ <div className="rounded-md px-3 py-2 text-sm bg-success/10 text-success">
877
+ ✓ Account connected successfully. You can now test the connection.
878
+ </div>
879
+ )}
880
+ </div>
881
+ );
882
+ }