@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,399 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { X } from 'lucide-react';
3
+ import { Button } from '../ui/button';
4
+ import { Input } from '../ui/input';
5
+ import { Label } from '../ui/label';
6
+ import { Textarea } from '../ui/textarea';
7
+ import type {
8
+ Credential,
9
+ UpdateCredentialInput,
10
+ CredentialAuthType,
11
+ CredentialType,
12
+ } from '../../api/types';
13
+
14
+ interface EditCredentialModalProps {
15
+ credential: Credential;
16
+ open: boolean;
17
+ onClose: () => void;
18
+ onSubmit: (data: UpdateCredentialInput) => void;
19
+ isLoading?: boolean;
20
+ }
21
+
22
+ const ALL_AUTH_TYPES: { value: CredentialAuthType; label: string }[] = [
23
+ { value: 'bearer', label: 'Bearer Token' },
24
+ { value: 'apiKey', label: 'API Key' },
25
+ { value: 'basic', label: 'Basic Auth' },
26
+ { value: 'oauth2', label: 'OAuth2' },
27
+ { value: 'custom', label: 'Custom Headers' },
28
+ { value: 'awsSigV4', label: 'AWS Signature V4' },
29
+ { value: 'jwt', label: 'JWT' },
30
+ { value: 'connectionString', label: 'Connection String' },
31
+ ];
32
+
33
+ function getAuthTypesForType(type: CredentialType) {
34
+ if (type === 'database') {
35
+ return ALL_AUTH_TYPES.filter((t) => ['basic', 'connectionString', 'oauth2'].includes(t.value));
36
+ }
37
+ if (type === 'llm') {
38
+ return ALL_AUTH_TYPES.filter((t) => ['apiKey', 'bearer'].includes(t.value));
39
+ }
40
+ // http-api
41
+ return ALL_AUTH_TYPES.filter((t) => !['connectionString'].includes(t.value));
42
+ }
43
+
44
+ export const EditCredentialModal: React.FC<EditCredentialModalProps> = ({
45
+ credential,
46
+ open,
47
+ onClose,
48
+ onSubmit,
49
+ isLoading,
50
+ }) => {
51
+ const [formData, setFormData] = useState<UpdateCredentialInput>({
52
+ name: credential.name,
53
+ type: credential.type,
54
+ authType: credential.authType,
55
+ description: credential.description,
56
+ isActive: credential.isActive,
57
+ config: credential.config || {},
58
+ metadata: credential.metadata || {},
59
+ });
60
+
61
+ useEffect(() => {
62
+ setFormData({
63
+ name: credential.name,
64
+ type: credential.type,
65
+ authType: credential.authType,
66
+ description: credential.description,
67
+ isActive: credential.isActive,
68
+ config: credential.config || {},
69
+ metadata: credential.metadata || {},
70
+ });
71
+ }, [credential]);
72
+
73
+ const handleSubmit = (e: React.FormEvent) => {
74
+ e.preventDefault();
75
+ onSubmit(formData);
76
+ };
77
+
78
+ const updateConfig = (key: string, value: string) => {
79
+ setFormData((prev) => ({
80
+ ...prev,
81
+ config: { ...prev.config, [key]: value },
82
+ }));
83
+ };
84
+
85
+ if (!open) {
86
+ return null;
87
+ }
88
+
89
+ return (
90
+ <div className="fixed inset-0 z-50">
91
+ <div className="fixed inset-0 bg-background/80" onClick={onClose} />
92
+ <div className="fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] z-50 w-full max-w-2xl">
93
+ <div className="grid w-full gap-4 border border-border bg-background p-6 shadow-lg sm:rounded-lg max-h-[90vh] overflow-y-auto">
94
+ <div className="flex items-center justify-between">
95
+ <h2 className="text-lg font-semibold">Edit Credential</h2>
96
+ <button
97
+ onClick={onClose}
98
+ className="rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
99
+ >
100
+ <X className="h-4 w-4" />
101
+ <span className="sr-only">Close</span>
102
+ </button>
103
+ </div>
104
+
105
+ <form
106
+ onSubmit={handleSubmit}
107
+ className="space-y-4"
108
+ autoComplete="one-time-code"
109
+ data-lpignore="true"
110
+ >
111
+ {/* Name */}
112
+ <div className="space-y-2">
113
+ <Label htmlFor="name">Name *</Label>
114
+ <Input
115
+ id="name"
116
+ value={formData.name}
117
+ onChange={(e) => setFormData({ ...formData, name: e.target.value })}
118
+ placeholder="My Stripe Production"
119
+ required
120
+ />
121
+ </div>
122
+
123
+ {/* Credential Type */}
124
+ <div className="space-y-2">
125
+ <Label htmlFor="type">Credential Type *</Label>
126
+ <select
127
+ id="type"
128
+ value={formData.type}
129
+ onChange={(e) => {
130
+ const newType = e.target.value as CredentialType;
131
+ if (newType === 'llm') {
132
+ setFormData({ ...formData, type: newType, authType: 'apiKey' });
133
+ } else {
134
+ const available = getAuthTypesForType(newType);
135
+ const nextAuthType = available.some((t) => t.value === formData.authType)
136
+ ? formData.authType
137
+ : available[0]?.value || 'basic';
138
+ setFormData({ ...formData, type: newType, authType: nextAuthType });
139
+ }
140
+ }}
141
+ className="flex h-10 w-full rounded-md border border-input bg-background dark:bg-input/30 px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
142
+ required
143
+ >
144
+ <option value="http-api">HTTP API</option>
145
+ <option value="llm">LLM Provider</option>
146
+ <option value="database">Database</option>
147
+ </select>
148
+ </div>
149
+
150
+ {/* Auth Type (hidden for LLM — always apiKey) */}
151
+ {formData.type !== 'llm' && (
152
+ <div className="space-y-2">
153
+ <Label htmlFor="authType">Authentication Type *</Label>
154
+ <select
155
+ id="authType"
156
+ value={formData.authType}
157
+ onChange={(e) =>
158
+ setFormData({ ...formData, authType: e.target.value as CredentialAuthType })
159
+ }
160
+ className="flex h-10 w-full rounded-md border border-input bg-background dark:bg-input/30 px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
161
+ required
162
+ >
163
+ {getAuthTypesForType(formData.type || 'http-api').map((type) => (
164
+ <option key={type.value} value={type.value}>
165
+ {type.label}
166
+ </option>
167
+ ))}
168
+ </select>
169
+ </div>
170
+ )}
171
+
172
+ {/* Active Status */}
173
+ <div className="flex items-center gap-2">
174
+ <input
175
+ type="checkbox"
176
+ id="isActive"
177
+ checked={formData.isActive}
178
+ onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}
179
+ className="h-4 w-4 rounded border-border"
180
+ />
181
+ <Label htmlFor="isActive" className="cursor-pointer">
182
+ Active
183
+ </Label>
184
+ </div>
185
+
186
+ {/* LLM Provider selector (only shown for LLM type) */}
187
+ {formData.type === 'llm' && (
188
+ <div className="space-y-2">
189
+ <Label htmlFor="edit-llmProvider">LLM Provider</Label>
190
+ <select
191
+ id="edit-llmProvider"
192
+ value={(formData.metadata?.provider as string) || ''}
193
+ onChange={(e) =>
194
+ setFormData({
195
+ ...formData,
196
+ metadata: { ...formData.metadata, provider: e.target.value },
197
+ })
198
+ }
199
+ className="flex h-10 w-full rounded-md border border-input bg-background dark:bg-input/30 px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
200
+ >
201
+ <option value="">Select a provider…</option>
202
+ <option value="openai">OpenAI</option>
203
+ <option value="anthropic">Anthropic</option>
204
+ <option value="openrouter">OpenRouter</option>
205
+ </select>
206
+ </div>
207
+ )}
208
+
209
+ {/* Config fields based on auth type */}
210
+ <div className="space-y-4 p-4 bg-muted rounded-lg">
211
+ <h3 className="font-medium text-sm">Credentials</h3>
212
+ <p className="text-xs text-muted-foreground">
213
+ Leave fields empty to keep existing values
214
+ </p>
215
+
216
+ {/* LLM: plain API key only */}
217
+ {formData.type === 'llm' && (
218
+ <div className="space-y-2">
219
+ <Label htmlFor="apiKey">API Key</Label>
220
+ <Input
221
+ id="apiKey"
222
+ type="text"
223
+ style={{ WebkitTextSecurity: 'disc' }}
224
+ value={(formData.config?.apiKey as string) || ''}
225
+ onChange={(e) => updateConfig('apiKey', e.target.value)}
226
+ placeholder="Enter API key or leave empty to keep current"
227
+ autoComplete="one-time-code"
228
+ data-1p-ignore
229
+ data-lpignore="true"
230
+ />
231
+ </div>
232
+ )}
233
+
234
+ {formData.type !== 'llm' && formData.authType === 'bearer' && (
235
+ <div className="space-y-2">
236
+ <Label htmlFor="token">Token</Label>
237
+ <Input
238
+ id="token"
239
+ type="text"
240
+ style={{ WebkitTextSecurity: 'disc' }}
241
+ value={(formData.config?.token as string) || ''}
242
+ onChange={(e) => updateConfig('token', e.target.value)}
243
+ placeholder="Enter new bearer token or leave empty"
244
+ autoComplete="one-time-code"
245
+ data-1p-ignore
246
+ data-lpignore="true"
247
+ />
248
+ </div>
249
+ )}
250
+
251
+ {formData.type !== 'llm' && formData.authType === 'apiKey' && (
252
+ <>
253
+ <div className="space-y-2">
254
+ <Label htmlFor="apiKey">API Key</Label>
255
+ <Input
256
+ id="apiKey"
257
+ type="text"
258
+ style={{ WebkitTextSecurity: 'disc' }}
259
+ value={(formData.config?.apiKey as string) || ''}
260
+ onChange={(e) => updateConfig('apiKey', e.target.value)}
261
+ placeholder="Enter new API key or leave empty"
262
+ autoComplete="one-time-code"
263
+ data-1p-ignore
264
+ data-lpignore="true"
265
+ />
266
+ </div>
267
+ <div className="space-y-2">
268
+ <Label htmlFor="location">Location</Label>
269
+ <select
270
+ id="location"
271
+ value={(formData.config?.location as string) || 'header'}
272
+ onChange={(e) => updateConfig('location', e.target.value)}
273
+ className="flex h-10 w-full rounded-md border border-input bg-background dark:bg-input/30 px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
274
+ >
275
+ <option value="header">Header</option>
276
+ <option value="query">Query Parameter</option>
277
+ </select>
278
+ </div>
279
+ <div className="space-y-2">
280
+ <Label htmlFor="paramName">Parameter Name</Label>
281
+ <Input
282
+ id="paramName"
283
+ value={(formData.config?.paramName as string) || ''}
284
+ onChange={(e) => updateConfig('paramName', e.target.value)}
285
+ placeholder="X-API-Key"
286
+ autoComplete="one-time-code"
287
+ data-1p-ignore
288
+ data-lpignore="true"
289
+ />
290
+ </div>
291
+ </>
292
+ )}
293
+
294
+ {formData.authType === 'connectionString' && (
295
+ <div className="space-y-2">
296
+ <Label htmlFor="connectionString">Connection String</Label>
297
+ <Input
298
+ id="connectionString"
299
+ type="text"
300
+ style={{ WebkitTextSecurity: 'disc' }}
301
+ value={(formData.config?.connectionString as string) || ''}
302
+ onChange={(e) => updateConfig('connectionString', e.target.value)}
303
+ placeholder="postgres://user:pass@host:5432/dbname?sslmode=require"
304
+ autoComplete="one-time-code"
305
+ data-1p-ignore
306
+ data-lpignore="true"
307
+ />
308
+ </div>
309
+ )}
310
+
311
+ {formData.authType === 'basic' && (
312
+ <>
313
+ <div className="space-y-2">
314
+ <Label htmlFor="username">Username</Label>
315
+ <Input
316
+ id="username"
317
+ value={(formData.config?.username as string) || ''}
318
+ onChange={(e) => updateConfig('username', e.target.value)}
319
+ placeholder="Enter new username or leave empty"
320
+ autoComplete="one-time-code"
321
+ data-1p-ignore
322
+ data-lpignore="true"
323
+ />
324
+ </div>
325
+ <div className="space-y-2">
326
+ <Label htmlFor="password">Password</Label>
327
+ <Input
328
+ id="password"
329
+ type="text"
330
+ style={{ WebkitTextSecurity: 'disc' }}
331
+ value={(formData.config?.password as string) || ''}
332
+ onChange={(e) => updateConfig('password', e.target.value)}
333
+ placeholder="Enter new password or leave empty"
334
+ autoComplete="one-time-code"
335
+ data-1p-ignore
336
+ data-lpignore="true"
337
+ />
338
+ </div>
339
+ </>
340
+ )}
341
+
342
+ {formData.authType === 'oauth2' && (
343
+ <>
344
+ <div className="space-y-2">
345
+ <Label htmlFor="clientId">Client ID</Label>
346
+ <Input
347
+ id="clientId"
348
+ value={(formData.config?.clientId as string) || ''}
349
+ onChange={(e) => updateConfig('clientId', e.target.value)}
350
+ placeholder="Enter client ID or leave empty"
351
+ autoComplete="one-time-code"
352
+ data-1p-ignore
353
+ data-lpignore="true"
354
+ />
355
+ </div>
356
+ <div className="space-y-2">
357
+ <Label htmlFor="clientSecret">Client Secret</Label>
358
+ <Input
359
+ id="clientSecret"
360
+ type="text"
361
+ style={{ WebkitTextSecurity: 'disc' }}
362
+ value={(formData.config?.clientSecret as string) || ''}
363
+ onChange={(e) => updateConfig('clientSecret', e.target.value)}
364
+ placeholder="Enter client secret or leave empty"
365
+ autoComplete="one-time-code"
366
+ data-1p-ignore
367
+ data-lpignore="true"
368
+ />
369
+ </div>
370
+ </>
371
+ )}
372
+ </div>
373
+
374
+ {/* Description */}
375
+ <div className="space-y-2">
376
+ <Label htmlFor="description">Description</Label>
377
+ <Textarea
378
+ id="description"
379
+ value={formData.description || ''}
380
+ onChange={(e) => setFormData({ ...formData, description: e.target.value })}
381
+ placeholder="Optional description for this credential"
382
+ rows={3}
383
+ />
384
+ </div>
385
+
386
+ <div className="flex justify-end gap-2 pt-4">
387
+ <Button type="button" variant="outline" onClick={onClose}>
388
+ Cancel
389
+ </Button>
390
+ <Button type="submit" disabled={isLoading}>
391
+ {isLoading ? 'Saving...' : 'Save Changes'}
392
+ </Button>
393
+ </div>
394
+ </form>
395
+ </div>
396
+ </div>
397
+ </div>
398
+ );
399
+ };
@@ -0,0 +1,288 @@
1
+ /**
2
+ * OAuth2 Connect Button Component
3
+ *
4
+ * A button that initiates OAuth2 authorization flow for a specific provider.
5
+ * Opens a popup window for the user to authorize, then handles the callback.
6
+ */
7
+
8
+ import React, { useState, useCallback, useEffect, useRef } from 'react';
9
+ import { Button } from '../ui/button';
10
+ import { Loader2, ExternalLink, CheckCircle2, AlertCircle } from 'lucide-react';
11
+ import { cn } from '../../lib/utils';
12
+ import { useHandleOAuth2Callback, useStartOAuth2Flow } from '../../api/credentials.api';
13
+ import type { OAuth2ProviderDefinition, Credential } from '../../api/types';
14
+
15
+ export interface OAuth2ConnectButtonProps {
16
+ /** The OAuth2 provider to connect to */
17
+ provider: OAuth2ProviderDefinition;
18
+ /** OAuth2 client ID (from your app's OAuth configuration) */
19
+ clientId: string;
20
+ /** OAuth2 client secret (from your app's OAuth configuration) */
21
+ clientSecret: string;
22
+ /** Redirect URI registered with the OAuth provider */
23
+ redirectUri: string;
24
+ /** Optional: Custom scopes to request (defaults to provider's default scopes) */
25
+ scopes?: string[];
26
+ /** Optional: Custom name for the created credential */
27
+ credentialName?: string;
28
+ /** Called when credential is successfully created */
29
+ onSuccess?: (credential: Credential) => void;
30
+ /** Called when an error occurs */
31
+ onError?: (error: Error) => void;
32
+ /** Button variant */
33
+ variant?: 'default' | 'outline' | 'secondary' | 'ghost';
34
+ /** Button size */
35
+ size?: 'default' | 'sm' | 'lg' | 'icon';
36
+ /** Additional CSS classes */
37
+ className?: string;
38
+ /** Disabled state */
39
+ disabled?: boolean;
40
+ /** Children to render inside button (defaults to "Connect with {provider.name}") */
41
+ children?: React.ReactNode;
42
+ }
43
+
44
+ type ConnectionStatus = 'idle' | 'connecting' | 'success' | 'error';
45
+
46
+ export function OAuth2ConnectButton({
47
+ provider,
48
+ clientId,
49
+ clientSecret,
50
+ redirectUri,
51
+ scopes,
52
+ credentialName,
53
+ onSuccess,
54
+ onError,
55
+ variant = 'outline',
56
+ size = 'default',
57
+ className,
58
+ disabled,
59
+ children,
60
+ }: OAuth2ConnectButtonProps) {
61
+ const startOAuth2FlowMutation = useStartOAuth2Flow();
62
+ const handleOAuth2CallbackMutation = useHandleOAuth2Callback();
63
+ const [status, setStatus] = useState<ConnectionStatus>('idle');
64
+ const [errorMessage, setErrorMessage] = useState<string | null>(null);
65
+ const [popupWindow, setPopupWindow] = useState<Window | null>(null);
66
+
67
+ // Store callback params in refs so we can access them in the message handler
68
+ const callbackParamsRef = useRef({ clientId, clientSecret, redirectUri });
69
+ useEffect(() => {
70
+ callbackParamsRef.current = { clientId, clientSecret, redirectUri };
71
+ }, [clientId, clientSecret, redirectUri]);
72
+
73
+ // Store callbacks in refs to avoid stale closures in the message handler
74
+ const onSuccessRef = useRef(onSuccess);
75
+ const onErrorRef = useRef(onError);
76
+ useEffect(() => {
77
+ onSuccessRef.current = onSuccess;
78
+ onErrorRef.current = onError;
79
+ }, [onSuccess, onError]);
80
+
81
+ // Listen for OAuth callback message from popup
82
+ useEffect(() => {
83
+ const handleMessage = async (event: MessageEvent) => {
84
+ // Verify origin for security
85
+ if (event.origin !== window.location.origin) {
86
+ return;
87
+ }
88
+
89
+ const { type, code, state, error } = event.data;
90
+
91
+ if (type !== 'oauth2_callback') {
92
+ return;
93
+ }
94
+
95
+ // Close the popup
96
+ if (popupWindow && !popupWindow.closed) {
97
+ popupWindow.close();
98
+ }
99
+ setPopupWindow(null);
100
+
101
+ if (error) {
102
+ setStatus('error');
103
+ setErrorMessage(error);
104
+ onErrorRef.current?.(new Error(error));
105
+ return;
106
+ }
107
+
108
+ if (!code || !state) {
109
+ setStatus('error');
110
+ setErrorMessage('Invalid OAuth callback - missing code or state');
111
+ onErrorRef.current?.(new Error('Invalid OAuth callback'));
112
+ return;
113
+ }
114
+
115
+ // Exchange code for tokens using the mutation (which invalidates credentials cache)
116
+ try {
117
+ const params = callbackParamsRef.current;
118
+ const credential = await handleOAuth2CallbackMutation.mutateAsync({
119
+ code,
120
+ state,
121
+ clientId: params.clientId,
122
+ clientSecret: params.clientSecret,
123
+ redirectUri: params.redirectUri,
124
+ });
125
+
126
+ setStatus('success');
127
+ onSuccessRef.current?.(credential);
128
+
129
+ // Reset to idle after showing success
130
+ setTimeout(() => setStatus('idle'), 2000);
131
+ } catch (err) {
132
+ setStatus('error');
133
+ const message = err instanceof Error ? err.message : 'Failed to exchange OAuth code';
134
+ setErrorMessage(message);
135
+ onErrorRef.current?.(err instanceof Error ? err : new Error(message));
136
+ }
137
+ };
138
+
139
+ window.addEventListener('message', handleMessage);
140
+ return () => window.removeEventListener('message', handleMessage);
141
+ }, [popupWindow, handleOAuth2CallbackMutation]);
142
+
143
+ // Check if popup was closed without completing
144
+ useEffect(() => {
145
+ if (!popupWindow) {
146
+ return;
147
+ }
148
+
149
+ const checkClosed = setInterval(() => {
150
+ if (popupWindow.closed) {
151
+ clearInterval(checkClosed);
152
+ setPopupWindow(null);
153
+ if (status === 'connecting') {
154
+ setStatus('idle');
155
+ }
156
+ }
157
+ }, 500);
158
+
159
+ return () => clearInterval(checkClosed);
160
+ }, [popupWindow, status]);
161
+
162
+ const handleConnect = useCallback(async () => {
163
+ setStatus('connecting');
164
+ setErrorMessage(null);
165
+
166
+ try {
167
+ // Start OAuth flow to get authorization URL
168
+ const result = await startOAuth2FlowMutation.mutateAsync({
169
+ providerId: provider.id,
170
+ clientId,
171
+ clientSecret,
172
+ redirectUri,
173
+ scopes,
174
+ credentialName,
175
+ returnUrl: window.location.href,
176
+ });
177
+
178
+ // Open popup window for OAuth
179
+ const width = 600;
180
+ const height = 700;
181
+ const left = window.screenX + (window.outerWidth - width) / 2;
182
+ const top = window.screenY + (window.outerHeight - height) / 2;
183
+
184
+ const popup = window.open(
185
+ result.authorizationUrl,
186
+ `oauth2_${provider.id}`,
187
+ `width=${width},height=${height},left=${left},top=${top},menubar=no,toolbar=no,location=no,status=no`,
188
+ );
189
+
190
+ if (!popup) {
191
+ throw new Error('Failed to open popup window. Please allow popups for this site.');
192
+ }
193
+
194
+ setPopupWindow(popup);
195
+ } catch (err) {
196
+ setStatus('error');
197
+ const message = err instanceof Error ? err.message : 'Failed to start OAuth flow';
198
+ setErrorMessage(message);
199
+ onError?.(err instanceof Error ? err : new Error(message));
200
+ }
201
+ }, [
202
+ startOAuth2FlowMutation,
203
+ provider.id,
204
+ clientId,
205
+ clientSecret,
206
+ redirectUri,
207
+ scopes,
208
+ credentialName,
209
+ onError,
210
+ ]);
211
+
212
+ const isDisabled = disabled || status === 'connecting';
213
+
214
+ return (
215
+ <div className="flex flex-col gap-1">
216
+ <Button
217
+ type="button"
218
+ variant={variant}
219
+ size={size}
220
+ onClick={handleConnect}
221
+ disabled={isDisabled}
222
+ className={cn(
223
+ 'gap-2',
224
+ status === 'success' && 'bg-success/10 border-success/50 text-success',
225
+ status === 'error' && 'bg-destructive/10 border-destructive/50 text-destructive',
226
+ className,
227
+ )}
228
+ >
229
+ {status === 'connecting' && <Loader2 className="w-4 h-4 animate-spin" />}
230
+ {status === 'success' && <CheckCircle2 className="w-4 h-4" />}
231
+ {status === 'error' && <AlertCircle className="w-4 h-4" />}
232
+ {status === 'idle' && <ExternalLink className="w-4 h-4" />}
233
+
234
+ {children ??
235
+ (status === 'success'
236
+ ? 'Connected!'
237
+ : status === 'error'
238
+ ? 'Connection Failed'
239
+ : `Connect with ${provider.name}`)}
240
+ </Button>
241
+
242
+ {status === 'error' && errorMessage && (
243
+ <p className="text-xs text-destructive">{errorMessage}</p>
244
+ )}
245
+ </div>
246
+ );
247
+ }
248
+
249
+ /**
250
+ * OAuth2 Callback Handler Component
251
+ *
252
+ * Place this component on your OAuth callback page.
253
+ * It extracts the code/state from URL and sends it to the parent window.
254
+ */
255
+ export function OAuth2CallbackHandler() {
256
+ useEffect(() => {
257
+ const params = new URLSearchParams(window.location.search);
258
+ const code = params.get('code');
259
+ const state = params.get('state');
260
+ const error = params.get('error');
261
+ const errorDescription = params.get('error_description');
262
+
263
+ // Send message to parent window
264
+ if (window.opener) {
265
+ window.opener.postMessage(
266
+ {
267
+ type: 'oauth2_callback',
268
+ code,
269
+ state,
270
+ error: error || errorDescription,
271
+ },
272
+ window.location.origin,
273
+ );
274
+ }
275
+
276
+ // Close this window after a short delay
277
+ setTimeout(() => window.close(), 100);
278
+ }, []);
279
+
280
+ return (
281
+ <div className="flex items-center justify-center min-h-screen">
282
+ <div className="text-center">
283
+ <Loader2 className="w-8 h-8 mx-auto mb-4 animate-spin text-muted-foreground" />
284
+ <p className="text-sm text-muted-foreground">Completing authorization...</p>
285
+ </div>
286
+ </div>
287
+ );
288
+ }