From 99d4296ee142e97ee8fbf1955c5441f33dd252a2 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Sat, 11 Oct 2025 07:18:44 +0000 Subject: [PATCH] Enhance AI model selection with search and scroll functionality Replace standard select components with a new ModelCombobox component in both the AI chat and settings pages. This component supports searching and vertical scrolling for a better user experience when selecting AI models. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/cesUZ4w --- client/src/components/ai-chat.tsx | 38 ++----- client/src/components/model-combobox.tsx | 134 +++++++++++++++++++++++ client/src/pages/settings.tsx | 25 ++--- 3 files changed, 156 insertions(+), 41 deletions(-) create mode 100644 client/src/components/model-combobox.tsx diff --git a/client/src/components/ai-chat.tsx b/client/src/components/ai-chat.tsx index bb2d530..55320bd 100644 --- a/client/src/components/ai-chat.tsx +++ b/client/src/components/ai-chat.tsx @@ -6,7 +6,7 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { Bot, User, Lightbulb, History, Zap, Sparkles, Loader2 } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { ModelCombobox } from "@/components/model-combobox"; interface Message { role: "user" | "assistant"; @@ -114,32 +114,16 @@ export default function AiChat() {
- +
diff --git a/client/src/components/model-combobox.tsx b/client/src/components/model-combobox.tsx new file mode 100644 index 0000000..90f6de2 --- /dev/null +++ b/client/src/components/model-combobox.tsx @@ -0,0 +1,134 @@ +import { useState } from "react"; +import { Check, ChevronsUpDown, Loader2 } from "lucide-react"; +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "@/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; + +interface Model { + id: string; + name: string; + pricing?: { + prompt: string; + completion: string; + }; +} + +interface ModelComboboxProps { + models: Model[]; + value: string; + onValueChange: (value: string) => void; + placeholder?: string; + isLoading?: boolean; + disabled?: boolean; + className?: string; + testId?: string; +} + +export function ModelCombobox({ + models, + value, + onValueChange, + placeholder = "Sélectionner un modèle", + isLoading = false, + disabled = false, + className, + testId, +}: ModelComboboxProps) { + const [open, setOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + + const selectedModel = models.find((model) => model.id === value); + + const filteredModels = models.filter((model) => + model.name.toLowerCase().includes(searchQuery.toLowerCase()) || + model.id.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + return ( + + + + + + + + + Aucun modèle trouvé. + + {filteredModels.map((model) => ( + { + onValueChange(currentValue); + setOpen(false); + setSearchQuery(""); + }} + data-testid={`${testId}-option-${model.id}`} + > + +
+ {model.name} + {model.pricing && ( + + Prompt: ${model.pricing.prompt} | Completion: ${model.pricing.completion} + + )} +
+
+ ))} +
+
+
+
+
+ ); +} diff --git a/client/src/pages/settings.tsx b/client/src/pages/settings.tsx index 788aabb..e3bf3cb 100644 --- a/client/src/pages/settings.tsx +++ b/client/src/pages/settings.tsx @@ -8,10 +8,10 @@ import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Button } from "@/components/ui/button"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; +import { ModelCombobox } from "@/components/model-combobox"; export default function Settings() { const [sidebarOpen, setSidebarOpen] = useState(false); @@ -33,7 +33,7 @@ export default function Settings() { queryKey: ['/api/openrouter/config'], }); - const { data: openrouterModels } = useQuery({ + const { data: openrouterModels, isLoading: modelsLoading } = useQuery({ queryKey: ['/api/openrouter/models'], }); @@ -227,18 +227,15 @@ export default function Settings() {
- +

Choisissez le modèle d'IA pour générer vos publications