@vertesia/ui 1.5.0-dev.20260714.072725Z → 1.5.0-dev.20260722.120446Z
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/SidePanel.js +1 -1
- package/lib/core/components/SidePanel.js.map +1 -1
- package/lib/core/components/shadcn/button.d.ts +10 -3
- package/lib/core/components/shadcn/button.d.ts.map +1 -1
- package/lib/core/components/shadcn/button.js +41 -9
- package/lib/core/components/shadcn/button.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +1 -1
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeSwitcher.js +1 -1
- package/lib/core/components/shadcn/theme/ThemeSwitcher.js.map +1 -1
- package/lib/env/index.d.ts +19 -0
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +6 -0
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/chat/AgentChatPlaybackControls.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentChatPlaybackControls.js +2 -2
- package/lib/features/agent/chat/AgentChatPlaybackControls.js.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.js +2 -2
- package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +68 -11
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/ImageLightbox.d.ts.map +1 -1
- package/lib/features/agent/chat/ImageLightbox.js +1 -1
- package/lib/features/agent/chat/ImageLightbox.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +52 -49
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +5 -5
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.js +4 -2
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +15 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts +8 -1
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.js +28 -10
- package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +73 -0
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +1 -0
- package/lib/features/document-viewer/UniversalDocumentViewer.js +415 -0
- package/lib/features/document-viewer/UniversalDocumentViewer.js.map +1 -0
- package/lib/features/document-viewer/index.d.ts +2 -0
- package/lib/features/document-viewer/index.d.ts.map +1 -0
- package/lib/features/document-viewer/index.js +2 -0
- package/lib/features/document-viewer/index.js.map +1 -0
- package/lib/features/environment/SelectEnvironment.d.ts +28 -0
- package/lib/features/environment/SelectEnvironment.d.ts.map +1 -0
- package/lib/features/environment/SelectEnvironment.js +97 -0
- package/lib/features/environment/SelectEnvironment.js.map +1 -0
- package/lib/features/environment/index.d.ts +2 -0
- package/lib/features/environment/index.d.ts.map +1 -0
- package/lib/features/environment/index.js +2 -0
- package/lib/features/environment/index.js.map +1 -0
- package/lib/features/index.d.ts +3 -0
- package/lib/features/index.d.ts.map +1 -1
- package/lib/features/index.js +3 -0
- package/lib/features/index.js.map +1 -1
- package/lib/features/magic-pdf/AnnotatedImageSlider.js +12 -12
- package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
- package/lib/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
- package/lib/features/magic-pdf/DownloadPopover.js +3 -17
- package/lib/features/magic-pdf/DownloadPopover.js.map +1 -1
- package/lib/features/magic-pdf/ExtractedContentView.js +2 -6
- package/lib/features/magic-pdf/ExtractedContentView.js.map +1 -1
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts +25 -0
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts.map +1 -0
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js +42 -0
- package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js.map +1 -0
- package/lib/features/magic-pdf/GroundedExtractionView.d.ts +27 -0
- package/lib/features/magic-pdf/GroundedExtractionView.d.ts.map +1 -0
- package/lib/features/magic-pdf/GroundedExtractionView.js +377 -0
- package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -0
- package/lib/features/magic-pdf/MagicPdfProvider.d.ts +0 -2
- package/lib/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -1
- package/lib/features/magic-pdf/MagicPdfProvider.js +15 -42
- package/lib/features/magic-pdf/MagicPdfProvider.js.map +1 -1
- package/lib/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
- package/lib/features/magic-pdf/MagicPdfView.js +2 -19
- package/lib/features/magic-pdf/MagicPdfView.js.map +1 -1
- package/lib/features/magic-pdf/index.d.ts +1 -0
- package/lib/features/magic-pdf/index.d.ts.map +1 -1
- package/lib/features/magic-pdf/index.js +1 -0
- package/lib/features/magic-pdf/index.js.map +1 -1
- package/lib/features/magic-pdf/types.d.ts +1 -1
- package/lib/features/magic-pdf/types.d.ts.map +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.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
- package/lib/features/pdf-viewer/PdfPageSlider.js +2 -2
- package/lib/features/pdf-viewer/PdfPageSlider.js.map +1 -1
- package/lib/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -1
- package/lib/features/pdf-viewer/SimplePdfViewer.js +3 -3
- package/lib/features/pdf-viewer/SimplePdfViewer.js.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.d.ts +2 -3
- package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js +31 -38
- package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.js +5 -5
- package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.js +2 -2
- package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/features/store/objects/components/ContentDispositionButton.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentDispositionButton.js +1 -1
- package/lib/features/store/objects/components/ContentDispositionButton.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +148 -31
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/components/DocumentIcon.js +1 -1
- package/lib/features/store/objects/components/VectorSearchWidget.js +1 -1
- package/lib/features/store/objects/components/VectorSearchWidget.js.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts +1 -2
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.js +4 -8
- package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
- package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/features/store/objects/layout/renderers.js +2 -2
- package/lib/features/store/objects/layout/renderers.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/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +4 -4
- package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.d.ts +15 -0
- package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -0
- package/lib/features/store/types/IntakePolicyEditor.js +455 -0
- package/lib/features/store/types/IntakePolicyEditor.js.map +1 -0
- package/lib/features/store/types/IntakePolicyForm.d.ts +11 -0
- package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -0
- package/lib/features/store/types/IntakePolicyForm.js +91 -0
- package/lib/features/store/types/IntakePolicyForm.js.map +1 -0
- package/lib/features/store/types/SelectContentTypeModal.js +1 -1
- package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
- package/lib/features/store/types/index.d.ts +2 -0
- package/lib/features/store/types/index.d.ts.map +1 -1
- package/lib/features/store/types/index.js +2 -0
- package/lib/features/store/types/index.js.map +1 -1
- package/lib/features/store/types/intake-policy-editor.logic.d.ts +7 -0
- package/lib/features/store/types/intake-policy-editor.logic.d.ts.map +1 -0
- package/lib/features/store/types/intake-policy-editor.logic.js +60 -0
- package/lib/features/store/types/intake-policy-editor.logic.js.map +1 -0
- package/lib/features/store/types/typeCatalogCache.d.ts +5 -0
- package/lib/features/store/types/typeCatalogCache.d.ts.map +1 -0
- package/lib/features/store/types/typeCatalogCache.js +40 -0
- package/lib/features/store/types/typeCatalogCache.js.map +1 -0
- package/lib/features/user/UserInfo.js +7 -3
- package/lib/features/user/UserInfo.js.map +1 -1
- package/lib/features/views/ViewExperience.d.ts +20 -0
- package/lib/features/views/ViewExperience.d.ts.map +1 -0
- package/lib/features/views/ViewExperience.js +188 -0
- package/lib/features/views/ViewExperience.js.map +1 -0
- package/lib/features/views/ViewNavigation.d.ts +3 -0
- package/lib/features/views/ViewNavigation.d.ts.map +1 -0
- package/lib/features/views/ViewNavigation.js +36 -0
- package/lib/features/views/ViewNavigation.js.map +1 -0
- package/lib/features/views/ViewResults.d.ts +9 -0
- package/lib/features/views/ViewResults.d.ts.map +1 -0
- package/lib/features/views/ViewResults.js +229 -0
- package/lib/features/views/ViewResults.js.map +1 -0
- package/lib/features/views/ViewSearch.d.ts +3 -0
- package/lib/features/views/ViewSearch.d.ts.map +1 -0
- package/lib/features/views/ViewSearch.js +74 -0
- package/lib/features/views/ViewSearch.js.map +1 -0
- package/lib/features/views/index.d.ts +7 -0
- package/lib/features/views/index.d.ts.map +1 -0
- package/lib/features/views/index.js +7 -0
- package/lib/features/views/index.js.map +1 -0
- package/lib/features/views/types.d.ts +39 -0
- package/lib/features/views/types.d.ts.map +1 -0
- package/lib/features/views/types.js +2 -0
- package/lib/features/views/types.js.map +1 -0
- package/lib/features/views/viewState.d.ts +14 -0
- package/lib/features/views/viewState.d.ts.map +1 -0
- package/lib/features/views/viewState.js +117 -0
- package/lib/features/views/viewState.js.map +1 -0
- package/lib/i18n/locales/ar.json +18 -0
- package/lib/i18n/locales/de.json +14 -0
- package/lib/i18n/locales/en.json +246 -32
- package/lib/i18n/locales/es.json +15 -0
- package/lib/i18n/locales/fr.json +15 -0
- package/lib/i18n/locales/it.json +15 -0
- package/lib/i18n/locales/ja.json +13 -0
- package/lib/i18n/locales/ko.json +13 -0
- package/lib/i18n/locales/pt.json +15 -0
- package/lib/i18n/locales/ru.json +16 -0
- package/lib/i18n/locales/tr.json +14 -0
- package/lib/i18n/locales/zh-TW.json +13 -0
- package/lib/i18n/locales/zh.json +13 -0
- package/lib/router/HistoryNavigator.d.ts.map +1 -1
- package/lib/router/HistoryNavigator.js +27 -14
- package/lib/router/HistoryNavigator.js.map +1 -1
- package/lib/router/Nav.d.ts.map +1 -1
- package/lib/router/Nav.js +21 -6
- package/lib/router/Nav.js.map +1 -1
- package/lib/router/Router.d.ts.map +1 -1
- package/lib/router/Router.js +19 -4
- package/lib/router/Router.js.map +1 -1
- package/lib/router/path.d.ts +15 -0
- package/lib/router/path.d.ts.map +1 -1
- package/lib/router/path.js +43 -0
- package/lib/router/path.js.map +1 -1
- package/lib/session/UserSession.d.ts +6 -0
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +36 -12
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +111 -49
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +52 -3
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/session/auth/domainRouting.d.ts +25 -0
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +36 -0
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/shell/login/SignInRestrictedEnvStep.d.ts +1 -1
- package/lib/shell/login/SignInRestrictedEnvStep.js +1 -1
- package/lib/shell/login/SigninScreen.js +9 -1
- package/lib/shell/login/SigninScreen.js.map +1 -1
- package/lib/shell/login/productionUrl.d.ts +0 -14
- package/lib/shell/login/productionUrl.d.ts.map +1 -1
- package/lib/shell/login/productionUrl.js +14 -5
- package/lib/shell/login/productionUrl.js.map +1 -1
- package/lib/vertesia-ui-core.js +4 -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 +35 -28
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +15 -15
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-router.js +1 -1
- package/lib/vertesia-ui-router.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +1 -1
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +7 -7
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/form/Form.js +1 -1
- package/lib/widgets/form/Form.js.map +1 -1
- package/lib/widgets/json-view/JSONSwitcher.js +1 -1
- package/lib/widgets/json-view/JSONSwitcher.js.map +1 -1
- package/lib/widgets/json-view/JSONView.js +6 -6
- package/lib/widgets/json-view/JSONView.js.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.js +29 -0
- package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
- package/lib/widgets/schema-editor/ManagedSchema.d.ts +8 -0
- package/lib/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
- package/lib/widgets/schema-editor/ManagedSchema.js +16 -0
- package/lib/widgets/schema-editor/ManagedSchema.js.map +1 -1
- package/lib/widgets/schema-editor/editor/EditableSchemaProperty.d.ts +2 -0
- package/lib/widgets/schema-editor/editor/EditableSchemaProperty.d.ts.map +1 -1
- package/lib/widgets/schema-editor/editor/EditableSchemaProperty.js +1 -0
- package/lib/widgets/schema-editor/editor/EditableSchemaProperty.js.map +1 -1
- package/lib/widgets/schema-editor/editor/PropertyViewer.d.ts.map +1 -1
- package/lib/widgets/schema-editor/editor/PropertyViewer.js +4 -1
- package/lib/widgets/schema-editor/editor/PropertyViewer.js.map +1 -1
- package/lib/widgets/schema-editor/editor/SchemaEditor.d.ts.map +1 -1
- package/lib/widgets/schema-editor/editor/SchemaEditor.js +22 -11
- package/lib/widgets/schema-editor/editor/SchemaEditor.js.map +1 -1
- package/llms.txt +70 -70
- package/package.json +33 -32
- package/src/__tests__/a11y.test.tsx +73 -0
- package/src/core/components/SidePanel.tsx +1 -1
- package/src/core/components/shadcn/button.tsx +67 -12
- package/src/core/components/shadcn/modal/dialog.tsx +1 -1
- package/src/core/components/shadcn/theme/ThemeSwitcher.tsx +1 -1
- package/src/env/index.ts +24 -0
- package/src/features/agent/chat/AgentChatPlaybackControls.tsx +0 -5
- package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +31 -0
- package/src/features/agent/chat/AgentRequestInputOverlay.tsx +6 -2
- package/src/features/agent/chat/ArtifactsTab.tsx +165 -21
- package/src/features/agent/chat/ImageLightbox.tsx +0 -1
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +48 -0
- package/src/features/agent/chat/ModernAgentConversation.tsx +53 -51
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +6 -1
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +21 -15
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +3 -3
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +0 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +4 -1
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +80 -0
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +21 -1
- package/src/features/agent/chat/hooks/useArtifacts.ts +44 -11
- package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +123 -0
- package/src/features/document-viewer/UniversalDocumentViewer.tsx +746 -0
- package/src/features/document-viewer/index.ts +1 -0
- package/src/features/environment/SelectEnvironment.tsx +186 -0
- package/src/features/environment/index.ts +1 -0
- package/src/features/index.ts +3 -0
- package/src/features/magic-pdf/AnnotatedImageSlider.tsx +62 -66
- package/src/features/magic-pdf/DownloadPopover.tsx +5 -48
- package/src/features/magic-pdf/ExtractedContentView.tsx +2 -14
- package/src/features/magic-pdf/GroundedExtractionAssistantPanel.tsx +86 -0
- package/src/features/magic-pdf/GroundedExtractionView.test.tsx +65 -0
- package/src/features/magic-pdf/GroundedExtractionView.tsx +1055 -0
- package/src/features/magic-pdf/MagicPdfProvider.tsx +17 -47
- package/src/features/magic-pdf/MagicPdfView.tsx +3 -51
- package/src/features/magic-pdf/index.ts +1 -0
- package/src/features/magic-pdf/types.ts +1 -1
- package/src/features/oauth/McpConnectionsButton.tsx +0 -2
- package/src/features/oauth/McpConnectionsDialog.tsx +0 -1
- package/src/features/oauth/RemoteMcpConnectionButton.tsx +0 -1
- package/src/features/pdf-viewer/PdfPageSlider.tsx +5 -5
- package/src/features/pdf-viewer/SimplePdfViewer.tsx +11 -12
- package/src/features/permissions/UserPermissionsProvider.tsx +36 -39
- package/src/features/store/objects/DocumentQuickFilter.tsx +13 -15
- package/src/features/store/objects/DocumentSearchResults.tsx +3 -6
- package/src/features/store/objects/components/ContentDispositionButton.tsx +5 -1
- package/src/features/store/objects/components/ContentOverview.tsx +240 -67
- package/src/features/store/objects/components/DocumentIcon.tsx +1 -1
- package/src/features/store/objects/components/VectorSearchWidget.tsx +2 -2
- package/src/features/store/objects/components/useContentPanelHooks.ts +3 -15
- package/src/features/store/objects/layout/renderers.tsx +1 -2
- package/src/features/store/objects/selection/SelectionActions.tsx +1 -1
- package/src/features/store/types/ContentObjectTypesTable.tsx +12 -14
- package/src/features/store/types/IntakePolicyEditor.tsx +679 -0
- package/src/features/store/types/IntakePolicyForm.tsx +838 -0
- package/src/features/store/types/SelectContentTypeModal.tsx +2 -2
- package/src/features/store/types/index.ts +2 -0
- package/src/features/store/types/intake-policy-editor.logic.test.ts +109 -0
- package/src/features/store/types/intake-policy-editor.logic.ts +87 -0
- package/src/features/store/types/typeCatalogCache.ts +45 -0
- package/src/features/user/UserInfo.tsx +7 -7
- package/src/features/views/ViewExperience.test.tsx +273 -0
- package/src/features/views/ViewExperience.tsx +408 -0
- package/src/features/views/ViewNavigation.test.tsx +86 -0
- package/src/features/views/ViewNavigation.tsx +187 -0
- package/src/features/views/ViewResults.test.ts +82 -0
- package/src/features/views/ViewResults.tsx +609 -0
- package/src/features/views/ViewSearch.test.tsx +147 -0
- package/src/features/views/ViewSearch.tsx +205 -0
- package/src/features/views/index.ts +6 -0
- package/src/features/views/types.ts +57 -0
- package/src/features/views/viewState.test.ts +111 -0
- package/src/features/views/viewState.ts +132 -0
- package/src/i18n/locales/ar.json +18 -0
- package/src/i18n/locales/de.json +14 -0
- package/src/i18n/locales/en.json +965 -751
- package/src/i18n/locales/es.json +15 -0
- package/src/i18n/locales/fr.json +15 -0
- package/src/i18n/locales/it.json +15 -0
- package/src/i18n/locales/ja.json +13 -0
- package/src/i18n/locales/ko.json +13 -0
- package/src/i18n/locales/pt.json +15 -0
- package/src/i18n/locales/ru.json +16 -0
- package/src/i18n/locales/tr.json +14 -0
- package/src/i18n/locales/zh-TW.json +13 -0
- package/src/i18n/locales/zh.json +13 -0
- package/src/router/HistoryNavigator.test.ts +48 -0
- package/src/router/HistoryNavigator.ts +28 -14
- package/src/router/Nav.tsx +24 -8
- package/src/router/Router.tsx +18 -4
- package/src/router/path.test.ts +87 -0
- package/src/router/path.ts +38 -0
- package/src/session/UserSession.test.ts +39 -0
- package/src/session/UserSession.ts +37 -12
- package/src/session/UserSessionProvider.tsx +138 -62
- package/src/session/auth/composable.test.ts +111 -0
- package/src/session/auth/composable.ts +58 -3
- package/src/session/auth/domainRouting.test.ts +28 -1
- package/src/session/auth/domainRouting.ts +38 -0
- package/src/shell/login/SignInRestrictedEnvStep.tsx +1 -1
- package/src/shell/login/SigninScreen.tsx +9 -1
- package/src/shell/login/productionUrl.test.ts +8 -5
- package/src/shell/login/productionUrl.ts +15 -5
- package/src/widgets/form/Form.tsx +1 -1
- package/src/widgets/json-view/JSONSwitcher.tsx +2 -2
- package/src/widgets/json-view/JSONView.tsx +7 -7
- package/src/widgets/monacoEditor/MonacoEditor.tsx +29 -0
- package/src/widgets/schema-editor/ManagedSchema.ts +22 -0
- package/src/widgets/schema-editor/editor/EditableSchemaProperty.tsx +3 -0
- package/src/widgets/schema-editor/editor/PropertyViewer.tsx +14 -3
- package/src/widgets/schema-editor/editor/SchemaEditor.tsx +80 -29
|
@@ -17,6 +17,44 @@ interface ComposableTokenResponse {
|
|
|
17
17
|
message?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function normalizeIssuer(value: string | undefined): string | undefined {
|
|
21
|
+
return value?.replace(/\/+$/, '');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function decodeToken(token: string): AuthTokenPayload {
|
|
25
|
+
return jwtDecode(token) as AuthTokenPayload;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isVertesiaIssuedToken(token: string | undefined): token is string {
|
|
29
|
+
if (!token) return false;
|
|
30
|
+
try {
|
|
31
|
+
const decoded = decodeToken(token) as AuthTokenPayload & { iss?: string };
|
|
32
|
+
return normalizeIssuer(decoded.iss) === normalizeIssuer(Env.endpoints.sts);
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function canUseVertesiaTokenDirectly(token: string, accountId?: string, projectId?: string): boolean {
|
|
39
|
+
const decoded = decodeToken(token);
|
|
40
|
+
const hasAuthorizationClaims = Boolean(
|
|
41
|
+
decoded.permissions?.length ||
|
|
42
|
+
decoded.account_roles?.length ||
|
|
43
|
+
decoded.project_roles?.length ||
|
|
44
|
+
decoded.apps?.length,
|
|
45
|
+
);
|
|
46
|
+
if (!hasAuthorizationClaims) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (accountId && decoded.account?.id !== accountId) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (projectId && decoded.project?.id !== projectId) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
20
58
|
export async function fetchComposableToken(
|
|
21
59
|
getIdToken: () => Promise<string | null | undefined>,
|
|
22
60
|
accountId?: string,
|
|
@@ -319,23 +357,40 @@ export async function getComposableToken(
|
|
|
319
357
|
const selectedAccount = accountId ?? localStorage.getItem(LastSelectedAccountId_KEY) ?? undefined;
|
|
320
358
|
const selectedProject =
|
|
321
359
|
projectId ?? localStorage.getItem(`${LastSelectedProjectId_KEY}-${selectedAccount}`) ?? undefined;
|
|
360
|
+
const devAuthToken = Env.isLocalDev ? Env.devAuthToken : undefined;
|
|
361
|
+
const suppliedToken = devAuthToken ?? initToken ?? AUTH_TOKEN_RAW;
|
|
322
362
|
|
|
323
363
|
//token is still valid for more than 5 minutes
|
|
324
364
|
if (!forceRefresh && AUTH_TOKEN_RAW && AUTH_TOKEN && AUTH_TOKEN.exp > Date.now() / 1000 + 300) {
|
|
325
365
|
return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };
|
|
326
366
|
}
|
|
327
367
|
|
|
368
|
+
if (
|
|
369
|
+
!forceRefresh &&
|
|
370
|
+
isVertesiaIssuedToken(suppliedToken) &&
|
|
371
|
+
canUseVertesiaTokenDirectly(suppliedToken, selectedAccount, selectedProject)
|
|
372
|
+
) {
|
|
373
|
+
AUTH_TOKEN_RAW = suppliedToken;
|
|
374
|
+
AUTH_TOKEN = decodeToken(AUTH_TOKEN_RAW);
|
|
375
|
+
if (!AUTH_TOKEN.exp) {
|
|
376
|
+
throw new Error('Invalid composable token');
|
|
377
|
+
}
|
|
378
|
+
return { rawToken: AUTH_TOKEN_RAW, token: AUTH_TOKEN, error: false };
|
|
379
|
+
}
|
|
380
|
+
|
|
328
381
|
//token is close to expire, refresh it
|
|
329
|
-
if (!useInternalAuth && getFirebaseAuth().currentUser) {
|
|
382
|
+
if (!devAuthToken && !useInternalAuth && getFirebaseAuth().currentUser) {
|
|
330
383
|
//we have a firebase user, get the token from there
|
|
331
384
|
AUTH_TOKEN_RAW = await fetchComposableTokenFromFirebaseToken(selectedAccount, selectedProject);
|
|
332
|
-
} else if (initToken || AUTH_TOKEN_RAW) {
|
|
385
|
+
} else if (!devAuthToken && (initToken || AUTH_TOKEN_RAW)) {
|
|
333
386
|
// we have a token already and no firebase user, refresh it
|
|
334
387
|
AUTH_TOKEN_RAW = await fetchComposableToken(
|
|
335
388
|
() => Promise.resolve(initToken ?? AUTH_TOKEN_RAW),
|
|
336
389
|
selectedAccount,
|
|
337
390
|
selectedProject,
|
|
338
391
|
);
|
|
392
|
+
} else if (devAuthToken) {
|
|
393
|
+
AUTH_TOKEN_RAW = devAuthToken;
|
|
339
394
|
}
|
|
340
395
|
|
|
341
396
|
if (!AUTH_TOKEN_RAW) {
|
|
@@ -348,7 +403,7 @@ export async function getComposableToken(
|
|
|
348
403
|
throw new Error('Cannot acquire a composable token');
|
|
349
404
|
}
|
|
350
405
|
|
|
351
|
-
AUTH_TOKEN =
|
|
406
|
+
AUTH_TOKEN = decodeToken(AUTH_TOKEN_RAW);
|
|
352
407
|
|
|
353
408
|
if (!AUTH_TOKEN?.exp || !AUTH_TOKEN_RAW) {
|
|
354
409
|
console.error('Invalid composable token', AUTH_TOKEN);
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { shouldRedirectToCentralAuth, shouldUseFirebaseAuth } from './domainRouting';
|
|
2
|
+
import { mountRootUrl, shouldRedirectToCentralAuth, shouldUseFirebaseAuth } from './domainRouting';
|
|
3
|
+
|
|
4
|
+
// Stub document.baseURI to simulate the served `<base href>` (deep gateway mount) or its absence.
|
|
5
|
+
function setBaseURI(baseURI: string) {
|
|
6
|
+
(globalThis as { document?: unknown }).document = { baseURI };
|
|
7
|
+
}
|
|
3
8
|
|
|
4
9
|
describe('domainRouting', () => {
|
|
5
10
|
afterEach(() => {
|
|
6
11
|
delete (globalThis as { window?: unknown }).window;
|
|
12
|
+
delete (globalThis as { document?: unknown }).document;
|
|
7
13
|
});
|
|
8
14
|
|
|
9
15
|
it("uses Firebase auth when AUTH_MODE is 'firebase'", () => {
|
|
@@ -23,4 +29,25 @@ describe('domainRouting', () => {
|
|
|
23
29
|
expect(shouldUseFirebaseAuth()).toBe(false);
|
|
24
30
|
expect(shouldRedirectToCentralAuth()).toBe(true);
|
|
25
31
|
});
|
|
32
|
+
|
|
33
|
+
describe('mountRootUrl', () => {
|
|
34
|
+
it('returns the deep gateway mount root (dropping any deep route / query / hash)', () => {
|
|
35
|
+
const mount = 'https://gw.example.com/tenants/05948c_5ed5f4/apps/furniture-catalog/versions/v1/app/';
|
|
36
|
+
setBaseURI(mount);
|
|
37
|
+
expect(mountRootUrl().toString()).toBe(mount);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('strips an existing query and hash so callers control the reload target', () => {
|
|
41
|
+
setBaseURI('https://gw.example.com/tenants/t/apps/a/versions/v/app/');
|
|
42
|
+
const url = mountRootUrl();
|
|
43
|
+
url.searchParams.set('a', 'acct1');
|
|
44
|
+
url.searchParams.set('p', 'proj1');
|
|
45
|
+
expect(url.toString()).toBe('https://gw.example.com/tenants/t/apps/a/versions/v/app/?a=acct1&p=proj1');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('is the origin root for the Studio UI (no <base> element)', () => {
|
|
49
|
+
setBaseURI('https://studio.vertesia.io/');
|
|
50
|
+
expect(mountRootUrl().toString()).toBe('https://studio.vertesia.io/');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
26
53
|
});
|
|
@@ -11,3 +11,41 @@ export function shouldUseFirebaseAuth(_hostname?: string) {
|
|
|
11
11
|
export function shouldRedirectToCentralAuth(_hostname?: string) {
|
|
12
12
|
return !shouldUseFirebaseAuth();
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The page URL to return to after a central-auth round-trip (`redirect_uri`).
|
|
17
|
+
*
|
|
18
|
+
* Apps served under a deep gateway mount carry a `<base href="/tenants/<t>/apps/<app>/.../app/">`
|
|
19
|
+
* that the app-gateway injects at serve time. The in-app router rewrites the address bar relative
|
|
20
|
+
* to the origin rather than that mount, so by the time the auth flow runs `window.location` can
|
|
21
|
+
* read as the bare origin `/`. Building `redirect_uri` from that drops the app path, and the
|
|
22
|
+
* post-login token bounces back to a URL that serves no app.
|
|
23
|
+
*
|
|
24
|
+
* Prefer the live location when it still sits under the mount (preserves the in-app deep route);
|
|
25
|
+
* otherwise fall back to `document.baseURI` — the mount, which the router cannot clobber. With no
|
|
26
|
+
* `<base>` element (the Studio UI), `document.baseURI` is the document URL and its `pathname` is a
|
|
27
|
+
* prefix of the live location, so the live URL is used unchanged — no behavior change there.
|
|
28
|
+
*/
|
|
29
|
+
export function authReturnUrl(): URL {
|
|
30
|
+
const base = new URL(document.baseURI);
|
|
31
|
+
const current = new URL(window.location.href);
|
|
32
|
+
const target = current.pathname.startsWith(base.pathname) ? current : base;
|
|
33
|
+
target.hash = '';
|
|
34
|
+
return target;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The app's mount root URL — the served `<base href>` (or the origin root for the Studio UI).
|
|
39
|
+
*
|
|
40
|
+
* Used for full-reload navigations that intentionally reset to the app root (logout, account /
|
|
41
|
+
* project switch). Building these from a bare `/` drops a gateway-mounted app off its mount and
|
|
42
|
+
* lands on a URL that serves no app; resolving against `document.baseURI` keeps the reload inside
|
|
43
|
+
* the mount. For the Studio UI (no `<base>` element) `document.baseURI` is the origin root, so the
|
|
44
|
+
* behavior is unchanged.
|
|
45
|
+
*/
|
|
46
|
+
export function mountRootUrl(): URL {
|
|
47
|
+
const url = new URL(document.baseURI);
|
|
48
|
+
url.hash = '';
|
|
49
|
+
url.search = '';
|
|
50
|
+
return url;
|
|
51
|
+
}
|
|
@@ -15,7 +15,7 @@ interface SignInRestrictedEnvStepProps {
|
|
|
15
15
|
const AUTO_REDIRECT_SECONDS = 15;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Shown when the STS rejects sign-in because the current environment (
|
|
18
|
+
* Shown when the STS rejects sign-in because the current environment (any non-production tier) is
|
|
19
19
|
* restricted to early-access users. Offers a redirect to the production web application — in the
|
|
20
20
|
* user's own region — and a way to sign in with a different account. If the user takes no action, it
|
|
21
21
|
* redirects automatically after {@link AUTO_REDIRECT_SECONDS}. See
|
|
@@ -89,7 +89,15 @@ function SigninScreenImpl({
|
|
|
89
89
|
|
|
90
90
|
useEffect(() => {
|
|
91
91
|
if (!preservePath) {
|
|
92
|
-
|
|
92
|
+
// Reset to the app's mount root, not the bare origin. A gateway-mounted app carries a
|
|
93
|
+
// served `<base href>` deep mount; collapsing to '/' drops the app off that mount (the
|
|
94
|
+
// bare origin serves no app) and the address bar can no longer be reloaded. This effect
|
|
95
|
+
// also flashes briefly for already-authenticated users during the loading transition, so
|
|
96
|
+
// a bare '/' here loses the URL even on a normal login. Deriving the root from
|
|
97
|
+
// `document.baseURI` keeps it inside the mount; for the origin-served Studio UI the
|
|
98
|
+
// pathname is '/', so the behavior is unchanged.
|
|
99
|
+
const mountRoot = new URL(document.baseURI).pathname || '/';
|
|
100
|
+
history.replaceState({}, '', mountRoot);
|
|
93
101
|
}
|
|
94
102
|
}, [preservePath]);
|
|
95
103
|
|
|
@@ -2,17 +2,20 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { getProductionAppUrl } from './productionUrl.js';
|
|
3
3
|
|
|
4
4
|
describe('getProductionAppUrl', () => {
|
|
5
|
-
it('sends
|
|
5
|
+
it('sends every production region to its regional site (one cloud.{region} pattern)', () => {
|
|
6
|
+
// us1 is not special-cased — it uses the same regional pattern as every other region.
|
|
7
|
+
expect(getProductionAppUrl('us1')).toBe('https://cloud.us1.vertesia.io/');
|
|
8
|
+
expect(getProductionAppUrl('us2')).toBe('https://cloud.us2.vertesia.io/');
|
|
6
9
|
expect(getProductionAppUrl('eu1')).toBe('https://cloud.eu1.vertesia.io/');
|
|
7
10
|
expect(getProductionAppUrl('jp1')).toBe('https://cloud.jp1.vertesia.io/');
|
|
8
11
|
});
|
|
9
12
|
|
|
10
|
-
it('sends
|
|
11
|
-
|
|
12
|
-
expect(getProductionAppUrl('
|
|
13
|
+
it('sends a dev region to the production region it mirrors, not the dev host', () => {
|
|
14
|
+
// dev1 mirrors us1: a rejected user must land on production, never back on cloud.dev1.
|
|
15
|
+
expect(getProductionAppUrl('dev1')).toBe('https://cloud.us1.vertesia.io/');
|
|
13
16
|
});
|
|
14
17
|
|
|
15
|
-
it('falls back to the canonical
|
|
18
|
+
it('falls back to the canonical non-regional site when the region is unknown', () => {
|
|
16
19
|
expect(getProductionAppUrl(undefined)).toBe('https://cloud.vertesia.io/');
|
|
17
20
|
expect(getProductionAppUrl('')).toBe('https://cloud.vertesia.io/');
|
|
18
21
|
});
|
|
@@ -4,15 +4,25 @@
|
|
|
4
4
|
* they do have access — in their own region, never another one (an EU user must not land on the US
|
|
5
5
|
* site, and vice versa).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Every production region follows one URL pattern — `https://cloud.{region}.vertesia.io/` (e.g.
|
|
8
|
+
* `us1`, `us2`, `eu1`, `jp1`) — with no region special-cased. Only the legacy non-regional
|
|
9
|
+
* deployment has no region and falls back to the apex `https://cloud.vertesia.io/`.
|
|
10
|
+
*
|
|
11
|
+
* Dev/ephemeral regions have no production site of their own — they mirror a production region — so
|
|
12
|
+
* they are mapped to it first. Sending a rejected user to the dev host (e.g. `cloud.dev1.vertesia.io`)
|
|
13
|
+
* would just bounce them back to the same restricted environment. `dev1` (us-central1) mirrors the
|
|
14
|
+
* `us1` production region.
|
|
10
15
|
*
|
|
11
16
|
* Region is preferred over parsing the current hostname because it is well-defined for every serving
|
|
12
17
|
* pattern (including the direct-routing `*.ui.{region}.vertesia.io` hosts, which carry no
|
|
13
18
|
* `preview.`/`preprod.` prefix to strip). Callers pass `Env.region` from `@vertesia/ui/env`.
|
|
14
19
|
*/
|
|
20
|
+
const DEV_REGION_TO_PRODUCTION_REGION: Record<string, string> = {
|
|
21
|
+
// dev1 (us-central1) is a dev mirror of the us1 production region.
|
|
22
|
+
dev1: 'us1',
|
|
23
|
+
};
|
|
24
|
+
|
|
15
25
|
export function getProductionAppUrl(region?: string): string {
|
|
16
|
-
const
|
|
17
|
-
return
|
|
26
|
+
const prodRegion = (region && DEV_REGION_TO_PRODUCTION_REGION[region]) || region;
|
|
27
|
+
return prodRegion ? `https://cloud.${prodRegion}.vertesia.io/` : 'https://cloud.vertesia.io/';
|
|
18
28
|
}
|
|
@@ -184,7 +184,7 @@ function ListItem({ list, object, onDelete, disabled }: ListItemProps) {
|
|
|
184
184
|
return (
|
|
185
185
|
<div className="flex gap-2 w-full">
|
|
186
186
|
<div className="flex-1">{renderItemProperty(object, editor)}</div>
|
|
187
|
-
<Button variant="ghost" onClick={onDelete} disabled={disabled}
|
|
187
|
+
<Button variant="ghost" onClick={onDelete} disabled={disabled} title="Delete">
|
|
188
188
|
<Trash2 className="size-4 text-destructive" />
|
|
189
189
|
</Button>
|
|
190
190
|
</div>
|
|
@@ -14,7 +14,7 @@ export function JSONSwitcher({
|
|
|
14
14
|
<Button
|
|
15
15
|
variant={viewCode ? 'ghost' : 'primary'}
|
|
16
16
|
size="sm"
|
|
17
|
-
|
|
17
|
+
title="Preview properties"
|
|
18
18
|
onClick={() => setViewCode(false)}
|
|
19
19
|
>
|
|
20
20
|
{title}
|
|
@@ -22,7 +22,7 @@ export function JSONSwitcher({
|
|
|
22
22
|
<Button
|
|
23
23
|
variant={viewCode ? 'primary' : 'ghost'}
|
|
24
24
|
size="sm"
|
|
25
|
-
|
|
25
|
+
title="View in JSON format"
|
|
26
26
|
onClick={() => setViewCode(true)}
|
|
27
27
|
>
|
|
28
28
|
JSON
|
|
@@ -35,7 +35,7 @@ interface PropertyTitleProps {
|
|
|
35
35
|
name: string;
|
|
36
36
|
}
|
|
37
37
|
function PropertyTitle({ name }: PropertyTitleProps) {
|
|
38
|
-
return <div className="text-
|
|
38
|
+
return <div className="text-sm font-semibold">{computeTitleFromName(name)}</div>;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
interface BlockElementProps {
|
|
@@ -64,14 +64,14 @@ function PropertyElement({ name, value }: PropertyElementProps) {
|
|
|
64
64
|
switch (info.type) {
|
|
65
65
|
case ValueType.Inline:
|
|
66
66
|
return (
|
|
67
|
-
<div className="w-full flex gap-2">
|
|
67
|
+
<div className="w-full flex gap-2 text-sm">
|
|
68
68
|
<PropertyTitle name={`${name}:`} />
|
|
69
69
|
<p>{info.value}</p>
|
|
70
70
|
</div>
|
|
71
71
|
);
|
|
72
72
|
case ValueType.Paragraph:
|
|
73
73
|
return (
|
|
74
|
-
<div>
|
|
74
|
+
<div className="w-full flex flex-col gap-2 text-sm">
|
|
75
75
|
<PropertyTitle name={name} />
|
|
76
76
|
<p>{info.value}</p>
|
|
77
77
|
</div>
|
|
@@ -80,14 +80,14 @@ function PropertyElement({ name, value }: PropertyElementProps) {
|
|
|
80
80
|
return (
|
|
81
81
|
<div className="prose dark:prose-invert">
|
|
82
82
|
<PropertyTitle name={name} />
|
|
83
|
-
<div className="vprose dark:prose-invert">{info.value}</div>
|
|
83
|
+
<div className="vprose prose-sm dark:prose-invert">{info.value}</div>
|
|
84
84
|
</div>
|
|
85
85
|
);
|
|
86
86
|
case ValueType.Array:
|
|
87
87
|
return <ArrayProperty name={name} value={value as JSONArray} />;
|
|
88
88
|
case ValueType.Object:
|
|
89
89
|
return (
|
|
90
|
-
<div>
|
|
90
|
+
<div className="w-full flex flex-col gap-2 text-sm">
|
|
91
91
|
<PropertyTitle name={name} />
|
|
92
92
|
<BlockElement className="mt-2">
|
|
93
93
|
{Object.entries(value as JSONObject).map(([key, value]) => (
|
|
@@ -164,8 +164,8 @@ function ItemProperty({ index, value, useBullet }: ItemPropertyProps) {
|
|
|
164
164
|
break;
|
|
165
165
|
}
|
|
166
166
|
return (
|
|
167
|
-
<div className="flex gap-4 hover:bg-
|
|
168
|
-
<div className="font-semibold text-
|
|
167
|
+
<div className="flex gap-4 hover:bg-muted py-2 pe-2 ps-4">
|
|
168
|
+
<div className="font-semibold text-muted">{bullet}</div>
|
|
169
169
|
<div>{content}</div>
|
|
170
170
|
</div>
|
|
171
171
|
);
|
|
@@ -8,6 +8,33 @@ import { registerCustomFoldingProviders } from './foldingProviders.js';
|
|
|
8
8
|
|
|
9
9
|
export type Monaco = typeof monaco;
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Shared, body-level host for Monaco "overflow widgets" — the suggestion, hover, and
|
|
13
|
+
* parameter-hint popups. With `fixedOverflowWidgets` enabled these are `position: fixed`; a CSS
|
|
14
|
+
* `transform` on any ancestor (e.g. a modal centered with `translate(-50%, -50%)`) becomes their
|
|
15
|
+
* containing block and drags the popups away from the cursor, sometimes off-screen. Hosting them in
|
|
16
|
+
* an untransformed node appended to `document.body` keeps them anchored to the caret. The node
|
|
17
|
+
* carries the `monaco-editor` class so Monaco's (global) theme styles apply, and a high z-index so
|
|
18
|
+
* the popups render above modals/overlays. One shared node is reused by every editor instance.
|
|
19
|
+
*/
|
|
20
|
+
let overflowWidgetsNode: HTMLElement | undefined;
|
|
21
|
+
function getOverflowWidgetsNode(): HTMLElement | undefined {
|
|
22
|
+
if (typeof document === 'undefined') return undefined;
|
|
23
|
+
if (!overflowWidgetsNode) {
|
|
24
|
+
const node = document.createElement('div');
|
|
25
|
+
node.className = 'monaco-editor';
|
|
26
|
+
// `absolute` + z-index establishes a stacking context above modals without creating a
|
|
27
|
+
// containing block for the fixed-positioned popups (only transform/filter/etc. would).
|
|
28
|
+
node.style.position = 'absolute';
|
|
29
|
+
node.style.top = '0';
|
|
30
|
+
node.style.left = '0';
|
|
31
|
+
node.style.zIndex = '10000';
|
|
32
|
+
document.body.appendChild(node);
|
|
33
|
+
overflowWidgetsNode = node;
|
|
34
|
+
}
|
|
35
|
+
return overflowWidgetsNode;
|
|
36
|
+
}
|
|
37
|
+
|
|
11
38
|
export interface IEditorApi {
|
|
12
39
|
getValue(): string;
|
|
13
40
|
setValue(value?: string): void;
|
|
@@ -226,6 +253,8 @@ export function MonacoEditor({
|
|
|
226
253
|
tabSize: 2,
|
|
227
254
|
insertSpaces: true,
|
|
228
255
|
fixedOverflowWidgets: true, // Hover/diagnostic popovers float outside the editor bounds
|
|
256
|
+
// Host the fixed popups in a body-level node so a modal's CSS transform doesn't offset them.
|
|
257
|
+
overflowWidgetsDomNode: getOverflowWidgetsNode(),
|
|
229
258
|
glyphMargin: true, // Enable better error reporting
|
|
230
259
|
renderValidationDecorations: 'on', // Show error squiggles
|
|
231
260
|
renderLineHighlight: 'line', // Highlight entire line for errors
|
|
@@ -17,6 +17,11 @@ export interface NodeUpdate {
|
|
|
17
17
|
isRequired?: boolean;
|
|
18
18
|
editor?: string | null; // use null to force remove editor
|
|
19
19
|
description?: string;
|
|
20
|
+
/**
|
|
21
|
+
* When false, the property is marked `"x-extract": false` and is omitted from
|
|
22
|
+
* extraction result_schema. Default / true = extractable.
|
|
23
|
+
*/
|
|
24
|
+
extractable?: boolean;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
interface SchemaLoader {
|
|
@@ -141,6 +146,19 @@ export class SchemaNode {
|
|
|
141
146
|
this.schema.description = value;
|
|
142
147
|
}
|
|
143
148
|
|
|
149
|
+
/** Whether extraction models may fill this field. Default true. */
|
|
150
|
+
get extractable(): boolean {
|
|
151
|
+
return (this.schema as Record<string, unknown>)['x-extract'] !== false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
set extractable(value: boolean) {
|
|
155
|
+
if (value) {
|
|
156
|
+
delete (this.schema as Record<string, unknown>)['x-extract'];
|
|
157
|
+
} else {
|
|
158
|
+
(this.schema as Record<string, unknown>)['x-extract'] = false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
144
162
|
get isParent() {
|
|
145
163
|
return this.type.isObject;
|
|
146
164
|
}
|
|
@@ -300,6 +318,10 @@ export class SchemaNode {
|
|
|
300
318
|
this.description = data.description;
|
|
301
319
|
updated = true;
|
|
302
320
|
}
|
|
321
|
+
if (data.extractable != null && this.extractable !== data.extractable) {
|
|
322
|
+
this.extractable = data.extractable;
|
|
323
|
+
updated = true;
|
|
324
|
+
}
|
|
303
325
|
|
|
304
326
|
return updated;
|
|
305
327
|
}
|
|
@@ -4,6 +4,8 @@ export interface EditableSchemaProperty {
|
|
|
4
4
|
name: string;
|
|
5
5
|
type: string;
|
|
6
6
|
description?: string;
|
|
7
|
+
/** When false, field is excluded from model extraction (`x-extract: false`). Default true. */
|
|
8
|
+
extractable?: boolean;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
export function getEditableSchemaProperty(schema: SchemaNode): EditableSchemaProperty {
|
|
@@ -11,5 +13,6 @@ export function getEditableSchemaProperty(schema: SchemaNode): EditableSchemaPro
|
|
|
11
13
|
name: schema.getNameSignature(),
|
|
12
14
|
type: schema.getTypeSignature(),
|
|
13
15
|
description: schema.description,
|
|
16
|
+
extractable: schema.extractable,
|
|
14
17
|
};
|
|
15
18
|
}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
1
2
|
import type { DataViewerProps } from './Editable.js';
|
|
2
3
|
import type { EditableSchemaProperty } from './EditableSchemaProperty.js';
|
|
3
4
|
|
|
4
5
|
export function PropertyViewer({ value }: DataViewerProps<EditableSchemaProperty>) {
|
|
6
|
+
const { t } = useUITranslation();
|
|
5
7
|
if (!value) return null;
|
|
8
|
+
const noExtract = value.extractable === false;
|
|
6
9
|
return (
|
|
7
|
-
<div className="w-full flex items-baseline">
|
|
8
|
-
<div>{value.name || ''}</div>
|
|
9
|
-
<div className="
|
|
10
|
+
<div className="w-full flex items-baseline gap-2 min-w-0">
|
|
11
|
+
<div className="truncate">{value.name || ''}</div>
|
|
12
|
+
<div className="text-sm text-muted shrink-0">{value.type || ''}</div>
|
|
13
|
+
{noExtract && (
|
|
14
|
+
<span
|
|
15
|
+
className="shrink-0 text-[10px] uppercase tracking-wide text-attention border border-attention/40 bg-attention/10 rounded px-1.5 py-0.5"
|
|
16
|
+
title={t('widgets.schema.extractFromDocumentHint')}
|
|
17
|
+
>
|
|
18
|
+
{t('widgets.schema.noExtract')}
|
|
19
|
+
</span>
|
|
20
|
+
)}
|
|
10
21
|
</div>
|
|
11
22
|
);
|
|
12
23
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button, errorMessage, useToast } from '@vertesia/ui/core';
|
|
1
|
+
import { Button, errorMessage, Switch, useToast } from '@vertesia/ui/core';
|
|
2
2
|
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
3
3
|
import { ChevronDown, ChevronRight, Plus } from 'lucide-react';
|
|
4
4
|
import { useState } from 'react';
|
|
@@ -20,13 +20,26 @@ interface SchemaTreeProps {
|
|
|
20
20
|
readonly?: boolean;
|
|
21
21
|
}
|
|
22
22
|
export function SchemaEditor({ schema, readonly = false }: SchemaTreeProps) {
|
|
23
|
+
const { t } = useUITranslation();
|
|
23
24
|
return (
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
<div className="space-y-1">
|
|
26
|
+
<div className="flex items-center gap-2 px-2 py-1 text-xs font-medium text-muted-foreground border-b border-border">
|
|
27
|
+
<div className="flex-1 min-w-0">{t('widgets.schema.propertyColumn')}</div>
|
|
28
|
+
{!readonly && (
|
|
29
|
+
<div className="shrink-0 w-28 text-end pe-1" title={t('widgets.schema.extractFromDocumentHint')}>
|
|
30
|
+
{t('widgets.schema.extractFromDocument')}
|
|
31
|
+
</div>
|
|
32
|
+
)}
|
|
33
|
+
{/* space for expand/collapse on parent rows */}
|
|
34
|
+
<div className="w-8 shrink-0" />
|
|
35
|
+
</div>
|
|
36
|
+
<ul className="">
|
|
37
|
+
{schema.children.map((prop) => {
|
|
38
|
+
return renderProperty(prop, readonly);
|
|
39
|
+
})}
|
|
40
|
+
{!readonly ? <AddPropertyButton parent={schema.root} /> : null}
|
|
41
|
+
</ul>
|
|
42
|
+
</div>
|
|
30
43
|
);
|
|
31
44
|
}
|
|
32
45
|
|
|
@@ -44,7 +57,7 @@ interface SimpleItemProps {
|
|
|
44
57
|
}
|
|
45
58
|
function SimpleItem({ node, readonly }: SimpleItemProps) {
|
|
46
59
|
return (
|
|
47
|
-
<li>
|
|
60
|
+
<li className="border-b border-border/40 last:border-0">
|
|
48
61
|
<PropertyTitleBar property={node} readonly={readonly} />
|
|
49
62
|
</li>
|
|
50
63
|
);
|
|
@@ -59,20 +72,21 @@ function ParentItem({ property, readonly }: ParentItemProps) {
|
|
|
59
72
|
const Icon = isOpen ? ChevronDown : ChevronRight;
|
|
60
73
|
|
|
61
74
|
return (
|
|
62
|
-
<li>
|
|
63
|
-
<div className="flex items-center w-full">
|
|
75
|
+
<li className="border-b border-border/40 last:border-0">
|
|
76
|
+
<div className="flex items-center w-full gap-1">
|
|
77
|
+
<div className="flex-1 min-w-0">
|
|
78
|
+
<PropertyTitleBar property={property} readonly={readonly} />
|
|
79
|
+
</div>
|
|
64
80
|
<Button
|
|
65
81
|
variant="ghost"
|
|
66
82
|
size="icon"
|
|
67
83
|
onClick={() => setOpen(!isOpen)}
|
|
68
84
|
aria-label={isOpen ? `Collapse ${property.name}` : `Expand ${property.name}`}
|
|
69
85
|
aria-expanded={isOpen}
|
|
86
|
+
className="shrink-0"
|
|
70
87
|
>
|
|
71
88
|
<Icon className="size-4 cn-rtl-flip" />
|
|
72
89
|
</Button>
|
|
73
|
-
<div className="flex-1">
|
|
74
|
-
<PropertyTitleBar property={property} readonly={readonly} />
|
|
75
|
-
</div>
|
|
76
90
|
</div>
|
|
77
91
|
{isOpen && (
|
|
78
92
|
<ul className="ms-4 border-s border-gray-400 border-dashed">
|
|
@@ -110,7 +124,13 @@ function PropertyTitleBar({ property, readonly }: PropertyTitleBarProps) {
|
|
|
110
124
|
|
|
111
125
|
const update = property.getUpdateFromNameAndTypeSignature(value.name, value.type);
|
|
112
126
|
|
|
113
|
-
if (
|
|
127
|
+
if (
|
|
128
|
+
property.update({
|
|
129
|
+
...update,
|
|
130
|
+
description: value.description,
|
|
131
|
+
extractable: value.extractable,
|
|
132
|
+
})
|
|
133
|
+
) {
|
|
114
134
|
property.reloadTree();
|
|
115
135
|
}
|
|
116
136
|
} catch (err: unknown) {
|
|
@@ -124,25 +144,56 @@ function PropertyTitleBar({ property, readonly }: PropertyTitleBarProps) {
|
|
|
124
144
|
}
|
|
125
145
|
return true;
|
|
126
146
|
};
|
|
147
|
+
|
|
148
|
+
/** Toggle extractability without entering name/type edit mode. */
|
|
149
|
+
const onExtractableChange = (extractable: boolean) => {
|
|
150
|
+
if (property.update({ extractable })) {
|
|
151
|
+
property.reloadTree();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
127
155
|
const isNew = property.resetIsNew();
|
|
128
156
|
const editableProp = getEditableSchemaProperty(property);
|
|
129
157
|
|
|
130
158
|
return (
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
159
|
+
<div className="flex items-center gap-2 w-full min-w-0 py-0.5">
|
|
160
|
+
<div className="flex-1 min-w-0">
|
|
161
|
+
<Editable
|
|
162
|
+
value={editableProp}
|
|
163
|
+
onChange={onChange}
|
|
164
|
+
onDelete={() => {
|
|
165
|
+
property.remove();
|
|
166
|
+
property.reloadTree();
|
|
167
|
+
}}
|
|
168
|
+
editor={PropertyEditor}
|
|
169
|
+
viewer={PropertyViewer}
|
|
170
|
+
outlineOnHover
|
|
171
|
+
isEditing={isNew}
|
|
172
|
+
skipClickOutside={skipClickOutside}
|
|
173
|
+
readonly={readonly}
|
|
174
|
+
onValidate={(prop) => validatePropertyName(prop.name)}
|
|
175
|
+
/>
|
|
176
|
+
</div>
|
|
177
|
+
{!readonly ? (
|
|
178
|
+
<div className="shrink-0 w-28 flex items-center justify-end gap-1.5 pe-1">
|
|
179
|
+
<Switch
|
|
180
|
+
size="sm"
|
|
181
|
+
value={property.extractable}
|
|
182
|
+
onChange={onExtractableChange}
|
|
183
|
+
aria-label={`${t('widgets.schema.extractFromDocument')}: ${property.name}`}
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
) : property.extractable === false ? (
|
|
187
|
+
<div className="shrink-0 w-28 flex justify-end pe-1">
|
|
188
|
+
<span
|
|
189
|
+
className="text-[10px] uppercase tracking-wide text-attention border border-attention/40 bg-attention/10 rounded px-1.5 py-0.5"
|
|
190
|
+
title={t('widgets.schema.extractFromDocumentHint')}
|
|
191
|
+
>
|
|
192
|
+
{t('widgets.schema.noExtract')}
|
|
193
|
+
</span>
|
|
194
|
+
</div>
|
|
195
|
+
) : null}
|
|
196
|
+
</div>
|
|
146
197
|
);
|
|
147
198
|
}
|
|
148
199
|
|