From d15244758a4e15f894b2d803a035fc177d03e62b Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Thu, 2 Apr 2026 13:42:32 +1100 Subject: [PATCH] fix: prevent file drags from replacing the app view (#71) * fix: prevent dropped files from replacing the app view * test: use drag events in app navigation test --- ui/goose2/src/app/App.test.tsx | 39 ++++++++++++++++++++++++++++++++++ ui/goose2/src/app/App.tsx | 12 +++++++++++ 2 files changed, 51 insertions(+) create mode 100644 ui/goose2/src/app/App.test.tsx diff --git a/ui/goose2/src/app/App.test.tsx b/ui/goose2/src/app/App.test.tsx new file mode 100644 index 0000000000..a1e88ecb89 --- /dev/null +++ b/ui/goose2/src/app/App.test.tsx @@ -0,0 +1,39 @@ +import { render } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { App } from "./App"; + +vi.mock("@/app/AppShell", () => ({ + AppShell: () =>
, +})); + +describe("App", () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it("prevents default window navigation when files are dragged into the app", () => { + vi.stubGlobal("__TAURI_INTERNALS__", undefined); + vi.stubGlobal( + "DragEvent", + window.DragEvent ?? class DragEvent extends Event {}, + ); + + render(); + + const dragOverEvent = new DragEvent("dragover", { + bubbles: true, + cancelable: true, + }); + const dropEvent = new DragEvent("drop", { + bubbles: true, + cancelable: true, + }); + + window.dispatchEvent(dragOverEvent); + window.dispatchEvent(dropEvent); + + expect(dragOverEvent.defaultPrevented).toBe(true); + expect(dropEvent.defaultPrevented).toBe(true); + }); +}); diff --git a/ui/goose2/src/app/App.tsx b/ui/goose2/src/app/App.tsx index 8769ea4cb3..a496490bbd 100644 --- a/ui/goose2/src/app/App.tsx +++ b/ui/goose2/src/app/App.tsx @@ -4,6 +4,13 @@ import { AppShell } from "@/app/AppShell"; export function App() { useEffect(() => { + const preventWindowFileNavigation = (event: DragEvent) => { + event.preventDefault(); + }; + + window.addEventListener("dragover", preventWindowFileNavigation); + window.addEventListener("drop", preventWindowFileNavigation); + // Dynamic import to avoid crash in non-Tauri environments (e.g., Playwright E2E) if (window.__TAURI_INTERNALS__) { import("@tauri-apps/api/window").then(({ getCurrentWindow }) => { @@ -12,6 +19,11 @@ export function App() { .catch(() => {}); }); } + + return () => { + window.removeEventListener("dragover", preventWindowFileNavigation); + window.removeEventListener("drop", preventWindowFileNavigation); + }; }, []); return ;