mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
Render scheduled task summaries as markdown
Scheduled task results can contain assistant-authored markdown, but the runs panel previously displayed that content as plain pre-wrapped text. Reusing the desktop markdown renderer keeps task summaries aligned with chat and settings surfaces while adding a compact prose variant for the narrow log panel. Constraint: Desktop task logs need dense formatting without introducing a new markdown dependency Rejected: Keep whitespace-pre-wrap summary text | markdown syntax remains visible in completed task runs Confidence: high Scope-risk: narrow Directive: Keep scheduled run summary rendering on the shared MarkdownRenderer path so links, lists, inline code, and future markdown fixes stay consistent Tested: cd desktop && bun run test src/components/markdown/MarkdownRenderer.test.tsx src/components/tasks/TaskRunsPanel.test.tsx Tested: cd desktop && bun run lint Tested: cd desktop && bun run build Tested: bun run check:desktop Tested: agent-browser E2E against isolated CLAUDE_CONFIG_DIR with real backend and Vite UI; verified strong/li/code/link DOM output and no raw markdown bold markers Not-tested: Tauri native packaged app shell
This commit is contained in:
parent
da477c2b4b
commit
065a80580b
@ -51,6 +51,22 @@ describe('MarkdownRenderer', () => {
|
||||
expect(screen.getByText('Body copy.')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('applies compact prose classes for dense surfaces', () => {
|
||||
const { container } = render(
|
||||
<MarkdownRenderer
|
||||
content={'**Done**\n\n- One\n- Two'}
|
||||
variant="compact"
|
||||
/>,
|
||||
)
|
||||
|
||||
const root = container.firstChild as HTMLDivElement
|
||||
expect(root).toBeInTheDocument()
|
||||
expect(root.className).toContain('prose-p:text-xs')
|
||||
expect(root.className).toContain('prose-li:text-xs')
|
||||
expect(screen.getByText('Done')).toBeInTheDocument()
|
||||
expect(screen.getByText('One')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('uses semantic code colors for inline code so both themes stay readable', () => {
|
||||
const { container } = render(
|
||||
<MarkdownRenderer content={'Use `claude-sonnet-4-6` for balanced speed.'} />,
|
||||
|
||||
@ -6,7 +6,7 @@ import { MermaidRenderer } from '../chat/MermaidRenderer'
|
||||
|
||||
type Props = {
|
||||
content: string
|
||||
variant?: 'default' | 'document'
|
||||
variant?: 'default' | 'document' | 'compact'
|
||||
className?: string
|
||||
}
|
||||
|
||||
@ -136,8 +136,24 @@ const DOCUMENT_PROSE_CLASSES = `
|
||||
prose-li:my-1.5
|
||||
prose-table:my-0`
|
||||
|
||||
function getProseClasses(variant: 'default' | 'document', className?: string) {
|
||||
return [BASE_PROSE_CLASSES, variant === 'document' ? DOCUMENT_PROSE_CLASSES : '', className ?? '']
|
||||
const COMPACT_PROSE_CLASSES = `
|
||||
prose-p:my-1 prose-p:text-xs prose-p:leading-5 prose-p:text-[var(--color-text-secondary)]
|
||||
prose-headings:mt-2 prose-headings:mb-1 prose-headings:leading-snug
|
||||
prose-h1:text-base prose-h2:text-sm prose-h3:text-xs prose-h4:text-xs
|
||||
prose-blockquote:my-2 prose-blockquote:border-l-2 prose-blockquote:border-[var(--color-outline-variant)] prose-blockquote:pl-3 prose-blockquote:text-[var(--color-text-secondary)]
|
||||
prose-code:text-[12px]
|
||||
prose-ul:my-1 prose-ol:my-1 prose-ul:pl-4 prose-ol:pl-4
|
||||
prose-li:my-0.5 prose-li:text-xs prose-li:leading-5 prose-li:text-[var(--color-text-secondary)]
|
||||
prose-table:text-xs
|
||||
[&_.md-table-wrap]:my-2`
|
||||
|
||||
function getProseClasses(variant: 'default' | 'document' | 'compact', className?: string) {
|
||||
return [
|
||||
BASE_PROSE_CLASSES,
|
||||
variant === 'document' ? DOCUMENT_PROSE_CLASSES : '',
|
||||
variant === 'compact' ? COMPACT_PROSE_CLASSES : '',
|
||||
className ?? '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
47
desktop/src/components/tasks/TaskRunsPanel.test.tsx
Normal file
47
desktop/src/components/tasks/TaskRunsPanel.test.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import '@testing-library/jest-dom'
|
||||
|
||||
import { TaskRunsPanel } from './TaskRunsPanel'
|
||||
import { useSettingsStore } from '../../stores/settingsStore'
|
||||
import { useTaskStore } from '../../stores/taskStore'
|
||||
import type { TaskRun } from '../../types/task'
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
useSettingsStore.setState(useSettingsStore.getInitialState(), true)
|
||||
useTaskStore.setState(useTaskStore.getInitialState(), true)
|
||||
})
|
||||
|
||||
describe('TaskRunsPanel', () => {
|
||||
it('renders scheduled task summaries as markdown', async () => {
|
||||
const run: TaskRun = {
|
||||
id: 'run-1',
|
||||
taskId: 'task-1',
|
||||
taskName: 'Daily summary',
|
||||
startedAt: '2026-05-08T12:05:37.000Z',
|
||||
status: 'completed',
|
||||
prompt: 'Summarize recent commits',
|
||||
output: '最近7天有3个commit,主要改动:\n\n**1. 2865d50 - UI无障碍改进**\n- 添加 theme-color meta 标签\n- 修复 select 标签问题',
|
||||
durationMs: 12000,
|
||||
sessionId: 'session-1',
|
||||
}
|
||||
useSettingsStore.setState({ locale: 'en' })
|
||||
useTaskStore.setState({
|
||||
fetchTaskRuns: vi.fn(async () => [run]),
|
||||
} as Partial<ReturnType<typeof useTaskStore.getState>>)
|
||||
|
||||
const { container } = render(
|
||||
<TaskRunsPanel taskId="task-1" onClose={vi.fn()} />,
|
||||
)
|
||||
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: 'Summary' })).toBeInTheDocument())
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Summary' }))
|
||||
|
||||
expect(screen.getByText('1. 2865d50 - UI无障碍改进')).toBeInTheDocument()
|
||||
expect(container.querySelector('strong')).toHaveTextContent('1. 2865d50 - UI无障碍改进')
|
||||
expect(screen.getByText('添加 theme-color meta 标签')).toBeInTheDocument()
|
||||
expect(container.querySelector('li')).toHaveTextContent('添加 theme-color meta 标签')
|
||||
expect(container.textContent).not.toContain('**1. 2865d50')
|
||||
})
|
||||
})
|
||||
@ -5,6 +5,7 @@ import { useTabStore } from '../../stores/tabStore'
|
||||
import { useTranslation } from '../../i18n'
|
||||
import { parseRunOutput } from '../../lib/parseRunOutput'
|
||||
import type { TaskRun } from '../../types/task'
|
||||
import { MarkdownRenderer } from '../markdown/MarkdownRenderer'
|
||||
|
||||
function RunOutput({ run }: { run: TaskRun }) {
|
||||
const t = useTranslation()
|
||||
@ -28,10 +29,13 @@ function RunOutput({ run }: { run: TaskRun }) {
|
||||
)
|
||||
}
|
||||
|
||||
// Render AI text response with proper formatting (not monospace <pre>)
|
||||
return (
|
||||
<div className="mt-2 p-2.5 rounded-[var(--radius-sm)] bg-[var(--color-surface-container)] text-xs text-[var(--color-text-secondary)] whitespace-pre-wrap break-words max-h-48 overflow-y-auto leading-relaxed">
|
||||
{text}
|
||||
<div className="mt-2 max-h-48 overflow-y-auto rounded-[var(--radius-sm)] bg-[var(--color-surface-container)] p-2.5">
|
||||
<MarkdownRenderer
|
||||
content={text}
|
||||
variant="compact"
|
||||
className="break-words"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user