@vertesia/ui 1.5.0-dev.20260722.120446Z → 1.5.0-dev.20260725.083715Z
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/filters/filterBar.d.ts.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.d.ts +1 -1
- package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +2 -0
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/tabs.d.ts +12 -1
- package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
- package/lib/core/components/shadcn/tabs.js +12 -4
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts +5 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +2 -2
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts +5 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +48 -11
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/DocumentEditingActionCard.d.ts +6 -0
- package/lib/features/agent/chat/DocumentEditingActionCard.d.ts.map +1 -0
- package/lib/features/agent/chat/DocumentEditingActionCard.js +129 -0
- package/lib/features/agent/chat/DocumentEditingActionCard.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +19 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +125 -27
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts +45 -0
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js +40 -0
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +94 -49
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +9 -5
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts +25 -0
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js +33 -0
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +22 -24
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts +14 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js +21 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts +30 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js +53 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +21 -2
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js +29 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts +33 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js +129 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +7 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js +11 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +24 -9
- package/lib/features/agent/chat/hooks/useAgentStream.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 +3 -0
- package/lib/features/agent/chat/index.js.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/ContentOverview.d.ts +2 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +86 -15
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts +16 -0
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js +116 -0
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts +7 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.js +13 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.js.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.d.ts +48 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.d.ts.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.js +720 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.js.map +1 -0
- package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
- package/lib/features/store/objects/components/TextEditorPanel.js +22 -9
- package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
- package/lib/features/store/objects/components/documentArtifactRefs.d.ts +26 -0
- package/lib/features/store/objects/components/documentArtifactRefs.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentArtifactRefs.js +52 -0
- package/lib/features/store/objects/components/documentArtifactRefs.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts +4 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.js +40 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingPrompts.d.ts +3 -0
- package/lib/features/store/objects/components/documentEditingPrompts.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingPrompts.js +13 -0
- package/lib/features/store/objects/components/documentEditingPrompts.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingRun.d.ts +27 -0
- package/lib/features/store/objects/components/documentEditingRun.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingRun.js +126 -0
- package/lib/features/store/objects/components/documentEditingRun.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingTarget.d.ts +20 -0
- package/lib/features/store/objects/components/documentEditingTarget.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingTarget.js +40 -0
- package/lib/features/store/objects/components/documentEditingTarget.js.map +1 -0
- package/lib/features/store/objects/components/index.d.ts +1 -0
- package/lib/features/store/objects/components/index.d.ts.map +1 -1
- package/lib/features/store/objects/components/index.js +1 -0
- package/lib/features/store/objects/components/index.js.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts +5 -1
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.js +53 -29
- package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
- package/lib/features/store/objects/components/useDownloadFile.d.ts +2 -1
- package/lib/features/store/objects/components/useDownloadFile.d.ts.map +1 -1
- package/lib/features/store/objects/components/useDownloadFile.js +3 -0
- package/lib/features/store/objects/components/useDownloadFile.js.map +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +1 -1
- package/lib/i18n/locales/ar.json +118 -1
- package/lib/i18n/locales/de.json +118 -1
- package/lib/i18n/locales/en.json +118 -0
- package/lib/i18n/locales/es.json +118 -1
- package/lib/i18n/locales/fr.json +118 -1
- package/lib/i18n/locales/it.json +118 -1
- package/lib/i18n/locales/ja.json +118 -1
- package/lib/i18n/locales/ko.json +118 -1
- package/lib/i18n/locales/pt.json +118 -1
- package/lib/i18n/locales/ru.json +118 -1
- package/lib/i18n/locales/tr.json +118 -1
- package/lib/i18n/locales/zh-TW.json +118 -1
- package/lib/i18n/locales/zh.json +118 -1
- package/lib/rich-text/EditorToolbar.d.ts +37 -0
- package/lib/rich-text/EditorToolbar.d.ts.map +1 -0
- package/lib/rich-text/EditorToolbar.js +215 -0
- package/lib/rich-text/EditorToolbar.js.map +1 -0
- package/lib/rich-text/VertesiaRichTextEditor.d.ts +26 -0
- package/lib/rich-text/VertesiaRichTextEditor.d.ts.map +1 -0
- package/lib/rich-text/VertesiaRichTextEditor.js +67 -0
- package/lib/rich-text/VertesiaRichTextEditor.js.map +1 -0
- package/lib/rich-text/index.d.ts +2 -0
- package/lib/rich-text/index.d.ts.map +1 -0
- package/lib/rich-text/index.js +2 -0
- package/lib/rich-text/index.js.map +1 -0
- package/lib/vertesia-ui-core.js +2 -2
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-features.js +35 -30
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +14 -14
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +5 -0
- package/lib/vertesia-ui-rich-text.js.map +1 -0
- package/lib/vertesia-ui-widgets.js +25 -7
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/markdown/AgentResourceResolver.d.ts +31 -0
- package/lib/widgets/markdown/AgentResourceResolver.d.ts.map +1 -0
- package/lib/widgets/markdown/AgentResourceResolver.js +39 -0
- package/lib/widgets/markdown/AgentResourceResolver.js.map +1 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.d.ts +63 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.d.ts.map +1 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.js +582 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.js.map +1 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts +69 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts.map +1 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js +374 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js.map +1 -0
- package/lib/widgets/markdown/MarkdownLink.d.ts +3 -1
- package/lib/widgets/markdown/MarkdownLink.d.ts.map +1 -1
- package/lib/widgets/markdown/MarkdownLink.js +41 -14
- package/lib/widgets/markdown/MarkdownLink.js.map +1 -1
- package/lib/widgets/markdown/MarkdownRenderer.d.ts +8 -1
- package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
- package/lib/widgets/markdown/MarkdownRenderer.js +20 -4
- package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
- package/lib/widgets/markdown/index.d.ts +5 -1
- package/lib/widgets/markdown/index.d.ts.map +1 -1
- package/lib/widgets/markdown/index.js +5 -1
- package/lib/widgets/markdown/index.js.map +1 -1
- package/lib/widgets/markdown/normalizeCustomSchemeLinks.d.ts.map +1 -1
- package/lib/widgets/markdown/normalizeCustomSchemeLinks.js +14 -2
- package/lib/widgets/markdown/normalizeCustomSchemeLinks.js.map +1 -1
- package/lib/widgets/markdown/textDiff.d.ts +52 -0
- package/lib/widgets/markdown/textDiff.d.ts.map +1 -0
- package/lib/widgets/markdown/textDiff.js +362 -0
- package/lib/widgets/markdown/textDiff.js.map +1 -0
- package/lib/widgets/markdown/useArtifactContent.d.ts +5 -3
- package/lib/widgets/markdown/useArtifactContent.d.ts.map +1 -1
- package/lib/widgets/markdown/useArtifactContent.js +6 -3
- package/lib/widgets/markdown/useArtifactContent.js.map +1 -1
- package/lib/widgets/markdown/useResolvedUrl.d.ts +1 -5
- package/lib/widgets/markdown/useResolvedUrl.d.ts.map +1 -1
- package/lib/widgets/markdown/useResolvedUrl.js +19 -31
- package/lib/widgets/markdown/useResolvedUrl.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +9 -0
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +20 -17
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
- package/package.json +13 -9
- package/src/__tests__/a11y.test.tsx +4 -1
- package/src/__tests__/axe-helper.ts +17 -7
- package/src/__tests__/setup.ts +25 -0
- package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
- package/src/core/components/shadcn/modal/dialog.tsx +3 -1
- package/src/core/components/shadcn/tabs.test.tsx +65 -0
- package/src/core/components/shadcn/tabs.tsx +25 -3
- package/src/features/agent/chat/AgentRightPanel.tsx +16 -1
- package/src/features/agent/chat/ArtifactsTab.test.tsx +55 -0
- package/src/features/agent/chat/ArtifactsTab.tsx +203 -52
- package/src/features/agent/chat/DocumentEditingActionCard.test.tsx +105 -0
- package/src/features/agent/chat/DocumentEditingActionCard.tsx +210 -0
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +237 -40
- package/src/features/agent/chat/ModernAgentConversation.tsx +247 -75
- package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.test.tsx +79 -0
- package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.tsx +94 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +257 -34
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +217 -105
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +17 -0
- package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.test.tsx +44 -0
- package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx +88 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +30 -46
- package/src/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.tsx +40 -0
- package/src/features/agent/chat/ModernAgentOutput/ResourceChip.test.tsx +148 -0
- package/src/features/agent/chat/ModernAgentOutput/ResourceChip.tsx +141 -0
- package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +33 -1
- package/src/features/agent/chat/ModernAgentOutput/resourceLinks.tsx +43 -0
- package/src/features/agent/chat/ModernAgentOutput/resourceSummary.test.ts +229 -0
- package/src/features/agent/chat/ModernAgentOutput/resourceSummary.ts +152 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +17 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.ts +14 -1
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +188 -0
- package/src/features/agent/chat/hooks/useAgentStream.ts +28 -8
- package/src/features/agent/chat/index.ts +11 -0
- package/src/features/store/objects/DocumentSearchResults.tsx +2 -2
- package/src/features/store/objects/components/ContentOverview.tsx +216 -65
- package/src/features/store/objects/components/DocumentEditingConfigurationSelector.test.ts +34 -0
- package/src/features/store/objects/components/DocumentEditingConfigurationSelector.tsx +211 -0
- package/src/features/store/objects/components/DocumentEditingLockStatus.test.tsx +32 -0
- package/src/features/store/objects/components/DocumentEditingLockStatus.tsx +45 -0
- package/src/features/store/objects/components/DocumentEditingPanel.test.tsx +336 -0
- package/src/features/store/objects/components/DocumentEditingPanel.tsx +1236 -0
- package/src/features/store/objects/components/TextEditorPanel.test.tsx +48 -0
- package/src/features/store/objects/components/TextEditorPanel.tsx +41 -20
- package/src/features/store/objects/components/documentArtifactRefs.test.ts +65 -0
- package/src/features/store/objects/components/documentArtifactRefs.ts +72 -0
- package/src/features/store/objects/components/documentEditingAgentConfig.test.ts +28 -0
- package/src/features/store/objects/components/documentEditingAgentConfig.ts +41 -0
- package/src/features/store/objects/components/documentEditingPrompts.test.ts +26 -0
- package/src/features/store/objects/components/documentEditingPrompts.ts +12 -0
- package/src/features/store/objects/components/documentEditingRun.test.ts +176 -0
- package/src/features/store/objects/components/documentEditingRun.ts +184 -0
- package/src/features/store/objects/components/documentEditingTarget.test.ts +96 -0
- package/src/features/store/objects/components/documentEditingTarget.ts +63 -0
- package/src/features/store/objects/components/index.ts +1 -0
- package/src/features/store/objects/components/useContentPanelHooks.ts +52 -27
- package/src/features/store/objects/components/useDownloadFile.test.ts +20 -0
- package/src/features/store/objects/components/useDownloadFile.ts +5 -1
- package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +2 -2
- package/src/i18n/locales/ar.json +118 -1
- package/src/i18n/locales/de.json +118 -1
- package/src/i18n/locales/en.json +118 -0
- package/src/i18n/locales/es.json +118 -1
- package/src/i18n/locales/fr.json +118 -1
- package/src/i18n/locales/it.json +118 -1
- package/src/i18n/locales/ja.json +118 -1
- package/src/i18n/locales/ko.json +118 -1
- package/src/i18n/locales/pt.json +118 -1
- package/src/i18n/locales/ru.json +118 -1
- package/src/i18n/locales/tr.json +118 -1
- package/src/i18n/locales/zh-TW.json +118 -1
- package/src/i18n/locales/zh.json +118 -1
- package/src/rich-text/EditorToolbar.tsx +708 -0
- package/src/rich-text/VertesiaRichTextEditor.test.tsx +211 -0
- package/src/rich-text/VertesiaRichTextEditor.tsx +241 -0
- package/src/rich-text/index.ts +9 -0
- package/src/session/UserSession.test.ts +11 -11
- package/src/widgets/markdown/AgentResourceResolver.test.ts +24 -0
- package/src/widgets/markdown/AgentResourceResolver.tsx +70 -0
- package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +537 -0
- package/src/widgets/markdown/ArtifactEditingSurface.tsx +878 -0
- package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +484 -0
- package/src/widgets/markdown/CollaborativeMarkdownRenderer.tsx +825 -0
- package/src/widgets/markdown/MarkdownLink.test.tsx +122 -0
- package/src/widgets/markdown/MarkdownLink.tsx +102 -17
- package/src/widgets/markdown/MarkdownRenderer.tsx +30 -3
- package/src/widgets/markdown/index.ts +39 -1
- package/src/widgets/markdown/normalizeCustomSchemeLinks.ts +15 -2
- package/src/widgets/markdown/textDiff.test.ts +156 -0
- package/src/widgets/markdown/textDiff.ts +399 -0
- package/src/widgets/markdown/useArtifactContent.ts +9 -3
- package/src/widgets/markdown/useResolvedUrl.test.ts +29 -40
- package/src/widgets/markdown/useResolvedUrl.ts +33 -35
- package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +26 -0
- package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +23 -18
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { AgentsApi } from '@vertesia/client';
|
|
2
|
+
import type { AgentRun } from '@vertesia/common';
|
|
3
|
+
|
|
4
|
+
const DOCUMENT_EDITING_TAG = 'document-editing';
|
|
5
|
+
const DOCUMENT_ROOT_TAG_PREFIX = 'document-root:';
|
|
6
|
+
const LEGACY_DOCUMENT_TAG_PREFIX = 'document:';
|
|
7
|
+
export const DOCUMENT_EDITING_DEFAULT_INTERACTION = 'sys:GeneralAgent';
|
|
8
|
+
const openDocumentEditingScopes = new Set<string>();
|
|
9
|
+
const MARKDOWN_CONTENT_TYPES = new Set(['text/markdown', 'text/x-markdown']);
|
|
10
|
+
const DOCUMENT_EDITING_CONTENT_TYPES = new Set([...MARKDOWN_CONTENT_TYPES, 'text/plain']);
|
|
11
|
+
|
|
12
|
+
export type DocumentEditingRunProperties = {
|
|
13
|
+
resource_kind: 'store_document';
|
|
14
|
+
document_id: string;
|
|
15
|
+
document_root_id: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface DocumentEditingRunIdentity {
|
|
19
|
+
tags: string[];
|
|
20
|
+
properties: DocumentEditingRunProperties;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type DocumentEditingRunApi = Pick<AgentsApi, 'list' | 'retrieve' | 'search'>;
|
|
24
|
+
|
|
25
|
+
export function createDocumentEditingScopeKey(projectId: string, documentRootId: string): string {
|
|
26
|
+
return `${projectId}:${documentRootId}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isDocumentEditingScopeOpen(scopeKey: string): boolean {
|
|
30
|
+
return openDocumentEditingScopes.has(scopeKey);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function setDocumentEditingScopeOpen(scopeKey: string, isOpen: boolean): void {
|
|
34
|
+
if (isOpen) {
|
|
35
|
+
openDocumentEditingScopes.add(scopeKey);
|
|
36
|
+
} else {
|
|
37
|
+
openDocumentEditingScopes.delete(scopeKey);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getRecord(value: unknown): Record<string, unknown> | undefined {
|
|
42
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function documentRootTag(documentRootId: string): string {
|
|
46
|
+
return `${DOCUMENT_ROOT_TAG_PREFIX}${documentRootId}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function legacyDocumentTag(documentId: string): string {
|
|
50
|
+
return `${LEGACY_DOCUMENT_TAG_PREFIX}${documentId}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createDocumentEditingRunIdentity(
|
|
54
|
+
documentId: string,
|
|
55
|
+
documentRootId: string,
|
|
56
|
+
): DocumentEditingRunIdentity {
|
|
57
|
+
return {
|
|
58
|
+
tags: [DOCUMENT_EDITING_TAG, documentRootTag(documentRootId), legacyDocumentTag(documentId)],
|
|
59
|
+
properties: {
|
|
60
|
+
resource_kind: 'store_document',
|
|
61
|
+
document_id: documentId,
|
|
62
|
+
document_root_id: documentRootId,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getDocumentTextActionAccess(canEdit: boolean, canCollaborate: boolean) {
|
|
68
|
+
return {
|
|
69
|
+
canEdit,
|
|
70
|
+
canCollaborate,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizedContentType(contentType: string | undefined): string | undefined {
|
|
75
|
+
return contentType?.split(';', 1)[0]?.trim().toLowerCase() || undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isMarkdownContentType(contentType: string | undefined): boolean {
|
|
79
|
+
const normalized = normalizedContentType(contentType);
|
|
80
|
+
return normalized !== undefined && MARKDOWN_CONTENT_TYPES.has(normalized);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isDocumentEditingContentType(contentType: string | undefined): boolean {
|
|
84
|
+
const normalized = normalizedContentType(contentType);
|
|
85
|
+
return normalized !== undefined && DOCUMENT_EDITING_CONTENT_TYPES.has(normalized);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function isDocumentEditingRun(
|
|
89
|
+
run: AgentRun,
|
|
90
|
+
documentId: string,
|
|
91
|
+
documentRootId: string,
|
|
92
|
+
startedBy: string,
|
|
93
|
+
interaction = DOCUMENT_EDITING_DEFAULT_INTERACTION,
|
|
94
|
+
): boolean {
|
|
95
|
+
if (run.interaction !== interaction || run.started_by !== startedBy) return false;
|
|
96
|
+
// A cancelled run was explicitly terminated by the user; never resume it as the editing session.
|
|
97
|
+
if (run.status === 'cancelled') return false;
|
|
98
|
+
|
|
99
|
+
const tags = run.tags ?? [];
|
|
100
|
+
if (!tags.includes(DOCUMENT_EDITING_TAG)) return false;
|
|
101
|
+
|
|
102
|
+
const properties = getRecord(run.properties);
|
|
103
|
+
const hasStableRootTag = tags.includes(documentRootTag(documentRootId));
|
|
104
|
+
if (hasStableRootTag) {
|
|
105
|
+
return properties?.resource_kind === 'store_document' && properties.document_root_id === documentRootId;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Runs created before stable root properties were added only carry a document tag.
|
|
109
|
+
return tags.includes(legacyDocumentTag(documentRootId)) || tags.includes(legacyDocumentTag(documentId));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function retrieveMatchingRun(
|
|
113
|
+
agents: DocumentEditingRunApi,
|
|
114
|
+
runIds: string[],
|
|
115
|
+
documentId: string,
|
|
116
|
+
documentRootId: string,
|
|
117
|
+
startedBy: string,
|
|
118
|
+
interaction: string,
|
|
119
|
+
): Promise<AgentRun | undefined> {
|
|
120
|
+
for (const runId of runIds) {
|
|
121
|
+
try {
|
|
122
|
+
const run = await agents.retrieve(runId);
|
|
123
|
+
if (isDocumentEditingRun(run, documentId, documentRootId, startedBy, interaction)) return run;
|
|
124
|
+
} catch {
|
|
125
|
+
// The run may have been deleted between search and retrieval. Try the next candidate.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function findDocumentEditingRun(
|
|
132
|
+
agents: DocumentEditingRunApi,
|
|
133
|
+
documentId: string,
|
|
134
|
+
documentRootId: string,
|
|
135
|
+
startedBy: string,
|
|
136
|
+
interaction = DOCUMENT_EDITING_DEFAULT_INTERACTION,
|
|
137
|
+
): Promise<AgentRun | undefined> {
|
|
138
|
+
const lookupTags = [
|
|
139
|
+
documentRootTag(documentRootId),
|
|
140
|
+
legacyDocumentTag(documentRootId),
|
|
141
|
+
legacyDocumentTag(documentId),
|
|
142
|
+
];
|
|
143
|
+
const searchedRunIds = new Set<string>();
|
|
144
|
+
|
|
145
|
+
for (const tag of new Set(lookupTags)) {
|
|
146
|
+
try {
|
|
147
|
+
const response = await agents.search({
|
|
148
|
+
interaction,
|
|
149
|
+
started_by: startedBy,
|
|
150
|
+
tags: [tag],
|
|
151
|
+
limit: 20,
|
|
152
|
+
sort: ['updated_at:desc'],
|
|
153
|
+
});
|
|
154
|
+
const candidateIds = response.hits.map((hit) => hit.id).filter((id) => !searchedRunIds.has(id));
|
|
155
|
+
for (const id of candidateIds) {
|
|
156
|
+
searchedRunIds.add(id);
|
|
157
|
+
}
|
|
158
|
+
const run = await retrieveMatchingRun(
|
|
159
|
+
agents,
|
|
160
|
+
candidateIds,
|
|
161
|
+
documentId,
|
|
162
|
+
documentRootId,
|
|
163
|
+
startedBy,
|
|
164
|
+
interaction,
|
|
165
|
+
);
|
|
166
|
+
if (run) return run;
|
|
167
|
+
} catch {
|
|
168
|
+
// Fall through to the authoritative Mongo-backed list lookup below.
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const response = await agents.list({
|
|
174
|
+
interaction,
|
|
175
|
+
started_by: startedBy,
|
|
176
|
+
limit: 100,
|
|
177
|
+
sort: 'updated_at',
|
|
178
|
+
order: 'desc',
|
|
179
|
+
});
|
|
180
|
+
return response.items.find(
|
|
181
|
+
(run): run is AgentRun =>
|
|
182
|
+
run.run_kind === 'agent' && isDocumentEditingRun(run, documentId, documentRootId, startedBy, interaction),
|
|
183
|
+
);
|
|
184
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ContentObject, ContentObjectItem } from '@vertesia/common';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import {
|
|
4
|
+
type DocumentEditingTargetApi,
|
|
5
|
+
DocumentEditingTargetError,
|
|
6
|
+
resolveDocumentEditingTarget,
|
|
7
|
+
} from './documentEditingTarget.js';
|
|
8
|
+
|
|
9
|
+
function contentObject(id: string, head: boolean, etag = `${id}-etag`): ContentObject {
|
|
10
|
+
return {
|
|
11
|
+
id,
|
|
12
|
+
content: { source: `gs://bucket/${id}.md`, type: 'text/markdown', etag },
|
|
13
|
+
revision: { root: 'root-id', parent: 'root-id', head },
|
|
14
|
+
} as unknown as ContentObject;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function revisionItem(id: string, head: boolean): ContentObjectItem {
|
|
18
|
+
return {
|
|
19
|
+
id,
|
|
20
|
+
revision: { root: 'root-id', parent: 'root-id', head },
|
|
21
|
+
} as unknown as ContentObjectItem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function targetApi(): DocumentEditingTargetApi & {
|
|
25
|
+
retrieve: ReturnType<typeof vi.fn<(id: string) => Promise<ContentObject>>>;
|
|
26
|
+
getRevisions: ReturnType<typeof vi.fn<(id: string) => Promise<ContentObjectItem[]>>>;
|
|
27
|
+
getObjectText: ReturnType<typeof vi.fn<(id: string) => Promise<{ text?: string }>>>;
|
|
28
|
+
} {
|
|
29
|
+
return {
|
|
30
|
+
retrieve: vi.fn<(id: string) => Promise<ContentObject>>(),
|
|
31
|
+
getRevisions: vi.fn<(id: string) => Promise<ContentObjectItem[]>>(),
|
|
32
|
+
getObjectText: vi.fn<(id: string) => Promise<{ text?: string }>>(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('resolveDocumentEditingTarget', () => {
|
|
37
|
+
it('uses a freshly retrieved head revision and its text', async () => {
|
|
38
|
+
const objects = targetApi();
|
|
39
|
+
objects.retrieve.mockResolvedValue(contentObject('head-id', true));
|
|
40
|
+
objects.getObjectText.mockResolvedValue({ text: '# Current head' });
|
|
41
|
+
|
|
42
|
+
await expect(resolveDocumentEditingTarget(objects, 'head-id')).resolves.toEqual({
|
|
43
|
+
id: 'head-id',
|
|
44
|
+
etag: 'head-id-etag',
|
|
45
|
+
content: '# Current head',
|
|
46
|
+
});
|
|
47
|
+
expect(objects.getRevisions).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('resolves a historical revision to the unique current head', async () => {
|
|
51
|
+
const objects = targetApi();
|
|
52
|
+
objects.retrieve
|
|
53
|
+
.mockResolvedValueOnce(contentObject('old-id', false))
|
|
54
|
+
.mockResolvedValueOnce(contentObject('head-id', true));
|
|
55
|
+
objects.getRevisions.mockResolvedValue([revisionItem('old-id', false), revisionItem('head-id', true)]);
|
|
56
|
+
objects.getObjectText.mockResolvedValue({ text: '# Current head' });
|
|
57
|
+
|
|
58
|
+
await expect(resolveDocumentEditingTarget(objects, 'old-id')).resolves.toEqual({
|
|
59
|
+
id: 'head-id',
|
|
60
|
+
etag: 'head-id-etag',
|
|
61
|
+
content: '# Current head',
|
|
62
|
+
});
|
|
63
|
+
expect(objects.retrieve).toHaveBeenNthCalledWith(2, 'head-id');
|
|
64
|
+
expect(objects.getObjectText).toHaveBeenCalledWith('head-id');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('rejects a historical revision when the current head cannot be proven', async () => {
|
|
68
|
+
const objects = targetApi();
|
|
69
|
+
objects.retrieve.mockResolvedValue(contentObject('old-id', false));
|
|
70
|
+
objects.getRevisions.mockResolvedValue([revisionItem('old-id', false)]);
|
|
71
|
+
|
|
72
|
+
await expect(resolveDocumentEditingTarget(objects, 'old-id')).rejects.toBeInstanceOf(
|
|
73
|
+
DocumentEditingTargetError,
|
|
74
|
+
);
|
|
75
|
+
expect(objects.getObjectText).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('rejects when the resolved head changes before it can be loaded', async () => {
|
|
79
|
+
const objects = targetApi();
|
|
80
|
+
objects.retrieve
|
|
81
|
+
.mockResolvedValueOnce(contentObject('old-id', false))
|
|
82
|
+
.mockResolvedValueOnce(contentObject('former-head-id', false));
|
|
83
|
+
objects.getRevisions.mockResolvedValue([revisionItem('old-id', false), revisionItem('former-head-id', true)]);
|
|
84
|
+
|
|
85
|
+
await expect(resolveDocumentEditingTarget(objects, 'old-id')).rejects.toThrow('is no longer the current head');
|
|
86
|
+
expect(objects.getObjectText).not.toHaveBeenCalled();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('rejects a target without a content ETag', async () => {
|
|
90
|
+
const objects = targetApi();
|
|
91
|
+
objects.retrieve.mockResolvedValue(contentObject('head-id', true, ''));
|
|
92
|
+
|
|
93
|
+
await expect(resolveDocumentEditingTarget(objects, 'head-id')).rejects.toThrow('has no content ETag');
|
|
94
|
+
expect(objects.getObjectText).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ContentObject, ContentObjectItem, ContentObjectTextResponse } from '@vertesia/common';
|
|
2
|
+
|
|
3
|
+
export interface DocumentEditingTargetApi {
|
|
4
|
+
retrieve(id: string): Promise<ContentObject>;
|
|
5
|
+
getRevisions(id: string): Promise<ContentObjectItem[]>;
|
|
6
|
+
getObjectText(id: string): Promise<ContentObjectTextResponse>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ResolvedDocumentEditingTarget {
|
|
10
|
+
id: string;
|
|
11
|
+
etag: string;
|
|
12
|
+
content: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class DocumentEditingTargetError extends Error {
|
|
16
|
+
constructor(message: string, cause?: unknown) {
|
|
17
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
18
|
+
this.name = 'DocumentEditingTargetError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the current head and load its write precondition and text as one unit.
|
|
24
|
+
* Nothing from a historical revision is returned when the head cannot be proven.
|
|
25
|
+
*/
|
|
26
|
+
export async function resolveDocumentEditingTarget(
|
|
27
|
+
objects: DocumentEditingTargetApi,
|
|
28
|
+
requestedDocumentId: string,
|
|
29
|
+
): Promise<ResolvedDocumentEditingTarget> {
|
|
30
|
+
const requestedObject = await objects.retrieve(requestedDocumentId);
|
|
31
|
+
let targetObject = requestedObject;
|
|
32
|
+
const resolvingHistoricalRevision = Boolean(requestedObject.revision && !requestedObject.revision.head);
|
|
33
|
+
|
|
34
|
+
if (resolvingHistoricalRevision) {
|
|
35
|
+
const revisions = await objects.getRevisions(requestedObject.id);
|
|
36
|
+
const heads = revisions.filter((revision) => revision.revision?.head === true);
|
|
37
|
+
if (heads.length !== 1) {
|
|
38
|
+
throw new DocumentEditingTargetError(
|
|
39
|
+
`Expected one head revision for document ${requestedDocumentId}, found ${heads.length}`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
targetObject = await objects.retrieve(heads[0].id);
|
|
43
|
+
if (targetObject.revision?.head !== true) {
|
|
44
|
+
throw new DocumentEditingTargetError(`Resolved document ${targetObject.id} is no longer the current head`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const etag = targetObject.content?.etag;
|
|
49
|
+
if (!etag) {
|
|
50
|
+
throw new DocumentEditingTargetError(`Document ${targetObject.id} has no content ETag`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const response = await objects.getObjectText(targetObject.id);
|
|
54
|
+
if (typeof response.text !== 'string') {
|
|
55
|
+
throw new DocumentEditingTargetError(`Document ${targetObject.id} has no text content`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
id: targetObject.id,
|
|
60
|
+
etag,
|
|
61
|
+
content: response.text,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type DocAnalyzerProgress, MarkdownRenditionFormat, WorkflowExecutionStatus } from '@vertesia/common';
|
|
2
2
|
import { i18nInstance, NAMESPACE } from '@vertesia/ui/i18n';
|
|
3
3
|
import { useUserSession } from '@vertesia/ui/session';
|
|
4
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
5
5
|
|
|
6
6
|
// Maximum text size before cropping (128K characters)
|
|
7
7
|
const MAX_TEXT_DISPLAY_SIZE = 128 * 1024;
|
|
@@ -9,7 +9,7 @@ const MAX_TEXT_DISPLAY_SIZE = 128 * 1024;
|
|
|
9
9
|
/**
|
|
10
10
|
* Hook for managing object text loading and cropping.
|
|
11
11
|
*/
|
|
12
|
-
export function useObjectText(objectId: string, initialText?: string, loadOnMount = false) {
|
|
12
|
+
export function useObjectText(objectId: string, initialText?: string, loadOnMount = false, changeGroupId = objectId) {
|
|
13
13
|
const { store } = useUserSession();
|
|
14
14
|
|
|
15
15
|
const [fullText, setFullText] = useState<string | undefined>(initialText);
|
|
@@ -21,56 +21,81 @@ export function useObjectText(objectId: string, initialText?: string, loadOnMoun
|
|
|
21
21
|
});
|
|
22
22
|
const [isLoading, setIsLoading] = useState(false);
|
|
23
23
|
const [isCropped, setIsCropped] = useState(() => !!initialText && initialText.length > MAX_TEXT_DISPLAY_SIZE);
|
|
24
|
+
const [changeHighlight, setChangeHighlight] = useState<{ previousText: string; version: number }>();
|
|
25
|
+
const fullTextRef = useRef(initialText);
|
|
26
|
+
const objectIdRef = useRef(objectId);
|
|
27
|
+
const changeGroupIdRef = useRef(changeGroupId);
|
|
28
|
+
const suppressNextHighlightRef = useRef(false);
|
|
29
|
+
|
|
30
|
+
const applyText = useCallback((nextText: string | undefined, shouldHighlight = true) => {
|
|
31
|
+
const previousText = fullTextRef.current;
|
|
32
|
+
if (shouldHighlight && previousText && nextText && previousText !== nextText) {
|
|
33
|
+
setChangeHighlight((current) => ({
|
|
34
|
+
previousText,
|
|
35
|
+
version: (current?.version ?? 0) + 1,
|
|
36
|
+
}));
|
|
37
|
+
} else if (!shouldHighlight) {
|
|
38
|
+
setChangeHighlight(undefined);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fullTextRef.current = nextText;
|
|
42
|
+
setFullText(nextText);
|
|
43
|
+
if (nextText && nextText.length > MAX_TEXT_DISPLAY_SIZE) {
|
|
44
|
+
setDisplayText(nextText.substring(0, MAX_TEXT_DISPLAY_SIZE));
|
|
45
|
+
setIsCropped(true);
|
|
46
|
+
} else {
|
|
47
|
+
setDisplayText(nextText);
|
|
48
|
+
setIsCropped(false);
|
|
49
|
+
}
|
|
50
|
+
}, []);
|
|
24
51
|
|
|
25
52
|
const loadText = useCallback(() => {
|
|
53
|
+
const requestedObjectId = objectId;
|
|
54
|
+
const requestedChangeGroupId = changeGroupId;
|
|
26
55
|
setIsLoading(true);
|
|
27
56
|
store.objects
|
|
28
57
|
.getObjectText(objectId)
|
|
29
58
|
.then((res) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
setDisplayText(res.text);
|
|
36
|
-
setIsCropped(false);
|
|
37
|
-
}
|
|
59
|
+
if (objectIdRef.current !== requestedObjectId) return;
|
|
60
|
+
const shouldHighlight =
|
|
61
|
+
changeGroupIdRef.current === requestedChangeGroupId && !suppressNextHighlightRef.current;
|
|
62
|
+
applyText(res.text, shouldHighlight);
|
|
63
|
+
suppressNextHighlightRef.current = false;
|
|
38
64
|
})
|
|
39
65
|
.catch((err) => {
|
|
40
66
|
console.error('Failed to load text', err);
|
|
41
|
-
setFullText(undefined);
|
|
42
|
-
setDisplayText(undefined);
|
|
43
|
-
setIsCropped(false);
|
|
44
67
|
})
|
|
45
68
|
.finally(() => {
|
|
46
|
-
setIsLoading(false);
|
|
69
|
+
if (objectIdRef.current === requestedObjectId) setIsLoading(false);
|
|
47
70
|
});
|
|
48
|
-
}, [objectId, store]);
|
|
71
|
+
}, [applyText, changeGroupId, objectId, store]);
|
|
49
72
|
|
|
50
73
|
// Reset state when objectId changes
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
useLayoutEffect(() => {
|
|
75
|
+
const objectChanged = objectIdRef.current !== objectId;
|
|
76
|
+
const changeGroupChanged = changeGroupIdRef.current !== changeGroupId;
|
|
77
|
+
objectIdRef.current = objectId;
|
|
78
|
+
changeGroupIdRef.current = changeGroupId;
|
|
79
|
+
if (changeGroupChanged) suppressNextHighlightRef.current = true;
|
|
80
|
+
|
|
81
|
+
// Keep the previous revision mounted until the next revision's text is ready.
|
|
82
|
+
if (initialText !== undefined) {
|
|
83
|
+
applyText(initialText, !changeGroupChanged);
|
|
84
|
+
suppressNextHighlightRef.current = false;
|
|
61
85
|
}
|
|
62
86
|
|
|
63
87
|
// Load text if requested
|
|
64
|
-
if (loadOnMount &&
|
|
88
|
+
if (loadOnMount && initialText === undefined && (objectChanged || fullTextRef.current === undefined)) {
|
|
65
89
|
loadText();
|
|
66
90
|
}
|
|
67
|
-
}, [initialText, loadOnMount, loadText]);
|
|
91
|
+
}, [applyText, changeGroupId, initialText, loadOnMount, loadText, objectId]);
|
|
68
92
|
|
|
69
93
|
return {
|
|
70
94
|
fullText,
|
|
71
95
|
displayText,
|
|
72
96
|
isLoading,
|
|
73
97
|
isCropped,
|
|
98
|
+
changeHighlight,
|
|
74
99
|
loadText,
|
|
75
100
|
};
|
|
76
101
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ContentObject } from '@vertesia/common';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { getContentObjectDownloadName } from './useDownloadFile.js';
|
|
4
|
+
|
|
5
|
+
describe('getContentObjectDownloadName', () => {
|
|
6
|
+
it('preserves the original source extension instead of an extensionless display name', () => {
|
|
7
|
+
const object = {
|
|
8
|
+
name: 'Quarterly Report',
|
|
9
|
+
content: { name: 'quarterly-report.md', type: 'text/markdown' },
|
|
10
|
+
} as ContentObject;
|
|
11
|
+
|
|
12
|
+
expect(getContentObjectDownloadName(object)).toBe('quarterly-report.md');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('falls back to the object name when the content has no source name', () => {
|
|
16
|
+
const object = { name: 'Quarterly Report' } as ContentObject;
|
|
17
|
+
|
|
18
|
+
expect(getContentObjectDownloadName(object)).toBe('Quarterly Report');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VertesiaClient, ZenoClient } from '@vertesia/client';
|
|
2
|
-
import type { MarkdownRenditionFormat, RenderMarkdownPayload } from '@vertesia/common';
|
|
2
|
+
import type { ContentObject, MarkdownRenditionFormat, RenderMarkdownPayload } from '@vertesia/common';
|
|
3
3
|
import type { ToastFn } from '@vertesia/ui/core';
|
|
4
4
|
import { i18nInstance, NAMESPACE } from '@vertesia/ui/i18n';
|
|
5
5
|
import { useCallback, useState } from 'react';
|
|
@@ -37,6 +37,10 @@ export interface UseDownloadFileResult {
|
|
|
37
37
|
isDownloading: boolean;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
export function getContentObjectDownloadName(object: Pick<ContentObject, 'name' | 'content'>): string | undefined {
|
|
41
|
+
return object.content?.name || object.name;
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
/**
|
|
41
45
|
* Hook for downloading files from various sources.
|
|
42
46
|
* Handles GCS URIs (via client.files API), direct URLs, and markdown rendering.
|
|
@@ -71,7 +71,7 @@ function StartWorkflowModal({ objectIds, onClose }: StartWorkflowModalProps) {
|
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
return (
|
|
74
|
-
<Modal isOpen onClose={onClose}>
|
|
74
|
+
<Modal isOpen onClose={onClose} size="lg">
|
|
75
75
|
<ModalTitle>{t('store.actions.startWorkflowByRule')}</ModalTitle>
|
|
76
76
|
<ModalBody>
|
|
77
77
|
<div className="pb-2">{t('store.actions.chooseWorkflowRule')}</div>
|
|
@@ -82,7 +82,7 @@ function StartWorkflowModal({ objectIds, onClose }: StartWorkflowModalProps) {
|
|
|
82
82
|
) : (
|
|
83
83
|
<div className="max-h-[420px] overflow-y-auto border-border border rounded-md">
|
|
84
84
|
<SelectList
|
|
85
|
-
className="text-start"
|
|
85
|
+
className="text-start w-full"
|
|
86
86
|
options={rules ?? []}
|
|
87
87
|
value={selected}
|
|
88
88
|
onChange={setSelected}
|