From f344592aeb1658013235ded154107f72d86f24e7 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Thu, 17 Aug 2023 18:43:12 -0700 Subject: [PATCH] Allows setting a height to `gr.File` and improves the UI of the component (#5221) * file * file downlaod * add changeset * added story * lint * fix test * add changeset * margin * fixes * lint * modify * lint * add changeset * revert * revert * add changeset * Delete Chatbot.stories.svelte * revert * revert * add changeset * redesign * lint * fixes --------- Co-authored-by: gradio-pr-bot --- .changeset/lovely-bikes-thank.md | 6 +++ gradio/components/file.py | 6 +++ gradio/components/gallery.py | 6 +-- js/file/File.stories.svelte | 45 ++++++++++++++++++++++ js/file/index.svelte | 3 ++ js/file/interactive/FileUpload.svelte | 3 +- js/file/interactive/InteractiveFile.svelte | 4 ++ js/file/shared/FilePreview.svelte | 22 ++++++++--- js/file/shared/utils.ts | 14 +++++-- js/file/static/File.svelte | 3 +- js/file/static/StaticFile.svelte | 3 +- test/test_components.py | 1 + 12 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 .changeset/lovely-bikes-thank.md create mode 100644 js/file/File.stories.svelte diff --git a/.changeset/lovely-bikes-thank.md b/.changeset/lovely-bikes-thank.md new file mode 100644 index 000000000000..41c9c18cf4a7 --- /dev/null +++ b/.changeset/lovely-bikes-thank.md @@ -0,0 +1,6 @@ +--- +"@gradio/file": minor +"gradio": minor +--- + +feat:Allows setting a height to `gr.File` and improves the UI of the component diff --git a/gradio/components/file.py b/gradio/components/file.py index 79426473d605..e6bfb5ff3291 100644 --- a/gradio/components/file.py +++ b/gradio/components/file.py @@ -55,6 +55,7 @@ def __init__( container: bool = True, scale: int | None = None, min_width: int = 160, + height: int | float | None = None, interactive: bool | None = None, visible: bool = True, elem_id: str | None = None, @@ -73,6 +74,7 @@ def __init__( container: If True, will place the component in a container - providing some extra padding around the border. scale: relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer. min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first. + height: The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear. interactive: if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output. visible: If False, component will be hidden. elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles. @@ -102,6 +104,7 @@ def __init__( "The `file_types` parameter is ignored when `file_count` is 'directory'." ) self.type = type + self.height = height self.select: EventListenerMethod """ Event listener for when the user selects file from list. @@ -130,6 +133,7 @@ def get_config(self): "file_types": self.file_types, "value": self.value, "selectable": self.selectable, + "height": self.height, **IOComponent.get_config(self), } @@ -141,6 +145,7 @@ def update( container: bool | None = None, scale: int | None = None, min_width: int | None = None, + height: int | float | None = None, interactive: bool | None = None, visible: bool | None = None, ): @@ -150,6 +155,7 @@ def update( "container": container, "scale": scale, "min_width": min_width, + "height": height, "interactive": interactive, "visible": visible, "value": value, diff --git a/gradio/components/gallery.py b/gradio/components/gallery.py index 8dccacf77f3b..1c0bd9cf050f 100644 --- a/gradio/components/gallery.py +++ b/gradio/components/gallery.py @@ -48,7 +48,7 @@ def __init__( elem_classes: list[str] | str | None = None, columns: int | tuple | None = 2, rows: int | tuple | None = None, - height: str | None = None, + height: int | float | None = None, preview: bool | None = None, object_fit: Literal["contain", "cover", "fill", "none", "scale-down"] | None = None, @@ -71,7 +71,7 @@ def __init__( elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles. columns: Represents the number of images that should be shown in one row, for each of the six standard screen sizes (<576px, <768px, <992px, <1200px, <1400px, >1400px). if fewer that 6 are given then the last will be used for all subsequent breakpoints rows: Represents the number of rows in the image grid, for each of the six standard screen sizes (<576px, <768px, <992px, <1200px, <1400px, >1400px). if fewer that 6 are given then the last will be used for all subsequent breakpoints - height: Height of the gallery. + height: The height of the gallery component, in pixels. If more images are displayed than can fit in the height, a scrollbar will appear. preview: If True, will display the Gallery in preview mode, which shows all of the images as thumbnails and allows the user to click on them to view them in full size. object_fit: CSS object-fit property for the thumbnail images in the gallery. Can be "contain", "cover", "fill", "none", or "scale-down". allow_preview: If True, images in the gallery will be enlarged when they are clicked. Default is True. @@ -127,7 +127,7 @@ def update( visible: bool | None = None, columns: int | tuple | None = None, rows: int | tuple | None = None, - height: str | None = None, + height: int | float | None = None, preview: bool | None = None, object_fit: Literal["contain", "cover", "fill", "none", "scale-down"] | None = None, diff --git a/js/file/File.stories.svelte b/js/file/File.stories.svelte new file mode 100644 index 000000000000..6f6590624f3b --- /dev/null +++ b/js/file/File.stories.svelte @@ -0,0 +1,45 @@ + + + + + + + + diff --git a/js/file/index.svelte b/js/file/index.svelte index ee69ae26de98..b3537b3499c9 100644 --- a/js/file/index.svelte +++ b/js/file/index.svelte @@ -31,6 +31,7 @@ export let container = true; export let scale: number | null = null; export let min_width: number | undefined = undefined; + export let height: number | undefined = undefined; {#if mode === "static"} @@ -49,6 +50,7 @@ {container} {scale} {min_width} + {height} on:clear on:select on:change @@ -73,6 +75,7 @@ {container} {scale} {min_width} + {height} on:clear on:select on:change diff --git a/js/file/interactive/FileUpload.svelte b/js/file/interactive/FileUpload.svelte index d068801710c0..2e4404353ce1 100644 --- a/js/file/interactive/FileUpload.svelte +++ b/js/file/interactive/FileUpload.svelte @@ -14,6 +14,7 @@ export let file_count = "single"; export let file_types: string[] | null = null; export let selectable = false; + export let height: number | undefined = undefined; async function handle_upload({ detail @@ -64,7 +65,7 @@ {#if value} - + {:else} ("upload_files") ?? @@ -113,6 +114,8 @@ {container} {scale} {min_width} + {height} + allow_overflow={false} > (value = detail)} on:drag={({ detail }) => (dragging = detail)} on:clear diff --git a/js/file/shared/FilePreview.svelte b/js/file/shared/FilePreview.svelte index 13310fb08994..28cb5b7c7568 100644 --- a/js/file/shared/FilePreview.svelte +++ b/js/file/shared/FilePreview.svelte @@ -9,9 +9,13 @@ }>(); export let value: FileData | FileData[]; export let selectable = false; + export let height: number | undefined = undefined; -
+
{#each Array.isArray(value) ? value : [value] as file, i} @@ -28,10 +32,6 @@ {display_file_name(file)} - -
- {display_file_size(file)} - {#if file.data} - Download + {@html display_file_size(file)} ⇣ {:else} Uploading... @@ -64,11 +64,13 @@ } .file-preview-holder { overflow-x: auto; + overflow-y: scroll; } .file-preview { width: var(--size-full); max-height: var(--size-60); overflow-y: auto; + margin-top: var(--size-1); color: var(--body-text-color); } .file { @@ -98,4 +100,12 @@ .selectable { cursor: pointer; } + + tbody > tr:nth-child(even) { + background: var(--block-background-fill); + } + + tbody > tr:nth-child(odd) { + background: var(--table-odd-background-fill); + } diff --git a/js/file/shared/utils.ts b/js/file/shared/utils.ts index 4b0ce6057f91..21d1fc5d2107 100644 --- a/js/file/shared/utils.ts +++ b/js/file/shared/utils.ts @@ -8,14 +8,22 @@ export const prettyBytes = (bytes: number): string => { i++; } let unit = units[i]; - return bytes.toFixed(1) + " " + unit; + return bytes.toFixed(1) + " " + unit; }; export const display_file_name = (value: FileData): string => { var str: string; str = value.orig_name || value.name; - if (str.length > 30) { - return `${str.substr(0, 30)}...`; + const max_length = 30; + + if (str.length > max_length) { + const truncated_name = str.substring(0, max_length); + const file_extension_index = str.lastIndexOf("."); + if (file_extension_index !== -1) { + const file_extension = str.slice(file_extension_index); + return `${truncated_name}..${file_extension}`; + } + return truncated_name; } return str; }; diff --git a/js/file/static/File.svelte b/js/file/static/File.svelte index f1382ac5c2ba..7711cbba8856 100644 --- a/js/file/static/File.svelte +++ b/js/file/static/File.svelte @@ -8,6 +8,7 @@ export let label: string; export let show_label = true; export let selectable = false; + export let height: number | undefined = undefined; {#if value} - + {:else} {/if} diff --git a/js/file/static/StaticFile.svelte b/js/file/static/StaticFile.svelte index 8bf62d2cf6b6..2b0ec2ef92f0 100644 --- a/js/file/static/StaticFile.svelte +++ b/js/file/static/StaticFile.svelte @@ -25,6 +25,7 @@ export let root: string; export let label: string; export let show_label: boolean; + export let height: number | undefined = undefined; export let root_url: null | string; export let selectable = false; @@ -120,5 +121,5 @@ : loading_status?.status || "complete"} /> - + diff --git a/test/test_components.py b/test/test_components.py index 91b1388ed765..8a49d73cdb68 100644 --- a/test/test_components.py +++ b/test/test_components.py @@ -1014,6 +1014,7 @@ def test_component_functions(self): "interactive": None, "root_url": None, "selectable": False, + "height": None, } assert file_input.preprocess(None) is None x_file["is_example"] = True