@vertesia/ui 1.5.0-dev.20260901.052906Z → 1.5.0-dev.20260910.051115Z
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/Avatar.d.ts.map +1 -1
- package/lib/core/components/Avatar.js +3 -3
- package/lib/core/components/Avatar.js.map +1 -1
- package/lib/core/components/ComboBox.js +1 -1
- package/lib/core/components/ComboBox.js.map +1 -1
- package/lib/core/components/FileUpload.js +1 -1
- package/lib/core/components/FileUpload.js.map +1 -1
- package/lib/core/components/Link.js +1 -1
- package/lib/core/components/Link.js.map +1 -1
- package/lib/core/components/SelectList.js +1 -1
- package/lib/core/components/SelectList.js.map +1 -1
- package/lib/core/components/SidePanel.js +1 -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 +8 -8
- package/lib/core/components/TagsInput.js.map +1 -1
- package/lib/core/components/shadcn/MessageBox.js +1 -1
- package/lib/core/components/shadcn/MessageBox.js.map +1 -1
- package/lib/core/components/shadcn/button.js +1 -1
- package/lib/core/components/shadcn/button.js.map +1 -1
- package/lib/core/components/shadcn/card.d.ts.map +1 -1
- package/lib/core/components/shadcn/card.js +1 -1
- package/lib/core/components/shadcn/card.js.map +1 -1
- package/lib/core/components/shadcn/command.js +5 -5
- package/lib/core/components/shadcn/command.js.map +1 -1
- package/lib/core/components/shadcn/filters/DynamicLabel.js +1 -1
- package/lib/core/components/shadcn/filters/DynamicLabel.js.map +1 -1
- package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +3 -3
- package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
- package/lib/core/components/shadcn/input.js +3 -3
- package/lib/core/components/shadcn/input.js.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.js +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +2 -2
- package/lib/core/components/shadcn/modal/dialog.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/popover.js +1 -1
- package/lib/core/components/shadcn/popover.js.map +1 -1
- package/lib/core/components/shadcn/radioGroup.d.ts.map +1 -1
- package/lib/core/components/shadcn/radioGroup.js +3 -3
- package/lib/core/components/shadcn/radioGroup.js.map +1 -1
- package/lib/core/components/shadcn/selectBox.js +1 -1
- package/lib/core/components/shadcn/selectBox.js.map +1 -1
- package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
- package/lib/core/components/shadcn/tabs.js +5 -2
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/core/components/styles.js +1 -1
- package/lib/core/components/styles.js.map +1 -1
- package/lib/core/components/table/index.js +1 -1
- package/lib/core/hooks/useFetch.d.ts.map +1 -1
- package/lib/core/hooks/useFetch.js +2 -0
- package/lib/core/hooks/useFetch.js.map +1 -1
- package/lib/features/activity-doc/ActivityDoc.js +8 -8
- package/lib/features/activity-doc/ActivityDoc.js.map +1 -1
- package/lib/features/agent/chat/AgentChart.js +1 -1
- package/lib/features/agent/chat/AgentChart.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts +2 -3
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +3 -3
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +13 -13
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/DocumentPanel.d.ts +7 -7
- package/lib/features/agent/chat/DocumentPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/DocumentPanel.js +6 -12
- package/lib/features/agent/chat/DocumentPanel.js.map +1 -1
- package/lib/features/agent/chat/DocumentsTab.d.ts +15 -0
- package/lib/features/agent/chat/DocumentsTab.d.ts.map +1 -0
- package/lib/features/agent/chat/DocumentsTab.js +33 -0
- package/lib/features/agent/chat/DocumentsTab.js.map +1 -0
- package/lib/features/agent/chat/JumpingDots.js +1 -1
- package/lib/features/agent/chat/JumpingDots.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +3 -3
- 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 +22 -9
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js +5 -5
- package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.js +16 -11
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/InlineSlideInPanel.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/InlineSlideInPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +1 -1
- 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 +7 -7
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessagesContainer.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessagesContainer.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.js +10 -10
- package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js +17 -17
- package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +14 -2
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +15 -15
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +18 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
- package/lib/features/agent/chat/SlidingThinkingIndicator.d.ts.map +1 -1
- package/lib/features/agent/chat/SlidingThinkingIndicator.js +5 -2
- package/lib/features/agent/chat/SlidingThinkingIndicator.js.map +1 -1
- package/lib/features/agent/chat/VegaLiteChart.d.ts.map +1 -1
- package/lib/features/agent/chat/VegaLiteChart.js +6 -2
- package/lib/features/agent/chat/VegaLiteChart.js.map +1 -1
- package/lib/features/agent/chat/hooks/useDocumentPanel.d.ts +2 -2
- package/lib/features/agent/chat/hooks/useDocumentPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useDocumentPanel.js +0 -18
- package/lib/features/agent/chat/hooks/useDocumentPanel.js.map +1 -1
- package/lib/features/errors/RowErrorBoundary.js +1 -1
- package/lib/features/errors/RowErrorBoundary.js.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.js +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
- package/lib/features/facets/utils/VInteractionFacet.d.ts +3 -5
- package/lib/features/facets/utils/VInteractionFacet.d.ts.map +1 -1
- package/lib/features/facets/utils/VInteractionFacet.js +10 -23
- package/lib/features/facets/utils/VInteractionFacet.js.map +1 -1
- package/lib/features/facets/utils/VUserFacet.js +1 -1
- package/lib/features/facets/utils/VUserFacet.js.map +1 -1
- package/lib/features/layout/GenericPageNavHeader.d.ts.map +1 -1
- package/lib/features/layout/GenericPageNavHeader.js +4 -1
- package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
- package/lib/features/layout/NotFoundView.js +1 -1
- package/lib/features/layout/NotFoundView.js.map +1 -1
- package/lib/features/magic-pdf/AnnotatedImageSlider.js +4 -12
- package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
- package/lib/features/magic-pdf/ExtractedContentView.js +4 -4
- package/lib/features/magic-pdf/ExtractedContentView.js.map +1 -1
- package/lib/features/magic-pdf/MagicPdfView.js +1 -1
- package/lib/features/magic-pdf/MagicPdfView.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.js +4 -1
- 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 +3 -2
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +6 -7
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
- package/lib/features/oauth/useMcpConnections.js +27 -20
- package/lib/features/oauth/useMcpConnections.js.map +1 -1
- package/lib/features/pdf-viewer/PdfPageRenderer.js +2 -2
- package/lib/features/pdf-viewer/PdfPageRenderer.js.map +1 -1
- package/lib/features/pdf-viewer/PdfPageSlider.js +3 -3
- package/lib/features/pdf-viewer/PdfPageSlider.js.map +1 -1
- package/lib/features/pdf-viewer/SimplePdfViewer.js +1 -1
- package/lib/features/pdf-viewer/SimplePdfViewer.js.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.d.ts +2 -1
- package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js +35 -22
- package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
- package/lib/features/permissions/useRoleMappings.d.ts +19 -0
- package/lib/features/permissions/useRoleMappings.d.ts.map +1 -0
- package/lib/features/permissions/useRoleMappings.js +87 -0
- package/lib/features/permissions/useRoleMappings.js.map +1 -0
- package/lib/features/store/collections/SelectCollection.js +1 -1
- package/lib/features/store/collections/SelectCollection.js.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js +9 -9
- package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
- package/lib/features/store/objects/DocumentTable.js +1 -1
- package/lib/features/store/objects/DocumentTable.js.map +1 -1
- package/lib/features/store/objects/components/DocumentIcon.js +2 -2
- package/lib/features/store/objects/components/DocumentIcon.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/components/PropertiesEditorModal.js +1 -1
- package/lib/features/store/objects/components/PropertiesEditorModal.js.map +1 -1
- package/lib/features/store/objects/components/SaveVersionConfirmModal.js +1 -1
- package/lib/features/store/objects/components/SaveVersionConfirmModal.js.map +1 -1
- package/lib/features/store/objects/layout/documentLayout.d.ts.map +1 -1
- package/lib/features/store/objects/layout/documentLayout.js +2 -2
- package/lib/features/store/objects/layout/documentLayout.js.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.d.ts +10 -1
- package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.js +29 -19
- package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
- package/lib/features/store/types/IntakePolicyForm.d.ts +1 -1
- package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
- package/lib/features/store/types/IntakePolicyForm.js +5 -3
- package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
- package/lib/features/store/types/SelectContentTypeModal.js +1 -1
- package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
- package/lib/features/store/types/TypeRegistry.d.ts +10 -5
- package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +10 -5
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
- package/lib/features/user/UserAvatar.js +2 -2
- package/lib/features/user/UserAvatar.js.map +1 -1
- package/lib/features/user/UserInfo.d.ts.map +1 -1
- package/lib/features/user/UserInfo.js +7 -7
- package/lib/features/user/UserInfo.js.map +1 -1
- package/lib/features/utils/index.d.ts +1 -0
- package/lib/features/utils/index.d.ts.map +1 -1
- package/lib/features/utils/index.js +1 -0
- package/lib/features/utils/index.js.map +1 -1
- package/lib/features/utils/interaction.d.ts +55 -0
- package/lib/features/utils/interaction.d.ts.map +1 -0
- package/lib/features/utils/interaction.js +77 -0
- package/lib/features/utils/interaction.js.map +1 -0
- package/lib/features/views/ViewResults.js +2 -2
- package/lib/features/views/ViewResults.js.map +1 -1
- package/lib/i18n/locales/ar.json +17 -1
- package/lib/i18n/locales/de.json +13 -1
- package/lib/i18n/locales/en.json +13 -1
- package/lib/i18n/locales/es.json +13 -1
- package/lib/i18n/locales/fr.json +13 -1
- package/lib/i18n/locales/it.json +13 -1
- package/lib/i18n/locales/ja.json +13 -1
- package/lib/i18n/locales/ko.json +13 -1
- package/lib/i18n/locales/pt.json +13 -1
- package/lib/i18n/locales/ru.json +15 -1
- package/lib/i18n/locales/tr.json +13 -1
- package/lib/i18n/locales/zh-TW.json +13 -1
- package/lib/i18n/locales/zh.json +13 -1
- package/lib/layout/FullHeightLayout.js +2 -2
- package/lib/layout/FullHeightLayout.js.map +1 -1
- package/lib/layout/Navbar.js +4 -4
- package/lib/layout/Navbar.js.map +1 -1
- package/lib/layout/Sidebar.js +1 -1
- package/lib/layout/Sidebar.js.map +1 -1
- package/lib/router/NestedNavigationContext.d.ts +3 -1
- package/lib/router/NestedNavigationContext.d.ts.map +1 -1
- package/lib/router/NestedNavigationContext.js +2 -2
- package/lib/router/NestedNavigationContext.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +2 -13
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/authState.d.ts +13 -0
- package/lib/session/auth/authState.d.ts.map +1 -0
- package/lib/session/auth/authState.js +37 -0
- package/lib/session/auth/authState.js.map +1 -0
- package/lib/session/auth/domainRouting.d.ts +39 -0
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +85 -0
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/session/auth/useAuthState.d.ts +4 -7
- package/lib/session/auth/useAuthState.d.ts.map +1 -1
- package/lib/session/auth/useAuthState.js +5 -41
- package/lib/session/auth/useAuthState.js.map +1 -1
- package/lib/session/index.d.ts +1 -0
- package/lib/session/index.d.ts.map +1 -1
- package/lib/session/index.js +2 -0
- package/lib/session/index.js.map +1 -1
- package/lib/shell/SplashScreen.d.ts +1 -1
- package/lib/shell/SplashScreen.d.ts.map +1 -1
- package/lib/shell/SplashScreen.js +6 -2
- package/lib/shell/SplashScreen.js.map +1 -1
- package/lib/shell/VertesiaShell.js +1 -1
- package/lib/shell/VertesiaShell.js.map +1 -1
- package/lib/shell/apps/AppProjectSelector.js +1 -1
- package/lib/shell/apps/AppProjectSelector.js.map +1 -1
- package/lib/shell/apps/StandaloneApp.js +2 -2
- package/lib/shell/apps/StandaloneApp.js.map +1 -1
- package/lib/shell/login/SignInPrimitives.js +2 -2
- package/lib/shell/login/SignInPrimitives.js.map +1 -1
- package/lib/shell/login/SigninScreen.js +1 -1
- package/lib/shell/login/SigninScreen.js.map +1 -1
- package/lib/shell/login/SignupForm.js +1 -1
- package/lib/shell/login/SignupForm.js.map +1 -1
- package/lib/shell/login/TerminalLogin.js +2 -2
- package/lib/shell/login/TerminalLogin.js.map +1 -1
- package/lib/shell/login/UserInfo.d.ts.map +1 -1
- package/lib/shell/login/UserInfo.js +1 -1
- package/lib/shell/login/UserInfo.js.map +1 -1
- package/lib/shell/login/UserSessionMenu.js +1 -1
- package/lib/shell/login/UserSessionMenu.js.map +1 -1
- package/lib/vertesia-ui-core.js +7 -7
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-features.js +179 -182
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.js +2 -2
- package/lib/vertesia-ui-layout.js +1 -1
- package/lib/vertesia-ui-layout.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +24 -24
- package/lib/vertesia-ui-rich-text.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 +3 -3
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +54 -54
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/Progress.js +1 -1
- package/lib/widgets/Progress.js.map +1 -1
- package/lib/widgets/form/Form.js +2 -2
- package/lib/widgets/form/Form.js.map +1 -1
- package/lib/widgets/form/fields.js +2 -2
- package/lib/widgets/form/fields.js.map +1 -1
- package/lib/widgets/json-view/JSONView.js +1 -1
- package/lib/widgets/json-view/JSONView.js.map +1 -1
- package/lib/widgets/markdown/MermaidDiagram.js +1 -1
- package/lib/widgets/markdown/MermaidDiagram.js.map +1 -1
- package/lib/widgets/markdown/remarkDirectiveHandler.d.ts +7 -2
- package/lib/widgets/markdown/remarkDirectiveHandler.d.ts.map +1 -1
- package/lib/widgets/markdown/remarkDirectiveHandler.js +19 -4
- package/lib/widgets/markdown/remarkDirectiveHandler.js.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.js +4 -2
- package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
- package/lib/widgets/monacoEditor/index.d.ts +1 -0
- package/lib/widgets/monacoEditor/index.d.ts.map +1 -1
- package/lib/widgets/monacoEditor/index.js +1 -0
- package/lib/widgets/monacoEditor/index.js.map +1 -1
- package/lib/widgets/monacoEditor/loadMonaco.d.ts +45 -0
- package/lib/widgets/monacoEditor/loadMonaco.d.ts.map +1 -0
- package/lib/widgets/monacoEditor/loadMonaco.js +62 -0
- package/lib/widgets/monacoEditor/loadMonaco.js.map +1 -0
- package/lib/widgets/properties/PropertiesView.js +1 -1
- package/lib/widgets/properties/PropertiesView.js.map +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js +2 -2
- package/lib/widgets/schema-editor/editor/Editable.js.map +1 -1
- package/lib/widgets/schema-editor/editor/PropertyEditor.js +1 -1
- package/lib/widgets/schema-editor/editor/PropertyEditor.js.map +1 -1
- package/lib/widgets/schema-editor/editor/SchemaEditor.js +2 -2
- package/lib/widgets/schema-editor/editor/SchemaEditor.js.map +1 -1
- package/lib/widgets/upload/DropZone.js +1 -1
- package/lib/widgets/upload/DropZone.js.map +1 -1
- package/lib/widgets/upload/UploadResultCategory.d.ts +1 -1
- package/lib/widgets/upload/UploadResultCategory.d.ts.map +1 -1
- package/lib/widgets/upload/UploadResultCategory.js +3 -3
- package/lib/widgets/upload/UploadResultCategory.js.map +1 -1
- package/lib/widgets/upload/UploadSummary.js +1 -1
- package/lib/widgets/upload/UploadSummary.js.map +1 -1
- package/lib/widgets/xml-viewer/components/XMLViewer.d.ts.map +1 -1
- package/lib/widgets/xml-viewer/components/XMLViewer.js +7 -3
- package/lib/widgets/xml-viewer/components/XMLViewer.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +11 -13
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +41 -14
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
- package/package.json +7 -7
- package/src/__tests__/contrast.test.ts +1 -0
- package/src/core/components/Avatar.tsx +3 -3
- package/src/core/components/ComboBox.tsx +1 -1
- package/src/core/components/FileUpload.tsx +4 -4
- package/src/core/components/Link.tsx +1 -1
- package/src/core/components/SelectList.tsx +1 -1
- package/src/core/components/SidePanel.tsx +1 -1
- package/src/core/components/Spinner.tsx +1 -1
- package/src/core/components/TagsInput.tsx +8 -8
- package/src/core/components/shadcn/MessageBox.tsx +1 -1
- package/src/core/components/shadcn/button.tsx +1 -1
- package/src/core/components/shadcn/card.tsx +1 -3
- package/src/core/components/shadcn/command.tsx +5 -5
- package/src/core/components/shadcn/filters/DynamicLabel.tsx +1 -1
- package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +3 -3
- package/src/core/components/shadcn/input.tsx +3 -3
- package/src/core/components/shadcn/modal/ConfirmModal.tsx +3 -3
- package/src/core/components/shadcn/modal/dialog.tsx +2 -4
- package/src/core/components/shadcn/overflowTabs.tsx +2 -2
- package/src/core/components/shadcn/popover.tsx +1 -1
- package/src/core/components/shadcn/radioGroup.tsx +5 -7
- package/src/core/components/shadcn/selectBox.tsx +1 -1
- package/src/core/components/shadcn/tabs.tsx +4 -2
- package/src/core/components/styles.ts +1 -1
- package/src/core/components/table/index.tsx +1 -1
- package/src/core/hooks/useFetch.test.ts +20 -0
- package/src/core/hooks/useFetch.ts +2 -0
- package/src/css/base.css +1 -1
- package/src/css/color.css +4 -0
- package/src/css/theme.css +1 -0
- package/src/css/typography.css +2 -2
- package/src/features/activity-doc/ActivityDoc.tsx +11 -11
- package/src/features/agent/chat/AgentChart.tsx +1 -1
- package/src/features/agent/chat/AgentRightPanel.tsx +4 -8
- package/src/features/agent/chat/AskUserWidget.tsx +19 -23
- package/src/features/agent/chat/DocumentPanel.tsx +39 -48
- package/src/features/agent/chat/DocumentsTab.test.tsx +87 -0
- package/src/features/agent/chat/DocumentsTab.tsx +124 -0
- package/src/features/agent/chat/JumpingDots.tsx +3 -3
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +0 -1
- package/src/features/agent/chat/ModernAgentConversation.tsx +3 -5
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +60 -1
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +44 -24
- package/src/features/agent/chat/ModernAgentOutput/BatchProgressPanel.tsx +12 -12
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +28 -15
- package/src/features/agent/chat/ModernAgentOutput/InlineSlideInPanel.tsx +4 -4
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +7 -12
- package/src/features/agent/chat/ModernAgentOutput/MessagesContainer.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/PlanPanel.tsx +16 -22
- package/src/features/agent/chat/ModernAgentOutput/SlideInPanel.tsx +4 -4
- package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +2 -4
- package/src/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.tsx +21 -21
- package/src/features/agent/chat/ModernAgentOutput/StreamingMessage.tsx +4 -4
- package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +16 -1
- package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +19 -40
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +41 -0
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +19 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +93 -0
- package/src/features/agent/chat/SlidingThinkingIndicator.tsx +5 -2
- package/src/features/agent/chat/VegaLiteChart.tsx +6 -2
- package/src/features/agent/chat/hooks/useDocumentPanel.test.tsx +33 -0
- package/src/features/agent/chat/hooks/useDocumentPanel.ts +3 -20
- package/src/features/errors/RowErrorBoundary.tsx +1 -1
- package/src/features/facets/AgentRunnerFacetsNav.tsx +1 -1
- package/src/features/facets/utils/VInteractionFacet.tsx +22 -34
- package/src/features/facets/utils/VUserFacet.tsx +1 -1
- package/src/features/layout/GenericPageNavHeader.tsx +9 -1
- package/src/features/layout/NotFoundView.tsx +1 -1
- package/src/features/magic-pdf/AnnotatedImageSlider.tsx +8 -16
- package/src/features/magic-pdf/ExtractedContentView.tsx +4 -4
- package/src/features/magic-pdf/MagicPdfView.tsx +1 -1
- package/src/features/oauth/McpConnectionsButton.test.tsx +79 -8
- package/src/features/oauth/McpConnectionsButton.tsx +6 -3
- package/src/features/oauth/McpConnectionsDialog.tsx +9 -3
- package/src/features/oauth/useMcpConnections.ts +33 -27
- package/src/features/pdf-viewer/PdfPageRenderer.tsx +2 -2
- package/src/features/pdf-viewer/PdfPageSlider.tsx +4 -4
- package/src/features/pdf-viewer/SimplePdfViewer.tsx +1 -1
- package/src/features/permissions/UserPermissionsProvider.test.tsx +172 -0
- package/src/features/permissions/UserPermissionsProvider.tsx +68 -21
- package/src/features/permissions/useRoleMappings.ts +105 -0
- package/src/features/store/collections/SelectCollection.tsx +1 -1
- package/src/features/store/objects/DocumentPreviewPanel.tsx +43 -53
- package/src/features/store/objects/DocumentTable.tsx +2 -2
- package/src/features/store/objects/components/DocumentIcon.tsx +4 -4
- package/src/features/store/objects/components/DocumentInput.tsx +3 -3
- package/src/features/store/objects/components/PropertiesEditorModal.tsx +2 -2
- package/src/features/store/objects/components/SaveVersionConfirmModal.tsx +2 -2
- package/src/features/store/objects/layout/documentLayout.tsx +2 -4
- package/src/features/store/objects/selection/SelectionActions.tsx +1 -1
- package/src/features/store/types/IntakePolicyEditor.tsx +70 -36
- package/src/features/store/types/IntakePolicyForm.tsx +11 -3
- package/src/features/store/types/SelectContentTypeModal.tsx +1 -1
- package/src/features/user/UserAvatar.tsx +3 -3
- package/src/features/user/UserInfo.tsx +11 -16
- package/src/features/utils/index.ts +1 -0
- package/src/features/utils/interaction.test.tsx +93 -0
- package/src/features/utils/interaction.tsx +125 -0
- package/src/features/views/ViewResults.tsx +3 -3
- package/src/i18n/locales/ar.json +17 -1
- package/src/i18n/locales/de.json +13 -1
- package/src/i18n/locales/en.json +13 -1
- package/src/i18n/locales/es.json +13 -1
- package/src/i18n/locales/fr.json +13 -1
- package/src/i18n/locales/it.json +13 -1
- package/src/i18n/locales/ja.json +13 -1
- package/src/i18n/locales/ko.json +13 -1
- package/src/i18n/locales/pt.json +13 -1
- package/src/i18n/locales/ru.json +15 -1
- package/src/i18n/locales/tr.json +13 -1
- package/src/i18n/locales/zh-TW.json +13 -1
- package/src/i18n/locales/zh.json +13 -1
- package/src/layout/FullHeightLayout.tsx +2 -2
- package/src/layout/Navbar.tsx +5 -5
- package/src/layout/Sidebar.tsx +1 -1
- package/src/router/NestedNavigationContext.test.tsx +54 -0
- package/src/router/NestedNavigationContext.tsx +9 -2
- package/src/session/UserSessionProvider.tsx +2 -15
- package/src/session/auth/authState.test.ts +35 -0
- package/src/session/auth/authState.ts +42 -0
- package/src/session/auth/domainRouting.test.ts +169 -1
- package/src/session/auth/domainRouting.ts +89 -0
- package/src/session/auth/useAuthState.ts +5 -49
- package/src/session/index.ts +6 -0
- package/src/shell/SplashScreen.test.tsx +22 -0
- package/src/shell/SplashScreen.tsx +6 -2
- package/src/shell/VertesiaShell.tsx +1 -1
- package/src/shell/apps/AppProjectSelector.tsx +1 -1
- package/src/shell/apps/StandaloneApp.tsx +9 -9
- package/src/shell/login/SignInPrimitives.tsx +2 -2
- package/src/shell/login/SigninScreen.tsx +1 -1
- package/src/shell/login/SignupForm.tsx +2 -2
- package/src/shell/login/TerminalLogin.tsx +5 -5
- package/src/shell/login/UserInfo.tsx +2 -5
- package/src/shell/login/UserSessionMenu.tsx +2 -2
- package/src/widgets/Progress.tsx +2 -2
- package/src/widgets/form/Form.tsx +4 -4
- package/src/widgets/form/fields.tsx +2 -2
- package/src/widgets/json-view/JSONView.tsx +1 -6
- package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +33 -29
- package/src/widgets/markdown/MarkdownRenderer.test.tsx +52 -0
- package/src/widgets/markdown/MermaidDiagram.tsx +2 -2
- package/src/widgets/markdown/remarkDirectiveHandler.ts +21 -5
- package/src/widgets/monacoEditor/MonacoEditor.tsx +4 -2
- package/src/widgets/monacoEditor/index.ts +1 -0
- package/src/widgets/monacoEditor/loadMonaco.test.ts +63 -0
- package/src/widgets/monacoEditor/loadMonaco.ts +70 -0
- package/src/widgets/properties/PropertiesView.tsx +1 -1
- package/src/widgets/schema-editor/editor/Editable.tsx +2 -2
- package/src/widgets/schema-editor/editor/PropertyEditor.tsx +1 -1
- package/src/widgets/schema-editor/editor/SchemaEditor.tsx +2 -2
- package/src/widgets/upload/DropZone.tsx +1 -1
- package/src/widgets/upload/UploadResultCategory.tsx +7 -7
- package/src/widgets/upload/UploadSummary.tsx +4 -4
- package/src/widgets/xml-viewer/components/XMLViewer.tsx +7 -3
- package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +60 -7
- package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +70 -16
- package/lib/features/agent/chat/DocumentTabBar.d.ts +0 -9
- package/lib/features/agent/chat/DocumentTabBar.d.ts.map +0 -1
- package/lib/features/agent/chat/DocumentTabBar.js +0 -9
- package/lib/features/agent/chat/DocumentTabBar.js.map +0 -1
- package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js.map +0 -1
- package/src/features/agent/chat/DocumentTabBar.tsx +0 -41
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
2
|
+
import { VertesiaClient } from '@vertesia/client';
|
|
3
|
+
import type { AuthTokenPayload, SystemRoleDefinition } from '@vertesia/common';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { UserPermissionProvider } from './UserPermissionsProvider';
|
|
6
|
+
|
|
7
|
+
const session = {
|
|
8
|
+
client: new VertesiaClient({ serverUrl: 'https://studio.example.test', storeUrl: 'https://store.example.test' }),
|
|
9
|
+
authToken: { sub: 'user-a', account_roles: [] } as unknown as AuthTokenPayload,
|
|
10
|
+
signOut: vi.fn(),
|
|
11
|
+
};
|
|
12
|
+
vi.mock('@vertesia/ui/session', () => ({ useUserSession: () => session }));
|
|
13
|
+
|
|
14
|
+
function renderProvider() {
|
|
15
|
+
return render(
|
|
16
|
+
<UserPermissionProvider>
|
|
17
|
+
<div>Protected workspace</div>
|
|
18
|
+
</UserPermissionProvider>,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function advance(ms: number) {
|
|
23
|
+
await act(async () => {
|
|
24
|
+
await vi.advanceTimersByTimeAsync(ms);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('role mapping recovery', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
vi.useFakeTimers();
|
|
31
|
+
vi.spyOn(Math, 'random').mockReturnValue(1);
|
|
32
|
+
session.authToken = { sub: 'user-a', account_roles: [] } as unknown as AuthTokenPayload;
|
|
33
|
+
session.signOut.mockClear();
|
|
34
|
+
});
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
vi.useRealTimers();
|
|
37
|
+
vi.restoreAllMocks();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it.each([0, 502, 503, 504])(
|
|
41
|
+
'recovers automatically from status %s without rendering protected content early',
|
|
42
|
+
async (status) => {
|
|
43
|
+
const fetch = vi
|
|
44
|
+
.spyOn(session.client.iam.roles, 'listSystem')
|
|
45
|
+
.mockRejectedValueOnce(Object.assign(new Error('JWKSTimeout'), { status }))
|
|
46
|
+
.mockResolvedValue([]);
|
|
47
|
+
renderProvider();
|
|
48
|
+
expect(screen.queryByText('Protected workspace')).toBeNull();
|
|
49
|
+
await advance(0);
|
|
50
|
+
expect(screen.getByRole('status').textContent).toContain('automatically');
|
|
51
|
+
expect(screen.queryByText('JWKSTimeout')).toBeNull();
|
|
52
|
+
await advance(1_000);
|
|
53
|
+
expect(screen.getByText('Protected workspace')).toBeTruthy();
|
|
54
|
+
expect(fetch).toHaveBeenCalledTimes(2);
|
|
55
|
+
expect(screen.queryByRole('alert')).toBeNull();
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
it('stops after one minute and lets a manual retry recover without navigating', async () => {
|
|
60
|
+
const fetch = vi
|
|
61
|
+
.spyOn(session.client.iam.roles, 'listSystem')
|
|
62
|
+
.mockRejectedValue(Object.assign(new Error('JWKSTimeout'), { status: 503 }));
|
|
63
|
+
const location = window.location.href;
|
|
64
|
+
renderProvider();
|
|
65
|
+
await advance(60_000);
|
|
66
|
+
expect(screen.getByRole('alert').textContent).toContain('couldn’t connect');
|
|
67
|
+
const calls = fetch.mock.calls.length;
|
|
68
|
+
await advance(60_000);
|
|
69
|
+
expect(fetch).toHaveBeenCalledTimes(calls);
|
|
70
|
+
fetch.mockResolvedValue([]);
|
|
71
|
+
fireEvent.click(screen.getByRole('button', { name: 'Try again' }));
|
|
72
|
+
await advance(0);
|
|
73
|
+
expect(screen.getByText('Protected workspace')).toBeTruthy();
|
|
74
|
+
expect(window.location.href).toBe(location);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('does not restart recovery when authentication re-decodes the same JWT', async () => {
|
|
78
|
+
const fetch = vi.spyOn(session.client.iam.roles, 'listSystem').mockImplementation(async () => {
|
|
79
|
+
session.authToken = { ...session.authToken };
|
|
80
|
+
throw Object.assign(new Error('Unavailable'), { status: 503 });
|
|
81
|
+
});
|
|
82
|
+
renderProvider();
|
|
83
|
+
await advance(60_000);
|
|
84
|
+
expect(screen.getByRole('button', { name: 'Try again' })).toBeTruthy();
|
|
85
|
+
const calls = fetch.mock.calls.length;
|
|
86
|
+
await advance(10_000);
|
|
87
|
+
expect(fetch).toHaveBeenCalledTimes(calls);
|
|
88
|
+
fetch.mockImplementation(async () => {
|
|
89
|
+
session.authToken = { ...session.authToken };
|
|
90
|
+
return [];
|
|
91
|
+
});
|
|
92
|
+
fireEvent.click(screen.getByRole('button', { name: 'Try again' }));
|
|
93
|
+
await advance(0);
|
|
94
|
+
expect(screen.getByText('Protected workspace')).toBeTruthy();
|
|
95
|
+
expect(fetch).toHaveBeenCalledTimes(calls + 1);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('bounds a hung request and ignores its late success', async () => {
|
|
99
|
+
let resolve!: (roles: SystemRoleDefinition[]) => void;
|
|
100
|
+
const fetch = vi.spyOn(session.client.iam.roles, 'listSystem').mockImplementation(
|
|
101
|
+
() =>
|
|
102
|
+
new Promise((done) => {
|
|
103
|
+
resolve = done;
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
renderProvider();
|
|
107
|
+
await advance(60_000);
|
|
108
|
+
expect(fetch.mock.calls[0][0]?.signal?.aborted).toBe(true);
|
|
109
|
+
await act(async () => resolve([]));
|
|
110
|
+
expect(screen.queryByText('Protected workspace')).toBeNull();
|
|
111
|
+
expect(screen.getByRole('button', { name: 'Try again' })).toBeTruthy();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it.each([401, 403, 400, 500])('does not automatically retry status %s', async (status) => {
|
|
115
|
+
const fetch = vi
|
|
116
|
+
.spyOn(session.client.iam.roles, 'listSystem')
|
|
117
|
+
.mockRejectedValue(Object.assign(new Error('Request failed'), { status }));
|
|
118
|
+
renderProvider();
|
|
119
|
+
await advance(60_000);
|
|
120
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
121
|
+
expect(screen.queryByText('Protected workspace')).toBeNull();
|
|
122
|
+
if (status === 401 || status === 403) {
|
|
123
|
+
fireEvent.click(screen.getByRole('button', { name: 'Use a different account' }));
|
|
124
|
+
expect(session.signOut).toHaveBeenCalledOnce();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('cancels retries on unmount', async () => {
|
|
129
|
+
const fetch = vi
|
|
130
|
+
.spyOn(session.client.iam.roles, 'listSystem')
|
|
131
|
+
.mockRejectedValue(Object.assign(new Error('Unavailable'), { status: 503 }));
|
|
132
|
+
const view = renderProvider();
|
|
133
|
+
await advance(0);
|
|
134
|
+
view.unmount();
|
|
135
|
+
await advance(60_000);
|
|
136
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
137
|
+
expect(fetch.mock.calls[0][0]?.signal?.aborted).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('ignores the previous session’s pending response after a token change', async () => {
|
|
141
|
+
let resolveOld!: (roles: SystemRoleDefinition[]) => void;
|
|
142
|
+
const fetch = vi
|
|
143
|
+
.spyOn(session.client.iam.roles, 'listSystem')
|
|
144
|
+
.mockImplementationOnce(
|
|
145
|
+
() =>
|
|
146
|
+
new Promise((done) => {
|
|
147
|
+
resolveOld = done;
|
|
148
|
+
}),
|
|
149
|
+
)
|
|
150
|
+
.mockRejectedValue(Object.assign(new Error('Forbidden'), { status: 403 }));
|
|
151
|
+
const view = renderProvider();
|
|
152
|
+
session.authToken = { sub: 'user-b', account_roles: [] } as unknown as AuthTokenPayload;
|
|
153
|
+
view.rerender(
|
|
154
|
+
<UserPermissionProvider>
|
|
155
|
+
<div>Protected workspace</div>
|
|
156
|
+
</UserPermissionProvider>,
|
|
157
|
+
);
|
|
158
|
+
await advance(0);
|
|
159
|
+
await act(async () => resolveOld([]));
|
|
160
|
+
expect(fetch.mock.calls[0][0]?.signal?.aborted).toBe(true);
|
|
161
|
+
expect(screen.queryByText('Protected workspace')).toBeNull();
|
|
162
|
+
expect(screen.getByRole('alert').textContent).toContain('Access Denied');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('uses permissions embedded in the token without fetching mappings', () => {
|
|
166
|
+
session.authToken = { ...session.authToken, permissions: [] };
|
|
167
|
+
const fetch = vi.spyOn(session.client.iam.roles, 'listSystem');
|
|
168
|
+
renderProvider();
|
|
169
|
+
expect(screen.getByText('Protected workspace')).toBeTruthy();
|
|
170
|
+
expect(fetch).not.toHaveBeenCalled();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type AuthTokenPayload, type Permission, PrincipalType, type SystemRoleDefinition } from '@vertesia/common';
|
|
2
|
-
import {
|
|
2
|
+
import { Button, errorMessage, Spinner } from '@vertesia/ui/core';
|
|
3
3
|
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
4
4
|
import { useUserSession } from '@vertesia/ui/session';
|
|
5
5
|
import { createContext, useContext, useMemo } from 'react';
|
|
6
6
|
import { isAnyOf } from './helpers';
|
|
7
|
+
import { roleMappingsErrorStatus, useRoleMappings } from './useRoleMappings';
|
|
7
8
|
|
|
8
9
|
type ListRolesResponse = SystemRoleDefinition[];
|
|
9
10
|
|
|
@@ -68,35 +69,81 @@ export function useUserPermissions() {
|
|
|
68
69
|
|
|
69
70
|
interface UserPermissionProviderProps {
|
|
70
71
|
children: React.ReactNode;
|
|
72
|
+
loadingIcon?: React.ReactNode;
|
|
71
73
|
}
|
|
72
|
-
export function UserPermissionProvider({ children }: UserPermissionProviderProps) {
|
|
74
|
+
export function UserPermissionProvider({ children, loadingIcon }: UserPermissionProviderProps) {
|
|
73
75
|
const { t } = useUITranslation();
|
|
74
76
|
const session = useUserSession();
|
|
75
77
|
const authToken = session.authToken;
|
|
76
|
-
const
|
|
77
|
-
const { data, error, isLoading } = useFetch<ListRolesResponse | undefined>(() => {
|
|
78
|
-
if (shouldFetchRoleMappings) {
|
|
79
|
-
return session.client.iam.roles.listSystem();
|
|
80
|
-
}
|
|
81
|
-
return Promise.resolve(undefined);
|
|
82
|
-
}, [session.client, authToken, shouldFetchRoleMappings]);
|
|
78
|
+
const { state, retry } = useRoleMappings(session.client, authToken);
|
|
83
79
|
|
|
84
80
|
const perms = useMemo(() => {
|
|
85
|
-
if (authToken)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
return undefined;
|
|
81
|
+
if (!authToken) return undefined;
|
|
82
|
+
if (authToken.permissions) {
|
|
83
|
+
return new UserPermissions(authToken);
|
|
84
|
+
}
|
|
85
|
+
if (state.status === 'ready') {
|
|
86
|
+
return new UserPermissions(authToken, state.roles);
|
|
94
87
|
}
|
|
95
88
|
return undefined;
|
|
96
|
-
}, [authToken,
|
|
89
|
+
}, [authToken, state]);
|
|
97
90
|
|
|
98
|
-
if (
|
|
99
|
-
|
|
91
|
+
if (authToken && !perms) {
|
|
92
|
+
const failed = state.status === 'error';
|
|
93
|
+
const status = failed ? roleMappingsErrorStatus(state.error) : undefined;
|
|
94
|
+
const needsSignIn = status === 401;
|
|
95
|
+
const denied = status === 403;
|
|
96
|
+
const title = needsSignIn
|
|
97
|
+
? t('auth.recovery.credential.title')
|
|
98
|
+
: denied
|
|
99
|
+
? t('shell.accessDenied')
|
|
100
|
+
: failed
|
|
101
|
+
? t('permissions.connectionFailed')
|
|
102
|
+
: t('permissions.connecting');
|
|
103
|
+
return (
|
|
104
|
+
<div className="flex min-h-dvh items-center justify-center bg-background px-6 text-foreground">
|
|
105
|
+
<div className="w-full max-w-md space-y-6 text-center">
|
|
106
|
+
<div aria-hidden="true" className="flex justify-center">
|
|
107
|
+
{loadingIcon || (!failed && <Spinner size="2xl" className="text-primary" />)}
|
|
108
|
+
</div>
|
|
109
|
+
<div
|
|
110
|
+
role={failed ? 'alert' : 'status'}
|
|
111
|
+
aria-live={failed ? 'assertive' : 'polite'}
|
|
112
|
+
className="space-y-2"
|
|
113
|
+
>
|
|
114
|
+
<h1 className="text-xl font-semibold">{title}</h1>
|
|
115
|
+
<p className="text-muted">
|
|
116
|
+
{needsSignIn
|
|
117
|
+
? t('auth.recovery.credential.body')
|
|
118
|
+
: denied
|
|
119
|
+
? t('permissions.accessDenied')
|
|
120
|
+
: failed
|
|
121
|
+
? t('permissions.tryAgainLater')
|
|
122
|
+
: state.status === 'retrying'
|
|
123
|
+
? t('permissions.retrying')
|
|
124
|
+
: t('permissions.loadingPermissions')}
|
|
125
|
+
</p>
|
|
126
|
+
</div>
|
|
127
|
+
{failed && (
|
|
128
|
+
<>
|
|
129
|
+
<Button variant="outline" onClick={needsSignIn || denied ? () => session.signOut() : retry}>
|
|
130
|
+
{needsSignIn || denied
|
|
131
|
+
? t('auth.recovery.useDifferentAccount')
|
|
132
|
+
: t('auth.recovery.tryAgain')}
|
|
133
|
+
</Button>
|
|
134
|
+
{state.error != null && (
|
|
135
|
+
<details className="text-start text-sm text-muted">
|
|
136
|
+
<summary className="cursor-pointer">{t('auth.recovery.technicalDetails')}</summary>
|
|
137
|
+
<pre className="mt-2 max-h-48 overflow-auto whitespace-pre-wrap wrap-break-word">
|
|
138
|
+
{errorMessage(state.error)}
|
|
139
|
+
</pre>
|
|
140
|
+
</details>
|
|
141
|
+
)}
|
|
142
|
+
</>
|
|
143
|
+
)}
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
100
147
|
}
|
|
101
148
|
|
|
102
149
|
return perms && <UserPermissionsContext.Provider value={perms}>{children}</UserPermissionsContext.Provider>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { VertesiaClient } from '@vertesia/client';
|
|
2
|
+
import type { AuthTokenPayload, SystemRoleDefinition } from '@vertesia/common';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
type RoleMappingsState =
|
|
6
|
+
| { status: 'loading' | 'retrying' }
|
|
7
|
+
| { status: 'ready'; roles: SystemRoleDefinition[] }
|
|
8
|
+
| { status: 'error'; error?: unknown };
|
|
9
|
+
|
|
10
|
+
export function roleMappingsErrorStatus(error: unknown): number | undefined {
|
|
11
|
+
if (error && typeof error === 'object' && 'status' in error && typeof error.status === 'number') {
|
|
12
|
+
return error.status;
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isTransient(error: unknown): boolean {
|
|
18
|
+
const status = roleMappingsErrorStatus(error);
|
|
19
|
+
return (
|
|
20
|
+
status === 0 ||
|
|
21
|
+
status === 502 ||
|
|
22
|
+
status === 503 ||
|
|
23
|
+
status === 504 ||
|
|
24
|
+
(error instanceof Error && error.name === 'TimeoutError')
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Each session gets an independent, cancellable recovery window. Never reuse another session's roles. */
|
|
29
|
+
export function useRoleMappings(client: VertesiaClient, authToken?: AuthTokenPayload) {
|
|
30
|
+
// UserSession.rawAuthToken decodes the cached JWT on each authenticated request.
|
|
31
|
+
// Object identity would restart recovery on every failure (or success), forever.
|
|
32
|
+
// Preserve all claims in the identity: subject/account/expiry can stay the same
|
|
33
|
+
// when project, roles, or other authorization claims change.
|
|
34
|
+
const tokenKey = useMemo(() => (authToken ? JSON.stringify(authToken) : undefined), [authToken]);
|
|
35
|
+
const needsMappings = Boolean(authToken && !authToken.permissions);
|
|
36
|
+
const [attempt, setAttempt] = useState(0);
|
|
37
|
+
const [result, setResult] = useState<{
|
|
38
|
+
client: VertesiaClient;
|
|
39
|
+
tokenKey: string | undefined;
|
|
40
|
+
attempt: number;
|
|
41
|
+
state: RoleMappingsState;
|
|
42
|
+
}>();
|
|
43
|
+
const retry = useCallback(() => setAttempt((value) => value + 1), []);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!needsMappings) return;
|
|
47
|
+
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
let stopped = false;
|
|
50
|
+
let failures = 0;
|
|
51
|
+
let lastError: unknown;
|
|
52
|
+
let retryTimer: ReturnType<typeof setTimeout> | undefined;
|
|
53
|
+
const update = (state: RoleMappingsState) => setResult({ client, tokenKey, attempt, state });
|
|
54
|
+
const stop = () => {
|
|
55
|
+
stopped = true;
|
|
56
|
+
clearTimeout(slowTimer);
|
|
57
|
+
clearTimeout(deadlineTimer);
|
|
58
|
+
clearTimeout(retryTimer);
|
|
59
|
+
controller.abort();
|
|
60
|
+
};
|
|
61
|
+
const slowTimer = setTimeout(() => update({ status: 'retrying' }), 5_000);
|
|
62
|
+
// Bound the whole recovery window, including requests that never settle.
|
|
63
|
+
const deadlineTimer = setTimeout(() => {
|
|
64
|
+
stop();
|
|
65
|
+
update({ status: 'error', error: lastError });
|
|
66
|
+
}, 60_000);
|
|
67
|
+
|
|
68
|
+
const fetchRoles = async () => {
|
|
69
|
+
try {
|
|
70
|
+
const roles = await client.iam.roles.listSystem({
|
|
71
|
+
signal: controller.signal,
|
|
72
|
+
timeoutMs: 15_000,
|
|
73
|
+
// This hook owns backoff and the overall deadline, not the client's retry policy.
|
|
74
|
+
retryPolicy: false,
|
|
75
|
+
});
|
|
76
|
+
if (stopped) return;
|
|
77
|
+
stop();
|
|
78
|
+
update({ status: 'ready', roles });
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (stopped) return;
|
|
81
|
+
lastError = error;
|
|
82
|
+
if (!isTransient(error)) {
|
|
83
|
+
stop();
|
|
84
|
+
update({ status: 'error', error });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
update({ status: 'retrying' });
|
|
88
|
+
const delay = Math.min(1_000 * 2 ** failures++, 8_000) * (0.5 + Math.random() * 0.5);
|
|
89
|
+
retryTimer = setTimeout(() => {
|
|
90
|
+
void fetchRoles();
|
|
91
|
+
}, delay);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
update({ status: 'loading' });
|
|
96
|
+
void fetchRoles();
|
|
97
|
+
return stop;
|
|
98
|
+
}, [client, tokenKey, needsMappings, attempt]);
|
|
99
|
+
|
|
100
|
+
const state: RoleMappingsState =
|
|
101
|
+
result?.client === client && result.tokenKey === tokenKey && result.attempt === attempt
|
|
102
|
+
? result.state
|
|
103
|
+
: { status: 'loading' };
|
|
104
|
+
return { state, retry };
|
|
105
|
+
}
|
|
@@ -217,7 +217,7 @@ export function SelectCollection({
|
|
|
217
217
|
placeholder={resolvedSearchPlaceholder}
|
|
218
218
|
value={searchQuery}
|
|
219
219
|
onValueChange={handleSearchChange}
|
|
220
|
-
className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted
|
|
220
|
+
className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted disabled:cursor-not-allowed disabled:opacity-50"
|
|
221
221
|
/>
|
|
222
222
|
{isSearching && (
|
|
223
223
|
<div className="me-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
|
@@ -127,13 +127,13 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
127
127
|
|
|
128
128
|
return (
|
|
129
129
|
<div
|
|
130
|
-
className={`fixed inset-y-0 end-0 w-2/5 dark:bg-
|
|
130
|
+
className={`fixed inset-y-0 end-0 w-2/5 dark:bg-muted shadow-xl z-50 flex flex-col transition-transform duration-300 transform ${panelTranslateClass}`}
|
|
131
131
|
>
|
|
132
132
|
{/* Header */}
|
|
133
|
-
<div className="flex items-center justify-between px-4 py-3 border-b dark:border-
|
|
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-
|
|
136
|
-
<h2 className="text-lg font-semibold text-
|
|
135
|
+
<FileText className="h-5 w-5 text-primary me-2" />
|
|
136
|
+
<h2 className="text-lg font-semibold text-foreground truncate">
|
|
137
137
|
{isLoading ? t('store.loadingDocument') : object?.name || t('store.documentPreview')}
|
|
138
138
|
</h2>
|
|
139
139
|
</div>
|
|
@@ -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-primary hover:text-primary"
|
|
146
146
|
>
|
|
147
147
|
<Maximize2 className="h-4 w-4" />
|
|
148
148
|
<span>{t('store.fullView')}</span>
|
|
@@ -151,7 +151,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
151
151
|
variant="ghost"
|
|
152
152
|
size="sm"
|
|
153
153
|
onClick={onClose}
|
|
154
|
-
className="flex items-center text-
|
|
154
|
+
className="flex items-center text-muted hover:text-foreground dark:text-foreground"
|
|
155
155
|
>
|
|
156
156
|
<X className="h-5 w-5" />
|
|
157
157
|
</Button>
|
|
@@ -162,8 +162,8 @@ 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-
|
|
166
|
-
<p className="text-
|
|
165
|
+
<Spinner size="lg" className="text-primary mb-2" />
|
|
166
|
+
<p className="text-muted">{t('store.loadingDocument')}</p>
|
|
167
167
|
</div>
|
|
168
168
|
</div>
|
|
169
169
|
) : (
|
|
@@ -175,8 +175,8 @@ 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-
|
|
179
|
-
: 'border-transparent text-
|
|
178
|
+
? 'border-primary text-primary'
|
|
179
|
+
: 'border-transparent text-muted hover:text-foreground'
|
|
180
180
|
}`}
|
|
181
181
|
onClick={() => setCurrentTab('preview')}
|
|
182
182
|
>
|
|
@@ -189,8 +189,8 @@ 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-
|
|
193
|
-
: 'border-transparent text-
|
|
192
|
+
? 'border-primary text-primary'
|
|
193
|
+
: 'border-transparent text-muted hover:text-foreground'
|
|
194
194
|
}`}
|
|
195
195
|
onClick={() => setCurrentTab('properties')}
|
|
196
196
|
>
|
|
@@ -209,16 +209,16 @@ 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-primary" />
|
|
213
213
|
</div>
|
|
214
214
|
) : text ? (
|
|
215
|
-
<div className="shadow rounded-md p-4 border border-
|
|
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-
|
|
217
|
+
<div className="prose prose-sm max-w-none prose-p:my-2 prose-pre:bg-muted prose-pre:my-2 prose-headings:text-primary dark:prose-invert">
|
|
218
218
|
<MarkdownRenderer>{text}</MarkdownRenderer>
|
|
219
219
|
</div>
|
|
220
220
|
) : (
|
|
221
|
-
<pre className="text-wrap whitespace-pre-wrap dark:text-
|
|
221
|
+
<pre className="text-wrap whitespace-pre-wrap dark:text-foreground">
|
|
222
222
|
{text}
|
|
223
223
|
</pre>
|
|
224
224
|
)}
|
|
@@ -229,7 +229,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
229
229
|
{isImage && (
|
|
230
230
|
<div className="mt-4">
|
|
231
231
|
{imageUrl ? (
|
|
232
|
-
<div className="border border-
|
|
232
|
+
<div className="border border-border rounded-md p-2 bg-white dark:bg-muted">
|
|
233
233
|
<img
|
|
234
234
|
src={imageUrl}
|
|
235
235
|
alt={object?.name}
|
|
@@ -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-primary" />
|
|
242
242
|
</div>
|
|
243
243
|
)}
|
|
244
244
|
</div>
|
|
@@ -246,14 +246,12 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
246
246
|
|
|
247
247
|
{/* PDF Content Notice */}
|
|
248
248
|
{isPdf && (
|
|
249
|
-
<div className="flex flex-col items-center justify-center h-64 border border-
|
|
250
|
-
<FileText className="h-16 w-16 text-
|
|
251
|
-
<p className="text-
|
|
252
|
-
{t('store.pdfPreviewFullView')}
|
|
253
|
-
</p>
|
|
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-primary mb-4" />
|
|
251
|
+
<p className="text-muted text-center mb-4">{t('store.pdfPreviewFullView')}</p>
|
|
254
252
|
<Button
|
|
255
253
|
onClick={handleViewFullDocument}
|
|
256
|
-
className="bg-
|
|
254
|
+
className="bg-primary hover:bg-primary text-white"
|
|
257
255
|
>
|
|
258
256
|
{t('store.openFullDocumentView')}
|
|
259
257
|
</Button>
|
|
@@ -262,11 +260,9 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
262
260
|
|
|
263
261
|
{/* No Content Notice */}
|
|
264
262
|
{!isImage && !text && !isPdf && !loadingText && (
|
|
265
|
-
<div className="flex flex-col items-center justify-center h-64 border border-
|
|
266
|
-
<FileText className="h-16 w-16 text-
|
|
267
|
-
<p className="text-
|
|
268
|
-
{t('store.noPreviewAvailable')}
|
|
269
|
-
</p>
|
|
263
|
+
<div className="flex flex-col items-center justify-center h-64 border border-border rounded-md p-4 bg-muted">
|
|
264
|
+
<FileText className="h-16 w-16 text-foreground dark:text-muted mb-4" />
|
|
265
|
+
<p className="text-muted text-center">{t('store.noPreviewAvailable')}</p>
|
|
270
266
|
</div>
|
|
271
267
|
)}
|
|
272
268
|
</div>
|
|
@@ -275,56 +271,50 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
275
271
|
{currentTab === 'properties' && object && (
|
|
276
272
|
<div className="h-full">
|
|
277
273
|
{object.properties ? (
|
|
278
|
-
<div className="shadow rounded-md p-4 border border-
|
|
274
|
+
<div className="shadow rounded-md p-4 border border-border bg-white dark:bg-muted">
|
|
279
275
|
<JSONDisplay value={object.properties} />
|
|
280
276
|
</div>
|
|
281
277
|
) : (
|
|
282
|
-
<div className="flex flex-col items-center justify-center h-64 border border-
|
|
283
|
-
<Info className="h-16 w-16 text-
|
|
284
|
-
<p className="text-
|
|
285
|
-
{t('store.noPropertiesAvailable')}
|
|
286
|
-
</p>
|
|
278
|
+
<div className="flex flex-col items-center justify-center h-64 border border-border rounded-md p-4 bg-muted">
|
|
279
|
+
<Info className="h-16 w-16 text-foreground dark:text-muted mb-4" />
|
|
280
|
+
<p className="text-muted text-center">{t('store.noPropertiesAvailable')}</p>
|
|
287
281
|
</div>
|
|
288
282
|
)}
|
|
289
283
|
|
|
290
284
|
<div className="mt-4">
|
|
291
|
-
<h3 className="text-sm font-semibold text-
|
|
285
|
+
<h3 className="text-sm font-semibold text-foreground mb-2">
|
|
292
286
|
{t('store.documentInformation')}
|
|
293
287
|
</h3>
|
|
294
|
-
<div className="shadow rounded-md p-4 border border-
|
|
288
|
+
<div className="shadow rounded-md p-4 border border-border bg-white dark:bg-muted">
|
|
295
289
|
<div className="grid grid-cols-2 gap-y-2 gap-x-4 text-sm">
|
|
296
|
-
<div className="text-
|
|
297
|
-
<div className="font-medium dark:text-
|
|
290
|
+
<div className="text-muted">{t('store.id')}</div>
|
|
291
|
+
<div className="font-medium dark:text-foreground">{object.id}</div>
|
|
298
292
|
|
|
299
|
-
<div className="text-
|
|
300
|
-
|
|
301
|
-
</div>
|
|
302
|
-
<div className="font-medium dark:text-gray-200">
|
|
293
|
+
<div className="text-muted">{t('store.contentType')}</div>
|
|
294
|
+
<div className="font-medium dark:text-foreground">
|
|
303
295
|
{object.type?.name || t('store.unknown')}
|
|
304
296
|
</div>
|
|
305
297
|
|
|
306
|
-
<div className="text-
|
|
307
|
-
|
|
308
|
-
</div>
|
|
309
|
-
<div className="font-medium dark:text-gray-200">
|
|
298
|
+
<div className="text-muted">{t('store.contentType')}</div>
|
|
299
|
+
<div className="font-medium dark:text-foreground">
|
|
310
300
|
{object.content?.type || t('store.na')}
|
|
311
301
|
</div>
|
|
312
302
|
|
|
313
|
-
<div className="text-
|
|
303
|
+
<div className="text-muted">{t('store.size')}</div>
|
|
314
304
|
<div className="font-medium">
|
|
315
305
|
{object.content && 'size' in object.content
|
|
316
306
|
? formatFileSize(object.content.size as number)
|
|
317
307
|
: t('store.unknown')}
|
|
318
308
|
</div>
|
|
319
309
|
|
|
320
|
-
<div className="text-
|
|
310
|
+
<div className="text-muted">{t('store.created')}</div>
|
|
321
311
|
<div className="font-medium">
|
|
322
312
|
{object.created_at
|
|
323
313
|
? new Date(object.created_at).toLocaleString()
|
|
324
314
|
: t('store.na')}
|
|
325
315
|
</div>
|
|
326
316
|
|
|
327
|
-
<div className="text-
|
|
317
|
+
<div className="text-muted">{t('store.updated')}</div>
|
|
328
318
|
<div className="font-medium">
|
|
329
319
|
{object.updated_at
|
|
330
320
|
? new Date(object.updated_at).toLocaleString()
|
|
@@ -340,7 +330,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
340
330
|
)}
|
|
341
331
|
|
|
342
332
|
{/* Footer actions */}
|
|
343
|
-
<div className="flex items-center justify-between p-4 border-t bg-
|
|
333
|
+
<div className="flex items-center justify-between p-4 border-t bg-muted dark:border-border">
|
|
344
334
|
<div>
|
|
345
335
|
{object?.content?.source && (
|
|
346
336
|
<Button
|
|
@@ -363,14 +353,14 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
|
|
|
363
353
|
}
|
|
364
354
|
}}
|
|
365
355
|
variant="outline"
|
|
366
|
-
className="text-
|
|
356
|
+
className="text-primary border-primary hover:bg-info"
|
|
367
357
|
>
|
|
368
358
|
<Download className="h-4 w-4 me-2" />
|
|
369
359
|
{t('pdf.download')}
|
|
370
360
|
</Button>
|
|
371
361
|
)}
|
|
372
362
|
</div>
|
|
373
|
-
<Button onClick={handleViewFullDocument} className="bg-
|
|
363
|
+
<Button onClick={handleViewFullDocument} className="bg-primary hover:bg-primary text-white">
|
|
374
364
|
{t('store.openFullDocument')}
|
|
375
365
|
<ChevronRight className="h-4 w-4 ms-2 cn-rtl-flip" />
|
|
376
366
|
</Button>
|