fix(workbench): scope trace loading indicators (#797)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -1196,6 +1196,15 @@ function taskTraceStepsLoaded(task: any, attemptIndex: any = null): boolean {
|
||||
return Boolean(task?._traceStepsLoaded);
|
||||
}
|
||||
|
||||
function traceStepsLoadingKey(taskId: string, attemptIndex: any = null): string {
|
||||
const attemptKey = attemptIndex === null || attemptIndex === undefined || String(attemptIndex).length === 0 ? "all" : String(attemptIndex);
|
||||
return `${taskId}:${attemptKey}`;
|
||||
}
|
||||
|
||||
function traceStepLoadingKey(taskId: string, seq: any): string {
|
||||
return `${taskId}:${String(seq ?? "")}`;
|
||||
}
|
||||
|
||||
function taskTraceStepDetails(task: any): AnyRecord {
|
||||
return task?._traceStepDetails && typeof task._traceStepDetails === "object" && !Array.isArray(task._traceStepDetails) ? task._traceStepDetails : {};
|
||||
}
|
||||
@@ -2158,12 +2167,14 @@ function ProgressivePromptBlock({ task, loading, onLoadPromptPart, testId = "cod
|
||||
);
|
||||
}
|
||||
|
||||
function ProgressiveExecutionSummary({ task, attempt, attemptIndex, loading, onLoadSteps, onLoadStep, testId = "codex-execution-summary" }: AnyRecord) {
|
||||
function ProgressiveExecutionSummary({ task, attempt, attemptIndex, traceStepsLoading, traceStepLoading, onLoadSteps, onLoadStep, testId = "codex-execution-summary" }: AnyRecord) {
|
||||
const steps = coalesceTraceSteps(taskTraceSteps(task, attemptIndex));
|
||||
const execution = canonicalExecutionSummary(attemptExecutionSummary(task, attempt));
|
||||
const stats = attempt ? attemptOaTraceStats(task, attempt) : taskOaTraceStats(task);
|
||||
const stepDetails = taskTraceStepDetails(task);
|
||||
const stepsLoaded = taskTraceStepsLoaded(task, attemptIndex);
|
||||
const taskId = String(task?.id || "");
|
||||
const stepsLoading = Boolean(traceStepsLoading?.[traceStepsLoadingKey(taskId, attemptIndex)]);
|
||||
const errorCount = statCount(stats?.errorCount);
|
||||
const fallbackStepCount = rawTraceStepCountFallback(
|
||||
steps.length > 0 ? steps.length : null,
|
||||
@@ -2226,10 +2237,11 @@ function ProgressiveExecutionSummary({ task, attempt, attemptIndex, loading, onL
|
||||
h("span", null, `执行命令:${listPreview(commands, 4)}`),
|
||||
),
|
||||
steps.length === 0
|
||||
? h("div", { className: "codex-output-empty" }, loading ? "正在按需拉取步骤 summary..." : "展开后将只请求执行步骤 summary,不拉取单步骤全量。")
|
||||
? h("div", { className: "codex-output-empty" }, stepsLoading ? "正在按需拉取步骤 summary..." : "展开后将只请求执行步骤 summary,不拉取单步骤全量。")
|
||||
: h("div", { className: "codex-trace-step-list" }, steps.map((step: any) => {
|
||||
const seq = String(step?.seq ?? "");
|
||||
const detail = stepDetails[seq];
|
||||
const detailLoading = Boolean(traceStepLoading?.[traceStepLoadingKey(taskId, seq)]);
|
||||
const summaryLines = Array.isArray(step?.summaryLines) ? step.summaryLines.slice(0, 4) : [];
|
||||
const inlineSummary = summaryLines.find((line: any) => String(line || "").trim().length > 0);
|
||||
return h("details", {
|
||||
@@ -2261,7 +2273,7 @@ function ProgressiveExecutionSummary({ task, attempt, attemptIndex, loading, onL
|
||||
className: "codex-transcript codex-step-detail-transcript",
|
||||
collapseTools: false,
|
||||
})
|
||||
: h("div", { className: "codex-output-empty" }, loading ? "正在按需拉取这个步骤的全量数据..." : "展开后将只请求这个单步骤的全量数据。"),
|
||||
: h("div", { className: "codex-output-empty" }, detailLoading ? "正在按需拉取这个步骤的全量数据..." : "展开后将只请求这个单步骤的全量数据。"),
|
||||
);
|
||||
})),
|
||||
);
|
||||
@@ -2345,7 +2357,7 @@ function ProgressiveJudgeFeedbackPrompt({ task, attempt, attemptIndex, loading,
|
||||
);
|
||||
}
|
||||
|
||||
function ProgressiveAttemptCycle({ task, attempt, position, loading, onLoadPromptPart, onLoadSteps, onLoadStep }: AnyRecord) {
|
||||
function ProgressiveAttemptCycle({ task, attempt, position, loading, traceStepsLoading, traceStepLoading, onLoadPromptPart, onLoadSteps, onLoadStep }: AnyRecord) {
|
||||
const attemptIndex = attemptSegmentIndex(attempt, position);
|
||||
const current = attemptIsActiveCurrent(task, attemptIndex);
|
||||
const first = position === 0 && !current;
|
||||
@@ -2362,7 +2374,8 @@ function ProgressiveAttemptCycle({ task, attempt, position, loading, onLoadPromp
|
||||
task,
|
||||
attempt,
|
||||
attemptIndex,
|
||||
loading,
|
||||
traceStepsLoading,
|
||||
traceStepLoading,
|
||||
onLoadSteps,
|
||||
onLoadStep,
|
||||
testId: current ? "codex-execution-summary-current" : first ? "codex-execution-summary" : `codex-execution-summary-attempt-${attemptIndex}`,
|
||||
@@ -2390,16 +2403,16 @@ function ProgressiveAttemptCycle({ task, attempt, position, loading, onLoadPromp
|
||||
);
|
||||
}
|
||||
|
||||
function ProgressiveTrace({ task, loading, onLoadPromptPart, onLoadSteps, onLoadStep }: AnyRecord) {
|
||||
function ProgressiveTrace({ task, loading, traceStepsLoading, traceStepLoading, onLoadPromptPart, onLoadSteps, onLoadStep }: AnyRecord) {
|
||||
if (!task) return h(EmptyState, { title: "未选择任务", text: "从左侧队列选择任务,或提交新 Codex 任务。" });
|
||||
const attempts = taskProgressiveAttempts(task);
|
||||
return h("div", { className: "codex-transcript codex-progressive-trace", "data-testid": "codex-output" },
|
||||
loading && !taskTraceSummary(task) ? h("div", { className: "codex-output-empty" }, "正在加载 Trace Summary...") : null,
|
||||
h(ProgressivePromptBlock, { task, loading, onLoadPromptPart }),
|
||||
attempts.length > 0
|
||||
? attempts.map((attempt: any, index: number) => h(ProgressiveAttemptCycle, { key: `${attempt?.index || index + 1}-${attempt?.startedAt || index}`, task, attempt, position: index, loading, onLoadPromptPart, onLoadSteps, onLoadStep }))
|
||||
? attempts.map((attempt: any, index: number) => h(ProgressiveAttemptCycle, { key: `${attempt?.index || index + 1}-${attempt?.startedAt || index}`, task, attempt, position: index, loading, traceStepsLoading, traceStepLoading, onLoadPromptPart, onLoadSteps, onLoadStep }))
|
||||
: [
|
||||
h(ProgressiveExecutionSummary, { key: "execution", task, loading, onLoadSteps, onLoadStep }),
|
||||
h(ProgressiveExecutionSummary, { key: "execution", task, traceStepsLoading, traceStepLoading, onLoadSteps, onLoadStep }),
|
||||
h(ProgressiveFinalResponse, { key: "final", task }),
|
||||
h(ProgressiveJudge, { key: "judge", task }),
|
||||
],
|
||||
@@ -2492,6 +2505,8 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
|
||||
const [selectedId, setSelectedId] = useState(initialSelectedId);
|
||||
const [selectedTask, setSelectedTask] = useState(initialSelectedTask);
|
||||
const [selectedDetailLoading, setSelectedDetailLoading] = useState(false);
|
||||
const [traceStepsLoading, setTraceStepsLoading] = useState<AnyRecord>({});
|
||||
const [traceStepLoading, setTraceStepLoading] = useState<AnyRecord>({});
|
||||
const [taskSearchQuery, setTaskSearchQuery] = useState("");
|
||||
const [searchTasksData, setSearchTasksData] = useState(null);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
@@ -3015,6 +3030,8 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
|
||||
const existing = traceStepsInFlightRef.current.get(key);
|
||||
if (existing) return existing;
|
||||
const token = detailLoadTokenRef.current;
|
||||
const loadingKey = traceStepsLoadingKey(taskId, attemptKey || null);
|
||||
setTraceStepsLoading((prev: AnyRecord) => ({ ...prev, [loadingKey]: true }));
|
||||
if (selectedIdRef.current === taskId) setSelectedDetailLoading(true);
|
||||
const promise = (async () => {
|
||||
try {
|
||||
@@ -3042,6 +3059,11 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
|
||||
}
|
||||
} finally {
|
||||
traceStepsInFlightRef.current.delete(key);
|
||||
setTraceStepsLoading((prev: AnyRecord) => {
|
||||
const next = { ...prev };
|
||||
delete next[loadingKey];
|
||||
return next;
|
||||
});
|
||||
if (token === detailLoadTokenRef.current && selectedIdRef.current === taskId) setSelectedDetailLoading(false);
|
||||
}
|
||||
})();
|
||||
@@ -3060,6 +3082,8 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
|
||||
const existing = traceStepInFlightRef.current.get(key);
|
||||
if (existing) return existing;
|
||||
const token = detailLoadTokenRef.current;
|
||||
const loadingKey = traceStepLoadingKey(taskId, seqKey);
|
||||
setTraceStepLoading((prev: AnyRecord) => ({ ...prev, [loadingKey]: true }));
|
||||
if (selectedIdRef.current === taskId) setSelectedDetailLoading(true);
|
||||
const promise = (async () => {
|
||||
try {
|
||||
@@ -3072,6 +3096,11 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
|
||||
}, token);
|
||||
} finally {
|
||||
traceStepInFlightRef.current.delete(key);
|
||||
setTraceStepLoading((prev: AnyRecord) => {
|
||||
const next = { ...prev };
|
||||
delete next[loadingKey];
|
||||
return next;
|
||||
});
|
||||
if (token === detailLoadTokenRef.current && selectedIdRef.current === taskId) setSelectedDetailLoading(false);
|
||||
}
|
||||
})();
|
||||
@@ -4241,7 +4270,7 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
|
||||
) : null,
|
||||
h("div", { className: "codex-session-main" },
|
||||
h("div", { className: "codex-output-stack" },
|
||||
h(ProgressiveTrace, { task: selectedTask, loading: selectedDetailLoading, onLoadPromptPart: ensurePromptPart, onLoadSteps: ensureTraceSteps, onLoadStep: ensureTraceStep }),
|
||||
h(ProgressiveTrace, { task: selectedTask, loading: selectedDetailLoading, traceStepsLoading, traceStepLoading, onLoadPromptPart: ensurePromptPart, onLoadSteps: ensureTraceSteps, onLoadStep: ensureTraceStep }),
|
||||
h(RawTranscript, { task: selectedTask }),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user