diff --git a/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.test.tsx b/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.test.tsx index 27180638b70..8e0dc8ee307 100644 --- a/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.test.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.test.tsx @@ -176,3 +176,89 @@ describe('SessionHistoryDropdown pagination', () => { expect(onLoadMore).toHaveBeenCalledTimes(1); }); }); + +describe('SessionHistoryDropdown calendar-week grouping', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + function sessionAt(sessionId: string, updatedAt: Date): DaemonSessionSummary { + const stamp = updatedAt.toISOString(); + return { + sessionId, + workspaceCwd: '/workspace', + displayName: sessionId, + createdAt: stamp, + updatedAt: stamp, + }; + } + + async function renderWithSessions(sessions: DaemonSessionSummary[]) { + const container = document.createElement('div'); + document.body.appendChild(container); + const root = createRoot(container); + await act(async () => { + root.render( + {}} + onSelect={() => {}} + onRename={async () => {}} + onDelete={async () => {}} + onLoadMore={() => {}} + onClose={() => {}} + />, + ); + await Promise.resolve(); + }); + mounted.push({ container, root }); + return container; + } + + function groupLabels(container: HTMLElement): string[] { + return Array.from(container.querySelectorAll('[role="group"]')).map( + (group) => group.getAttribute('aria-label') ?? '', + ); + } + + it('buckets a Saturday session as older on the following Monday', async () => { + // Monday 2026-11-02: a rolling 168h window would still call last Saturday + // "this week", but the calendar week started today. + vi.useFakeTimers({ toFake: ['Date'] }); + vi.setSystemTime(new Date(2026, 10, 2, 12)); + + const container = await renderWithSessions([ + sessionAt('last-saturday', new Date(2026, 9, 31, 12)), + ]); + + const labels = groupLabels(container); + expect(labels).not.toContain(t('group.thisWeek')); + expect(labels).toContain(t('group.older')); + const row = container.querySelector('[data-session-id="last-saturday"]'); + expect(row?.closest('[role="group"]')?.getAttribute('aria-label')).toBe( + t('group.older'), + ); + }); + + it('keeps a Wednesday session in this week on the following Friday', async () => { + // Positive control: the This Week bucket still exists mid-week, so the + // Monday assertion above cannot pass merely because the group never shows. + vi.useFakeTimers({ toFake: ['Date'] }); + vi.setSystemTime(new Date(2026, 10, 6, 12)); + + const container = await renderWithSessions([ + sessionAt('wednesday', new Date(2026, 10, 4, 12)), + ]); + + const labels = groupLabels(container); + expect(labels).toContain(t('group.thisWeek')); + const row = container.querySelector('[data-session-id="wednesday"]'); + expect(row?.closest('[role="group"]')?.getAttribute('aria-label')).toBe( + t('group.thisWeek'), + ); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.tsx b/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.tsx index 76ba044eaf8..cb5e93e86c4 100644 --- a/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SessionHistoryDropdown.tsx @@ -33,6 +33,11 @@ function groupSessions( today.setHours(0, 0, 0, 0); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); + // Monday-first start of the current calendar week, derived from the same + // local day boundary as `today`/`yesterday`. Use setDate rather than + // millisecond arithmetic so a DST transition cannot shift the bucket edge. + const weekStart = new Date(today); + weekStart.setDate(today.getDate() - ((today.getDay() + 6) % 7)); const groups = new Map([ [t('group.today'), []], [t('group.yesterday'), []], @@ -50,7 +55,7 @@ function groupSessions( if (day.getTime() === today.getTime()) label = t('group.today'); else if (day.getTime() === yesterday.getTime()) { label = t('group.yesterday'); - } else if (day.getTime() > today.getTime() - 7 * 86_400_000) { + } else if (day.getTime() >= weekStart.getTime()) { label = t('group.thisWeek'); } }