@vertesia/ui 1.4.0-dev.20260615.042549Z → 1.4.0-dev.20260629.130134Z
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/shadcn/dropdown.d.ts.map +1 -1
- package/lib/core/components/shadcn/dropdown.js +6 -2
- package/lib/core/components/shadcn/dropdown.js.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js +9 -2
- package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.d.ts +16 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.js +25 -3
- package/lib/core/components/shadcn/modal/ConfirmModal.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/popover.d.ts.map +1 -1
- package/lib/core/components/shadcn/popover.js +3 -1
- package/lib/core/components/shadcn/popover.js.map +1 -1
- package/lib/core/components/shadcn/switch.js +3 -3
- package/lib/core/components/shadcn/switch.js.map +1 -1
- package/lib/core/components/shadcn/tabs.js +1 -1
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/core/components/shadcn/tooltip.d.ts.map +1 -1
- package/lib/core/components/shadcn/tooltip.js +3 -1
- package/lib/core/components/shadcn/tooltip.js.map +1 -1
- package/lib/env/index.d.ts +0 -19
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +0 -6
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/PayloadBuilder.d.ts +4 -0
- package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/features/agent/PayloadBuilder.js +16 -0
- package/lib/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts +10 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts.map +1 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.js +50 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.js.map +1 -0
- package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts +2 -1
- package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentChatFixtureReplay.js +3 -3
- package/lib/features/agent/chat/AgentChatFixtureReplay.js.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +5 -2
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.js +41 -7
- package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +133 -12
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/AnimatedThinkingDots.js +1 -1
- package/lib/features/agent/chat/AnimatedThinkingDots.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +11 -65
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts +3 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +4 -3
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +10 -2
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +526 -117
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +8 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +19 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +8 -2
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +551 -92
- 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 +7 -6
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts +8 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js +61 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +15 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +28 -38
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts +5 -0
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +59 -4
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +180 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.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 +92 -2
- package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
- package/lib/features/agent/chat/clipboardFiles.d.ts +15 -0
- package/lib/features/agent/chat/clipboardFiles.d.ts.map +1 -0
- package/lib/features/agent/chat/clipboardFiles.js +35 -0
- package/lib/features/agent/chat/clipboardFiles.js.map +1 -0
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts +6 -0
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +218 -37
- package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts +1 -8
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.js +10 -28
- package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
- package/lib/features/agent/chat/index.d.ts +2 -1
- package/lib/features/agent/chat/index.d.ts.map +1 -1
- package/lib/features/agent/chat/index.js +2 -1
- package/lib/features/agent/chat/index.js.map +1 -1
- package/lib/features/agent/chat/workstreams.d.ts +1 -0
- package/lib/features/agent/chat/workstreams.d.ts.map +1 -1
- package/lib/features/agent/chat/workstreams.js +28 -0
- package/lib/features/agent/chat/workstreams.js.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts +10 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.js +6 -3
- package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts +10 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.js +14 -5
- package/lib/features/facets/CollectionsFacetsNav.js.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts +10 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.js +14 -5
- package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
- package/lib/features/facets/RunsFacetsNav.d.ts +10 -1
- package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/RunsFacetsNav.js +14 -5
- package/lib/features/facets/RunsFacetsNav.js.map +1 -1
- package/lib/features/index.d.ts +0 -1
- package/lib/features/index.d.ts.map +1 -1
- package/lib/features/index.js +0 -1
- package/lib/features/index.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +30 -0
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -0
- package/lib/features/oauth/McpConnectionsButton.js +70 -0
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -0
- package/lib/features/oauth/McpConnectionsDialog.d.ts +25 -0
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -0
- package/lib/features/oauth/McpConnectionsDialog.js +26 -0
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -0
- package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js +14 -6
- package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
- package/lib/features/oauth/index.d.ts +3 -0
- package/lib/features/oauth/index.d.ts.map +1 -1
- package/lib/features/oauth/index.js +3 -0
- package/lib/features/oauth/index.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +44 -0
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -0
- package/lib/features/oauth/useMcpConnections.js +168 -0
- package/lib/features/oauth/useMcpConnections.js.map +1 -0
- package/lib/features/permissions/UserPermissionsProvider.d.ts +4 -6
- package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js +40 -42
- package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js +2 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.d.ts +23 -0
- package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -0
- package/lib/features/store/objects/DocumentQuickFilter.js +30 -0
- package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -0
- package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.js +17 -1
- package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +17 -74
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.d.ts +7 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.d.ts.map +1 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.js +27 -3
- package/lib/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
- package/lib/features/store/objects/layout/documentLayout.js +1 -1
- package/lib/features/store/objects/layout/renderers.d.ts +2 -1
- package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/features/store/objects/layout/renderers.js +27 -20
- package/lib/features/store/objects/layout/renderers.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesSearch.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesSearch.js +4 -1
- package/lib/features/store/types/ContentObjectTypesSearch.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts +2 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +8 -3
- package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/i18n/instance.d.ts.map +1 -1
- package/lib/i18n/instance.js +1 -0
- package/lib/i18n/instance.js.map +1 -1
- package/lib/i18n/locales/ar.json +72 -45
- package/lib/i18n/locales/de.json +65 -34
- package/lib/i18n/locales/en.json +63 -47
- package/lib/i18n/locales/es.json +65 -35
- package/lib/i18n/locales/fr.json +65 -35
- package/lib/i18n/locales/it.json +72 -42
- package/lib/i18n/locales/ja.json +72 -41
- package/lib/i18n/locales/ko.json +72 -41
- package/lib/i18n/locales/pt.json +72 -42
- package/lib/i18n/locales/ru.json +72 -43
- package/lib/i18n/locales/tr.json +72 -41
- package/lib/i18n/locales/zh-TW.json +72 -41
- package/lib/i18n/locales/zh.json +72 -41
- package/lib/session/UserSession.d.ts +0 -6
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +0 -15
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +39 -98
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +3 -33
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
- package/lib/shell/login/SignInPrimitives.js +3 -2
- package/lib/shell/login/SignInPrimitives.js.map +1 -1
- package/lib/vertesia-ui-core.js +1 -1
- 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 +1 -1
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +1 -1
- package/lib/vertesia-ui-i18n.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 +1 -1
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js.map +1 -1
- package/llms.txt +70 -70
- package/package.json +35 -32
- package/src/core/components/shadcn/dropdown.tsx +2 -0
- package/src/core/components/shadcn/filters/filterBar.tsx +9 -2
- package/src/core/components/shadcn/modal/ConfirmModal.tsx +65 -3
- package/src/core/components/shadcn/modal/dialog.tsx +1 -1
- package/src/core/components/shadcn/popover.tsx +1 -0
- package/src/core/components/shadcn/switch.tsx +4 -4
- package/src/core/components/shadcn/tabs.tsx +1 -1
- package/src/core/components/shadcn/tooltip.tsx +1 -0
- package/src/env/index.ts +0 -24
- package/src/features/agent/PayloadBuilder.tsx +18 -0
- package/src/features/agent/chat/AgentApprovalModeSelector.tsx +130 -0
- package/src/features/agent/chat/AgentChatFixtureReplay.test.tsx +22 -2
- package/src/features/agent/chat/AgentChatFixtureReplay.tsx +33 -27
- package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +122 -0
- package/src/features/agent/chat/AgentRequestInputOverlay.tsx +91 -17
- package/src/features/agent/chat/AgentRightPanel.tsx +238 -50
- package/src/features/agent/chat/AnimatedThinkingDots.tsx +1 -1
- package/src/features/agent/chat/ArtifactsTab.tsx +21 -155
- package/src/features/agent/chat/AskUserWidget.tsx +6 -2
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +1157 -47
- package/src/features/agent/chat/ModernAgentConversation.tsx +703 -136
- package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +74 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +1420 -126
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +934 -111
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +31 -40
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +28 -28
- package/src/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.tsx +83 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +38 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +121 -98
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +7 -1
- package/src/features/agent/chat/ModernAgentOutput/SlideInPanel.tsx +3 -3
- package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +82 -2
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +216 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +149 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.ts +103 -2
- package/src/features/agent/chat/clipboardFiles.ts +33 -0
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +355 -4
- package/src/features/agent/chat/hooks/useAgentStream.ts +270 -43
- package/src/features/agent/chat/hooks/useArtifacts.ts +11 -44
- package/src/features/agent/chat/index.ts +10 -1
- package/src/features/agent/chat/workstreams.ts +42 -0
- package/src/features/facets/AgentRunnerFacetsNav.tsx +23 -3
- package/src/features/facets/CollectionsFacetsNav.tsx +30 -5
- package/src/features/facets/PromptsFacetsNav.tsx +30 -5
- package/src/features/facets/RunsFacetsNav.tsx +32 -5
- package/src/features/index.ts +0 -1
- package/src/features/oauth/McpConnectionsButton.test.tsx +248 -0
- package/src/features/oauth/McpConnectionsButton.tsx +269 -0
- package/src/features/oauth/McpConnectionsDialog.tsx +142 -0
- package/src/features/oauth/RemoteMcpConnectionButton.tsx +37 -14
- package/src/features/oauth/index.ts +3 -0
- package/src/features/oauth/useMcpConnections.test.ts +94 -0
- package/src/features/oauth/useMcpConnections.ts +210 -0
- package/src/features/permissions/UserPermissionsProvider.tsx +41 -59
- package/src/features/store/objects/DocumentPreviewPanel.tsx +4 -2
- package/src/features/store/objects/DocumentQuickFilter.tsx +72 -0
- package/src/features/store/objects/DocumentSearchResults.tsx +30 -11
- package/src/features/store/objects/components/ContentOverview.tsx +30 -99
- package/src/features/store/objects/layout/DocumentTableColumn.tsx +29 -4
- package/src/features/store/objects/layout/documentLayout.tsx +1 -1
- package/src/features/store/objects/layout/renderers.tsx +80 -20
- package/src/features/store/types/ContentObjectTypesSearch.tsx +7 -1
- package/src/features/store/types/ContentObjectTypesTable.tsx +34 -4
- package/src/i18n/instance.ts +1 -0
- package/src/i18n/locales/ar.json +72 -45
- package/src/i18n/locales/de.json +65 -34
- package/src/i18n/locales/en.json +63 -47
- package/src/i18n/locales/es.json +65 -35
- package/src/i18n/locales/fr.json +65 -35
- package/src/i18n/locales/it.json +72 -42
- package/src/i18n/locales/ja.json +72 -41
- package/src/i18n/locales/ko.json +72 -41
- package/src/i18n/locales/pt.json +72 -42
- package/src/i18n/locales/ru.json +72 -43
- package/src/i18n/locales/tr.json +72 -41
- package/src/i18n/locales/zh-TW.json +72 -41
- package/src/i18n/locales/zh.json +72 -41
- package/src/i18n/rtl.test.ts +57 -1
- package/src/session/UserSession.ts +0 -16
- package/src/session/UserSessionProvider.tsx +51 -123
- package/src/session/auth/composable.ts +3 -34
- package/src/shell/login/SignInPrimitives.tsx +3 -2
- package/src/widgets/schema-editor/editor/Editable.tsx +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +0 -73
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +0 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.js +0 -415
- package/lib/features/document-viewer/UniversalDocumentViewer.js.map +0 -1
- package/lib/features/document-viewer/index.d.ts +0 -2
- package/lib/features/document-viewer/index.d.ts.map +0 -1
- package/lib/features/document-viewer/index.js +0 -2
- package/lib/features/document-viewer/index.js.map +0 -1
- package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +0 -123
- package/src/features/document-viewer/UniversalDocumentViewer.tsx +0 -746
- package/src/features/document-viewer/index.ts +0 -1
- package/src/session/auth/composable.test.ts +0 -79
|
@@ -1,746 +0,0 @@
|
|
|
1
|
-
import { Badge, Button, cn } from '@vertesia/ui/core';
|
|
2
|
-
import { useUserSession } from '@vertesia/ui/session';
|
|
3
|
-
import { MarkdownRenderer, type MarkdownRendererProps, XMLViewer } from '@vertesia/ui/widgets';
|
|
4
|
-
import { AlertCircleIcon, FileIcon, ImageIcon, Loader2Icon } from 'lucide-react';
|
|
5
|
-
import { type ComponentType, type ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
|
-
import { SimplePdfViewer } from '../pdf-viewer/SimplePdfViewer.js';
|
|
7
|
-
|
|
8
|
-
export type UniversalDocumentRenditionTarget = 'pdf' | 'markdown' | 'text' | 'image';
|
|
9
|
-
|
|
10
|
-
export interface UniversalDocumentSource {
|
|
11
|
-
id?: string;
|
|
12
|
-
title?: string;
|
|
13
|
-
fileName?: string;
|
|
14
|
-
contentType?: string;
|
|
15
|
-
url?: string;
|
|
16
|
-
sourcePath?: string;
|
|
17
|
-
content?: string;
|
|
18
|
-
artifact?: {
|
|
19
|
-
runId: string;
|
|
20
|
-
path: string;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface UniversalDocumentRendition {
|
|
25
|
-
url?: string;
|
|
26
|
-
sourcePath?: string;
|
|
27
|
-
content?: string;
|
|
28
|
-
contentType?: string;
|
|
29
|
-
fileName?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface UniversalDocumentViewerContext {
|
|
33
|
-
source: UniversalDocumentSource;
|
|
34
|
-
fileName: string;
|
|
35
|
-
extension: string;
|
|
36
|
-
contentType?: string;
|
|
37
|
-
url?: string;
|
|
38
|
-
content?: string;
|
|
39
|
-
isLoading: boolean;
|
|
40
|
-
error: string | null;
|
|
41
|
-
reload: () => void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface UniversalDocumentRenderer {
|
|
45
|
-
id: string;
|
|
46
|
-
canRender: (context: UniversalDocumentViewerContext) => boolean;
|
|
47
|
-
render?: (context: UniversalDocumentViewerContext) => ReactNode;
|
|
48
|
-
Component?: ComponentType<{ context: UniversalDocumentViewerContext }>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface UniversalDocumentConverterContext {
|
|
52
|
-
source: UniversalDocumentSource;
|
|
53
|
-
fileName: string;
|
|
54
|
-
extension: string;
|
|
55
|
-
contentType?: string;
|
|
56
|
-
target: UniversalDocumentRenditionTarget;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface UniversalDocumentConverter {
|
|
60
|
-
id: string;
|
|
61
|
-
target: UniversalDocumentRenditionTarget;
|
|
62
|
-
canConvert: (context: UniversalDocumentConverterContext) => boolean;
|
|
63
|
-
convert: (context: UniversalDocumentConverterContext) => Promise<UniversalDocumentRendition | null>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface UniversalDocumentViewerProps {
|
|
67
|
-
source: UniversalDocumentSource;
|
|
68
|
-
className?: string;
|
|
69
|
-
bodyClassName?: string;
|
|
70
|
-
renderers?: UniversalDocumentRenderer[];
|
|
71
|
-
converters?: UniversalDocumentConverter[];
|
|
72
|
-
resolveUrl?: (source: UniversalDocumentSource, disposition: 'inline' | 'attachment') => Promise<string>;
|
|
73
|
-
loadText?: (source: UniversalDocumentSource) => Promise<string>;
|
|
74
|
-
/**
|
|
75
|
-
* @deprecated Use converters instead.
|
|
76
|
-
*/
|
|
77
|
-
createRendition?: (
|
|
78
|
-
source: UniversalDocumentSource,
|
|
79
|
-
target: UniversalDocumentRenditionTarget,
|
|
80
|
-
) => Promise<UniversalDocumentRendition | null>;
|
|
81
|
-
markdownComponents?: MarkdownRendererProps['components'];
|
|
82
|
-
showHeader?: boolean;
|
|
83
|
-
onDownload?: (source: UniversalDocumentSource) => void;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function getFileName(source: UniversalDocumentSource): string {
|
|
87
|
-
return (
|
|
88
|
-
source.fileName ||
|
|
89
|
-
source.title ||
|
|
90
|
-
source.artifact?.path.split('/').pop() ||
|
|
91
|
-
source.sourcePath?.split('/').pop() ||
|
|
92
|
-
'Document'
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function getExtension(fileName: string): string {
|
|
97
|
-
const cleanName = fileName.split('?')[0] || fileName;
|
|
98
|
-
return cleanName.includes('.') ? cleanName.split('.').pop()?.toLowerCase() || '' : '';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function isPdf(context: UniversalDocumentViewerContext): boolean {
|
|
102
|
-
return context.contentType === 'application/pdf' || context.extension === 'pdf';
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function isMarkdown(context: UniversalDocumentViewerContext): boolean {
|
|
106
|
-
return (
|
|
107
|
-
['md', 'markdown'].includes(context.extension) ||
|
|
108
|
-
['text/markdown', 'text/x-markdown'].includes(context.contentType || '')
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function isImage(context: UniversalDocumentViewerContext): boolean {
|
|
113
|
-
return (
|
|
114
|
-
context.contentType?.startsWith('image/') ||
|
|
115
|
-
['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'].includes(context.extension)
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function isHtml(context: UniversalDocumentViewerContext): boolean {
|
|
120
|
-
return context.contentType === 'text/html' || ['html', 'htm'].includes(context.extension);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function isXml(context: UniversalDocumentViewerContext): boolean {
|
|
124
|
-
return ['application/xml', 'text/xml'].includes(context.contentType || '') || context.extension === 'xml';
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function isCodeOrText(context: UniversalDocumentViewerContext): boolean {
|
|
128
|
-
return (
|
|
129
|
-
context.contentType?.startsWith('text/') ||
|
|
130
|
-
['css', 'csv', 'json', 'txt', 'tsx', 'ts', 'jsx', 'js', 'xml', 'yaml', 'yml'].includes(context.extension)
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function isTsxMockupSource(context: UniversalDocumentViewerContext): boolean {
|
|
135
|
-
return ['tsx', 'jsx'].includes(context.extension);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function canUsePdfRendition(context: UniversalDocumentViewerContext): boolean {
|
|
139
|
-
return (
|
|
140
|
-
['doc', 'docx', 'ppt', 'pptx'].includes(context.extension) ||
|
|
141
|
-
[
|
|
142
|
-
'application/msword',
|
|
143
|
-
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
144
|
-
'application/vnd.ms-powerpoint',
|
|
145
|
-
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
146
|
-
].includes(context.contentType || '')
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function CodeViewer({ content, extension }: { content?: string; extension: string }) {
|
|
151
|
-
return (
|
|
152
|
-
<pre className="h-full overflow-auto rounded-md bg-muted/10 p-3 text-xs leading-5">
|
|
153
|
-
<code className={extension ? `language-${extension}` : undefined}>{content || ''}</code>
|
|
154
|
-
</pre>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function EmptyState({ message }: { message: string }) {
|
|
159
|
-
return (
|
|
160
|
-
<div className="flex h-full min-h-64 flex-col items-center justify-center gap-2 text-muted">
|
|
161
|
-
<FileIcon className="size-8" />
|
|
162
|
-
<span className="text-sm">{message}</span>
|
|
163
|
-
</div>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function renderWithCustomRenderer(
|
|
168
|
-
renderer: UniversalDocumentRenderer,
|
|
169
|
-
context: UniversalDocumentViewerContext,
|
|
170
|
-
): ReactNode {
|
|
171
|
-
if (renderer.Component) {
|
|
172
|
-
const RendererComponent = renderer.Component;
|
|
173
|
-
return <RendererComponent context={context} />;
|
|
174
|
-
}
|
|
175
|
-
return renderer.render?.(context) ?? null;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
interface TsxRenderMetadata {
|
|
179
|
-
ok?: boolean;
|
|
180
|
-
source_artifact?: string;
|
|
181
|
-
screenshot_artifact?: string;
|
|
182
|
-
rendered_at?: string;
|
|
183
|
-
viewport?: {
|
|
184
|
-
width?: number;
|
|
185
|
-
height?: number;
|
|
186
|
-
};
|
|
187
|
-
dependencies_reused?: boolean;
|
|
188
|
-
status?: number;
|
|
189
|
-
title?: string;
|
|
190
|
-
console_errors?: unknown[];
|
|
191
|
-
page_errors?: unknown[];
|
|
192
|
-
failed_requests?: unknown[];
|
|
193
|
-
bad_responses?: unknown[];
|
|
194
|
-
timings_ms?: Record<string, unknown>;
|
|
195
|
-
error?: unknown;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
interface TsxSandboxPreviewState {
|
|
199
|
-
isLoading: boolean;
|
|
200
|
-
imageUrl?: string;
|
|
201
|
-
metadata?: TsxRenderMetadata;
|
|
202
|
-
previewError?: string;
|
|
203
|
-
metadataError?: string;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function replaceExtension(path: string, nextExtension: string): string {
|
|
207
|
-
return path.includes('.') ? path.replace(/\.[^/.]+$/, nextExtension) : `${path}${nextExtension}`;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function fileNameFromPath(path: string): string {
|
|
211
|
-
return path.split('/').pop() || path;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
215
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
216
|
-
? (value as Record<string, unknown>)
|
|
217
|
-
: undefined;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function asNumber(value: unknown): number | undefined {
|
|
221
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function formatDuration(ms: number | undefined): string | undefined {
|
|
225
|
-
if (ms === undefined) return undefined;
|
|
226
|
-
if (ms < 1000) return `${Math.round(ms)} ms`;
|
|
227
|
-
return `${(ms / 1000).toFixed(ms < 10000 ? 1 : 0)} s`;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function countItems(value: unknown): number {
|
|
231
|
-
return Array.isArray(value) ? value.length : 0;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function parseTsxRenderMetadata(text: string): TsxRenderMetadata | undefined {
|
|
235
|
-
try {
|
|
236
|
-
const parsed = JSON.parse(text) as unknown;
|
|
237
|
-
const record = asRecord(parsed);
|
|
238
|
-
if (!record) return undefined;
|
|
239
|
-
const viewport = asRecord(record.viewport);
|
|
240
|
-
return {
|
|
241
|
-
ok: typeof record.ok === 'boolean' ? record.ok : undefined,
|
|
242
|
-
source_artifact: typeof record.source_artifact === 'string' ? record.source_artifact : undefined,
|
|
243
|
-
screenshot_artifact:
|
|
244
|
-
typeof record.screenshot_artifact === 'string' ? record.screenshot_artifact : undefined,
|
|
245
|
-
rendered_at: typeof record.rendered_at === 'string' ? record.rendered_at : undefined,
|
|
246
|
-
viewport: viewport
|
|
247
|
-
? {
|
|
248
|
-
width: asNumber(viewport.width),
|
|
249
|
-
height: asNumber(viewport.height),
|
|
250
|
-
}
|
|
251
|
-
: undefined,
|
|
252
|
-
dependencies_reused:
|
|
253
|
-
typeof record.dependencies_reused === 'boolean' ? record.dependencies_reused : undefined,
|
|
254
|
-
status: asNumber(record.status),
|
|
255
|
-
title: typeof record.title === 'string' ? record.title : undefined,
|
|
256
|
-
console_errors: Array.isArray(record.console_errors) ? record.console_errors : undefined,
|
|
257
|
-
page_errors: Array.isArray(record.page_errors) ? record.page_errors : undefined,
|
|
258
|
-
failed_requests: Array.isArray(record.failed_requests) ? record.failed_requests : undefined,
|
|
259
|
-
bad_responses: Array.isArray(record.bad_responses) ? record.bad_responses : undefined,
|
|
260
|
-
timings_ms: asRecord(record.timings_ms),
|
|
261
|
-
error: record.error,
|
|
262
|
-
};
|
|
263
|
-
} catch {
|
|
264
|
-
return undefined;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
async function fetchText(url: string, fileName: string): Promise<string> {
|
|
269
|
-
const response = await fetch(url);
|
|
270
|
-
if (!response.ok) {
|
|
271
|
-
throw new Error(`Failed to load ${fileName}: ${response.statusText}`);
|
|
272
|
-
}
|
|
273
|
-
return response.text();
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function resolveScreenshotPath({
|
|
277
|
-
metadata,
|
|
278
|
-
sourcePath,
|
|
279
|
-
fallbackPath,
|
|
280
|
-
artifactMode,
|
|
281
|
-
}: {
|
|
282
|
-
metadata?: TsxRenderMetadata;
|
|
283
|
-
sourcePath: string;
|
|
284
|
-
fallbackPath: string;
|
|
285
|
-
artifactMode: boolean;
|
|
286
|
-
}): string {
|
|
287
|
-
const screenshotArtifact = metadata?.screenshot_artifact?.replace(/^\/+/, '');
|
|
288
|
-
if (!screenshotArtifact) return fallbackPath;
|
|
289
|
-
if (artifactMode) return screenshotArtifact;
|
|
290
|
-
|
|
291
|
-
const sourceArtifact = metadata?.source_artifact?.replace(/^\/+/, '');
|
|
292
|
-
const normalizedSourcePath = sourcePath.replace(/^\/+/, '');
|
|
293
|
-
if (sourceArtifact && normalizedSourcePath.endsWith(sourceArtifact)) {
|
|
294
|
-
const storageRoot = normalizedSourcePath.slice(0, -sourceArtifact.length).replace(/\/+$/, '');
|
|
295
|
-
return storageRoot ? `${storageRoot}/${screenshotArtifact}` : screenshotArtifact;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const sourceDir = normalizedSourcePath.includes('/')
|
|
299
|
-
? normalizedSourcePath.slice(0, normalizedSourcePath.lastIndexOf('/') + 1)
|
|
300
|
-
: '';
|
|
301
|
-
return sourceDir ? `${sourceDir}${fileNameFromPath(screenshotArtifact)}` : fallbackPath;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function TsxRenderDetails({ metadata }: { metadata?: TsxRenderMetadata }) {
|
|
305
|
-
if (!metadata) return null;
|
|
306
|
-
|
|
307
|
-
const totalMs = asNumber(metadata.timings_ms?.total_before_cleanup);
|
|
308
|
-
const issueCount =
|
|
309
|
-
countItems(metadata.console_errors) +
|
|
310
|
-
countItems(metadata.page_errors) +
|
|
311
|
-
countItems(metadata.failed_requests) +
|
|
312
|
-
countItems(metadata.bad_responses);
|
|
313
|
-
|
|
314
|
-
return (
|
|
315
|
-
<div className="grid gap-2 border-b p-3 text-xs">
|
|
316
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
317
|
-
{metadata.ok !== undefined && (
|
|
318
|
-
<Badge variant={metadata.ok ? 'success' : 'destructive'}>
|
|
319
|
-
{metadata.ok ? 'render ok' : 'render failed'}
|
|
320
|
-
</Badge>
|
|
321
|
-
)}
|
|
322
|
-
{metadata.dependencies_reused !== undefined && (
|
|
323
|
-
<Badge variant={metadata.dependencies_reused ? 'info' : 'secondary'}>
|
|
324
|
-
deps {metadata.dependencies_reused ? 'reused' : 'installed'}
|
|
325
|
-
</Badge>
|
|
326
|
-
)}
|
|
327
|
-
{metadata.status && <Badge variant="secondary">HTTP {metadata.status}</Badge>}
|
|
328
|
-
{issueCount > 0 && <Badge variant="attention">{issueCount} browser issue(s)</Badge>}
|
|
329
|
-
</div>
|
|
330
|
-
<div className="grid gap-1 text-muted sm:grid-cols-2">
|
|
331
|
-
{metadata.viewport?.width && metadata.viewport.height && (
|
|
332
|
-
<div>
|
|
333
|
-
Viewport {metadata.viewport.width} x {metadata.viewport.height}
|
|
334
|
-
</div>
|
|
335
|
-
)}
|
|
336
|
-
{formatDuration(totalMs) && <div>Total {formatDuration(totalMs)}</div>}
|
|
337
|
-
{metadata.rendered_at && <div>Rendered {new Date(metadata.rendered_at).toLocaleString()}</div>}
|
|
338
|
-
{metadata.title && <div className="truncate">Title {metadata.title}</div>}
|
|
339
|
-
</div>
|
|
340
|
-
{typeof metadata.error === 'string' && <div className="text-destructive">{metadata.error}</div>}
|
|
341
|
-
</div>
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function TsxSandboxRenderPreview({ context }: { context: UniversalDocumentViewerContext }) {
|
|
346
|
-
const { client } = useUserSession();
|
|
347
|
-
const artifact = context.source.artifact;
|
|
348
|
-
const sourcePath = artifact?.path || context.source.sourcePath;
|
|
349
|
-
const artifactMode = !!artifact;
|
|
350
|
-
const code = context.content || '';
|
|
351
|
-
const [state, setState] = useState<TsxSandboxPreviewState>({ isLoading: false });
|
|
352
|
-
|
|
353
|
-
const getRelatedUrl = useCallback(
|
|
354
|
-
async (path: string, disposition: 'inline' | 'attachment') => {
|
|
355
|
-
if (artifact) {
|
|
356
|
-
const result = await client.files.getArtifactDownloadUrl(artifact.runId, path, disposition);
|
|
357
|
-
return result.url;
|
|
358
|
-
}
|
|
359
|
-
const result = await client.files.getDownloadUrl(path, fileNameFromPath(path), disposition);
|
|
360
|
-
return result.url;
|
|
361
|
-
},
|
|
362
|
-
[artifact, client],
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
useEffect(() => {
|
|
366
|
-
if (!sourcePath) {
|
|
367
|
-
setState({ isLoading: false, previewError: 'No source path is available for this TSX artifact.' });
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
const currentSourcePath: string = sourcePath;
|
|
371
|
-
|
|
372
|
-
let cancelled = false;
|
|
373
|
-
const pngPath = replaceExtension(currentSourcePath, '.png');
|
|
374
|
-
const metadataPath = replaceExtension(currentSourcePath, '.render.json');
|
|
375
|
-
|
|
376
|
-
async function loadPreview() {
|
|
377
|
-
setState({ isLoading: true });
|
|
378
|
-
|
|
379
|
-
let metadata: TsxRenderMetadata | undefined;
|
|
380
|
-
let metadataError: string | undefined;
|
|
381
|
-
let imagePath = pngPath;
|
|
382
|
-
|
|
383
|
-
try {
|
|
384
|
-
const metadataUrl = await getRelatedUrl(metadataPath, 'inline');
|
|
385
|
-
metadata = parseTsxRenderMetadata(await fetchText(metadataUrl, fileNameFromPath(metadataPath)));
|
|
386
|
-
imagePath = resolveScreenshotPath({
|
|
387
|
-
metadata,
|
|
388
|
-
sourcePath: currentSourcePath,
|
|
389
|
-
fallbackPath: pngPath,
|
|
390
|
-
artifactMode,
|
|
391
|
-
});
|
|
392
|
-
} catch (err: unknown) {
|
|
393
|
-
metadataError = err instanceof Error ? err.message : 'Render metadata is not available';
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
let imageUrl: string | undefined;
|
|
397
|
-
let previewError: string | undefined;
|
|
398
|
-
try {
|
|
399
|
-
imageUrl = await getRelatedUrl(imagePath, 'inline');
|
|
400
|
-
} catch (err: unknown) {
|
|
401
|
-
previewError = err instanceof Error ? err.message : 'Sandbox render image is not available';
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (!cancelled) {
|
|
405
|
-
setState({
|
|
406
|
-
isLoading: false,
|
|
407
|
-
imageUrl,
|
|
408
|
-
metadata,
|
|
409
|
-
metadataError,
|
|
410
|
-
previewError,
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
void loadPreview();
|
|
416
|
-
return () => {
|
|
417
|
-
cancelled = true;
|
|
418
|
-
};
|
|
419
|
-
}, [artifactMode, getRelatedUrl, sourcePath]);
|
|
420
|
-
|
|
421
|
-
return (
|
|
422
|
-
<div className="flex h-full min-h-0 flex-col">
|
|
423
|
-
<div className="flex min-h-10 flex-wrap items-center gap-2 border-b px-3 py-2 text-sm">
|
|
424
|
-
<ImageIcon className="size-4 text-info" />
|
|
425
|
-
<span className="font-medium">Sandbox render</span>
|
|
426
|
-
{state.isLoading ? (
|
|
427
|
-
<Badge variant="secondary">loading</Badge>
|
|
428
|
-
) : state.imageUrl ? (
|
|
429
|
-
<Badge variant="success">PNG preview</Badge>
|
|
430
|
-
) : (
|
|
431
|
-
<Badge variant="attention">source only</Badge>
|
|
432
|
-
)}
|
|
433
|
-
{state.metadata?.rendered_at && (
|
|
434
|
-
<span className="text-xs text-muted">{new Date(state.metadata.rendered_at).toLocaleString()}</span>
|
|
435
|
-
)}
|
|
436
|
-
</div>
|
|
437
|
-
|
|
438
|
-
{state.isLoading ? (
|
|
439
|
-
<div className="flex h-full min-h-64 items-center justify-center gap-2 text-muted">
|
|
440
|
-
<Loader2Icon className="size-5 animate-spin" />
|
|
441
|
-
<span className="text-sm">Loading sandbox render...</span>
|
|
442
|
-
</div>
|
|
443
|
-
) : state.imageUrl ? (
|
|
444
|
-
<div className="grid min-h-0 flex-1 xl:grid-cols-[minmax(0,1fr)_minmax(24rem,0.7fr)]">
|
|
445
|
-
<div className="flex min-h-0 items-center justify-center overflow-auto bg-muted/10 p-3">
|
|
446
|
-
<img
|
|
447
|
-
src={state.imageUrl}
|
|
448
|
-
alt={`${context.fileName} sandbox render`}
|
|
449
|
-
className="max-h-full max-w-full rounded-md object-contain"
|
|
450
|
-
/>
|
|
451
|
-
</div>
|
|
452
|
-
<div className="min-h-0 overflow-auto border-t xl:border-s xl:border-t-0">
|
|
453
|
-
<TsxRenderDetails metadata={state.metadata} />
|
|
454
|
-
<div className="p-3">
|
|
455
|
-
<CodeViewer content={code} extension={context.extension} />
|
|
456
|
-
</div>
|
|
457
|
-
</div>
|
|
458
|
-
</div>
|
|
459
|
-
) : (
|
|
460
|
-
<div className="grid min-h-0 flex-1 grid-rows-[auto_minmax(0,1fr)]">
|
|
461
|
-
<div className="border-b px-3 py-2 text-xs text-muted">
|
|
462
|
-
No sandbox-rendered PNG was found for this TSX artifact. Showing the source without executing it
|
|
463
|
-
in Studio.
|
|
464
|
-
{state.previewError && <span className="ms-1">Preview lookup: {state.previewError}</span>}
|
|
465
|
-
{!state.previewError && state.metadataError && (
|
|
466
|
-
<span className="ms-1">Metadata lookup: {state.metadataError}</span>
|
|
467
|
-
)}
|
|
468
|
-
</div>
|
|
469
|
-
<div className="min-h-0 overflow-auto p-3">
|
|
470
|
-
<TsxRenderDetails metadata={state.metadata} />
|
|
471
|
-
<CodeViewer content={code} extension={context.extension} />
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
)}
|
|
475
|
-
</div>
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
export function UniversalDocumentViewer({
|
|
480
|
-
source,
|
|
481
|
-
className,
|
|
482
|
-
bodyClassName,
|
|
483
|
-
renderers = [],
|
|
484
|
-
converters = [],
|
|
485
|
-
resolveUrl,
|
|
486
|
-
loadText,
|
|
487
|
-
createRendition,
|
|
488
|
-
markdownComponents,
|
|
489
|
-
showHeader = true,
|
|
490
|
-
onDownload,
|
|
491
|
-
}: UniversalDocumentViewerProps) {
|
|
492
|
-
const { client } = useUserSession();
|
|
493
|
-
const fileName = useMemo(() => getFileName(source), [source]);
|
|
494
|
-
const extension = useMemo(() => getExtension(fileName), [fileName]);
|
|
495
|
-
const [url, setUrl] = useState(source.url);
|
|
496
|
-
const [content, setContent] = useState(source.content);
|
|
497
|
-
const [rendition, setRendition] = useState<UniversalDocumentRendition | null>(null);
|
|
498
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
499
|
-
const [error, setError] = useState<string | null>(null);
|
|
500
|
-
const [refreshKey, setRefreshKey] = useState(0);
|
|
501
|
-
const sourceKey = [
|
|
502
|
-
source.id,
|
|
503
|
-
source.title,
|
|
504
|
-
source.fileName,
|
|
505
|
-
source.contentType,
|
|
506
|
-
source.url,
|
|
507
|
-
source.sourcePath,
|
|
508
|
-
source.content,
|
|
509
|
-
source.artifact?.runId,
|
|
510
|
-
source.artifact?.path,
|
|
511
|
-
].join('\0');
|
|
512
|
-
|
|
513
|
-
const defaultResolveUrl = useCallback(
|
|
514
|
-
async (currentSource: UniversalDocumentSource, disposition: 'inline' | 'attachment') => {
|
|
515
|
-
if (currentSource.url) return currentSource.url;
|
|
516
|
-
if (currentSource.artifact) {
|
|
517
|
-
const result = await client.files.getArtifactDownloadUrl(
|
|
518
|
-
currentSource.artifact.runId,
|
|
519
|
-
currentSource.artifact.path,
|
|
520
|
-
disposition,
|
|
521
|
-
);
|
|
522
|
-
return result.url;
|
|
523
|
-
}
|
|
524
|
-
if (currentSource.sourcePath) {
|
|
525
|
-
const result = await client.files.getDownloadUrl(
|
|
526
|
-
currentSource.sourcePath,
|
|
527
|
-
currentSource.fileName,
|
|
528
|
-
disposition,
|
|
529
|
-
);
|
|
530
|
-
return result.url;
|
|
531
|
-
}
|
|
532
|
-
return '';
|
|
533
|
-
},
|
|
534
|
-
[client],
|
|
535
|
-
);
|
|
536
|
-
|
|
537
|
-
const resolveDocumentUrl = resolveUrl || defaultResolveUrl;
|
|
538
|
-
|
|
539
|
-
const defaultLoadText = useCallback(
|
|
540
|
-
async (currentSource: UniversalDocumentSource) => {
|
|
541
|
-
if (currentSource.content !== undefined) return currentSource.content;
|
|
542
|
-
const resolvedUrl = await resolveDocumentUrl(currentSource, 'inline');
|
|
543
|
-
if (!resolvedUrl) return '';
|
|
544
|
-
const response = await fetch(resolvedUrl);
|
|
545
|
-
if (!response.ok) {
|
|
546
|
-
throw new Error(`Failed to load ${getFileName(currentSource)}: ${response.statusText}`);
|
|
547
|
-
}
|
|
548
|
-
return response.text();
|
|
549
|
-
},
|
|
550
|
-
[resolveDocumentUrl],
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
const loadDocumentText = loadText || defaultLoadText;
|
|
554
|
-
|
|
555
|
-
const baseContext: UniversalDocumentViewerContext = {
|
|
556
|
-
source,
|
|
557
|
-
fileName,
|
|
558
|
-
extension,
|
|
559
|
-
contentType: source.contentType || rendition?.contentType,
|
|
560
|
-
url: rendition?.url || url,
|
|
561
|
-
content: rendition?.content || content,
|
|
562
|
-
isLoading,
|
|
563
|
-
error,
|
|
564
|
-
reload: () => setRefreshKey((key) => key + 1),
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
const selectedCustomRenderer = renderers.find((renderer) => renderer.canRender(baseContext));
|
|
568
|
-
const needsText =
|
|
569
|
-
!selectedCustomRenderer &&
|
|
570
|
-
(isMarkdown(baseContext) || isHtml(baseContext) || isXml(baseContext) || isCodeOrText(baseContext));
|
|
571
|
-
const needsUrl = !selectedCustomRenderer && (isPdf(baseContext) || isImage(baseContext));
|
|
572
|
-
const converterContext: UniversalDocumentConverterContext = {
|
|
573
|
-
source,
|
|
574
|
-
fileName,
|
|
575
|
-
extension,
|
|
576
|
-
contentType: source.contentType,
|
|
577
|
-
target: 'pdf',
|
|
578
|
-
};
|
|
579
|
-
const selectedConverter =
|
|
580
|
-
!selectedCustomRenderer && !baseContext.url
|
|
581
|
-
? converters.find((converter) => converter.target === 'pdf' && converter.canConvert(converterContext))
|
|
582
|
-
: undefined;
|
|
583
|
-
const needsPdfRendition =
|
|
584
|
-
!selectedCustomRenderer &&
|
|
585
|
-
!baseContext.url &&
|
|
586
|
-
(canUsePdfRendition(baseContext) || !!selectedConverter) &&
|
|
587
|
-
(!!selectedConverter || !!createRendition);
|
|
588
|
-
|
|
589
|
-
useEffect(() => {
|
|
590
|
-
let cancelled = false;
|
|
591
|
-
// These values intentionally retrigger loading even when source object identity is stable.
|
|
592
|
-
void refreshKey;
|
|
593
|
-
void sourceKey;
|
|
594
|
-
const currentSource = source;
|
|
595
|
-
setError(null);
|
|
596
|
-
setUrl(currentSource.url);
|
|
597
|
-
setContent(currentSource.content);
|
|
598
|
-
setRendition(null);
|
|
599
|
-
|
|
600
|
-
async function load() {
|
|
601
|
-
if (!needsText && !needsUrl && !needsPdfRendition) return;
|
|
602
|
-
setIsLoading(true);
|
|
603
|
-
try {
|
|
604
|
-
if (needsPdfRendition) {
|
|
605
|
-
const result = selectedConverter
|
|
606
|
-
? await selectedConverter.convert({
|
|
607
|
-
source: currentSource,
|
|
608
|
-
fileName,
|
|
609
|
-
extension,
|
|
610
|
-
contentType: currentSource.contentType,
|
|
611
|
-
target: 'pdf',
|
|
612
|
-
})
|
|
613
|
-
: await createRendition?.(currentSource, 'pdf');
|
|
614
|
-
if (!cancelled) setRendition(result ?? null);
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
if (needsText) {
|
|
619
|
-
const result = await loadDocumentText(currentSource);
|
|
620
|
-
if (!cancelled) setContent(result);
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
if (needsUrl) {
|
|
625
|
-
const result = await resolveDocumentUrl(currentSource, 'inline');
|
|
626
|
-
if (!cancelled) setUrl(result);
|
|
627
|
-
}
|
|
628
|
-
} catch (err: unknown) {
|
|
629
|
-
if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load document');
|
|
630
|
-
} finally {
|
|
631
|
-
if (!cancelled) setIsLoading(false);
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
void load();
|
|
636
|
-
return () => {
|
|
637
|
-
cancelled = true;
|
|
638
|
-
};
|
|
639
|
-
}, [
|
|
640
|
-
createRendition,
|
|
641
|
-
extension,
|
|
642
|
-
fileName,
|
|
643
|
-
loadDocumentText,
|
|
644
|
-
needsPdfRendition,
|
|
645
|
-
needsText,
|
|
646
|
-
needsUrl,
|
|
647
|
-
refreshKey,
|
|
648
|
-
resolveDocumentUrl,
|
|
649
|
-
selectedConverter,
|
|
650
|
-
source,
|
|
651
|
-
sourceKey,
|
|
652
|
-
]);
|
|
653
|
-
|
|
654
|
-
const context: UniversalDocumentViewerContext = {
|
|
655
|
-
...baseContext,
|
|
656
|
-
url: rendition?.url || url,
|
|
657
|
-
content: rendition?.content || content,
|
|
658
|
-
contentType: rendition?.contentType || source.contentType,
|
|
659
|
-
isLoading,
|
|
660
|
-
error,
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
let body: ReactNode;
|
|
664
|
-
if (isLoading) {
|
|
665
|
-
body = (
|
|
666
|
-
<div className="flex h-full min-h-64 items-center justify-center gap-2 text-muted">
|
|
667
|
-
<Loader2Icon className="size-5 animate-spin" />
|
|
668
|
-
<span className="text-sm">Loading preview...</span>
|
|
669
|
-
</div>
|
|
670
|
-
);
|
|
671
|
-
} else if (error) {
|
|
672
|
-
body = (
|
|
673
|
-
<div className="flex h-full min-h-64 flex-col items-center justify-center gap-2 text-destructive">
|
|
674
|
-
<AlertCircleIcon className="size-7" />
|
|
675
|
-
<span className="max-w-xl text-center text-sm">{error}</span>
|
|
676
|
-
<Button variant="outline" size="sm" onClick={context.reload}>
|
|
677
|
-
Retry
|
|
678
|
-
</Button>
|
|
679
|
-
</div>
|
|
680
|
-
);
|
|
681
|
-
} else if (selectedCustomRenderer) {
|
|
682
|
-
body = renderWithCustomRenderer(selectedCustomRenderer, context);
|
|
683
|
-
} else if ((isPdf(context) || rendition?.contentType === 'application/pdf') && context.url) {
|
|
684
|
-
body = <SimplePdfViewer url={context.url} className="h-full" />;
|
|
685
|
-
} else if (isImage(context) && context.url) {
|
|
686
|
-
body = (
|
|
687
|
-
<div className="flex h-full min-h-0 items-center justify-center overflow-auto bg-muted/10 p-3">
|
|
688
|
-
<img src={context.url} alt={fileName} className="max-h-full max-w-full rounded-md object-contain" />
|
|
689
|
-
</div>
|
|
690
|
-
);
|
|
691
|
-
} else if (isMarkdown(context)) {
|
|
692
|
-
body = (
|
|
693
|
-
<div className="prose prose-sm dark:prose-invert max-w-none px-5 py-4">
|
|
694
|
-
<MarkdownRenderer artifactRunId={source.artifact?.runId} components={markdownComponents}>
|
|
695
|
-
{context.content || ''}
|
|
696
|
-
</MarkdownRenderer>
|
|
697
|
-
</div>
|
|
698
|
-
);
|
|
699
|
-
} else if (isHtml(context)) {
|
|
700
|
-
body = (
|
|
701
|
-
<iframe
|
|
702
|
-
title={fileName}
|
|
703
|
-
className="h-full min-h-96 w-full bg-white"
|
|
704
|
-
sandbox=""
|
|
705
|
-
srcDoc={context.content || ''}
|
|
706
|
-
/>
|
|
707
|
-
);
|
|
708
|
-
} else if (isXml(context)) {
|
|
709
|
-
body = (
|
|
710
|
-
<div className="px-4 py-2">
|
|
711
|
-
<XMLViewer xml={context.content || ''} collapsible />
|
|
712
|
-
</div>
|
|
713
|
-
);
|
|
714
|
-
} else if (isTsxMockupSource(context)) {
|
|
715
|
-
body = <TsxSandboxRenderPreview context={context} />;
|
|
716
|
-
} else if (isCodeOrText(context)) {
|
|
717
|
-
body = <CodeViewer content={context.content} extension={extension} />;
|
|
718
|
-
} else if (canUsePdfRendition(context) && !selectedConverter && !createRendition) {
|
|
719
|
-
body = <EmptyState message="This file needs a PDF rendition before it can be previewed." />;
|
|
720
|
-
} else {
|
|
721
|
-
body = <EmptyState message="Preview is not available for this file type." />;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
return (
|
|
725
|
-
<div className={cn('flex h-full min-h-0 flex-col overflow-hidden', className)}>
|
|
726
|
-
{showHeader && (
|
|
727
|
-
<div className="flex min-h-10 items-center justify-between gap-3 border-b py-2 ps-3 pe-16">
|
|
728
|
-
<div className="min-w-0">
|
|
729
|
-
<div className="truncate text-sm font-medium" title={fileName}>
|
|
730
|
-
{fileName}
|
|
731
|
-
</div>
|
|
732
|
-
{context.contentType && (
|
|
733
|
-
<div className="truncate text-xs text-muted">{context.contentType}</div>
|
|
734
|
-
)}
|
|
735
|
-
</div>
|
|
736
|
-
{onDownload && (
|
|
737
|
-
<Button variant="outline" size="sm" onClick={() => onDownload(source)}>
|
|
738
|
-
Download
|
|
739
|
-
</Button>
|
|
740
|
-
)}
|
|
741
|
-
</div>
|
|
742
|
-
)}
|
|
743
|
-
<div className={cn('min-h-0 flex-1 overflow-auto', bodyClassName)}>{body}</div>
|
|
744
|
-
</div>
|
|
745
|
-
);
|
|
746
|
-
}
|