fix(ui): normalize grouped account audience order

This commit is contained in:
Tam Nhu Tran
2026-03-30 15:30:11 -04:00
parent 22f091689f
commit 498448a431
2 changed files with 72 additions and 10 deletions
+31 -10
View File
@@ -34,6 +34,12 @@ export interface AccountVisualGroup {
variants?: AccountVisualVariant[];
}
const AUDIENCE_ORDER: Record<AccountAudience, number> = {
business: 0,
personal: 1,
unknown: 2,
};
function getLatestTimestamp(current?: string, candidate?: string): string | undefined {
if (!candidate) return current;
if (!current) return candidate;
@@ -64,6 +70,20 @@ function buildAccountVariant(
};
}
function sortAccountVariants(variants: AccountVisualVariant[]): AccountVisualVariant[] {
return [...variants].sort((left, right) => {
const audienceDelta = AUDIENCE_ORDER[left.audience] - AUDIENCE_ORDER[right.audience];
if (audienceDelta !== 0) {
return audienceDelta;
}
const leftLabel = left.audienceLabel ?? left.detailLabel ?? left.id;
const rightLabel = right.audienceLabel ?? right.detailLabel ?? right.id;
return leftLabel.localeCompare(rightLabel);
});
}
export function buildAccountVisualGroups(
accounts: OAuthAccount[],
statsData?: Pick<CliproxyStats, 'accountStats'> | null
@@ -104,24 +124,25 @@ export function buildAccountVisualGroups(
};
}
const canonicalEmail = variants[0]?.email ?? bucketKey;
const originalProvider = accountMeta.get(variants[0]?.id ?? '')?.provider ?? 'codex';
const orderedVariants = sortAccountVariants(variants);
const canonicalEmail = orderedVariants[0]?.email ?? bucketKey;
const originalProvider = accountMeta.get(orderedVariants[0]?.id ?? '')?.provider ?? 'codex';
return {
id: bucketKey,
email: canonicalEmail,
tokenFile: variants[0]?.tokenFile ?? '',
tokenFile: orderedVariants[0]?.tokenFile ?? '',
provider: originalProvider,
isDefault: variants.some((variant) => variant.isDefault),
successCount: variants.reduce((sum, variant) => sum + variant.successCount, 0),
failureCount: variants.reduce((sum, variant) => sum + variant.failureCount, 0),
lastUsedAt: variants.reduce<string | undefined>(
isDefault: orderedVariants.some((variant) => variant.isDefault),
successCount: orderedVariants.reduce((sum, variant) => sum + variant.successCount, 0),
failureCount: orderedVariants.reduce((sum, variant) => sum + variant.failureCount, 0),
lastUsedAt: orderedVariants.reduce<string | undefined>(
(latest, variant) => getLatestTimestamp(latest, variant.lastUsedAt),
undefined
),
paused: variants.every((variant) => Boolean(variant.paused)),
memberIds: variants.map((variant) => variant.id),
variants,
paused: orderedVariants.every((variant) => Boolean(variant.paused)),
memberIds: orderedVariants.map((variant) => variant.id),
variants: orderedVariants,
};
});
}
@@ -0,0 +1,41 @@
import { describe, expect, it } from 'vitest';
import type { OAuthAccount } from '@/lib/api-client';
import { buildAccountVisualGroups } from '@/lib/account-visual-groups';
function makeAccount(overrides: Partial<OAuthAccount> & Pick<OAuthAccount, 'id' | 'tokenFile'>) {
return {
id: overrides.id,
email: 'kaidu.kd@gmail.com',
provider: 'codex',
isDefault: false,
tokenFile: overrides.tokenFile,
createdAt: '2026-03-30T00:00:00.000Z',
...overrides,
} satisfies OAuthAccount;
}
describe('buildAccountVisualGroups', () => {
it('orders grouped codex variants by audience consistently', () => {
const groups = buildAccountVisualGroups([
makeAccount({
id: 'kaidu.kd@gmail.com#free',
tokenFile: 'codex-kaidu.kd@gmail.com-free.json',
}),
makeAccount({
id: 'kaidu.kd@gmail.com#04a0f049-team',
tokenFile: 'codex-04a0f049-kaidu.kd@gmail.com-team.json',
}),
]);
expect(groups).toHaveLength(1);
expect(groups[0]?.variants?.map((variant) => variant.audience)).toEqual([
'business',
'personal',
]);
expect(groups[0]?.memberIds).toEqual([
'kaidu.kd@gmail.com#04a0f049-team',
'kaidu.kd@gmail.com#free',
]);
});
});