diff --git a/desktop/frontend-next/src/ui/WorkbenchPanel.test.tsx b/desktop/frontend-next/src/ui/WorkbenchPanel.test.tsx index df80ddfeda..306ca1c1c9 100644 --- a/desktop/frontend-next/src/ui/WorkbenchPanel.test.tsx +++ b/desktop/frontend-next/src/ui/WorkbenchPanel.test.tsx @@ -10,7 +10,7 @@ import { SsePort } from "../port/sse"; import { WorkbenchPanel } from "./WorkbenchPanel"; import { unseenPageOpenings } from "./browser_open"; -afterEach(cleanup); +afterEach(() => { cleanup(); localStorage.clear(); }); describe("WorkbenchPanel", () => { it("opens workspace files as tabs and saves what was typed in the editor", async () => { @@ -614,7 +614,10 @@ describe("WorkbenchPanel", () => { // From the keyboard: the menu key reports no pointer, and the item takes focus. fireEvent.contextMenu(screen.getByRole("button", { name: "README.md" }), { clientX: 0, clientY: 0 }); - expect(document.activeElement).toBe(screen.getByRole("menuitem", { name: "在系统文件管理器中显示" })); + expect(document.activeElement).toBe(screen.getByRole("menuitem", { name: "复制引用" })); + const target = screen.getByRole("menuitem", { name: "在系统文件管理器中显示" }); + for (let i = 0; i < screen.getAllByRole("menuitem").length && document.activeElement !== target; i++) await user.keyboard("{ArrowDown}"); + expect(document.activeElement).toBe(target); await user.keyboard("{Enter}"); expect(reveal).toHaveBeenLastCalledWith("README.md"); }); diff --git a/desktop/frontend-next/src/ui/Workspaces.tsx b/desktop/frontend-next/src/ui/Workspaces.tsx index d3f2977ba7..b3b0ac5064 100644 --- a/desktop/frontend-next/src/ui/Workspaces.tsx +++ b/desktop/frontend-next/src/ui/Workspaces.tsx @@ -101,6 +101,7 @@ function WorkspacesView({ hub, tree, treeRead, answered = null, runtimes, active if (e instanceof HttpError && e.reason?.code === "workspace.folder_missing") { setGone(ws.root); setConfirm(ws.root); } else onError(e); }; const [selection, setSelection] = useState | null>(null); + const selectFrom = useRef(""); const [expanded, setExpanded] = useState>(new Set()); // The row a Delete key asked about. The question replaces that row, so focus // goes back to it once the question is gone, or a keyboard is left nowhere. @@ -369,7 +370,7 @@ function WorkspacesView({ hub, tree, treeRead, answered = null, runtimes, active <> {moveTo.dialog} treeKeys.ref.current?.parentElement?.previousElementSibling?.querySelector('[data-action="machine.menu"]')?.focus()} + onExit={() => document.querySelector(`[data-action="workspace.menu"][data-target="${CSS.escape(selectFrom.current)}"]`)?.focus()} onBusy={(pending) => { setBusy(pending ? "batch" : ""); if (pending) { setSessionMenu(""); setEditing(""); setConfirm(""); } }} onClose={onClose} onArchive={onArchive} liveIds={liveIds} reload={reload} onError={onError} /> @@ -491,7 +492,7 @@ function WorkspacesView({ hub, tree, treeRead, answered = null, runtimes, active {ws.remembered && w.remembered).findIndex((w) => w.root === ws.root)} total={tree.filter((w) => w.remembered).length} hub={hub} reload={reload} dismiss={dismissMenu} onError={onError} />} - 0} selecting={selection !== null} onSelect={() => setSelection(new Set())} dismiss={dismissMenu} /> + 0} selecting={selection !== null} onSelect={() => { selectFrom.current = ws.root; setSelection(new Set()); }} dismiss={dismissMenu} />