Merge pull request #65 from R0m1k3/claude/fix-stack-redeploy-error-011CV4ma2o8R5TFqh2v7L5hK

Feature: Amélioration du sélecteur de modèles IA avec recherche
This commit is contained in:
LogiFlow authored and GitHub committed 2025-11-13 10:05:03 +01:00
commit 84b342ae4f
1 file changed
+67 -20
+67 -20
View File
@@ -10,10 +10,12 @@ import { Checkbox } from "@/components/ui/checkbox";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { RichTextEditor } from "@/components/RichTextEditor"; import { RichTextEditor } from "@/components/RichTextEditor";
import { import {
PlusCircle, Search, User, LogOut, Settings, ChevronDown, Plus, Archive, Trash2, PlusCircle, Search, User, LogOut, Settings, ChevronDown, Plus, Archive, Trash2,
Image as ImageIcon, CheckSquare, FileText, Rss, ExternalLink, RefreshCw, Key, Zap, Paperclip, X, Edit, Calendar as CalendarIcon, Tag as TagIcon, MessageSquare, Send Image as ImageIcon, CheckSquare, FileText, Rss, ExternalLink, RefreshCw, Key, Zap, Paperclip, X, Edit, Calendar as CalendarIcon, Tag as TagIcon, MessageSquare, Send, Check, ChevronsUpDown
} from "lucide-react"; } from "lucide-react";
import AuthService from "@/services/AuthService"; import AuthService from "@/services/AuthService";
import AdminService from "@/services/AdminService"; import AdminService from "@/services/AdminService";
@@ -98,6 +100,7 @@ const Index = () => {
const [chatLoading, setChatLoading] = useState(false); const [chatLoading, setChatLoading] = useState(false);
const [selectedModel, setSelectedModel] = useState<string>(""); const [selectedModel, setSelectedModel] = useState<string>("");
const [defaultModel, setDefaultModel] = useState<string>(""); const [defaultModel, setDefaultModel] = useState<string>("");
const [modelSelectorOpen, setModelSelectorOpen] = useState(false);
// Debounce timer for auto-save // Debounce timer for auto-save
const saveTimerRef = useRef<NodeJS.Timeout | null>(null); const saveTimerRef = useRef<NodeJS.Timeout | null>(null);
@@ -2376,29 +2379,73 @@ const Index = () => {
</div> </div>
</div> </div>
<div className="mt-3 flex gap-2"> <div className="mt-3 flex gap-2">
<select <Popover open={modelSelectorOpen} onOpenChange={setModelSelectorOpen}>
value={selectedModel} <PopoverTrigger asChild>
onChange={(e) => setSelectedModel(e.target.value)} <Button
className="flex-1 text-xs px-2 py-1.5 border border-input rounded-md bg-background" variant="outline"
disabled={chatLoading || loadingModels} role="combobox"
> aria-expanded={modelSelectorOpen}
{loadingModels ? ( className="flex-1 justify-between text-xs h-9"
<option value="">Chargement des modèles...</option> disabled={chatLoading || loadingModels}
) : openRouterModels.length === 0 ? ( >
<option value="">Aucun modèle disponible</option> <span className="truncate">
) : ( {loadingModels ? (
openRouterModels.map(model => ( "Chargement des modèles..."
<option key={model.id} value={model.id}> ) : openRouterModels.length === 0 ? (
{model.name} "Aucun modèle disponible"
</option> ) : selectedModel ? (
)) <>
)} {openRouterModels.find(m => m.id === selectedModel)?.name || "Sélectionner un modèle"}
</select> {defaultModel === selectedModel && (
<span className="ml-1 text-yellow-500">★</span>
)}
</>
) : (
"Sélectionner un modèle"
)}
</span>
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[320px] p-0" align="start">
<Command>
<CommandInput placeholder="Rechercher un modèle..." className="h-9" />
<CommandList>
<CommandEmpty>Aucun modèle trouvé.</CommandEmpty>
<CommandGroup>
{openRouterModels.map((model) => (
<CommandItem
key={model.id}
value={model.name}
onSelect={() => {
setSelectedModel(model.id);
setModelSelectorOpen(false);
}}
className="text-xs"
>
<Check
className={`mr-2 h-4 w-4 ${
selectedModel === model.id ? "opacity-100" : "opacity-0"
}`}
/>
<div className="flex-1 truncate">
{model.name}
</div>
{defaultModel === model.id && (
<span className="ml-1 text-yellow-500 text-sm">★</span>
)}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
{selectedModel && ( {selectedModel && (
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-8 w-8" className="h-9 w-9"
onClick={() => handleSetDefaultModel(selectedModel)} onClick={() => handleSetDefaultModel(selectedModel)}
disabled={loadingModels} disabled={loadingModels}
title="Définir comme modèle par défaut" title="Définir comme modèle par défaut"