fix(desktop): keep dismissed task progress hidden

Dismissed completed task lists are a user visibility choice for that completed cycle, so polling the same persisted tasks during the next chat turn should not resurrect the bar. The store now keeps the dismissed completion key while the remote reset is in flight, and the markdown renderer gives default lists enough inset so bullets stay inside message cards.

Constraint: Preserve future task cycles when new TodoWrite or task updates arrive.
Rejected: Clear only the visible task array | polling can rehydrate the same completed list before remote reset finishes
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run test -- run src/stores/cliTaskStore.test.ts src/components/markdown/MarkdownRenderer.test.tsx
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Live Tauri chat session task creation and dismissal
This commit is contained in:
程序员阿江(Relakkes) 2026-05-31 13:52:54 +08:00
parent 3b1b96022f
commit ef818f8d8c
4 changed files with 46 additions and 5 deletions

View File

@ -57,6 +57,19 @@ describe('MarkdownRenderer', () => {
expect(screen.getByText('Body copy.')).toBeInTheDocument()
})
it('gives default markdown lists enough inset to keep bullets inside message cards', () => {
const { container } = render(
<MarkdownRenderer content={'- First item\n- Second item'} />,
)
const root = container.firstChild as HTMLDivElement
expect(root.className).toContain('prose-ul:pl-5')
expect(root.className).toContain('prose-ol:pl-5')
expect(root.className).toContain('prose-ul:list-outside')
expect(root.className).toContain('prose-ol:list-outside')
expect(screen.getByText('First item')).toBeInTheDocument()
})
it('applies compact prose classes for dense surfaces', () => {
const { container } = render(
<MarkdownRenderer

View File

@ -414,7 +414,7 @@ const BASE_PROSE_CLASSES = `markdown-prose prose prose-sm min-w-0 max-w-none bre
prose-pre:!bg-transparent prose-pre:!p-0 prose-pre:!shadow-none
prose-a:text-[var(--color-text-accent)] prose-a:no-underline prose-a:[overflow-wrap:anywhere] hover:prose-a:underline
prose-strong:text-[var(--color-text-primary)]
prose-ul:my-2 prose-ol:my-2
prose-ul:my-2 prose-ol:my-2 prose-ul:pl-5 prose-ol:pl-5 prose-ul:list-outside prose-ol:list-outside
prose-li:my-0.5
prose-table:my-0 prose-table:w-full prose-table:table-auto prose-table:text-sm
prose-th:bg-[var(--color-surface-info)] prose-th:px-3 prose-th:py-2 prose-th:text-left prose-th:whitespace-normal prose-th:break-words prose-th:align-top prose-th:border-b prose-th:border-[var(--color-border)]

View File

@ -95,8 +95,8 @@ describe('cliTaskStore', () => {
expect(useCLITaskStore.getState()).toMatchObject({
tasks: [],
resetting: true,
completedAndDismissed: false,
dismissedCompletionKey: null,
completedAndDismissed: true,
dismissedCompletionKey: 'session-1::1::Keep current session isolated::completed::::|session-1::2::Second completed task::completed::::',
expanded: false,
})
@ -107,6 +107,34 @@ describe('cliTaskStore', () => {
expect(useCLITaskStore.getState().resetting).toBe(false)
})
it('keeps a dismissed completed list hidden if polling returns it again', async () => {
const completedTasks = [
makeTask('session-1', 'completed'),
{ ...makeTask('session-1', 'completed'), id: '2', subject: 'Second completed task' },
]
vi.mocked(cliTasksApi.resetTaskList).mockResolvedValue({ ok: true })
vi.mocked(cliTasksApi.getTasksForList).mockResolvedValue({ tasks: completedTasks })
useCLITaskStore.setState({
sessionId: 'session-1',
tasks: completedTasks,
expanded: true,
completedAndDismissed: false,
dismissedCompletionKey: null,
})
await useCLITaskStore.getState().resetCompletedTasks()
await useCLITaskStore.getState().fetchSessionTasks('session-1')
expect(useCLITaskStore.getState()).toMatchObject({
tasks: completedTasks,
completedAndDismissed: true,
dismissedCompletionKey: 'session-1::1::Keep current session isolated::completed::::|session-1::2::Second completed task::completed::::',
expanded: false,
})
})
it('refreshes tasks for the currently tracked session by default', async () => {
vi.mocked(cliTasksApi.getTasksForList).mockResolvedValue({
tasks: [makeTask('session-1', 'in_progress')],

View File

@ -165,8 +165,8 @@ export const useCLITaskStore = create<CLITaskStore>((set, get) => ({
set({
tasks: [],
resetting: true,
completedAndDismissed: false,
dismissedCompletionKey: null,
completedAndDismissed: true,
dismissedCompletionKey: completionKey,
expanded: false,
})