diff --git a/frontend/app.js b/frontend/app.js index 2f17236..da50ca9 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -104,6 +104,11 @@ const ARTIFACT_DETAIL_RE = /^#\/artifacts\/([^/]+)$/; // reaching renderTaskDetail/mountTaskDetail with a bogus org_node that would // otherwise need its own defensive checks further down. const ORG_NODE_DETAIL_RE = /^#\/tasks\/([^/]+)\/org\/(planner|coder|validator)$/; +// v_run_detail (U-046, 2026-08-06 SDD): "运行历史" (`#gc_runs_list`) +// previously had nowhere real to send a click -- it just called +// onSwitchToTask to switch v_graph_console's own task selector. This is the +// actual run-detail page/route that closes that gap. +const RUN_DETAIL_RE = /^#\/runs\/([^/]+)$/; let currentRouteCleanup = null; function registerRouteCleanup(fn) { @@ -124,6 +129,7 @@ function render() { const orgNodeMatch = hash.match(ORG_NODE_DETAIL_RE); const skillMatch = hash.match(SKILL_AUDIT_RE); const artifactMatch = hash.match(ARTIFACT_DETAIL_RE); + const runMatch = hash.match(RUN_DETAIL_RE); if (orgNodeMatch) { // Reuses v_task_detail itself (same render/mount) with the org_node // carried through as a second arg -- no separate view/route handler. @@ -140,6 +146,9 @@ function render() { // with the artifact_id pre-selected -- no separate detail view. route = { render: renderArtifactBrowser, mount: mountArtifactBrowser }; routeArgs = [artifactMatch[1]]; + } else if (runMatch) { + route = { render: renderRunDetail, mount: mountRunDetail }; + routeArgs = [runMatch[1]]; } } if (!route) route = { render: () => "
" + hash + "
" }; @@ -1468,6 +1477,122 @@ function mountTaskDetail(taskId, initialOrgNode) { }); } +// ---- v_run_detail (`#/runs/:run_id`, U-046 2026-08-06 SDD): single Work +// Graph Run detail -- every work_node_execution the run contains, each with +// its own log (live c_ws_log_tail while running, static c_execution_log_get +// once terminal). Reuses renderGraphVisualizerPanel/mountLogViewer +// unmodified, same as v_task_detail's todo tree above; the one DOM-id +// contract mountLogViewer relies on (`#todo-detail-