fix: only show the unified mailbox section when it can be populated #843

This commit is contained in:
Linus Rath
2026-09-07 22:34:47 +02:00
parent 07bbde4786
commit f3f0127c9d
2 changed files with 78 additions and 1 deletions
@@ -0,0 +1,72 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import type { Mailbox } from '@/lib/jmap/types';
// #843: the "Unified Mailbox" header used to appear as soon as two accounts
// were connected, but mail-app only populates the section when the admin gate
// and the user's cross-account toggle are both on (`crossAccountActive`), or a
// merged group inbox / cross view exists. An empty header is not shown.
vi.mock('@/components/plugins/plugin-slot', () => ({ PluginSlot: () => null }));
vi.mock('@/components/tour/tour-provider', () => ({
useTour: () => ({ startTour: vi.fn(), resetTourCompletion: vi.fn(), activeTour: null, endTour: vi.fn(), registerStep: vi.fn() }),
}));
vi.mock('@/contexts/drag-drop-context', () => ({
useDragDropContext: () => ({ isDragging: false }),
}));
vi.mock('@/hooks/use-mailbox-drop', () => ({
useMailboxDrop: () => ({ dropHandlers: {}, isValidDropTarget: false, isInvalidDropTarget: false }),
}));
vi.mock('@/hooks/use-tag-drop', () => ({
useTagDrop: () => ({ dropHandlers: {}, isValidDropTarget: false }),
}));
vi.mock('../account-switcher', () => ({ AccountSwitcher: () => null }));
const { Sidebar } = await import('../sidebar');
const { useAccountStore } = await import('@/stores/account-store');
const { useSettingsStore } = await import('@/stores/settings-store');
const mailboxes: Mailbox[] = [
{ id: 'inbox', name: 'Inbox', role: 'inbox', parentId: null, totalEmails: 0, unreadEmails: 0, myRights: { mayAddItems: true } },
] as unknown as Mailbox[];
function account(id: string) {
return {
id,
label: `${id}@example.com`,
email: `${id}@example.com`,
username: `${id}@example.com`,
cookieSlot: id === 'a' ? 0 : 1,
isConnected: true,
};
}
describe('Sidebar unified mailbox section (#843)', () => {
beforeEach(() => {
useAccountStore.setState({ accounts: [account('a'), account('b')] } as never);
useSettingsStore.setState({
enableUnifiedMailbox: true,
includeGroupInUnified: false,
hideAccountSwitcher: true,
} as never);
});
it('hides the header with two accounts when cross-account is not active', () => {
render(<Sidebar mailboxes={mailboxes} selectedMailbox="inbox" crossAccountActive={false} />);
expect(screen.queryByText('unified_mailbox')).toBeNull();
expect(screen.queryByText('all_accounts')).toBeNull();
});
it('shows the header once cross-account is active', () => {
render(<Sidebar mailboxes={mailboxes} selectedMailbox="inbox" crossAccountActive />);
expect(screen.getByText('all_accounts')).toBeInTheDocument();
});
it('shows the header for a cross view even without cross-account', () => {
render(<Sidebar mailboxes={mailboxes} selectedMailbox="inbox" crossAccountActive={false} showCrossUnread />);
expect(screen.getByText('unified_mailbox')).toBeInTheDocument();
});
});
+6 -1
View File
@@ -904,9 +904,14 @@ export function Sidebar({
// single account we still surface unified when the user has opted into
// merging group/shared inboxes — otherwise the counts would just duplicate
// the one inbox.
// Only show the section when mail-app will actually populate it: cross-account
// needs the admin gate + user toggle (`crossAccountActive`, which already
// implies 2+ connected accounts), otherwise a merged group inbox or one of
// the cross views must exist. A bare "2+ accounts" left an empty header. (#843)
const anyCrossViewEnabled = showCrossUnread || showCrossStarred || showCrossAll;
const showUnified =
(multiAccountMode || enableUnifiedMailbox) &&
(connectedAccounts.length > 1 || (includeGroupInUnified && hasGroupInboxes));
(crossAccountActive || (includeGroupInUnified && hasGroupInboxes) || anyCrossViewEnabled);
const { unifiedCounts } = useEmailStore();
const t = useTranslations('sidebar');