diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.css b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.css index 8e06134e73..ecdd0305c3 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.css +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-history.css @@ -102,11 +102,20 @@ .research-record-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-block: 12px; } .research-record-filters input { flex: 1 1 220px; min-width: 0; } .research-record-filters input, .research-record-filters select, .research-record-search button { min-height: 44px; padding: 8px 12px; border: 1px solid var(--pw-line); border-radius: 6px; color: var(--pw-text); background: var(--pw-bg); font: inherit; } -.research-record-search > p { color: var(--pw-muted); } +.research-record-count, .research-comparison-controls { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; margin-block: 12px; color: var(--pw-muted); font-size: var(--text-body); } +.research-comparison-controls > label { margin-inline-start: auto; color: var(--pw-text); } +.research-record-search .context-help-trigger { min-height: 28px; padding: 4px; border: 0; border-radius: 4px; } .research-record-search .research-history-records { list-style: none; padding: 0; } .research-record-search li { border-bottom: 1px solid var(--pw-line); } .research-record-search summary { min-height: 44px; overflow-wrap: anywhere; } .research-record-search summary span { display: block; color: var(--pw-muted); font-size: var(--text-caption); } +.research-record-entry:not([open]) > summary > strong { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; } +.research-record-entry[open] > summary > strong { display: block; line-height: var(--leading-prose); } +.research-record-entry > summary { position: relative; padding-inline-start: 18px; list-style: none; } +.research-record-entry > summary::-webkit-details-marker { display: none; } +.research-record-entry > summary::before { content: "▸"; position: absolute; inset-inline-start: 0; } +.research-record-entry[open] > summary::before { content: "▾"; } +.research-record-sources { margin-block: 12px; } .research-record-search p { white-space: pre-wrap; line-height: var(--leading-prose); overflow-wrap: anywhere; } .research-record-search code { display: block; overflow-wrap: anywhere; font-size: var(--text-body); } .research-record-search dd { margin: 0 0 8px; } @@ -292,10 +301,12 @@ .research-comparison-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; } .research-comparison-pair > div { min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; } .research-comparison-pair pre { white-space: pre-wrap; } +.research-comparison-identities p { margin-block: 4px 12px; } .research-comparison-field { border-block-start: 1px solid var(--pw-line); padding-block: 12px; } .research-comparison-side, .research-comparison-missing { color: var(--pw-muted); } .research-comparison-side { display: none; } @media (max-width: 640px) { .research-comparison-pair { grid-template-columns: 1fr; gap: 16px; } + .research-comparison-identities { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } .research-comparison-side { display: block; margin-block-end: 4px; } } 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 2afc3b3ab5..03bc5f7090 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 @@ -1,5 +1,5 @@ import {ResearchRecordComparison} from "./research-record-comparison"; -import {CircleHelp} from "lucide-react"; +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"; @@ -21,6 +21,8 @@ export function ResearchRecordSearch({goalId, events, displayEvents, renderBody, const matches = useMemo(() => searchResearchRecords(events, query, status), [events, query, status]); const displayed = useMemo(() => new Map(displayEvents?.map(event => [event.event_id, event])), [displayEvents]); 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") : ""; const reset = () => {setQuery(""); setStatus(""); setLimit(50);}; return
{zh ? "无法开始下载,记录未改变。请重试下载。" : "Could not start the download. Records are unchanged; try downloading again."}
: null} -{zh ? `匹配 ${matches.length} / ${events.length} 条已读记录` : `${matches.length} matches in ${events.length} loaded records`} - {!complete ? (zh ? " · 历史不完整" : " · History incomplete") : ""} - {busy ? (zh ? " · 正在读取历史" : " · Reading history") : stale ? (zh ? " · 刷新失败,显示上次读取的记录" : " · Refresh failed; showing previously read records") - : ""}
- {!matches.length ?{complete && !stale && !busy - ? (zh ? "没有匹配的记录。尝试其他文字或清除筛选。" : "No matching records. Try another term or clear the filters.") - : (zh ? "已读部分没有匹配记录;其余历史尚未核验。" : "No matches in the loaded records; the remaining history is not verified.")}
{countLabel}{zh ? "。" : "."}
+{complete ? (zh ? "已搜索完整载入的历史。" : "Search covers the complete loaded history.") : (zh ? "历史不完整;其余记录尚未核验。" : "History is incomplete; remaining records have not been verified.")}
+ {stale ?{zh ? "刷新失败,显示上次读取的记录。" : "Refresh failed; showing previously read records."}
: null} + {!matches.length ?{complete && !stale && !busy + ? (zh ? "没有匹配的记录。尝试其他文字或清除筛选。" : "No matching records. Try another term or clear the filters.") + : (zh ? "已读部分没有匹配记录;其余历史尚未核验。" : "No matches in the loaded records; the remaining history is not verified.")}
: null} +{event.summary}
: null} {shown.blocked_reason ?{shown.blocked_reason}
: null} {renderBody ?{event.summary}
{event.blocked_reason ?{event.blocked_reason}
: null}{event.event_id}{event.result_id}{event.run_id}{event.from_node} → {event.to_node}{event.agent_id}{ref})}
+ {zh ? "比较原始记录,不代表同条件评测或研究质量变化。" : "Compares original records, not matched evaluations or changes in research quality."}
-{timeLabel(event.recorded_at)}
{event.event_id}{zh ? "比较原始记录,不代表同条件评测或研究质量变化。" : "Compares original records, not matched evaluations or changes in research quality."}
+{zh ? "所选记录" : "Selected record"}{selected.event_id}
{zh ? "对照记录" : "Comparison record"}{comparison.event_id}
{timeLabel(event.recorded_at)}
{zh ? `${changed.length} 个字段不同` : `${changed.length} fields differ`}
- {(showAll ? researchComparisonFields : changed).map(field =>