fix(web): route la famille layout dans /api/invoke + fallback UX restauration — #212
Le web-server ne routait pas load_layout (UNKNOWN_COMMAND a l'ouverture d'un projet web PC). Alignement de l'adapter web sur les contrats Tauri: load_layout, mutate_layout, list_layouts, create_layout, rename_layout, delete_layout, set_active_layout. useLayout ne propage plus l'erreur brute: message utilisateur + fallback singleLeafTree.
This commit is contained in:
@ -35,6 +35,31 @@ function renderGrid(layout: MockLayoutGateway, projectId = "p1") {
|
||||
}
|
||||
|
||||
describe("LayoutGrid (with MockLayoutGateway)", () => {
|
||||
it("falls back to an empty workspace with a user-facing message when layout restore fails", async () => {
|
||||
const layout = new MockLayoutGateway();
|
||||
vi.spyOn(layout, "loadLayout").mockRejectedValueOnce(
|
||||
new Error("unknown command: load_layout"),
|
||||
);
|
||||
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
|
||||
renderGrid(layout);
|
||||
|
||||
const alert = await screen.findByRole("alert");
|
||||
expect(alert.textContent).toContain(
|
||||
"Impossible de restaurer l’espace de travail de ce projet.",
|
||||
);
|
||||
expect(alert.textContent).not.toContain("unknown command");
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByTestId("layout-leaf")).toHaveLength(1);
|
||||
});
|
||||
expect(warn).toHaveBeenCalledWith(
|
||||
"Layout restore failed",
|
||||
expect.objectContaining({ message: "unknown command: load_layout" }),
|
||||
);
|
||||
|
||||
warn.mockRestore();
|
||||
});
|
||||
|
||||
it("renders a single-leaf layout without throwing", async () => {
|
||||
const layout = new MockLayoutGateway();
|
||||
expect(() => renderGrid(layout)).not.toThrow();
|
||||
|
||||
@ -20,9 +20,13 @@ import { useGateways } from "@/app/di";
|
||||
import {
|
||||
leaves,
|
||||
replaceCustomPluginLayoutWithTerminal,
|
||||
singleLeafTree,
|
||||
splitOp,
|
||||
} from "./layout";
|
||||
|
||||
const LAYOUT_RESTORE_ERROR =
|
||||
"Impossible de restaurer l’espace de travail de ce projet. Un espace vide a été ouvert ; rechargez le projet pour réessayer.";
|
||||
|
||||
/** What the layout grid UI needs from this hook. */
|
||||
export interface LayoutViewModel {
|
||||
/** The current layout tree, or `null` until loaded. */
|
||||
@ -109,13 +113,18 @@ export function useLayout(
|
||||
}
|
||||
let cancelled = false;
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
gateway
|
||||
.loadLayout(projectId, layoutId)
|
||||
.then((tree) => {
|
||||
if (!cancelled) applyTree(tree);
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
if (!cancelled) setError(describe(e));
|
||||
if (!cancelled) {
|
||||
console.warn("Layout restore failed", e);
|
||||
applyTree(singleLeafTree());
|
||||
setError(LAYOUT_RESTORE_ERROR);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setBusy(false);
|
||||
|
||||
Reference in New Issue
Block a user