import { useStore } from '@nanostores/react' import { useQuery } from '@tanstack/react-query' import { useMemo, useState } from 'react' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Switch } from '@/components/ui/switch' import type { HermesGateway } from '@/hermes' import { getGlobalModelOptions } from '@/hermes' import { displayModelName, modelDisplayParts } from '@/lib/model-status-label' import { $visibleModels, collapseModelFamilies, effectiveVisibleKeys, modelVisibilityKey, setVisibleModels } from '@/store/model-visibility' import type { ModelOptionProvider, ModelOptionsResponse } from '@/types/hermes' interface ModelVisibilityDialogProps { gw?: HermesGateway onOpenChange: (open: boolean) => void onOpenProviders: () => void open: boolean sessionId?: string | null } export function ModelVisibilityDialog({ gw, onOpenChange, onOpenProviders, open, sessionId }: ModelVisibilityDialogProps) { const [search, setSearch] = useState('') const stored = useStore($visibleModels) const modelOptions = useQuery({ queryKey: ['model-options', sessionId || 'global'], queryFn: (): Promise => { if (gw && sessionId) { return gw.request('model.options', { session_id: sessionId }) } return getGlobalModelOptions() }, enabled: open }) const providers = useMemo( () => (modelOptions.data?.providers ?? []).filter(provider => (provider.models ?? []).length > 0), [modelOptions.data] ) const visible = effectiveVisibleKeys(stored, providers) const toggle = (provider: ModelOptionProvider, model: string) => { const next = new Set(effectiveVisibleKeys($visibleModels.get(), providers)) const key = modelVisibilityKey(provider.slug, model) if (next.has(key)) { next.delete(key) } else { next.add(key) } setVisibleModels(next) } const q = search.trim().toLowerCase() const matches = (provider: ModelOptionProvider, model: string) => !q || `${model} ${provider.name} ${provider.slug} ${displayModelName(model)}`.toLowerCase().includes(q) return ( Models
setSearch(event.target.value)} placeholder="Search models" type="text" value={search} />
{providers.length === 0 ? (
{modelOptions.isPending ? 'Loading…' : 'No authenticated providers.'}
) : ( providers.map(provider => { const models = collapseModelFamilies(provider.models ?? []).filter(family => matches(provider, family.id) ) if (models.length === 0) { return null } return (
{provider.name}
{models.map(family => { const { name, tag } = modelDisplayParts(family.id) const key = modelVisibilityKey(provider.slug, family.id) return ( ) })}
) }) )}
) }