Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Few File component drag and drop #7141

Merged
merged 12 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/puny-clowns-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@gradio/upload": patch
"gradio": patch
---

fix:Few File component drag and drop
2 changes: 1 addition & 1 deletion demo/file_component_events/run.ipynb
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: file_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " \n", " with gr.Row():\n", " with gr.Column():\n", " file_component = gr.File(label=\"Upload Single File\", file_count=\"single\")\n", " with gr.Column():\n", " output_file_1 = gr.File(label=\"Upload Single File Output\", file_count=\"single\")\n", " num_load_btn_1 = gr.Number(label=\"# Load Upload Single File\", value=0)\n", " file_component.upload(lambda s,n: (s, n + 1), [file_component, num_load_btn_1], [output_file_1, num_load_btn_1])\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_multiple = gr.File(label=\"Upload Multiple Files\", file_count=\"multiple\")\n", " with gr.Column():\n", " output_file_2 = gr.File(label=\"Upload Multiple Files Output\", file_count=\"multiple\")\n", " num_load_btn_2 = gr.Number(label=\"# Load Upload Multiple Files\", value=0)\n", " file_component_multiple.upload(lambda s,n: (s, n + 1), [file_component_multiple, num_load_btn_2], [output_file_2, num_load_btn_2])\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: file_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " \n", " with gr.Row():\n", " with gr.Column():\n", " file_component = gr.File(label=\"Upload Single File\", file_count=\"single\")\n", " with gr.Column():\n", " output_file_1 = gr.File(label=\"Upload Single File Output\", file_count=\"single\")\n", " num_load_btn_1 = gr.Number(label=\"# Load Upload Single File\", value=0)\n", " file_component.upload(lambda s,n: (s, n + 1), [file_component, num_load_btn_1], [output_file_1, num_load_btn_1])\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_multiple = gr.File(label=\"Upload Multiple Files\", file_count=\"multiple\")\n", " with gr.Column():\n", " output_file_2 = gr.File(label=\"Upload Multiple Files Output\", file_count=\"multiple\")\n", " num_load_btn_2 = gr.Number(label=\"# Load Upload Multiple Files\", value=0)\n", " file_component_multiple.upload(lambda s,n: (s, n + 1), [file_component_multiple, num_load_btn_2], [output_file_2, num_load_btn_2])\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_specific = gr.File(label=\"Upload Multiple Files Image/Video\", file_count=\"multiple\", file_types=[\"image\", \"video\"])\n", " with gr.Column():\n", " output_file_3 = gr.File(label=\"Upload Multiple Files Output Image/Video\", file_count=\"multiple\")\n", " num_load_btn_3 = gr.Number(label=\"# Load Upload Multiple Files Image/Video\", value=0)\n", " file_component_specific.upload(lambda s,n: (s, n + 1), [file_component_specific, num_load_btn_3], [output_file_3, num_load_btn_3])\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
7 changes: 7 additions & 0 deletions demo/file_component_events/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
output_file_2 = gr.File(label="Upload Multiple Files Output", file_count="multiple")
num_load_btn_2 = gr.Number(label="# Load Upload Multiple Files", value=0)
file_component_multiple.upload(lambda s,n: (s, n + 1), [file_component_multiple, num_load_btn_2], [output_file_2, num_load_btn_2])
with gr.Row():
with gr.Column():
file_component_specific = gr.File(label="Upload Multiple Files Image/Video", file_count="multiple", file_types=["image", "video"])
with gr.Column():
output_file_3 = gr.File(label="Upload Multiple Files Output Image/Video", file_count="multiple")
num_load_btn_3 = gr.Number(label="# Load Upload Multiple Files Image/Video", value=0)
file_component_specific.upload(lambda s,n: (s, n + 1), [file_component_specific, num_load_btn_3], [output_file_3, num_load_btn_3])

if __name__ == "__main__":
demo.launch()
50 changes: 24 additions & 26 deletions js/app/test/file_component_events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ test("File component properly dispatches load event for the single file case.",
.getByRole("button", { name: "Drop File Here - or - Click to Upload" })
.first()
.click();
const uploader = await page.getByTestId("file-upload").first();
const uploader = await page.locator("input[type=file]").first();
await uploader.setInputFiles(["./test/files/cheetah1.jpg"]);

await expect(page.getByLabel("# Load Upload Single File")).toHaveValue("1");
Expand All @@ -18,36 +18,34 @@ test("File component properly dispatches load event for the single file case.",
await expect(download.suggestedFilename()).toBe("cheetah1.jpg");
});

test("File component properly dispatches load event for the multiple file case.", async ({
test("File component drag-and-drop uploads a file to the server correctly.", async ({
page
}) => {
await page
.getByRole("button", { name: "Drop File Here - or - Click to Upload" })
.last()
.click();
const uploader = await page.getByTestId("file-upload").last();
await uploader.setInputFiles([
"./test/files/face.obj",
"./test/files/cheetah1.jpg"
]);
const uploader = await page.locator("input[type=file]").nth(1);
await uploader.setInputFiles(["./test/files/alphabet.txt"]);

await expect(page.getByLabel("# Load Upload Multiple Files")).toHaveValue(
"1"
);

const downloadPromise = page.waitForEvent("download");
await page.getByRole("link").nth(1).click();
const download = await downloadPromise;
await expect(download.suggestedFilename()).toBe("cheetah1.jpg");
await expect(
page.getByLabel("# Load Upload Multiple Files").first()
).toHaveValue("1");
});

test("File component drag-and-drop uploads a file to the server correctly.", async ({
test("File component properly handles drag and drop of image and video files.", async ({
page
}) => {
await drag_and_drop_file(
page,
"input[type=file]",
"./test/files/alphabet.txt",
"alphabet.txt"
);
const uploader = await page.locator("input[type=file]").last();
await uploader.setInputFiles(["./test/files/cheetah1.jpg"]);

// Check that the image file was uploaded
await expect(
page.getByLabel("# Load Upload Multiple Files Image/Video")
).toHaveValue("1");

await page.getByLabel("Clear").click();

await uploader.setInputFiles(["./test/files/world.mp4"]);

// Check that the video file was uploaded
await expect(
page.getByLabel("# Load Upload Multiple Files Image/Video")
).toHaveValue("2");
});
Binary file added js/app/test/files/world.mp4
Binary file not shown.
37 changes: 22 additions & 15 deletions js/upload/src/Upload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
let hidden_upload: HTMLInputElement;

const dispatch = createEventDispatcher();

$: if (filetype == null || typeof filetype === "string") {
accept_file_types = filetype;
} else {
Expand Down Expand Up @@ -106,32 +105,40 @@

function is_valid_mimetype(
file_accept: string | string[] | null,
mime_type: string
uploaded_file_extension: string,
uploaded_file_type: string
): boolean {
if (!file_accept || file_accept === "*" || file_accept === "file/*") {
return true;
}
if (typeof file_accept === "string" && file_accept.endsWith("/*")) {
file_accept = file_accept.split(",");
}
if (Array.isArray(file_accept)) {
return (
file_accept.includes(mime_type) ||
file_accept.some((type) => {
const [category] = type.split("/");
return type.endsWith("/*") && mime_type.startsWith(category + "/");
})
);
let acceptArray: string[];
if (typeof file_accept === "string") {
acceptArray = file_accept.split(",").map((s) => s.trim());
} else if (Array.isArray(file_accept)) {
acceptArray = file_accept;
} else {
return false;
}
return file_accept === mime_type;
return (
acceptArray.includes(uploaded_file_extension) ||
acceptArray.some((type) => {
const [category] = type.split("/").map((s) => s.trim());
return (
type.endsWith("/*") && uploaded_file_type.startsWith(category + "/")
);
})
);
}

async function loadFilesFromDrop(e: DragEvent): Promise<void> {
dragging = false;
if (!e.dataTransfer?.files) return;
const files_to_load = Array.from(e.dataTransfer.files).filter((file) => {
const file_extension = "." + file.name.split(".").pop();
if (file.type && is_valid_mimetype(filetype, file.type)) {
if (
file_extension &&
is_valid_mimetype(filetype, file_extension, file.type)
) {
return true;
}
if (
Expand Down
Loading