From 2a04925aecdc3075194cc18113cea5ced09bf9f6 Mon Sep 17 00:00:00 2001
From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Date: Sun, 8 Nov 2026 05:37:11 +0800
Subject: [PATCH] Restore focus after reading a research group
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
---
.../personal-workspace/goal-research-history.tsx | 10 ++++++----
.../personal-workspace/goal-research-timeline.tsx | 8 ++++----
.../research-route-reading.mjs | 12 +++++++++++-
3 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx
index 7d15617961..5960bf4e6c 100644
--- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx
+++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.tsx
@@ -338,9 +338,9 @@ export function GoalResearchHistory({goalId, originalGoalId = goalId, preferHist
const clusterY = layout.length ? Math.max(...layout.map(item => item.y + 124)) + 24 : 24;
const width = Math.max(600, grouped.groups.length ? 944 : 0, ...layout.map(item => item.x + 230));
const height = Math.max(230, ...layout.map(item => item.y + 124), grouped.groups.length ? clusterY + Math.ceil(grouped.groups.length / 4) * 124 : 0);
- const select = (next: Selection, focus = true) => {
+ const select = (next: Selection, focus = true, openingControl?: HTMLButtonElement) => {
if (focus && (next.nodes.length || next.day !== null)) {
- opener.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
+ opener.current = openingControl ?? (document.activeElement instanceof HTMLElement ? document.activeElement : null);
focusPending.current = true;
}
next = {...next, question: next.question ?? !next.finding,
@@ -426,7 +426,9 @@ export function GoalResearchHistory({goalId, originalGoalId = goalId, preferHist
: null;
const historyView = !value ? null : lens === "timeline" && timeline ?
- select({nodes: [], day})} phase={phase} onPhase={next => chooseView(lens, next)} onSelect={(id, finding) => choose(id, true, finding)} onSelectMany={nodes => select({nodes, day: null})} timeLabel={fullTime} dayLabel={dayTime}/>
+ select({nodes: [], day}, true, button)} phase={phase} onPhase={next => chooseView(lens, next)}
+ onSelect={(id, finding) => choose(id, true, finding)} onSelectMany={(nodes, button) => select({nodes, day: null}, true, button)} timeLabel={fullTime} dayLabel={dayTime}/>
:
> : null}
{swarm.length ? <>
{copy.singles} · {swarm.length}
diff --git a/examples/personal-workspace-browser/research-route-reading.mjs b/examples/personal-workspace-browser/research-route-reading.mjs
index 69af7facb6..f7db2ed722 100644
--- a/examples/personal-workspace-browser/research-route-reading.mjs
+++ b/examples/personal-workspace-browser/research-route-reading.mjs
@@ -251,7 +251,17 @@ export const researchRouteReadingScenario = {
await page.emulateMedia({reducedMotion: "reduce"});
await page.evaluate(value => localStorage.setItem("loopx-pw-locale", value), locale);
await page.goto(url);
- await history.locator('[data-research-day="2026-01-04"]').click();
+ const day = history.locator('[data-research-day="2026-01-04"]');
+ await day.waitFor();
+ await history.locator(".research-history-canvas").focus();
+ // WebKit can activate the button while leaving focus on the canvas.
+ await day.evaluate(button => button.click());
+ await reader.locator(".research-question-index button").nth(3).click();
+ await page.keyboard.press("Escape");
+ await reader.locator(".research-question-index").waitFor();
+ await page.keyboard.press("Escape");
+ await page.waitForFunction(() => document.activeElement?.getAttribute("data-research-day") === "2026-01-04");
+ await day.click();
assert.equal(await reader.locator(".research-question-index li").count(), 24);
await reader.locator(".research-question-index button").nth(3).click();
const questions = reader.getByRole("combobox", {name: zh ? "选择同组研究问题" : "Choose a question in this group"});