@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,217 @@
1
+ import { useMemo, useState } from 'react';
2
+ import { ChevronsUpDown, Check, Loader2, Plus, RefreshCw, XCircle, Pencil } from 'lucide-react';
3
+ import { Button } from '../../ui/button';
4
+ import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover';
5
+ import {
6
+ Command,
7
+ CommandEmpty,
8
+ CommandGroup,
9
+ CommandInput,
10
+ CommandItem,
11
+ CommandList,
12
+ } from '../../ui/command';
13
+ import { ProviderIcon } from '../../shared/ProviderIcon';
14
+ import type { Credential } from '../../../api/types';
15
+ import { cn } from '../../../lib/utils';
16
+ import { getCredentialBranding } from '../../../utils/credentialBranding';
17
+
18
+ const NO_CREDENTIAL_VALUE = '__invect_no_credential__';
19
+
20
+ interface Props {
21
+ credentials: Credential[];
22
+ value: string;
23
+ onChange: (value: string) => void;
24
+ placeholder?: string;
25
+ isLoading: boolean;
26
+ isError: boolean;
27
+ onRetry: () => void;
28
+ onAddNew: () => void;
29
+ onEditCredential?: (credential: Credential) => void;
30
+ onRefreshOAuthCredential?: (credential: Credential) => void;
31
+ /** ID of the credential currently being refreshed */
32
+ refreshingCredentialId?: string | null;
33
+ container?: HTMLElement | null;
34
+ disablePortal?: boolean;
35
+ /** Custom label for the add button (default: "Add new credential") */
36
+ addButtonLabel?: string;
37
+ }
38
+
39
+ export function CredentialCombobox({
40
+ credentials,
41
+ value,
42
+ onChange,
43
+ placeholder = 'Select credential',
44
+ isLoading,
45
+ isError,
46
+ onRetry,
47
+ onAddNew,
48
+ onEditCredential,
49
+ onRefreshOAuthCredential,
50
+ refreshingCredentialId,
51
+ container,
52
+ disablePortal = true,
53
+ addButtonLabel = 'Add new credential',
54
+ }: Props) {
55
+ const [open, setOpen] = useState(false);
56
+ const selectedCredential = useMemo(
57
+ () => credentials.find((cred) => cred.id === value),
58
+ [credentials, value],
59
+ );
60
+ const selectedCredentialBranding = useMemo(
61
+ () => (selectedCredential ? getCredentialBranding(selectedCredential) : null),
62
+ [selectedCredential],
63
+ );
64
+
65
+ const handleSelect = (nextValue: string) => {
66
+ const normalizedValue = nextValue === NO_CREDENTIAL_VALUE ? '' : nextValue;
67
+ onChange(normalizedValue);
68
+ setOpen(false);
69
+ };
70
+
71
+ return (
72
+ <Popover open={open} onOpenChange={setOpen}>
73
+ <PopoverTrigger asChild>
74
+ <Button
75
+ variant="outline"
76
+ role="combobox"
77
+ aria-expanded={open}
78
+ className="justify-between gap-2 w-full font-mono text-xs"
79
+ >
80
+ <span className="flex min-w-0 items-center gap-2 overflow-hidden">
81
+ {selectedCredential && selectedCredentialBranding ? (
82
+ <ProviderIcon
83
+ providerId={selectedCredentialBranding.providerId}
84
+ icon={selectedCredentialBranding.icon}
85
+ className="w-3.5 h-3.5 shrink-0 text-muted-foreground"
86
+ />
87
+ ) : null}
88
+ <span className="truncate">
89
+ {selectedCredential ? selectedCredential.name : placeholder}
90
+ </span>
91
+ </span>
92
+ <ChevronsUpDown className="w-4 h-4 opacity-50" />
93
+ </Button>
94
+ </PopoverTrigger>
95
+ <PopoverContent
96
+ className="p-0"
97
+ align="start"
98
+ container={container}
99
+ disablePortal={disablePortal}
100
+ >
101
+ <Command>
102
+ <CommandInput
103
+ className="h-8 border-0 rounded-none py-1 font-mono text-xs shadow-none focus:outline-none focus:ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
104
+ placeholder="Search credentials..."
105
+ />
106
+ <CommandList>
107
+ {isLoading && (
108
+ <div className="flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground">
109
+ <Loader2 className="w-4 h-4 animate-spin" />
110
+ Loading credentials...
111
+ </div>
112
+ )}
113
+ {isError && !isLoading && (
114
+ <CommandEmpty>
115
+ <div className="flex flex-col items-center gap-2 text-sm">
116
+ <XCircle className="w-4 h-4 text-destructive" />
117
+ <span>Failed to load credentials.</span>
118
+ <Button variant="ghost" size="sm" className="mt-1" onClick={onRetry}>
119
+ <RefreshCw className="w-4 h-4 mr-2" /> Retry
120
+ </Button>
121
+ </div>
122
+ </CommandEmpty>
123
+ )}
124
+ {!isLoading && !isError && credentials.length === 0 && (
125
+ <CommandEmpty>No credentials found.</CommandEmpty>
126
+ )}
127
+ {!isLoading && !isError && (
128
+ <>
129
+ <CommandGroup>
130
+ <CommandItem
131
+ value={NO_CREDENTIAL_VALUE}
132
+ onSelect={handleSelect}
133
+ className="flex items-center gap-2 font-mono text-xs"
134
+ >
135
+ <Check className={cn('h-4 w-4', value === '' ? 'opacity-100' : 'opacity-0')} />
136
+ No credential
137
+ </CommandItem>
138
+ {credentials.map((credential) => {
139
+ const branding = getCredentialBranding(credential);
140
+ const isOAuth = credential.authType === 'oauth2';
141
+ const isRefreshing = refreshingCredentialId === credential.id;
142
+
143
+ return (
144
+ <CommandItem
145
+ key={credential.id}
146
+ value={credential.id}
147
+ onSelect={handleSelect}
148
+ className="flex items-center gap-2 font-mono text-xs group"
149
+ >
150
+ <Check
151
+ className={cn(
152
+ 'h-4 w-4 shrink-0',
153
+ credential.id === value ? 'opacity-100' : 'opacity-0',
154
+ )}
155
+ />
156
+ <ProviderIcon
157
+ providerId={branding.providerId}
158
+ icon={branding.icon}
159
+ className="w-3.5 h-3.5 shrink-0 text-muted-foreground"
160
+ />
161
+ <span className="truncate flex-1">{credential.name}</span>
162
+ <span className="flex items-center gap-0.5 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">
163
+ {isOAuth && (
164
+ <button
165
+ type="button"
166
+ className={cn(
167
+ 'p-0.5 rounded hover:bg-accent text-muted-foreground hover:text-foreground',
168
+ isRefreshing && 'pointer-events-none',
169
+ )}
170
+ title="Re-authorize OAuth credential"
171
+ onClick={(e) => {
172
+ e.stopPropagation();
173
+ onRefreshOAuthCredential?.(credential);
174
+ }}
175
+ >
176
+ <RefreshCw
177
+ className={cn('h-3 w-3', isRefreshing && 'animate-spin')}
178
+ />
179
+ </button>
180
+ )}
181
+ <button
182
+ type="button"
183
+ className="p-0.5 rounded hover:bg-accent text-muted-foreground hover:text-foreground"
184
+ title="Edit credential"
185
+ onClick={(e) => {
186
+ e.stopPropagation();
187
+ setOpen(false);
188
+ onEditCredential?.(credential);
189
+ }}
190
+ >
191
+ <Pencil className="h-3 w-3" />
192
+ </button>
193
+ </span>
194
+ </CommandItem>
195
+ );
196
+ })}
197
+ </CommandGroup>
198
+ <div className="p-2 border-t">
199
+ <Button
200
+ onClick={() => {
201
+ setOpen(false);
202
+ onAddNew();
203
+ }}
204
+ className="w-full"
205
+ size="sm"
206
+ >
207
+ <Plus className="w-4 h-4 mr-2" /> {addButtonLabel}
208
+ </Button>
209
+ </div>
210
+ </>
211
+ )}
212
+ </CommandList>
213
+ </Command>
214
+ </PopoverContent>
215
+ </Popover>
216
+ );
217
+ }
@@ -0,0 +1,154 @@
1
+ import { useCallback } from 'react';
2
+ import { Label } from '../../ui/label';
3
+ import { Button } from '../../ui/button';
4
+ import { Code2, Type } from 'lucide-react';
5
+ import type { NodeParamField } from '../../../types/node-definition.types';
6
+ import type { Credential } from '../../../api/types';
7
+ import { CredentialCombobox } from './CredentialCombobox';
8
+ import { DroppableInput } from './DroppableInput';
9
+ import { cn } from '../../../lib/utils';
10
+ import { filterCredentialsForField } from '../../../utils/credentialFiltering';
11
+
12
+ interface CredentialsSectionProps {
13
+ fields: NodeParamField[];
14
+ formValues: Record<string, unknown>;
15
+ onFieldChange: (fieldName: string, value: string) => void;
16
+ credentials: Credential[];
17
+ isLoading: boolean;
18
+ isError: boolean;
19
+ onRefresh: () => void;
20
+ onAddNewCredential: (fieldName: string) => void;
21
+ onEditCredential?: (credential: Credential) => void;
22
+ onRefreshOAuthCredential?: (credential: Credential) => void;
23
+ refreshingCredentialId?: string | null;
24
+ portalContainer?: HTMLElement | null;
25
+ disablePortal?: boolean;
26
+ }
27
+
28
+ /**
29
+ * Get the template modes object from form values.
30
+ */
31
+ function getTemplateModes(formValues: Record<string, unknown>): Record<string, boolean> {
32
+ const modes = formValues._templateModes;
33
+ if (modes && typeof modes === 'object' && !Array.isArray(modes)) {
34
+ return modes as Record<string, boolean>;
35
+ }
36
+ return {};
37
+ }
38
+
39
+ export const CredentialsSection = ({
40
+ fields,
41
+ formValues,
42
+ onFieldChange,
43
+ credentials,
44
+ isLoading,
45
+ isError,
46
+ onRefresh,
47
+ onAddNewCredential,
48
+ onEditCredential,
49
+ onRefreshOAuthCredential,
50
+ refreshingCredentialId,
51
+ portalContainer,
52
+ disablePortal = true,
53
+ }: CredentialsSectionProps) => {
54
+ const templateModes = getTemplateModes(formValues);
55
+
56
+ const handleTemplateModeChange = useCallback(
57
+ (fieldName: string, enabled: boolean) => {
58
+ const currentModes = getTemplateModes(formValues);
59
+ const updatedModes = {
60
+ ...currentModes,
61
+ [fieldName]: enabled,
62
+ };
63
+ // We need to use a generic field change for _templateModes
64
+ // Since onFieldChange expects string value, we'll use a workaround
65
+ // by storing it in formValues through a parent handler
66
+ (onFieldChange as (fieldName: string, value: unknown) => void)(
67
+ '_templateModes',
68
+ updatedModes,
69
+ );
70
+ },
71
+ [formValues, onFieldChange],
72
+ );
73
+
74
+ if (!fields.length) {
75
+ return null;
76
+ }
77
+
78
+ return (
79
+ <div className="flex flex-col gap-3 pb-3">
80
+ {isLoading && <div className="text-[11px] text-muted-foreground">Loading credentials…</div>}
81
+ {isError && !isLoading && (
82
+ <div className="text-[11px] text-destructive">
83
+ Failed to load credentials. Please try again.
84
+ </div>
85
+ )}
86
+ {fields.map((field) => {
87
+ const isTemplateMode = templateModes[field.name] ?? false;
88
+ const fieldCredentials = filterCredentialsForField(credentials, field);
89
+
90
+ const templateModeToggle = (
91
+ <Button
92
+ variant="ghost"
93
+ size="sm"
94
+ className={cn(
95
+ 'h-5 px-1.5 text-[10px] gap-0.5',
96
+ isTemplateMode ? 'text-primary' : 'text-muted-foreground',
97
+ )}
98
+ onClick={() => handleTemplateModeChange(field.name, !isTemplateMode)}
99
+ title={isTemplateMode ? 'Switch to static value' : 'Switch to template'}
100
+ >
101
+ {isTemplateMode ? (
102
+ <>
103
+ <Code2 className="h-2.5 w-2.5" />
104
+ <span>Template</span>
105
+ </>
106
+ ) : (
107
+ <>
108
+ <Type className="h-2.5 w-2.5" />
109
+ <span>Static</span>
110
+ </>
111
+ )}
112
+ </Button>
113
+ );
114
+
115
+ return (
116
+ <div key={field.name} className="flex flex-col gap-1.5">
117
+ <div className="flex items-center justify-between gap-2">
118
+ <Label htmlFor={`credential-${field.name}`} className="text-xs">
119
+ {field.label}
120
+ </Label>
121
+ {templateModeToggle}
122
+ </div>
123
+ {isTemplateMode ? (
124
+ <DroppableInput
125
+ id={`credential-${field.name}`}
126
+ className="font-mono text-xs"
127
+ rows={1}
128
+ value={(formValues[field.name] as string) ?? ''}
129
+ placeholder="{{ config_node.data.variables.credential_id.value }}"
130
+ onChange={(newValue) => onFieldChange(field.name, newValue)}
131
+ />
132
+ ) : (
133
+ <CredentialCombobox
134
+ credentials={fieldCredentials}
135
+ value={(formValues[field.name] as string) ?? ''}
136
+ onChange={(value) => onFieldChange(field.name, value)}
137
+ placeholder={field.placeholder || 'Select credential'}
138
+ isLoading={isLoading}
139
+ isError={isError}
140
+ onRetry={onRefresh}
141
+ onAddNew={() => onAddNewCredential(field.name)}
142
+ onEditCredential={onEditCredential}
143
+ onRefreshOAuthCredential={onRefreshOAuthCredential}
144
+ refreshingCredentialId={refreshingCredentialId}
145
+ container={portalContainer}
146
+ disablePortal={disablePortal}
147
+ />
148
+ )}
149
+ </div>
150
+ );
151
+ })}
152
+ </div>
153
+ );
154
+ };
@@ -0,0 +1,45 @@
1
+ import { CodeMirrorNunjucksEditor } from '../../ui/codemirror-nunjucks-editor';
2
+
3
+ interface DroppableInputProps {
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ placeholder?: string;
7
+ disabled?: boolean;
8
+ className?: string;
9
+ id?: string;
10
+ multiline?: boolean;
11
+ rows?: number;
12
+ fillAvailableHeight?: boolean;
13
+ }
14
+
15
+ /**
16
+ * A text input that accepts drops from the DraggableJsonTree.
17
+ * When a nunjucks path is dropped, it's inserted at the cursor position.
18
+ *
19
+ * For multiline inputs, uses CodeMirror with Nunjucks syntax highlighting.
20
+ * For single-line inputs, uses a standard Input with drag-drop support.
21
+ */
22
+ export function DroppableInput({
23
+ value,
24
+ onChange,
25
+ placeholder,
26
+ disabled,
27
+ className = 'text-xs',
28
+ id: _id,
29
+ multiline = false,
30
+ rows = 1,
31
+ fillAvailableHeight = false,
32
+ }: DroppableInputProps) {
33
+ return (
34
+ <CodeMirrorNunjucksEditor
35
+ value={value}
36
+ onChange={onChange}
37
+ placeholder={placeholder}
38
+ disabled={disabled}
39
+ multiline={multiline}
40
+ rows={rows}
41
+ fillAvailableHeight={fillAvailableHeight}
42
+ className={className}
43
+ />
44
+ );
45
+ }
@@ -0,0 +1,223 @@
1
+ import { useState, useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { Check, ChevronsUpDown, Loader2 } from 'lucide-react';
3
+ import { cn } from '../../../lib/utils';
4
+ import { Button } from '../../ui/button';
5
+ import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover';
6
+ import {
7
+ Command,
8
+ CommandEmpty,
9
+ CommandGroup,
10
+ CommandInput,
11
+ CommandItem,
12
+ CommandList,
13
+ } from '../../ui/command';
14
+ import { useLoadFieldOptions } from '../../../api/node-data.api';
15
+ import type { NodeParamField } from '../../../types/node-definition.types';
16
+
17
+ interface DynamicSelectFieldProps {
18
+ /** The action / node type id (e.g. "core.model"). */
19
+ actionId: string;
20
+ /** The field definition — must have `loadOptions`. */
21
+ field: NodeParamField;
22
+ /** Current field value. */
23
+ value: unknown;
24
+ /** Called when the user picks a new value. */
25
+ onChange: (value: unknown) => void;
26
+ /** Current form values — used to extract dependency values. */
27
+ formValues: Record<string, unknown>;
28
+ /** Portal container for the dropdown. */
29
+ portalContainer?: HTMLElement | null;
30
+ }
31
+
32
+ /**
33
+ * A select field whose options are loaded from the server via the
34
+ * `loadOptions` system. Re-fetches whenever any of the declared
35
+ * dependency fields change.
36
+ */
37
+ export function DynamicSelectField({
38
+ actionId,
39
+ field,
40
+ value,
41
+ onChange,
42
+ formValues,
43
+ portalContainer: _portalContainer,
44
+ }: DynamicSelectFieldProps) {
45
+ const [open, setOpen] = useState(false);
46
+ const [search, setSearch] = useState('');
47
+ const dependsOn = field.loadOptions?.dependsOn ?? [];
48
+
49
+ // Build dependency values from formValues
50
+ const dependencyValues = useMemo(() => {
51
+ const deps: Record<string, unknown> = {};
52
+ for (const dep of dependsOn) {
53
+ deps[dep] = formValues[dep];
54
+ }
55
+ return deps;
56
+ }, [dependsOn, ...dependsOn.map((d) => formValues[d])]);
57
+
58
+ // Only fetch when all dependency values are non-empty
59
+ const hasDeps = dependsOn.every(
60
+ (d) =>
61
+ dependencyValues[d] !== undefined &&
62
+ dependencyValues[d] !== null &&
63
+ dependencyValues[d] !== '',
64
+ );
65
+
66
+ const { data, isLoading, isError, error } = useLoadFieldOptions(
67
+ actionId,
68
+ field.name,
69
+ dependencyValues,
70
+ { enabled: hasDeps },
71
+ );
72
+
73
+ // Auto-select the default value when options arrive (only on first load
74
+ // or when the current value is not in the new option set).
75
+ const prevDepsKey = useRef<string>('');
76
+ useEffect(() => {
77
+ if (!data) {
78
+ return;
79
+ }
80
+ const depsKey = JSON.stringify(dependencyValues);
81
+ if (depsKey === prevDepsKey.current) {
82
+ return;
83
+ }
84
+ prevDepsKey.current = depsKey;
85
+
86
+ const currentStr = value === undefined || value === null ? '' : String(value);
87
+ const inList = data.options.some((o) => String(o.value) === currentStr);
88
+
89
+ if (!inList && data.defaultValue !== undefined) {
90
+ onChange(data.defaultValue);
91
+ } else if (!inList && data.options.length > 0 && currentStr) {
92
+ // Current value is stale — clear it so the user picks a new one
93
+ onChange('');
94
+ }
95
+ }, [data, dependencyValues, value, onChange]);
96
+
97
+ // Merge static options from field definition with dynamic options
98
+ const options = data?.options ?? field.options ?? [];
99
+ const placeholder = data?.placeholder ?? field.placeholder ?? 'Select…';
100
+ const disabled = field.disabled || data?.disabled || false;
101
+
102
+ const stringValue = value === undefined || value === null ? '' : String(value);
103
+
104
+ // If the current value is not in the options list, prepend it so the
105
+ // user can still see what was previously selected.
106
+ const optionEntries = options.map((o) => ({ label: o.label, value: String(o.value) }));
107
+ const hasCurrentValue = stringValue ? optionEntries.some((o) => o.value === stringValue) : false;
108
+ const renderOptions =
109
+ hasCurrentValue || !stringValue
110
+ ? optionEntries
111
+ : [{ label: stringValue, value: stringValue }, ...optionEntries];
112
+
113
+ // Client-side search filter
114
+ const filteredOptions = useMemo(() => {
115
+ if (!search) {
116
+ return renderOptions;
117
+ }
118
+ const lower = search.toLowerCase();
119
+ return renderOptions.filter(
120
+ (o) => o.label.toLowerCase().includes(lower) || o.value.toLowerCase().includes(lower),
121
+ );
122
+ }, [renderOptions, search]);
123
+
124
+ const handleSelect = useCallback(
125
+ (val: string) => {
126
+ onChange(val);
127
+ setOpen(false);
128
+ setSearch('');
129
+ },
130
+ [onChange],
131
+ );
132
+
133
+ // Reset search when popover closes
134
+ useEffect(() => {
135
+ if (!open) {
136
+ setSearch('');
137
+ }
138
+ }, [open]);
139
+
140
+ const displayLabel = useMemo(() => {
141
+ if (!stringValue) {
142
+ return null;
143
+ }
144
+ const match = renderOptions.find((o) => o.value === stringValue);
145
+ return match?.label ?? stringValue;
146
+ }, [stringValue, renderOptions]);
147
+
148
+ return (
149
+ <div className="relative">
150
+ <Popover open={open} onOpenChange={setOpen}>
151
+ <PopoverTrigger asChild>
152
+ <Button
153
+ variant="outline"
154
+ role="combobox"
155
+ aria-expanded={open}
156
+ id={field.name}
157
+ disabled={disabled || isLoading}
158
+ className={cn(
159
+ 'w-full justify-between font-mono text-xs h-9',
160
+ isLoading && 'opacity-60',
161
+ !stringValue && 'text-muted-foreground',
162
+ )}
163
+ >
164
+ {isLoading ? (
165
+ <span className="flex items-center gap-2 text-muted-foreground">
166
+ <Loader2 className="h-3 w-3 animate-spin" />
167
+ Loading…
168
+ </span>
169
+ ) : (
170
+ <span className="truncate">{displayLabel ?? placeholder}</span>
171
+ )}
172
+ <ChevronsUpDown className="ml-auto h-3 w-3 shrink-0 opacity-50" />
173
+ </Button>
174
+ </PopoverTrigger>
175
+ <PopoverContent className="w-(--radix-popover-trigger-width) p-0" align="start">
176
+ <Command shouldFilter={false}>
177
+ <CommandInput
178
+ placeholder="Search…"
179
+ className="h-8 text-xs"
180
+ value={search}
181
+ onValueChange={setSearch}
182
+ />
183
+ <CommandList className="max-h-52">
184
+ {!isLoading && filteredOptions.length === 0 && (
185
+ <CommandEmpty className="text-xs">
186
+ {!hasDeps
187
+ ? 'Fill in required fields first'
188
+ : search
189
+ ? 'No matching options'
190
+ : 'No options available'}
191
+ </CommandEmpty>
192
+ )}
193
+ {filteredOptions.length > 0 && (
194
+ <CommandGroup>
195
+ {filteredOptions
196
+ .filter((o) => o.value !== '')
197
+ .map((option) => (
198
+ <CommandItem
199
+ key={option.value}
200
+ value={option.value}
201
+ onSelect={() => handleSelect(option.value)}
202
+ className="text-xs font-mono"
203
+ >
204
+ <span className="truncate">{option.label}</span>
205
+ {stringValue === option.value && (
206
+ <Check className="ml-auto h-3 w-3 shrink-0" />
207
+ )}
208
+ </CommandItem>
209
+ ))}
210
+ </CommandGroup>
211
+ )}
212
+ </CommandList>
213
+ </Command>
214
+ </PopoverContent>
215
+ </Popover>
216
+ {isError && (
217
+ <p className="mt-1 text-xs text-destructive">
218
+ {error instanceof Error ? error.message : 'Failed to load options'}
219
+ </p>
220
+ )}
221
+ </div>
222
+ );
223
+ }