mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(ui): usage copy actions silently hide clipboard failures (#129562)
* fix(ui): show usage copy success and failure * test(ui): decouple usage copy proof from CSS classes
This commit is contained in:
committed by
GitHub
parent
b13993af15
commit
d8ff371780
@@ -82,6 +82,7 @@ function renderDailyChart(
|
||||
afterEach(() => {
|
||||
document.body.replaceChildren();
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
function directText(element: Element | null | undefined): string | undefined {
|
||||
@@ -557,7 +558,16 @@ describe("renderCostWindowComparison", () => {
|
||||
describe("renderSessionsCard", () => {
|
||||
const noop = () => {};
|
||||
|
||||
it("renders named native session toggles while preserving shift selection and separate copy", () => {
|
||||
it.each([
|
||||
{ copied: true, feedback: "Copied!" },
|
||||
{ copied: false, feedback: "Copy failed" },
|
||||
])("keeps session selection separate while showing $feedback", async ({ copied, feedback }) => {
|
||||
const writeText = vi.fn(async () => {
|
||||
if (!copied) {
|
||||
throw new Error("Clipboard access denied");
|
||||
}
|
||||
});
|
||||
vi.stubGlobal("navigator", { clipboard: { writeText } });
|
||||
const container = document.createElement("div");
|
||||
document.body.append(container);
|
||||
const onSelectSession = vi.fn<(key: string, shiftKey: boolean) => void>();
|
||||
@@ -616,7 +626,15 @@ describe("renderSessionsCard", () => {
|
||||
sessions.map((s) => s.key),
|
||||
);
|
||||
|
||||
rows[0]?.querySelector<HTMLButtonElement>(".session-bar-actions button")?.click();
|
||||
const copyButton = rows[0]?.querySelector<HTMLButtonElement>(".session-bar-actions button");
|
||||
copyButton?.click();
|
||||
await vi.waitFor(() => {
|
||||
expect(copyButton?.textContent?.trim()).toBe(feedback);
|
||||
expect(copyButton?.getAttribute("aria-label")).toBe(feedback);
|
||||
});
|
||||
expect(writeText).toHaveBeenCalledWith("Selected thread");
|
||||
expect(copyButton?.dataset[copied ? "copied" : "error"]).toBe("1");
|
||||
expect(copyButton?.dataset[copied ? "error" : "copied"]).toBeUndefined();
|
||||
expect(onSelectSession).toHaveBeenCalledOnce();
|
||||
rows[0]?.querySelector<HTMLElement>(".session-bar-value")?.click();
|
||||
expect(onSelectSession).toHaveBeenCalledWith(
|
||||
|
||||
@@ -4,10 +4,10 @@ import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
|
||||
// Control UI view renders usage render overview screen content.
|
||||
import { html, nothing } from "lit";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
import { handleCopyButton } from "../../components/copy-button.ts";
|
||||
import { renderSettingsSection } from "../../components/settings-ui.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import "../../components/tooltip.ts";
|
||||
import { copyToClipboard } from "../../lib/clipboard.ts";
|
||||
import { formatDurationCompact } from "../../lib/format.ts";
|
||||
import {
|
||||
buildUsageCostWindows,
|
||||
@@ -926,10 +926,10 @@ function renderSessionsCard(
|
||||
class="btn btn--sm btn--ghost"
|
||||
@click=${(e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
void copyToClipboard(formatSessionListLabel(s));
|
||||
void handleCopyButton(e, formatSessionListLabel(s), t("usage.sessions.copy"));
|
||||
}}
|
||||
>
|
||||
${t("usage.sessions.copy")}
|
||||
<span data-copy-label>${t("usage.sessions.copy")}</span>
|
||||
</button>
|
||||
<div class="session-bar-value">
|
||||
${isTokenMode ? formatUsageTokens(value) : formatAnalysisCost(value)}
|
||||
|
||||
Reference in New Issue
Block a user