From 86dbd917a51741899ecb0c74b81f90e0f838f92b Mon Sep 17 00:00:00 2001
From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Date: Tue, 27 Oct 2026 02:55:19 +0800
Subject: [PATCH] fix(research): search displayed translations and export
original matches
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
---
.../goal-research-history.tsx | 1 +
.../research-record-browser.tsx | 12 +++---
.../research-record-export.test.mjs | 10 +++++
.../research-record-export.ts | 8 ++--
.../research-record-search.test.mjs | 19 +++++++++
.../research-record-search.ts | 19 ++++++++-
.../research-search/after-body-390.png | Bin 0 -> 70854 bytes
.../research-search/after-search-1440.png | Bin 0 -> 99914 bytes
.../research-search/after-search-390.png | Bin 0 -> 59198 bytes
.../research-search/before-search-1440.png | Bin 0 -> 98648 bytes
.../research-search/first-1440.png | Bin 0 -> 99394 bytes
.../research-search/first-390.png | Bin 0 -> 56626 bytes
.../research-display-language.mjs | 36 ++++++++++++++++++
13 files changed, 94 insertions(+), 11 deletions(-)
create mode 100644 apps/presentation/dashboard/visual-evidence/research-search/after-body-390.png
create mode 100644 apps/presentation/dashboard/visual-evidence/research-search/after-search-1440.png
create mode 100644 apps/presentation/dashboard/visual-evidence/research-search/after-search-390.png
create mode 100644 apps/presentation/dashboard/visual-evidence/research-search/before-search-1440.png
create mode 100644 apps/presentation/dashboard/visual-evidence/research-search/first-1440.png
create mode 100644 apps/presentation/dashboard/visual-evidence/research-search/first-390.png
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 4552545bf7..30c93d4964 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
@@ -540,6 +540,7 @@ export function GoalResearchHistory({goalId, active, zh, refreshRevision = 0, re
{value?.events.length ? setRecordsOpen(event.currentTarget.open)}>{zh ? "全部已读记录" : "All loaded records"} · {value.events.length}
{recordsOpen ? : null}
: null}
diff --git a/apps/presentation/dashboard/src/features/personal-workspace/research-record-browser.tsx b/apps/presentation/dashboard/src/features/personal-workspace/research-record-browser.tsx
index 03bc5f7090..70b3001352 100644
--- a/apps/presentation/dashboard/src/features/personal-workspace/research-record-browser.tsx
+++ b/apps/presentation/dashboard/src/features/personal-workspace/research-record-browser.tsx
@@ -3,14 +3,15 @@ import {CircleHelp, TriangleAlert} from "lucide-react";
import {ContextHelp} from "./context-help";
import {useMemo, useState, type ReactNode} from "react";
import type {ExploreHistoryEvent} from "../../../../../../loopx/control_plane/presentation/explore_history.ts";
-import {searchResearchRecords} from "./research-record-search";
+import {searchResearchRecords, type ResearchRecordDisplay} from "./research-record-search";
import {exportResearchRecords} from "./research-record-export";
import {downloadReport} from "./report-download";
/** Local read controls over the existing validated history snapshot. */
-export function ResearchRecordSearch({goalId, events, displayEvents, renderBody, complete, stale, busy, zh, stateLabel, timeLabel}: {
+export function ResearchRecordSearch({goalId, events, displayEvents, displaySections, renderBody, complete, stale, busy, zh, stateLabel, timeLabel}: {
goalId: string;
displayEvents?: readonly ExploreHistoryEvent[]; renderBody?: (event: ExploreHistoryEvent) => ReactNode;
+ displaySections?: ResearchRecordDisplay["sections"];
events: readonly ExploreHistoryEvent[]; complete: boolean; stale: boolean; busy: boolean; zh: boolean;
stateLabel: (status: string) => string; timeLabel: (at: string) => string;
}) {
@@ -18,8 +19,9 @@ export function ResearchRecordSearch({goalId, events, displayEvents, renderBody,
const [status, setStatus] = useState("");
const [limit, setLimit] = useState(50);
const [downloadFailed, setDownloadFailed] = useState(false);
- const matches = useMemo(() => searchResearchRecords(events, query, status), [events, query, status]);
const displayed = useMemo(() => new Map(displayEvents?.map(event => [event.event_id, event])), [displayEvents]);
+ const display = useMemo(() => ({events: displayed, sections: displaySections}), [displayed, displaySections]);
+ const matches = useMemo(() => searchResearchRecords(events, query, status, display), [events, query, status, display]);
const statuses = [...new Set(events.map(event => event.status).filter(Boolean))].sort();
const countLabel = zh ? `匹配 ${matches.length} / ${events.length} 条已读记录` : `${matches.length} matches in ${events.length} loaded records`;
const readState = busy ? (zh ? "读取中" : "Reading") : stale ? (zh ? "刷新失败" : "Refresh failed") : "";
@@ -27,7 +29,7 @@ export function ResearchRecordSearch({goalId, events, displayEvents, renderBody,
return
{setQuery(event.target.value); setLimit(50);}}/>