fix(desktop): a sign-in stays visible when the same profile is picked again

Review round 3: on a multi-connection desktop the scope selector pins
`{connectionId, profile}` while an operation started from the ambient
scope holds the bare profile name, so re-picking the same profile hid
the open sign-in. Scopes now compare by the backend they resolve to
(connection, else the active one, plus profile).
This commit is contained in:
Siddharth Balyan
2026-10-08 21:49:16 +05:30
committed by Siddharth Balyan
parent 49c396d20a
commit 66f4ab7932
2 changed files with 23 additions and 3 deletions

View File

@@ -24,4 +24,10 @@ describe('accountOperationFor', () => {
expect(accountOperationFor(operations, 'gmail', { connectionId: 'remote', profile: 'home' })?.opId).toBe('b')
expect(accountOperationFor(operations, 'gmail', 'other')).toBeNull()
})
it('treats a bare profile and the same profile pinned to the active connection as one scope', () => {
const operations = { a: operation('a', 'home') }
expect(accountOperationFor(operations, 'gmail', { connectionId: 'local', profile: 'home' })?.opId).toBe('a')
})
})

View File

@@ -6,8 +6,10 @@ import type {
} from '@hermes/shared'
import { atom } from 'nanostores'
import { type ProfileScope, profileScopeKey } from '@/hermes'
import type { ProfileScope } from '@/hermes'
import { type ConnectionTarget, parseConnectionTarget } from '@/store/connection-request'
import { activeGatewayConnectionId } from '@/store/gateway'
import { normalizeProfileKey } from '@/store/profile'
import { invalidateConnectors } from './keys'
import { accountOperationStatus } from './rpc'
@@ -44,16 +46,28 @@ function resumeConnect(slugs: readonly string[]): void {
const parseTargets = (targets: ConnectionUpdatePayload['targets']): ConnectionTarget[] =>
targets.map(parseConnectionTarget).filter((target): target is ConnectionTarget => target !== null)
// A bare profile name rides the active connection, so `'home'` and `{connectionId: <active>, profile: 'home'}` are
// the same backend and must match.
function resolvedScopeKey(scope: ProfileScope): string {
const active = activeGatewayConnectionId() ?? 'local'
if (scope instanceof Object) {
return `${(scope.connectionId ?? '').trim() || 'local'}::${normalizeProfileKey(scope.profile)}`
}
return `${active}::${normalizeProfileKey(scope)}`
}
/** The open (else newest) operation for one app in one profile scope; other profiles' sign-ins are not this one's. */
export function accountOperationFor(
operations: Readonly<Record<string, AccountOperation>>,
slug: string,
scope: ProfileScope
): AccountOperation | null {
const key = profileScopeKey(scope)
const key = resolvedScopeKey(scope)
const mine = Object.values(operations).filter(
operation => operation.connectors.includes(slug) && profileScopeKey(operation.scope) === key
operation => operation.connectors.includes(slug) && resolvedScopeKey(operation.scope) === key
)
return mine.find(operation => !operation.settled) ?? mine[mine.length - 1] ?? null