mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(ui): show session diff path copy feedback (#129999)
This commit is contained in:
committed by
GitHub
parent
fed350dbc4
commit
565fd93544
@@ -55,7 +55,6 @@ export type SessionDiffMenuDraft = WithoutMenuAnchor<SessionDiffMenuData>;
|
||||
|
||||
export type SessionDiffMenuAction =
|
||||
| { kind: "collapse-all" }
|
||||
| { kind: "copy-path"; path: string }
|
||||
| { kind: "expand-all" }
|
||||
| { kind: "open-editor"; editor: EditorId; path: string }
|
||||
| { kind: "open-file"; path: string }
|
||||
@@ -99,10 +98,6 @@ class SessionDiffMenu extends OpenClawLightDomElement {
|
||||
"scope:uncommitted": { kind: "scope", value: { scope: "uncommitted" } },
|
||||
};
|
||||
const fileMenu = this.menu?.kind === "file" ? this.menu : null;
|
||||
if (fileMenu && value === "copy-path") {
|
||||
this.run({ kind: "copy-path", path: fileMenu.path });
|
||||
return;
|
||||
}
|
||||
if (fileMenu && value === "open-file") {
|
||||
this.run({ kind: "open-file", path: fileMenu.path });
|
||||
return;
|
||||
@@ -142,10 +137,7 @@ class SessionDiffMenu extends OpenClawLightDomElement {
|
||||
|
||||
private renderFileMenu(menu: Extract<SessionDiffMenuData, { kind: "file" }>) {
|
||||
return html`
|
||||
<wa-dropdown-item class="session-menu__item" value="copy-path">
|
||||
<span slot="icon" class="session-menu__icon" aria-hidden="true">${icons.copy}</span>
|
||||
<span class="session-menu__text">${t("chat.sessionDiff.copyPath")}</span>
|
||||
</wa-dropdown-item>
|
||||
${this.renderCopyRow(menu.path, t("chat.sessionDiff.copyPath"))}
|
||||
<wa-dropdown-item class="session-menu__item" value="open-file" ?disabled=${!menu.canOpenFile}>
|
||||
<span slot="icon" class="session-menu__icon" aria-hidden="true">${icons.fileText}</span>
|
||||
<span class="session-menu__text">${t("chat.sessionDiff.openFile")}</span>
|
||||
|
||||
@@ -76,9 +76,51 @@ afterEach(() => {
|
||||
document.body.replaceChildren();
|
||||
clearNativeGatewayTestState();
|
||||
vi.restoreAllMocks();
|
||||
Reflect.deleteProperty(navigator, "clipboard");
|
||||
});
|
||||
|
||||
describe("SessionDiffPanel", () => {
|
||||
it.each([
|
||||
{ surface: "file", failed: false, feedback: "Copied!" },
|
||||
{ surface: "file", failed: true, feedback: "Copy failed" },
|
||||
{ surface: "sync", failed: false, feedback: "Copied!" },
|
||||
{ surface: "sync", failed: true, feedback: "Copy failed" },
|
||||
])(
|
||||
"keeps $surface path copy feedback visible: $feedback",
|
||||
async ({ surface, failed, feedback }) => {
|
||||
const writeText = failed
|
||||
? vi.fn().mockRejectedValue(new DOMException("Clipboard access denied", "NotAllowedError"))
|
||||
: vi.fn().mockResolvedValue(undefined);
|
||||
Object.defineProperty(navigator, "clipboard", {
|
||||
configurable: true,
|
||||
value: { writeText },
|
||||
});
|
||||
setNativeGatewayTestState(null);
|
||||
const panel = document.createElement("openclaw-session-diff") as SessionDiffElement;
|
||||
panel.loader = vi.fn(async () => ({ ...fileResult(SNAPSHOT_PATCH), root: "/workspace" }));
|
||||
document.body.append(panel);
|
||||
|
||||
const triggerSelector =
|
||||
surface === "file" ? ".session-diff__file-menu" : ".session-diff__toolbar-button";
|
||||
await vi.waitFor(() => expect(panel.querySelector(triggerSelector)).not.toBeNull());
|
||||
panel.querySelector<HTMLButtonElement>(triggerSelector)?.click();
|
||||
await panel.updateComplete;
|
||||
|
||||
const menu = panel.querySelector("openclaw-session-diff-menu");
|
||||
expect(menu).not.toBeNull();
|
||||
const label = surface === "file" ? "Copy Path" : "Checkout path";
|
||||
const button = menu?.querySelector<HTMLButtonElement>(`button[aria-label="${label}"]`);
|
||||
expect(button).toBeInstanceOf(HTMLButtonElement);
|
||||
|
||||
button?.click();
|
||||
await vi.waitFor(() => expect(button?.getAttribute("aria-label")).toBe(feedback));
|
||||
|
||||
expect(writeText).toHaveBeenCalledWith(surface === "file" ? "example.txt" : "/workspace");
|
||||
expect(button?.dataset[failed ? "error" : "copied"]).toBe("1");
|
||||
expect(panel.querySelector("openclaw-session-diff-menu")).toBe(menu);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ name: "plain browser", nativeGateway: null, offered: false },
|
||||
{ name: "native local gateway", nativeGateway: "local", offered: true },
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
} from "../../../lib/chat/session-diff-split.ts";
|
||||
import { parseSessionDiffPatch, type ParsedFilePatch } from "../../../lib/chat/session-diff.ts";
|
||||
import type { DiffLine } from "../../../lib/chat/tool-call-diff.ts";
|
||||
import { copyToClipboard } from "../../../lib/clipboard.ts";
|
||||
import { openEditor } from "../../../lib/editor-links.ts";
|
||||
import { formatUiError } from "../../../lib/format-error.ts";
|
||||
import { OpenClawLightDomElement } from "../../../lit/openclaw-element.ts";
|
||||
@@ -263,9 +262,6 @@ class SessionDiffPanel extends OpenClawLightDomElement {
|
||||
case "scope":
|
||||
this.scope = action.value;
|
||||
return;
|
||||
case "copy-path":
|
||||
void copyToClipboard(action.path);
|
||||
return;
|
||||
case "open-file":
|
||||
this.openFile?.(action.path);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user