@vertesia/ui 1.5.0-dev.20260807.073259Z → 1.5.0-dev.20260901.005903Z
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/README.md +1 -7
- package/lib/core/components/FormItem.d.ts.map +1 -1
- package/lib/core/components/FormItem.js +2 -3
- package/lib/core/components/FormItem.js.map +1 -1
- package/lib/core/components/InfoTip.d.ts +20 -0
- package/lib/core/components/InfoTip.d.ts.map +1 -0
- package/lib/core/components/InfoTip.js +18 -0
- package/lib/core/components/InfoTip.js.map +1 -0
- package/lib/core/components/index.d.ts +1 -0
- package/lib/core/components/index.d.ts.map +1 -1
- package/lib/core/components/index.js +1 -0
- package/lib/core/components/index.js.map +1 -1
- package/lib/core/components/shadcn/Panel.d.ts.map +1 -1
- package/lib/core/components/shadcn/Panel.js +3 -3
- package/lib/core/components/shadcn/Panel.js.map +1 -1
- package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +1 -1
- package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
- package/lib/core/components/shadcn/filters/filter/dateFilter.d.ts.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.d.ts.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/index.d.ts +1 -0
- package/lib/core/components/shadcn/index.d.ts.map +1 -1
- package/lib/core/components/shadcn/index.js +1 -0
- package/lib/core/components/shadcn/index.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +1 -3
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/overflowTabs.d.ts +59 -0
- package/lib/core/components/shadcn/overflowTabs.d.ts.map +1 -0
- package/lib/core/components/shadcn/overflowTabs.js +173 -0
- package/lib/core/components/shadcn/overflowTabs.js.map +1 -0
- package/lib/core/components/shadcn/selectBox.js +2 -2
- package/lib/core/components/shadcn/selectBox.js.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.d.ts +3 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.d.ts.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.js +8 -9
- package/lib/core/components/shadcn/theme/ThemeProvider.js.map +1 -1
- package/lib/core/utils/dayjs.d.ts +12 -0
- package/lib/core/utils/dayjs.d.ts.map +1 -0
- package/lib/core/utils/dayjs.js +16 -0
- package/lib/core/utils/dayjs.js.map +1 -0
- package/lib/env/index.d.ts +17 -0
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +18 -1
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/PayloadBuilder.d.ts +1 -0
- package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/features/agent/PayloadBuilder.js +22 -5
- package/lib/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +3 -135
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +19 -4
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +99 -29
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +10 -9
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.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 -8
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +45 -4
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js +1 -1
- 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 +3 -3
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.d.ts.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/ToolCallGroup.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +9 -121
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js +19 -11
- package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
- package/lib/features/agent/chat/VegaLiteChart.d.ts.map +1 -1
- package/lib/features/agent/chat/VegaLiteChart.js +11 -3
- package/lib/features/agent/chat/VegaLiteChart.js.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +3 -0
- package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.js +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.js.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts +14 -2
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.js +20 -2
- package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts +3 -3
- package/lib/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.js +6 -1
- package/lib/features/facets/CollectionsFacetsNav.js.map +1 -1
- package/lib/features/facets/DocumentsFacetsNav.d.ts +3 -3
- package/lib/features/facets/DocumentsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/DocumentsFacetsNav.js +20 -8
- package/lib/features/facets/DocumentsFacetsNav.js.map +1 -1
- package/lib/features/facets/InteractionsFacetsNav.d.ts +3 -3
- package/lib/features/facets/InteractionsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/InteractionsFacetsNav.js +11 -1
- package/lib/features/facets/InteractionsFacetsNav.js.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts +3 -3
- package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.js +6 -1
- package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
- package/lib/features/facets/RunsFacetsNav.d.ts +4 -14
- package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/RunsFacetsNav.js +26 -15
- package/lib/features/facets/RunsFacetsNav.js.map +1 -1
- package/lib/features/facets/WorkflowExecutionsFacetsNav.d.ts +4 -3
- package/lib/features/facets/WorkflowExecutionsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/WorkflowExecutionsFacetsNav.js +18 -10
- package/lib/features/facets/WorkflowExecutionsFacetsNav.js.map +1 -1
- package/lib/features/facets/index.d.ts +1 -1
- package/lib/features/facets/index.d.ts.map +1 -1
- package/lib/features/facets/index.js.map +1 -1
- package/lib/features/facets/utils/SearchInterface.d.ts +4 -3
- package/lib/features/facets/utils/SearchInterface.d.ts.map +1 -1
- package/lib/features/facets/utils/SearchInterface.js +4 -0
- package/lib/features/facets/utils/SearchInterface.js.map +1 -1
- package/lib/features/layout/GenericPageNavHeader.d.ts +8 -1
- package/lib/features/layout/GenericPageNavHeader.d.ts.map +1 -1
- package/lib/features/layout/GenericPageNavHeader.js +9 -1
- package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
- package/lib/features/magic-pdf/DownloadPopover.d.ts +3 -2
- package/lib/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
- package/lib/features/magic-pdf/DownloadPopover.js.map +1 -1
- package/lib/features/magic-pdf/GroundedExtractionView.d.ts.map +1 -1
- package/lib/features/magic-pdf/GroundedExtractionView.js +51 -64
- package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.js +2 -2
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.d.ts +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js +2 -2
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +4 -5
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
- package/lib/features/oauth/useMcpConnections.js +20 -4
- package/lib/features/oauth/useMcpConnections.js.map +1 -1
- package/lib/features/pdf-viewer/PdfPageRenderer.d.ts.map +1 -1
- package/lib/features/pdf-viewer/PdfPageRenderer.js +9 -11
- package/lib/features/pdf-viewer/PdfPageRenderer.js.map +1 -1
- package/lib/features/pdf-viewer/lazyReactPdf.d.ts +10 -0
- package/lib/features/pdf-viewer/lazyReactPdf.d.ts.map +1 -0
- package/lib/features/pdf-viewer/lazyReactPdf.js +25 -0
- package/lib/features/pdf-viewer/lazyReactPdf.js.map +1 -0
- package/lib/features/store/collections/CollectionsTable.d.ts.map +1 -1
- package/lib/features/store/collections/CollectionsTable.js +1 -3
- package/lib/features/store/collections/CollectionsTable.js.map +1 -1
- package/lib/features/store/collections/EditCollectionView.js +1 -1
- package/lib/features/store/collections/EditCollectionView.js.map +1 -1
- package/lib/features/store/objects/ExportPropertiesModal.d.ts +3 -1
- package/lib/features/store/objects/ExportPropertiesModal.d.ts.map +1 -1
- package/lib/features/store/objects/ExportPropertiesModal.js +5 -5
- package/lib/features/store/objects/ExportPropertiesModal.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +4 -10
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
- package/lib/features/store/objects/components/TextEditorPanel.js +8 -3
- package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
- package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/features/store/objects/layout/renderers.js +1 -5
- package/lib/features/store/objects/layout/renderers.js.map +1 -1
- package/lib/features/store/objects/search/DocumentSearchContext.d.ts +44 -62
- package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
- package/lib/features/store/objects/search/DocumentSearchContext.js +47 -2
- package/lib/features/store/objects/search/DocumentSearchContext.js.map +1 -1
- package/lib/features/store/objects/selection/actions/DeleteObjectsAction.d.ts.map +1 -1
- package/lib/features/store/objects/selection/actions/DeleteObjectsAction.js +5 -0
- package/lib/features/store/objects/selection/actions/DeleteObjectsAction.js.map +1 -1
- package/lib/features/store/objects/upload/DocumentUploadModal.d.ts +6 -1
- package/lib/features/store/objects/upload/DocumentUploadModal.d.ts.map +1 -1
- package/lib/features/store/objects/upload/DocumentUploadModal.js +4 -3
- package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
- package/lib/features/store/objects/upload/useSmartFileUploadProcessing.d.ts.map +1 -1
- package/lib/features/store/objects/upload/useSmartFileUploadProcessing.js +2 -2
- package/lib/features/store/objects/upload/useSmartFileUploadProcessing.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +1 -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 +12 -2
- package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
- package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
- package/lib/features/store/types/IntakePolicyForm.js +15 -15
- package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
- package/lib/features/store/types/ObjectSchemaEditor.d.ts.map +1 -1
- package/lib/features/store/types/ObjectSchemaEditor.js +6 -2
- package/lib/features/store/types/ObjectSchemaEditor.js.map +1 -1
- package/lib/features/store/types/TableLayoutEditor.d.ts.map +1 -1
- package/lib/features/store/types/TableLayoutEditor.js +2 -0
- package/lib/features/store/types/TableLayoutEditor.js.map +1 -1
- package/lib/features/store/types/TypeRegistry.d.ts +282 -0
- package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +281 -0
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
- package/lib/features/user/UserInfo.d.ts.map +1 -1
- package/lib/features/user/UserInfo.js +2 -4
- package/lib/features/user/UserInfo.js.map +1 -1
- package/lib/features/views/ViewActions.d.ts +32 -0
- package/lib/features/views/ViewActions.d.ts.map +1 -0
- package/lib/features/views/ViewActions.js +186 -0
- package/lib/features/views/ViewActions.js.map +1 -0
- package/lib/features/views/ViewDropTarget.d.ts +15 -0
- package/lib/features/views/ViewDropTarget.d.ts.map +1 -0
- package/lib/features/views/ViewDropTarget.js +79 -0
- package/lib/features/views/ViewDropTarget.js.map +1 -0
- package/lib/features/views/ViewExperience.d.ts +3 -2
- package/lib/features/views/ViewExperience.d.ts.map +1 -1
- package/lib/features/views/ViewExperience.js +103 -12
- package/lib/features/views/ViewExperience.js.map +1 -1
- package/lib/features/views/ViewNavigation.d.ts +1 -1
- package/lib/features/views/ViewNavigation.d.ts.map +1 -1
- package/lib/features/views/ViewNavigation.js +14 -5
- package/lib/features/views/ViewNavigation.js.map +1 -1
- package/lib/features/views/ViewResults.d.ts +1 -1
- package/lib/features/views/ViewResults.d.ts.map +1 -1
- package/lib/features/views/ViewResults.js +124 -34
- package/lib/features/views/ViewResults.js.map +1 -1
- package/lib/features/views/index.d.ts +1 -0
- package/lib/features/views/index.d.ts.map +1 -1
- package/lib/features/views/index.js +1 -0
- package/lib/features/views/index.js.map +1 -1
- package/lib/features/views/types.d.ts +46 -1
- package/lib/features/views/types.d.ts.map +1 -1
- package/lib/features/views/viewState.d.ts.map +1 -1
- package/lib/features/views/viewState.js +34 -0
- package/lib/features/views/viewState.js.map +1 -1
- package/lib/i18n/LanguageProvider.d.ts +3 -1
- package/lib/i18n/LanguageProvider.d.ts.map +1 -1
- package/lib/i18n/LanguageProvider.js +9 -7
- package/lib/i18n/LanguageProvider.js.map +1 -1
- package/lib/i18n/instance.d.ts +2 -0
- package/lib/i18n/instance.d.ts.map +1 -1
- package/lib/i18n/instance.js +45 -26
- package/lib/i18n/instance.js.map +1 -1
- package/lib/i18n/locales/ar.json +296 -15
- package/lib/i18n/locales/de.json +294 -13
- package/lib/i18n/locales/en.json +65 -4
- package/lib/i18n/locales/es.json +295 -14
- package/lib/i18n/locales/fr.json +294 -13
- package/lib/i18n/locales/it.json +294 -13
- package/lib/i18n/locales/ja.json +292 -10
- package/lib/i18n/locales/ko.json +292 -10
- package/lib/i18n/locales/pt.json +294 -13
- package/lib/i18n/locales/ru.json +291 -10
- package/lib/i18n/locales/tr.json +291 -10
- package/lib/i18n/locales/zh-TW.json +292 -10
- package/lib/i18n/locales/zh.json +292 -10
- package/lib/router/RouteComponent.d.ts +8 -0
- package/lib/router/RouteComponent.d.ts.map +1 -1
- package/lib/router/RouteComponent.js +41 -9
- package/lib/router/RouteComponent.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +20 -29
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +25 -19
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/session/auth/domainRouting.d.ts +11 -0
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +13 -0
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/session/auth/firebase.js +1 -1
- package/lib/session/auth/firebase.js.map +1 -1
- package/lib/session/useUXTracking.d.ts.map +1 -1
- package/lib/session/useUXTracking.js +6 -1
- package/lib/session/useUXTracking.js.map +1 -1
- package/lib/shell/VertesiaShell.d.ts.map +1 -1
- package/lib/shell/VertesiaShell.js +2 -1
- package/lib/shell/VertesiaShell.js.map +1 -1
- package/lib/shell/apps/AppInstallationProvider.d.ts +4 -2
- package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
- package/lib/shell/apps/IframeAppContextSync.d.ts +3 -0
- package/lib/shell/apps/IframeAppContextSync.d.ts.map +1 -0
- package/lib/shell/apps/IframeAppContextSync.js +95 -0
- package/lib/shell/apps/IframeAppContextSync.js.map +1 -0
- package/lib/shell/apps/iframe-auth.d.ts +55 -0
- package/lib/shell/apps/iframe-auth.d.ts.map +1 -0
- package/lib/shell/apps/iframe-auth.js +154 -0
- package/lib/shell/apps/iframe-auth.js.map +1 -0
- package/lib/shell/apps/index.d.ts +2 -0
- package/lib/shell/apps/index.d.ts.map +1 -1
- package/lib/shell/apps/index.js +2 -0
- package/lib/shell/apps/index.js.map +1 -1
- package/lib/vertesia-ui-core.js +199 -4
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +975 -35
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.js +2 -38
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js.map +1 -0
- package/lib/vertesia-ui-layout.js +80 -1
- package/lib/vertesia-ui-layout.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +278 -4
- 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 +118 -1
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +336 -20
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
- package/lib/widgets/markdown/MarkdownRenderer.js +43 -2
- package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
- package/lib/widgets/markdown/MermaidDiagram.d.ts.map +1 -1
- package/lib/widgets/markdown/MermaidDiagram.js +35 -22
- package/lib/widgets/markdown/MermaidDiagram.js.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.js +14 -10
- package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
- package/package.json +24 -29
- package/src/core/components/FormItem.tsx +2 -5
- package/src/core/components/InfoTip.test.tsx +33 -0
- package/src/core/components/InfoTip.tsx +32 -0
- package/src/core/components/index.ts +1 -0
- package/src/core/components/shadcn/Panel.tsx +3 -7
- package/src/core/components/shadcn/filters/comboBox/DateCombobox.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/index.ts +1 -0
- package/src/core/components/shadcn/modal/dialog.test.tsx +35 -0
- package/src/core/components/shadcn/modal/dialog.tsx +0 -4
- package/src/core/components/shadcn/overflowTabs.tsx +320 -0
- package/src/core/components/shadcn/selectBox.tsx +2 -2
- package/src/core/components/shadcn/theme/ThemeProvider.tsx +10 -9
- package/src/core/utils/dayjs.ts +17 -0
- package/src/css/base.css +78 -0
- package/src/env/index.test.ts +94 -0
- package/src/env/index.ts +36 -1
- package/src/features/agent/PayloadBuilder.test.ts +68 -0
- package/src/features/agent/PayloadBuilder.tsx +28 -4
- package/src/features/agent/chat/AgentRightPanel.tsx +2 -252
- package/src/features/agent/chat/ArtifactsTab.tsx +1 -0
- package/src/features/agent/chat/AskUserWidget.test.tsx +20 -1
- package/src/features/agent/chat/AskUserWidget.tsx +22 -6
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +160 -0
- package/src/features/agent/chat/ModernAgentConversation.tsx +111 -31
- package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +86 -67
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +90 -7
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +4 -6
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.test.ts +103 -1
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +50 -4
- package/src/features/agent/chat/ModernAgentOutput/BatchProgressPanel.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +18 -1
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/StreamingMessage.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +37 -167
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +94 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.ts +19 -10
- package/src/features/agent/chat/VegaLiteChart.tsx +32 -14
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +18 -0
- package/src/features/agent/chat/hooks/useAgentStream.ts +3 -0
- package/src/features/document-viewer/UniversalDocumentViewer.tsx +1 -1
- package/src/features/facets/AgentRunnerFacetsNav.tsx +44 -4
- package/src/features/facets/CollectionsFacetsNav.tsx +15 -4
- package/src/features/facets/DocumentsFacetsNav.tsx +25 -8
- package/src/features/facets/FacetQueryHandlers.test.ts +84 -0
- package/src/features/facets/InteractionsFacetsNav.tsx +20 -4
- package/src/features/facets/PromptsFacetsNav.tsx +15 -4
- package/src/features/facets/RunsFacetsNav.test.ts +59 -0
- package/src/features/facets/RunsFacetsNav.tsx +40 -30
- package/src/features/facets/WorkflowExecutionsFacetsNav.test.ts +57 -0
- package/src/features/facets/WorkflowExecutionsFacetsNav.tsx +36 -16
- package/src/features/facets/index.ts +1 -0
- package/src/features/facets/utils/SearchInterface.tsx +12 -3
- package/src/features/layout/GenericPageNavHeader.tsx +16 -0
- package/src/features/magic-pdf/DownloadPopover.tsx +1 -2
- package/src/features/magic-pdf/GroundedExtractionView.test.tsx +7 -1
- package/src/features/magic-pdf/GroundedExtractionView.tsx +162 -242
- package/src/features/oauth/McpConnectionsButton.test.tsx +18 -1
- package/src/features/oauth/McpConnectionsButton.tsx +6 -2
- package/src/features/oauth/McpConnectionsDialog.tsx +3 -3
- package/src/features/oauth/useMcpConnections.test.ts +1 -0
- package/src/features/oauth/useMcpConnections.ts +24 -7
- package/src/features/pdf-viewer/PdfPageRenderer.tsx +76 -71
- package/src/features/pdf-viewer/lazyReactPdf.ts +33 -0
- package/src/features/store/collections/CollectionsTable.tsx +1 -4
- package/src/features/store/collections/EditCollectionView.tsx +1 -1
- package/src/features/store/objects/ExportPropertiesModal.tsx +25 -16
- package/src/features/store/objects/components/ContentOverview.tsx +2 -28
- package/src/features/store/objects/components/TextEditorPanel.tsx +13 -3
- package/src/features/store/objects/layout/renderers.tsx +1 -6
- package/src/features/store/objects/search/DocumentSearchContext.test.ts +45 -0
- package/src/features/store/objects/search/DocumentSearchContext.ts +54 -4
- package/src/features/store/objects/selection/actions/DeleteObjectsAction.tsx +5 -0
- package/src/features/store/objects/upload/DocumentUploadModal.tsx +10 -3
- package/src/features/store/objects/upload/useSmartFileUploadProcessing.ts +15 -6
- package/src/features/store/types/ContentObjectTypesTable.tsx +1 -4
- package/src/features/store/types/IntakePolicyEditor.tsx +14 -5
- package/src/features/store/types/IntakePolicyForm.tsx +120 -20
- package/src/features/store/types/ObjectSchemaEditor.tsx +6 -2
- package/src/features/store/types/TableLayoutEditor.tsx +2 -0
- package/src/features/user/UserInfo.test.tsx +10 -0
- package/src/features/user/UserInfo.tsx +2 -7
- package/src/features/views/ViewActions.test.tsx +80 -0
- package/src/features/views/ViewActions.tsx +352 -0
- package/src/features/views/ViewDropTarget.test.tsx +150 -0
- package/src/features/views/ViewDropTarget.tsx +140 -0
- package/src/features/views/ViewExperience.test.tsx +72 -0
- package/src/features/views/ViewExperience.tsx +189 -22
- package/src/features/views/ViewMedia.test.tsx +180 -0
- package/src/features/views/ViewNavigation.test.tsx +42 -0
- package/src/features/views/ViewNavigation.tsx +43 -5
- package/src/features/views/ViewResults.tsx +243 -26
- package/src/features/views/index.ts +1 -0
- package/src/features/views/types.ts +50 -0
- package/src/features/views/viewState.test.ts +7 -1
- package/src/features/views/viewState.ts +32 -0
- package/src/i18n/LanguageProvider.tsx +15 -8
- package/src/i18n/instance.test.ts +30 -0
- package/src/i18n/instance.ts +67 -40
- package/src/i18n/locales/ar.json +1192 -911
- package/src/i18n/locales/de.json +1148 -867
- package/src/i18n/locales/en.json +65 -4
- package/src/i18n/locales/es.json +1159 -878
- package/src/i18n/locales/fr.json +1159 -878
- package/src/i18n/locales/it.json +1159 -878
- package/src/i18n/locales/ja.json +1148 -866
- package/src/i18n/locales/ko.json +1148 -866
- package/src/i18n/locales/pt.json +1159 -878
- package/src/i18n/locales/ru.json +1170 -889
- package/src/i18n/locales/tr.json +1148 -867
- package/src/i18n/locales/zh-TW.json +1148 -866
- package/src/i18n/locales/zh.json +1148 -866
- package/src/i18n/rtl.test.ts +16 -7
- package/src/rich-text/VertesiaRichTextEditor.test.tsx +33 -1
- package/src/router/RouteComponent.test.tsx +139 -0
- package/src/router/RouteComponent.tsx +54 -9
- package/src/session/UserSessionProvider.tsx +20 -31
- package/src/session/auth/composable.scope.test.ts +1 -1
- package/src/session/auth/composable.test.ts +61 -1
- package/src/session/auth/composable.ts +29 -23
- package/src/session/auth/domainRouting.test.ts +24 -1
- package/src/session/auth/domainRouting.ts +29 -0
- package/src/session/auth/firebase.ts +1 -1
- package/src/session/useUXTracking.tsx +6 -1
- package/src/shell/VertesiaShell.tsx +2 -0
- package/src/shell/apps/IframeAppContextSync.test.tsx +196 -0
- package/src/shell/apps/IframeAppContextSync.tsx +101 -0
- package/src/shell/apps/iframe-auth.test.ts +118 -0
- package/src/shell/apps/iframe-auth.ts +193 -0
- package/src/shell/apps/index.ts +2 -0
- package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +12 -3
- package/src/widgets/markdown/MarkdownRenderer.tsx +50 -2
- package/src/widgets/markdown/MermaidDiagram.tsx +38 -22
- package/src/widgets/monacoEditor/MonacoEditor.tsx +27 -20
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts +0 -25
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts.map +0 -1
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js +0 -42
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js.map +0 -1
- package/src/features/magic-pdf/GroundedExtractionAssistantPanel.tsx +0 -86
package/src/i18n/rtl.test.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
1
4
|
import i18next from 'i18next';
|
|
2
5
|
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import {
|
|
6
|
+
import { AVAILABLE_LOCALES, NAMESPACE } from './instance.js';
|
|
4
7
|
import { isRTL, RTL_LANGUAGES, resolveLanguage, SUPPORTED_LANGUAGES } from './rtl.js';
|
|
5
8
|
|
|
6
9
|
describe('isRTL', () => {
|
|
@@ -67,10 +70,10 @@ describe('RTL_LANGUAGES set', () => {
|
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
describe('SUPPORTED_LANGUAGES divergence guard', () => {
|
|
70
|
-
it('matches exactly the locales
|
|
71
|
-
const
|
|
73
|
+
it('matches exactly the locales the i18n instance can serve', () => {
|
|
74
|
+
const available = [...AVAILABLE_LOCALES].sort();
|
|
72
75
|
const supported = [...SUPPORTED_LANGUAGES].sort();
|
|
73
|
-
expect(
|
|
76
|
+
expect(available).toEqual(supported);
|
|
74
77
|
});
|
|
75
78
|
});
|
|
76
79
|
|
|
@@ -95,8 +98,10 @@ describe('empty translation fallback', () => {
|
|
|
95
98
|
expect(t('test.emptyTranslationFallback')).toBe('English fallback');
|
|
96
99
|
});
|
|
97
100
|
|
|
101
|
+
// Reads the locale files rather than `i18nInstance.options.resources`: only the `en` fallback is
|
|
102
|
+
// bundled there now, the rest are fetched on demand.
|
|
98
103
|
it('does not ship parser-created empty locale entries', () => {
|
|
99
|
-
const
|
|
104
|
+
const localesDir = join(dirname(fileURLToPath(import.meta.url)), 'locales');
|
|
100
105
|
const emptyEntries: string[] = [];
|
|
101
106
|
|
|
102
107
|
const collectEmptyEntries = (value: unknown, path: string[]) => {
|
|
@@ -121,8 +126,12 @@ describe('empty translation fallback', () => {
|
|
|
121
126
|
}
|
|
122
127
|
};
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
const localeFiles = readdirSync(localesDir).filter((name) => name.endsWith('.json'));
|
|
130
|
+
expect(localeFiles.length).toBe(SUPPORTED_LANGUAGES.length);
|
|
131
|
+
|
|
132
|
+
for (const file of localeFiles) {
|
|
133
|
+
const resource: unknown = JSON.parse(readFileSync(join(localesDir, file), 'utf-8'));
|
|
134
|
+
collectEmptyEntries(resource, [file.replace(/\.json$/, '')]);
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
expect(emptyEntries).toEqual([]);
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/** @vitest-environment jsdom */
|
|
2
2
|
|
|
3
3
|
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS,
|
|
6
|
+
MarkdownRichTextEditor,
|
|
7
|
+
type MarkdownRichTextEditorProps,
|
|
8
|
+
setEditorMarkdown,
|
|
9
|
+
} from '@vertesia/rich-text';
|
|
5
10
|
import { describe, expect, it, vi } from 'vitest';
|
|
6
11
|
import { I18nProvider } from '../i18n/index.js';
|
|
7
12
|
import {
|
|
@@ -174,6 +179,33 @@ describe('VertesiaMarkdownRichTextEditor', () => {
|
|
|
174
179
|
expect(await screen.findByRole('heading', { name: 'Setext heading' })).not.toBeNull();
|
|
175
180
|
expect(screen.getByRole('textbox', { name: 'Markdown document editor' })).not.toBeNull();
|
|
176
181
|
expect(screen.queryByRole('heading', { name: 'Some Markdown formatting may change' })).toBeNull();
|
|
182
|
+
// The document editor debounces serialization, so wait past that window: otherwise this
|
|
183
|
+
// assertion passes merely because a spurious change has not been flushed yet.
|
|
184
|
+
await new Promise((resolve) => setTimeout(resolve, DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS * 2));
|
|
185
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('does not report a change when the document is locked or unlocked', async () => {
|
|
189
|
+
const onChange = vi.fn();
|
|
190
|
+
const renderEditable = (editable: boolean) => (
|
|
191
|
+
<I18nProvider lng="en">
|
|
192
|
+
<VertesiaMarkdownDocumentEditor
|
|
193
|
+
value={'Setext heading\n=============='}
|
|
194
|
+
onChange={onChange}
|
|
195
|
+
editable={editable}
|
|
196
|
+
/>
|
|
197
|
+
</I18nProvider>
|
|
198
|
+
);
|
|
199
|
+
const view = render(renderEditable(true));
|
|
200
|
+
|
|
201
|
+
expect(await screen.findByRole('heading', { name: 'Setext heading' })).not.toBeNull();
|
|
202
|
+
// Both directions matter: either toggle emits an editor update on its own.
|
|
203
|
+
view.rerender(renderEditable(false));
|
|
204
|
+
await new Promise((resolve) => setTimeout(resolve, DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS * 2));
|
|
205
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
206
|
+
|
|
207
|
+
view.rerender(renderEditable(true));
|
|
208
|
+
await new Promise((resolve) => setTimeout(resolve, DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS * 2));
|
|
177
209
|
expect(onChange).not.toHaveBeenCalled();
|
|
178
210
|
});
|
|
179
211
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { act, cleanup, render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
|
+
import { prefetchLazyRoutes, RouteComponent } from './RouteComponent';
|
|
4
|
+
import { type LazyRouteModule, useNavigate } from './Router';
|
|
5
|
+
import { RouterProvider } from './RouterProvider';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Lazy routes resolve their module asynchronously, which opens two windows for showing the wrong
|
|
9
|
+
* page: reusing the state of the previous lazy route while the next import is in flight, and a
|
|
10
|
+
* slower earlier import landing after a newer navigation already resolved. Both were real —
|
|
11
|
+
* RouteComponent now remounts per path and drops stale module resolutions.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
function deferredModule(text: string) {
|
|
15
|
+
let resolve!: (module: LazyRouteModule) => void;
|
|
16
|
+
const promise = new Promise<LazyRouteModule>((r) => {
|
|
17
|
+
resolve = r;
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
promise,
|
|
21
|
+
resolve: () => resolve({ default: () => <div>{text}</div> }),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let navigateFn: ReturnType<typeof useNavigate>;
|
|
26
|
+
function CaptureNavigate() {
|
|
27
|
+
navigateFn = useNavigate();
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('RouteComponent lazy routes', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
window.history.pushState({}, '', '/a');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
cleanup();
|
|
38
|
+
window.history.pushState({}, '', '/');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('stops showing the previous lazy route while the next one loads', async () => {
|
|
42
|
+
const pageA = deferredModule('Page A');
|
|
43
|
+
const pageB = deferredModule('Page B');
|
|
44
|
+
const routes = [
|
|
45
|
+
{ path: '/a', LazyComponent: () => pageA.promise },
|
|
46
|
+
{ path: '/b', LazyComponent: () => pageB.promise },
|
|
47
|
+
];
|
|
48
|
+
render(
|
|
49
|
+
<RouterProvider routes={routes}>
|
|
50
|
+
<CaptureNavigate />
|
|
51
|
+
<RouteComponent spinner={<div>loading</div>} />
|
|
52
|
+
</RouterProvider>,
|
|
53
|
+
);
|
|
54
|
+
await act(async () => pageA.resolve());
|
|
55
|
+
await waitFor(() => expect(screen.getByText('Page A')).toBeDefined());
|
|
56
|
+
|
|
57
|
+
await act(async () => navigateFn('/b'));
|
|
58
|
+
// The old page must not linger while B's import is still pending.
|
|
59
|
+
expect(screen.queryByText('Page A')).toBeNull();
|
|
60
|
+
expect(screen.getByText('loading')).toBeDefined();
|
|
61
|
+
|
|
62
|
+
await act(async () => pageB.resolve());
|
|
63
|
+
await waitFor(() => expect(screen.getByText('Page B')).toBeDefined());
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('ignores a slow import that resolves after a newer navigation', async () => {
|
|
67
|
+
const pageA = deferredModule('Page A');
|
|
68
|
+
const pageB = deferredModule('Page B');
|
|
69
|
+
const routes = [
|
|
70
|
+
{ path: '/a', LazyComponent: () => pageA.promise },
|
|
71
|
+
{ path: '/b', LazyComponent: () => pageB.promise },
|
|
72
|
+
];
|
|
73
|
+
render(
|
|
74
|
+
<RouterProvider routes={routes}>
|
|
75
|
+
<CaptureNavigate />
|
|
76
|
+
<RouteComponent />
|
|
77
|
+
</RouterProvider>,
|
|
78
|
+
);
|
|
79
|
+
// Navigate away from /a before its import resolves.
|
|
80
|
+
await act(async () => navigateFn('/b'));
|
|
81
|
+
await act(async () => pageB.resolve());
|
|
82
|
+
await waitFor(() => expect(screen.getByText('Page B')).toBeDefined());
|
|
83
|
+
|
|
84
|
+
// A's import resolving late must not replace the current page.
|
|
85
|
+
await act(async () => pageA.resolve());
|
|
86
|
+
expect(screen.queryByText('Page A')).toBeNull();
|
|
87
|
+
expect(screen.getByText('Page B')).toBeDefined();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('renders a previously resolved lazy route synchronously on revisit', async () => {
|
|
91
|
+
const pageA = deferredModule('Page A');
|
|
92
|
+
const pageB = deferredModule('Page B');
|
|
93
|
+
const routes = [
|
|
94
|
+
{ path: '/a', LazyComponent: () => pageA.promise },
|
|
95
|
+
{ path: '/b', LazyComponent: () => pageB.promise },
|
|
96
|
+
];
|
|
97
|
+
render(
|
|
98
|
+
<RouterProvider routes={routes}>
|
|
99
|
+
<CaptureNavigate />
|
|
100
|
+
<RouteComponent spinner={<div>loading</div>} />
|
|
101
|
+
</RouterProvider>,
|
|
102
|
+
);
|
|
103
|
+
await act(async () => pageA.resolve());
|
|
104
|
+
await waitFor(() => expect(screen.getByText('Page A')).toBeDefined());
|
|
105
|
+
await act(async () => navigateFn('/b'));
|
|
106
|
+
await act(async () => pageB.resolve());
|
|
107
|
+
await waitFor(() => expect(screen.getByText('Page B')).toBeDefined());
|
|
108
|
+
|
|
109
|
+
// Back to /a: its module is cached, so not even one spinner frame may show.
|
|
110
|
+
act(() => navigateFn('/a'));
|
|
111
|
+
expect(screen.getByText('Page A')).toBeDefined();
|
|
112
|
+
expect(screen.queryByText('loading')).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('prefetched lazy routes render without a spinner on first navigation', async () => {
|
|
116
|
+
const pageA = deferredModule('Page A');
|
|
117
|
+
const pageB = deferredModule('Page B');
|
|
118
|
+
const routes = [
|
|
119
|
+
{ path: '/a', LazyComponent: () => pageA.promise },
|
|
120
|
+
{ path: '/b', LazyComponent: () => pageB.promise },
|
|
121
|
+
{ path: '/c', Component: () => <div>Page C</div> },
|
|
122
|
+
];
|
|
123
|
+
pageA.resolve();
|
|
124
|
+
pageB.resolve();
|
|
125
|
+
await prefetchLazyRoutes(routes);
|
|
126
|
+
|
|
127
|
+
render(
|
|
128
|
+
<RouterProvider routes={routes}>
|
|
129
|
+
<CaptureNavigate />
|
|
130
|
+
<RouteComponent spinner={<div>loading</div>} />
|
|
131
|
+
</RouterProvider>,
|
|
132
|
+
);
|
|
133
|
+
// Even the initial mount renders from the prefetch cache.
|
|
134
|
+
expect(screen.getByText('Page A')).toBeDefined();
|
|
135
|
+
act(() => navigateFn('/b'));
|
|
136
|
+
expect(screen.getByText('Page B')).toBeDefined();
|
|
137
|
+
expect(screen.queryByText('loading')).toBeNull();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type ComponentRoute,
|
|
4
|
+
type LazyComponentRoute,
|
|
5
|
+
type LazyRouteModule,
|
|
6
|
+
type Route,
|
|
7
|
+
useRouterContext,
|
|
8
|
+
} from './Router';
|
|
9
|
+
|
|
10
|
+
// Resolved lazy modules, keyed by the route's LazyComponent function (a stable identity: route
|
|
11
|
+
// tables are declared once). A revisited lazy route renders synchronously from this cache instead
|
|
12
|
+
// of unmounting to the spinner for the async import() round-trip — without it, every navigation
|
|
13
|
+
// between two lazy routes blanks the page for at least a frame, even when the module is loaded.
|
|
14
|
+
const resolvedComponents = new Map<LazyComponentRoute['LazyComponent'], LazyRouteModule['default']>();
|
|
15
|
+
|
|
16
|
+
function resolveLazyRoute(route: LazyComponentRoute): Promise<LazyRouteModule['default']> {
|
|
17
|
+
return route.LazyComponent().then((module) => {
|
|
18
|
+
if (!module.default) {
|
|
19
|
+
throw new Error(`Lazy module for ${route.path} does not have a default export`);
|
|
20
|
+
}
|
|
21
|
+
resolvedComponents.set(route.LazyComponent, module.default);
|
|
22
|
+
return module.default;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Start loading the given routes' lazy modules ahead of navigation (non-lazy routes are ignored).
|
|
28
|
+
* Call it during idle time after first paint: the first navigation to a prefetched route then
|
|
29
|
+
* renders synchronously instead of flashing the spinner while its chunk downloads. Failures are
|
|
30
|
+
* swallowed — navigation retries the import and reports the error the normal way.
|
|
31
|
+
*/
|
|
32
|
+
export function prefetchLazyRoutes(routes: Route[]): Promise<unknown> {
|
|
33
|
+
return Promise.allSettled(
|
|
34
|
+
routes
|
|
35
|
+
.filter((route): route is LazyComponentRoute => !!(route as LazyComponentRoute).LazyComponent)
|
|
36
|
+
.map((route) => resolveLazyRoute(route)),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
3
39
|
|
|
4
40
|
interface RouteComponentProps {
|
|
5
41
|
spinner?: React.ReactNode;
|
|
@@ -12,7 +48,9 @@ export function RouteComponent({ spinner }: RouteComponentProps) {
|
|
|
12
48
|
const Component = (route as ComponentRoute).Component;
|
|
13
49
|
return <Component {...ctx.params} />;
|
|
14
50
|
} else if ((route as LazyComponentRoute).LazyComponent) {
|
|
15
|
-
|
|
51
|
+
// Keyed per path so navigating between two lazy routes remounts: a reused instance would
|
|
52
|
+
// keep rendering the previous route's component while the next import resolves.
|
|
53
|
+
return <LazyRouteComponent key={route.path} route={route as LazyComponentRoute} spinner={spinner} />;
|
|
16
54
|
} else {
|
|
17
55
|
throw new Error(`Invalid route for ${route.path}. Either Component or LazyCOmponent must be specified.`);
|
|
18
56
|
}
|
|
@@ -23,16 +61,23 @@ interface LazyRouteComponentProps {
|
|
|
23
61
|
spinner?: React.ReactNode;
|
|
24
62
|
}
|
|
25
63
|
function LazyRouteComponent({ route, spinner }: LazyRouteComponentProps) {
|
|
26
|
-
const [Component, setComponent] = useState<LazyRouteModule['default'] | null>(
|
|
64
|
+
const [Component, setComponent] = useState<LazyRouteModule['default'] | null>(
|
|
65
|
+
() => resolvedComponents.get(route.LazyComponent) ?? null,
|
|
66
|
+
);
|
|
27
67
|
useEffect(() => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
68
|
+
// A slow import must not land after this instance moved on (unmount, or a route object
|
|
69
|
+
// swap without a path change): the stale module would overwrite the current one.
|
|
70
|
+
let stale = false;
|
|
71
|
+
void resolveLazyRoute(route).then((component) => {
|
|
72
|
+
if (!stale) {
|
|
73
|
+
// we need to wrap the component type in an arrow function
|
|
74
|
+
// otherwise the setState function will execute the function as a state update function
|
|
75
|
+
setComponent(() => component);
|
|
31
76
|
}
|
|
32
|
-
// we need to wrap the component type in an arrow function
|
|
33
|
-
// otherwise the setState function will execute the function as a state update function
|
|
34
|
-
setComponent(() => module.default);
|
|
35
77
|
});
|
|
78
|
+
return () => {
|
|
79
|
+
stale = true;
|
|
80
|
+
};
|
|
36
81
|
}, [route]);
|
|
37
82
|
|
|
38
83
|
return Component ? <Component /> : spinner || null;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
resolveAuthSelection,
|
|
13
13
|
UserNotFoundError,
|
|
14
14
|
} from './auth/composable';
|
|
15
|
-
import { authReturnUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
|
|
15
|
+
import { authReturnUrl, centralAuthRedirectUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
|
|
16
16
|
import { getFirebaseAuth } from './auth/firebase';
|
|
17
17
|
import { useAuthState } from './auth/useAuthState';
|
|
18
18
|
import { UserSession, UserSessionContext } from './UserSession';
|
|
@@ -110,31 +110,29 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
|
|
|
110
110
|
return true;
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
-
const redirectToCentralAuth = (
|
|
114
|
-
const url =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
const redirectToCentralAuth = (selection: { accountId?: string; projectId?: string }) => {
|
|
114
|
+
const url = centralAuthRedirectUrl({
|
|
115
|
+
centralAuthUrl: CENTRAL_AUTH_REDIRECT,
|
|
116
|
+
stsEndpoint: Env.endpoints.sts ?? 'https://sts.vertesia.io',
|
|
117
|
+
returnUrl: authReturnUrl(),
|
|
118
|
+
state: generateState(),
|
|
119
|
+
...selection,
|
|
120
|
+
});
|
|
120
121
|
location.replace(url.toString());
|
|
121
122
|
};
|
|
122
123
|
|
|
123
124
|
authFlowRef.current = () => {
|
|
124
125
|
// Make this effect idempotent - only run auth flow once
|
|
125
126
|
if (hasInitiatedAuthRef.current) {
|
|
126
|
-
|
|
127
|
+
Env.logger.debug('Skipping duplicate auth flow initiation');
|
|
127
128
|
return;
|
|
128
129
|
}
|
|
129
130
|
hasInitiatedAuthRef.current = true;
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
Env.logger.info('Starting auth flow');
|
|
132
|
+
Env.logger.debug('Starting auth flow');
|
|
133
133
|
const currentUrl = new URL(window.location.href);
|
|
134
134
|
const { accountId: selectedAccount, projectId: selectedProject } = resolveAuthSelection(currentUrl);
|
|
135
|
-
|
|
136
|
-
console.log('Auth: selected project', selectedProject);
|
|
137
|
-
Env.logger.info('Selected account and project', {
|
|
135
|
+
Env.logger.debug('Selected account and project', {
|
|
138
136
|
vertesia: {
|
|
139
137
|
account_id: selectedAccount,
|
|
140
138
|
project_id: selectedProject,
|
|
@@ -174,7 +172,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
|
|
|
174
172
|
state: state,
|
|
175
173
|
},
|
|
176
174
|
});
|
|
177
|
-
redirectToCentralAuth();
|
|
175
|
+
redirectToCentralAuth({ accountId: selectedAccount, projectId: selectedProject });
|
|
178
176
|
} else {
|
|
179
177
|
clearState();
|
|
180
178
|
}
|
|
@@ -194,7 +192,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
|
|
|
194
192
|
error: err,
|
|
195
193
|
},
|
|
196
194
|
});
|
|
197
|
-
redirectToCentralAuth();
|
|
195
|
+
redirectToCentralAuth({ accountId: selectedAccount, projectId: selectedProject });
|
|
198
196
|
});
|
|
199
197
|
return;
|
|
200
198
|
}
|
|
@@ -207,31 +205,24 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
|
|
|
207
205
|
|
|
208
206
|
// If the current host is not in the Firebase allowlist, central auth owns sign-in.
|
|
209
207
|
if (!session.isLoggedIn()) {
|
|
210
|
-
|
|
211
|
-
Env.logger.info('Not logged in & no token/state', {
|
|
208
|
+
Env.logger.debug('Not logged in & no token/state', {
|
|
212
209
|
vertesia: {
|
|
213
210
|
account_id: selectedAccount,
|
|
214
211
|
project_id: selectedProject,
|
|
215
212
|
},
|
|
216
213
|
});
|
|
217
214
|
if (shouldRedirectToCentralAuth()) {
|
|
218
|
-
|
|
219
|
-
'Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection',
|
|
220
|
-
selectedAccount,
|
|
221
|
-
selectedProject,
|
|
222
|
-
);
|
|
223
|
-
Env.logger.info('Redirecting to central auth with selection', {
|
|
215
|
+
Env.logger.debug('Redirecting to central auth with selection', {
|
|
224
216
|
vertesia: {
|
|
225
217
|
account_id: selectedAccount,
|
|
226
218
|
project_id: selectedProject,
|
|
227
219
|
},
|
|
228
220
|
});
|
|
229
|
-
redirectToCentralAuth();
|
|
221
|
+
redirectToCentralAuth({ accountId: selectedAccount, projectId: selectedProject });
|
|
230
222
|
return; // Don't register onAuthStateChanged listener when redirecting
|
|
231
223
|
}
|
|
232
224
|
|
|
233
|
-
|
|
234
|
-
Env.logger.info('Host is in Firebase auth allowlist', {
|
|
225
|
+
Env.logger.debug('Host is in Firebase auth allowlist', {
|
|
235
226
|
vertesia: {
|
|
236
227
|
account_id: selectedAccount,
|
|
237
228
|
project_id: selectedProject,
|
|
@@ -241,8 +232,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
|
|
|
241
232
|
|
|
242
233
|
unsubscribe = onAuthStateChanged(getFirebaseAuth(), async (firebaseUser) => {
|
|
243
234
|
if (firebaseUser) {
|
|
244
|
-
|
|
245
|
-
Env.logger.info('Successful login with firebase', {
|
|
235
|
+
Env.logger.debug('Successful login with firebase', {
|
|
246
236
|
vertesia: {
|
|
247
237
|
account_id: selectedAccount,
|
|
248
238
|
project_id: selectedProject,
|
|
@@ -274,8 +264,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
|
|
|
274
264
|
});
|
|
275
265
|
} else {
|
|
276
266
|
// anonymous user
|
|
277
|
-
|
|
278
|
-
Env.logger.info('Using anonymous user', {
|
|
267
|
+
Env.logger.debug('Using anonymous user', {
|
|
279
268
|
vertesia: {
|
|
280
269
|
account_id: selectedAccount,
|
|
281
270
|
project_id: selectedProject,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
|
|
4
|
-
const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
4
|
+
const logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
5
5
|
|
|
6
6
|
vi.mock('@vertesia/ui/env', () => ({
|
|
7
7
|
Env: {
|
|
@@ -5,7 +5,7 @@ function makeJwt(payload: Record<string, unknown>) {
|
|
|
5
5
|
return `${encode({ alg: 'ES256', typ: 'JWT' })}.${encode(payload)}.signature`;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
async function importComposableAuth() {
|
|
8
|
+
async function importComposableAuth(authTokenProvider?: () => Promise<string | undefined>) {
|
|
9
9
|
vi.resetModules();
|
|
10
10
|
const [{ Env }, composableAuth] = await Promise.all([import('@vertesia/ui/env'), import('./composable')]);
|
|
11
11
|
Env.init({
|
|
@@ -19,6 +19,7 @@ async function importComposableAuth() {
|
|
|
19
19
|
zeno: 'https://zeno-server-dev-feat-appgen.api.dev1.vertesia.io',
|
|
20
20
|
sts: 'https://sts.dev1.vertesia.io',
|
|
21
21
|
},
|
|
22
|
+
authTokenProvider,
|
|
22
23
|
});
|
|
23
24
|
return composableAuth;
|
|
24
25
|
}
|
|
@@ -53,6 +54,65 @@ describe('getComposableToken', () => {
|
|
|
53
54
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
54
55
|
});
|
|
55
56
|
|
|
57
|
+
it('reacquires a fresh injected token instead of reusing an expired cached credential', async () => {
|
|
58
|
+
const expiredToken = makeJwt({
|
|
59
|
+
iss: 'https://sts.dev1.vertesia.io',
|
|
60
|
+
exp: Math.floor(Date.now() / 1000) - 60,
|
|
61
|
+
account: { id: 'account-id', name: 'Account' },
|
|
62
|
+
project: { id: 'project-id', name: 'Project', account: 'account-id' },
|
|
63
|
+
project_roles: ['developer'],
|
|
64
|
+
});
|
|
65
|
+
const freshToken = makeJwt({
|
|
66
|
+
iss: 'https://sts.dev1.vertesia.io',
|
|
67
|
+
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
68
|
+
account: { id: 'account-id', name: 'Account' },
|
|
69
|
+
project: { id: 'project-id', name: 'Project', account: 'account-id' },
|
|
70
|
+
project_roles: ['developer'],
|
|
71
|
+
});
|
|
72
|
+
const authTokenProvider = vi.fn(() => Promise.resolve(freshToken));
|
|
73
|
+
const fetchMock = vi.fn();
|
|
74
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
75
|
+
|
|
76
|
+
const { getComposableToken } = await importComposableAuth(authTokenProvider);
|
|
77
|
+
const result = await getComposableToken('account-id', 'project-id', expiredToken, false, true);
|
|
78
|
+
|
|
79
|
+
expect(result.rawToken).toBe(freshToken);
|
|
80
|
+
expect(authTokenProvider).toHaveBeenCalledOnce();
|
|
81
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('falls back to the cached credential when the injected provider is unavailable', async () => {
|
|
85
|
+
const expiringToken = makeJwt({
|
|
86
|
+
iss: 'https://sts.dev1.vertesia.io',
|
|
87
|
+
exp: Math.floor(Date.now() / 1000) + 60,
|
|
88
|
+
account: { id: 'account-id', name: 'Account' },
|
|
89
|
+
project: { id: 'project-id', name: 'Project', account: 'account-id' },
|
|
90
|
+
project_roles: ['developer'],
|
|
91
|
+
});
|
|
92
|
+
const refreshedToken = makeJwt({
|
|
93
|
+
iss: 'https://sts.dev1.vertesia.io',
|
|
94
|
+
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
95
|
+
account: { id: 'account-id', name: 'Account' },
|
|
96
|
+
project: { id: 'project-id', name: 'Project', account: 'account-id' },
|
|
97
|
+
project_roles: ['developer'],
|
|
98
|
+
});
|
|
99
|
+
const authTokenProvider = vi.fn(() => Promise.resolve(undefined));
|
|
100
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
101
|
+
ok: true,
|
|
102
|
+
status: 200,
|
|
103
|
+
json: () => Promise.resolve({ token: refreshedToken }),
|
|
104
|
+
});
|
|
105
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
106
|
+
|
|
107
|
+
const { getComposableToken } = await importComposableAuth(authTokenProvider);
|
|
108
|
+
const result = await getComposableToken('account-id', 'project-id', expiringToken, false, true);
|
|
109
|
+
|
|
110
|
+
expect(result.rawToken).toBe(refreshedToken);
|
|
111
|
+
expect(authTokenProvider).toHaveBeenCalledOnce();
|
|
112
|
+
expect(fetchMock).toHaveBeenCalledOnce();
|
|
113
|
+
expect(fetchMock.mock.calls[0]?.[1]?.headers).toMatchObject({ Authorization: `Bearer ${expiringToken}` });
|
|
114
|
+
});
|
|
115
|
+
|
|
56
116
|
it('exchanges a bare STS-issued Vertesia token so roles can be hydrated', async () => {
|
|
57
117
|
const sourceToken = makeJwt({
|
|
58
118
|
iss: 'https://sts.dev1.vertesia.io',
|