/** * Root component. Smoke-tests the full hexagonal pipeline by calling `health` * through the {@link SystemGateway} (never `invoke()` directly) and listening * for relayed domain events. */ import { useEffect, useState } from "react"; import type { DomainEvent, HealthReport } from "@/domain"; import { ProjectsView } from "@/features/projects"; import { FirstRunWizard } from "@/features/first-run"; import { AppExitConfirmDialog } from "@/features/appExit"; import { PluginRuntimeProvider } from "@/features/plugins"; import { Panel, Spinner, Toolbar } from "@/shared"; import { useGateways, shouldUseMock } from "./di"; import { useI18n } from "@/i18n"; export function App() { const { tr } = useI18n(); const { system, profile } = useGateways(); const [health, setHealth] = useState(null); const [error, setError] = useState(null); const [events, setEvents] = useState([]); // First-run gating: null while loading, then true (wizard) / false (normal). const [firstRun, setFirstRun] = useState(null); useEffect(() => { let unsub: (() => void) | undefined; let cancelled = false; system .onDomainEvent((e) => setEvents((prev) => [...prev, e])) .then((u) => { if (cancelled) u(); else unsub = u; }) .catch(() => { /* event relay unavailable in this environment; ignore for smoke test */ }); system .health("ui-boot") .then((report) => setHealth(report)) .catch((e: unknown) => setError(describeError(e))); return () => { cancelled = true; unsub?.(); }; }, [system]); useEffect(() => { let cancelled = false; profile .firstRunState() .then((s) => { if (!cancelled) setFirstRun(s.isFirstRun); }) .catch(() => { // First-run state unavailable: behave as a normal (non-first) run. if (!cancelled) setFirstRun(false); }); return () => { cancelled = true; }; }, [profile]); return (
{/* ── Header ── */}

IdeA

{shouldUseMock() ? "mock" : "tauri"}
{health ? ( <> {tr("backend", "backend")} ● v{health.version} ·{" "} {events.length} {tr("événements", "events")} ) : error ? ( {tr("backend indisponible", "backend unavailable")} ) : ( {tr("vérification…", "checking…")} )}
{/* ── Body ── */}
{error && (

{tr("Erreur :", "Error:")} {error}

)} {firstRun ? ( // First launch: the wizard takes over the area, in a scrollable column // (it can be taller than the viewport).
setFirstRun(false)} />
) : ( // ProjectsView owns the full remaining area (its own IDE layout, // single menu bar, and the AI Profiles view switch — ticket #16). )}
); } function describeError(e: unknown): string { if (e && typeof e === "object" && "message" in e) { return String((e as { message: unknown }).message); } return String(e); }