mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-14 12:16:38 +00:00
Merge pull request #1022 from kaitranntt/kai/fix/codex-free-account-badge
fix(accounts): refine codex plan badges
This commit is contained in:
14 files changed
+523
-133
No files matched your search
@@ -1,6 +1,9 @@
|
||||
import type { CLIProxyProvider } from '../types';
|
||||
|
||||
const DUPLICATE_EMAIL_ACCOUNT_PROVIDERS = new Set<string>(['codex']);
|
||||
const FREE_PLAN_PARTS = new Set(['free']);
|
||||
const PERSONAL_PLAN_PARTS = new Set(['plus', 'pro']);
|
||||
const BUSINESS_PLAN_PARTS = new Set(['team']);
|
||||
|
||||
// Keep variant parsing aligned with ui/src/lib/account-identity.ts. The UI copy is
|
||||
// separate because the browser bundle cannot import this server module directly.
|
||||
@@ -49,6 +52,20 @@ function formatVariantPart(value: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function formatWorkspaceLabel(parts: string[]): string | null {
|
||||
const workspaceId = parts.find((part) => /^[a-f0-9]{8}$/i.test(part));
|
||||
if (workspaceId) {
|
||||
return `Workspace ${workspaceId.toLowerCase()}`;
|
||||
}
|
||||
|
||||
return parts.map(formatVariantPart).filter(Boolean).join(' · ') || null;
|
||||
}
|
||||
|
||||
function formatAudienceDetail(parts: string[]): string | null {
|
||||
const label = parts.map(formatVariantPart).filter(Boolean).join(' · ');
|
||||
return label || null;
|
||||
}
|
||||
|
||||
export function supportsDuplicateEmailAccounts(provider: CLIProxyProvider | string): boolean {
|
||||
return DUPLICATE_EMAIL_ACCOUNT_PROVIDERS.has(normalizeProvider(provider));
|
||||
}
|
||||
@@ -136,8 +153,16 @@ export function formatAccountVariantLabel(accountId: string, email?: string): st
|
||||
}
|
||||
|
||||
const suffix = parts[parts.length - 1]?.toLowerCase();
|
||||
if (suffix && ['team', 'free', 'plus', 'pro'].includes(suffix)) {
|
||||
return [formatVariantPart(suffix), ...parts.slice(0, -1).map(formatVariantPart)]
|
||||
if (suffix && BUSINESS_PLAN_PARTS.has(suffix)) {
|
||||
return ['Business', formatWorkspaceLabel(parts.slice(0, -1))].filter(Boolean).join(' · ');
|
||||
}
|
||||
|
||||
if (suffix && FREE_PLAN_PARTS.has(suffix)) {
|
||||
return ['Free', formatAudienceDetail(parts.slice(0, -1))].filter(Boolean).join(' · ');
|
||||
}
|
||||
|
||||
if (suffix && PERSONAL_PLAN_PARTS.has(suffix)) {
|
||||
return ['Personal', formatVariantPart(suffix), formatAudienceDetail(parts.slice(0, -1))]
|
||||
.filter(Boolean)
|
||||
.join(' · ');
|
||||
}
|
||||
|
||||
@@ -624,11 +624,12 @@ export async function fetchCodexQuota(
|
||||
|
||||
// Extract plan type
|
||||
const planTypeRaw = data.plan_type || data.planType;
|
||||
let planType: 'free' | 'plus' | 'team' | null = null;
|
||||
let planType: 'free' | 'plus' | 'pro' | 'team' | null = null;
|
||||
if (planTypeRaw) {
|
||||
const normalized = planTypeRaw.toLowerCase();
|
||||
if (normalized === 'free') planType = 'free';
|
||||
else if (normalized === 'plus') planType = 'plus';
|
||||
else if (normalized === 'pro') planType = 'pro';
|
||||
else if (normalized === 'team') planType = 'team';
|
||||
}
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ export interface CodexQuotaResult extends QuotaErrorMetadata {
|
||||
windows: CodexQuotaWindow[];
|
||||
/** Explicit core usage windows (5h + weekly) for easier reset display */
|
||||
coreUsage?: CodexCoreUsageSummary;
|
||||
/** Plan type: free, plus, team, or null if unknown */
|
||||
planType: 'free' | 'plus' | 'team' | null;
|
||||
/** Plan type: free, plus, pro, team, or null if unknown */
|
||||
planType: 'free' | 'plus' | 'pro' | 'team' | null;
|
||||
/** Timestamp of fetch */
|
||||
lastUpdated: number;
|
||||
/** Error message if fetch failed */
|
||||
|
||||
Reference in new issue
Block a user