From 8e242f8c48a3d538c057c68693608f5d34b5600e Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Sun, 8 Nov 2026 03:23:31 +0800 Subject: [PATCH] Show child research navigation while Goal status loads Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- .../goal-research-workbench.tsx | 31 +++++----- .../personal-workspace-page.tsx | 37 +++++++----- .../research-child-goals.tsx | 10 ++-- ...pace-progressive-loading-browser-smoke.mjs | 58 ++++++++++++++++++- 4 files changed, 102 insertions(+), 34 deletions(-) diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-workbench.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-workbench.tsx index c9da132892..852461c8d1 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-research-workbench.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-research-workbench.tsx @@ -1,4 +1,4 @@ -import {useState} from "react"; +import {useState, type ReactNode} from "react"; import {GoalResearchHistory} from "./goal-research-history"; import {GoalExploreResults} from "./goal-explore-results"; import {goalHierarchy} from "./goal-hierarchy"; @@ -9,9 +9,9 @@ import './research-case-study.css'; type ResearchGoal = ResearchChildGoal & Pick; /** Parentage organizes explicit source views; it never combines evidence or execution scope. */ -export function ResearchGoalNavigation({goalId, goals, zh, onSelect, directoryUrl, active, refreshRevision}: { +function ResearchGoalNavigation({goalId, goals, zh, onSelect, directoryUrl, active, showTiming, refreshRevision}: { goalId: string; goals: ResearchGoal[]; zh: boolean; onSelect: (goalId: string) => void; - directoryUrl?: string; active: boolean; refreshRevision: number; + directoryUrl?: string; active: boolean; showTiming: boolean; refreshRevision: number; }) { const selected = goals.find(g => g.goalId === goalId); if (!selected) return null; @@ -24,25 +24,30 @@ export function ResearchGoalNavigation({goalId, goals, zh, onSelect, directoryUr return ; } /** One read surface for the selected original Goal; opening it never starts research. */ -export function GoalResearchWorkbench(props: {goalId: string; active: boolean; zh: boolean; refreshRevision: number; readSourceUrl?: string; directoryReadSourceUrl?: string; goals?: ResearchGoal[]; onSelectGoal?: (goalId: string) => void; onOpenTasks?: () => void}) { +export function GoalResearchWorkbench(props: {goalId: string; active: boolean; zh: boolean; refreshRevision: number; readSourceUrl?: string; directoryReadSourceUrl?: string; goals?: ResearchGoal[]; onSelectGoal?: (goalId: string) => void; onOpenTasks?: () => void; statusNotice?: ReactNode}) { const selected = props.goals?.find(goal => goal.goalId === props.goalId); const source = selected?.sourceAccess; const [evidenceOpen, setEvidenceOpen] = useState(false); return
+ {props.statusNotice} + {/* The directory supplies navigation while the selected snapshot loads. + A denied or stale snapshot still blocks evidence reads. */} {props.goals && props.onSelectGoal ? : null} - -
setEvidenceOpen(event.currentTarget.open)}> - {props.zh ? "阅读已保存的结论" : "Read saved findings"} - {evidenceOpen ? : null} -
+ active={props.active} showTiming={!props.statusNotice} refreshRevision={props.refreshRevision}/> : null} + {!props.statusNotice ? <> + +
setEvidenceOpen(event.currentTarget.open)}> + {props.zh ? "阅读已保存的结论" : "Read saved findings"} + {evidenceOpen ? : null} +
+ : null}
; } diff --git a/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx b/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx index b299561a41..b25cb2b032 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx @@ -2797,6 +2797,21 @@ export function PersonalWorkspacePage({ onOpenConversation={() => {setSelectedGoalTab("chat"); requestAnimationFrame(() => composerRef.current?.focus());}} /> : undefined} />) : null; + const goalStatusNotice = selectedGoal?.loadState ? ( +
+
{t(selectedGoal.loadState === "error" ? "startup.goalError" : "startup.goalLoading")} +

{t(selectedGoal.loadError ? `startup.error.${selectedGoal.loadError}` : "startup.independent")}

+ {selectedGoal.loadState === "error" ? selectedGoal.loadError === "authority" && !readOnly ? + + : : null}
+
+ ) : null; + const researchPanel = selectedGoal && (!readOnly || researchReadSourceUrl) + ? selectGoal(id, "research")} + onOpenTasks={() => setSelectedGoalTab("tasks")} active={!settingsOpen && selectedGoalTab === "research"} + zh={locale === "zh-CN"} refreshRevision={historyRefreshRevision} readSourceUrl={researchReadSourceUrl} + directoryReadSourceUrl={directoryReadSourceUrl} statusNotice={goalStatusNotice} /> + : goalStatusNotice ??

{locale === "zh-CN" ? "此来源尚未提供研究记录的读取入口。" : "This source does not provide a research history endpoint."}

; return ( <> {!rootUnavailable ?