@vertesia/ui 1.5.0-dev.20260910.052912Z → 1.5.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/lib/core/components/Link.js +1 -1
- package/lib/core/components/Link.js.map +1 -1
- package/lib/core/components/SelectList.d.ts.map +1 -1
- package/lib/core/components/SelectList.js +3 -3
- package/lib/core/components/SelectList.js.map +1 -1
- package/lib/core/components/SidePanel.d.ts.map +1 -1
- package/lib/core/components/SidePanel.js +2 -1
- package/lib/core/components/SidePanel.js.map +1 -1
- package/lib/core/components/Spinner.js +1 -1
- package/lib/core/components/Spinner.js.map +1 -1
- package/lib/core/components/TagsInput.js +7 -7
- package/lib/core/components/TagsInput.js.map +1 -1
- package/lib/core/components/shadcn/badge.js +1 -1
- package/lib/core/components/shadcn/badge.js.map +1 -1
- package/lib/core/components/shadcn/button.d.ts.map +1 -1
- package/lib/core/components/shadcn/button.js +2 -2
- package/lib/core/components/shadcn/button.js.map +1 -1
- package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +2 -2
- package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
- package/lib/core/components/shadcn/filters/comboBox/SelectCombobox.js +1 -1
- package/lib/core/components/shadcn/filters/comboBox/SelectCombobox.js.map +1 -1
- package/lib/core/components/shadcn/filters/comboBox/StringListCombobox.js +1 -1
- package/lib/core/components/shadcn/filters/comboBox/StringListCombobox.js.map +1 -1
- package/lib/core/components/shadcn/filters/comboBox/TextCombobox.js +1 -1
- package/lib/core/components/shadcn/filters/comboBox/TextCombobox.js.map +1 -1
- package/lib/core/components/shadcn/filters/filter/dateFilter.js +1 -1
- package/lib/core/components/shadcn/filters/filter/dateFilter.js.map +1 -1
- package/lib/core/components/shadcn/filters/filters.js +1 -1
- package/lib/core/components/shadcn/filters/filters.js.map +1 -1
- package/lib/core/components/shadcn/overflowTabs.js +2 -2
- package/lib/core/components/shadcn/overflowTabs.js.map +1 -1
- package/lib/core/components/shadcn/tabs.js +1 -1
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/features/activity-doc/ActivityDoc.js +1 -1
- package/lib/features/activity-doc/ActivityDoc.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts +1 -0
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +15 -4
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +51 -17
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +5 -3
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +5 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +9 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentPlans.d.ts +1 -1
- package/lib/features/agent/chat/hooks/useAgentPlans.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentPlans.js +5 -5
- package/lib/features/agent/chat/hooks/useAgentPlans.js.map +1 -1
- package/lib/features/layout/GenericPageNavHeader.js +1 -1
- package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
- package/lib/features/magic-pdf/AnnotatedImageSlider.js +1 -1
- package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
- package/lib/features/magic-pdf/GroundedExtractionView.js +3 -3
- package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +2 -2
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.js +9 -7
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js +7 -3
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +4 -2
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
- package/lib/features/oauth/useMcpConnections.js +15 -9
- package/lib/features/oauth/useMcpConnections.js.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js +5 -5
- package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
- package/lib/features/store/objects/components/DocumentInput.js +1 -1
- package/lib/features/store/objects/components/DocumentInput.js.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.js +2 -0
- package/lib/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.d.ts +4 -2
- package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js +6 -3
- package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/features/store/objects/selection/actions/RunIntakeAction.d.ts +8 -0
- package/lib/features/store/objects/selection/actions/RunIntakeAction.d.ts.map +1 -0
- package/lib/features/store/objects/selection/actions/RunIntakeAction.js +65 -0
- package/lib/features/store/objects/selection/actions/RunIntakeAction.js.map +1 -0
- package/lib/features/store/objects/selection/actions/index.d.ts +1 -0
- package/lib/features/store/objects/selection/actions/index.d.ts.map +1 -1
- package/lib/features/store/objects/selection/actions/index.js +1 -0
- package/lib/features/store/objects/selection/actions/index.js.map +1 -1
- package/lib/features/store/objects/upload/DocumentUploadModal.js +1 -1
- package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +11 -3
- package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.js +14 -14
- package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
- package/lib/features/store/types/TypeRegistry.d.ts +275 -150
- package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +275 -150
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
- package/lib/features/user/UserInfo.d.ts +2 -0
- package/lib/features/user/UserInfo.d.ts.map +1 -1
- package/lib/features/user/UserInfo.js +1 -1
- package/lib/features/user/UserInfo.js.map +1 -1
- package/lib/i18n/locales/ar.json +28 -7
- package/lib/i18n/locales/de.json +24 -7
- package/lib/i18n/locales/en.json +24 -7
- package/lib/i18n/locales/es.json +24 -7
- package/lib/i18n/locales/fr.json +25 -7
- package/lib/i18n/locales/it.json +24 -7
- package/lib/i18n/locales/ja.json +24 -7
- package/lib/i18n/locales/ko.json +24 -7
- package/lib/i18n/locales/pt.json +24 -7
- package/lib/i18n/locales/ru.json +26 -7
- package/lib/i18n/locales/tr.json +24 -7
- package/lib/i18n/locales/zh-TW.json +24 -7
- package/lib/i18n/locales/zh.json +24 -7
- package/lib/router/RouteComponent.d.ts.map +1 -1
- package/lib/router/RouteComponent.js +15 -12
- package/lib/router/RouteComponent.js.map +1 -1
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +4 -0
- package/lib/session/UserSession.js.map +1 -1
- package/lib/shell/SplashScreen.js +1 -1
- package/lib/shell/SplashScreen.js.map +1 -1
- package/lib/shell/apps/AppInstallationProvider.d.ts +4 -4
- package/lib/shell/login/SignInIcons.d.ts.map +1 -1
- package/lib/shell/login/SignInIcons.js +2 -1
- package/lib/shell/login/SignInIcons.js.map +1 -1
- package/lib/shell/login/SignInPasswordStep.d.ts +9 -0
- package/lib/shell/login/SignInPasswordStep.d.ts.map +1 -0
- package/lib/shell/login/SignInPasswordStep.js +58 -0
- package/lib/shell/login/SignInPasswordStep.js.map +1 -0
- package/lib/shell/login/SignInPrimitives.d.ts +13 -0
- package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
- package/lib/shell/login/SignInPrimitives.js +11 -1
- package/lib/shell/login/SignInPrimitives.js.map +1 -1
- package/lib/shell/login/SignInProvidersStep.d.ts +3 -1
- package/lib/shell/login/SignInProvidersStep.d.ts.map +1 -1
- package/lib/shell/login/SignInProvidersStep.js +4 -2
- package/lib/shell/login/SignInProvidersStep.js.map +1 -1
- package/lib/shell/login/SignInReturningStep.d.ts +3 -1
- package/lib/shell/login/SignInReturningStep.d.ts.map +1 -1
- package/lib/shell/login/SignInReturningStep.js +18 -8
- package/lib/shell/login/SignInReturningStep.js.map +1 -1
- package/lib/shell/login/SignInTenantStep.d.ts +3 -1
- package/lib/shell/login/SignInTenantStep.d.ts.map +1 -1
- package/lib/shell/login/SignInTenantStep.js +2 -2
- package/lib/shell/login/SignInTenantStep.js.map +1 -1
- package/lib/shell/login/SignInWithProviderButton.d.ts +5 -3
- package/lib/shell/login/SignInWithProviderButton.d.ts.map +1 -1
- package/lib/shell/login/SignInWithProviderButton.js +8 -7
- package/lib/shell/login/SignInWithProviderButton.js.map +1 -1
- package/lib/shell/login/SigninScreen.d.ts.map +1 -1
- package/lib/shell/login/SigninScreen.js +13 -4
- package/lib/shell/login/SigninScreen.js.map +1 -1
- package/lib/shell/login/signInUtils.d.ts +20 -4
- package/lib/shell/login/signInUtils.d.ts.map +1 -1
- package/lib/shell/login/signInUtils.js +47 -1
- package/lib/shell/login/signInUtils.js.map +1 -1
- package/lib/vertesia-ui-core.js +3 -3
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-features.js +33 -33
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.BoNE1APG.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BoNE1APG.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BoPtiSPb.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BoPtiSPb.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.C4BBW5v5.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.C4BBW5v5.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.C81wuNkY.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.C81wuNkY.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.C9GipKIH.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.C9GipKIH.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CWsoS0W9.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CWsoS0W9.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Cr9NtzZB.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Cr9NtzZB.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DEpkHOD5.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DEpkHOD5.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DPXaRKFO.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DPXaRKFO.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.D_QNm1Xg.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.D_QNm1Xg.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.F26Cc0f7.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.F26Cc0f7.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.YkXIESV_.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.YkXIESV_.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.js +3 -3
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-router.js +1 -1
- package/lib/vertesia-ui-router.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +15 -9
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +2 -2
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/json-view/JSONCode.js +1 -1
- package/lib/widgets/json-view/JSONCode.js.map +1 -1
- package/lib/widgets/upload/DropZone.d.ts.map +1 -1
- package/lib/widgets/upload/DropZone.js +1 -1
- package/lib/widgets/upload/DropZone.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
- package/package.json +7 -7
- package/src/core/components/Link.tsx +1 -1
- package/src/core/components/SelectList.tsx +5 -2
- package/src/core/components/SidePanel.tsx +65 -60
- package/src/core/components/Spinner.tsx +1 -1
- package/src/core/components/TagsInput.tsx +7 -7
- package/src/core/components/shadcn/badge.tsx +1 -1
- package/src/core/components/shadcn/button.tsx +2 -3
- package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +2 -2
- package/src/core/components/shadcn/filters/comboBox/SelectCombobox.tsx +1 -1
- package/src/core/components/shadcn/filters/comboBox/StringListCombobox.tsx +1 -1
- package/src/core/components/shadcn/filters/comboBox/TextCombobox.tsx +1 -1
- package/src/core/components/shadcn/filters/filter/dateFilter.tsx +1 -1
- package/src/core/components/shadcn/filters/filters.tsx +1 -1
- package/src/core/components/shadcn/overflowTabs.tsx +2 -2
- package/src/core/components/shadcn/tabs.tsx +1 -1
- package/src/css/utilities.css +7 -0
- package/src/features/activity-doc/ActivityDoc.tsx +1 -1
- package/src/features/agent/chat/AskUserWidget.test.tsx +24 -2
- package/src/features/agent/chat/AskUserWidget.tsx +19 -4
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +150 -1
- package/src/features/agent/chat/ModernAgentConversation.tsx +59 -21
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +62 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +8 -7
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +17 -1
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +4 -3
- package/src/features/agent/chat/hooks/useAgentPlans.test.ts +52 -0
- package/src/features/agent/chat/hooks/useAgentPlans.ts +5 -5
- package/src/features/layout/GenericPageNavHeader.test.tsx +36 -0
- package/src/features/layout/GenericPageNavHeader.tsx +1 -1
- package/src/features/magic-pdf/AnnotatedImageSlider.tsx +1 -1
- package/src/features/magic-pdf/GroundedExtractionView.tsx +3 -3
- package/src/features/oauth/McpConnectionsButton.test.tsx +56 -0
- package/src/features/oauth/McpConnectionsButton.tsx +9 -6
- package/src/features/oauth/McpConnectionsDialog.tsx +14 -5
- package/src/features/oauth/useMcpConnections.test.ts +10 -0
- package/src/features/oauth/useMcpConnections.ts +18 -10
- package/src/features/permissions/UserPermissionsProvider.tsx +1 -1
- package/src/features/store/objects/DocumentPreviewPanel.tsx +10 -10
- package/src/features/store/objects/components/DocumentInput.tsx +1 -1
- package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -0
- package/src/features/store/objects/selection/SelectionActions.tsx +13 -6
- package/src/features/store/objects/selection/actions/RunIntakeAction.tsx +69 -0
- package/src/features/store/objects/selection/actions/index.ts +1 -0
- package/src/features/store/objects/upload/DocumentUploadModal.tsx +1 -1
- package/src/features/store/types/ContentObjectTypesTable.tsx +20 -3
- package/src/features/store/types/IntakePolicyEditor.tsx +33 -28
- package/src/features/user/UserInfo.tsx +1 -1
- package/src/i18n/locales/ar.json +28 -7
- package/src/i18n/locales/de.json +24 -7
- package/src/i18n/locales/en.json +24 -7
- package/src/i18n/locales/es.json +24 -7
- package/src/i18n/locales/fr.json +25 -7
- package/src/i18n/locales/it.json +24 -7
- package/src/i18n/locales/ja.json +24 -7
- package/src/i18n/locales/ko.json +24 -7
- package/src/i18n/locales/pt.json +24 -7
- package/src/i18n/locales/ru.json +26 -7
- package/src/i18n/locales/tr.json +24 -7
- package/src/i18n/locales/zh-TW.json +24 -7
- package/src/i18n/locales/zh.json +24 -7
- package/src/router/RouteComponent.test.tsx +65 -1
- package/src/router/RouteComponent.tsx +18 -15
- package/src/session/UserSession.test.ts +65 -0
- package/src/session/UserSession.ts +4 -0
- package/src/shell/SplashScreen.tsx +1 -1
- package/src/shell/login/SignInIcons.tsx +2 -1
- package/src/shell/login/SignInPasswordRequired.test.tsx +82 -0
- package/src/shell/login/SignInPasswordStep.test.tsx +71 -0
- package/src/shell/login/SignInPasswordStep.tsx +103 -0
- package/src/shell/login/SignInPrimitives.tsx +53 -1
- package/src/shell/login/SignInProvidersStep.tsx +8 -4
- package/src/shell/login/SignInReturningStep.tsx +20 -8
- package/src/shell/login/SignInTenantStep.tsx +6 -2
- package/src/shell/login/SignInWithProviderButton.tsx +11 -7
- package/src/shell/login/SigninScreen.tsx +32 -3
- package/src/shell/login/signInPassword.test.ts +133 -0
- package/src/shell/login/signInUtils.ts +60 -7
- package/src/widgets/json-view/JSONCode.test.tsx +2 -2
- package/src/widgets/json-view/JSONCode.tsx +1 -1
- package/src/widgets/upload/DropZone.tsx +2 -4
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts +0 -7
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts.map +0 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +0 -51
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +0 -1
- package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +0 -1
- package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +0 -104
|
@@ -18,14 +18,14 @@ export interface UseAgentPlansResult {
|
|
|
18
18
|
* Key improvement: incremental processing. Instead of scanning ALL messages
|
|
19
19
|
* on every change, tracks `lastProcessedIndex` and only scans new messages.
|
|
20
20
|
*/
|
|
21
|
-
export function useAgentPlans(messages: AgentMessage[], interactive: boolean
|
|
21
|
+
export function useAgentPlans(messages: AgentMessage[], interactive: boolean): UseAgentPlansResult {
|
|
22
22
|
const [plans, setPlans] = useState<Array<{ plan: Plan; timestamp: number }>>([]);
|
|
23
23
|
const [activePlanIndex, setActivePlanIndex] = useState<number>(0);
|
|
24
24
|
const [workstreamStatusMap, setWorkstreamStatusMap] = useState<
|
|
25
25
|
Map<number, Map<string, 'pending' | 'in_progress' | 'completed' | 'skipped'>>
|
|
26
26
|
>(new Map());
|
|
27
27
|
const [showInput, setShowInput] = useState(interactive);
|
|
28
|
-
const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(
|
|
28
|
+
const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(false);
|
|
29
29
|
|
|
30
30
|
// Incremental processing: track how far we've scanned
|
|
31
31
|
const lastProcessedIndex = useRef<number>(-1);
|
|
@@ -38,12 +38,12 @@ export function useAgentPlans(messages: AgentMessage[], interactive: boolean, is
|
|
|
38
38
|
setPlans([]);
|
|
39
39
|
setActivePlanIndex(0);
|
|
40
40
|
setWorkstreamStatusMap(new Map());
|
|
41
|
-
//
|
|
42
|
-
setShowSlidingPanel(
|
|
41
|
+
// Open automatically only once a plan is available.
|
|
42
|
+
setShowSlidingPanel(false);
|
|
43
43
|
lastProcessedIndex.current = -1;
|
|
44
44
|
knownPlanTimestamps.current.clear();
|
|
45
45
|
}
|
|
46
|
-
}, [messages.length
|
|
46
|
+
}, [messages.length]);
|
|
47
47
|
|
|
48
48
|
// Helper to determine showInput from the latest message
|
|
49
49
|
const updateShowInput = useCallback(
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { screen } from '@testing-library/react';
|
|
2
|
+
import type { ComponentProps } from 'react';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { renderWithProviders } from '../../__tests__/test-utils';
|
|
5
|
+
import { GenericPageNavHeader } from './GenericPageNavHeader';
|
|
6
|
+
|
|
7
|
+
vi.mock('@vertesia/ui/router', () => ({ useNavigate: () => vi.fn() }));
|
|
8
|
+
|
|
9
|
+
describe('GenericPageNavHeader breadcrumbs', () => {
|
|
10
|
+
it.each(['Parent', null])('ignores non-array breadcrumbs: %s', (breadcrumbs) => {
|
|
11
|
+
renderWithProviders(
|
|
12
|
+
<GenericPageNavHeader
|
|
13
|
+
title="Page"
|
|
14
|
+
useDynamicBreadcrumbs={false}
|
|
15
|
+
breadcrumbs={breadcrumbs as unknown as ComponentProps<typeof GenericPageNavHeader>['breadcrumbs']}
|
|
16
|
+
/>,
|
|
17
|
+
);
|
|
18
|
+
expect(screen.getByText('Page')).toBeDefined();
|
|
19
|
+
expect(screen.queryByText('Parent')).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('preserves breadcrumb elements', () => {
|
|
23
|
+
renderWithProviders(
|
|
24
|
+
<GenericPageNavHeader
|
|
25
|
+
title="Page"
|
|
26
|
+
useDynamicBreadcrumbs={false}
|
|
27
|
+
breadcrumbs={[
|
|
28
|
+
<a key="parent" href="/parent">
|
|
29
|
+
Parent
|
|
30
|
+
</a>,
|
|
31
|
+
]}
|
|
32
|
+
/>,
|
|
33
|
+
);
|
|
34
|
+
expect(screen.getByText('Parent')).toBeDefined();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -124,7 +124,7 @@ export function GenericPageNavHeader({
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// Add current page breadcrumbs
|
|
127
|
-
if (breadcrumbs
|
|
127
|
+
if (Array.isArray(breadcrumbs)) {
|
|
128
128
|
breadcrumbs.forEach((breadcrumb) => {
|
|
129
129
|
// Preserve the entire React element as label
|
|
130
130
|
const label = breadcrumb.props?.children || breadcrumb;
|
|
@@ -326,7 +326,7 @@ function ImageTypeButton({ type, currentType, onClick, icon, tooltip }: ImageTyp
|
|
|
326
326
|
aria-pressed={isSelected}
|
|
327
327
|
className={clsx(
|
|
328
328
|
'p-1 rounded cursor-pointer transition-colors',
|
|
329
|
-
isSelected ? 'text-
|
|
329
|
+
isSelected ? 'text-info bg-info' : 'text-muted hover:text-foreground hover:bg-muted',
|
|
330
330
|
)}
|
|
331
331
|
onClick={onClick}
|
|
332
332
|
>
|
|
@@ -659,7 +659,7 @@ function PageWithOverlay({
|
|
|
659
659
|
'absolute cursor-pointer border rounded-[1px] transition-colors',
|
|
660
660
|
citation.misaligned && 'border-dashed',
|
|
661
661
|
isSelected
|
|
662
|
-
? 'border-2 border-
|
|
662
|
+
? 'border-2 border-info bg-info/20 z-10'
|
|
663
663
|
: citation.verified
|
|
664
664
|
? 'border-success/70 hover:bg-success/20'
|
|
665
665
|
: citation.reviewed
|
|
@@ -853,7 +853,7 @@ function ArrayTable({
|
|
|
853
853
|
className={cn(
|
|
854
854
|
'text-start rounded px-1 w-full',
|
|
855
855
|
isSelected
|
|
856
|
-
? 'bg-
|
|
856
|
+
? 'bg-info/15 ring-1 ring-primary'
|
|
857
857
|
: citation
|
|
858
858
|
? 'hover:bg-muted cursor-pointer'
|
|
859
859
|
: 'text-muted cursor-default',
|
|
@@ -909,7 +909,7 @@ function LeafRow({
|
|
|
909
909
|
onClick={() => citation && onSelect(path)}
|
|
910
910
|
className={cn(
|
|
911
911
|
'flex items-center gap-2 w-full text-start text-sm rounded px-1.5 py-0.5',
|
|
912
|
-
isSelected ? 'bg-
|
|
912
|
+
isSelected ? 'bg-info/15 ring-1 ring-primary' : citation ? 'hover:bg-muted' : '',
|
|
913
913
|
!citation && 'cursor-default',
|
|
914
914
|
)}
|
|
915
915
|
>
|
|
@@ -183,6 +183,62 @@ describe('MCP connection controls', () => {
|
|
|
183
183
|
expect(onChange).toHaveBeenCalledWith(['linear']);
|
|
184
184
|
});
|
|
185
185
|
|
|
186
|
+
it.each([{ oauthIds: [] }, { oauthIds: ['anonymous'] }])(
|
|
187
|
+
'shows anonymous servers without status requests, including stale OAuth ids %j',
|
|
188
|
+
async ({ oauthIds }) => {
|
|
189
|
+
mocks.getInstalledApps.mockResolvedValue([
|
|
190
|
+
{
|
|
191
|
+
id: 'anonymous-app',
|
|
192
|
+
manifest: {
|
|
193
|
+
name: 'anonymous-app',
|
|
194
|
+
tool_collections: [
|
|
195
|
+
{
|
|
196
|
+
type: 'mcp',
|
|
197
|
+
id: 'anonymous',
|
|
198
|
+
name: 'Anonymous MCP',
|
|
199
|
+
namespace: 'anonymous',
|
|
200
|
+
url: 'https://anonymous.example.com/mcp',
|
|
201
|
+
auth: 'none',
|
|
202
|
+
oauth_app: 'stale-oauth-app',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
oauth_collection_ids: oauthIds,
|
|
207
|
+
},
|
|
208
|
+
]);
|
|
209
|
+
const onChange = vi.fn();
|
|
210
|
+
const { rerender } = renderWithProviders(
|
|
211
|
+
<McpConnectionsInlineList disabledCollections={['other']} onChange={onChange} />,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
expect(await screen.findByText('Anonymous MCP')).not.toBeNull();
|
|
215
|
+
expect(screen.getAllByText('No authentication')).toHaveLength(1);
|
|
216
|
+
expect(screen.queryByRole('button', { name: /connect/i })).toBeNull();
|
|
217
|
+
expect(mocks.getStatus).not.toHaveBeenCalled();
|
|
218
|
+
expect(mocks.getCollectionStatus).not.toHaveBeenCalled();
|
|
219
|
+
|
|
220
|
+
fireEvent.click(screen.getByRole('switch', { name: 'Deactivate Anonymous MCP for this conversation' }));
|
|
221
|
+
expect(onChange).toHaveBeenLastCalledWith(['other', 'anonymous']);
|
|
222
|
+
rerender(<McpConnectionsInlineList disabledCollections={['other', 'anonymous']} onChange={onChange} />);
|
|
223
|
+
fireEvent.click(screen.getByRole('switch', { name: 'Activate Anonymous MCP for this conversation' }));
|
|
224
|
+
expect(onChange).toHaveBeenLastCalledWith(['other']);
|
|
225
|
+
rerender(<McpConnectionsInlineList onChange={onChange} readOnly />);
|
|
226
|
+
expect(screen.getByRole('switch')).toHaveProperty('disabled', true);
|
|
227
|
+
|
|
228
|
+
rerender(<McpConnectionsActionMenu onChange={onChange} />);
|
|
229
|
+
fireEvent.pointerDown(await screen.findByRole('button', { name: /settings/i }));
|
|
230
|
+
const menuItem = await screen.findByText('MCP');
|
|
231
|
+
expect(screen.getByText('1')).not.toBeNull();
|
|
232
|
+
fireEvent.click(menuItem);
|
|
233
|
+
expect(await screen.findByText('Anonymous MCP')).not.toBeNull();
|
|
234
|
+
expect(screen.getByText('No authentication')).not.toBeNull();
|
|
235
|
+
expect(screen.queryByRole('button', { name: /connect/i })).toBeNull();
|
|
236
|
+
fireEvent.click(screen.getByRole('switch', { name: 'Deactivate Anonymous MCP for this conversation' }));
|
|
237
|
+
expect(onChange).toHaveBeenLastCalledWith(['anonymous']);
|
|
238
|
+
expect(mocks.getStatus).not.toHaveBeenCalled();
|
|
239
|
+
},
|
|
240
|
+
);
|
|
241
|
+
|
|
186
242
|
it('renders MCP rows before connection statuses finish loading', async () => {
|
|
187
243
|
const statusRequest =
|
|
188
244
|
deferred<
|
|
@@ -7,6 +7,7 @@ import { RemoteMcpConnectionButton } from './RemoteMcpConnectionButton.js';
|
|
|
7
7
|
import {
|
|
8
8
|
countConnectedActiveGroups,
|
|
9
9
|
getConnectedActiveGroupLabels,
|
|
10
|
+
isGroupConnected,
|
|
10
11
|
isGroupDisabled,
|
|
11
12
|
toggleGroupDisabled,
|
|
12
13
|
useMcpConnections,
|
|
@@ -29,7 +30,7 @@ export interface McpConnectionsButtonProps {
|
|
|
29
30
|
/**
|
|
30
31
|
* Toolbar button that opens the MCP connections dialog. The badge shows how many MCP
|
|
31
32
|
* servers are connected and active for this conversation.
|
|
32
|
-
* Renders nothing when the project has no
|
|
33
|
+
* Renders nothing when the project has no MCP servers installed.
|
|
33
34
|
*/
|
|
34
35
|
export function McpConnectionsButton({
|
|
35
36
|
disabledCollections,
|
|
@@ -93,7 +94,7 @@ export function McpConnectionsButton({
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
/**
|
|
96
|
-
* Inline MCP status list for forms. It shows all available
|
|
97
|
+
* Inline MCP status list for forms. It shows all available MCP groups
|
|
97
98
|
* without requiring the user to open the management dialog.
|
|
98
99
|
*/
|
|
99
100
|
export function McpConnectionsInlineList({
|
|
@@ -127,7 +128,7 @@ export function McpConnectionsInlineList({
|
|
|
127
128
|
<div className="space-y-1">
|
|
128
129
|
{groups.map((group) => {
|
|
129
130
|
const active = !isGroupDisabled(group, disabledCollections);
|
|
130
|
-
const connected = group
|
|
131
|
+
const connected = isGroupConnected(group);
|
|
131
132
|
const interactiveOAuth = group.authType === 'oauth' && group.oauthGrantType !== 'client_credentials';
|
|
132
133
|
const StatusIcon = connected ? Link2 : Link2Off;
|
|
133
134
|
return (
|
|
@@ -179,9 +180,11 @@ export function McpConnectionsInlineList({
|
|
|
179
180
|
/>
|
|
180
181
|
) : (
|
|
181
182
|
<Badge variant="outline" className="h-6 w-32 justify-center px-2 text-xs">
|
|
182
|
-
{group.authType === '
|
|
183
|
-
? t('mcpConnections.
|
|
184
|
-
:
|
|
183
|
+
{group.authType === 'none'
|
|
184
|
+
? t('mcpConnections.noAuthentication')
|
|
185
|
+
: group.authType === 'api_key'
|
|
186
|
+
? t('mcpConnections.apiKey')
|
|
187
|
+
: t('mcpConnections.managedByApp')}
|
|
185
188
|
</Badge>
|
|
186
189
|
)}
|
|
187
190
|
{onChange && (
|
|
@@ -2,7 +2,12 @@ import { useUITranslation } from '@vertesia/ui/i18n';
|
|
|
2
2
|
import { Link2, Link2Off } from 'lucide-react';
|
|
3
3
|
import { Badge, Button, Modal, ModalBody, ModalTitle, Spinner, Switch, VTooltip } from '../../core/index.js';
|
|
4
4
|
import { RemoteMcpConnectionButton } from './RemoteMcpConnectionButton.js';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isGroupConnected,
|
|
7
|
+
isGroupDisabled,
|
|
8
|
+
type McpConnectionGroup,
|
|
9
|
+
toggleGroupDisabled,
|
|
10
|
+
} from './useMcpConnections.js';
|
|
6
11
|
|
|
7
12
|
export interface McpConnectionsDialogProps {
|
|
8
13
|
isOpen: boolean;
|
|
@@ -61,7 +66,7 @@ export function McpConnectionsDialog({
|
|
|
61
66
|
<div className="space-y-1">
|
|
62
67
|
{groups.map((group) => {
|
|
63
68
|
const active = !isGroupDisabled(group, disabledCollections);
|
|
64
|
-
const connected = group
|
|
69
|
+
const connected = isGroupConnected(group);
|
|
65
70
|
const interactiveOAuth =
|
|
66
71
|
group.authType === 'oauth' && group.oauthGrantType !== 'client_credentials';
|
|
67
72
|
const StatusIcon = connected ? Link2 : Link2Off;
|
|
@@ -115,11 +120,15 @@ export function McpConnectionsDialog({
|
|
|
115
120
|
showDisconnect
|
|
116
121
|
readOnly={readOnly}
|
|
117
122
|
/>
|
|
118
|
-
) :
|
|
123
|
+
) : (
|
|
119
124
|
<Badge variant="outline" className="h-6 w-32 justify-center px-2 text-xs">
|
|
120
|
-
{
|
|
125
|
+
{group.authType === 'none'
|
|
126
|
+
? t('mcpConnections.noAuthentication')
|
|
127
|
+
: group.authType === 'api_key'
|
|
128
|
+
? t('mcpConnections.apiKey')
|
|
129
|
+
: t('mcpConnections.managedByApp')}
|
|
121
130
|
</Badge>
|
|
122
|
-
)
|
|
131
|
+
)}
|
|
123
132
|
{onChange && (
|
|
124
133
|
<Switch
|
|
125
134
|
size="sm"
|
|
@@ -93,3 +93,13 @@ describe('toggleGroupDisabled', () => {
|
|
|
93
93
|
expect(toggleGroupDisabled(g, disabled, true)).toEqual([]);
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
|
+
|
|
97
|
+
describe('anonymous MCP groups', () => {
|
|
98
|
+
it('counts anonymous servers without credential status and respects disabled collections', () => {
|
|
99
|
+
const anonymous = { ...group(['anonymous'], false, 'Anonymous'), authType: 'none' as const };
|
|
100
|
+
expect(countConnectedActiveGroups([anonymous])).toBe(1);
|
|
101
|
+
expect(getConnectedActiveGroupLabels([anonymous])).toEqual(['Anonymous']);
|
|
102
|
+
expect(countConnectedActiveGroups([anonymous], ['anonymous'])).toBe(0);
|
|
103
|
+
expect(getConnectedActiveGroupLabels([anonymous], ['anonymous'])).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -20,13 +20,13 @@ export interface McpConnectionGroup {
|
|
|
20
20
|
memberIds: string[];
|
|
21
21
|
/** Collection names represented by this row. */
|
|
22
22
|
memberNames: string[];
|
|
23
|
-
authType: 'oauth' | 'api_key';
|
|
23
|
+
authType: 'none' | 'oauth' | 'api_key';
|
|
24
24
|
oauthGrantType?: 'authorization_code' | 'client_credentials';
|
|
25
25
|
authStatus?: OAuthAuthStatus;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Loads the project's installed
|
|
29
|
+
* Loads the project's installed MCP tool collections and resolves their status.
|
|
30
30
|
*
|
|
31
31
|
* Shared by the MCP connections button (badge count) and dialog (list) so the data is
|
|
32
32
|
* fetched once and refreshed together after connect/disconnect.
|
|
@@ -57,8 +57,10 @@ export function useMcpConnections() {
|
|
|
57
57
|
const mcpCollections = inst.manifest.tool_collections
|
|
58
58
|
.map((c) => normalizeToolCollection(c))
|
|
59
59
|
.filter((c): c is MCPToolCollectionObject => c.type === 'mcp');
|
|
60
|
-
const oauthCollections = mcpCollections.filter(
|
|
61
|
-
|
|
60
|
+
const oauthCollections = mcpCollections.filter(
|
|
61
|
+
(c) => c.auth !== 'none' && c.auth !== 'api_key' && oauthIds.includes(c.id),
|
|
62
|
+
);
|
|
63
|
+
const directCollections = mcpCollections.filter((c) => c.auth === 'none' || c.auth === 'api_key');
|
|
62
64
|
|
|
63
65
|
const providerMap = new Map<string, MCPToolCollectionObject[]>();
|
|
64
66
|
const oauthAppMap = new Map<string, MCPToolCollectionObject[]>();
|
|
@@ -124,16 +126,16 @@ export function useMcpConnections() {
|
|
|
124
126
|
});
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
for (const col of
|
|
129
|
+
for (const col of directCollections) {
|
|
128
130
|
allGroups.push({
|
|
129
|
-
key: `${inst.id}
|
|
131
|
+
key: `${inst.id}:${col.auth}:${col.id}`,
|
|
130
132
|
appId: inst.id,
|
|
131
133
|
appName: inst.manifest.title || inst.manifest.name,
|
|
132
134
|
label: col.name,
|
|
133
135
|
representativeId: col.id,
|
|
134
136
|
memberIds: [col.id],
|
|
135
137
|
memberNames: [col.name],
|
|
136
|
-
authType: 'api_key',
|
|
138
|
+
authType: col.auth === 'none' ? 'none' : 'api_key',
|
|
137
139
|
});
|
|
138
140
|
}
|
|
139
141
|
}
|
|
@@ -155,6 +157,8 @@ export function useMcpConnections() {
|
|
|
155
157
|
const statusRequestsByApp = new Map<string, Promise<OAuthAuthStatus[]>>();
|
|
156
158
|
const groupsWithStatus = await Promise.all(
|
|
157
159
|
allGroups.map(async (group) => {
|
|
160
|
+
// Anonymous servers are available without a credential status lookup.
|
|
161
|
+
if (group.authType === 'none') return group;
|
|
158
162
|
try {
|
|
159
163
|
let statusRequest = statusRequestsByApp.get(group.appId);
|
|
160
164
|
if (!statusRequest) {
|
|
@@ -219,15 +223,19 @@ export function toggleGroupDisabled(
|
|
|
219
223
|
return Array.from(current);
|
|
220
224
|
}
|
|
221
225
|
|
|
226
|
+
/** Anonymous servers are available without authentication; other modes require valid credentials. */
|
|
227
|
+
export function isGroupConnected(group: McpConnectionGroup): boolean {
|
|
228
|
+
return group.authType === 'none' || group.authStatus?.authenticated === true;
|
|
229
|
+
}
|
|
230
|
+
|
|
222
231
|
/** Count connected MCP groups that are enabled for the current conversation. */
|
|
223
232
|
export function countConnectedActiveGroups(groups: McpConnectionGroup[], disabled?: string[]): number {
|
|
224
|
-
return groups.filter((group) => group
|
|
225
|
-
.length;
|
|
233
|
+
return groups.filter((group) => isGroupConnected(group) && !isGroupDisabled(group, disabled)).length;
|
|
226
234
|
}
|
|
227
235
|
|
|
228
236
|
/** Names of connected MCP groups that are enabled for the current conversation. */
|
|
229
237
|
export function getConnectedActiveGroupLabels(groups: McpConnectionGroup[], disabled?: string[]): string[] {
|
|
230
238
|
return groups
|
|
231
|
-
.filter((group) => group
|
|
239
|
+
.filter((group) => isGroupConnected(group) && !isGroupDisabled(group, disabled))
|
|
232
240
|
.map((group) => group.label);
|
|
233
241
|
}
|
|
@@ -104,7 +104,7 @@ export function UserPermissionProvider({ children, loadingIcon }: UserPermission
|
|
|
104
104
|
<div className="flex min-h-dvh items-center justify-center bg-background px-6 text-foreground">
|
|
105
105
|
<div className="w-full max-w-md space-y-6 text-center">
|
|
106
106
|
<div aria-hidden="true" className="flex justify-center">
|
|
107
|
-
{loadingIcon || (!failed && <Spinner size="2xl" className="text-
|
|
107
|
+
{loadingIcon || (!failed && <Spinner size="2xl" className="text-info" />)}
|
|
108
108
|
</div>
|
|
109
109
|
<div
|
|
110
110
|
role={failed ? 'alert' : 'status'}
|
|
@@ -132,7 +132,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
132
132
|
{/* Header */}
|
|
133
133
|
<div className="flex items-center justify-between px-4 py-3 border-b dark:border-border bg-gradient-to-r from-indigo-50 to-gray-50 dark:from-gray-800 dark:to-gray-900">
|
|
134
134
|
<div className="flex items-center">
|
|
135
|
-
<FileText className="h-5 w-5 text-
|
|
135
|
+
<FileText className="h-5 w-5 text-info me-2" />
|
|
136
136
|
<h2 className="text-lg font-semibold text-foreground truncate">
|
|
137
137
|
{isLoading ? t('store.loadingDocument') : object?.name || t('store.documentPreview')}
|
|
138
138
|
</h2>
|
|
@@ -142,7 +142,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
142
142
|
variant="ghost"
|
|
143
143
|
size="sm"
|
|
144
144
|
onClick={handleViewFullDocument}
|
|
145
|
-
className="flex items-center gap-1 text-
|
|
145
|
+
className="flex items-center gap-1 text-info hover:text-info"
|
|
146
146
|
>
|
|
147
147
|
<Maximize2 className="h-4 w-4" />
|
|
148
148
|
<span>{t('store.fullView')}</span>
|
|
@@ -162,7 +162,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
162
162
|
{isLoading ? (
|
|
163
163
|
<div className="flex-1 flex items-center justify-center">
|
|
164
164
|
<div className="text-center">
|
|
165
|
-
<Spinner size="lg" className="text-
|
|
165
|
+
<Spinner size="lg" className="text-info mb-2" />
|
|
166
166
|
<p className="text-muted">{t('store.loadingDocument')}</p>
|
|
167
167
|
</div>
|
|
168
168
|
</div>
|
|
@@ -175,7 +175,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
175
175
|
variant="unstyled"
|
|
176
176
|
className={`py-2 px-4 font-medium border-b-2 ${
|
|
177
177
|
currentTab === 'preview'
|
|
178
|
-
? 'border-primary text-
|
|
178
|
+
? 'border-primary text-info'
|
|
179
179
|
: 'border-transparent text-muted hover:text-foreground'
|
|
180
180
|
}`}
|
|
181
181
|
onClick={() => setCurrentTab('preview')}
|
|
@@ -189,7 +189,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
189
189
|
variant="unstyled"
|
|
190
190
|
className={`py-2 px-4 font-medium border-b-2 ${
|
|
191
191
|
currentTab === 'properties'
|
|
192
|
-
? 'border-primary text-
|
|
192
|
+
? 'border-primary text-info'
|
|
193
193
|
: 'border-transparent text-muted hover:text-foreground'
|
|
194
194
|
}`}
|
|
195
195
|
onClick={() => setCurrentTab('properties')}
|
|
@@ -209,12 +209,12 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
209
209
|
{/* Text/Markdown Content */}
|
|
210
210
|
{loadingText ? (
|
|
211
211
|
<div className="flex items-center justify-center h-40">
|
|
212
|
-
<Spinner size="md" className="text-
|
|
212
|
+
<Spinner size="md" className="text-info" />
|
|
213
213
|
</div>
|
|
214
214
|
) : text ? (
|
|
215
215
|
<div className="shadow rounded-md p-4 border border-border bg-white dark:bg-muted">
|
|
216
216
|
{seemsMarkdown ? (
|
|
217
|
-
<div className="prose prose-sm max-w-none prose-p:my-2 prose-pre:bg-muted prose-pre:my-2 prose-headings:text-
|
|
217
|
+
<div className="prose prose-sm max-w-none prose-p:my-2 prose-pre:bg-muted prose-pre:my-2 prose-headings:text-info dark:prose-invert">
|
|
218
218
|
<MarkdownRenderer>{text}</MarkdownRenderer>
|
|
219
219
|
</div>
|
|
220
220
|
) : (
|
|
@@ -238,7 +238,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
238
238
|
</div>
|
|
239
239
|
) : (
|
|
240
240
|
<div className="flex items-center justify-center h-40">
|
|
241
|
-
<Spinner size="md" className="text-
|
|
241
|
+
<Spinner size="md" className="text-info" />
|
|
242
242
|
</div>
|
|
243
243
|
)}
|
|
244
244
|
</div>
|
|
@@ -247,7 +247,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
247
247
|
{/* PDF Content Notice */}
|
|
248
248
|
{isPdf && (
|
|
249
249
|
<div className="flex flex-col items-center justify-center h-64 border border-border rounded-md p-4 bg-muted">
|
|
250
|
-
<FileText className="h-16 w-16 text-
|
|
250
|
+
<FileText className="h-16 w-16 text-info mb-4" />
|
|
251
251
|
<p className="text-muted text-center mb-4">{t('store.pdfPreviewFullView')}</p>
|
|
252
252
|
<Button
|
|
253
253
|
onClick={handleViewFullDocument}
|
|
@@ -353,7 +353,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
353
353
|
}
|
|
354
354
|
}}
|
|
355
355
|
variant="outline"
|
|
356
|
-
className="text-
|
|
356
|
+
className="text-info border-primary hover:bg-info"
|
|
357
357
|
>
|
|
358
358
|
<Download className="h-4 w-4 me-2" />
|
|
359
359
|
{t('pdf.download')}
|
|
@@ -87,7 +87,7 @@ export function DocumentInput({ object }: DocumentInputProps) {
|
|
|
87
87
|
<SelectDocumentModal value={actualValue} isOpen={isOn} onClose={onSelect} />
|
|
88
88
|
</div>
|
|
89
89
|
{doc && (
|
|
90
|
-
<div className="p-1 semibold text-sm text-muted dark:text-foreground">
|
|
90
|
+
<div className="p-1 font-semibold text-sm text-muted dark:text-foreground">
|
|
91
91
|
{typeof doc.properties?.title === 'string' ? doc.properties.title : doc.name}
|
|
92
92
|
</div>
|
|
93
93
|
)}
|
|
@@ -10,6 +10,7 @@ import { ChangeTypeAction } from './actions/ChangeTypeAction';
|
|
|
10
10
|
import { DeleteObjectsAction, DeleteObjectsFromCollectionsAction } from './actions/DeleteObjectsAction';
|
|
11
11
|
import { ExportPropertiesAction } from './actions/ExportPropertiesAction';
|
|
12
12
|
import { RemoveFromCollectionAction } from './actions/RemoveFromCollectionAction';
|
|
13
|
+
import { RunIntakeAction } from './actions/RunIntakeAction';
|
|
13
14
|
import { ObjectsActionContext } from './ObjectsActionContextClass';
|
|
14
15
|
import { ObjectsActionContextReact, useObjectsActionContext } from './ObjectsActionHooks';
|
|
15
16
|
import type { ObjectsActionSpec } from './ObjectsActionSpec';
|
|
@@ -18,6 +19,7 @@ const DEFAULT_ACTIONS: ObjectsActionSpec[] = [
|
|
|
18
19
|
ExportPropertiesAction,
|
|
19
20
|
ChangeTypeAction,
|
|
20
21
|
AddToCollectionAction,
|
|
22
|
+
RunIntakeAction,
|
|
21
23
|
DeleteObjectsAction,
|
|
22
24
|
RemoveFromCollectionAction,
|
|
23
25
|
DeleteObjectsFromCollectionsAction,
|
|
@@ -7,7 +7,6 @@ import { useState } from 'react';
|
|
|
7
7
|
import { type DocumentSelection, useDocumentSelection } from '../DocumentSelectionProvider.js';
|
|
8
8
|
import { DocumentUploadModal } from '../upload/DocumentUploadModal.js';
|
|
9
9
|
import { ExportPropertiesAction } from './actions/ExportPropertiesAction';
|
|
10
|
-
import { StartWorkflowButton } from './actions/StartWorkflowButton';
|
|
11
10
|
import { ObjectsActionContextProvider } from './ObjectsActionContext';
|
|
12
11
|
import { useObjectsActionContext } from './ObjectsActionHooks';
|
|
13
12
|
import type { ObjectsActionSpec } from './ObjectsActionSpec';
|
|
@@ -17,8 +16,10 @@ interface SelectionActionsProps {
|
|
|
17
16
|
allowMutations?: boolean;
|
|
18
17
|
allowDelete?: boolean;
|
|
19
18
|
/**
|
|
20
|
-
* Opt-in: shows the "Start Workflow"
|
|
21
|
-
* surfaces — callers must pass a permission-gated value (e.g.
|
|
19
|
+
* Opt-in: shows the "Start Workflow" entry in the actions menu. Defaults to `false` so it never
|
|
20
|
+
* leaks to read-only surfaces — callers must pass a permission-gated value (e.g.
|
|
21
|
+
* `canRunWorkflow(perms)`). Running a workflow is its own permission, so this is deliberately
|
|
22
|
+
* separate from `allowMutations`.
|
|
22
23
|
*/
|
|
23
24
|
allowWorkflowRun?: boolean;
|
|
24
25
|
}
|
|
@@ -52,11 +53,11 @@ export function SelectionActions({
|
|
|
52
53
|
</Button>
|
|
53
54
|
</div>
|
|
54
55
|
)}
|
|
55
|
-
{allowWorkflowRun && <StartWorkflowButton />}
|
|
56
56
|
<SelectionActionsPopover
|
|
57
57
|
selection={selection}
|
|
58
58
|
allowMutations={allowMutations}
|
|
59
59
|
allowDelete={allowDelete}
|
|
60
|
+
allowWorkflowRun={allowWorkflowRun}
|
|
60
61
|
>
|
|
61
62
|
{(actions) =>
|
|
62
63
|
actions.length > 0 ? (
|
|
@@ -123,7 +124,9 @@ function SelectionActionsPopover({
|
|
|
123
124
|
children,
|
|
124
125
|
allowMutations = true,
|
|
125
126
|
allowDelete = true,
|
|
126
|
-
|
|
127
|
+
allowWorkflowRun = false,
|
|
128
|
+
}: SelectionActionsPopoverProps &
|
|
129
|
+
Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete' | 'allowWorkflowRun'>>) {
|
|
127
130
|
const context = useObjectsActionContext();
|
|
128
131
|
const executeAction = (action: ObjectsActionSpec) => {
|
|
129
132
|
context.run(action.id);
|
|
@@ -131,6 +134,7 @@ function SelectionActionsPopover({
|
|
|
131
134
|
const actions = getAvailableActions(context.actions, selection, {
|
|
132
135
|
allowMutations,
|
|
133
136
|
allowDelete,
|
|
137
|
+
allowWorkflowRun,
|
|
134
138
|
});
|
|
135
139
|
const trigger = children(actions);
|
|
136
140
|
|
|
@@ -169,7 +173,7 @@ function PopoverBody({ executeAction, actions }: PopoverBodyProps) {
|
|
|
169
173
|
function getAvailableActions(
|
|
170
174
|
actions: ObjectsActionSpec[],
|
|
171
175
|
selection: DocumentSelection,
|
|
172
|
-
permissions: Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete'>>,
|
|
176
|
+
permissions: Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete' | 'allowWorkflowRun'>>,
|
|
173
177
|
): ObjectsActionSpec[] {
|
|
174
178
|
if (!selection?.hasSelection()) {
|
|
175
179
|
return [ExportPropertiesAction];
|
|
@@ -182,6 +186,9 @@ function getAvailableActions(
|
|
|
182
186
|
if (action.id === 'delete' || action.id === 'deleteFromCollections') {
|
|
183
187
|
return permissions.allowDelete;
|
|
184
188
|
}
|
|
189
|
+
if (action.id === 'runIntake') {
|
|
190
|
+
return permissions.allowWorkflowRun;
|
|
191
|
+
}
|
|
185
192
|
if (action.id === 'changeType' || action.id === 'addToCollection' || action.id === 'removeFromCollection') {
|
|
186
193
|
return permissions.allowMutations;
|
|
187
194
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { errorMessage, useToast } from '@vertesia/ui/core';
|
|
2
|
+
import { i18nInstance, NAMESPACE, useUITranslation } from '@vertesia/ui/i18n';
|
|
3
|
+
import { useUserSession } from '@vertesia/ui/session';
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import { useDocumentSearch } from '../../search';
|
|
6
|
+
import { useObjectsActionContext } from '../ObjectsActionHooks';
|
|
7
|
+
import type { ActionComponentTypeProps, ObjectsActionSpec } from '../ObjectsActionSpec';
|
|
8
|
+
import ConfirmAction from './ConfirmAction';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Re-runs the unified standard intake pipeline over the selected objects. The server resolves each
|
|
12
|
+
* object's nature and starts one run per object — see the `start_workflow` bulk operation.
|
|
13
|
+
*/
|
|
14
|
+
export function RunIntakeActionComponent({ action, objectIds }: ActionComponentTypeProps) {
|
|
15
|
+
const { t } = useUITranslation();
|
|
16
|
+
const ctx = useObjectsActionContext();
|
|
17
|
+
const toast = useToast();
|
|
18
|
+
const { store } = useUserSession();
|
|
19
|
+
const search = useDocumentSearch();
|
|
20
|
+
|
|
21
|
+
const callback = useCallback(() => {
|
|
22
|
+
if (!objectIds?.length) {
|
|
23
|
+
toast({
|
|
24
|
+
status: 'error',
|
|
25
|
+
title: t('store.actions.noObjectsSelected'),
|
|
26
|
+
description: t('store.actions.pleaseSelectObjectsToRunIntake'),
|
|
27
|
+
duration: 3000,
|
|
28
|
+
});
|
|
29
|
+
return Promise.resolve(false);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return store
|
|
33
|
+
.runOperation({ name: 'start_workflow', ids: objectIds, params: {} })
|
|
34
|
+
.then(() => {
|
|
35
|
+
toast({
|
|
36
|
+
status: 'success',
|
|
37
|
+
title: t('store.actions.intakeStarted'),
|
|
38
|
+
description: t('store.actions.intakeStartedOn', { count: objectIds.length }),
|
|
39
|
+
duration: 3000,
|
|
40
|
+
});
|
|
41
|
+
// Intake rewrites status, type and properties asynchronously, so refresh the list
|
|
42
|
+
// to pick up the `processing` status rather than leaving stale rows selected.
|
|
43
|
+
if (search) {
|
|
44
|
+
ctx.params?.selection?.removeAll();
|
|
45
|
+
search.search();
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.catch((err: unknown) => {
|
|
49
|
+
toast({
|
|
50
|
+
status: 'error',
|
|
51
|
+
title: t('store.actions.errorStartingIntake'),
|
|
52
|
+
description: errorMessage(err),
|
|
53
|
+
duration: 5000,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}, [ctx.params?.selection?.removeAll, objectIds, search, search?.search, store.runOperation, t, toast]);
|
|
57
|
+
|
|
58
|
+
return <ConfirmAction action={action} callback={callback} />;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const t_static = i18nInstance.getFixedT(null, NAMESPACE);
|
|
62
|
+
export const RunIntakeAction: ObjectsActionSpec = {
|
|
63
|
+
id: 'runIntake',
|
|
64
|
+
name: t_static('store.actions.runIntake'),
|
|
65
|
+
description: t_static('store.actions.runIntakeDesc'),
|
|
66
|
+
confirm: true,
|
|
67
|
+
confirmationText: t_static('store.actions.confirmRunIntake'),
|
|
68
|
+
component: RunIntakeActionComponent,
|
|
69
|
+
};
|