mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
fix(vscode): bucket session history by calendar week (#16097)
The session history dropdown grouped entries with a rolling 168-hour window while the buckets are labelled Today / Yesterday / This Week / Older. On a Monday, a session from the previous Saturday was still within 168 hours, so it showed up under "This Week" even though the calendar week had only just started. This Week now begins at the Monday-first start of the current calendar week, derived from the same local day boundary as the Today/Yesterday buckets. The boundary uses setDate rather than millisecond arithmetic so a DST transition cannot shift it. Sessions before that boundary fall through to Older, and Today/Yesterday are untouched. Regression coverage pins a Monday with a previous-Saturday session (Older), plus a Friday/Wednesday positive control proving This Week still exists mid-week so the Monday assertion cannot pass on a missing group. Patrol-Run: qwen-issue-patrol/jmvyk46lrtc Co-authored-by: Qwen-Coder <[email protected]>
This commit is contained in:
1 parent
8de81eb209
commit
91bce47a14
2 files changed
+92
-1
No files matched your search
@@ -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(
|
||||
<SessionHistoryDropdown
|
||||
t={t}
|
||||
sessions={sessions}
|
||||
searchQuery=""
|
||||
loading={false}
|
||||
hasMore={false}
|
||||
onSearchChange={() => {}}
|
||||
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'),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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<string, DaemonSessionSummary[]>([
|
||||
[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');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user