mirror of
https://github.com/gradio-app/gradio.git
synced 2025-03-31 12:20:26 +08:00
fix pending chatbot message styling and ensure messages with value None
don't render (#5775)
* fix pending chatbot message styling * border fixes * add changeset * add changeset * ensure null messages arent shown * add hide css again * render loading inside message + add test * fix test * add changeset * add changeset * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
parent
6e56a0d9b0
commit
e2874bc3cb
6
.changeset/rude-dots-grab.md
Normal file
6
.changeset/rude-dots-grab.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gradio/chatbot": patch
|
||||
"gradio": patch
|
||||
---
|
||||
|
||||
fix:fix pending chatbot message styling and ensure messages with value `None` don't render
|
@ -36,8 +36,8 @@ describe("Chatbot", () => {
|
||||
assert.exists(user);
|
||||
});
|
||||
|
||||
test("renders none messages", async () => {
|
||||
const { getAllByTestId } = await render(Chatbot, {
|
||||
test("null messages are not visible", async () => {
|
||||
const { getByRole, container } = await render(Chatbot, {
|
||||
loading_status,
|
||||
label: "chatbot",
|
||||
value: [[null, null]],
|
||||
@ -47,10 +47,33 @@ describe("Chatbot", () => {
|
||||
theme_mode: "dark"
|
||||
});
|
||||
|
||||
const user = getAllByTestId("user");
|
||||
const bot = getAllByTestId("bot");
|
||||
assert.isFalse(user[0].innerHTML.includes("span"));
|
||||
assert.isFalse(bot[0].innerHTML.includes("span"));
|
||||
const chatbot = getByRole("log");
|
||||
|
||||
const userButton = container.querySelector(".user button");
|
||||
const botButton = container.querySelector(".bot button");
|
||||
|
||||
assert.notExists(userButton);
|
||||
assert.notExists(botButton);
|
||||
|
||||
assert.isFalse(chatbot.innerHTML.includes("button"));
|
||||
});
|
||||
|
||||
test("empty string messages are visible", async () => {
|
||||
const { container } = await render(Chatbot, {
|
||||
loading_status,
|
||||
label: "chatbot",
|
||||
value: [["", ""]],
|
||||
root: "",
|
||||
root_url: "",
|
||||
latex_delimiters: [{ left: "$$", right: "$$", display: true }],
|
||||
theme_mode: "dark"
|
||||
});
|
||||
|
||||
const userButton = container.querySelector(".user button");
|
||||
const botButton = container.querySelector(".bot button");
|
||||
|
||||
assert.exists(userButton);
|
||||
assert.exists(botButton);
|
||||
});
|
||||
|
||||
test("renders additional message as they are passed", async () => {
|
||||
|
@ -121,131 +121,131 @@
|
||||
{#if value !== null}
|
||||
{#each value as message_pair, i}
|
||||
{#each message_pair as message, j}
|
||||
<div
|
||||
class="message-row {layout} {j == 0 ? 'user-row' : 'bot-row'}"
|
||||
class:hide={message === null}
|
||||
>
|
||||
{#if avatar_images[j] !== null}
|
||||
<div class="avatar-container">
|
||||
<img
|
||||
class="avatar-image"
|
||||
src={get_fetchable_url_or_file(
|
||||
avatar_images[j],
|
||||
root,
|
||||
root_url
|
||||
)}
|
||||
alt="{j == 0 ? 'user' : 'bot'} avatar"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="message {j == 0 ? 'user' : 'bot'}"
|
||||
class:message-fit={layout === "bubble" && !bubble_full_width}
|
||||
class:panel-full-width={layout === "panel"}
|
||||
class:message-bubble-border={layout === "bubble"}
|
||||
class:message-markdown-disabled={!render_markdown}
|
||||
>
|
||||
<button
|
||||
data-testid={j == 0 ? "user" : "bot"}
|
||||
class:latest={i === value.length - 1}
|
||||
class:message-markdown-disabled={!render_markdown}
|
||||
class:selectable
|
||||
style:text-align="left"
|
||||
on:click={() => handle_select(i, j, message)}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handle_select(i, j, message);
|
||||
}
|
||||
}}
|
||||
dir={rtl ? "rtl" : "ltr"}
|
||||
aria-label={(j == 0 ? "user" : "bot") +
|
||||
"'s message:' " +
|
||||
message}
|
||||
>
|
||||
{#if typeof message === "string"}
|
||||
<Markdown
|
||||
{message}
|
||||
{latex_delimiters}
|
||||
{sanitize_html}
|
||||
{render_markdown}
|
||||
{line_breaks}
|
||||
on:load={scroll}
|
||||
/>
|
||||
{:else if message !== null && message.mime_type?.includes("audio")}
|
||||
<audio
|
||||
data-testid="chatbot-audio"
|
||||
controls
|
||||
preload="metadata"
|
||||
src={message.data}
|
||||
title={message.alt_text}
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
/>
|
||||
{:else if message !== null && message.mime_type?.includes("video")}
|
||||
<video
|
||||
data-testid="chatbot-video"
|
||||
controls
|
||||
src={message.data}
|
||||
title={message.alt_text}
|
||||
preload="auto"
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
>
|
||||
<track kind="captions" />
|
||||
</video>
|
||||
{:else if message !== null && message.mime_type?.includes("image")}
|
||||
{#if message !== null || pending_message}
|
||||
<div class="message-row {layout} {j == 0 ? 'user-row' : 'bot-row'}">
|
||||
{#if avatar_images[j] !== null}
|
||||
<div class="avatar-container">
|
||||
<img
|
||||
data-testid="chatbot-image"
|
||||
src={message.data}
|
||||
alt={message.alt_text}
|
||||
class="avatar-image"
|
||||
src={get_fetchable_url_or_file(
|
||||
avatar_images[j],
|
||||
root,
|
||||
root_url
|
||||
)}
|
||||
alt="{j == 0 ? 'user' : 'bot'} avatar"
|
||||
/>
|
||||
{:else if message !== null && message.data !== null}
|
||||
<a
|
||||
data-testid="chatbot-file"
|
||||
href={message.data}
|
||||
target="_blank"
|
||||
download={window.__is_colab__
|
||||
? null
|
||||
: message.orig_name || message.name}
|
||||
>
|
||||
{message.orig_name || message.name}
|
||||
</a>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{#if (likeable && j !== 0) || (show_copy_button && message && typeof message === "string")}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="message-buttons-{j == 0
|
||||
? 'user'
|
||||
: 'bot'} message-buttons-{layout} {avatar_images[j] !==
|
||||
null && 'with-avatar'}"
|
||||
class:message-buttons-fit={layout === "bubble" &&
|
||||
!bubble_full_width}
|
||||
class:bubble-buttons-user={layout === "bubble"}
|
||||
class="message {j == 0 ? 'user' : 'bot'}"
|
||||
class:message-fit={layout === "bubble" && !bubble_full_width}
|
||||
class:panel-full-width={layout === "panel"}
|
||||
class:message-bubble-border={layout === "bubble"}
|
||||
class:message-markdown-disabled={!render_markdown}
|
||||
>
|
||||
{#if likeable && j == 1}
|
||||
<LikeDislike
|
||||
action="like"
|
||||
handle_action={() => handle_like(i, j, message, true)}
|
||||
/>
|
||||
<LikeDislike
|
||||
action="dislike"
|
||||
handle_action={() => handle_like(i, j, message, false)}
|
||||
/>
|
||||
{/if}
|
||||
{#if show_copy_button && message && typeof message === "string"}
|
||||
<Copy value={message} />
|
||||
{/if}
|
||||
<button
|
||||
data-testid={j == 0 ? "user" : "bot"}
|
||||
class:latest={i === value.length - 1}
|
||||
class:message-markdown-disabled={!render_markdown}
|
||||
class:selectable
|
||||
style:text-align="left"
|
||||
on:click={() => handle_select(i, j, message)}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handle_select(i, j, message);
|
||||
}
|
||||
}}
|
||||
dir={rtl ? "rtl" : "ltr"}
|
||||
aria-label={(j == 0 ? "user" : "bot") +
|
||||
"'s message:' " +
|
||||
message}
|
||||
>
|
||||
{#if typeof message === "string"}
|
||||
<Markdown
|
||||
{message}
|
||||
{latex_delimiters}
|
||||
{sanitize_html}
|
||||
{render_markdown}
|
||||
{line_breaks}
|
||||
on:load={scroll}
|
||||
/>
|
||||
{:else if message !== null && message.mime_type?.includes("audio")}
|
||||
<audio
|
||||
data-testid="chatbot-audio"
|
||||
controls
|
||||
preload="metadata"
|
||||
src={message.data}
|
||||
title={message.alt_text}
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
/>
|
||||
{:else if message !== null && message.mime_type?.includes("video")}
|
||||
<video
|
||||
data-testid="chatbot-video"
|
||||
controls
|
||||
src={message.data}
|
||||
title={message.alt_text}
|
||||
preload="auto"
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
>
|
||||
<track kind="captions" />
|
||||
</video>
|
||||
{:else if message !== null && message.mime_type?.includes("image")}
|
||||
<img
|
||||
data-testid="chatbot-image"
|
||||
src={message.data}
|
||||
alt={message.alt_text}
|
||||
/>
|
||||
{:else if message !== null && message.data !== null}
|
||||
<a
|
||||
data-testid="chatbot-file"
|
||||
href={message.data}
|
||||
target="_blank"
|
||||
download={window.__is_colab__
|
||||
? null
|
||||
: message.orig_name || message.name}
|
||||
>
|
||||
{message.orig_name || message.name}
|
||||
</a>
|
||||
{:else if pending_message && j === 1}
|
||||
<Pending {layout} />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if (likeable && j !== 0) || (show_copy_button && message && typeof message === "string")}
|
||||
<div
|
||||
class="message-buttons-{j == 0
|
||||
? 'user'
|
||||
: 'bot'} message-buttons-{layout} {avatar_images[j] !==
|
||||
null && 'with-avatar'}"
|
||||
class:message-buttons-fit={layout === "bubble" &&
|
||||
!bubble_full_width}
|
||||
class:bubble-buttons-user={layout === "bubble"}
|
||||
>
|
||||
{#if likeable && j == 1}
|
||||
<LikeDislike
|
||||
action="like"
|
||||
handle_action={() => handle_like(i, j, message, true)}
|
||||
/>
|
||||
<LikeDislike
|
||||
action="dislike"
|
||||
handle_action={() => handle_like(i, j, message, false)}
|
||||
/>
|
||||
{/if}
|
||||
{#if show_copy_button && message && typeof message === "string"}
|
||||
<Copy value={message} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{/if}
|
||||
<Pending {pending_message} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,26 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let pending_message = false;
|
||||
export let layout = "bubble";
|
||||
</script>
|
||||
|
||||
{#if pending_message}
|
||||
<div
|
||||
class="message pending"
|
||||
role="status"
|
||||
aria-label="Loading response"
|
||||
aria-live="polite"
|
||||
>
|
||||
<span class="sr-only">Loading content</span>
|
||||
<div class="dot-flashing" />
|
||||
|
||||
<div class="dot-flashing" />
|
||||
|
||||
<div class="dot-flashing" />
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="message pending"
|
||||
role="status"
|
||||
aria-label="Loading response"
|
||||
aria-live="polite"
|
||||
style:border-radius={layout === "bubble" ? "var(--radius-xxl)" : "none"}
|
||||
>
|
||||
<span class="sr-only">Loading content</span>
|
||||
<div class="dot-flashing" />
|
||||
|
||||
<div class="dot-flashing" />
|
||||
|
||||
<div class="dot-flashing" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pending {
|
||||
border-color: var(--border-color-primary);
|
||||
background: var(--background-fill-secondary);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -28,6 +26,8 @@
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
gap: 2px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.dot-flashing {
|
||||
animation: dot-flashing 1s infinite linear alternate;
|
||||
|
Loading…
x
Reference in New Issue
Block a user