import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useAppConfig } from '@/hooks/useAppConfig'; import { useCloudAccounts } from '@/hooks/useCloudAccounts'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Checkbox } from '@/components/ui/checkbox'; import { Badge } from '@/components/ui/badge'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; import { Loader2, Search, RotateCcw, Save, Copy, CheckCircle } from 'lucide-react'; import { filter, flatMap, includes, size, sortBy, sumBy, uniq, values } from 'lodash-es'; import type { CloudAccount } from '@/types/cloudAccount'; function collectAvailableModelIds(accounts: CloudAccount[] | undefined): string[] { if (!accounts) { return []; } const modelNames = flatMap(accounts, (account) => { if (!account.quota?.models) { return []; } return Object.keys(account.quota.models); }); return sortBy(uniq(modelNames)); } function filterModelIdsByQuery(modelIds: string[], query: string): string[] { const normalizedSearchQuery = query.toLowerCase(); return filter(modelIds, (modelId) => includes(modelId.toLowerCase(), normalizedSearchQuery)); } export function ModelVisibilitySettings() { const { t } = useTranslation(); const { config, saveConfig } = useAppConfig(); const { data: accounts, isLoading: accountsLoading } = useCloudAccounts(); const [searchQuery, setSearchQuery] = useState(''); const [modelVisibilityMap, setModelVisibilityMap] = useState>({}); const [providerGroupingEnabled, setProviderGroupingEnabled] = useState(false); const [isSavingSettings, setIsSavingSettings] = useState(false); const [copiedModel, setCopiedModel] = useState(null); // Initialize model visibility and provider groupings from config useEffect(() => { if (config?.model_visibility) { setTimeout(() => setModelVisibilityMap(config.model_visibility), 0); } if (config?.provider_groupings_enabled !== undefined) { setTimeout(() => setProviderGroupingEnabled(config.provider_groupings_enabled), 0); } }, [config?.model_visibility, config?.provider_groupings_enabled]); // Get all unique models from all accounts const availableModelIds = useMemo(() => { return collectAvailableModelIds(accounts); }, [accounts]); // Filter models based on search term const filteredModelIds = useMemo(() => { return filterModelIdsByQuery(availableModelIds, searchQuery); }, [availableModelIds, searchQuery]); const hiddenModelCount = useMemo(() => { return sumBy(values(modelVisibilityMap), (isVisible) => (isVisible === false ? 1 : 0)); }, [modelVisibilityMap]); const isModelVisible = (modelId: string): boolean => { return modelVisibilityMap[modelId] !== false; }; // Reset to defaults (all models visible) const resetVisibilityOverrides = () => { setModelVisibilityMap({}); }; // Save configuration const saveVisibilitySettings = async () => { if (!config) { return; } setIsSavingSettings(true); try { const nextConfig = { ...config, model_visibility: modelVisibilityMap, provider_groupings_enabled: providerGroupingEnabled, }; await saveConfig(nextConfig); } catch (error) { console.error('Failed to save model visibility settings:', error); } finally { setIsSavingSettings(false); } }; const handleSearchQueryChange = (nextQuery: string) => { setSearchQuery(nextQuery); }; const handleProviderGroupingToggle = (checked: boolean) => { setProviderGroupingEnabled(checked); }; const handleModelVisibilityChange = (modelId: string, checked: boolean) => { setModelVisibilityMap((prev) => ({ ...prev, [modelId]: checked, })); }; const copyModelId = (modelId: string, e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); navigator.clipboard.writeText(modelId); setCopiedModel(modelId); setTimeout(() => setCopiedModel(null), 2000); }; if (accountsLoading) { return ( {t('common.loading')} ); } return ( {t('settings.modelVisibility.title')} {t('settings.providerGroupings.models', { count: filteredModelIds.length })} {t('settings.modelVisibility.description')} {/* Search */}
handleSearchQueryChange(event.target.value)} className="pl-10" />
{/* Provider Groupings Toggle */}

{t('settings.providerGroupings.description')}

{/* Model List */}
{filteredModelIds.length === 0 ? (
{searchQuery ? t('settings.modelVisibility.noModelsFound') : t('settings.modelVisibility.noModels')}
) : ( filteredModelIds.map((modelId) => { const isVisible = isModelVisible(modelId); return (
handleModelVisibilityChange(modelId, checked as boolean) } />
{!isVisible && ( {t('settings.modelVisibility.hidden')} )}
); }) )}
{/* Action Buttons */}
{/* Statistics */}
{t('settings.modelVisibility.totalModels')}: {availableModelIds.length} {t('settings.modelVisibility.visibleModels')}:{' '} {availableModelIds.length - hiddenModelCount} {t('settings.modelVisibility.hiddenModels')}: {hiddenModelCount}
); }