From 146979ec4d04f98abb4dd3236763aea8baa04d18 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Mon, 31 Aug 2026 17:40:10 -0400 Subject: [PATCH] fix(seer): allow collapsing ThinkingBlock while thinking is active --- .../core/chat/thinkingBlock.spec.tsx | 42 +++++++++++++++++++ .../components/core/chat/thinkingBlock.tsx | 13 ++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/static/app/components/core/chat/thinkingBlock.spec.tsx b/static/app/components/core/chat/thinkingBlock.spec.tsx index cc2c90e2a2b3..3bb807f7c257 100644 --- a/static/app/components/core/chat/thinkingBlock.spec.tsx +++ b/static/app/components/core/chat/thinkingBlock.spec.tsx @@ -55,6 +55,48 @@ describe('ThinkingBlock', () => { expect(screen.getByText('inner content')).not.toBeVisible(); }); + it('can be manually collapsed while thinking is active', async () => { + jest.useRealTimers(); + const start = new Date(); + + render( + +
inner content
+
+ ); + + expect(screen.getByText('inner content')).toBeVisible(); + + await userEvent.click(screen.getByText('Thinking')); + expect(screen.getByText('inner content')).not.toBeVisible(); + }); + + it('auto-collapses when thinking completes even if user re-expanded', async () => { + jest.useRealTimers(); + const start = new Date(); + + const {rerender} = render( + +
inner content
+
+ ); + + // collapse then re-expand while still active + await userEvent.click(screen.getByText('Thinking')); + expect(screen.getByText('inner content')).not.toBeVisible(); + await userEvent.click(screen.getByText('Thinking')); + expect(screen.getByText('inner content')).toBeVisible(); + + // thinking completes → auto-collapse + rerender( + +
inner content
+
+ ); + + expect(screen.getByText('inner content')).not.toBeVisible(); + }); + it('can be manually toggled after collapsing', async () => { jest.useRealTimers(); const start = new Date(); diff --git a/static/app/components/core/chat/thinkingBlock.tsx b/static/app/components/core/chat/thinkingBlock.tsx index 4ff443fecea8..a1c4e1896fab 100644 --- a/static/app/components/core/chat/thinkingBlock.tsx +++ b/static/app/components/core/chat/thinkingBlock.tsx @@ -76,19 +76,26 @@ export function ThinkingBlock({title, startTime, endTime, children}: ThinkingBlo const {t} = useTranslation(); const elapsed = useElapsedTime(startTime, endTime); const isActive = !endTime; - const [userExpanded, setUserExpanded] = useState(false); + // ponytail: null = no user interaction, falls through to isActive default + const [override, setOverride] = useState(null); + + useEffect(() => { + if (!isActive) { + setOverride(null); + } + }, [isActive]); const titleRef = useRef(null); const baseTitle = title.replace(/[.…\s]+$/u, ''); useTextDecodeAnimation(titleRef, baseTitle); - const isExpanded = isActive || userExpanded; + const isExpanded = override ?? isActive; const summaryTitle = t('See thinking and tool calls'); return (