diff --git a/apps/presentation/dashboard/src/features/personal-workspace/context-drawer.tsx b/apps/presentation/dashboard/src/features/personal-workspace/context-drawer.tsx index cda1bd0145..06ba3826b1 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/context-drawer.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/context-drawer.tsx @@ -282,6 +282,9 @@ export function ContextDrawer({ agents, attentionHistory = [], onSelectAttention const returnFocus = returnFocusRef.current; onClose(); window.requestAnimationFrame(() => { + const activeElement = document.activeElement; + if (activeElement instanceof HTMLElement && activeElement !== document.body + && !drawerRef.current?.contains(activeElement)) return; if (returnFocus && returnFocus !== document.body) { returnFocus.focus(); if (document.activeElement === returnFocus) return; diff --git a/examples/personal-workspace-browser/goal-work-map.mjs b/examples/personal-workspace-browser/goal-work-map.mjs index bd98e10133..c597b4a2bb 100644 --- a/examples/personal-workspace-browser/goal-work-map.mjs +++ b/examples/personal-workspace-browser/goal-work-map.mjs @@ -4,14 +4,14 @@ import { spawn } from "node:child_process"; import { mkdtemp, rename, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { createInterface } from "node:readline"; -import { resolveTestPython } from "../../scripts/test-python.mjs"; +import { testPythonCommand } from "../../scripts/test-python.mjs"; import { outputDir, repoRoot } from "./fixture.mjs"; import { deliveryReadFixture } from "./showcase-workspace.mjs"; import { fetchWorkspaceBackend, openWorkspacePage } from "./scenario-context.mjs"; async function requestAuthority(text) { const root = await mkdtemp(resolve(tmpdir(), "loopx-map-request-")); - const child = spawn(resolveTestPython(), ["-u", "-c", ` + const python = testPythonCommand(` from pathlib import Path import json, os, signal, sys, tempfile root = Path(sys.argv[1]); tempfile.tempdir = str(root) @@ -41,7 +41,8 @@ finally: server.server_close() assert read_canonical_todos_if_promoted(runtime_root=runtime, goal_id="product-release") == before restart_effect_runtime() -`, root, text], { cwd: repoRoot, stdio: ["ignore", "pipe", "pipe"] }); +`); + const child = spawn(python.command, [...python.args, root, text], { cwd: repoRoot, stdio: ["ignore", "pipe", "pipe"] }); const lines = createInterface({ input: child.stdout }); let diagnostic = ""; child.stderr.on("data", chunk => { diagnostic = (diagnostic + chunk).slice(-3000); }); @@ -203,7 +204,15 @@ export const goalWorkMapScenario = { await rename(hiddenRegistry, authority.registry); await drawer.getByRole("button", { name: "重试读取完整要求", exact: true }).click(); await drawer.getByText(finalRequirement, { exact: true }).waitFor(); - await page.getByRole("button", { name: /关闭详情/ }).click(); + await page.getByRole("button", { name: /关闭详情/ }).evaluate(button => { + button.click(); + document.querySelector(".goal-overview-evidence > summary")?.focus(); + }); + await page.evaluate(() => new Promise(resolve => requestAnimationFrame(resolve))); + assert.equal(await page.locator(".goal-overview-evidence > summary").evaluate( + summary => document.activeElement === summary), true, + "Closing Task details must preserve focus explicitly moved to another control"); + await page.screenshot({ path: resolve(outputDir, "goal-map-focus-return-desktop.png"), animations: "disabled" }); limits = { omitted_node_count: 3, topology_complete: false }; const evidence = page.locator(".goal-overview-evidence");