@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.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/Invect-CWpIwZ5F.js +92738 -0
- package/dist/Invect.d.ts +25 -0
- package/dist/InvectShell.d.ts +14 -0
- package/dist/api/agent-tools.api.d.ts +1 -0
- package/dist/api/client.d.ts +207 -0
- package/dist/api/credentials.api.d.ts +47 -0
- package/dist/api/executions.api.d.ts +43 -0
- package/dist/api/flows.api.d.ts +100 -0
- package/dist/api/index.d.ts +9 -0
- package/dist/api/node-data.api.d.ts +66 -0
- package/dist/api/query-keys.d.ts +22 -0
- package/dist/api/triggers.api.d.ts +44 -0
- package/dist/api/types.d.ts +147 -0
- package/dist/api/use-flow-run-stream.d.ts +12 -0
- package/dist/assets/invect-branding.d.ts +4 -0
- package/dist/assets/provider-icons/index.d.ts +8 -0
- package/dist/babel-C9OtljFZ.js +9721 -0
- package/dist/components/PageLayout.d.ts +17 -0
- package/dist/components/chat/ChatInput.d.ts +17 -0
- package/dist/components/chat/ChatMessageList.d.ts +14 -0
- package/dist/components/chat/ChatModelSelector.d.ts +11 -0
- package/dist/components/chat/ChatPanel.d.ts +19 -0
- package/dist/components/chat/ChatPromptOverlay.d.ts +13 -0
- package/dist/components/chat/ChatProviderSelector.d.ts +9 -0
- package/dist/components/chat/ChatSettingsPanel.d.ts +11 -0
- package/dist/components/chat/InlineCredentialSetup.d.ts +9 -0
- package/dist/components/chat/MarkdownRenderer.d.ts +7 -0
- package/dist/components/chat/chat-memory.d.ts +21 -0
- package/dist/components/chat/chat.store.d.ts +416 -0
- package/dist/components/chat/index.d.ts +5 -0
- package/dist/components/chat/use-chat.d.ts +28 -0
- package/dist/components/credentials/CreateCredentialModal.d.ts +13 -0
- package/dist/components/credentials/CredentialDetailDialog.d.ts +17 -0
- package/dist/components/credentials/EditCredentialModal.d.ts +11 -0
- package/dist/components/credentials/OAuth2ConnectButton.d.ts +38 -0
- package/dist/components/credentials/OAuth2ProviderSelector.d.ts +15 -0
- package/dist/components/credentials/credential-utils.d.ts +12 -0
- package/dist/components/credentials/index.d.ts +9 -0
- package/dist/components/dashboard/FailedRunsAlert.d.ts +3 -0
- package/dist/components/dashboard/FlowCard.d.ts +7 -0
- package/dist/components/dashboard/RecentActivityTable.d.ts +9 -0
- package/dist/components/dashboard/StatCard.d.ts +10 -0
- package/dist/components/dashboard/index.d.ts +5 -0
- package/dist/components/dashboard/status-helpers.d.ts +5 -0
- package/dist/components/flow-editor/ActionsSidebar.d.ts +2 -0
- package/dist/components/flow-editor/FlowEditor.d.ts +21 -0
- package/dist/components/flow-editor/FlowHeader.d.ts +9 -0
- package/dist/components/flow-editor/FlowLayout.d.ts +24 -0
- package/dist/components/flow-editor/ModeSwitcher.d.ts +7 -0
- package/dist/components/flow-editor/NodeSidebar.d.ts +24 -0
- package/dist/components/flow-editor/RunControls.d.ts +12 -0
- package/dist/components/flow-editor/ToolConfigPanel.d.ts +16 -0
- package/dist/components/flow-editor/ValidationPanel.d.ts +5 -0
- package/dist/components/flow-editor/flow-editor.store.d.ts +1 -0
- package/dist/components/flow-editor/index.d.ts +6 -0
- package/dist/components/flow-editor/inline-edit.d.ts +10 -0
- package/dist/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.d.ts +26 -0
- package/dist/components/flow-editor/node-config-panel/CredentialCombobox.d.ts +21 -0
- package/dist/components/flow-editor/node-config-panel/CredentialsSection.d.ts +19 -0
- package/dist/components/flow-editor/node-config-panel/DroppableInput.d.ts +20 -0
- package/dist/components/flow-editor/node-config-panel/DynamicSelectField.d.ts +22 -0
- package/dist/components/flow-editor/node-config-panel/JsonPreviewPanel.d.ts +25 -0
- package/dist/components/flow-editor/node-config-panel/NodeConfigPanel.d.ts +14 -0
- package/dist/components/flow-editor/node-config-panel/NodeConfigPanelHeader.d.ts +15 -0
- package/dist/components/flow-editor/node-config-panel/ParametersSection.d.ts +16 -0
- package/dist/components/flow-editor/node-config-panel/SearchableSelectField.d.ts +17 -0
- package/dist/components/flow-editor/node-config-panel/SwitchCasesField.d.ts +18 -0
- package/dist/components/flow-editor/node-config-panel/hooks/index.d.ts +2 -0
- package/dist/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.d.ts +24 -0
- package/dist/components/flow-editor/node-config-panel/hooks/use-node-execution.d.ts +46 -0
- package/dist/components/flow-editor/node-config-panel/hooks/use-upstream-slots.d.ts +16 -0
- package/dist/components/flow-editor/node-config-panel/panels/AgentToolsPanel.d.ts +18 -0
- package/dist/components/flow-editor/node-config-panel/panels/ConfigurationPanel.d.ts +49 -0
- package/dist/components/flow-editor/node-config-panel/panels/DataMapperPane.d.ts +40 -0
- package/dist/components/flow-editor/node-config-panel/panels/InputPanel.d.ts +49 -0
- package/dist/components/flow-editor/node-config-panel/panels/OutputPanel.d.ts +7 -0
- package/dist/components/flow-editor/node-config-panel/panels/index.d.ts +4 -0
- package/dist/components/flow-editor/node-config-panel/types.d.ts +19 -0
- package/dist/components/flow-editor/node-config-panel/use-node-config-panel-store.d.ts +49 -0
- package/dist/components/flow-editor/node-config-panel/use-node-config-state.d.ts +26 -0
- package/dist/components/flow-editor/node-config-panel/use-run-node.d.ts +16 -0
- package/dist/components/flow-editor/node-config-panel/utils.d.ts +9 -0
- package/dist/components/flow-editor/serialize-to-sdk.d.ts +20 -0
- package/dist/components/flow-editor/toolbar-context.d.ts +2 -0
- package/dist/components/flow-editor/use-copy-paste.d.ts +7 -0
- package/dist/components/flow-editor/use-copy-paste.types.d.ts +38 -0
- package/dist/components/flow-editor/use-flow-editor.d.ts +44 -0
- package/dist/components/flow-runs-table/FlowRunsTable.d.ts +6 -0
- package/dist/components/flow-runs-table/index.d.ts +1 -0
- package/dist/components/flow-viewer/FlowRunsView.d.ts +7 -0
- package/dist/components/flow-viewer/FlowStatusView.d.ts +21 -0
- package/dist/components/flow-viewer/RunSelector.d.ts +13 -0
- package/dist/components/flow-viewer/RunsSidebar.d.ts +14 -0
- package/dist/components/flow-viewer/agent-tool-executions-list.d.ts +7 -0
- package/dist/components/flow-viewer/index.d.ts +1 -0
- package/dist/components/flow-viewer/logs-panel.d.ts +18 -0
- package/dist/components/flow-viewer/use-execution-log-data.d.ts +113 -0
- package/dist/components/graph/BatchFlowEdge.d.ts +33 -0
- package/dist/components/graph/LayoutSelector.d.ts +9 -0
- package/dist/components/graph/index.d.ts +47 -0
- package/dist/components/graph/styleUtils.d.ts +124 -0
- package/dist/components/nodes/AgentConfigPanel.d.ts +24 -0
- package/dist/components/nodes/AgentNode.d.ts +8 -0
- package/dist/components/nodes/AgentToolsBox.d.ts +41 -0
- package/dist/components/nodes/NodeAppendix.d.ts +19 -0
- package/dist/components/nodes/NodeStatusIndicator.d.ts +30 -0
- package/dist/components/nodes/NodeViewContext.d.ts +18 -0
- package/dist/components/nodes/ToolParamField.d.ts +28 -0
- package/dist/components/nodes/ToolSelectorModal.d.ts +80 -0
- package/dist/components/nodes/ToolSelectorParts.d.ts +30 -0
- package/dist/components/nodes/UniversalNode.d.ts +2 -0
- package/dist/components/nodes/createContextAwareNodes.d.ts +6 -0
- package/dist/components/nodes/index.d.ts +22 -0
- package/dist/components/nodes/nodeRegistry.d.ts +13 -0
- package/dist/components/nodes/withNodeContext.d.ts +7 -0
- package/dist/components/shared/InvectLoader.d.ts +8 -0
- package/dist/components/shared/InvectLogo.d.ts +9 -0
- package/dist/components/shared/ProviderIcon.d.ts +23 -0
- package/dist/components/side-menu/side-menu.d.ts +4 -0
- package/dist/components/sidebar/BaseSidebar.d.ts +17 -0
- package/dist/components/sidebar/index.d.ts +1 -0
- package/dist/components/triggers/CronPreview.d.ts +12 -0
- package/dist/components/triggers/index.d.ts +1 -0
- package/dist/components/ui/alert-dialog.d.ts +18 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/button.d.ts +13 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/codemirror-js-editor.d.ts +25 -0
- package/dist/components/ui/codemirror-json-editor.d.ts +18 -0
- package/dist/components/ui/codemirror-nunjucks-editor.d.ts +13 -0
- package/dist/components/ui/codemirror-vscode-theme.d.ts +24 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/command.d.ts +18 -0
- package/dist/components/ui/dialog.d.ts +18 -0
- package/dist/components/ui/dropdown-menu.d.ts +25 -0
- package/dist/components/ui/empty-state.d.ts +21 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/popover.d.ts +10 -0
- package/dist/components/ui/resizable.d.ts +8 -0
- package/dist/components/ui/scroll-area.d.ts +5 -0
- package/dist/components/ui/select.d.ts +18 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/slider.d.ts +4 -0
- package/dist/components/ui/switch.d.ts +3 -0
- package/dist/components/ui/table.d.ts +10 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/components/ui/tree-view.d.ts +107 -0
- package/dist/contexts/AgentToolCallbacksContext.d.ts +23 -0
- package/dist/contexts/ApiContext.d.ts +11 -0
- package/dist/contexts/FlowDataContext.d.ts +9 -0
- package/dist/contexts/NodeRegistryContext.d.ts +14 -0
- package/dist/contexts/PluginRegistryContext.d.ts +39 -0
- package/dist/contexts/ThemeProvider.d.ts +18 -0
- package/dist/contexts/ValidationContext.d.ts +22 -0
- package/dist/demo/DemoInvect.d.ts +11 -0
- package/dist/demo/FlowViewer.d.ts +31 -0
- package/dist/demo/demo-api-client.d.ts +33 -0
- package/dist/demo/index.d.ts +6 -0
- package/dist/demo/sample-data.d.ts +1538 -0
- package/dist/demo.d.ts +2 -0
- package/dist/demo.js +2774 -0
- package/dist/estree-ClbRfS-1.js +7076 -0
- package/dist/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
- package/dist/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/geist-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/iosevka-latin-400-normal.woff2 +0 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/use-document-title.d.ts +1 -0
- package/dist/hooks/use-flow-data.d.ts +22 -0
- package/dist/hooks/use-invect-portal-class.d.ts +21 -0
- package/dist/hooks/useFlowEditorStore.d.ts +1 -0
- package/dist/index.css +3 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +717 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/prettier.d.ts +13 -0
- package/dist/routes/all-flow-runs.d.ts +5 -0
- package/dist/routes/credentials.d.ts +5 -0
- package/dist/routes/flow-route-layout.d.ts +19 -0
- package/dist/routes/flow-runs.d.ts +5 -0
- package/dist/routes/flow.d.ts +5 -0
- package/dist/routes/home.d.ts +5 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/standalone-C3Df7W52.js +3463 -0
- package/dist/stores/executionViewStore.d.ts +64 -0
- package/dist/stores/flow-editor.store.d.ts +137 -0
- package/dist/stores/flowEditorStore.d.ts +1 -0
- package/dist/stores/index.d.ts +2 -0
- package/dist/stores/uiStore.d.ts +45 -0
- package/dist/types/agent-tools.types.d.ts +53 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/node-definition.types.d.ts +85 -0
- package/dist/types/plugin.types.d.ts +100 -0
- package/dist/utils/credentialBranding.d.ts +8 -0
- package/dist/utils/credentialFiltering.d.ts +20 -0
- package/dist/utils/flowTransformations.d.ts +16 -0
- package/dist/utils/layoutUtils.d.ts +23 -0
- package/dist/utils/nodeReferenceUtils.d.ts +37 -0
- package/dist/vendor.d.ts +5 -0
- package/package.json +130 -0
- package/src/.DS_Store +0 -0
- package/src/Invect.tsx +229 -0
- package/src/InvectShell.tsx +55 -0
- package/src/api/agent-tools.api.ts +23 -0
- package/src/api/client.ts +899 -0
- package/src/api/credentials.api.ts +197 -0
- package/src/api/executions.api.ts +228 -0
- package/src/api/flows.api.ts +195 -0
- package/src/api/index.ts +17 -0
- package/src/api/node-data.api.ts +167 -0
- package/src/api/query-keys.ts +44 -0
- package/src/api/triggers.api.ts +120 -0
- package/src/api/types.ts +212 -0
- package/src/api/use-flow-run-stream.ts +206 -0
- package/src/app.css +560 -0
- package/src/assets/.DS_Store +0 -0
- package/src/assets/favicon.ico +0 -0
- package/src/assets/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
- package/src/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
- package/src/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
- package/src/assets/fonts/iosevka-latin-400-normal.woff2 +0 -0
- package/src/assets/invect-branding.ts +51 -0
- package/src/assets/provider-icons/anthropic.svg +1 -0
- package/src/assets/provider-icons/anthropic_light.svg +1 -0
- package/src/assets/provider-icons/github.svg +1 -0
- package/src/assets/provider-icons/github_light.svg +1 -0
- package/src/assets/provider-icons/gmail.svg +1 -0
- package/src/assets/provider-icons/google_calendar.svg +1 -0
- package/src/assets/provider-icons/google_docs.svg +1 -0
- package/src/assets/provider-icons/google_drive.svg +1 -0
- package/src/assets/provider-icons/google_sheets.svg +1 -0
- package/src/assets/provider-icons/index.ts +55 -0
- package/src/assets/provider-icons/linear.svg +1 -0
- package/src/assets/provider-icons/openai.svg +1 -0
- package/src/assets/provider-icons/postgres.svg +1 -0
- package/src/assets/provider-icons/slack.svg +1 -0
- package/src/assets/small-loader-dark.svg +22 -0
- package/src/assets/small-loader-light.svg +22 -0
- package/src/assets/small.svg +7 -0
- package/src/components/.DS_Store +0 -0
- package/src/components/PageLayout.tsx +55 -0
- package/src/components/chat/ChatInput.tsx +115 -0
- package/src/components/chat/ChatMessageList.tsx +788 -0
- package/src/components/chat/ChatModelSelector.tsx +208 -0
- package/src/components/chat/ChatPanel.tsx +243 -0
- package/src/components/chat/ChatPromptOverlay.tsx +150 -0
- package/src/components/chat/ChatProviderSelector.tsx +135 -0
- package/src/components/chat/ChatSettingsPanel.tsx +277 -0
- package/src/components/chat/InlineCredentialSetup.tsx +343 -0
- package/src/components/chat/MarkdownRenderer.tsx +140 -0
- package/src/components/chat/chat-memory.ts +88 -0
- package/src/components/chat/chat.store.ts +479 -0
- package/src/components/chat/index.ts +5 -0
- package/src/components/chat/use-chat.ts +473 -0
- package/src/components/credentials/CreateCredentialModal.tsx +609 -0
- package/src/components/credentials/CredentialDetailDialog.tsx +882 -0
- package/src/components/credentials/EditCredentialModal.tsx +399 -0
- package/src/components/credentials/OAuth2ConnectButton.tsx +288 -0
- package/src/components/credentials/OAuth2ProviderSelector.tsx +360 -0
- package/src/components/credentials/credential-utils.ts +99 -0
- package/src/components/credentials/index.ts +10 -0
- package/src/components/dashboard/FailedRunsAlert.tsx +67 -0
- package/src/components/dashboard/FlowCard.tsx +64 -0
- package/src/components/dashboard/RecentActivityTable.tsx +92 -0
- package/src/components/dashboard/StatCard.tsx +32 -0
- package/src/components/dashboard/index.ts +5 -0
- package/src/components/dashboard/status-helpers.tsx +102 -0
- package/src/components/flow-editor/ActionsSidebar.tsx +503 -0
- package/src/components/flow-editor/FlowEditor.tsx +1002 -0
- package/src/components/flow-editor/FlowHeader.tsx +87 -0
- package/src/components/flow-editor/FlowLayout.tsx +117 -0
- package/src/components/flow-editor/ModeSwitcher.tsx +49 -0
- package/src/components/flow-editor/NodeSidebar.tsx +343 -0
- package/src/components/flow-editor/RunControls.tsx +109 -0
- package/src/components/flow-editor/ToolConfigPanel.tsx +434 -0
- package/src/components/flow-editor/ValidationPanel.tsx +167 -0
- package/src/components/flow-editor/flow-editor.store.ts +2 -0
- package/src/components/flow-editor/index.ts +6 -0
- package/src/components/flow-editor/inline-edit.tsx +111 -0
- package/src/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.tsx +334 -0
- package/src/components/flow-editor/node-config-panel/CredentialCombobox.tsx +217 -0
- package/src/components/flow-editor/node-config-panel/CredentialsSection.tsx +154 -0
- package/src/components/flow-editor/node-config-panel/DroppableInput.tsx +45 -0
- package/src/components/flow-editor/node-config-panel/DynamicSelectField.tsx +223 -0
- package/src/components/flow-editor/node-config-panel/JsonPreviewPanel.tsx +134 -0
- package/src/components/flow-editor/node-config-panel/NodeConfigPanel.tsx +650 -0
- package/src/components/flow-editor/node-config-panel/NodeConfigPanelHeader.tsx +91 -0
- package/src/components/flow-editor/node-config-panel/ParametersSection.tsx +144 -0
- package/src/components/flow-editor/node-config-panel/SearchableSelectField.tsx +126 -0
- package/src/components/flow-editor/node-config-panel/SwitchCasesField.tsx +212 -0
- package/src/components/flow-editor/node-config-panel/hooks/index.ts +2 -0
- package/src/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.ts +284 -0
- package/src/components/flow-editor/node-config-panel/hooks/use-node-execution.ts +287 -0
- package/src/components/flow-editor/node-config-panel/hooks/use-upstream-slots.ts +310 -0
- package/src/components/flow-editor/node-config-panel/panels/AgentToolsPanel.tsx +837 -0
- package/src/components/flow-editor/node-config-panel/panels/ConfigurationPanel.tsx +383 -0
- package/src/components/flow-editor/node-config-panel/panels/DataMapperPane.tsx +456 -0
- package/src/components/flow-editor/node-config-panel/panels/InputPanel.tsx +338 -0
- package/src/components/flow-editor/node-config-panel/panels/OutputPanel.tsx +109 -0
- package/src/components/flow-editor/node-config-panel/panels/index.ts +4 -0
- package/src/components/flow-editor/node-config-panel/types.ts +20 -0
- package/src/components/flow-editor/node-config-panel/use-node-config-panel-store.ts +283 -0
- package/src/components/flow-editor/node-config-panel/use-node-config-state.ts +172 -0
- package/src/components/flow-editor/node-config-panel/use-run-node.ts +147 -0
- package/src/components/flow-editor/node-config-panel/utils.ts +73 -0
- package/src/components/flow-editor/serialize-to-sdk.ts +204 -0
- package/src/components/flow-editor/toolbar-context.ts +9 -0
- package/src/components/flow-editor/use-copy-paste.ts +575 -0
- package/src/components/flow-editor/use-copy-paste.types.ts +35 -0
- package/src/components/flow-editor/use-flow-editor.ts +241 -0
- package/src/components/flow-runs-table/FlowRunsTable.tsx +631 -0
- package/src/components/flow-runs-table/index.ts +1 -0
- package/src/components/flow-viewer/FlowRunsView.tsx +268 -0
- package/src/components/flow-viewer/FlowStatusView.tsx +351 -0
- package/src/components/flow-viewer/RunSelector.tsx +422 -0
- package/src/components/flow-viewer/RunsSidebar.tsx +125 -0
- package/src/components/flow-viewer/agent-tool-executions-list.tsx +298 -0
- package/src/components/flow-viewer/index.ts +1 -0
- package/src/components/flow-viewer/logs-panel.tsx +567 -0
- package/src/components/flow-viewer/use-execution-log-data.ts +374 -0
- package/src/components/graph/BatchFlowEdge.tsx +229 -0
- package/src/components/graph/LayoutSelector.tsx +42 -0
- package/src/components/graph/index.ts +61 -0
- package/src/components/graph/styleUtils.ts +375 -0
- package/src/components/nodes/.DS_Store +0 -0
- package/src/components/nodes/AgentConfigPanel.tsx +1033 -0
- package/src/components/nodes/AgentNode.tsx +298 -0
- package/src/components/nodes/AgentToolsBox.tsx +193 -0
- package/src/components/nodes/NodeAppendix.tsx +98 -0
- package/src/components/nodes/NodeStatusIndicator.tsx +74 -0
- package/src/components/nodes/NodeViewContext.tsx +45 -0
- package/src/components/nodes/ToolParamField.tsx +282 -0
- package/src/components/nodes/ToolSelectorModal.tsx +648 -0
- package/src/components/nodes/ToolSelectorParts.tsx +505 -0
- package/src/components/nodes/UniversalNode.tsx +356 -0
- package/src/components/nodes/createContextAwareNodes.ts +19 -0
- package/src/components/nodes/index.ts +45 -0
- package/src/components/nodes/nodeRegistry.ts +50 -0
- package/src/components/nodes/withNodeContext.tsx +55 -0
- package/src/components/shared/InvectLoader.tsx +59 -0
- package/src/components/shared/InvectLogo.tsx +59 -0
- package/src/components/shared/ProviderIcon.tsx +115 -0
- package/src/components/side-menu/side-menu.tsx +267 -0
- package/src/components/sidebar/BaseSidebar.tsx +148 -0
- package/src/components/sidebar/index.ts +1 -0
- package/src/components/triggers/CronPreview.tsx +243 -0
- package/src/components/triggers/index.ts +1 -0
- package/src/components/ui/alert-dialog.tsx +152 -0
- package/src/components/ui/badge.tsx +39 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/codemirror-js-editor.tsx +432 -0
- package/src/components/ui/codemirror-json-editor.tsx +816 -0
- package/src/components/ui/codemirror-nunjucks-editor.tsx +451 -0
- package/src/components/ui/codemirror-vscode-theme.ts +243 -0
- package/src/components/ui/collapsible.tsx +12 -0
- package/src/components/ui/command.tsx +162 -0
- package/src/components/ui/dialog.tsx +140 -0
- package/src/components/ui/dropdown-menu.tsx +232 -0
- package/src/components/ui/empty-state.tsx +93 -0
- package/src/components/ui/input.tsx +26 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/popover.tsx +53 -0
- package/src/components/ui/resizable.tsx +61 -0
- package/src/components/ui/scroll-area.tsx +56 -0
- package/src/components/ui/select.tsx +179 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/slider.tsx +58 -0
- package/src/components/ui/switch.tsx +22 -0
- package/src/components/ui/table.tsx +90 -0
- package/src/components/ui/textarea.tsx +23 -0
- package/src/components/ui/tooltip.tsx +54 -0
- package/src/components/ui/tree-view.tsx +574 -0
- package/src/contexts/AgentToolCallbacksContext.tsx +31 -0
- package/src/contexts/ApiContext.tsx +51 -0
- package/src/contexts/FlowDataContext.tsx +21 -0
- package/src/contexts/NodeRegistryContext.tsx +54 -0
- package/src/contexts/PluginRegistryContext.tsx +182 -0
- package/src/contexts/ThemeProvider.tsx +106 -0
- package/src/contexts/ValidationContext.tsx +122 -0
- package/src/demo/DemoInvect.tsx +42 -0
- package/src/demo/FlowViewer.tsx +294 -0
- package/src/demo/demo-api-client.ts +246 -0
- package/src/demo/index.ts +28 -0
- package/src/demo/sample-data.ts +1980 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-document-title.ts +8 -0
- package/src/hooks/use-flow-data.ts +144 -0
- package/src/hooks/use-invect-portal-class.ts +27 -0
- package/src/hooks/useFlowEditorStore.ts +2 -0
- package/src/index.ts +70 -0
- package/src/lib/utils.ts +6 -0
- package/src/prettier.d.ts +13 -0
- package/src/routes/all-flow-runs.tsx +27 -0
- package/src/routes/credentials.tsx +362 -0
- package/src/routes/flow-route-layout.tsx +113 -0
- package/src/routes/flow-runs.tsx +22 -0
- package/src/routes/flow.tsx +22 -0
- package/src/routes/home.tsx +282 -0
- package/src/services/index.ts +6 -0
- package/src/stores/executionViewStore.ts +211 -0
- package/src/stores/flow-editor.store.ts +738 -0
- package/src/stores/flowEditorStore.ts +2 -0
- package/src/stores/index.ts +10 -0
- package/src/stores/uiStore.ts +189 -0
- package/src/types/agent-tools.types.ts +64 -0
- package/src/types/index.ts +5 -0
- package/src/types/node-definition.types.ts +104 -0
- package/src/types/plugin.types.ts +123 -0
- package/src/utils/credentialBranding.ts +116 -0
- package/src/utils/credentialFiltering.ts +68 -0
- package/src/utils/flowTransformations.ts +137 -0
- package/src/utils/layoutUtils.ts +127 -0
- package/src/utils/nodeReferenceUtils.ts +135 -0
- package/src/vendor.d.ts +7 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './use-flow-data';
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
useNodesState,
|
|
4
|
+
useEdgesState,
|
|
5
|
+
type Node,
|
|
6
|
+
type Edge,
|
|
7
|
+
type NodeChange,
|
|
8
|
+
type EdgeChange,
|
|
9
|
+
} from '@xyflow/react';
|
|
10
|
+
import { useFlowReactFlowData } from '../api/flows.api';
|
|
11
|
+
import { type ReactFlowData } from '@invect/core/types';
|
|
12
|
+
|
|
13
|
+
// Hook that uses the backend React Flow renderer service
|
|
14
|
+
export function useFlowData(
|
|
15
|
+
flowId: string,
|
|
16
|
+
flowVersion?: string,
|
|
17
|
+
flowRunId?: string,
|
|
18
|
+
): {
|
|
19
|
+
flowData: ReactFlowData | undefined;
|
|
20
|
+
displayVersion: ReactFlowData['version'] | undefined;
|
|
21
|
+
loading: boolean;
|
|
22
|
+
error: string | null;
|
|
23
|
+
nodes: Node[];
|
|
24
|
+
setNodes: React.Dispatch<React.SetStateAction<Node[]>>;
|
|
25
|
+
onNodesChange: (changes: NodeChange<Node>[]) => void;
|
|
26
|
+
edges: Edge[];
|
|
27
|
+
setEdges: React.Dispatch<React.SetStateAction<Edge[]>>;
|
|
28
|
+
onEdgesChange: (changes: EdgeChange<Edge>[]) => void;
|
|
29
|
+
isDirty: boolean;
|
|
30
|
+
resetDirty: (savedVersionId?: string) => void;
|
|
31
|
+
queryError: string | null;
|
|
32
|
+
nodeMetadata: Record<string, { name: string; type?: string }>;
|
|
33
|
+
} {
|
|
34
|
+
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([]);
|
|
35
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
|
|
36
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
37
|
+
const [initialDataLoaded, setInitialDataLoaded] = useState(false);
|
|
38
|
+
|
|
39
|
+
// Track the last version we loaded to avoid re-applying same data after save
|
|
40
|
+
const lastLoadedVersionRef = useRef<string | null>(null);
|
|
41
|
+
|
|
42
|
+
// Use React Query to fetch flow data (backend already provides positioned nodes)
|
|
43
|
+
const {
|
|
44
|
+
data: flowData,
|
|
45
|
+
isLoading: loading,
|
|
46
|
+
error: queryError,
|
|
47
|
+
} = useFlowReactFlowData(flowId, { version: flowVersion, flowRunId });
|
|
48
|
+
|
|
49
|
+
// Apply backend data directly when it changes (backend provides positions)
|
|
50
|
+
// But skip if we just saved and the version hasn't actually changed
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!flowData?.nodes) {
|
|
53
|
+
setNodes([]);
|
|
54
|
+
setEdges([]);
|
|
55
|
+
lastLoadedVersionRef.current = null;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Use flowId:version as composite identifier to detect if this is truly new data
|
|
60
|
+
const versionInfo = flowData.version;
|
|
61
|
+
const currentVersionId = versionInfo ? `${versionInfo.flowId}:${versionInfo.version}` : null;
|
|
62
|
+
|
|
63
|
+
// When tracking a flow run, always update nodes to show execution status changes
|
|
64
|
+
// Only skip version check when NOT tracking execution
|
|
65
|
+
if (!flowRunId) {
|
|
66
|
+
// Skip if we've already loaded this exact version (prevents panel closing on save)
|
|
67
|
+
if (
|
|
68
|
+
currentVersionId &&
|
|
69
|
+
currentVersionId === lastLoadedVersionRef.current &&
|
|
70
|
+
initialDataLoaded
|
|
71
|
+
) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Set nodes and edges from backend (already positioned)
|
|
77
|
+
setNodes(flowData.nodes as Node[]);
|
|
78
|
+
setEdges(flowData.edges as Edge[]);
|
|
79
|
+
|
|
80
|
+
// Mark initial data as loaded and track the version
|
|
81
|
+
setInitialDataLoaded(true);
|
|
82
|
+
lastLoadedVersionRef.current = currentVersionId;
|
|
83
|
+
}, [flowData, flowRunId, setNodes, setEdges, initialDataLoaded]);
|
|
84
|
+
|
|
85
|
+
// Track local changes (dirty state) - only after initial data is loaded
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (initialDataLoaded) {
|
|
88
|
+
setIsDirty(true);
|
|
89
|
+
}
|
|
90
|
+
}, [nodes, edges, initialDataLoaded]);
|
|
91
|
+
|
|
92
|
+
// Reset dirty state, optionally marking a newly saved version as already loaded
|
|
93
|
+
const resetDirty = useCallback((savedVersionId?: string) => {
|
|
94
|
+
setIsDirty(false);
|
|
95
|
+
// If we know the new version ID, mark it as loaded so we don't re-apply data on refetch
|
|
96
|
+
if (savedVersionId) {
|
|
97
|
+
lastLoadedVersionRef.current = savedVersionId;
|
|
98
|
+
}
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
const nodeMetadata = useMemo(() => {
|
|
102
|
+
if (!flowData?.nodes) {
|
|
103
|
+
return {};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return flowData.nodes.reduce(
|
|
107
|
+
(acc: Record<string, { name: string; type?: string }>, node: Node) => {
|
|
108
|
+
acc[node.id] = {
|
|
109
|
+
name: ((node.data as Record<string, unknown>)?.display_name as string) || node.id,
|
|
110
|
+
type: node.type,
|
|
111
|
+
};
|
|
112
|
+
return acc;
|
|
113
|
+
},
|
|
114
|
+
{},
|
|
115
|
+
);
|
|
116
|
+
}, [flowData]);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
// Data
|
|
120
|
+
flowData,
|
|
121
|
+
displayVersion: flowData?.version,
|
|
122
|
+
|
|
123
|
+
// Loading states
|
|
124
|
+
loading,
|
|
125
|
+
error: queryError?.message || null,
|
|
126
|
+
|
|
127
|
+
// Nodes and edges
|
|
128
|
+
nodes,
|
|
129
|
+
setNodes,
|
|
130
|
+
onNodesChange,
|
|
131
|
+
edges,
|
|
132
|
+
setEdges,
|
|
133
|
+
onEdgesChange,
|
|
134
|
+
|
|
135
|
+
// Dirty state tracking
|
|
136
|
+
isDirty,
|
|
137
|
+
resetDirty,
|
|
138
|
+
|
|
139
|
+
queryError: queryError?.message || null,
|
|
140
|
+
nodeMetadata,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export type UseFlowDataResult = ReturnType<typeof useFlowData>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useTheme } from '../contexts/ThemeProvider';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the class name string for portal wrappers that need to be inside the
|
|
5
|
+
* `.invect` CSS scope.
|
|
6
|
+
*
|
|
7
|
+
* Radix portals render to `document.body`, which sits outside the main `.invect`
|
|
8
|
+
* container. Without a wrapper, portal content loses access to invect's CSS
|
|
9
|
+
* variables and the Tailwind `dark:` variant.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const portalClass = useInvectPortalClass();
|
|
14
|
+
* return (
|
|
15
|
+
* <SomePrimitive.Portal>
|
|
16
|
+
* <div className={portalClass}>
|
|
17
|
+
* {children}
|
|
18
|
+
* </div>
|
|
19
|
+
* </SomePrimitive.Portal>
|
|
20
|
+
* );
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function useInvectPortalClass(): string {
|
|
24
|
+
const { resolvedTheme } = useTheme();
|
|
25
|
+
|
|
26
|
+
return `invect ${resolvedTheme}`;
|
|
27
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Main component exports
|
|
2
|
+
export { Invect } from './Invect';
|
|
3
|
+
export { InvectShell } from './InvectShell';
|
|
4
|
+
export { InvectLoader } from './components/shared/InvectLoader';
|
|
5
|
+
export { InvectLogo } from './components/shared/InvectLogo';
|
|
6
|
+
|
|
7
|
+
// Export types for better TypeScript support
|
|
8
|
+
export type { InvectProps } from './Invect';
|
|
9
|
+
export type { InvectShellProps } from './InvectShell';
|
|
10
|
+
export type { InvectLoaderProps } from './components/shared/InvectLoader';
|
|
11
|
+
export type { InvectLogoProps } from './components/shared/InvectLogo';
|
|
12
|
+
|
|
13
|
+
// Plugin system types
|
|
14
|
+
export type {
|
|
15
|
+
InvectFrontendPlugin,
|
|
16
|
+
PluginSidebarContribution,
|
|
17
|
+
PluginRouteContribution,
|
|
18
|
+
PluginPanelTabContribution,
|
|
19
|
+
PluginHeaderActionContribution,
|
|
20
|
+
PanelTabProps,
|
|
21
|
+
HeaderActionProps,
|
|
22
|
+
PermissionContext,
|
|
23
|
+
} from './types/plugin.types';
|
|
24
|
+
export { usePluginRegistry } from './contexts/PluginRegistryContext';
|
|
25
|
+
export type { PluginRegistry } from './contexts/PluginRegistryContext';
|
|
26
|
+
|
|
27
|
+
// Export API context for advanced usage
|
|
28
|
+
export { ApiProvider, useApiClient, useApiBaseURL } from './contexts/ApiContext';
|
|
29
|
+
export type { ApiProviderProps } from './contexts/ApiContext';
|
|
30
|
+
|
|
31
|
+
// OAuth2 callback handler - needed for OAuth2 redirects
|
|
32
|
+
export { OAuth2CallbackHandler } from './components/credentials/OAuth2ConnectButton';
|
|
33
|
+
|
|
34
|
+
// Flow editor shell
|
|
35
|
+
export { FlowEditor } from './components/flow-editor/FlowEditor';
|
|
36
|
+
|
|
37
|
+
// Standard page layout for non-editor pages
|
|
38
|
+
export { PageLayout } from './components/PageLayout';
|
|
39
|
+
export type { PageLayoutProps } from './components/PageLayout';
|
|
40
|
+
|
|
41
|
+
// Zustand stores for state management
|
|
42
|
+
export * from './stores';
|
|
43
|
+
|
|
44
|
+
// React Query + Zustand hooks
|
|
45
|
+
export * from './api';
|
|
46
|
+
|
|
47
|
+
// UI primitives
|
|
48
|
+
export { TreeView, type TreeDataItem, type TreeRenderItemParams } from './components/ui/tree-view';
|
|
49
|
+
export {
|
|
50
|
+
Dialog,
|
|
51
|
+
DialogClose,
|
|
52
|
+
DialogContent,
|
|
53
|
+
DialogDescription,
|
|
54
|
+
DialogFooter,
|
|
55
|
+
DialogHeader,
|
|
56
|
+
DialogOverlay,
|
|
57
|
+
DialogPortal,
|
|
58
|
+
DialogTitle,
|
|
59
|
+
DialogTrigger,
|
|
60
|
+
} from './components/ui/dialog';
|
|
61
|
+
export {
|
|
62
|
+
DropdownMenu,
|
|
63
|
+
DropdownMenuContent,
|
|
64
|
+
DropdownMenuItem,
|
|
65
|
+
DropdownMenuLabel,
|
|
66
|
+
DropdownMenuRadioGroup,
|
|
67
|
+
DropdownMenuRadioItem,
|
|
68
|
+
DropdownMenuSeparator,
|
|
69
|
+
DropdownMenuTrigger,
|
|
70
|
+
} from './components/ui/dropdown-menu';
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare module 'prettier/standalone' {
|
|
2
|
+
export function format(source: string, options: Record<string, unknown>): Promise<string>;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
declare module 'prettier/plugins/babel' {
|
|
6
|
+
const plugin: Record<string, unknown>;
|
|
7
|
+
export default plugin;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
declare module 'prettier/plugins/estree' {
|
|
11
|
+
const plugin: Record<string, unknown>;
|
|
12
|
+
export default plugin;
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Link } from 'react-router';
|
|
2
|
+
import { FlowRunsTable } from '../components/flow-runs-table/FlowRunsTable';
|
|
3
|
+
import { PageLayout } from '../components/PageLayout';
|
|
4
|
+
import { useDocumentTitle } from '../hooks/use-document-title';
|
|
5
|
+
|
|
6
|
+
interface AllFlowRunsProps {
|
|
7
|
+
basePath?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const AllFlowRuns = ({ basePath = '' }: AllFlowRunsProps) => {
|
|
11
|
+
useDocumentTitle('flow runs');
|
|
12
|
+
return (
|
|
13
|
+
<PageLayout
|
|
14
|
+
title="Flow Runs"
|
|
15
|
+
actions={
|
|
16
|
+
<Link
|
|
17
|
+
to={basePath || '/'}
|
|
18
|
+
className="inline-flex items-center px-3 py-1.5 text-sm text-muted-foreground bg-card border border-border rounded hover:bg-muted transition-colors"
|
|
19
|
+
>
|
|
20
|
+
← Back to Home
|
|
21
|
+
</Link>
|
|
22
|
+
}
|
|
23
|
+
>
|
|
24
|
+
<FlowRunsTable basePath={basePath} />
|
|
25
|
+
</PageLayout>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import React, { useState, useRef, useMemo } from 'react';
|
|
2
|
+
import { PageLayout } from '../components/PageLayout';
|
|
3
|
+
import { Link } from 'react-router';
|
|
4
|
+
import { Plus, Shield, Clock, AlertCircle, Search, Loader2, ChevronRight } from 'lucide-react';
|
|
5
|
+
import { Button } from '../components/ui/button';
|
|
6
|
+
import { Badge } from '../components/ui/badge';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
AlertDialog,
|
|
10
|
+
AlertDialogAction,
|
|
11
|
+
AlertDialogCancel,
|
|
12
|
+
AlertDialogContent,
|
|
13
|
+
AlertDialogDescription,
|
|
14
|
+
AlertDialogFooter,
|
|
15
|
+
AlertDialogHeader,
|
|
16
|
+
AlertDialogTitle,
|
|
17
|
+
} from '../components/ui/alert-dialog';
|
|
18
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../components/ui/tooltip';
|
|
19
|
+
import type { Credential, CreateCredentialInput } from '../api/types';
|
|
20
|
+
import { useDocumentTitle } from '../hooks/use-document-title';
|
|
21
|
+
import { CreateCredentialModal } from '../components/credentials/CreateCredentialModal';
|
|
22
|
+
import { CredentialDetailDialog } from '../components/credentials/CredentialDetailDialog';
|
|
23
|
+
import { ProviderIcon } from '../components/shared/ProviderIcon';
|
|
24
|
+
import { getCredentialBranding, getCredentialProviderLabel } from '../utils/credentialBranding';
|
|
25
|
+
import {
|
|
26
|
+
AUTH_TYPE_CONFIG,
|
|
27
|
+
formatDate,
|
|
28
|
+
formatFullDate,
|
|
29
|
+
isTokenExpired,
|
|
30
|
+
} from '../components/credentials/credential-utils';
|
|
31
|
+
import {
|
|
32
|
+
useCredentials,
|
|
33
|
+
useCreateCredential,
|
|
34
|
+
useUpdateCredential,
|
|
35
|
+
useDeleteCredential,
|
|
36
|
+
useTestCredential,
|
|
37
|
+
} from '../api/credentials.api';
|
|
38
|
+
|
|
39
|
+
export interface CredentialsProps {
|
|
40
|
+
basePath?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const Credentials: React.FC<CredentialsProps> = ({ basePath: _basePath = '/invect' }) => {
|
|
44
|
+
useDocumentTitle('credentials');
|
|
45
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
46
|
+
|
|
47
|
+
// State
|
|
48
|
+
const [createModalOpen, setCreateModalOpen] = useState(false);
|
|
49
|
+
const [selectedCredential, setSelectedCredential] = useState<Credential | null>(null);
|
|
50
|
+
const [deletingCredential, setDeletingCredential] = useState<Credential | null>(null);
|
|
51
|
+
const [testingId, setTestingId] = useState<string | null>(null);
|
|
52
|
+
const [testResult, setTestResult] = useState<{ success: boolean; error?: string } | null>(null);
|
|
53
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
54
|
+
const [filterAuthType, setFilterAuthType] = useState<string>('all');
|
|
55
|
+
|
|
56
|
+
// Queries
|
|
57
|
+
const { data: credentials = [], isLoading, error } = useCredentials({ includeShared: true });
|
|
58
|
+
const createCredentialMutation = useCreateCredential();
|
|
59
|
+
const updateCredentialMutation = useUpdateCredential();
|
|
60
|
+
const deleteCredentialMutation = useDeleteCredential();
|
|
61
|
+
const testCredentialMutation = useTestCredential();
|
|
62
|
+
|
|
63
|
+
// Derived
|
|
64
|
+
const authTypes = useMemo(() => {
|
|
65
|
+
const types = new Set(credentials.map((c) => c.authType));
|
|
66
|
+
return Array.from(types).sort();
|
|
67
|
+
}, [credentials]);
|
|
68
|
+
|
|
69
|
+
const filteredCredentials = useMemo(() => {
|
|
70
|
+
let result = credentials;
|
|
71
|
+
if (searchQuery.trim()) {
|
|
72
|
+
const q = searchQuery.toLowerCase();
|
|
73
|
+
result = result.filter(
|
|
74
|
+
(c) =>
|
|
75
|
+
c.name.toLowerCase().includes(q) ||
|
|
76
|
+
c.description?.toLowerCase().includes(q) ||
|
|
77
|
+
c.authType.toLowerCase().includes(q) ||
|
|
78
|
+
c.config?.oauth2Provider?.toLowerCase().includes(q),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (filterAuthType !== 'all') {
|
|
82
|
+
result = result.filter((c) => c.authType === filterAuthType);
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}, [credentials, searchQuery, filterAuthType]);
|
|
86
|
+
|
|
87
|
+
const openDetail = (credential: Credential) => {
|
|
88
|
+
setSelectedCredential(credential);
|
|
89
|
+
setTestResult(null);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const closeDetail = () => {
|
|
93
|
+
setSelectedCredential(null);
|
|
94
|
+
setTestResult(null);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const handleTest = (id: string) => {
|
|
98
|
+
setTestingId(id);
|
|
99
|
+
setTestResult(null);
|
|
100
|
+
testCredentialMutation.mutate(id, {
|
|
101
|
+
onSuccess: (result) => {
|
|
102
|
+
setTestingId(null);
|
|
103
|
+
setTestResult(result);
|
|
104
|
+
},
|
|
105
|
+
onError: (mutationError) => {
|
|
106
|
+
setTestingId(null);
|
|
107
|
+
const message = mutationError instanceof Error ? mutationError.message : 'Unknown error';
|
|
108
|
+
setTestResult({ success: false, error: message });
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<PageLayout
|
|
115
|
+
ref={containerRef}
|
|
116
|
+
title="Credentials"
|
|
117
|
+
subtitle="Manage API keys, OAuth connections, and database credentials for your integrations."
|
|
118
|
+
actions={
|
|
119
|
+
<>
|
|
120
|
+
<Link
|
|
121
|
+
to={_basePath || '/'}
|
|
122
|
+
className="inline-flex items-center px-3 py-1.5 text-sm text-muted-foreground bg-card border border-border rounded-md hover:bg-muted transition-colors"
|
|
123
|
+
>
|
|
124
|
+
← Back
|
|
125
|
+
</Link>
|
|
126
|
+
<Button onClick={() => setCreateModalOpen(true)}>
|
|
127
|
+
<Plus className="w-4 h-4 mr-2" />
|
|
128
|
+
New Credential
|
|
129
|
+
</Button>
|
|
130
|
+
</>
|
|
131
|
+
}
|
|
132
|
+
>
|
|
133
|
+
{/* Search & Filters */}
|
|
134
|
+
{credentials.length > 0 && (
|
|
135
|
+
<div className="flex flex-col gap-3 mb-4 sm:flex-row sm:items-center">
|
|
136
|
+
<div className="relative flex-1 max-w-sm">
|
|
137
|
+
<Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 pointer-events-none text-muted-foreground" />
|
|
138
|
+
<input
|
|
139
|
+
type="text"
|
|
140
|
+
placeholder="Search credentials…"
|
|
141
|
+
value={searchQuery}
|
|
142
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
143
|
+
className="w-full rounded-lg border border-border bg-transparent py-2 pl-9 pr-3 text-sm outline-none placeholder:text-muted-foreground focus:border-primary/50"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
<div className="flex items-center gap-1.5 flex-wrap">
|
|
147
|
+
<button
|
|
148
|
+
onClick={() => setFilterAuthType('all')}
|
|
149
|
+
className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors ${
|
|
150
|
+
filterAuthType === 'all'
|
|
151
|
+
? 'bg-foreground text-background border-foreground'
|
|
152
|
+
: 'bg-card text-muted-foreground border-border hover:border-foreground/30'
|
|
153
|
+
}`}
|
|
154
|
+
>
|
|
155
|
+
All ({credentials.length})
|
|
156
|
+
</button>
|
|
157
|
+
{authTypes.map((type) => {
|
|
158
|
+
const config = AUTH_TYPE_CONFIG[type];
|
|
159
|
+
const count = credentials.filter((c) => c.authType === type).length;
|
|
160
|
+
return (
|
|
161
|
+
<button
|
|
162
|
+
key={type}
|
|
163
|
+
onClick={() => setFilterAuthType(filterAuthType === type ? 'all' : type)}
|
|
164
|
+
className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors ${
|
|
165
|
+
filterAuthType === type
|
|
166
|
+
? 'bg-foreground text-background border-foreground'
|
|
167
|
+
: 'bg-card text-muted-foreground border-border hover:border-foreground/30'
|
|
168
|
+
}`}
|
|
169
|
+
>
|
|
170
|
+
{config?.label ?? type} ({count})
|
|
171
|
+
</button>
|
|
172
|
+
);
|
|
173
|
+
})}
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
|
|
178
|
+
{/* Content */}
|
|
179
|
+
<TooltipProvider>
|
|
180
|
+
{isLoading ? (
|
|
181
|
+
<div className="flex flex-col items-center justify-center py-20">
|
|
182
|
+
<Loader2 className="w-8 h-8 mb-3 text-muted-foreground animate-spin" />
|
|
183
|
+
<p className="text-sm text-muted-foreground">Loading credentials...</p>
|
|
184
|
+
</div>
|
|
185
|
+
) : error ? (
|
|
186
|
+
<div className="flex flex-col items-center justify-center py-20">
|
|
187
|
+
<AlertCircle className="w-12 h-12 mb-3 text-destructive" />
|
|
188
|
+
<p className="text-sm text-destructive">
|
|
189
|
+
Error loading credentials: {error instanceof Error ? error.message : 'Unknown error'}
|
|
190
|
+
</p>
|
|
191
|
+
</div>
|
|
192
|
+
) : credentials.length === 0 ? (
|
|
193
|
+
<div className="flex flex-col items-center justify-center py-20 border border-dashed rounded-xl border-border">
|
|
194
|
+
<div className="flex items-center justify-center w-16 h-16 mb-4 rounded-full bg-muted">
|
|
195
|
+
<Shield className="w-8 h-8 text-muted-foreground" />
|
|
196
|
+
</div>
|
|
197
|
+
<h3 className="mb-1 text-lg font-semibold text-foreground">No credentials yet</h3>
|
|
198
|
+
<p className="max-w-sm mb-6 text-sm text-center text-muted-foreground">
|
|
199
|
+
Add API keys, connect OAuth providers, or configure database credentials to power your
|
|
200
|
+
workflows.
|
|
201
|
+
</p>
|
|
202
|
+
<Button onClick={() => setCreateModalOpen(true)}>
|
|
203
|
+
<Plus className="w-4 h-4 mr-2" />
|
|
204
|
+
Create Credential
|
|
205
|
+
</Button>
|
|
206
|
+
</div>
|
|
207
|
+
) : filteredCredentials.length === 0 ? (
|
|
208
|
+
<div className="flex flex-col items-center justify-center py-16">
|
|
209
|
+
<Search className="w-10 h-10 mb-3 text-muted-foreground" />
|
|
210
|
+
<p className="text-sm text-muted-foreground">No credentials match your search.</p>
|
|
211
|
+
</div>
|
|
212
|
+
) : (
|
|
213
|
+
<div className="border border-border rounded-lg overflow-hidden bg-card divide-y divide-border">
|
|
214
|
+
{filteredCredentials.map((credential) => {
|
|
215
|
+
const iconInfo = getCredentialBranding(credential);
|
|
216
|
+
const providerLabel = getCredentialProviderLabel(credential);
|
|
217
|
+
const authConfig = AUTH_TYPE_CONFIG[credential.authType];
|
|
218
|
+
const expired = isTokenExpired(credential);
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<button
|
|
222
|
+
key={credential.id}
|
|
223
|
+
type="button"
|
|
224
|
+
onClick={() => openDetail(credential)}
|
|
225
|
+
className="w-full flex items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/50 focus-visible:bg-muted/50 focus-visible:outline-none"
|
|
226
|
+
>
|
|
227
|
+
{/* Icon */}
|
|
228
|
+
<div className="flex items-center justify-center w-9 h-9 rounded-lg bg-muted/60 shrink-0">
|
|
229
|
+
<ProviderIcon
|
|
230
|
+
providerId={iconInfo.providerId}
|
|
231
|
+
icon={iconInfo.icon}
|
|
232
|
+
className="w-5 h-5"
|
|
233
|
+
/>
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
{/* Name + provider */}
|
|
237
|
+
<div className="flex-1 min-w-0">
|
|
238
|
+
<div className="flex items-center gap-2">
|
|
239
|
+
<span className="text-sm font-medium text-foreground truncate">
|
|
240
|
+
{credential.name}
|
|
241
|
+
</span>
|
|
242
|
+
<span
|
|
243
|
+
className={`inline-block w-1.5 h-1.5 rounded-full shrink-0 ${
|
|
244
|
+
expired
|
|
245
|
+
? 'bg-warning'
|
|
246
|
+
: credential.isActive
|
|
247
|
+
? 'bg-success'
|
|
248
|
+
: 'bg-muted-foreground/40'
|
|
249
|
+
}`}
|
|
250
|
+
/>
|
|
251
|
+
{expired && (
|
|
252
|
+
<Badge
|
|
253
|
+
variant="secondary"
|
|
254
|
+
className="text-[10px] px-1.5 py-0 font-medium leading-4 bg-warning-muted text-warning"
|
|
255
|
+
>
|
|
256
|
+
Expired
|
|
257
|
+
</Badge>
|
|
258
|
+
)}
|
|
259
|
+
</div>
|
|
260
|
+
{providerLabel && (
|
|
261
|
+
<p className="text-xs text-muted-foreground truncate">{providerLabel}</p>
|
|
262
|
+
)}
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
{/* Auth badge */}
|
|
266
|
+
<Badge
|
|
267
|
+
variant="secondary"
|
|
268
|
+
className={`text-[10px] px-1.5 py-0 font-medium leading-5 shrink-0 ${authConfig?.color ?? 'bg-muted text-muted-foreground'}`}
|
|
269
|
+
>
|
|
270
|
+
{authConfig?.label ?? credential.authType}
|
|
271
|
+
</Badge>
|
|
272
|
+
|
|
273
|
+
{/* Last used */}
|
|
274
|
+
<Tooltip>
|
|
275
|
+
<TooltipTrigger asChild>
|
|
276
|
+
<span className="hidden sm:flex items-center gap-1 text-xs text-muted-foreground shrink-0 w-20 justify-end">
|
|
277
|
+
<Clock className="w-3 h-3" />
|
|
278
|
+
{formatDate(credential.lastUsedAt)}
|
|
279
|
+
</span>
|
|
280
|
+
</TooltipTrigger>
|
|
281
|
+
<TooltipContent>
|
|
282
|
+
Last used: {formatFullDate(credential.lastUsedAt)}
|
|
283
|
+
</TooltipContent>
|
|
284
|
+
</Tooltip>
|
|
285
|
+
|
|
286
|
+
<ChevronRight className="w-4 h-4 text-muted-foreground/50 shrink-0" />
|
|
287
|
+
</button>
|
|
288
|
+
);
|
|
289
|
+
})}
|
|
290
|
+
</div>
|
|
291
|
+
)}
|
|
292
|
+
</TooltipProvider>
|
|
293
|
+
|
|
294
|
+
{/* Detail Dialog */}
|
|
295
|
+
<CredentialDetailDialog
|
|
296
|
+
credential={selectedCredential}
|
|
297
|
+
onClose={closeDetail}
|
|
298
|
+
onDelete={(c) => setDeletingCredential(c)}
|
|
299
|
+
onTest={handleTest}
|
|
300
|
+
testingId={testingId}
|
|
301
|
+
testResult={testResult}
|
|
302
|
+
onUpdate={(id, data) => updateCredentialMutation.mutate({ id, data })}
|
|
303
|
+
isUpdating={updateCredentialMutation.isPending}
|
|
304
|
+
portalContainer={containerRef.current}
|
|
305
|
+
/>
|
|
306
|
+
|
|
307
|
+
{/* Create modal */}
|
|
308
|
+
<CreateCredentialModal
|
|
309
|
+
open={createModalOpen}
|
|
310
|
+
onClose={() => setCreateModalOpen(false)}
|
|
311
|
+
onSubmit={(data: CreateCredentialInput) =>
|
|
312
|
+
createCredentialMutation.mutate(data, {
|
|
313
|
+
onSuccess: () => setCreateModalOpen(false),
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
isLoading={createCredentialMutation.isPending}
|
|
317
|
+
portalContainer={containerRef.current}
|
|
318
|
+
/>
|
|
319
|
+
|
|
320
|
+
{/* Delete Confirmation */}
|
|
321
|
+
<AlertDialog
|
|
322
|
+
open={!!deletingCredential}
|
|
323
|
+
onOpenChange={(open) => !open && setDeletingCredential(null)}
|
|
324
|
+
>
|
|
325
|
+
<AlertDialogContent container={containerRef.current}>
|
|
326
|
+
<AlertDialogHeader>
|
|
327
|
+
<AlertDialogTitle>Delete Credential?</AlertDialogTitle>
|
|
328
|
+
<AlertDialogDescription>
|
|
329
|
+
Are you sure you want to delete "{deletingCredential?.name}"? This action cannot be
|
|
330
|
+
undone and may break workflows that use this credential.
|
|
331
|
+
</AlertDialogDescription>
|
|
332
|
+
</AlertDialogHeader>
|
|
333
|
+
<AlertDialogFooter>
|
|
334
|
+
<AlertDialogCancel onClick={() => setDeletingCredential(null)}>
|
|
335
|
+
Cancel
|
|
336
|
+
</AlertDialogCancel>
|
|
337
|
+
<AlertDialogAction
|
|
338
|
+
onClick={(e) => {
|
|
339
|
+
e.preventDefault();
|
|
340
|
+
if (deletingCredential) {
|
|
341
|
+
deleteCredentialMutation.mutate(deletingCredential.id, {
|
|
342
|
+
onSuccess: () => {
|
|
343
|
+
setDeletingCredential(null);
|
|
344
|
+
if (selectedCredential?.id === deletingCredential.id) {
|
|
345
|
+
closeDetail();
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
onError: () => setDeletingCredential(null),
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}}
|
|
352
|
+
disabled={deleteCredentialMutation.isPending}
|
|
353
|
+
className="bg-destructive hover:bg-destructive/90"
|
|
354
|
+
>
|
|
355
|
+
{deleteCredentialMutation.isPending ? 'Deleting…' : 'Delete'}
|
|
356
|
+
</AlertDialogAction>
|
|
357
|
+
</AlertDialogFooter>
|
|
358
|
+
</AlertDialogContent>
|
|
359
|
+
</AlertDialog>
|
|
360
|
+
</PageLayout>
|
|
361
|
+
);
|
|
362
|
+
};
|