"use client"; import { useAtomValue } from "jotai"; import { Check, ChevronDown, ChevronRight, Edit3, Globe, ImageIcon, Plus, Shuffle, User, } from "lucide-react"; import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; import { createImageGenConfigMutationAtom, updateImageGenConfigMutationAtom, } from "@/atoms/image-gen-config/image-gen-config-mutation.atoms"; import { globalImageGenConfigsAtom, imageGenConfigsAtom, } from "@/atoms/image-gen-config/image-gen-config-query.atoms"; import { updateLLMPreferencesMutationAtom } from "@/atoms/new-llm-config/new-llm-config-mutation.atoms"; import { llmPreferencesAtom } from "@/atoms/new-llm-config/new-llm-config-query.atoms"; import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Spinner } from "@/components/ui/spinner"; import type { GlobalImageGenConfig, ImageGenerationConfig, } from "@/contracts/types/new-llm-config.types"; import { cn } from "@/lib/utils"; interface ImageModelSelectorProps { className?: string; onAddNew?: () => void; onEdit?: (config: ImageGenerationConfig | GlobalImageGenConfig, isGlobal: boolean) => void; } export function ImageModelSelector({ className, onAddNew, onEdit }: ImageModelSelectorProps) { const [open, setOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const { data: globalConfigs, isLoading: globalLoading } = useAtomValue(globalImageGenConfigsAtom); const { data: userConfigs, isLoading: userLoading } = useAtomValue(imageGenConfigsAtom); const { data: preferences, isLoading: prefsLoading } = useAtomValue(llmPreferencesAtom); const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom); const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); const isLoading = globalLoading || userLoading || prefsLoading; const currentConfig = useMemo(() => { if (!preferences) return null; const id = preferences.image_generation_config_id; if (id === null || id === undefined) return null; const globalMatch = globalConfigs?.find((c) => c.id === id); if (globalMatch) return globalMatch; return userConfigs?.find((c) => c.id === id) ?? null; }, [preferences, globalConfigs, userConfigs]); const isCurrentAutoMode = useMemo(() => { return currentConfig && "is_auto_mode" in currentConfig && currentConfig.is_auto_mode; }, [currentConfig]); const filteredGlobal = useMemo(() => { if (!globalConfigs) return []; if (!searchQuery) return globalConfigs; const q = searchQuery.toLowerCase(); return globalConfigs.filter( (c) => c.name.toLowerCase().includes(q) || c.model_name.toLowerCase().includes(q) || c.provider.toLowerCase().includes(q) ); }, [globalConfigs, searchQuery]); const filteredUser = useMemo(() => { if (!userConfigs) return []; if (!searchQuery) return userConfigs; const q = searchQuery.toLowerCase(); return userConfigs.filter( (c) => c.name.toLowerCase().includes(q) || c.model_name.toLowerCase().includes(q) || c.provider.toLowerCase().includes(q) ); }, [userConfigs, searchQuery]); const totalModels = (globalConfigs?.length ?? 0) + (userConfigs?.length ?? 0); const handleSelect = useCallback( async (configId: number) => { if (currentConfig?.id === configId) { setOpen(false); return; } if (!searchSpaceId) { toast.error("No search space selected"); return; } try { await updatePreferences({ search_space_id: Number(searchSpaceId), data: { image_generation_config_id: configId }, }); toast.success("Image model updated"); setOpen(false); } catch { toast.error("Failed to switch image model"); } }, [currentConfig, searchSpaceId, updatePreferences] ); // Don't render if no configs at all if (!isLoading && totalModels === 0) { return ( ); } return ( {totalModels > 3 && (
)}

No image models found

{/* Global Image Gen Configs */} {filteredGlobal.length > 0 && (
Global Image Models
{filteredGlobal.map((config) => { const isSelected = currentConfig?.id === config.id; const isAuto = "is_auto_mode" in config && config.is_auto_mode; return ( handleSelect(config.id)} className={cn( "mx-2 rounded-lg mb-1 cursor-pointer group transition-all hover:bg-accent/50", isSelected && "bg-accent/80", isAuto && "border border-violet-200 dark:border-violet-800/50" )} >
{isAuto ? ( ) : ( )}
{config.name} {isAuto && ( Recommended )} {isSelected && }
{isAuto ? "Auto load balancing" : config.model_name}
{onEdit && ( { e.stopPropagation(); setOpen(false); onEdit(config, true); }} /> )}
); })}
)} {/* User Image Gen Configs */} {filteredUser.length > 0 && ( <> {filteredGlobal.length > 0 && }
Your Image Models
{filteredUser.map((config) => { const isSelected = currentConfig?.id === config.id; return ( handleSelect(config.id)} className={cn( "mx-2 rounded-lg mb-1 cursor-pointer group transition-all hover:bg-accent/50", isSelected && "bg-accent/80" )} >
{config.name} {isSelected && }
{config.model_name}
{onEdit && ( )}
); })}
)} {/* Add New */} {onAddNew && (
)}
); }