Skip to content

Commit

Permalink
Ensure checked files persist after FileExplorer rerenders (#6691)
Browse files Browse the repository at this point in the history
* add tree_updated flag

* add changeset

* add changeset

* test

* generate notebooks

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
  • Loading branch information
hannahblair and gradio-pr-bot committed Dec 8, 2023
1 parent 053bec9 commit 128ab5d
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 8 deletions.
6 changes: 6 additions & 0 deletions .changeset/strong-cooks-talk.md
@@ -0,0 +1,6 @@
---
"@gradio/fileexplorer": patch
"gradio": patch
---

fix:Ensure checked files persist after FileExplorer rerenders
2 changes: 1 addition & 1 deletion demo/file_explorer_component_events/run.ipynb
@@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: file_explorer_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": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('dir1')\n", "!wget -q -O dir1/bar.txt https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir1/bar.txt\n", "!wget -q -O dir1/foo.txt https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir1/foo.txt\n", "os.mkdir('dir2')\n", "!wget -q -O dir2/baz.png https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir2/baz.png\n", "!wget -q -O dir2/foo.png https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir2/foo.png"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "from pathlib import Path\n", "\n", "base_root = Path(__file__).parent.resolve()\n", "\n", "with gr.Blocks() as demo:\n", " dd = gr.Dropdown(label=\"Select File Explorer Root\",\n", " value=str(base_root / \"dir1\"),\n", " choices=[str(base_root / \"dir1\"), str(base_root / \"dir2\")])\n", " fe = gr.FileExplorer(root=str(base_root / \"dir1\"), interactive=True)\n", " dd.select(lambda s: gr.FileExplorer(root=s), inputs=[dd], outputs=[fe])\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: file_explorer_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": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('dir1')\n", "!wget -q -O dir1/bar.txt https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir1/bar.txt\n", "!wget -q -O dir1/foo.txt https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir1/foo.txt\n", "os.mkdir('dir2')\n", "!wget -q -O dir2/baz.png https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir2/baz.png\n", "!wget -q -O dir2/foo.png https://github.com/gradio-app/gradio/raw/main/demo/file_explorer_component_events/dir2/foo.png"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "from pathlib import Path\n", "\n", "base_root = Path(__file__).parent.resolve()\n", "\n", "with gr.Blocks() as demo:\n", " dd = gr.Dropdown(\n", " label=\"Select File Explorer Root\",\n", " value=str(base_root / \"dir1\"),\n", " choices=[str(base_root / \"dir1\"), str(base_root / \"dir2\")],\n", " )\n", " fe = gr.FileExplorer(root=str(base_root / \"dir1\"), interactive=True)\n", " dd.select(lambda s: gr.FileExplorer(root=s), inputs=[dd], outputs=[fe])\n", "\n", " with gr.Row():\n", " a = gr.Textbox(elem_id=\"input-box\")\n", " a.change(lambda x: x, inputs=[a])\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
12 changes: 9 additions & 3 deletions demo/file_explorer_component_events/run.py
Expand Up @@ -4,12 +4,18 @@
base_root = Path(__file__).parent.resolve()

with gr.Blocks() as demo:
dd = gr.Dropdown(label="Select File Explorer Root",
value=str(base_root / "dir1"),
choices=[str(base_root / "dir1"), str(base_root / "dir2")])
dd = gr.Dropdown(
label="Select File Explorer Root",
value=str(base_root / "dir1"),
choices=[str(base_root / "dir1"), str(base_root / "dir2")],
)
fe = gr.FileExplorer(root=str(base_root / "dir1"), interactive=True)
dd.select(lambda s: gr.FileExplorer(root=s), inputs=[dd], outputs=[fe])

with gr.Row():
a = gr.Textbox(elem_id="input-box")
a.change(lambda x: x, inputs=[a])


if __name__ == "__main__":
demo.launch()
12 changes: 11 additions & 1 deletion js/app/test/file_explorer_component_events.spec.ts
@@ -1,4 +1,4 @@
import { test } from "@gradio/tootils";
import { test, expect } from "@gradio/tootils";

test("File Explorer is interactive and re-runs the server_fn when root is updated", async ({
page
Expand Down Expand Up @@ -26,4 +26,14 @@ test("File Explorer is interactive and re-runs the server_fn when root is update
.filter({ hasText: "foo.png" })
.getByRole("checkbox")
.check();

await page.locator("#input-box").getByTestId("textbox").fill("test");

await expect(
page.locator("span").filter({ hasText: "baz.png" }).getByRole("checkbox")
).toBeChecked();

await expect(
page.locator("span").filter({ hasText: "foo.png" }).getByRole("checkbox")
).toBeChecked();
});
9 changes: 6 additions & 3 deletions js/fileexplorer/shared/utils.ts
Expand Up @@ -30,24 +30,26 @@ interface FSStore {
}

export const make_fs_store = (): FSStore => {
const { subscribe, set, update } = writable<Node[] | null>(null);
const { subscribe, set } = writable<Node[] | null>(null);
let root: Node = {
type: "folder",
path: "",
checked: false,
children_visible: false,
parent: null
};
let tree_updated = false;

function create_fs_graph(serialised_node: SerialisedNode[]): void {
root.children = process_tree(serialised_node);
tree_updated = true;
set(root.children);
}

let old_checked_paths: string[][] = [];

function set_checked_from_paths(checked_paths: string[][]): string[][] {
if (dequal(checked_paths, old_checked_paths)) {
if (dequal(checked_paths, old_checked_paths) && !tree_updated) {
return checked_paths;
}
old_checked_paths = checked_paths;
Expand Down Expand Up @@ -88,6 +90,8 @@ export const make_fs_store = (): FSStore => {

set(root.children!);

tree_updated = false;

return new_checked_paths;
}

Expand Down Expand Up @@ -235,7 +239,6 @@ function check_node_and_children(
checked: boolean,
checked_nodes: Node[]
): Node[] {
// console.log(node, checked);
if (node === null || node === undefined) return checked_nodes;
for (let i = 0; i < node.length; i++) {
node[i].checked = checked;
Expand Down

0 comments on commit 128ab5d

Please sign in to comment.