From 610df64463129cd7e59d330779ea268fbfdd5801 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:39:27 +0200 Subject: [PATCH] fix: keep the whole folder after a restart when a category tab was open #1264 --- .../email-store-refresh-category-tab.test.ts | 23 +++++++++++++++++++ stores/email-store.ts | 5 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/stores/__tests__/email-store-refresh-category-tab.test.ts b/stores/__tests__/email-store-refresh-category-tab.test.ts index 5dc7b467d..f91c72188 100644 --- a/stores/__tests__/email-store-refresh-category-tab.test.ts +++ b/stores/__tests__/email-store-refresh-category-tab.test.ts @@ -78,4 +78,27 @@ describe('refreshing a folder with a category tab open (#1264)', () => { expect(useEmailStore.getState().emails.map((e) => e.id)).toEqual(['receipt']); expect(useEmailStore.getState().newEmailNotification).toBeNull(); }); + + it('leaves no delta baseline for the tab page, as the first load does', async () => { + useMessageListTabsStore.getState().setActiveTab('receipts', 'inbox'); + const receipt = email('receipt', '2026-10-01T00:00:00Z'); + const newsletter = email('newsletter', '2026-10-15T00:00:00Z'); + const c = { + ...client([]), + getEmails: vi.fn(async (...args: unknown[]) => { + const rows = args[6] ? [receipt] : [newsletter, receipt]; + return { emails: rows, total: rows.length, hasMore: false, state: 's' }; + }), + getEmailChanges: vi.fn(async () => ({ created: [], updated: [], destroyed: [], newState: 's', hasMoreChanges: false })), + } as unknown as IJMAPClient; + await useEmailStore.getState().refreshCurrentMailbox(c); + expect(useEmailStore.getState().emailListSync).toBeNull(); + + // The baseline would be saved with the rows (boot snapshot). On the next + // boot, before the plugin has registered its tabs again, the folder loads + // behind those rows and must not take the tab's page for the whole folder. + useMessageListTabsStore.getState().clearTabs('receipts-plugin'); + await useEmailStore.getState().fetchEmails(c, 'inbox', { background: true }); + expect(useEmailStore.getState().emails.map((e) => e.id)).toEqual(['newsletter', 'receipt']); + }); }); diff --git a/stores/email-store.ts b/stores/email-store.ts index 74a52e63f..afd049c22 100644 --- a/stores/email-store.ts +++ b/stores/email-store.ts @@ -5634,8 +5634,9 @@ export const useEmailStore = create((set, get) => ({ const categoryFilter = useMessageListTabsStore.getState().getCategoryFilter(mailbox?.role); result = await effectiveClient.getEmails(jmapMailboxId, accountId, windowSize, 0, undefined, true, categoryFilter ?? undefined, order); // This page is the new delta-sync baseline for the folder; the - // search / unified paths above cannot be delta-synced. - syncAfterRefresh = result.state + // search / unified paths above cannot be delta-synced, and neither + // can a category tab's page (see fetchEmails). + syncAfterRefresh = result.state && !categoryFilter ? { state: result.state, accountId: accountId ?? effectiveClient.getAccountId(), mailboxId: selectedMailbox } : null; }