diff --git a/src/workspaces/officerdev/src/apps/Chat/components/UsagePopover.tsx b/src/workspaces/officerdev/src/apps/Chat/components/UsagePopover.tsx index d5388436..941da781 100644 --- a/src/workspaces/officerdev/src/apps/Chat/components/UsagePopover.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/components/UsagePopover.tsx @@ -193,7 +193,7 @@ export function UsagePopover({ label, harness }: UsagePopoverProps) { const enabled = isOwner && harness === 'claude-code'; const [open, setOpen] = useState(false); - const { accounts, isLoading, isRefreshing, isError } = useClaudeUsage(enabled && open); + const { accounts, allAccounts, isLoading, isRefreshing, isError } = useClaudeUsage(enabled && open); /* Which tab is showing. @@ -206,6 +206,7 @@ export function UsagePopover({ label, harness }: UsagePopoverProps) { */ const [selectedEmail, setSelectedEmail] = useState(null); const selected = accounts.find((a) => a.email === selectedEmail) ?? accounts[0] ?? null; + const hidden = Math.max(0, allAccounts.length - accounts.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. @@ -234,13 +235,26 @@ export function UsagePopover({ label, harness }: UsagePopoverProps) { {/* Plan and account in the accent rather than muted: this line is the ANSWER to "whose numbers am I looking at", which matters more the moment there is a second tab, and it was reading as chrome under the title. */} -
- {selected - ? [selected.plan, selected.email].filter(Boolean).join(' · ') - : isLoading - ? 'Reading usage…' - : 'Not signed in'} -
+ {/* The email on its own line, unshared. It is the answer to the only question this panel is + being opened to settle — which account am I spending — and joined with the plan it was the + half that got truncated first in a 320px popover. */} + {selected ? ( + <> +
+ {selected.email} +
+ {selected.plan &&
{selected.plan}
} + + ) : ( +
{isLoading ? 'Reading usage…' : 'Not signed in'}
+ )} + {/* Said out loud rather than silently dropped. Phase one shows one account; knowing another + exists and is hidden on purpose is different from wondering where it went. */} + {hidden > 0 && ( +
+ {hidden} other account{hidden === 1 ? '' : 's'} not shown +
+ )} {/* How old this reading is, and it earns its line only when it is not live. diff --git a/src/workspaces/officerdev/src/apps/Chat/useClaudeUsage.ts b/src/workspaces/officerdev/src/apps/Chat/useClaudeUsage.ts index a61d0578..c96f9385 100644 --- a/src/workspaces/officerdev/src/apps/Chat/useClaudeUsage.ts +++ b/src/workspaces/officerdev/src/apps/Chat/useClaudeUsage.ts @@ -76,8 +76,27 @@ export function useClaudeUsage(enabled: boolean) { if (fresh.data) queryClient.setQueryData(KEY, fresh.data); }, [fresh.data, queryClient]); + const all = fresh.data?.accounts ?? cached.data?.accounts ?? []; + + /* + PHASE ONE — the signed-in account only. Temporary, and a one-line revert: delete `onlyCurrent` and + return `all`. + + The stored snapshots for other accounts are a real feature and the server still serves them. The problem + is what they do to the question being asked. This machine's owner has a personal account and a + work one, both appear as tabs, and after signing in you cannot tell from a glance WHICH tab you are + now spending — the panel answers "here is usage for two accounts" when the question is "whose am I on". + + So while that is the question, show one account and let its absence mean something: no row marked + `current` renders as "Not signed in", which is a true and useful answer rather than a tab that happens + to be selected. + */ + const onlyCurrent = all.filter((a) => a.current); + return { - accounts: fresh.data?.accounts ?? cached.data?.accounts ?? [], + accounts: onlyCurrent, + /** Every account the server knows about — kept so a caller can say how many are being hidden. */ + allAccounts: all, /** Only true when there is nothing at all to show. A stale list is not a loading state. */ isLoading: cached.isLoading && fresh.isLoading, /** A refresh in flight over an already-painted panel. Worth a hint, never a spinner over the numbers. */