@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,211 @@
|
|
|
1
|
+
/** @vitest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { MarkdownRichTextEditor, type MarkdownRichTextEditorProps, setEditorMarkdown } from '@vertesia/rich-text';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { I18nProvider } from '../i18n/index.js';
|
|
7
|
+
import {
|
|
8
|
+
VertesiaMarkdownComponentEditor,
|
|
9
|
+
VertesiaMarkdownDocumentEditor,
|
|
10
|
+
VertesiaMarkdownRichTextEditor,
|
|
11
|
+
vertesiaRichTextRenderers,
|
|
12
|
+
} from './VertesiaRichTextEditor.js';
|
|
13
|
+
|
|
14
|
+
describe('VertesiaMarkdownRichTextEditor', () => {
|
|
15
|
+
it('renders Markdown and emits serialized Markdown after an editor update', async () => {
|
|
16
|
+
const onChange = vi.fn();
|
|
17
|
+
let editor: Parameters<NonNullable<MarkdownRichTextEditorProps['onEditor']>>[0] = null;
|
|
18
|
+
|
|
19
|
+
render(
|
|
20
|
+
<VertesiaMarkdownRichTextEditor
|
|
21
|
+
value="# Original heading"
|
|
22
|
+
onChange={onChange}
|
|
23
|
+
onEditor={(nextEditor) => {
|
|
24
|
+
editor = nextEditor;
|
|
25
|
+
}}
|
|
26
|
+
/>,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
expect(await screen.findByRole('heading', { name: 'Original heading' })).not.toBeNull();
|
|
30
|
+
await waitFor(() => expect(editor).not.toBeNull());
|
|
31
|
+
|
|
32
|
+
act(() => {
|
|
33
|
+
if (editor) setEditorMarkdown(editor, '## Updated heading', true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(await screen.findByRole('heading', { name: 'Updated heading' })).not.toBeNull();
|
|
37
|
+
expect(onChange).toHaveBeenLastCalledWith(expect.stringContaining('## Updated heading'));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('provides adapters for each Vertesia-specific Markdown surface', () => {
|
|
41
|
+
expect(vertesiaRichTextRenderers.codeBlock).toBeTypeOf('function');
|
|
42
|
+
expect(vertesiaRichTextRenderers.image).toBeTypeOf('function');
|
|
43
|
+
expect(vertesiaRichTextRenderers.link).toBeTypeOf('function');
|
|
44
|
+
expect(vertesiaRichTextRenderers.opaqueBlock).toBeTypeOf('function');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('keeps the editor instance when a consumer passes new renderer component identities', async () => {
|
|
48
|
+
const onEditor = vi.fn();
|
|
49
|
+
const view = render(<MarkdownRichTextEditor value="Paragraph" codeBlock={() => null} onEditor={onEditor} />);
|
|
50
|
+
await screen.findByText('Paragraph');
|
|
51
|
+
const initialEditor = onEditor.mock.calls.find(([value]) => value)?.[0];
|
|
52
|
+
|
|
53
|
+
view.rerender(<MarkdownRichTextEditor value="Paragraph" codeBlock={() => null} onEditor={onEditor} />);
|
|
54
|
+
|
|
55
|
+
expect(onEditor.mock.calls.filter(([value]) => value).at(-1)?.[0]).toBe(initialEditor);
|
|
56
|
+
expect(new Set(onEditor.mock.calls.flatMap(([value]) => (value ? [value] : [])))).toHaveLength(1);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('defers external values while focused so the caret is not reset', async () => {
|
|
60
|
+
const view = render(<MarkdownRichTextEditor value="Original paragraph" />);
|
|
61
|
+
const textbox = await screen.findByRole('textbox');
|
|
62
|
+
fireEvent.focus(textbox);
|
|
63
|
+
|
|
64
|
+
view.rerender(<MarkdownRichTextEditor value="External paragraph" />);
|
|
65
|
+
expect(screen.getByText('Original paragraph')).not.toBeNull();
|
|
66
|
+
expect(screen.queryByText('External paragraph')).toBeNull();
|
|
67
|
+
|
|
68
|
+
fireEvent.blur(textbox);
|
|
69
|
+
expect(await screen.findByText('External paragraph')).not.toBeNull();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('offers a formatting toolbar for both the compact component editor and the full-document editor', async () => {
|
|
73
|
+
const { rerender } = render(
|
|
74
|
+
<I18nProvider lng="en">
|
|
75
|
+
<VertesiaMarkdownComponentEditor value="Component text" />
|
|
76
|
+
</I18nProvider>,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(await screen.findByText('Component text')).not.toBeNull();
|
|
80
|
+
// The compact component editor now carries the same formatting toolbar as the document editor.
|
|
81
|
+
expect(await screen.findByRole('toolbar')).not.toBeNull();
|
|
82
|
+
|
|
83
|
+
rerender(
|
|
84
|
+
<I18nProvider lng="en">
|
|
85
|
+
<VertesiaMarkdownDocumentEditor value="# Full document" />
|
|
86
|
+
</I18nProvider>,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(await screen.findByRole('heading', { name: 'Full document' })).not.toBeNull();
|
|
90
|
+
expect(await screen.findByRole('toolbar')).not.toBeNull();
|
|
91
|
+
expect(screen.getByRole('textbox', { name: 'Markdown document editor' })).not.toBeNull();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('puts the document hand-off in the editor toolbar and highlights it when edits are pending', async () => {
|
|
95
|
+
const onSendChangesToAgent = vi.fn();
|
|
96
|
+
const view = render(
|
|
97
|
+
<I18nProvider lng="en">
|
|
98
|
+
<VertesiaMarkdownDocumentEditor
|
|
99
|
+
value="Document text"
|
|
100
|
+
onSendChangesToAgent={onSendChangesToAgent}
|
|
101
|
+
hasUnsentChanges={false}
|
|
102
|
+
/>
|
|
103
|
+
</I18nProvider>,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const inactiveButton = await screen.findByRole('button', { name: 'Send changes to agent' });
|
|
107
|
+
expect(screen.getByRole('toolbar').contains(inactiveButton)).toBe(true);
|
|
108
|
+
expect(inactiveButton).toHaveProperty('disabled', true);
|
|
109
|
+
expect(inactiveButton.className).not.toContain('bg-primary');
|
|
110
|
+
|
|
111
|
+
view.rerender(
|
|
112
|
+
<I18nProvider lng="en">
|
|
113
|
+
<VertesiaMarkdownDocumentEditor
|
|
114
|
+
value="Document text"
|
|
115
|
+
onSendChangesToAgent={onSendChangesToAgent}
|
|
116
|
+
hasUnsentChanges
|
|
117
|
+
/>
|
|
118
|
+
</I18nProvider>,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const activeButton = screen.getByRole('button', { name: 'Send changes to agent' });
|
|
122
|
+
expect(activeButton).toHaveProperty('disabled', false);
|
|
123
|
+
expect(activeButton.className).toContain('bg-primary');
|
|
124
|
+
fireEvent.click(activeButton);
|
|
125
|
+
expect(onSendChangesToAgent).toHaveBeenCalledTimes(1);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('sends selected-text comments while full-document content editing is locked', async () => {
|
|
129
|
+
const onSendComment = vi.fn();
|
|
130
|
+
let editor: Parameters<NonNullable<MarkdownRichTextEditorProps['onEditor']>>[0] = null;
|
|
131
|
+
render(
|
|
132
|
+
<I18nProvider lng="en">
|
|
133
|
+
<VertesiaMarkdownDocumentEditor
|
|
134
|
+
value="Locked paragraph."
|
|
135
|
+
editable={false}
|
|
136
|
+
onSendComment={onSendComment}
|
|
137
|
+
onEditor={(nextEditor) => {
|
|
138
|
+
editor = nextEditor;
|
|
139
|
+
}}
|
|
140
|
+
/>
|
|
141
|
+
</I18nProvider>,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await waitFor(() => expect(editor).not.toBeNull());
|
|
145
|
+
act(() => {
|
|
146
|
+
editor?.commands.setTextSelection({ from: 1, to: 7 });
|
|
147
|
+
});
|
|
148
|
+
expect(screen.getByRole('button', { name: 'Bold' })).toHaveProperty('disabled', true);
|
|
149
|
+
const commentButton = await screen.findByRole('button', { name: 'Comment on selection' });
|
|
150
|
+
expect(screen.getByRole('toolbar').contains(commentButton)).toBe(false);
|
|
151
|
+
expect(commentButton.parentElement?.className).toContain('pointer-events-auto');
|
|
152
|
+
expect(commentButton.parentElement?.className).toContain('z-100');
|
|
153
|
+
fireEvent.click(commentButton);
|
|
154
|
+
expect(screen.getByRole('dialog', { name: 'Comment on selection' })).not.toBeNull();
|
|
155
|
+
fireEvent.change(screen.getByPlaceholderText('Describe how the agent should improve this section...'), {
|
|
156
|
+
target: { value: 'Make this claim measurable.' },
|
|
157
|
+
});
|
|
158
|
+
fireEvent.click(screen.getByRole('button', { name: 'Add comment' }));
|
|
159
|
+
fireEvent.click(screen.getByRole('button', { name: 'Send to agent' }));
|
|
160
|
+
|
|
161
|
+
await waitFor(() => expect(onSendComment).toHaveBeenCalledTimes(1));
|
|
162
|
+
expect(onSendComment).toHaveBeenCalledWith(expect.stringContaining('“Locked”'));
|
|
163
|
+
expect(onSendComment).toHaveBeenCalledWith(expect.stringContaining('Make this claim measurable.'));
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('opens structurally preserving normalized Markdown directly in rich-text mode', async () => {
|
|
167
|
+
const onChange = vi.fn();
|
|
168
|
+
render(
|
|
169
|
+
<I18nProvider lng="en">
|
|
170
|
+
<VertesiaMarkdownDocumentEditor value={'Setext heading\n=============='} onChange={onChange} />
|
|
171
|
+
</I18nProvider>,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
expect(await screen.findByRole('heading', { name: 'Setext heading' })).not.toBeNull();
|
|
175
|
+
expect(screen.getByRole('textbox', { name: 'Markdown document editor' })).not.toBeNull();
|
|
176
|
+
expect(screen.queryByRole('heading', { name: 'Some Markdown formatting may change' })).toBeNull();
|
|
177
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('lets the user preserve Markdown source when normalization is lossy', async () => {
|
|
181
|
+
const onChange = vi.fn();
|
|
182
|
+
render(
|
|
183
|
+
<I18nProvider lng="en">
|
|
184
|
+
<VertesiaMarkdownDocumentEditor value="#" onChange={onChange} />
|
|
185
|
+
</I18nProvider>,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
expect(await screen.findByRole('heading', { name: 'Some Markdown formatting may change' })).not.toBeNull();
|
|
189
|
+
fireEvent.click(screen.getByRole('button', { name: 'Edit Markdown source' }));
|
|
190
|
+
|
|
191
|
+
const sourceEditor = screen.getByRole('textbox', { name: 'Markdown source editor' });
|
|
192
|
+
expect((sourceEditor as HTMLTextAreaElement).value).toBe('#');
|
|
193
|
+
fireEvent.change(sourceEditor, { target: { value: '##' } });
|
|
194
|
+
expect(onChange).toHaveBeenLastCalledWith('##');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('lets the user accept a lossy conversion and continue in rich-text mode', async () => {
|
|
198
|
+
render(
|
|
199
|
+
<I18nProvider lng="en">
|
|
200
|
+
<VertesiaMarkdownDocumentEditor value="#" />
|
|
201
|
+
</I18nProvider>,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
fireEvent.click(await screen.findByRole('button', { name: 'Continue with rich text' }));
|
|
205
|
+
|
|
206
|
+
expect(await screen.findByRole('textbox', { name: 'Markdown document editor' })).not.toBeNull();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Table row/column actions live in the toolbar's Table context dropdown (only when the caret is
|
|
210
|
+
// in a table); list indent/outdent is handled by Tab / Shift-Tab rather than a toolbar control.
|
|
211
|
+
});
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Editor,
|
|
3
|
+
getMarkdownCompatibility,
|
|
4
|
+
MarkdownComponentEditor,
|
|
5
|
+
type MarkdownComponentEditorProps,
|
|
6
|
+
MarkdownDocumentEditor,
|
|
7
|
+
type MarkdownDocumentEditorProps,
|
|
8
|
+
MarkdownRichTextEditor,
|
|
9
|
+
type MarkdownRichTextEditorProps,
|
|
10
|
+
type RichTextCodeBlockRendererProps,
|
|
11
|
+
type RichTextImageRendererProps,
|
|
12
|
+
type RichTextLinkRendererProps,
|
|
13
|
+
type RichTextOpaqueBlockRendererProps,
|
|
14
|
+
type RichTextRenderers,
|
|
15
|
+
} from '@vertesia/rich-text';
|
|
16
|
+
import { Button, cn, Modal, ModalBody, ModalFooter, ModalTitle, Textarea } from '@vertesia/ui/core';
|
|
17
|
+
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
18
|
+
import { type ReactNode, useCallback, useState } from 'react';
|
|
19
|
+
import { CodeBlockHandlerProvider, useCodeBlockContext } from '../widgets/markdown/CodeBlockContext.js';
|
|
20
|
+
import { useCodeBlockRendererRegistry } from '../widgets/markdown/CodeBlockRendering.js';
|
|
21
|
+
import { createDefaultCodeBlockHandlers, ExpandCodeBlockHandler } from '../widgets/markdown/codeBlockHandlers.js';
|
|
22
|
+
import { MarkdownFigure } from '../widgets/markdown/MarkdownFigure.js';
|
|
23
|
+
import { MarkdownImage } from '../widgets/markdown/MarkdownImage.js';
|
|
24
|
+
import { MarkdownLink } from '../widgets/markdown/MarkdownLink.js';
|
|
25
|
+
import { MarkdownRenderer } from '../widgets/markdown/MarkdownRenderer.js';
|
|
26
|
+
import { EditorToolbar, SendChangesToAgentButton } from './EditorToolbar.js';
|
|
27
|
+
|
|
28
|
+
const defaultCodeBlockHandlers = createDefaultCodeBlockHandlers();
|
|
29
|
+
|
|
30
|
+
function VertesiaCodeBlockPreview({ code, language }: RichTextCodeBlockRendererProps) {
|
|
31
|
+
const registry = useCodeBlockRendererRegistry();
|
|
32
|
+
const CustomRenderer = language ? registry?.getComponent(language) : undefined;
|
|
33
|
+
const DefaultRenderer = language ? defaultCodeBlockHandlers[language] : undefined;
|
|
34
|
+
const Renderer = language?.startsWith('expand:') ? ExpandCodeBlockHandler : (CustomRenderer ?? DefaultRenderer);
|
|
35
|
+
|
|
36
|
+
if (!Renderer) return null;
|
|
37
|
+
return <Renderer code={code} language={language} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function VertesiaImagePreview({ src, alt, title }: RichTextImageRendererProps) {
|
|
41
|
+
const { artifactRunId } = useCodeBlockContext();
|
|
42
|
+
if (title) {
|
|
43
|
+
return <MarkdownFigure src={src} alt={alt} caption={title} artifactRunId={artifactRunId} />;
|
|
44
|
+
}
|
|
45
|
+
return <MarkdownImage src={src} alt={alt} artifactRunId={artifactRunId} />;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function VertesiaLinkPreview({ href, title, children }: RichTextLinkRendererProps) {
|
|
49
|
+
const { artifactRunId } = useCodeBlockContext();
|
|
50
|
+
return (
|
|
51
|
+
<MarkdownLink href={href} artifactRunId={artifactRunId}>
|
|
52
|
+
<span title={title}>{children}</span>
|
|
53
|
+
</MarkdownLink>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function VertesiaOpaqueBlockPreview({ raw }: RichTextOpaqueBlockRendererProps) {
|
|
58
|
+
const { artifactRunId } = useCodeBlockContext();
|
|
59
|
+
return <MarkdownRenderer artifactRunId={artifactRunId}>{raw}</MarkdownRenderer>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const vertesiaRichTextRenderers: RichTextRenderers = {
|
|
63
|
+
codeBlock: VertesiaCodeBlockPreview,
|
|
64
|
+
image: VertesiaImagePreview,
|
|
65
|
+
link: VertesiaLinkPreview,
|
|
66
|
+
opaqueBlock: VertesiaOpaqueBlockPreview,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
interface VertesiaEditorProps {
|
|
70
|
+
artifactRunId?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface VertesiaMarkdownRichTextEditorProps
|
|
74
|
+
extends Omit<MarkdownRichTextEditorProps, keyof RichTextRenderers>,
|
|
75
|
+
VertesiaEditorProps {}
|
|
76
|
+
|
|
77
|
+
export function VertesiaMarkdownRichTextEditor({ artifactRunId, ...props }: VertesiaMarkdownRichTextEditorProps) {
|
|
78
|
+
return (
|
|
79
|
+
<CodeBlockHandlerProvider artifactRunId={artifactRunId} MarkdownRenderer={MarkdownRenderer}>
|
|
80
|
+
<MarkdownRichTextEditor {...props} {...vertesiaRichTextRenderers} />
|
|
81
|
+
</CodeBlockHandlerProvider>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface VertesiaMarkdownComponentEditorProps
|
|
86
|
+
extends Omit<MarkdownComponentEditorProps, keyof RichTextRenderers>,
|
|
87
|
+
VertesiaEditorProps {}
|
|
88
|
+
|
|
89
|
+
export function VertesiaMarkdownComponentEditor({
|
|
90
|
+
artifactRunId,
|
|
91
|
+
className,
|
|
92
|
+
contentClassName,
|
|
93
|
+
editorClassName,
|
|
94
|
+
onEditor,
|
|
95
|
+
...props
|
|
96
|
+
}: VertesiaMarkdownComponentEditorProps) {
|
|
97
|
+
const [editor, setEditor] = useState<Editor | null>(null);
|
|
98
|
+
const handleEditor = useCallback(
|
|
99
|
+
(next: Editor | null) => {
|
|
100
|
+
setEditor(next);
|
|
101
|
+
onEditor?.(next);
|
|
102
|
+
},
|
|
103
|
+
[onEditor],
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<CodeBlockHandlerProvider artifactRunId={artifactRunId} MarkdownRenderer={MarkdownRenderer}>
|
|
108
|
+
<div className={cn('overflow-hidden rounded-md border border-mixer-muted/30 bg-background', className)}>
|
|
109
|
+
<EditorToolbar editor={editor} editable={props.editable !== false} />
|
|
110
|
+
<MarkdownComponentEditor
|
|
111
|
+
{...props}
|
|
112
|
+
{...vertesiaRichTextRenderers}
|
|
113
|
+
onEditor={handleEditor}
|
|
114
|
+
contentClassName={cn('max-h-80 overflow-auto', contentClassName)}
|
|
115
|
+
editorClassName={cn('vprose prose-sm min-h-24 max-w-none px-3 py-2 outline-none', editorClassName)}
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
</CodeBlockHandlerProvider>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface VertesiaMarkdownDocumentEditorProps
|
|
123
|
+
extends Omit<MarkdownDocumentEditorProps, keyof RichTextRenderers>,
|
|
124
|
+
VertesiaEditorProps {
|
|
125
|
+
/** When set, the toolbar shows comment controls that queue and send a batch to the agent. */
|
|
126
|
+
onSendComment?: (message: string) => void | Promise<void>;
|
|
127
|
+
/** When set, the editor shows the document-level hand-off action in its own toolbar. */
|
|
128
|
+
onSendChangesToAgent?: () => void | Promise<void>;
|
|
129
|
+
hasUnsentChanges?: boolean;
|
|
130
|
+
isSendingChanges?: boolean;
|
|
131
|
+
sendChangesDisabled?: boolean;
|
|
132
|
+
/** Compact status rendered immediately beside the document hand-off action. */
|
|
133
|
+
toolbarStatus?: ReactNode;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function VertesiaMarkdownDocumentEditor({
|
|
137
|
+
artifactRunId,
|
|
138
|
+
className,
|
|
139
|
+
contentClassName,
|
|
140
|
+
editorClassName,
|
|
141
|
+
onEditor,
|
|
142
|
+
onSendComment,
|
|
143
|
+
onSendChangesToAgent,
|
|
144
|
+
hasUnsentChanges = false,
|
|
145
|
+
isSendingChanges = false,
|
|
146
|
+
sendChangesDisabled = false,
|
|
147
|
+
toolbarStatus,
|
|
148
|
+
...props
|
|
149
|
+
}: VertesiaMarkdownDocumentEditorProps) {
|
|
150
|
+
const { t } = useUITranslation();
|
|
151
|
+
const [editor, setEditor] = useState<Editor | null>(null);
|
|
152
|
+
const handleEditor = useCallback(
|
|
153
|
+
(next: Editor | null) => {
|
|
154
|
+
setEditor(next);
|
|
155
|
+
onEditor?.(next);
|
|
156
|
+
},
|
|
157
|
+
[onEditor],
|
|
158
|
+
);
|
|
159
|
+
const [editingMode, setEditingMode] = useState<'choose' | 'rich-text' | 'source'>(() =>
|
|
160
|
+
getMarkdownCompatibility(props.value) === 'lossy' ? 'choose' : 'rich-text',
|
|
161
|
+
);
|
|
162
|
+
const resolvedEditingMode = editingMode === 'choose' ? 'source' : editingMode;
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<CodeBlockHandlerProvider artifactRunId={artifactRunId} MarkdownRenderer={MarkdownRenderer}>
|
|
166
|
+
{resolvedEditingMode === 'rich-text' ? (
|
|
167
|
+
<div className={cn('flex h-full min-h-0 flex-col bg-background', className)}>
|
|
168
|
+
<EditorToolbar
|
|
169
|
+
editor={editor}
|
|
170
|
+
editable={props.editable !== false}
|
|
171
|
+
onSendComment={onSendComment}
|
|
172
|
+
onSendChangesToAgent={onSendChangesToAgent}
|
|
173
|
+
hasUnsentChanges={hasUnsentChanges}
|
|
174
|
+
isSendingChanges={isSendingChanges}
|
|
175
|
+
sendChangesDisabled={sendChangesDisabled}
|
|
176
|
+
toolbarStatus={toolbarStatus}
|
|
177
|
+
/>
|
|
178
|
+
<MarkdownDocumentEditor
|
|
179
|
+
{...props}
|
|
180
|
+
{...vertesiaRichTextRenderers}
|
|
181
|
+
onEditor={handleEditor}
|
|
182
|
+
ariaLabel={props.ariaLabel ?? t('richText.documentEditor')}
|
|
183
|
+
className="flex min-h-0 flex-1 flex-col"
|
|
184
|
+
contentClassName={cn('min-h-0 flex-1 overflow-auto', contentClassName)}
|
|
185
|
+
editorClassName={cn(
|
|
186
|
+
'vprose prose-sm mx-auto min-h-full w-full max-w-5xl px-6 py-5 outline-none',
|
|
187
|
+
editorClassName,
|
|
188
|
+
)}
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
) : (
|
|
192
|
+
<div className={cn('flex h-full min-h-0 flex-col bg-background', className)}>
|
|
193
|
+
{onSendChangesToAgent ? (
|
|
194
|
+
<div className="flex min-h-10 shrink-0 items-center justify-end gap-1 border-b border-mixer-muted/25 px-1.5 py-1">
|
|
195
|
+
{toolbarStatus}
|
|
196
|
+
<SendChangesToAgentButton
|
|
197
|
+
onSend={onSendChangesToAgent}
|
|
198
|
+
hasUnsentChanges={hasUnsentChanges}
|
|
199
|
+
isSending={isSendingChanges}
|
|
200
|
+
disabled={sendChangesDisabled}
|
|
201
|
+
/>
|
|
202
|
+
</div>
|
|
203
|
+
) : null}
|
|
204
|
+
<Textarea
|
|
205
|
+
value={props.value}
|
|
206
|
+
onChange={(event) => props.onChange?.(event.target.value)}
|
|
207
|
+
onFocus={() => props.onFocusChange?.(true)}
|
|
208
|
+
onBlur={() => props.onFocusChange?.(false)}
|
|
209
|
+
disabled={props.editable === false}
|
|
210
|
+
aria-label={t('richText.markdownSourceEditor')}
|
|
211
|
+
className={cn(
|
|
212
|
+
'vertesia-markdown-document-editor-content min-h-0 flex-1 resize-none rounded-none',
|
|
213
|
+
'border-0 px-6 py-5 font-mono text-sm leading-6 outline-none focus-visible:ring-0',
|
|
214
|
+
contentClassName,
|
|
215
|
+
editorClassName,
|
|
216
|
+
)}
|
|
217
|
+
/>
|
|
218
|
+
</div>
|
|
219
|
+
)}
|
|
220
|
+
<Modal
|
|
221
|
+
isOpen={editingMode === 'choose'}
|
|
222
|
+
onClose={() => setEditingMode('source')}
|
|
223
|
+
className="sm:max-w-lg"
|
|
224
|
+
disableCloseOnClickOutside
|
|
225
|
+
>
|
|
226
|
+
<ModalTitle>{t('richText.sourceCompatibilityWarningTitle')}</ModalTitle>
|
|
227
|
+
<ModalBody>
|
|
228
|
+
<p className="text-sm text-muted">{t('richText.sourceCompatibilityWarningDescription')}</p>
|
|
229
|
+
</ModalBody>
|
|
230
|
+
<ModalFooter align="right">
|
|
231
|
+
<Button variant="outline" onClick={() => setEditingMode('source')}>
|
|
232
|
+
{t('richText.editMarkdownSource')}
|
|
233
|
+
</Button>
|
|
234
|
+
<Button variant="secondary" onClick={() => setEditingMode('rich-text')}>
|
|
235
|
+
{t('richText.continueRichText')}
|
|
236
|
+
</Button>
|
|
237
|
+
</ModalFooter>
|
|
238
|
+
</Modal>
|
|
239
|
+
</CodeBlockHandlerProvider>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export {
|
|
2
|
+
VertesiaMarkdownComponentEditor,
|
|
3
|
+
type VertesiaMarkdownComponentEditorProps,
|
|
4
|
+
VertesiaMarkdownDocumentEditor,
|
|
5
|
+
type VertesiaMarkdownDocumentEditorProps,
|
|
6
|
+
VertesiaMarkdownRichTextEditor,
|
|
7
|
+
type VertesiaMarkdownRichTextEditorProps,
|
|
8
|
+
vertesiaRichTextRenderers,
|
|
9
|
+
} from './VertesiaRichTextEditor';
|
|
@@ -6,34 +6,34 @@ function createSession(onboardingProgress: () => Promise<Record<string, boolean>
|
|
|
6
6
|
const client = {
|
|
7
7
|
account: { onboardingProgress },
|
|
8
8
|
} as unknown as VertesiaClient;
|
|
9
|
-
const
|
|
10
|
-
session
|
|
11
|
-
return session;
|
|
9
|
+
const setSession = vi.fn<(session: UserSession) => void>();
|
|
10
|
+
const session = new UserSession(client, setSession);
|
|
11
|
+
return { session, setSession };
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
describe('UserSession.fetchOnboardingStatus', () => {
|
|
15
15
|
it('does not replace the session when an incomplete status is unchanged', async () => {
|
|
16
|
-
const session = createSession(async () => ({ project_created: false }));
|
|
16
|
+
const { session, setSession } = createSession(async () => ({ project_created: false }));
|
|
17
17
|
session.onboardingComplete = false;
|
|
18
18
|
|
|
19
19
|
await expect(session.fetchOnboardingStatus()).resolves.toBe(false);
|
|
20
|
-
expect(
|
|
20
|
+
expect(setSession).not.toHaveBeenCalled();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('updates the session and reports when onboarding becomes complete', async () => {
|
|
24
|
-
const session = createSession(async () => ({ project_created: true }));
|
|
24
|
+
const { session, setSession } = createSession(async () => ({ project_created: true }));
|
|
25
25
|
session.onboardingComplete = false;
|
|
26
26
|
|
|
27
27
|
await expect(session.fetchOnboardingStatus()).resolves.toBe(true);
|
|
28
|
-
expect(
|
|
29
|
-
expect(
|
|
28
|
+
expect(setSession).toHaveBeenCalledOnce();
|
|
29
|
+
expect(setSession.mock.calls[0]?.[0]?.onboardingComplete).toBe(true);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it('publishes the initial incomplete status without reporting completion', async () => {
|
|
33
|
-
const session = createSession(async () => ({ project_created: false }));
|
|
33
|
+
const { session, setSession } = createSession(async () => ({ project_created: false }));
|
|
34
34
|
|
|
35
35
|
await expect(session.fetchOnboardingStatus()).resolves.toBe(false);
|
|
36
|
-
expect(
|
|
37
|
-
expect(
|
|
36
|
+
expect(setSession).toHaveBeenCalledOnce();
|
|
37
|
+
expect(setSession.mock.calls[0]?.[0]?.onboardingComplete).toBe(false);
|
|
38
38
|
});
|
|
39
39
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { parseAgentResourceHref } from './AgentResourceResolver';
|
|
3
|
+
|
|
4
|
+
describe('parseAgentResourceHref', () => {
|
|
5
|
+
it.each([
|
|
6
|
+
['store:doc-1', 'document', 'doc-1'],
|
|
7
|
+
['document://doc-1', 'document', 'doc-1'],
|
|
8
|
+
['collection:col-1', 'collection', 'col-1'],
|
|
9
|
+
['interaction:int-1', 'interaction', 'int-1'],
|
|
10
|
+
['prompt:prompt-1', 'prompt', 'prompt-1'],
|
|
11
|
+
['agent:agent-1', 'agent', 'agent-1'],
|
|
12
|
+
['workflow:workflow-1', 'workflow', 'workflow-1'],
|
|
13
|
+
['process:process-1', 'process', 'process-1'],
|
|
14
|
+
['run:run-1', 'interaction_run', 'run-1'],
|
|
15
|
+
] as const)('maps %s to a resource reference', (rawHref, type, id) => {
|
|
16
|
+
expect(parseAgentResourceHref(rawHref)).toEqual({ type, id });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('returns undefined for standard, file, and empty resource URLs', () => {
|
|
20
|
+
expect(parseAgentResourceHref('https://example.com')).toBeUndefined();
|
|
21
|
+
expect(parseAgentResourceHref('artifact:report.pdf')).toBeUndefined();
|
|
22
|
+
expect(parseAgentResourceHref('store:')).toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { AgentResourceAction, AgentResourceType } from '@vertesia/common';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Resource identity accepted by link resolvers from either structured tool metadata or Markdown. */
|
|
5
|
+
export interface AgentResourceLinkReference {
|
|
6
|
+
type: AgentResourceType;
|
|
7
|
+
id: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
action?: AgentResourceAction;
|
|
10
|
+
revision_id?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type AgentResourceTarget =
|
|
14
|
+
| { kind: 'navigate'; href: string }
|
|
15
|
+
| { kind: 'activate'; onActivate: () => void }
|
|
16
|
+
| { kind: 'none' };
|
|
17
|
+
|
|
18
|
+
export interface ResourceResolveContext {
|
|
19
|
+
workflowRunId?: string;
|
|
20
|
+
source: 'structured' | 'markdown';
|
|
21
|
+
/** Original custom-scheme URL when the reference came from Markdown. */
|
|
22
|
+
rawHref?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type AgentResourceResolver = (
|
|
26
|
+
ref: AgentResourceLinkReference,
|
|
27
|
+
context: ResourceResolveContext,
|
|
28
|
+
) => AgentResourceTarget;
|
|
29
|
+
|
|
30
|
+
const unresolvedAgentResourceResolver: AgentResourceResolver = () => ({ kind: 'none' });
|
|
31
|
+
const AgentResourceResolverContext = createContext<AgentResourceResolver>(unresolvedAgentResourceResolver);
|
|
32
|
+
|
|
33
|
+
/** Supplies host-specific navigation for reusable chat and Markdown components. */
|
|
34
|
+
export const AgentResourceResolverProvider = AgentResourceResolverContext.Provider;
|
|
35
|
+
|
|
36
|
+
export function useAgentResourceResolver(): AgentResourceResolver {
|
|
37
|
+
return useContext(AgentResourceResolverContext);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const RESOURCE_SCHEME_TYPES = {
|
|
41
|
+
store: 'document',
|
|
42
|
+
document: 'document',
|
|
43
|
+
collection: 'collection',
|
|
44
|
+
interaction: 'interaction',
|
|
45
|
+
prompt: 'prompt',
|
|
46
|
+
agent: 'agent',
|
|
47
|
+
workflow: 'workflow',
|
|
48
|
+
process: 'process',
|
|
49
|
+
run: 'interaction_run',
|
|
50
|
+
} as const satisfies Record<string, AgentResourceType>;
|
|
51
|
+
|
|
52
|
+
/** Converts a supported agent Markdown scheme into the same resource identity used by tool metadata. */
|
|
53
|
+
export function parseAgentResourceHref(rawHref: string): AgentResourceLinkReference | undefined {
|
|
54
|
+
const colonIndex = rawHref.indexOf(':');
|
|
55
|
+
if (colonIndex <= 0) return undefined;
|
|
56
|
+
|
|
57
|
+
const scheme = rawHref.slice(0, colonIndex);
|
|
58
|
+
if (!Object.hasOwn(RESOURCE_SCHEME_TYPES, scheme)) return undefined;
|
|
59
|
+
|
|
60
|
+
const id = rawHref
|
|
61
|
+
.slice(colonIndex + 1)
|
|
62
|
+
.trim()
|
|
63
|
+
.replace(/^\/+/, '');
|
|
64
|
+
if (!id) return undefined;
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
type: RESOURCE_SCHEME_TYPES[scheme as keyof typeof RESOURCE_SCHEME_TYPES],
|
|
68
|
+
id,
|
|
69
|
+
};
|
|
70
|
+
}
|