Files
IdeA/frontend/src/features/first-run/ProfilesSettings.tsx
Blomios 6e92536d84 fix(frontend): align Settings desktop labels on French (#78)
UX decision (carnet #78): the human UI of IdeA is French by default,
uniform per surface — proper nouns and technical acronyms (URL, LAN,
IP/CIDR, HTTPS, API, CLI…) stay as-is. Settings mixed English (AI
Profiles, Deployment) with French (Appareils, frozen by UX for #77).

Renames the Settings menu/nav, the Profils IA and Déploiement panels
(titles, actions, states, help text) to French, per the carnet's
exhaustive list. Updates the affected tests accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 14:53:32 +02:00

103 lines
2.8 KiB
TypeScript

/**
* Minimal "Settings → AI Profiles" panel (L5). An always-available entry point
* to review the configured profiles and re-run the setup wizard after the first
* run. Kept intentionally small; richer per-profile editing reuses the wizard.
*
* Pure presentation over the {@link ProfileGateway} port (no `invoke()`).
*/
import { useCallback, useEffect, useState } from "react";
import type { AgentProfile, GatewayError } from "@/domain";
import { useGateways } from "@/app/di";
import { Button, Panel } from "@/shared";
import { FirstRunWizard } from "./FirstRunWizard";
export function ProfilesSettings() {
const { profile } = useGateways();
const [profiles, setProfiles] = useState<AgentProfile[]>([]);
const [error, setError] = useState<string | null>(null);
const [editing, setEditing] = useState(false);
const refresh = useCallback(async () => {
setError(null);
try {
setProfiles(await profile.listProfiles());
} catch (e) {
setError(
e && typeof e === "object" && "message" in e
? String((e as GatewayError).message)
: String(e),
);
}
}, [profile]);
useEffect(() => {
void refresh();
}, [refresh]);
async function del(id: string) {
await profile.deleteProfile(id);
await refresh();
}
if (editing) {
// Reopened after the first run, so force the wizard to render.
return (
<FirstRunWizard
forceOpen
onDone={() => {
setEditing(false);
void refresh();
}}
/>
);
}
return (
<Panel
aria-label="ai profiles settings"
title="Profils IA"
actions={
<Button size="sm" onClick={() => setEditing(true)}>
Configurer les profils
</Button>
}
>
<div className="flex flex-col gap-3">
{error && (
<p role="alert" className="text-sm text-danger">
{error}
</p>
)}
{profiles.length === 0 ? (
<p className="text-sm text-muted">Aucun profil configuré.</p>
) : (
<ul className="flex flex-col divide-y divide-border">
{profiles.map((p) => (
<li
key={p.id}
className="flex items-center justify-between gap-3 py-2 first:pt-0 last:pb-0"
>
<span className="flex items-baseline gap-2">
<strong className="text-sm text-content">{p.name}</strong>
<code className="text-xs text-muted">{p.command}</code>
</span>
<Button
size="sm"
variant="ghost"
aria-label={`supprimer ${p.name}`}
onClick={() => void del(p.id)}
>
Supprimer
</Button>
</li>
))}
</ul>
)}
</div>
</Panel>
);
}