fix(claude): drop the repeated sign-in line in the account menu and name the right Settings page (#26405)

This commit is contained in:
Jinwoo Hong
2026-10-07 23:38:52 -04:00
committed by GitHub
parent 4f4f021f8a
commit d0e729ca01
8 changed files with 44 additions and 8 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ export function formatAccountsBlock(label: string, block: AccountsBlock): string
const lines = block.accounts.map(
(account) =>
` ${account.email}${activeAccountIds.has(account.id) ? ' (active)' : ''}${
account.needsSignIn ? ' (sign in again in Orca Settings > Accounts)' : ''
account.needsSignIn ? ' (sign in again in Orca Settings > AI Provider Accounts)' : ''
}`
)
return `Managed ${label} accounts (${block.accounts.length}):\n${lines.join('\n')}`
+1 -1
View File
@@ -694,7 +694,7 @@ describe('account CLI handlers', () => {
expect(logSpy).toHaveBeenCalledWith(
expect.stringContaining(
' old@example.com (active) (sign in again in Orca Settings > Accounts)\n ok@example.com\n'
' old@example.com (active) (sign in again in Orca Settings > AI Provider Accounts)\n ok@example.com\n'
)
)
})
@@ -37,7 +37,8 @@ import { AccountRuntimeToggle } from './StatusBarAccountControls'
import {
InlineUsageBars,
InlineUsageSignInAction,
InlineUsageSkeleton
InlineUsageSkeleton,
isUnavailableInactiveUsage
} from './InlineProviderUsage'
import { ProviderDetailsMenu } from './ProviderDetailsMenu'
import { getClaudeAccountSyncKey } from './provider-account-sync-key'
@@ -352,7 +353,9 @@ export function ClaudeSwitcherMenu({
) : null}
{inactiveUsage?.isFetching && !inactiveUsage.rateLimits ? (
<InlineUsageSkeleton />
) : inactiveUsage?.rateLimits ? (
) : inactiveUsage?.rateLimits &&
// Why: the sign-in note above already says this; skip the repeat.
!(signInId && isUnavailableInactiveUsage(inactiveUsage.rateLimits)) ? (
<InlineUsageBars
limits={inactiveUsage.rateLimits}
isFetching={inactiveUsage.isFetching}
@@ -16,6 +16,7 @@ const reauthenticate = vi.fn(async (_args: unknown) => snapshot())
const selectClaudeProviderAccount = vi.fn(async () => snapshot())
let storeSettings: GlobalSettings
let activeRuntimeEnvironmentId: string | null = null
let inactiveClaudeAccounts: unknown[] = []
function account(id: string): ClaudeManagedAccount {
return {
@@ -102,7 +103,7 @@ vi.mock('../../store', () => {
recordFeatureInteraction: vi.fn(),
refreshClaudeRateLimitsForTarget: vi.fn(),
fetchInactiveClaudeAccountUsage: vi.fn(),
rateLimits: { inactiveClaudeAccounts: [], claudeTarget: { runtime: 'host', wslDistro: null } }
rateLimits: { inactiveClaudeAccounts, claudeTarget: { runtime: 'host', wslDistro: null } }
})
const useAppStore = (selector: (value: Record<string, unknown>) => unknown): unknown =>
selector(state())
@@ -137,6 +138,7 @@ describe('status bar Claude account that needs a sign-in', () => {
beforeEach(() => {
vi.clearAllMocks()
activeRuntimeEnvironmentId = null
inactiveClaudeAccounts = []
storeSettings = {
...getDefaultSettings('/home/me'),
claudeManagedAccounts: [account('old'), account('new')],
@@ -163,6 +165,21 @@ describe('status bar Claude account that needs a sign-in', () => {
expect(toastError).not.toHaveBeenCalled()
})
it('does not repeat its sign-in note with a usage sign-in line', async () => {
const unavailable = (accountId: string): unknown => ({
accountId,
isFetching: false,
rateLimits: { ...claudeProvider, status: 'error', error: 'Not signed in' }
})
inactiveClaudeAccounts = [unavailable('old'), unavailable('new')]
await openAccounts()
expect(screen.getByText('Sign in again to use this account')).toBeTruthy()
// Only the row without a sign-in note keeps the usage line.
expect(screen.getAllByText('Sign in to see usage')).toHaveLength(1)
const newRow = screen.getAllByText('new@example.com').at(-1)!.closest('[role="menuitem"]')
expect(newRow?.textContent).toContain('Sign in to see usage')
})
it('says why a failed sign-in failed', async () => {
reauthenticate.mockRejectedValueOnce(new Error('Claude login exited with code 1.'))
await openAccounts()
@@ -71,6 +71,22 @@ describe('InlineUsageBars', () => {
expect(markup).toContain('42% used Fable')
})
it('asks for a sign-in when another provider has no usage to show', async () => {
const { InlineUsageBars } = await import('./StatusBar')
const limits: ProviderRateLimits = {
provider: 'codex',
session: null,
weekly: null,
updatedAt: Date.now(),
error: 'Not signed in',
status: 'error'
}
const markup = renderToStaticMarkup(<InlineUsageBars limits={limits} isFetching={false} />)
expect(markup).toContain('Sign in to see usage')
})
it('derives the collapsed session label from resetsAt (#5399)', async () => {
const { InlineUsageBars } = await import('./StatusBar')
@@ -295,7 +295,7 @@ describe('provider usage error copy', () => {
expect(getProviderUsageStatusLabel(p)).toBe('Sign in again')
expect(getProviderUsageErrorMessage(p)).toBe(
'The selected Claude account needs you to sign in again. Open Settings > Accounts, or choose System default.'
'The selected Claude account needs you to sign in again. Open Settings > AI Provider Accounts, or choose System default.'
)
})
@@ -227,7 +227,7 @@ export function getProviderUsageErrorMessage(p: ProviderRateLimits): string {
case 'missing-credentials':
return translate(
'accounts.claude.usageSignInMessage',
'The selected Claude account needs you to sign in again. Open Settings > Accounts, or choose System default.'
'The selected Claude account needs you to sign in again. Open Settings > AI Provider Accounts, or choose System default.'
)
case 'server':
case 'parse':
+1 -1
View File
@@ -19439,7 +19439,7 @@
"signInRequired": "Sign in again to use this account",
"signInAgain": "Sign in again",
"usageSignInLabel": "Sign in again",
"usageSignInMessage": "The selected Claude account needs you to sign in again. Open Settings > Accounts, or choose System default.",
"usageSignInMessage": "The selected Claude account needs you to sign in again. Open Settings > AI Provider Accounts, or choose System default.",
"signIn": "Sign in",
"signInNotice": {
"title": "Finish setting up your Claude accounts",