mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
Feature: Amélioration du sélecteur de modèles IA avec recherche
Amélioration de l'interface de sélection de modèles dans l'assistant IA pour une meilleure expérience utilisateur. Fonctionnalités ajoutées: 1. **Système de recherche intégré** - Remplacement du <select> HTML par un Combobox avec recherche - Utilisation des composants Command et Popover de shadcn/ui - Recherche en temps réel dans la liste des modèles - Filtrage instantané par nom de modèle 2. **Affichage amélioré du modèle par défaut** - Indicateur ★ visible dans le bouton du sélecteur - Indicateur ★ visible dans chaque élément de la liste - Affichage du nom complet du modèle sélectionné 3. **UX améliorée** - Interface moderne avec icône ChevronsUpDown - Indicateur visuel (✓) pour le modèle actuellement sélectionné - Fermeture automatique après sélection - Meilleure gestion des états (chargement, vide, désactivé) - Truncate pour les noms longs de modèles Changements techniques: - src/pages/Index.tsx: * Import Popover, PopoverContent, PopoverTrigger * Import Command, CommandInput, CommandList, CommandItem, etc. * Import icônes Check et ChevronsUpDown * Ajout state modelSelectorOpen pour gérer l'ouverture du popover * Remplacement du <select> HTML (lignes 2379-2396) par Combobox * Ajustement taille bouton étoile (h-9 w-9 pour cohérence) Comportement préservé: - Le modèle par défaut est toujours chargé depuis localStorage - Sélection automatique du modèle par défaut au chargement - Possibilité de définir/changer le modèle par défaut avec ★ - Validation et désactivation selon les états de chargement Cette amélioration facilite grandement la navigation dans une longue liste de modèles IA et offre une expérience utilisateur moderne.
This commit is contained in:
1 file changed
+67
-20
+67
-20
@@ -10,10 +10,12 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Label } from "@/components/ui/label";
|
||||
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 {
|
||||
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";
|
||||
import AuthService from "@/services/AuthService";
|
||||
import AdminService from "@/services/AdminService";
|
||||
@@ -98,6 +100,7 @@ const Index = () => {
|
||||
const [chatLoading, setChatLoading] = useState(false);
|
||||
const [selectedModel, setSelectedModel] = useState<string>("");
|
||||
const [defaultModel, setDefaultModel] = useState<string>("");
|
||||
const [modelSelectorOpen, setModelSelectorOpen] = useState(false);
|
||||
|
||||
// Debounce timer for auto-save
|
||||
const saveTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
@@ -2376,29 +2379,73 @@ const Index = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 flex gap-2">
|
||||
<select
|
||||
value={selectedModel}
|
||||
onChange={(e) => setSelectedModel(e.target.value)}
|
||||
className="flex-1 text-xs px-2 py-1.5 border border-input rounded-md bg-background"
|
||||
disabled={chatLoading || loadingModels}
|
||||
>
|
||||
{loadingModels ? (
|
||||
<option value="">Chargement des modèles...</option>
|
||||
) : openRouterModels.length === 0 ? (
|
||||
<option value="">Aucun modèle disponible</option>
|
||||
) : (
|
||||
openRouterModels.map(model => (
|
||||
<option key={model.id} value={model.id}>
|
||||
{model.name}
|
||||
</option>
|
||||
))
|
||||
)}
|
||||
</select>
|
||||
<Popover open={modelSelectorOpen} onOpenChange={setModelSelectorOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={modelSelectorOpen}
|
||||
className="flex-1 justify-between text-xs h-9"
|
||||
disabled={chatLoading || loadingModels}
|
||||
>
|
||||
<span className="truncate">
|
||||
{loadingModels ? (
|
||||
"Chargement des modèles..."
|
||||
) : openRouterModels.length === 0 ? (
|
||||
"Aucun modèle disponible"
|
||||
) : selectedModel ? (
|
||||
<>
|
||||
{openRouterModels.find(m => m.id === selectedModel)?.name || "Sélectionner un modèle"}
|
||||
{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 && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
className="h-9 w-9"
|
||||
onClick={() => handleSetDefaultModel(selectedModel)}
|
||||
disabled={loadingModels}
|
||||
title="Définir comme modèle par défaut"
|
||||
|
||||
Reference in new issue
Block a user