feat(frontend): système de plugins — runtime, menus, layouts custom (#43)

Lots F1-F4 : runtime de chargement/registre plugin, extension des menus
existants, panneau de gestion des plugins, types de layout custom
(sélecteur, fallback, cellule dédiée) branchés sur le port plugin.
Suite npm typecheck/test verte (947/947).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 07:37:11 +02:00
parent bb35641715
commit ac726d075e
41 changed files with 3245 additions and 24 deletions

View File

@ -24,16 +24,18 @@
import { Button, cn } from "@/shared";
import { ProfilesSettings } from "@/features/first-run";
import { DevicesScreen } from "@/features/devices";
import { PluginsPanel } from "@/features/plugins";
import { DeploymentSettings } from "./DeploymentSettings";
/** The Settings sections, in menu/nav order. */
export type SettingsSection = "aiProfiles" | "deployment" | "devices";
export type SettingsSection = "aiProfiles" | "deployment" | "devices" | "plugins";
/** Human labels, shared by the nav column and the `Settings` menu (ticket #78 — French). */
export const SETTINGS_SECTION_LABEL: Record<SettingsSection, string> = {
aiProfiles: "Profils IA",
deployment: "Déploiement",
devices: "Appareils",
plugins: "Plugins",
};
/** Section order — the single source of truth for both nav and menu. */
@ -41,6 +43,7 @@ export const SETTINGS_SECTIONS: SettingsSection[] = [
"aiProfiles",
"deployment",
"devices",
"plugins",
];
interface SettingsViewProps {
@ -93,6 +96,8 @@ export function SettingsView({
<ProfilesSettings />
) : section === "deployment" ? (
<DeploymentSettings />
) : section === "plugins" ? (
<PluginsPanel />
) : (
// No `onSessionEnded`: the desktop app hosts the server and is never
// itself a paired device, so it cannot revoke its own session.