mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-31 02:18:08 +00:00
refactor(ui): unify working indicator status rendering (#133713)
This commit is contained in:
parent
9f6d8c5a60
commit
e8d767bd2e
2 changed files with 32 additions and 39 deletions
|
|
@ -1788,6 +1788,7 @@ describe("grouped chat rendering", () => {
|
|||
);
|
||||
expect(container.querySelector(".chat-working-indicator__elapsed")).not.toBeNull();
|
||||
expect(container.querySelector(".chat-working-indicator__status > .sr-only")).toBeNull();
|
||||
expect(container.querySelector("openclaw-working-phrase")).toBeNull();
|
||||
});
|
||||
|
||||
it("formats terminal recap durations with full localized units", () => {
|
||||
|
|
@ -1815,19 +1816,23 @@ describe("grouped chat rendering", () => {
|
|||
).toBe("Done in 30 seconds · 2,400 output tokens");
|
||||
});
|
||||
|
||||
it("shows live output usage beside elapsed time", () => {
|
||||
it.each([
|
||||
[0, "0 output tokens"],
|
||||
[1, "1 output token"],
|
||||
[5_500, "5,500 output tokens"],
|
||||
])("shows %i output tokens beside elapsed time", (outputTokens, label) => {
|
||||
const container = document.createElement("div");
|
||||
|
||||
render(
|
||||
renderStreamGroup([{ kind: "reading-indicator", key: "reading", startedAt: 1_000 }], {
|
||||
runOutputTokens: 5_500,
|
||||
runOutputTokens: outputTokens,
|
||||
}),
|
||||
container,
|
||||
);
|
||||
|
||||
expect(container.querySelector(".chat-working-indicator__elapsed")).not.toBeNull();
|
||||
expect(container.querySelector(".chat-working-indicator__tokens")?.textContent?.trim()).toBe(
|
||||
"5,500 output tokens",
|
||||
label,
|
||||
);
|
||||
// Known usage replaces the pre-usage working phrase.
|
||||
expect(container.querySelector("openclaw-working-phrase")).toBeNull();
|
||||
|
|
|
|||
|
|
@ -46,16 +46,6 @@ function outputTokensLabel(outputTokens: number): string {
|
|||
: t("chat.turnRecap.tokens", { count: outputTokens.toLocaleString(i18n.getLocale()) });
|
||||
}
|
||||
|
||||
function renderLiveOutputTokens(outputTokens: number | null | undefined) {
|
||||
if (outputTokens === null || outputTokens === undefined) {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<span aria-hidden="true">·</span>
|
||||
<span class="chat-working-indicator__tokens">${outputTokensLabel(outputTokens)}</span>
|
||||
`;
|
||||
}
|
||||
|
||||
export function renderChatWorkingIndicator(
|
||||
part: Extract<ChatItem, { kind: "reading-indicator" }>,
|
||||
options: {
|
||||
|
|
@ -67,9 +57,13 @@ export function renderChatWorkingIndicator(
|
|||
) {
|
||||
const waitingApproval = options.waitingApproval === true;
|
||||
const continuation = options.presentation === "continuation";
|
||||
const statusLabel = waitingApproval
|
||||
? t("chat.waitingForApproval")
|
||||
: options.startupLabel || t("common.working");
|
||||
const working = !waitingApproval && !options.startupLabel;
|
||||
// Providers report exact usage at response boundaries, not per text delta.
|
||||
// Keep the latest count visible while the run continues through tools.
|
||||
const hasTokens = options.outputTokens !== null && options.outputTokens !== undefined;
|
||||
const outputTokens = options.outputTokens;
|
||||
// The animated claw stays decorative; the text status exposes progress without
|
||||
// announcing every elapsed-time tick to screen readers.
|
||||
return html`
|
||||
|
|
@ -91,35 +85,29 @@ export function renderChatWorkingIndicator(
|
|||
</div>
|
||||
`}
|
||||
<span class="chat-working-indicator__status">
|
||||
<span class=${working && !continuation ? "sr-only" : ""}>${statusLabel}</span>
|
||||
${waitingApproval
|
||||
? html`<span>${t("chat.waitingForApproval")}</span>${renderLiveOutputTokens(
|
||||
options.outputTokens,
|
||||
)}`
|
||||
: options.startupLabel
|
||||
? nothing
|
||||
: html`
|
||||
<openclaw-elapsed-time
|
||||
class="chat-working-indicator__elapsed"
|
||||
.startMs=${part.startedAt}
|
||||
></openclaw-elapsed-time>
|
||||
`}
|
||||
${outputTokens !== null && outputTokens !== undefined
|
||||
? html`
|
||||
<span aria-hidden="true">·</span>
|
||||
<span class="chat-working-indicator__tokens">${outputTokensLabel(outputTokens)}</span>
|
||||
`
|
||||
: working
|
||||
? html`
|
||||
<span>${options.startupLabel}</span>
|
||||
<openclaw-elapsed-time
|
||||
class="chat-working-indicator__elapsed"
|
||||
<openclaw-working-phrase
|
||||
aria-hidden="true"
|
||||
.startMs=${part.startedAt}
|
||||
></openclaw-elapsed-time>
|
||||
${renderLiveOutputTokens(options.outputTokens)}
|
||||
.seed=${part.key}
|
||||
></openclaw-working-phrase>
|
||||
`
|
||||
: html`
|
||||
<span class=${continuation ? "" : "sr-only"}>${t("common.working")}</span>
|
||||
<openclaw-elapsed-time
|
||||
class="chat-working-indicator__elapsed"
|
||||
.startMs=${part.startedAt}
|
||||
></openclaw-elapsed-time>
|
||||
${hasTokens
|
||||
? renderLiveOutputTokens(options.outputTokens)
|
||||
: html`
|
||||
<openclaw-working-phrase
|
||||
aria-hidden="true"
|
||||
.startMs=${part.startedAt}
|
||||
.seed=${part.key}
|
||||
></openclaw-working-phrase>
|
||||
`}
|
||||
`}
|
||||
: nothing}
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue