From 8eb306a19ea42c542859a5942fb3d3decbb618b8 Mon Sep 17 00:00:00 2001 From: Brad Groux <3053586+BradGroux@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:00:07 -0500 Subject: [PATCH] feat(web): consolidate task attempts in History mode (#1348) --- .../agent-run-timeline-mantine.test.tsx | 29 ++++++++++++++++- .../__tests__/task-detail-mantine.test.tsx | 22 +++++++++++-- .../components/task/AgentRunTimelinePanel.tsx | 31 ++++++++++++++----- .../__tests__/task-detail-workspace.test.ts | 9 ++++++ 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/web/src/__tests__/agent-run-timeline-mantine.test.tsx b/web/src/__tests__/agent-run-timeline-mantine.test.tsx index 3509316b..8334838b 100644 --- a/web/src/__tests__/agent-run-timeline-mantine.test.tsx +++ b/web/src/__tests__/agent-run-timeline-mantine.test.tsx @@ -506,7 +506,11 @@ describe('agent run timeline Mantine surface', () => { /> ); - expect(screen.getByText('Run Timeline')).toBeDefined(); + expect(screen.getByText('Attempt Timeline')).toBeDefined(); + expect(screen.getByText('Latest attempt')).toBeDefined(); + expect(screen.getByRole('combobox', { name: 'Attempt' }).getAttribute('value')).toBe( + 'Latest | attempt-1 | complete' + ); expect(screen.getByText('Stored replay')).toBeDefined(); expect(screen.getByText('command.completed')).toBeDefined(); expect(screen.getByText('stream.stdout')).toBeDefined(); @@ -538,6 +542,29 @@ describe('agent run timeline Mantine surface', () => { expect(mocks.onOpenTab).toHaveBeenCalledWith('work-products'); }); + it('distinguishes an earlier attempt from the latest task execution', () => { + const taskWithHistory = createMockTask({ + ...task, + attempt: { + id: 'attempt-current', + agent: 'veritas', + status: 'running', + started: '2026-06-01T11:00:00.000Z', + }, + attempts: task.attempt ? [task.attempt] : [], + }); + + renderWithProviders( + + ); + + expect(screen.getByText('Historical attempt')).toBeDefined(); + expect(screen.getByRole('combobox', { name: 'Attempt' }).getAttribute('value')).toBe( + 'Historical | attempt-1 | completed' + ); + expect(screen.queryByText(/live polling/)).toBeNull(); + }); + it('highlights a deep-linked telemetry event', () => { renderWithProviders( ({ })); vi.mock('@/components/task/AgentRunTimelinePanel', () => ({ - AgentRunTimelinePanel: () =>
Run timeline panel
, + AgentRunTimelinePanel: ({ + initialAttemptId, + initialEventId, + }: { + initialAttemptId?: string | null; + initialEventId?: string | null; + }) => ( +
+ Run timeline panel + Attempt target: {initialAttemptId ?? 'none'} + Event target: {initialEventId ?? 'none'} +
+ ), })); vi.mock('@/components/task/DiffViewer', () => ({ @@ -537,7 +549,11 @@ describe('task detail Mantine migration', () => { task={codeTask} open onOpenChange={mocks.onOpenChange} - navigationTarget={{ tab: 'timeline', timelineAttemptId: 'attempt-1' }} + navigationTarget={{ + tab: 'timeline', + timelineAttemptId: 'attempt-1', + timelineEventId: 'event-1', + }} /> ); @@ -549,6 +565,8 @@ describe('task detail Mantine migration', () => { expect(screen.getByRole('tab', { name: 'Timeline' }).getAttribute('aria-selected')).toBe( 'true' ); + expect(screen.getByText('Attempt target: attempt-1')).toBeDefined(); + expect(screen.getByText('Event target: event-1')).toBeDefined(); rerender( !selectedAttemptId || product.sourceRunId === selectedAttemptId ); const pendingTaskApprovals = approvals.filter((approval) => approval.taskId === task.id); + const selectedIsLatestAttempt = Boolean( + selectedAttemptId && selectedAttemptId === task.attempt?.id + ); + const selectedIsLiveAttempt = hasLiveAttempt && selectedIsLatestAttempt; + const selectedAttemptScope = selectedIsLiveAttempt + ? 'Current attempt' + : selectedIsLatestAttempt + ? 'Latest attempt' + : selectedAttemptId + ? 'Historical attempt' + : 'Derived history'; useEffect(() => { setVisibleCount(TIMELINE_PAGE_SIZE); @@ -1436,7 +1452,8 @@ export function AgentRunTimelinePanel({ - Run Timeline + Attempt Timeline + {selectedAttemptScope} {source === 'live' ? 'Live' : source === 'stored' ? 'Stored replay' : 'Derived'} @@ -1451,7 +1468,7 @@ export function AgentRunTimelinePanel({ {selectedAttemptId || 'No attempt selected'} | {events.length} events - {hasLiveAttempt ? ' | live polling' : ''} + {selectedIsLiveAttempt ? ' | live polling' : ''} {isLoading && ( @@ -1466,8 +1483,8 @@ export function AgentRunTimelinePanel({