feat(ui): fenêtres View système séparées — WebviewWindow Tauri + port WindowGateway (#23)
Détache les vues dans de vraies fenêtres système Tauri (multi-écran, fullscreen). Backend : commandes de gestion de WebviewWindow, capabilities et composition root. Frontend : nouveau port WindowGateway et son adaptateur window, entrée panel-only ViewWindow/ViewPanelBody, détachement câblé dans ProjectsView. QA vert : app-tauri 63, frontend typecheck + vitest 546/546. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
71
frontend/src/adapters/window.test.ts
Normal file
71
frontend/src/adapters/window.test.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
|
||||
const invoke = vi.fn();
|
||||
const listen = vi.fn();
|
||||
vi.mock("@tauri-apps/api/core", () => ({
|
||||
invoke: (...args: unknown[]) => invoke(...args),
|
||||
}));
|
||||
vi.mock("@tauri-apps/api/event", () => ({
|
||||
listen: (...args: unknown[]) => listen(...args),
|
||||
}));
|
||||
|
||||
import { TauriWindowGateway } from "./window";
|
||||
|
||||
describe("TauriWindowGateway (#23)", () => {
|
||||
beforeEach(() => {
|
||||
invoke.mockReset().mockResolvedValue({});
|
||||
listen.mockReset();
|
||||
});
|
||||
|
||||
it("open/close relay camelCase payloads to the backend commands", async () => {
|
||||
const gw = new TauriWindowGateway();
|
||||
await gw.openViewWindow("tickets", "proj-1");
|
||||
expect(invoke).toHaveBeenCalledWith("open_view_window", {
|
||||
panel: "tickets",
|
||||
projectId: "proj-1",
|
||||
});
|
||||
await gw.closeViewWindow("git", "proj-2");
|
||||
expect(invoke).toHaveBeenCalledWith("close_view_window", {
|
||||
panel: "git",
|
||||
projectId: "proj-2",
|
||||
});
|
||||
});
|
||||
|
||||
it("onViewWindowClosed listens on the lifecycle channel and forwards only closes", async () => {
|
||||
// Capture the raw Tauri listener so we can drive lifecycle events at will.
|
||||
let raw: ((e: { payload: unknown }) => void) | undefined;
|
||||
const unlisten = vi.fn();
|
||||
listen.mockImplementation((_name: string, cb: typeof raw) => {
|
||||
raw = cb;
|
||||
return Promise.resolve(unlisten);
|
||||
});
|
||||
|
||||
const gw = new TauriWindowGateway();
|
||||
const handler = vi.fn();
|
||||
const off = await gw.onViewWindowClosed(handler);
|
||||
|
||||
expect(listen).toHaveBeenCalledWith(
|
||||
"view-window://lifecycle",
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
// opened / focused are dropped…
|
||||
raw?.({
|
||||
payload: { kind: "opened", panel: "git", projectId: "p", label: "view-git-p" },
|
||||
});
|
||||
raw?.({
|
||||
payload: { kind: "focused", panel: "git", projectId: "p", label: "view-git-p" },
|
||||
});
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
|
||||
// …only closed reaches the port handler, narrowed to { panel, projectId }.
|
||||
raw?.({
|
||||
payload: { kind: "closed", panel: "git", projectId: "p", label: "view-git-p" },
|
||||
});
|
||||
expect(handler).toHaveBeenCalledTimes(1);
|
||||
expect(handler).toHaveBeenCalledWith({ panel: "git", projectId: "p" });
|
||||
|
||||
off();
|
||||
expect(unlisten).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user