From 840390de501b899846d358d2bb573780569bfee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Thu, 9 Jul 2026 20:52:05 +0800 Subject: [PATCH] fix(desktop): preserve Mermaid shapes and summary truncation Keep auto-quoting slash labels for generated Mermaid paths while preserving slash-delimited flowchart shapes. Restore truncation on activity summary values so the compact summary layout and tests agree. Tested: cd desktop && bun run test -- src/pages/ActivitySettings.test.tsx src/components/chat/MermaidRenderer.test.tsx src/components/chat/MermaidRenderer.integration.test.tsx Tested: bun run check:desktop Confidence: high Scope-risk: narrow --- .../components/chat/MermaidRenderer.test.tsx | 34 +++++++++++++++++++ .../src/components/chat/MermaidRenderer.tsx | 11 +++++- desktop/src/pages/ActivitySettings.tsx | 4 +-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/desktop/src/components/chat/MermaidRenderer.test.tsx b/desktop/src/components/chat/MermaidRenderer.test.tsx index 5a4b835b..b95d30d3 100644 --- a/desktop/src/components/chat/MermaidRenderer.test.tsx +++ b/desktop/src/components/chat/MermaidRenderer.test.tsx @@ -78,6 +78,40 @@ describe('MermaidRenderer', () => { expect(arrow?.getAttribute('style') ?? '').not.toContain('stroke:') }) + it('quotes generated slash labels that Mermaid would parse as invalid shape syntax', async () => { + render( + D2[直接调用 dclService]', + ].join('\n')} + />, + ) + + await waitFor(() => { + expect(renderMock).toHaveBeenCalledWith( + expect.any(String), + [ + 'flowchart TD', + ' D1["/api/dcl"] --> D2[直接调用 dclService]', + ].join('\n'), + ) + }) + }) + + it('preserves slash-delimited Mermaid flowchart shapes', async () => { + const code = [ + 'flowchart TD', + ' A[/Manual input/] --> B[OK]', + ].join('\n') + + render() + + await waitFor(() => { + expect(renderMock).toHaveBeenCalledWith(expect.any(String), code) + }) + }) + it('fits oversized diagrams inside the chat message surface', async () => { const originalClientWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'clientWidth') Object.defineProperty(HTMLElement.prototype, 'clientWidth', { diff --git a/desktop/src/components/chat/MermaidRenderer.tsx b/desktop/src/components/chat/MermaidRenderer.tsx index 4489b05c..1e32f9f0 100644 --- a/desktop/src/components/chat/MermaidRenderer.tsx +++ b/desktop/src/components/chat/MermaidRenderer.tsx @@ -60,8 +60,17 @@ function isQuotedFlowchartLabel(label: string) { ) } +function isSlashDelimitedFlowchartShape(label: string) { + const trimmed = label.trim() + return trimmed.length >= 2 && trimmed.startsWith('/') && trimmed.endsWith('/') +} + function shouldQuoteFlowchartLabel(label: string) { - return !isQuotedFlowchartLabel(label) && UNQUOTED_FLOWCHART_LABEL_UNSAFE.test(label) + return ( + !isQuotedFlowchartLabel(label) && + !isSlashDelimitedFlowchartShape(label) && + UNQUOTED_FLOWCHART_LABEL_UNSAFE.test(label) + ) } function escapeFlowchartLabel(label: string) { diff --git a/desktop/src/pages/ActivitySettings.tsx b/desktop/src/pages/ActivitySettings.tsx index 334e6925..b4536a4a 100644 --- a/desktop/src/pages/ActivitySettings.tsx +++ b/desktop/src/pages/ActivitySettings.tsx @@ -772,9 +772,9 @@ export function ActivitySettings() { style={{ animationDelay: `${index * 45}ms` }} >
-
+ }`}> {metric.value}