fix(ui): prevent reading indicator from sticking after assistant resp… · openclaw/openclaw@a4f80f9
clawsweeper
·
2026-05-19
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -46,6 +46,7 @@ Docs: https://docs.openclaw.ai
|
46 | 46 | ### Fixes |
47 | 47 | |
48 | 48 | - Agents/image generation: allow distinct `image_generate` prompts to start separate session-backed background tasks while same-prompt retries still return the active task status. (#83614) Thanks @Elarwei001. |
| 49 | +- Control UI: stop the chat reading indicator from sticking after an assistant response finishes. (#83515) Thanks @njuboy11. |
49 | 50 | - Skills: reject empty or whitespace-only skill names and descriptions during quick validation. (#27061) |
50 | 51 | - Sessions: skip trailing custom transcript entries when checking tail assistant replies so embedded CLI gap-fill does not duplicate canonical assistant output. (#83635) Thanks @yaoyi1222. |
51 | 52 | - Memory Wiki: keep `wiki_lint` tool output path-safe by reporting vault-internal lint reports as relative paths in tool text and details while preserving absolute report paths for CLI/file callers. (#83439) Thanks @LLagoon3. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -489,14 +489,37 @@ describe("chat loading skeleton", () => {
|
489 | 489 | expect(container.querySelector(".agent-chat__welcome")).toBeNull(); |
490 | 490 | }); |
491 | 491 | |
492 | | -it("shows the reading indicator instead of the skeleton while an active run has no stream yet", () => { |
| 492 | +it("shows the loading skeleton for an active run with no stream", () => { |
493 | 493 | const container = renderChatView({ canAbort: true, loading: true }); |
494 | 494 | |
495 | | -expect(container.querySelector(".chat-loading-skeleton")).toBeNull(); |
496 | | -expect(container.querySelectorAll(".chat-reading-indicator")).toHaveLength(1); |
| 495 | +expect(container.querySelector(".chat-loading-skeleton")).not.toBeNull(); |
| 496 | +expect(container.querySelectorAll(".chat-reading-indicator")).toHaveLength(0); |
497 | 497 | expect(container.querySelector(".agent-chat__welcome")).toBeNull(); |
498 | 498 | }); |
499 | 499 | |
| 500 | +it("shows the reading indicator when an active run has an empty stream", () => { |
| 501 | +const container = renderChatView({ canAbort: true, stream: "" }); |
| 502 | + |
| 503 | +expect(container.querySelector(".chat-reading-indicator")).not.toBeNull(); |
| 504 | +}); |
| 505 | + |
| 506 | +it("does not keep the reading indicator after an assistant response has rendered", () => { |
| 507 | +const container = renderChatView({ |
| 508 | +canAbort: true, |
| 509 | +messages: [ |
| 510 | +{ |
| 511 | +role: "assistant", |
| 512 | +content: "Finished answer", |
| 513 | +timestamp: 1, |
| 514 | +}, |
| 515 | +], |
| 516 | +stream: null, |
| 517 | +}); |
| 518 | + |
| 519 | +expect(container.querySelector(".chat-reading-indicator")).toBeNull(); |
| 520 | +expect(container.querySelector(".chat-group")?.textContent?.trim()).toBe("Finished answer"); |
| 521 | +}); |
| 522 | + |
500 | 523 | it("keeps existing messages visible without the skeleton during a background reload", () => { |
501 | 524 | const container = renderChatView({ |
502 | 525 | loading: true, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1003,7 +1003,7 @@ export function renderChat(props: ChatProps) {
|
1003 | 1003 | const requestUpdate = props.onRequestUpdate ?? (() => {}); |
1004 | 1004 | const splitRatio = props.splitRatio ?? 0.6; |
1005 | 1005 | const sidebarOpen = Boolean(props.sidebarOpen && props.onCloseSidebar); |
1006 | | -const displayStream = props.stream ?? (canAbort ? "" : null); |
| 1006 | +const displayStream = props.stream ?? null; |
1007 | 1007 | |
1008 | 1008 | const handleCodeBlockCopy = (e: Event) => { |
1009 | 1009 | const btn = (e.target as HTMLElement).closest(".code-block-copy"); |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。