feat(domain,application,infrastructure,backend,web-server,app-tauri,frontend): lot utilisateur #325 #326 — icônes projet avec watermark CLI custom et localisation FR/EN (QA verte)
Lot en un seul commit: les deux features partagent les mêmes contrats (domain/settings.rs, DTO, commandes Tauri/HTTP, web-server) et les mêmes surfaces UI — la séparation par fichiers était impossible sans chirurgie de hunks risquant des états intermédiaires non compilables (convention lot des batches #310-#313 et #315). #325 — icône configurable par projet, watermark CLI custom: - domaine: ProjectIconSet (devicon, simple-icons, lucide, idea), ProjectIconRef validé (nom ASCII 1..=64, -_. internes), champ icon optionnel sur ProjectSettings; sérialisation camelCase et try_from strict - application: UpdateProjectSettings.execute accepte un patch theme_color OU icon (absent = inchangé, null = défaut produit), tests in-dependants avec store mémoire - backend/app-tauri/web-server: ProjectIconRefDto, UpdateProjectSettingsRequestDto avec icon optionnel (désérialisation additive), commandes update_project_settings alignées Tauri/HTTP, tests DTO et HTTP (défaut null, set, clear, nom invalide rejeté) - frontend: catalogue projectIcons (recherche EN), ProjectIconPicker en grille multi-lignes dans Paramètres projet, affichage de l'icône dans ProjectTabs et watermark grand format à faible opacité en fond de CLI custom; ports ProjectSettings.icon, Partial<ProjectSettings>, adapters tauri/mock/http et tests alignés #326 — localisation FR/EN et traduction des textes IdeA: - domaine: IdeaLanguage (fr | en), champ language optionnel sur IdeaUserSettings (absence = défaut produit, série additive validée) - backend/web-server: UserSettingsDto.language, update_user_settings accepte language, tests HTTP alignés; fixtures structured_launch_d3 mises à jour - frontend: i18n/ (catalogue FR/EN, I18nProvider, scan anti-régression des sources visibles), GeneralSettings avec sélecteur de langue dans les paramètres, setupI18n dans vitest; migration de l'ensemble des textes hardcodés vers le catalogue sur toutes les surfaces (agents, layout, projets, tickets, sprints, web, plugins, permissions, git, templates, skills, mémoire, model servers, embedder, first-run, devices, scheduled tasks, workstate, dialogs), FR conservé par défaut; recherche d'icônes #325 en anglais conformément au ticket QA verte sur feature/batch-325-326-project-icons-localisation. Aucun push.
This commit is contained in:
@ -18,6 +18,7 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { cn } from "@/shared";
|
||||
import { useI18n } from "@/i18n";
|
||||
import type { ModelServerStatus } from "@/domain";
|
||||
import type { AgentLaunchFailure } from "./useAgents";
|
||||
|
||||
@ -31,20 +32,21 @@ export interface ModelServerLaunchBadgeProps {
|
||||
/** Human label + tone for a non-failed lifecycle state. */
|
||||
function describeStatus(
|
||||
status: ModelServerStatus,
|
||||
tr: (french: string, english: string) => string,
|
||||
): { label: string; tone: string; role?: "status" } | null {
|
||||
switch (status.state) {
|
||||
case "notConfigured":
|
||||
return null; // Nothing to surface for an unmanaged endpoint.
|
||||
case "probing":
|
||||
return { label: "vérification du serveur…", tone: "bg-muted/20 text-muted", role: "status" };
|
||||
return { label: tr("vérification du serveur…", "checking server…"), tone: "bg-muted/20 text-muted", role: "status" };
|
||||
case "starting":
|
||||
return { label: "démarrage du serveur…", tone: "bg-warning/20 text-warning", role: "status" };
|
||||
return { label: tr("démarrage du serveur…", "starting server…"), tone: "bg-warning/20 text-warning", role: "status" };
|
||||
case "downloading":
|
||||
return { label: "téléchargement du modèle…", tone: "bg-warning/20 text-warning", role: "status" };
|
||||
return { label: tr("téléchargement du modèle…", "downloading model…"), tone: "bg-warning/20 text-warning", role: "status" };
|
||||
case "ready":
|
||||
return status.reused
|
||||
? { label: "serveur prêt (réutilisé)", tone: "bg-success/20 text-success" }
|
||||
: { label: "serveur prêt", tone: "bg-success/20 text-success" };
|
||||
? { label: tr("serveur prêt (réutilisé)", "server ready (reused)"), tone: "bg-success/20 text-success" }
|
||||
: { label: tr("serveur prêt", "server ready"), tone: "bg-success/20 text-success" };
|
||||
case "failed":
|
||||
// Handled by the failure branch below (richer, actionable).
|
||||
return null;
|
||||
@ -55,6 +57,7 @@ export function ModelServerLaunchBadge({
|
||||
status,
|
||||
failure,
|
||||
}: ModelServerLaunchBadgeProps) {
|
||||
const { tr } = useI18n();
|
||||
const [showDetail, setShowDetail] = useState(false);
|
||||
|
||||
// A launch failure (from `agentLaunchFailed`) or a `failed` status both mean
|
||||
@ -72,26 +75,26 @@ export function ModelServerLaunchBadge({
|
||||
<span className="flex min-w-0 flex-wrap items-center gap-2">
|
||||
<span
|
||||
role="alert"
|
||||
aria-label="model server launch failed"
|
||||
aria-label={tr("échec du lancement du serveur de modèle", "model server launch failed")}
|
||||
className={cn(
|
||||
"rounded-full px-2 py-0.5 text-xs font-medium",
|
||||
"bg-danger/20 text-danger",
|
||||
)}
|
||||
>
|
||||
Échec du lancement : {failed.message}
|
||||
{tr("Échec du lancement :", "Launch failed:")} {failed.message}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="toggle launch failure detail"
|
||||
aria-label={tr("afficher ou masquer le détail de l'échec", "toggle launch failure detail")}
|
||||
onClick={() => setShowDetail((v) => !v)}
|
||||
className="text-xs text-muted underline hover:text-content"
|
||||
>
|
||||
Détails
|
||||
{tr("Détails", "Details")}
|
||||
</button>
|
||||
{showDetail && (
|
||||
<span aria-label="launch failure detail" className="text-xs text-faint">
|
||||
code {failed.code}
|
||||
{failed.cause ? ` · cause ${failed.cause}` : ""}
|
||||
<span aria-label={tr("détail de l'échec du lancement", "launch failure detail")} className="text-xs text-faint">
|
||||
{tr("code", "code")} {failed.code}
|
||||
{failed.cause ? ` · ${tr("cause", "cause")} ${failed.cause}` : ""}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
@ -99,13 +102,13 @@ export function ModelServerLaunchBadge({
|
||||
}
|
||||
|
||||
if (!status) return null;
|
||||
const described = describeStatus(status);
|
||||
const described = describeStatus(status, tr);
|
||||
if (!described) return null;
|
||||
|
||||
return (
|
||||
<span
|
||||
role={described.role}
|
||||
aria-label="model server status"
|
||||
aria-label={tr("état du serveur de modèle", "model server status")}
|
||||
className={cn(
|
||||
"rounded-full px-2 py-0.5 text-xs font-medium",
|
||||
described.tone,
|
||||
|
||||
Reference in New Issue
Block a user