mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
feat(dashboard): add project_id display for Antigravity accounts
Display GCP project_id for Antigravity (agy) accounts in the Dashboard: - Add projectId field to AccountInfo interface (account-manager.ts) - Read project_id from auth files when discovering/registering accounts - Pass projectId through token-manager when registering new accounts - Add projectId to OAuthAccount type (api-client.ts) - Add projectId to AccountRow type (auth-monitor/types.ts) - Display project_id in account-item.tsx with FolderCode icon - Show N/A warning with amber tooltip if project_id is missing suggesting user remove and re-add account to fetch it Note: project_id is read-only and respects privacy mode blur.
This commit is contained in:
@@ -47,6 +47,8 @@ export interface AccountInfo {
|
||||
pausedAt?: string;
|
||||
/** Account tier: free or paid (Pro/Ultra combined) */
|
||||
tier?: AccountTier;
|
||||
/** GCP Project ID (Antigravity only) - read-only, fetched from auth token */
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
/** Provider accounts configuration */
|
||||
@@ -293,7 +295,8 @@ export function registerAccount(
|
||||
provider: CLIProxyProvider,
|
||||
tokenFile: string,
|
||||
email?: string,
|
||||
nickname?: string
|
||||
nickname?: string,
|
||||
projectId?: string
|
||||
): AccountInfo {
|
||||
const registry = loadAccountsRegistry();
|
||||
|
||||
@@ -350,7 +353,7 @@ export function registerAccount(
|
||||
const isFirstAccount = Object.keys(providerAccounts.accounts).length === 0;
|
||||
|
||||
// Create or update account
|
||||
providerAccounts.accounts[accountId] = {
|
||||
const accountMeta: Omit<AccountInfo, 'id' | 'provider' | 'isDefault'> = {
|
||||
email,
|
||||
nickname: accountNickname,
|
||||
tokenFile,
|
||||
@@ -358,6 +361,13 @@ export function registerAccount(
|
||||
lastUsedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// Include projectId for Antigravity accounts
|
||||
if (provider === 'agy' && projectId) {
|
||||
accountMeta.projectId = projectId;
|
||||
}
|
||||
|
||||
providerAccounts.accounts[accountId] = accountMeta;
|
||||
|
||||
// Set as default if first account
|
||||
if (isFirstAccount) {
|
||||
providerAccounts.default = accountId;
|
||||
@@ -671,13 +681,20 @@ export function discoverExistingAccounts(): void {
|
||||
// Register account with auto-generated nickname
|
||||
// Use mtime as lastUsedAt (when token was last modified = last auth/refresh)
|
||||
const lastModified = stats.mtime || stats.birthtime || new Date();
|
||||
providerAccounts.accounts[accountId] = {
|
||||
const accountMeta: Omit<AccountInfo, 'id' | 'provider' | 'isDefault'> = {
|
||||
email,
|
||||
nickname: generateNickname(email),
|
||||
tokenFile: file,
|
||||
createdAt: stats.birthtime?.toISOString() || new Date().toISOString(),
|
||||
lastUsedAt: lastModified.toISOString(),
|
||||
};
|
||||
|
||||
// Read project_id for Antigravity accounts (read-only field from auth token)
|
||||
if (provider === 'agy' && data.project_id) {
|
||||
accountMeta.projectId = data.project_id;
|
||||
}
|
||||
|
||||
providerAccounts.accounts[accountId] = accountMeta;
|
||||
} catch {
|
||||
// Skip invalid files
|
||||
continue;
|
||||
|
||||
@@ -229,8 +229,15 @@ export function registerAccountFromToken(
|
||||
const content = fs.readFileSync(tokenPath, 'utf-8');
|
||||
const data = JSON.parse(content);
|
||||
const email = data.email || undefined;
|
||||
const projectId = data.project_id || undefined;
|
||||
|
||||
return registerAccount(provider, newestFile, email, nickname || generateNickname(email));
|
||||
return registerAccount(
|
||||
provider,
|
||||
newestFile,
|
||||
email,
|
||||
nickname || generateNickname(email),
|
||||
projectId
|
||||
);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import {
|
||||
Pause,
|
||||
Play,
|
||||
AlertCircle,
|
||||
AlertTriangle,
|
||||
FolderCode,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
cn,
|
||||
@@ -167,6 +169,48 @@ export function AccountItem({
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{/* Project ID for Antigravity accounts - read-only */}
|
||||
{account.provider === 'agy' && (
|
||||
<div className="flex items-center gap-1.5 mt-1">
|
||||
{account.projectId ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<FolderCode className="w-3 h-3" />
|
||||
<span className={cn('font-mono', privacyMode && PRIVACY_BLUR_CLASS)}>
|
||||
{account.projectId}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
<p className="text-xs">GCP Project ID (read-only)</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center gap-1 text-xs text-amber-600 dark:text-amber-500">
|
||||
<AlertTriangle className="w-3 h-3" />
|
||||
<span>Project ID: N/A</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="max-w-[250px]">
|
||||
<div className="text-xs space-y-1">
|
||||
<p className="font-medium text-amber-600">Missing Project ID</p>
|
||||
<p>
|
||||
This may cause errors. Remove the account and re-add it to fetch the
|
||||
project ID.
|
||||
</p>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{account.lastUsedAt && (
|
||||
<div className="flex items-center gap-1 text-xs text-muted-foreground mt-0.5">
|
||||
<Clock className="w-3 h-3" />
|
||||
|
||||
@@ -99,6 +99,7 @@ export function useAuthMonitorData(): AuthMonitorData {
|
||||
failureCount: failure,
|
||||
lastUsedAt: realStats?.lastUsedAt ?? account.lastUsedAt,
|
||||
color: ACCOUNT_COLORS[colorIndex % ACCOUNT_COLORS.length],
|
||||
projectId: account.projectId,
|
||||
};
|
||||
accountsList.push(row);
|
||||
providerData.accounts.push(row);
|
||||
|
||||
@@ -12,6 +12,8 @@ export interface AccountRow {
|
||||
failureCount: number;
|
||||
lastUsedAt?: string;
|
||||
color: string;
|
||||
/** GCP Project ID (Antigravity only) - read-only */
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface ProviderStats {
|
||||
|
||||
@@ -83,6 +83,8 @@ export interface OAuthAccount {
|
||||
pausedAt?: string;
|
||||
/** Account tier: free or paid (Pro/Ultra combined) */
|
||||
tier?: 'free' | 'paid' | 'unknown';
|
||||
/** GCP Project ID (Antigravity only) - read-only */
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface AuthStatus {
|
||||
|
||||
Reference in New Issue
Block a user