diff --git a/plugins/file-manager/src/frontend/FileManagerGrid.tsx b/plugins/file-manager/src/frontend/FileManagerGrid.tsx index e1202aa4a..c1f67bb61 100644 --- a/plugins/file-manager/src/frontend/FileManagerGrid.tsx +++ b/plugins/file-manager/src/frontend/FileManagerGrid.tsx @@ -458,6 +458,9 @@ export function FileManagerGrid({ }; const handleFileDrop = (e: React.DragEvent, targetFile: FileItem) => { + // OS drops belong to the pane's upload handler, even over an existing row. + if (dragState.type !== "internal" && !isLocalFilesDrag(e.dataTransfer)) + return; e.preventDefault(); e.stopPropagation(); diff --git a/plugins/file-manager/tests/frontend/FileManagerGrid.test.tsx b/plugins/file-manager/tests/frontend/FileManagerGrid.test.tsx index fafd1636b..198a04da8 100644 --- a/plugins/file-manager/tests/frontend/FileManagerGrid.test.tsx +++ b/plugins/file-manager/tests/frontend/FileManagerGrid.test.tsx @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import "@testing-library/jest-dom/vitest"; import { FileManagerGrid } from "../../src/frontend/FileManagerGrid"; @@ -44,6 +44,7 @@ const props = { afterEach(() => { cleanup(); vi.restoreAllMocks(); + vi.unstubAllGlobals(); }); describe("remote file rename", () => { @@ -89,3 +90,52 @@ describe("remote file rename", () => { expect(screen.getByText(file.modified!)).toBeInTheDocument(); }); }); + +describe("external file drops", () => { + beforeEach(() => { + vi.stubGlobal( + "ResizeObserver", + class { + observe() {} + disconnect() {} + }, + ); + }); + it.each(["list", "grid"] as const)( + "uploads dropped folders over a file in %s view", + (viewMode) => { + const onUploadItems = vi.fn(); + render( + , + ); + const folder = { + name: "logs", + isDirectory: true, + isFile: false, + } as FileSystemEntry; + fireEvent.drop(screen.getByText(file.name), { + dataTransfer: { + types: ["Files"], + files: [], + getData: () => "", + items: [{ webkitGetAsEntry: () => folder }], + }, + }); + expect(onUploadItems).toHaveBeenCalledExactlyOnceWith([folder]); + }, + ); + + it("uploads a plain OS file dropped over a row", () => { + const onUpload = vi.fn(); + render(); + const files = [new File(["log"], "app.log")]; + fireEvent.drop(screen.getByText(file.name), { + dataTransfer: { types: ["Files"], files, items: [], getData: () => "" }, + }); + expect(onUpload).toHaveBeenCalledExactlyOnceWith(files); + }); +});