mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Presets : bouton d'ajout enfin lisible, et suppression branchée
Le bouton d'ajout existait mais était introuvable : l'en-tête des Réglages n'avait ni flex-wrap ni flex-none, donc les commandes s'écrasaient les unes sur les autres. « + Preset » se retrouvait compressé sur deux lignes dans 62 px, et le bouton d'enregistrement chevauchait le texte de description. - En-tête : les commandes ne se compriment plus (flex-none, whitespace-nowrap) et passent à la ligne si la largeur manque. - Le bouton devient « + Nouveau preset », explicite, sur une ligne. - Le preset appliqué reste sélectionné, avec un bouton de suppression : deletePreset existait côté API mais n'était appelé nulle part. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
This commit is contained in:
1 file changed
+55
-20
@@ -6,6 +6,7 @@ import {
|
|||||||
getBenchScores,
|
getBenchScores,
|
||||||
getHardware,
|
getHardware,
|
||||||
listMcp,
|
listMcp,
|
||||||
|
deletePreset,
|
||||||
listPresets,
|
listPresets,
|
||||||
pullModel,
|
pullModel,
|
||||||
runBench,
|
runBench,
|
||||||
@@ -19,7 +20,7 @@ import type {
|
|||||||
HardwareInfo,
|
HardwareInfo,
|
||||||
McpServer,
|
McpServer,
|
||||||
} from "../api/client";
|
} from "../api/client";
|
||||||
import { DownloadIcon, RefreshIcon } from "../components/Icon";
|
import { DownloadIcon, PlusIcon, RefreshIcon, TrashIcon } from "../components/Icon";
|
||||||
|
|
||||||
const TOOL_DESC: Record<string, string> = {
|
const TOOL_DESC: Record<string, string> = {
|
||||||
read_file: "Lire un fichier du projet",
|
read_file: "Lire un fichier du projet",
|
||||||
@@ -117,8 +118,11 @@ export function SettingsView() {
|
|||||||
<div className="scr flex-1 overflow-auto bg-base px-[30px] py-[26px]">
|
<div className="scr flex-1 overflow-auto bg-base px-[30px] py-[26px]">
|
||||||
<div className="mx-auto max-w-[1000px]">
|
<div className="mx-auto max-w-[1000px]">
|
||||||
{/* En-tête */}
|
{/* En-tête */}
|
||||||
<div className="mb-[22px] flex items-end justify-between">
|
{/* flex-wrap + flex-none : sans ça, les commandes s'écrasaient les unes
|
||||||
<div>
|
sur les autres et « + Preset » devenait un bloc illisible sur deux
|
||||||
|
lignes, chevauchant la description. */}
|
||||||
|
<div className="mb-[22px] flex flex-wrap items-end justify-between gap-x-6 gap-y-3">
|
||||||
|
<div className="min-w-[260px] flex-1">
|
||||||
<div className="font-pixel text-[13px] text-ink">
|
<div className="font-pixel text-[13px] text-ink">
|
||||||
MODÈLE & GÉNÉRATION
|
MODÈLE & GÉNÉRATION
|
||||||
</div>
|
</div>
|
||||||
@@ -127,19 +131,26 @@ export function SettingsView() {
|
|||||||
sont sauvegardés pour le modèle sélectionné.
|
sont sauvegardés pour le modèle sélectionné.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex flex-none items-center gap-2 whitespace-nowrap">
|
||||||
<PresetBar model={selectedModel} onApplied={refreshConfig} />
|
<PresetBar model={selectedModel} onApplied={refreshConfig} />
|
||||||
<div className="flex items-center gap-1.5 text-[13px] text-ok">
|
<span
|
||||||
<span className="h-2 w-2 border border-line bg-ok" />
|
className={`flex flex-none items-center gap-1.5 text-[13px] ${
|
||||||
|
status?.connected ? "text-ok" : "text-warn"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`h-1.5 w-1.5 rounded-full ${
|
||||||
|
status?.connected ? "bg-ok" : "bg-warn"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
{status?.connected ? "Ollama connecté" : "Ollama déconnecté"}
|
{status?.connected ? "Ollama connecté" : "Ollama déconnecté"}
|
||||||
</div>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={save}
|
onClick={save}
|
||||||
disabled={!dirty}
|
disabled={!dirty}
|
||||||
className="flex h-[34px] items-center gap-1.5 border border-line bg-accent px-4 text-[14px] text-white shadow-accent-soft disabled:opacity-40"
|
className="flex h-[34px] flex-none items-center rounded-card border border-line bg-accent px-4 text-[14px] text-white shadow-accent-soft disabled:opacity-40"
|
||||||
style={{ borderRadius: 7 }}
|
|
||||||
>
|
>
|
||||||
{saved ? "✓ ENREGISTRÉ" : dirty ? "ENREGISTRER" : "À JOUR"}
|
{saved ? "✓ Enregistré" : dirty ? "Enregistrer" : "À jour"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -932,6 +943,7 @@ function PresetBar({
|
|||||||
onApplied: () => void;
|
onApplied: () => void;
|
||||||
}) {
|
}) {
|
||||||
const [presets, setPresets] = useState<string[]>([]);
|
const [presets, setPresets] = useState<string[]>([]);
|
||||||
|
const [chosen, setChosen] = useState("");
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -939,6 +951,7 @@ function PresetBar({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const apply = async (name: string) => {
|
const apply = async (name: string) => {
|
||||||
|
setChosen(name);
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
try {
|
try {
|
||||||
@@ -955,6 +968,7 @@ function PresetBar({
|
|||||||
setBusy(true);
|
setBusy(true);
|
||||||
try {
|
try {
|
||||||
setPresets(await savePreset(name.trim(), model || undefined));
|
setPresets(await savePreset(name.trim(), model || undefined));
|
||||||
|
setChosen(name.trim());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window.alert(e instanceof Error ? e.message : "preset refusé");
|
window.alert(e instanceof Error ? e.message : "preset refusé");
|
||||||
} finally {
|
} 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 (
|
return (
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex flex-none items-center gap-1.5">
|
||||||
<select
|
<select
|
||||||
value=""
|
value={chosen}
|
||||||
disabled={busy || presets.length === 0}
|
disabled={busy || presets.length === 0}
|
||||||
onChange={(e) => apply(e.target.value)}
|
onChange={(e) => apply(e.target.value)}
|
||||||
className="h-[34px] border border-line bg-card px-2 text-[13px] text-ink disabled:opacity-40"
|
className="h-[34px] flex-none rounded-card border border-line bg-card px-2 text-[13px] text-ink disabled:opacity-40"
|
||||||
title="Appliquer un preset"
|
title="Appliquer un preset enregistré"
|
||||||
>
|
>
|
||||||
<option value="">
|
<option value="">{presets.length ? "Preset…" : "Aucun preset"}</option>
|
||||||
{presets.length ? "Preset…" : "Aucun preset"}
|
|
||||||
</option>
|
|
||||||
{presets.map((p) => (
|
{presets.map((p) => (
|
||||||
<option key={p} value={p}>
|
<option key={p} value={p}>
|
||||||
{p}
|
{p}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
{chosen && (
|
||||||
|
<button
|
||||||
|
onClick={remove}
|
||||||
|
disabled={busy}
|
||||||
|
className="h-[34px] flex-none rounded-card border border-line bg-card px-2 text-[13px] text-warn disabled:opacity-40"
|
||||||
|
title={`Supprimer le preset « ${chosen} »`}
|
||||||
|
>
|
||||||
|
<TrashIcon size={13} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={create}
|
onClick={create}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
className="h-[34px] border border-line bg-card px-2.5 text-[13px] text-muted-2 disabled:opacity-40"
|
className="flex h-[34px] flex-none items-center gap-1 whitespace-nowrap rounded-card border border-line bg-card px-3 text-[13px] text-ink-3 hover:border-accent hover:text-accent disabled:opacity-40"
|
||||||
title="Enregistrer les réglages actuels comme preset"
|
title="Enregistrer les réglages actuels comme nouveau preset"
|
||||||
>
|
>
|
||||||
+ Preset
|
<PlusIcon />
|
||||||
|
Nouveau preset
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user