From 5663f3c8454a3908e144e706260ae1fa729727a2 Mon Sep 17 00:00:00 2001 From: Hannah Date: Tue, 19 Dec 2023 19:24:08 +0000 Subject: [PATCH] Improve source selection UX (#6766) * Add new source option styling for pasting from clipboard Use SourceSelect in Image component * prevent device selection cut off tweak source selection ux * Check for dupe sources in source selection Set sources[0] to active_source in Image * tweaks * tweak * add image interaction test * more tests * improve light/dark mode color contrast * add changeset * remove unused prop * add no device found placeholder change T -> T * style tweak * allow pasting on click + add e2e test * fix e2e tests * formatting * add timeout to e2e test * tweak * tweak test * change `getByLabel` to `getByText` * value tweak * logic tweak * test * formatting --------- Co-authored-by: gradio-pr-bot --- .changeset/strong-files-swim.md | 11 ++ js/app/src/lang/en.json | 6 +- js/app/test/image_component_events.spec.ts | 28 ++++- js/app/test/video_component_events.spec.ts | 14 +-- js/atoms/src/SelectSource.svelte | 53 ++++++--- js/atoms/src/UploadText.svelte | 16 ++- js/audio/Index.svelte | 2 +- js/audio/interactive/InteractiveAudio.svelte | 1 - js/image/Image.stories.svelte | 67 ++++++++--- js/image/Index.svelte | 14 ++- js/image/shared/ImageUploader.svelte | 111 ++++++------------ js/image/shared/Webcam.svelte | 106 +++++++++-------- js/upload/src/Upload.svelte | 37 +++++- js/video/Index.svelte | 8 +- js/video/shared/InteractiveVideo.svelte | 115 +++++++++++-------- 15 files changed, 336 insertions(+), 253 deletions(-) create mode 100644 .changeset/strong-files-swim.md diff --git a/.changeset/strong-files-swim.md b/.changeset/strong-files-swim.md new file mode 100644 index 0000000000000..002dc818f9d25 --- /dev/null +++ b/.changeset/strong-files-swim.md @@ -0,0 +1,11 @@ +--- +"@gradio/app": patch +"@gradio/atoms": patch +"@gradio/audio": patch +"@gradio/image": patch +"@gradio/upload": patch +"@gradio/video": patch +"gradio": patch +--- + +fix:Improve source selection UX diff --git a/js/app/src/lang/en.json b/js/app/src/lang/en.json index e29f3ee13065c..58ef444c90f1b 100644 --- a/js/app/src/lang/en.json +++ b/js/app/src/lang/en.json @@ -48,7 +48,8 @@ "remove": "Remove", "share": "Share", "submit": "Submit", - "undo": "Undo" + "undo": "Undo", + "no_devices": "No devices found" }, "dataframe": { "incorrect_format": "Incorrect format, only CSV and TSV files are supported", @@ -110,6 +111,7 @@ "drop_csv": "Drop CSV Here", "drop_file": "Drop File Here", "drop_image": "Drop Image Here", - "drop_video": "Drop Video Here" + "drop_video": "Drop Video Here", + "paste_clipboard": "Paste from Clipboard" } } diff --git a/js/app/test/image_component_events.spec.ts b/js/app/test/image_component_events.spec.ts index 36cce521c880a..54d46086b4bff 100644 --- a/js/app/test/image_component_events.spec.ts +++ b/js/app/test/image_component_events.spec.ts @@ -65,7 +65,33 @@ test("Image copy from clipboard dispatches upload event.", async ({ page }) => { navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]); }); - await page.getByLabel("clipboard-image-toolbar-btn").click(); + await page.getByLabel("Paste from clipboard").click(); + await Promise.all([ + page.waitForResponse( + (resp) => resp.url().includes("/clipboard.png") && resp.status() === 200 + ) + ]); await expect(page.getByLabel("# Change Events").first()).toHaveValue("1"); await expect(page.getByLabel("# Upload Events")).toHaveValue("1"); }); + +test("Image paste to clipboard via the Upload component works", async ({ + page +}) => { + await page.evaluate(async () => { + navigator.clipboard.writeText("123"); + }); + + await page.getByLabel("Paste from clipboard").click(); + await page.evaluate(async () => { + const blob = await ( + await fetch( + `https://gradio-builds.s3.amazonaws.com/assets/PDFDisplay.png` + ) + ).blob(); + navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]); + }); + + await page.getByText("Paste from clipboard").click(); + await expect(page.getByLabel("# Upload Events")).toHaveValue("1"); +}); diff --git a/js/app/test/video_component_events.spec.ts b/js/app/test/video_component_events.spec.ts index 0006ed35c2604..8120a62816463 100644 --- a/js/app/test/video_component_events.spec.ts +++ b/js/app/test/video_component_events.spec.ts @@ -3,9 +3,7 @@ import { test, expect, drag_and_drop_file } from "@gradio/tootils"; test("Video click-to-upload uploads video successfuly. Clear, play, and pause buttons dispatch events correctly. Downloading the file works and has the correct name.", async ({ page }) => { - await page - .getByRole("button", { name: "Drop Video Here - or - Click to Upload" }) - .click(); + await page.getByRole("button", { name: "Upload file" }).click(); const uploader = await page.locator("input[type=file]"); await uploader.setInputFiles(["./test/files/file_test.ogg"]); @@ -14,9 +12,7 @@ test("Video click-to-upload uploads video successfuly. Clear, play, and pause bu await page.getByLabel("Clear").click(); await expect(page.getByLabel("# Change Events")).toHaveValue("2"); - await page - .getByRole("button", { name: "Drop Video Here - or - Click to Upload" }) - .click(); + await page.getByRole("button", { name: "Upload file" }).click(); await uploader.setInputFiles(["./test/files/file_test.ogg"]); @@ -30,9 +26,7 @@ test("Video click-to-upload uploads video successfuly. Clear, play, and pause bu }); test("Video play, pause events work correctly.", async ({ page }) => { - await page - .getByRole("button", { name: "Drop Video Here - or - Click to Upload" }) - .click(); + await page.getByLabel("Upload file").click(); const uploader = await page.locator("input[type=file]"); await uploader.setInputFiles(["./test/files/file_test.ogg"]); @@ -48,6 +42,7 @@ test("Video play, pause events work correctly.", async ({ page }) => { test("Video drag-and-drop uploads a file to the server correctly.", async ({ page }) => { + await page.getByLabel("Upload file").click(); await drag_and_drop_file( page, "input[type=file]", @@ -62,6 +57,7 @@ test("Video drag-and-drop uploads a file to the server correctly.", async ({ test("Video drag-and-drop displays a warning when the file is of the wrong mime type.", async ({ page }) => { + await page.getByLabel("Upload file").click(); await drag_and_drop_file( page, "input[type=file]", diff --git a/js/atoms/src/SelectSource.svelte b/js/atoms/src/SelectSource.svelte index a2db4585cb1f8..6e01a3cff9e61 100644 --- a/js/atoms/src/SelectSource.svelte +++ b/js/atoms/src/SelectSource.svelte @@ -1,22 +1,34 @@ -{#if sources.length > 1} +{#if unique_sources.length > 1} {#if sources.includes("upload")} handle_select_source("upload")}> {/if} @@ -25,10 +37,8 @@ class="icon" class:selected={active_source === "microphone"} aria-label="Record audio" - on:click={() => { - handle_clear(); - active_source = "microphone"; - }}> handle_select_source("microphone")} + > {/if} @@ -36,11 +46,17 @@ handle_select_source("webcam")}> + {/if} + {#if sources.includes("clipboard")} + {/if} @@ -58,7 +74,6 @@ right: 0; margin-left: auto; margin-right: auto; - align-self: flex-end; } .icon { diff --git a/js/atoms/src/UploadText.svelte b/js/atoms/src/UploadText.svelte index 84112f82980d6..88f9a7d823d0b 100644 --- a/js/atoms/src/UploadText.svelte +++ b/js/atoms/src/UploadText.svelte @@ -1,7 +1,8 @@
- + + {#if type === "clipboard"} + + {:else} + + {/if} + {i18n(defs[type] || defs.file)} diff --git a/js/audio/Index.svelte b/js/audio/Index.svelte index 8529278d2f2c0..a34278e524f5b 100644 --- a/js/audio/Index.svelte +++ b/js/audio/Index.svelte @@ -85,7 +85,7 @@ let dragging: boolean; - $: if (sources) { + $: if (!active_source && sources) { active_source = sources[0]; } diff --git a/js/audio/interactive/InteractiveAudio.svelte b/js/audio/interactive/InteractiveAudio.svelte index 2db20039d464b..21492620ebd6f 100644 --- a/js/audio/interactive/InteractiveAudio.svelte +++ b/js/audio/interactive/InteractiveAudio.svelte @@ -249,7 +249,6 @@ bind:dragging on:error={({ detail }) => dispatch("error", detail)} {root} - include_sources={sources.length > 1} > diff --git a/js/image/Image.stories.svelte b/js/image/Image.stories.svelte index 579f53ca3d08e..1d7d349130aee 100644 --- a/js/image/Image.stories.svelte +++ b/js/image/Image.stories.svelte @@ -1,25 +1,10 @@ - +