diff --git a/frontend/src/panels/SettingsView.tsx b/frontend/src/panels/SettingsView.tsx index 27af20b..9782117 100644 --- a/frontend/src/panels/SettingsView.tsx +++ b/frontend/src/panels/SettingsView.tsx @@ -6,6 +6,7 @@ import { getBenchScores, getHardware, listMcp, + deletePreset, listPresets, pullModel, runBench, @@ -19,7 +20,7 @@ import type { HardwareInfo, McpServer, } from "../api/client"; -import { DownloadIcon, RefreshIcon } from "../components/Icon"; +import { DownloadIcon, PlusIcon, RefreshIcon, TrashIcon } from "../components/Icon"; const TOOL_DESC: Record = { read_file: "Lire un fichier du projet", @@ -117,8 +118,11 @@ export function SettingsView() {
{/* En-tête */} -
-
+ {/* flex-wrap + flex-none : sans ça, les commandes s'écrasaient les unes + sur les autres et « + Preset » devenait un bloc illisible sur deux + lignes, chevauchant la description. */} +
+
MODÈLE & GÉNÉRATION
@@ -127,19 +131,26 @@ export function SettingsView() { sont sauvegardés pour le modèle sélectionné.
-
+
-
- + + {status?.connected ? "Ollama connecté" : "Ollama déconnecté"} -
+
@@ -932,6 +943,7 @@ function PresetBar({ onApplied: () => void; }) { const [presets, setPresets] = useState([]); + const [chosen, setChosen] = useState(""); const [busy, setBusy] = useState(false); useEffect(() => { @@ -939,6 +951,7 @@ function PresetBar({ }, []); const apply = async (name: string) => { + setChosen(name); if (!name) return; setBusy(true); try { @@ -955,6 +968,7 @@ function PresetBar({ setBusy(true); try { setPresets(await savePreset(name.trim(), model || undefined)); + setChosen(name.trim()); } catch (e) { window.alert(e instanceof Error ? e.message : "preset refusé"); } finally { @@ -962,31 +976,52 @@ function PresetBar({ } }; + const remove = async () => { + if (!chosen) return; + if (!window.confirm(`Supprimer le preset « ${chosen} » ?`)) return; + setBusy(true); + try { + setPresets(await deletePreset(chosen)); + setChosen(""); + } finally { + setBusy(false); + } + }; + return ( -
+
+ {chosen && ( + + )}
);