diff --git a/app/(main)/admin/_tabs/policy.tsx b/app/(main)/admin/_tabs/policy.tsx index 29c1a6a56..bab81c8ad 100644 --- a/app/(main)/admin/_tabs/policy.tsx +++ b/app/(main)/admin/_tabs/policy.tsx @@ -32,6 +32,7 @@ const FEATURE_GATE_LABELS: Partial - - " (see useDocumentTitle) + // The subject is kept out until the policy has loaded: a gate that keeps + // subjects out of browser history must not let one through while unknown. + const subjectInTabTitle = usePolicyStore((s) => s.loaded && s.isFeatureEnabled('tabTitleSubjectEnabled')); const titleContext = useMemo(() => { // Composing email const composer = showComposer @@ -967,8 +970,8 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { mailboxLine = unreadCount > 0 ? `${mailboxName} (${unreadCount})` : mailboxName; } - return mailTitleContext({ composer, subject, mailbox: mailboxLine }); - }, [showComposer, composerMode, selectedEmail, selectedMailbox, mailboxes, t]); + return mailTitleContext({ composer, subject, mailbox: mailboxLine }, { showSubject: subjectInTabTitle }); + }, [showComposer, composerMode, selectedEmail, selectedMailbox, mailboxes, t, subjectInTabTitle]); useDocumentTitle(titleContext); // When this page is rendered inside the Pro shell as the Mail tab body, diff --git a/lib/__tests__/tab-title.test.ts b/lib/__tests__/tab-title.test.ts index d8c67c4c0..1b0073fe8 100644 --- a/lib/__tests__/tab-title.test.ts +++ b/lib/__tests__/tab-title.test.ts @@ -41,4 +41,12 @@ describe('mailTitleContext', () => { it('has nothing to add before a mailbox is selected', () => { expect(mailTitleContext({})).toBeNull(); }); + + it('names the mailbox instead of the open message when the subject is kept out', () => { + expect(mailTitleContext({ ...view, composer: null }, { showSubject: false })).toBe('Inbox (3)'); + }); + + it('still names the composer when the subject is kept out', () => { + expect(mailTitleContext(view, { showSubject: false })).toBe('Reply'); + }); }); diff --git a/lib/admin/types.ts b/lib/admin/types.ts index 25f7a1e7a..437712c37 100644 --- a/lib/admin/types.ts +++ b/lib/admin/types.ts @@ -58,6 +58,7 @@ export interface FeatureGates { debugModeEnabled: boolean; folderIconsEnabled: boolean; hoverActionsConfigEnabled: boolean; + tabTitleSubjectEnabled: boolean; filesEnabled: boolean; contactsEnabled: boolean; /** @deprecated Folded into `crossAllViewEnabled`; normalized forward on policy load. */ @@ -85,6 +86,7 @@ export const DEFAULT_FEATURE_GATES: FeatureGates = { debugModeEnabled: true, folderIconsEnabled: true, hoverActionsConfigEnabled: true, + tabTitleSubjectEnabled: true, filesEnabled: true, contactsEnabled: true, allMailViewEnabled: false, diff --git a/lib/tab-title.ts b/lib/tab-title.ts index 37bd7e216..87fa1ce2f 100644 --- a/lib/tab-title.ts +++ b/lib/tab-title.ts @@ -21,7 +21,16 @@ export interface MailTitleView { mailbox?: string | null; } -/** The context part of the mail view's tab title: composer, then message, then mailbox. */ -export function mailTitleContext(view: MailTitleView): string | null { - return view.composer || view.subject || view.mailbox || null; +/** + * The context part of the mail view's tab title: composer, then message, then + * mailbox. The subject does not stay in the tab strip - browsers keep it in + * history and in the session-restore list, and screen shares show it - so an + * operator can keep it out (`tabTitleSubjectEnabled`). The mailbox line is + * shown instead, so the tab still says where you are. (#1159) + */ +export function mailTitleContext( + view: MailTitleView, + { showSubject = true }: { showSubject?: boolean } = {}, +): string | null { + return view.composer || (showSubject ? view.subject : null) || view.mailbox || null; }