import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; import { ToggleSwitch } from '@/components/ui/ToggleSwitch'; import { IconBot, IconCode, IconDownload, IconInfo, IconTrash2 } from '@/components/ui/icons'; import { ProviderStatusBar } from '@/components/providers/ProviderStatusBar'; import type { AuthFileItem } from '@/types'; import { resolveAuthProvider } from '@/utils/quota'; import { calculateStatusBarData, type KeyStats } from '@/utils/usage'; import { formatFileSize } from '@/utils/format'; import { QUOTA_PROVIDER_TYPES, formatModified, getTypeColor, getTypeLabel, isRuntimeOnlyAuthFile, normalizeAuthIndexValue, resolveAuthFileStats, type QuotaProviderType, type ResolvedTheme } from '@/features/authFiles/constants'; import type { AuthFileStatusBarData } from '@/features/authFiles/hooks/useAuthFilesStatusBarCache'; import { AuthFileQuotaSection } from '@/features/authFiles/components/AuthFileQuotaSection'; import styles from '@/pages/AuthFilesPage.module.scss'; export type AuthFileCardProps = { file: AuthFileItem; resolvedTheme: ResolvedTheme; disableControls: boolean; deleting: string | null; statusUpdating: Record; quotaFilterType: QuotaProviderType | null; keyStats: KeyStats; statusBarCache: Map; onShowModels: (file: AuthFileItem) => void; onShowDetails: (file: AuthFileItem) => void; onDownload: (name: string) => void; onOpenPrefixProxyEditor: (name: string) => void; onDelete: (name: string) => void; onToggleStatus: (file: AuthFileItem, enabled: boolean) => void; }; const resolveQuotaType = (file: AuthFileItem): QuotaProviderType | null => { const provider = resolveAuthProvider(file); if (!QUOTA_PROVIDER_TYPES.has(provider as QuotaProviderType)) return null; return provider as QuotaProviderType; }; export function AuthFileCard(props: AuthFileCardProps) { const { t } = useTranslation(); const { file, resolvedTheme, disableControls, deleting, statusUpdating, quotaFilterType, keyStats, statusBarCache, onShowModels, onShowDetails, onDownload, onOpenPrefixProxyEditor, onDelete, onToggleStatus } = props; const fileStats = resolveAuthFileStats(file, keyStats); const isRuntimeOnly = isRuntimeOnlyAuthFile(file); const isAistudio = (file.type || '').toLowerCase() === 'aistudio'; const showModelsButton = !isRuntimeOnly || isAistudio; const typeColor = getTypeColor(file.type || 'unknown', resolvedTheme); const quotaType = quotaFilterType && resolveQuotaType(file) === quotaFilterType ? quotaFilterType : null; const showQuotaLayout = Boolean(quotaType) && !isRuntimeOnly; const providerCardClass = quotaType === 'antigravity' ? styles.antigravityCard : quotaType === 'codex' ? styles.codexCard : quotaType === 'gemini-cli' ? styles.geminiCliCard : ''; const rawAuthIndex = file['auth_index'] ?? file.authIndex; const authIndexKey = normalizeAuthIndexValue(rawAuthIndex); const statusData = (authIndexKey && statusBarCache.get(authIndexKey)) || calculateStatusBarData([]); return (
{getTypeLabel(t, file.type || 'unknown')} {file.name}
{t('auth_files.file_size')}: {file.size ? formatFileSize(file.size) : '-'} {t('auth_files.file_modified')}: {formatModified(file)}
{t('stats.success')}: {fileStats.success} {t('stats.failure')}: {fileStats.failure}
{showQuotaLayout && quotaType && ( )}
{showModelsButton && ( )} {!isRuntimeOnly && ( <> )} {!isRuntimeOnly && (
onToggleStatus(file, value)} />
)} {isRuntimeOnly && (
{t('auth_files.type_virtual') || '虚拟认证文件'}
)}
); }