import { Fragment, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; import { Card } from '@/components/ui/Card'; import { ToggleSwitch } from '@/components/ui/ToggleSwitch'; import iconCodex from '@/assets/icons/codex.svg'; import type { ProviderKeyConfig } from '@/types'; import { maskApiKey } from '@/utils/format'; import { calculateStatusBarData, type KeyStats } from '@/utils/usage'; import { type UsageDetailsByAuthIndex, type UsageDetailsBySource } from '@/utils/usageIndex'; import styles from '@/pages/AiProvidersPage.module.scss'; import { ProviderList } from '../ProviderList'; import { ProviderStatusBar } from '../ProviderStatusBar'; import { collectUsageDetailsForIdentity, getProviderConfigKey, getStatsForIdentity, hasDisableAllModelsRule, } from '../utils'; interface CodexSectionProps { configs: ProviderKeyConfig[]; keyStats: KeyStats; usageDetailsBySource: UsageDetailsBySource; usageDetailsByAuthIndex: UsageDetailsByAuthIndex; loading: boolean; disableControls: boolean; isSwitching: boolean; onAdd: () => void; onEdit: (index: number) => void; onDelete: (index: number) => void; onToggle: (index: number, enabled: boolean) => void; } export function CodexSection({ configs, keyStats, usageDetailsBySource, usageDetailsByAuthIndex, loading, disableControls, isSwitching, onAdd, onEdit, onDelete, onToggle, }: CodexSectionProps) { const { t } = useTranslation(); const actionsDisabled = disableControls || loading || isSwitching; const toggleDisabled = disableControls || loading || isSwitching; const statusBarCache = useMemo(() => { const cache = new Map>(); configs.forEach((config, index) => { if (!config.apiKey) return; const configKey = getProviderConfigKey(config, index); cache.set( configKey, calculateStatusBarData( collectUsageDetailsForIdentity( { authIndex: config.authIndex, apiKey: config.apiKey, prefix: config.prefix }, usageDetailsBySource, usageDetailsByAuthIndex ) ) ); }); return cache; }, [configs, usageDetailsByAuthIndex, usageDetailsBySource]); return ( <> {t('ai_providers.codex_title')} } extra={ } > items={configs} loading={loading} keyField={(item, index) => getProviderConfigKey(item, index)} emptyTitle={t('ai_providers.codex_empty_title')} emptyDescription={t('ai_providers.codex_empty_desc')} onEdit={(_, index) => onEdit(index)} onDelete={(_, index) => onDelete(index)} actionsDisabled={actionsDisabled} getRowDisabled={(item) => hasDisableAllModelsRule(item.excludedModels)} renderExtraActions={(item, index) => ( void onToggle(index, value)} /> )} renderContent={(item, index) => { const stats = getStatsForIdentity( { authIndex: item.authIndex, apiKey: item.apiKey, prefix: item.prefix }, keyStats ); const headerEntries = Object.entries(item.headers || {}); const configDisabled = hasDisableAllModelsRule(item.excludedModels); const excludedModels = item.excludedModels ?? []; const statusData = statusBarCache.get(getProviderConfigKey(item, index)) || calculateStatusBarData([]); return (
{t('ai_providers.codex_item_title')}
{t('common.api_key')}: {maskApiKey(item.apiKey)}
{item.priority !== undefined && (
{t('common.priority')}: {item.priority}
)} {item.prefix && (
{t('common.prefix')}: {item.prefix}
)} {item.baseUrl && (
{t('common.base_url')}: {item.baseUrl}
)} {item.proxyUrl && (
{t('common.proxy_url')}: {item.proxyUrl}
)} {item.websockets !== undefined && (
{t('ai_providers.codex_websockets_label')}: {item.websockets ? t('common.yes') : t('common.no')}
)} {headerEntries.length > 0 && (
{headerEntries.map(([key, value]) => ( {key}: {value} ))}
)} {configDisabled && (
{t('ai_providers.config_disabled_badge')}
)} {item.models?.length ? (
{t('ai_providers.codex_models_count')}: {item.models.length} {item.models.map((model) => ( {model.name} {model.alias && model.alias !== model.name && ( {model.alias} )} ))}
) : null} {excludedModels.length ? (
{t('ai_providers.excluded_models_count', { count: excludedModels.length })}
{excludedModels.map((model) => ( {model} ))}
) : null}
{t('stats.success')}: {stats.success} {t('stats.failure')}: {stats.failure}
); }} />
); }