the account chips show the whole address, because the local part is the shared half

Two chips both read `andre.padez`. They are andre.padez@gmail.com and andre.padez@pertento.ai — one
person's personal and work accounts, which is the entire case this switcher exists for.

The chip showed the local part on the reasoning that the domain is what accounts have in common. That is
true of accounts belonging to different people and exactly backwards here: the local part is the half they
share and the domain is the half that tells them apart. So the strip wraps instead of scrolling, and the
address is not truncated.

The "N other accounts not shown" line was also lying. It counted stored usage READINGS minus the one being
displayed, which since the switcher landed includes accounts whose chip is two lines below — it said "2
other accounts not shown" with both of them on screen. It now counts only accounts with a reading and no
saved credential: an old login you can look at and cannot return to, which is the thing actually worth
saying. On this machine that is one, jrg.conceicao@gmail.com.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 21:30:06 +00:00
co-authored by Claude Opus 5
parent 7d7a80782e
commit 4b2cb3d266
@@ -154,7 +154,7 @@ const AccountSwitcher = ({
switchingTo: string | null;
onSwitch: (accountUuid: string) => void;
}) => (
<div className="flex items-center gap-1 overflow-x-auto border-t border-border px-2 py-2">
<div className="flex flex-wrap items-center gap-1 border-t border-border px-2 py-2">
{accounts.map((account) => {
const busy = isSwitching && switchingTo === account.accountUuid;
return (
@@ -180,9 +180,13 @@ const AccountSwitcher = ({
} ${isSwitching && !busy ? 'opacity-50' : ''}`}
>
{busy && <Loader2 className="h-3 w-3 animate-spin" />}
{/* The local part alone: the domain is what these accounts have in common and the part before it
is what tells them apart, in a 320px panel. */}
{account.emailAccount.split('@')[0]}
{/* The WHOLE address. This showed the local part alone, on the reasoning that the domain is what
accounts have in common — which is wrong for the case that matters: a personal and a work
account belonging to one person are `andre.padez@gmail.com` and `andre.padez@pertento.ai`, so
the local part is the half they SHARE and the domain is the half that tells them apart. Two
chips read as the same account. The strip wraps instead of scrolling, so a long address is
readable rather than clipped off the edge. */}
{account.emailAccount}
</button>
);
})}
@@ -238,7 +242,14 @@ export function UsagePopover({ label, harness }: UsagePopoverProps) {
another's chip lit — and that disagreement is the exact confusion this whole change set out to remove.
*/
const selected = accounts[0] ?? null;
const hidden = Math.max(0, allAccounts.length - accounts.length);
/*
Accounts with a stored READING but no stored credential — an old login that can be looked at and not
returned to. That is what is worth saying out loud.
This counted `allAccounts - accounts` until the switcher existed, which then double-counted: it called
an account "not shown" while its chip sat two lines below.
*/
const unreachable = allAccounts.filter((a) => !switchable.some((s) => s.emailAccount === a.email)).length;
// The countdowns tick. Only while the panel is open — an interval running behind a closed popover is a
// re-render a minute for something nobody is looking at.
@@ -287,9 +298,9 @@ export function UsagePopover({ label, harness }: UsagePopoverProps) {
{switchError instanceof Error ? switchError.message : 'could not switch account'}
</div>
)}
{hidden > 0 && (
{unreachable > 0 && (
<div className="mt-0.5 text-[10px] text-muted-foreground">
{hidden} other account{hidden === 1 ? '' : 's'} not shown
{unreachable} older account{unreachable === 1 ? '' : 's'} with no saved sign-in
</div>
)}
{/*