mirror of
https://github.com/gradio-app/gradio.git
synced 2024-11-21 01:01:05 +08:00
ensure css loads before mounting app (#3573)
* ensure css loads before mounting app * changelog * fix tests * change? * changelog
This commit is contained in:
parent
cecd5a2526
commit
0d9a08bf64
@ -13,6 +13,7 @@
|
||||
- Use Gradio API server to send telemetry using `huggingface_hub` [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3488](https://github.com/gradio-app/gradio/pull/3488)
|
||||
- Fixes an an issue where if the Blocks scope was not exited, then State could be shared across sessions, by [@abidlabs](https://github.com/abidlabs) in [PR 3600](https://github.com/gradio-app/gradio/pull/3600)
|
||||
- Fixed bug where "or" was not being localized in file upload text by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3599](https://github.com/gradio-app/gradio/pull/3599)
|
||||
- Ensure CSS has fully loaded before rendering the application, by [@pngwn](https://github.com/pngwn) in [PR 3573](https://github.com/gradio-app/gradio/pull/3573)
|
||||
|
||||
## Documentation Changes:
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: code"]}, {"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", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/code/file.css"]}, {"cell_type": "code", "execution_count": null, "id": 44380577570523278879349135829904343037, "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import os\n", "from time import sleep\n", "\n", "\n", "css_file = os.path.join(os.path.abspath(''), \"file.css\")\n", "\n", "\n", "def set_lang(language):\n", " print(language)\n", " return gr.Code.update(language=language)\n", "\n", "\n", "def set_lang_from_path():\n", " sleep(1)\n", " return gr.Code.update((css_file, ), language=\"css\")\n", "\n", "\n", "def code(language, code):\n", " return gr.Code.update(code, language=language)\n", "\n", "\n", "io = gr.Interface(lambda x: x, \"code\", \"code\")\n", "\n", "with gr.Blocks() as demo:\n", " lang = gr.Dropdown(value=\"python\", choices=gr.Code.languages)\n", " with gr.Row():\n", " code_in = gr.Code(language=\"python\", label=\"Input\")\n", " code_out = gr.Code(label=\"Ouput\")\n", " btn = gr.Button(\"Run\")\n", " btn_two = gr.Button(\"Load File\")\n", "\n", " lang.change(set_lang, inputs=lang, outputs=code_in)\n", " btn.click(code, inputs=[lang, code_in], outputs=code_out)\n", " btn_two.click(set_lang_from_path, inputs=None, outputs=code_out)\n", " io.render()\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: code"]}, {"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", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/code/file.css"]}, {"cell_type": "code", "execution_count": null, "id": 44380577570523278879349135829904343037, "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import os\n", "from time import sleep\n", "\n", "\n", "css_file = os.path.join(os.path.abspath(''), \"file.css\")\n", "\n", "\n", "def set_lang(language):\n", " print(language)\n", " return gr.Code.update(language=language)\n", "\n", "\n", "def set_lang_from_path():\n", " sleep(1)\n", " return gr.Code.update((css_file,), language=\"css\")\n", "\n", "\n", "def code(language, code):\n", " return gr.Code.update(code, language=language)\n", "\n", "\n", "io = gr.Interface(lambda x: x, \"code\", \"code\")\n", "\n", "with gr.Blocks() as demo:\n", " lang = gr.Dropdown(value=\"python\", choices=gr.Code.languages)\n", " with gr.Row():\n", " code_in = gr.Code(\n", " language=\"python\",\n", " label=\"Input\",\n", " value='def all_odd_elements(sequence):\\n \"\"\"Returns every odd element of the sequence.\"\"\"',\n", " )\n", " code_out = gr.Code(label=\"Ouput\")\n", " btn = gr.Button(\"Run\")\n", " btn_two = gr.Button(\"Load File\")\n", "\n", " lang.change(set_lang, inputs=lang, outputs=code_in)\n", " btn.click(code, inputs=[lang, code_in], outputs=code_out)\n", " btn_two.click(set_lang_from_path, inputs=None, outputs=code_out)\n", " io.render()\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -13,7 +13,7 @@ def set_lang(language):
|
||||
|
||||
def set_lang_from_path():
|
||||
sleep(1)
|
||||
return gr.Code.update((css_file, ), language="css")
|
||||
return gr.Code.update((css_file,), language="css")
|
||||
|
||||
|
||||
def code(language, code):
|
||||
@ -25,7 +25,11 @@ io = gr.Interface(lambda x: x, "code", "code")
|
||||
with gr.Blocks() as demo:
|
||||
lang = gr.Dropdown(value="python", choices=gr.Code.languages)
|
||||
with gr.Row():
|
||||
code_in = gr.Code(language="python", label="Input")
|
||||
code_in = gr.Code(
|
||||
language="python",
|
||||
label="Input",
|
||||
value='def all_odd_elements(sequence):\n """Returns every odd element of the sequence."""',
|
||||
)
|
||||
code_out = gr.Code(label="Ouput")
|
||||
btn = gr.Button("Run")
|
||||
btn_two = gr.Button("Load File")
|
||||
|
@ -90,22 +90,28 @@
|
||||
let config: Config;
|
||||
let loading_text: string = "Loading...";
|
||||
|
||||
function mount_custom_css(target: HTMLElement, css_string: string | null) {
|
||||
async function mount_custom_css(
|
||||
target: HTMLElement,
|
||||
css_string: string | null
|
||||
) {
|
||||
if (css_string) {
|
||||
let style = document.createElement("style");
|
||||
style.innerHTML = css_string;
|
||||
target.appendChild(style);
|
||||
}
|
||||
mount_css(config.root + "/theme.css", document.head);
|
||||
await mount_css(config.root + "/theme.css", document.head);
|
||||
if (!config.stylesheets) return;
|
||||
for (let stylesheet of config.stylesheets) {
|
||||
let absolute_link =
|
||||
stylesheet.startsWith("http:") || stylesheet.startsWith("https:");
|
||||
mount_css(
|
||||
absolute_link ? stylesheet : config.root + "/" + stylesheet,
|
||||
document.head
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
config.stylesheets.map((stylesheet) => {
|
||||
let absolute_link =
|
||||
stylesheet.startsWith("http:") || stylesheet.startsWith("https:");
|
||||
return mount_css(
|
||||
absolute_link ? stylesheet : config.root + "/" + stylesheet,
|
||||
document.head
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async function reload_check(root: string) {
|
||||
@ -178,6 +184,7 @@
|
||||
};
|
||||
|
||||
let app: Awaited<ReturnType<typeof client>>;
|
||||
let css_ready = false;
|
||||
function handle_status(_status: SpaceStatus) {
|
||||
status = _status;
|
||||
}
|
||||
@ -201,7 +208,8 @@
|
||||
detail: "RUNNING"
|
||||
};
|
||||
|
||||
mount_custom_css(wrapper, config.css);
|
||||
await mount_custom_css(wrapper, config.css);
|
||||
css_ready = true;
|
||||
window.__is_colab__ = config.is_colab;
|
||||
|
||||
if (config.dev_mode) {
|
||||
@ -314,7 +322,7 @@
|
||||
is_space={config.is_space}
|
||||
{app_mode}
|
||||
/>
|
||||
{:else if config && Blocks}
|
||||
{:else if config && Blocks && css_ready}
|
||||
<Blocks
|
||||
{app}
|
||||
{...config}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -28,7 +29,8 @@ function mock_api(page: Page, body: Array<unknown>) {
|
||||
test("renders the correct elements", async ({ page }) => {
|
||||
await mock_demo(page, "blocks_inputs");
|
||||
await mock_api(page, [["hi dawood"]]);
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
const textboxes = await page.getByLabel("Input");
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -28,7 +29,8 @@ function mock_api(page: Page, body: Array<unknown>) {
|
||||
test("renders the correct elements", async ({ page }) => {
|
||||
await mock_demo(page, "blocks_kinematics");
|
||||
await mock_api(page, [[25, 45]]);
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
await Promise.all([
|
||||
page.click("button:has-text('Run')"),
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -28,7 +29,8 @@ function mock_api(page: Page, body: Array<unknown>) {
|
||||
test("renders the correct elements", async ({ page }) => {
|
||||
await mock_demo(page, "blocks_page_load");
|
||||
await mock_api(page, [["Welcome! This page has loaded for Frank"]]);
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
const textbox = await page.getByLabel("Name");
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -27,7 +28,8 @@ function mock_api(page: Page, body: Array<unknown>) {
|
||||
|
||||
test("renders the correct elements", async ({ page }) => {
|
||||
await mock_demo(page, "blocks_xray");
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
const description = await page.getByTestId("markdown");
|
||||
await expect(description).toContainText("Detect Disease From Scan");
|
||||
@ -56,7 +58,8 @@ test("can run an api request and display the data", async ({ page }) => {
|
||||
]
|
||||
]);
|
||||
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
await page.getByLabel("Covid").check();
|
||||
await page.getByLabel("Lung Cancer").check();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -28,7 +29,8 @@ function mock_api(page: Page, body: Array<unknown>) {
|
||||
test("a component acts as both input and output", async ({ page }) => {
|
||||
await mock_demo(page, "input_output");
|
||||
await mock_api(page, [["tset"]]);
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
const textbox = await page.getByLabel("Input-Output");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { BASE64_IMAGE, BASE64_AUDIO } from "./media_data";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -28,7 +29,8 @@ function mock_api(page: Page, body: Array<unknown>) {
|
||||
|
||||
test("test inputs", async ({ page }) => {
|
||||
await mock_demo(page, "kitchen_sink");
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
const textbox = await page.getByLabel("Textbox").nth(0);
|
||||
await expect(textbox).toHaveValue("Lorem ipsum");
|
||||
@ -209,7 +211,8 @@ test("test outputs", async ({ page }) => {
|
||||
]
|
||||
]);
|
||||
|
||||
await page.goto("http://localhost:9876");
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
|
||||
const submit_button = await page.locator("button", { hasText: /Submit/ });
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { test, expect, Page } from "@playwright/test";
|
||||
import { BASE64_PLOT_IMG } from "./media_data";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
function mock_demo(page: Page, demo: string) {
|
||||
return page.route("**/config", (route) => {
|
||||
@ -12,17 +13,6 @@ function mock_demo(page: Page, demo: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function mock_theme(page: Page) {
|
||||
return page.route("**/theme.css", (route) => {
|
||||
return route.fulfill({
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
},
|
||||
path: `./test/mocks/theme.css`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function mock_api(page: Page, body: Array<unknown>) {
|
||||
return page.route("**/run/predict", (route) => {
|
||||
const id = JSON.parse(route.request().postData()!).fn_index;
|
||||
@ -41,7 +31,7 @@ test("matplotlib", async ({ page }) => {
|
||||
await mock_demo(page, "outbreak_forecast");
|
||||
await mock_api(page, [[{ type: "matplotlib", plot: BASE64_PLOT_IMG }]]);
|
||||
await mock_theme(page);
|
||||
await page.goto("http://localhost:9876");
|
||||
await wait_for_page(page);
|
||||
|
||||
await page.getByLabel("Plot Type").click();
|
||||
await page.getByRole("button", { name: "Matplotlib" }).click();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page, Locator } from "@playwright/test";
|
||||
import { mock_theme, wait_for_page } from "./utils";
|
||||
|
||||
//taken from: https://github.com/microsoft/playwright/issues/20032
|
||||
async function changeSlider(
|
||||
@ -59,8 +60,8 @@ function mock_api(page: Page) {
|
||||
test("slider release", async ({ page }) => {
|
||||
await mock_demo(page, "slider_release");
|
||||
await mock_api(page);
|
||||
await page.goto("http://localhost:9876");
|
||||
|
||||
await mock_theme(page);
|
||||
await wait_for_page(page);
|
||||
const slider = page.getByLabel("Slider");
|
||||
|
||||
await changeSlider(page, slider, slider, 0.7);
|
||||
|
17
ui/packages/app/test/utils.ts
Normal file
17
ui/packages/app/test/utils.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
|
||||
export function mock_theme(page: Page) {
|
||||
return page.route("**/theme.css", (route) => {
|
||||
return route.fulfill({
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
},
|
||||
path: `./test/mocks/theme.css`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function wait_for_page(page: Page) {
|
||||
await page.goto("http://localhost:9876");
|
||||
await page.waitForResponse("**/theme.css");
|
||||
}
|
Loading…
Reference in New Issue
Block a user