@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,44 @@
|
|
|
1
|
+
/** @vitest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { I18nProvider } from '../../../../i18n/index.js';
|
|
6
|
+
import { AGENT_LINE_CLAMP_CLASS, CollapsibleAgentMarkdown } from './CollapsibleAgentMarkdown.js';
|
|
7
|
+
|
|
8
|
+
afterEach(cleanup);
|
|
9
|
+
|
|
10
|
+
const renderMarkdown = (markdown: string, testId = 'prose') =>
|
|
11
|
+
render(
|
|
12
|
+
<I18nProvider lng="en">
|
|
13
|
+
<CollapsibleAgentMarkdown data-testid={testId}>{markdown}</CollapsibleAgentMarkdown>
|
|
14
|
+
</I18nProvider>,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
describe('CollapsibleAgentMarkdown', () => {
|
|
18
|
+
it('renders markdown without a toggle when the content is short', () => {
|
|
19
|
+
renderMarkdown('A **short** note.');
|
|
20
|
+
expect(screen.getByText('short')).not.toBeNull();
|
|
21
|
+
expect(screen.queryByRole('button', { name: /Show more/ })).toBeNull();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders a markdown table', () => {
|
|
25
|
+
renderMarkdown('| A | B |\n| - | - |\n| 1 | 2 |');
|
|
26
|
+
expect(screen.getByRole('table')).not.toBeNull();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('collapses long content behind a show more / show less toggle', () => {
|
|
30
|
+
const long = Array.from({ length: 10 }, (_, i) => `Line number ${i + 1} of the reference block.`).join('\n\n');
|
|
31
|
+
renderMarkdown(long);
|
|
32
|
+
|
|
33
|
+
const prose = screen.getByTestId('prose');
|
|
34
|
+
const showMore = screen.getByRole('button', { name: /Show more/ });
|
|
35
|
+
expect(showMore.getAttribute('aria-expanded')).toBe('false');
|
|
36
|
+
expect(prose.getAttribute('class') ?? '').toContain(AGENT_LINE_CLAMP_CLASS.split(' ')[0]);
|
|
37
|
+
|
|
38
|
+
fireEvent.click(showMore);
|
|
39
|
+
|
|
40
|
+
const showLess = screen.getByRole('button', { name: /Show less/ });
|
|
41
|
+
expect(showLess.getAttribute('aria-expanded')).toBe('true');
|
|
42
|
+
expect(prose.getAttribute('class') ?? '').not.toContain('[-webkit-line-clamp:6]');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { cn } from '@vertesia/ui/core';
|
|
2
|
+
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
3
|
+
import { MarkdownRenderer, type MarkdownRendererProps } from '@vertesia/ui/widgets';
|
|
4
|
+
import { ChevronDown } from 'lucide-react';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
|
|
7
|
+
/** Prose styling used for agent/model message markdown, shared across the conversation UI. */
|
|
8
|
+
export const AGENT_PROSE_CLASS = [
|
|
9
|
+
'agent-markdown vprose prose max-w-none break-words text-sm leading-6 text-foreground/80',
|
|
10
|
+
'prose-p:my-2 prose-p:leading-6 prose-li:my-0.5 prose-pre:my-3 prose-headings:tracking-normal',
|
|
11
|
+
'prose-headings:text-foreground prose-strong:text-foreground prose-code:text-foreground',
|
|
12
|
+
'prose-a:text-foreground prose-a:underline prose-a:decoration-muted prose-a:underline-offset-4',
|
|
13
|
+
'[&_p]:text-foreground/80 [&_li]:text-foreground/80 [&_li::marker]:text-muted',
|
|
14
|
+
].join(' ');
|
|
15
|
+
|
|
16
|
+
/** Clamp applied to collapsed markdown. Kept as a literal so Tailwind emits the utility. */
|
|
17
|
+
export const AGENT_LINE_CLAMP_CLASS =
|
|
18
|
+
'[display:-webkit-box] overflow-hidden [-webkit-box-orient:vertical] [-webkit-line-clamp:6]';
|
|
19
|
+
|
|
20
|
+
export const AGENT_COLLAPSE_LINES = 6;
|
|
21
|
+
export const AGENT_COLLAPSE_THRESHOLD = 520;
|
|
22
|
+
|
|
23
|
+
interface CollapsibleAgentMarkdownProps {
|
|
24
|
+
/** Raw markdown to render. */
|
|
25
|
+
children: string;
|
|
26
|
+
artifactRunId?: string;
|
|
27
|
+
components?: MarkdownRendererProps['components'];
|
|
28
|
+
/** Disable the show more/less affordance regardless of length. */
|
|
29
|
+
disableCollapse?: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
'data-testid'?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Renders agent/model markdown with the shared prose styling and, when the content is long,
|
|
36
|
+
* collapses it to a few lines behind a "Show more" / "Show less" toggle. Mirrors the treatment
|
|
37
|
+
* used for summary thought prose so edit/comment cards read like ordinary model messages.
|
|
38
|
+
*/
|
|
39
|
+
export function CollapsibleAgentMarkdown({
|
|
40
|
+
children,
|
|
41
|
+
artifactRunId,
|
|
42
|
+
components,
|
|
43
|
+
disableCollapse,
|
|
44
|
+
className,
|
|
45
|
+
'data-testid': dataTestId,
|
|
46
|
+
}: CollapsibleAgentMarkdownProps) {
|
|
47
|
+
const { t } = useUITranslation();
|
|
48
|
+
const normalizedText = children.trim();
|
|
49
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
50
|
+
const explicitLineCount = normalizedText ? normalizedText.split(/\r?\n/).length : 0;
|
|
51
|
+
const isLong = normalizedText.length > AGENT_COLLAPSE_THRESHOLD || explicitLineCount > AGENT_COLLAPSE_LINES;
|
|
52
|
+
const collapsed = isLong && !disableCollapse && !isExpanded;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className={cn('min-w-0', className)}>
|
|
56
|
+
<div
|
|
57
|
+
data-testid={dataTestId}
|
|
58
|
+
className={cn(AGENT_PROSE_CLASS, collapsed && AGENT_LINE_CLAMP_CLASS)}
|
|
59
|
+
style={{ overflowWrap: 'anywhere' }}
|
|
60
|
+
>
|
|
61
|
+
<MarkdownRenderer artifactRunId={artifactRunId} components={components}>
|
|
62
|
+
{children}
|
|
63
|
+
</MarkdownRenderer>
|
|
64
|
+
</div>
|
|
65
|
+
{isLong && !disableCollapse ? (
|
|
66
|
+
<div className="mt-1.5 flex justify-end">
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
aria-expanded={isExpanded}
|
|
70
|
+
className={cn(
|
|
71
|
+
'inline-flex items-center gap-1 text-sm font-medium text-muted transition-colors',
|
|
72
|
+
'[text-decoration:none] hover:text-foreground hover:[text-decoration:none]',
|
|
73
|
+
'focus-visible:text-foreground focus-visible:[text-decoration:none]',
|
|
74
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
75
|
+
)}
|
|
76
|
+
onClick={() => setIsExpanded((current) => !current)}
|
|
77
|
+
>
|
|
78
|
+
{isExpanded ? t('agent.showLess') : t('agent.showMore')}
|
|
79
|
+
<ChevronDown
|
|
80
|
+
className={cn('size-4 transition-transform', isExpanded && 'rotate-180')}
|
|
81
|
+
aria-hidden="true"
|
|
82
|
+
/>
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
) : null}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from '@vertesia/common';
|
|
7
7
|
import { Badge, Button, cn, Dropdown, MenuItem, useToast } from '@vertesia/ui/core';
|
|
8
8
|
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
9
|
-
import {
|
|
9
|
+
import { useRouterContext } from '@vertesia/ui/router';
|
|
10
10
|
import { useUserSession } from '@vertesia/ui/session';
|
|
11
11
|
import { MarkdownRenderer } from '@vertesia/ui/widgets';
|
|
12
12
|
import dayjs from 'dayjs';
|
|
@@ -29,9 +29,11 @@ import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
29
29
|
import { useDownloadFile } from '../../../store/objects/components/useDownloadFile.js';
|
|
30
30
|
import { PulsatingCircle } from '../AnimatedThinkingDots';
|
|
31
31
|
import { AskUserWidget } from '../AskUserWidget';
|
|
32
|
+
import { DocumentEditingActionCard, parseMarkdownEditingAction } from '../DocumentEditingActionCard.js';
|
|
32
33
|
import { useImageLightbox } from '../ImageLightbox';
|
|
33
34
|
import { getArtifactCacheKey, useArtifactUrlCache } from '../useArtifactUrlCache.js';
|
|
34
35
|
import { ThinkingMessages } from '../WaitingMessages';
|
|
36
|
+
import { createAgentMarkdownAnchor } from './AgentMarkdownAnchor';
|
|
35
37
|
import { AttachmentPreviewList, parseUserMessageAttachments } from './AttachmentPreview';
|
|
36
38
|
import { MessageDeliveryStatus } from './MessageDeliveryStatus';
|
|
37
39
|
import { processContentForMarkdown } from './processContentForMarkdown';
|
|
@@ -108,6 +110,8 @@ export interface MessageItemProps extends MessageItemClassNames {
|
|
|
108
110
|
showPulsatingCircle?: boolean;
|
|
109
111
|
/** Callback when user sends a message (e.g., from proposal selection) */
|
|
110
112
|
onSendMessage?: (message: string, metadata?: Record<string, unknown>) => void;
|
|
113
|
+
/** Open a Markdown artifact in the surrounding agent panel. */
|
|
114
|
+
onOpenArtifact?: (path: string) => void;
|
|
111
115
|
/** Whether a REQUEST_INPUT message has already been answered by a later user message */
|
|
112
116
|
requestInputAnswered?: boolean;
|
|
113
117
|
/** Sparse per-type overrides for MESSAGE_STYLES (deep-merged with defaults) */
|
|
@@ -197,6 +201,7 @@ function MessageItemComponent({
|
|
|
197
201
|
message,
|
|
198
202
|
showPulsatingCircle = false,
|
|
199
203
|
onSendMessage,
|
|
204
|
+
onOpenArtifact,
|
|
200
205
|
requestInputAnswered = false,
|
|
201
206
|
className,
|
|
202
207
|
cardClassName,
|
|
@@ -304,6 +309,13 @@ function MessageItemComponent({
|
|
|
304
309
|
|
|
305
310
|
const visibleMessageContent = parsedUserAttachments?.body ?? messageContent;
|
|
306
311
|
const messageAttachments = parsedUserAttachments?.attachments ?? [];
|
|
312
|
+
const editingAction = useMemo(
|
|
313
|
+
() =>
|
|
314
|
+
message.type === AgentMessageType.QUESTION
|
|
315
|
+
? parseMarkdownEditingAction(message.details?.editing_action)
|
|
316
|
+
: undefined,
|
|
317
|
+
[message.details, message.type],
|
|
318
|
+
);
|
|
307
319
|
|
|
308
320
|
// PERFORMANCE: Memoize processed content - expensive regex operations only run when messageContent changes
|
|
309
321
|
const processedContent = useMemo(() => {
|
|
@@ -367,52 +379,13 @@ function MessageItemComponent({
|
|
|
367
379
|
// PERFORMANCE: Memoize markdown components to prevent MarkdownRenderer remounts
|
|
368
380
|
const markdownComponents = useMemo(
|
|
369
381
|
() => ({
|
|
370
|
-
a: ({
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
...props
|
|
374
|
-
}: {
|
|
375
|
-
node?: unknown;
|
|
376
|
-
ref?: unknown;
|
|
377
|
-
href?: string;
|
|
378
|
-
children?: React.ReactNode;
|
|
379
|
-
}) => {
|
|
380
|
-
const href = props.href || '';
|
|
382
|
+
a: createAgentMarkdownAnchor({
|
|
383
|
+
StoreLinkComponent,
|
|
384
|
+
CollectionLinkComponent,
|
|
381
385
|
// Carry the active account (`a`) & project (`p`) params on internal routes so
|
|
382
386
|
// copy-link / open-in-new-tab preserve the current tenant.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if (StoreLinkComponent) {
|
|
386
|
-
const documentId = href.split('/store/objects/')[1] || '';
|
|
387
|
-
return (
|
|
388
|
-
<StoreLinkComponent href={withParams} documentId={documentId}>
|
|
389
|
-
{props.children}
|
|
390
|
-
</StoreLinkComponent>
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
return (
|
|
394
|
-
<NavLink href={withParams} topLevelNav>
|
|
395
|
-
{props.children}
|
|
396
|
-
</NavLink>
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
if (href.includes('/store/collections')) {
|
|
400
|
-
if (CollectionLinkComponent) {
|
|
401
|
-
const collectionId = href.split('/store/collections/')[1] || '';
|
|
402
|
-
return (
|
|
403
|
-
<CollectionLinkComponent href={withParams} collectionId={collectionId}>
|
|
404
|
-
{props.children}
|
|
405
|
-
</CollectionLinkComponent>
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
return (
|
|
409
|
-
<NavLink href={withParams} topLevelNav>
|
|
410
|
-
{props.children}
|
|
411
|
-
</NavLink>
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
return <a {...props} target="_blank" rel="noopener noreferrer" />;
|
|
415
|
-
},
|
|
387
|
+
addStickyParams: (href: string) => router.getTopRouter().navigator.addStickyParams(href),
|
|
388
|
+
}),
|
|
416
389
|
img: ({ node, ref, ...props }: { node?: unknown; ref?: unknown; src?: string; alt?: string }) => {
|
|
417
390
|
return (
|
|
418
391
|
<Button
|
|
@@ -466,6 +439,7 @@ function MessageItemComponent({
|
|
|
466
439
|
>
|
|
467
440
|
<MarkdownRenderer
|
|
468
441
|
artifactRunId={runId}
|
|
442
|
+
onArtifactOpen={onOpenArtifact}
|
|
469
443
|
onProposalSelect={(optionId) => onSendMessage?.(optionId)}
|
|
470
444
|
onProposalSubmit={(text) => onSendMessage?.(text)}
|
|
471
445
|
components={markdownComponents}
|
|
@@ -662,6 +636,8 @@ function MessageItemComponent({
|
|
|
662
636
|
compact
|
|
663
637
|
answered={requestInputAnswered}
|
|
664
638
|
/>
|
|
639
|
+
) : editingAction ? (
|
|
640
|
+
<DocumentEditingActionCard action={editingAction} />
|
|
665
641
|
) : (
|
|
666
642
|
visibleMessageContent && (
|
|
667
643
|
<div
|
|
@@ -677,6 +653,7 @@ function MessageItemComponent({
|
|
|
677
653
|
<AttachmentPreviewList
|
|
678
654
|
items={messageAttachments}
|
|
679
655
|
artifactRunId={runId}
|
|
656
|
+
onOpenArtifact={onOpenArtifact}
|
|
680
657
|
variant="message"
|
|
681
658
|
className={cn(visibleMessageContent && 'mt-3')}
|
|
682
659
|
StoreLinkComponent={StoreLinkComponent}
|
|
@@ -723,7 +700,13 @@ function MessageItemComponent({
|
|
|
723
700
|
variant="outline"
|
|
724
701
|
size="xs"
|
|
725
702
|
className="px-2 py-1 text-xs"
|
|
726
|
-
onClick={() =>
|
|
703
|
+
onClick={() => {
|
|
704
|
+
if (/\.md$/i.test(artifactPath) && onOpenArtifact) {
|
|
705
|
+
onOpenArtifact(artifactPath);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
window.open(url, '_blank');
|
|
709
|
+
}}
|
|
727
710
|
title={artifactPath}
|
|
728
711
|
>
|
|
729
712
|
{displayName}
|
|
@@ -790,6 +773,7 @@ const MessageItem = memo(MessageItemComponent, (prevProps, nextProps) => {
|
|
|
790
773
|
prevProps.message.workflow_run_id === nextProps.message.workflow_run_id &&
|
|
791
774
|
prevProps.showPulsatingCircle === nextProps.showPulsatingCircle &&
|
|
792
775
|
prevProps.onSendMessage === nextProps.onSendMessage &&
|
|
776
|
+
prevProps.onOpenArtifact === nextProps.onOpenArtifact &&
|
|
793
777
|
prevProps.requestInputAnswered === nextProps.requestInputAnswered &&
|
|
794
778
|
prevProps.messageStyleOverrides === nextProps.messageStyleOverrides &&
|
|
795
779
|
MESSAGE_ITEM_CLASS_NAME_KEYS.every((key) => prevProps[key] === nextProps[key])
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AgentResourceReference } from '@vertesia/common';
|
|
2
|
+
import { Button, cn } from '@vertesia/ui/core';
|
|
3
|
+
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { ResourceChipList } from './ResourceChip';
|
|
6
|
+
|
|
7
|
+
const COLLAPSE_THRESHOLD = 5;
|
|
8
|
+
|
|
9
|
+
interface ResourceChangeSummaryProps {
|
|
10
|
+
resources: AgentResourceReference[];
|
|
11
|
+
workflowRunId?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* End-of-turn summary listing every resource the assistant created/updated/deleted during the turn,
|
|
17
|
+
* as deep-linkable chips. Rendered once the turn is complete, from structured tool metadata rather
|
|
18
|
+
* than parsed prose. Collapses to the first few entries with a "view all" toggle when long.
|
|
19
|
+
*/
|
|
20
|
+
export function ResourceChangeSummary({ resources, workflowRunId, className }: ResourceChangeSummaryProps) {
|
|
21
|
+
const { t } = useUITranslation();
|
|
22
|
+
const [expanded, setExpanded] = useState(false);
|
|
23
|
+
|
|
24
|
+
if (resources.length === 0) return null;
|
|
25
|
+
|
|
26
|
+
const collapsible = resources.length > COLLAPSE_THRESHOLD;
|
|
27
|
+
const visible = collapsible && !expanded ? resources.slice(0, COLLAPSE_THRESHOLD) : resources;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className={cn('mx-auto w-full max-w-3xl py-2', className)} data-agent-resource-summary>
|
|
31
|
+
<div className="mb-2 text-xs font-medium text-muted">{t('agent.resourcesChanged')}</div>
|
|
32
|
+
<ResourceChipList resources={visible} workflowRunId={workflowRunId} />
|
|
33
|
+
{collapsible && (
|
|
34
|
+
<Button variant="outline" size="xs" className="mt-2" onClick={() => setExpanded((prev) => !prev)}>
|
|
35
|
+
{expanded ? t('agent.resourceShowLess') : t('agent.resourceViewAll', { total: resources.length })}
|
|
36
|
+
</Button>
|
|
37
|
+
)}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import type { AgentResourceReference } from '@vertesia/common';
|
|
5
|
+
import {
|
|
6
|
+
Boxes,
|
|
7
|
+
BrainCircuit,
|
|
8
|
+
Database,
|
|
9
|
+
FileType,
|
|
10
|
+
MessagesSquare,
|
|
11
|
+
PanelsTopLeft,
|
|
12
|
+
PlayCircle,
|
|
13
|
+
SquareTerminal,
|
|
14
|
+
Workflow,
|
|
15
|
+
} from 'lucide-react';
|
|
16
|
+
import type React from 'react';
|
|
17
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
18
|
+
import { I18nProvider } from '../../../../i18n/index.js';
|
|
19
|
+
import { ReactRouterContext, type RouterContext } from '../../../../router/index.js';
|
|
20
|
+
import { AgentResourceResolverProvider } from '../../../../widgets/markdown/AgentResourceResolver';
|
|
21
|
+
import { ResourceChangeSummary } from './ResourceChangeSummary';
|
|
22
|
+
import { ResourceChip } from './ResourceChip';
|
|
23
|
+
import { getResourceIcon } from './resourceLinks';
|
|
24
|
+
|
|
25
|
+
function makeRouterContext(): RouterContext {
|
|
26
|
+
return {
|
|
27
|
+
location: window.location,
|
|
28
|
+
route: { path: '/', Component: () => null },
|
|
29
|
+
params: {},
|
|
30
|
+
state: null,
|
|
31
|
+
matchedRoutePath: '/',
|
|
32
|
+
navigate: vi.fn(),
|
|
33
|
+
router: {
|
|
34
|
+
navigate: vi.fn(),
|
|
35
|
+
getTopRouter: () => ({ navigator: { addStickyParams: (href: string) => href } }),
|
|
36
|
+
},
|
|
37
|
+
} as unknown as RouterContext;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderWithProviders(ui: React.ReactNode) {
|
|
41
|
+
return render(
|
|
42
|
+
<I18nProvider lng="en">
|
|
43
|
+
<ReactRouterContext.Provider value={makeRouterContext()}>{ui}</ReactRouterContext.Provider>
|
|
44
|
+
</I18nProvider>,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const ref = (over: Partial<AgentResourceReference> = {}): AgentResourceReference => ({
|
|
49
|
+
type: 'document',
|
|
50
|
+
id: 'd1',
|
|
51
|
+
label: 'My Document',
|
|
52
|
+
action: 'created',
|
|
53
|
+
...over,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
afterEach(() => cleanup());
|
|
57
|
+
|
|
58
|
+
describe('ResourceChip', () => {
|
|
59
|
+
it('uses the same icons as the Studio navigation', () => {
|
|
60
|
+
expect(getResourceIcon('document')).toBe(Database);
|
|
61
|
+
expect(getResourceIcon('collection')).toBe(Boxes);
|
|
62
|
+
expect(getResourceIcon('content_type')).toBe(FileType);
|
|
63
|
+
expect(getResourceIcon('interaction')).toBe(MessagesSquare);
|
|
64
|
+
expect(getResourceIcon('prompt')).toBe(SquareTerminal);
|
|
65
|
+
expect(getResourceIcon('agent')).toBe(BrainCircuit);
|
|
66
|
+
expect(getResourceIcon('workflow')).toBe(Workflow);
|
|
67
|
+
expect(getResourceIcon('process')).toBe(Workflow);
|
|
68
|
+
expect(getResourceIcon('process_run')).toBe(PlayCircle);
|
|
69
|
+
expect(getResourceIcon('interaction_run')).toBe(PlayCircle);
|
|
70
|
+
expect(getResourceIcon('view')).toBe(PanelsTopLeft);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('renders a navigable link supplied by the host resolver', () => {
|
|
74
|
+
renderWithProviders(
|
|
75
|
+
<AgentResourceResolverProvider value={() => ({ kind: 'navigate', href: '/documents/d1' })}>
|
|
76
|
+
<ResourceChip resource={ref()} />
|
|
77
|
+
</AgentResourceResolverProvider>,
|
|
78
|
+
);
|
|
79
|
+
const link = screen.getByRole('link', { name: /My Document/ });
|
|
80
|
+
expect(link.getAttribute('href')).toContain('/documents/d1');
|
|
81
|
+
expect(screen.getByText('Created')).not.toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('renders a non-interactive chip when the host does not configure a resolver', () => {
|
|
85
|
+
renderWithProviders(<ResourceChip resource={ref({ type: 'interaction', id: 'int-1', label: 'Chat' })} />);
|
|
86
|
+
expect(screen.queryByRole('link')).toBeNull();
|
|
87
|
+
expect(screen.getByText('Chat')).not.toBeNull();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('renders a deleted resource as a non-interactive chip (no link)', () => {
|
|
91
|
+
renderWithProviders(<ResourceChip resource={ref({ action: 'deleted', label: 'Gone' })} />);
|
|
92
|
+
expect(screen.queryByRole('link')).toBeNull();
|
|
93
|
+
expect(screen.getByText('Gone')).not.toBeNull();
|
|
94
|
+
expect(screen.getByText('Deleted')).not.toBeNull();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('honors a resolver override from context', () => {
|
|
98
|
+
renderWithProviders(
|
|
99
|
+
<AgentResourceResolverProvider value={() => ({ kind: 'navigate', href: '/custom/path' })}>
|
|
100
|
+
<ResourceChip resource={ref()} />
|
|
101
|
+
</AgentResourceResolverProvider>,
|
|
102
|
+
);
|
|
103
|
+
expect(screen.getByRole('link').getAttribute('href')).toContain('/custom/path');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('supports a host activation callback instead of navigation', () => {
|
|
107
|
+
const onActivate = vi.fn();
|
|
108
|
+
renderWithProviders(
|
|
109
|
+
<AgentResourceResolverProvider value={() => ({ kind: 'activate', onActivate })}>
|
|
110
|
+
<ResourceChip resource={ref()} />
|
|
111
|
+
</AgentResourceResolverProvider>,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
fireEvent.click(screen.getByRole('button', { name: /My Document/ }));
|
|
115
|
+
expect(onActivate).toHaveBeenCalledOnce();
|
|
116
|
+
expect(screen.queryByRole('link')).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('ResourceChangeSummary', () => {
|
|
121
|
+
it('renders nothing when there are no resources', () => {
|
|
122
|
+
const { container } = renderWithProviders(<ResourceChangeSummary resources={[]} />);
|
|
123
|
+
expect(container.querySelector('[data-agent-resource-summary]')).toBeNull();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('renders a header and a chip per resource', () => {
|
|
127
|
+
const { container } = renderWithProviders(
|
|
128
|
+
<ResourceChangeSummary
|
|
129
|
+
resources={[ref({ id: 'd1', label: 'Doc One' }), ref({ type: 'collection', id: 'c1', label: 'Col' })]}
|
|
130
|
+
/>,
|
|
131
|
+
);
|
|
132
|
+
expect(container.querySelector('[data-agent-resource-summary]')?.className).not.toContain('bg-muted');
|
|
133
|
+
expect(screen.getByText('Resources changed')).not.toBeNull();
|
|
134
|
+
expect(screen.getByText('Doc One')).not.toBeNull();
|
|
135
|
+
expect(screen.getByText('Col')).not.toBeNull();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('collapses beyond five resources and expands on click', () => {
|
|
139
|
+
const many = Array.from({ length: 7 }, (_, i) => ref({ id: `d${i}`, label: `Doc ${i}` }));
|
|
140
|
+
renderWithProviders(<ResourceChangeSummary resources={many} />);
|
|
141
|
+
// Only 5 shown initially
|
|
142
|
+
expect(screen.queryByText('Doc 5')).toBeNull();
|
|
143
|
+
const toggle = screen.getByRole('button', { name: /View all 7 changes/ });
|
|
144
|
+
fireEvent.click(toggle);
|
|
145
|
+
expect(screen.getByText('Doc 5')).not.toBeNull();
|
|
146
|
+
expect(screen.getByText('Doc 6')).not.toBeNull();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { AgentResourceReference } from '@vertesia/common';
|
|
2
|
+
import { Badge, Button, cn } from '@vertesia/ui/core';
|
|
3
|
+
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
4
|
+
import { NavLink } from '@vertesia/ui/router';
|
|
5
|
+
import { useAgentResourceResolver } from '@vertesia/ui/widgets';
|
|
6
|
+
import { getResourceActionVariant, getResourceIcon } from './resourceLinks';
|
|
7
|
+
|
|
8
|
+
interface ResourceChipProps {
|
|
9
|
+
resource: AgentResourceReference;
|
|
10
|
+
/** Originating run, passed to the resolver for run-scoped resources. */
|
|
11
|
+
workflowRunId?: string;
|
|
12
|
+
/** Hide the action badge when surrounding text already communicates the action. */
|
|
13
|
+
showAction?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A compact resource chip for something an agent tool created/updated/deleted. The host resolver may
|
|
19
|
+
* make it navigable (NavLink applies tenant sticky params), activate a host callback, or leave it
|
|
20
|
+
* non-interactive.
|
|
21
|
+
*/
|
|
22
|
+
export function ResourceChip({ resource, workflowRunId, showAction = true, className }: ResourceChipProps) {
|
|
23
|
+
const { t } = useUITranslation();
|
|
24
|
+
const resolve = useAgentResourceResolver();
|
|
25
|
+
const target = resolve(resource, { workflowRunId, source: 'structured' });
|
|
26
|
+
const Icon = getResourceIcon(resource.type);
|
|
27
|
+
// Literal keys (not a dynamic lookup) so i18next-cli can statically extract them.
|
|
28
|
+
const actionLabel =
|
|
29
|
+
resource.action === 'created'
|
|
30
|
+
? t('agent.resourceActionCreated')
|
|
31
|
+
: resource.action === 'deleted'
|
|
32
|
+
? t('agent.resourceActionDeleted')
|
|
33
|
+
: t('agent.resourceActionUpdated');
|
|
34
|
+
|
|
35
|
+
const body = (
|
|
36
|
+
<>
|
|
37
|
+
<Icon className="size-3.5 shrink-0 text-foreground" aria-hidden="true" />
|
|
38
|
+
<span className="truncate">{resource.label}</span>
|
|
39
|
+
{showAction && (
|
|
40
|
+
<Badge variant={getResourceActionVariant(resource.action)} className="shrink-0 px-1.5 py-0 text-[10px]">
|
|
41
|
+
{actionLabel}
|
|
42
|
+
</Badge>
|
|
43
|
+
)}
|
|
44
|
+
</>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const baseClass = cn(
|
|
48
|
+
'inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-xs',
|
|
49
|
+
className,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (target.kind === 'navigate') {
|
|
53
|
+
return (
|
|
54
|
+
<NavLink
|
|
55
|
+
href={target.href}
|
|
56
|
+
topLevelNav
|
|
57
|
+
className={cn(baseClass, 'font-medium transition-colors hover:bg-muted/60')}
|
|
58
|
+
>
|
|
59
|
+
{body}
|
|
60
|
+
</NavLink>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (target.kind === 'activate') {
|
|
65
|
+
return (
|
|
66
|
+
<Button
|
|
67
|
+
variant="unstyled"
|
|
68
|
+
onClick={target.onActivate}
|
|
69
|
+
className={cn(baseClass, 'font-medium transition-colors hover:bg-muted/60')}
|
|
70
|
+
>
|
|
71
|
+
{body}
|
|
72
|
+
</Button>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Deleted or unresolvable resource: no navigation target, render a non-interactive chip.
|
|
77
|
+
return <span className={cn(baseClass, 'text-muted')}>{body}</span>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface ResourceActivityLinkListProps {
|
|
81
|
+
resources: AgentResourceReference[];
|
|
82
|
+
workflowRunId?: string;
|
|
83
|
+
className?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Inline action + deep-link presentation for completed tool timeline rows. */
|
|
87
|
+
export function ResourceActivityLinkList({ resources, workflowRunId, className }: ResourceActivityLinkListProps) {
|
|
88
|
+
const { t } = useUITranslation();
|
|
89
|
+
if (resources.length === 0) return null;
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div
|
|
93
|
+
className={cn('flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1', className)}
|
|
94
|
+
data-agent-resource-activity
|
|
95
|
+
>
|
|
96
|
+
{resources.map((resource) => {
|
|
97
|
+
const actionLabel =
|
|
98
|
+
resource.action === 'created'
|
|
99
|
+
? t('agent.resourceActionCreated')
|
|
100
|
+
: resource.action === 'deleted'
|
|
101
|
+
? t('agent.resourceActionDeleted')
|
|
102
|
+
: t('agent.resourceActionUpdated');
|
|
103
|
+
return (
|
|
104
|
+
<span
|
|
105
|
+
key={`${resource.type}:${resource.id}:${resource.action}`}
|
|
106
|
+
className="inline-flex min-w-0 items-center gap-1.5"
|
|
107
|
+
>
|
|
108
|
+
<span className="shrink-0 text-sm text-muted">{actionLabel}</span>
|
|
109
|
+
<ResourceChip
|
|
110
|
+
resource={resource}
|
|
111
|
+
workflowRunId={workflowRunId}
|
|
112
|
+
showAction={false}
|
|
113
|
+
className="py-0.5"
|
|
114
|
+
/>
|
|
115
|
+
</span>
|
|
116
|
+
);
|
|
117
|
+
})}
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface ResourceChipListProps {
|
|
123
|
+
resources: AgentResourceReference[];
|
|
124
|
+
workflowRunId?: string;
|
|
125
|
+
className?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function ResourceChipList({ resources, workflowRunId, className }: ResourceChipListProps) {
|
|
129
|
+
if (resources.length === 0) return null;
|
|
130
|
+
return (
|
|
131
|
+
<div className={cn('flex flex-wrap gap-1.5', className)}>
|
|
132
|
+
{resources.map((resource) => (
|
|
133
|
+
<ResourceChip
|
|
134
|
+
key={`${resource.type}:${resource.id}:${resource.action}`}
|
|
135
|
+
resource={resource}
|
|
136
|
+
workflowRunId={workflowRunId}
|
|
137
|
+
/>
|
|
138
|
+
))}
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|