fix(windows): fenêtres de panneau détachées suivent le projet en focus côté UI (#47)
Partie frontend. Ajoute un adaptateur focusedProject et un port dédié : la ViewWindow détachée n'est plus liée à un project_id figé, elle s'abonne à l'event focused-project émis par la fenêtre principale et affiche le panneau du projet courant. ProjectsView propage le focus ; le détachement crée une fenêtre panel-only. Couvert par les tests window/ViewWindow/focusedProject/ ProjectsView.focus. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
76
frontend/src/adapters/focusedProject.test.ts
Normal file
76
frontend/src/adapters/focusedProject.test.ts
Normal file
@ -0,0 +1,76 @@
|
||||
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 { TauriFocusedProjectGateway } from "./focusedProject";
|
||||
|
||||
describe("TauriFocusedProjectGateway (#47)", () => {
|
||||
beforeEach(() => {
|
||||
invoke.mockReset().mockResolvedValue(null);
|
||||
listen.mockReset();
|
||||
});
|
||||
|
||||
it("set/get relay to the backend focused-project commands", async () => {
|
||||
const gw = new TauriFocusedProjectGateway();
|
||||
|
||||
await gw.setFocusedProject({ id: "p1", name: "alpha", root: "/p/a" });
|
||||
expect(invoke).toHaveBeenCalledWith("set_focused_project", {
|
||||
project: { id: "p1", name: "alpha", root: "/p/a" },
|
||||
});
|
||||
|
||||
await gw.setFocusedProject(null);
|
||||
expect(invoke).toHaveBeenCalledWith("set_focused_project", {
|
||||
project: null,
|
||||
});
|
||||
|
||||
invoke.mockResolvedValueOnce({ id: "p2", name: "beta", root: "/p/b" });
|
||||
await expect(gw.getFocusedProject()).resolves.toEqual({
|
||||
id: "p2",
|
||||
name: "beta",
|
||||
root: "/p/b",
|
||||
});
|
||||
expect(invoke).toHaveBeenCalledWith("get_focused_project");
|
||||
|
||||
// A `null`/undefined focus normalises to `null`.
|
||||
invoke.mockResolvedValueOnce(null);
|
||||
await expect(gw.getFocusedProject()).resolves.toBeNull();
|
||||
});
|
||||
|
||||
it("onFocusedProjectChanged listens on the channel and forwards the project (or null)", async () => {
|
||||
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 TauriFocusedProjectGateway();
|
||||
const handler = vi.fn();
|
||||
const off = await gw.onFocusedProjectChanged(handler);
|
||||
|
||||
expect(listen).toHaveBeenCalledWith(
|
||||
"focused-project://changed",
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
raw?.({ payload: { project: { id: "p1", name: "alpha", root: "/p/a" } } });
|
||||
expect(handler).toHaveBeenLastCalledWith({
|
||||
id: "p1",
|
||||
name: "alpha",
|
||||
root: "/p/a",
|
||||
});
|
||||
|
||||
raw?.({ payload: { project: null } });
|
||||
expect(handler).toHaveBeenLastCalledWith(null);
|
||||
|
||||
off();
|
||||
expect(unlisten).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user