Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ export function GoalResearchHistory({goalId, originalGoalId = goalId, preferHist
{selectedMembers?.length ? <div className="research-history-detail" ref={detail} role="region" aria-label={selectedGroup ? (zh ? "按日期收纳的未关联问题" : "Unlinked questions by date") : (zh ? "相邻研究项的全部记录" : "All records for nearby research items")} tabIndex={-1} onKeyDown={event => {if (event.key === "Escape") {event.stopPropagation(); closeReader();}}}>
<div className="research-reader-content">
<button type="button" className="research-reader-back" onClick={closeReader}><ArrowLeft size={14} aria-hidden/>{copy.all}</button>
<h3>{selectedGroup ? `${selectedGroup.day || copy.unknown} · ${zh ? "未关联问题" : "Unlinked questions"}` : (zh ? `相邻研究项 · ${selectedMembers.length}` : `Nearby research items · ${selectedMembers.length}`)}</h3>
<h3>{selectedGroup ? `${selectedGroup.day ? `${selectedGroup.day} UTC` : copy.unknown} · ${zh ? "未关联问题" : "Unlinked questions"}` : (zh ? `相邻研究项 · ${selectedMembers.length}` : `Nearby research items · ${selectedMembers.length}`)}</h3>
{displayControl}
<ol className="research-question-index">{selectedMembers.map(node => <li key={node.id} data-research-node={node.id}>
<button type="button" onClick={() => {collectionOpener.current = opener.current; chooseQuestion(node, {nodes: selection.nodes, day: selection.day});}}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export function GoalResearchTimeline({timeline, zh, selectedIds, selectedEventId
<div className="research-row-label"><strong>{copy.singles} · {groupedIds.size}</strong></div>
<div className="research-unlinked-days">{dayGroups.map(group => <button type="button" key={group.day} data-research-day={group.day} aria-pressed={selectedDay === group.day}
className={`${selectedDay === group.day ? "is-selected" : ""}${group.nodes.some(node => inPhase(timeline.nodes.get(node.id)!.first)) ? "" : " is-dimmed"}`}
onClick={event => onGroupSelect(group.day, event.currentTarget)}><time>{group.day || (zh ? "时间未知" : "Unknown time")}</time><strong>{group.nodes.length} {group.nodes.length === 1 ? copy.question : copy.questions}</strong></button>)}</div>
onClick={event => onGroupSelect(group.day, event.currentTarget)}><time>{group.day ? `${group.day} UTC` : (zh ? "时间未知" : "Unknown time")}</time><strong>{group.nodes.length} {group.nodes.length === 1 ? copy.question : copy.questions}</strong></button>)}</div>
</> : null}
{swarm.length ? <>
<div className="research-row-label"><strong>{copy.singles} · {swarm.length}</strong></div>
Expand Down
21 changes: 18 additions & 3 deletions examples/personal-workspace-browser/research-route-reading.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ for index in range(24):
node=f'group-question-{index}'
title=f'{index+1}. 相同预算下的候选比较:保留负结果、失败和未知成本;哪些证据能支持下一步?'
events.append(build_explore_node_event(goal_id=goal,node_id=node,title=title,node_kind='question',
recorded_at=f'2026-01-04T00:00:{index:02}Z'))
recorded_at=f'2026-01-04T{23 if index==23 else 0:02}:00:{index:02}Z'))
for version,status in enumerate(('refuted','tentative')):
events.append(build_explore_finding_event(goal_id=goal,node_id=node,finding_id=f'group-finding-{index}-{version}',
title=f'候选 {index+1} · 记录 {version+1}',summary=f'原始观察 {index+1}/{version+1}:局部指标不同,完整收益和费用仍未知。',
status=status,recorded_at=f'2026-01-04T0{version+1}:00:{index:02}Z'))
status=status,recorded_at=f'2026-01-0{5 if index==23 else 4}T0{version+1}:00:{index:02}Z'))
Path(sys.argv[1]).write_text(json.dumps({'goal_id':goal,'display_name':'合成研究 · 路线阅读','events':events},ensure_ascii=False))
`, path], {cwd: repoRoot});
}
Expand Down Expand Up @@ -71,7 +71,7 @@ export const researchRouteReadingScenario = {
writeRouteReadingFixture(fixture);
const capture = JSON.parse(await readFile(fixture));
owner = await startHistoryOwner(fixture);
page = await browser.newPage({viewport: {width: 1440, height: 900}, hasTouch: true});
page = await browser.newPage({viewport: {width: 1440, height: 900}, hasTouch: true, timezoneId: "Asia/Shanghai"});
if (collectCoverage) await page.coverage.startJSCoverage({resetOnNavigation: false});
const url = new URL("/chat/?goalId=synthetic-route-reading&view=research&statusUrl=%2Fstatus.json", owner.base).href;
let state = "deep", analysisWrites = 0, releaseLoading;
Expand Down Expand Up @@ -253,9 +253,14 @@ export const researchRouteReadingScenario = {
await page.goto(url);
const day = history.locator('[data-research-day="2026-01-04"]');
await day.waitFor();
const dayText = await day.innerText();
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").waitFor();
await page.screenshot({path: resolve(outputDir, `research-day-group-${locale}-${width}.png`), animations: "disabled"});
assert.match(dayText, /2026-01-04 UTC/, "UTC grouping stays explicit beside the local record range");
assert.match(await reader.locator("h3").innerText(), /2026-01-04 UTC/, "Opening a date group preserves its time basis");
await reader.locator(".research-question-index button").nth(3).click();
await page.keyboard.press("Escape");
await reader.locator(".research-question-index").waitFor();
Expand Down Expand Up @@ -307,9 +312,19 @@ export const researchRouteReadingScenario = {
await page.keyboard.press("Escape");
await page.waitForFunction(() => document.activeElement?.closest("[data-research-node]")?.getAttribute("data-research-node") === "group-question-4");
await page.reload(); await reader.locator(".research-question-index").waitFor();
assert.match(await reader.locator("h3").innerText(), /2026-01-04 UTC/, "Reload preserves the date group's UTC basis");
await page.keyboard.press("Escape");
await page.waitForFunction(() => document.activeElement?.getAttribute("data-research-day") === "2026-01-04");
}
await history.getByRole("button", {name: "Graph", exact: true}).click();
const graphDay = history.locator('[data-research-day="2026-01-04"]');
assert.match(await graphDay.innerText(), /2026-01-04 UTC/);
await graphDay.click();
assert.match(await reader.locator("h3").innerText(), /2026-01-04 UTC/);
assert.equal(await reader.locator(".research-question-index li").count(), 24,
"The late UTC record remains in its UTC group across local midnight");
await page.keyboard.press("Escape");
await history.getByRole("button", {name: "Timeline", exact: true}).click();
// A saved multi-node selection retains the same local collection. A
// forged parent cannot borrow unrelated questions for its navigation.
const clustered = new URL(url);
Expand Down
Loading