From c3d82058396bbca35f7c90ffeed23da2e36c9320 Mon Sep 17 00:00:00 2001 From: weichen Date: Sat, 17 Oct 2026 04:07:58 +0000 Subject: [PATCH] Show version block in panorama node view Why: the I4 scenarios assert the version collapsible for a selected section in the panorama (not only the reader); the panorama node view had no version block, so .cockpit-versions-toggle never existed there. Also normalize null list projections in the panorama node detail fetch (same Go nil-slice issue fixed for the panel earlier). Evidence: tsc clean, vitest green, build green (SELF); seven-scenario rerun to be recorded on the Dev I4 card. Impact: cockpit panorama only. Refs: rollout I4 --- src/components/DocumentCockpit.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/DocumentCockpit.tsx b/src/components/DocumentCockpit.tsx index c450146..b271301 100644 --- a/src/components/DocumentCockpit.tsx +++ b/src/components/DocumentCockpit.tsx @@ -16,7 +16,7 @@ import { type CockpitTreeNode, type CockpitTreePage, type Density, type PanelTabId, type ViewMode, } from '../documentCockpit' -import { CockpitPanel, CockpitReader } from './CockpitReader' +import { CockpitPanel, CockpitReader, VersionBlock } from './CockpitReader' interface ProjectView { projectId: string; name: string; canAudit?: boolean } @@ -198,6 +198,7 @@ export function DocumentCockpit() { {overview && selected && viewMode === 'panorama' && ( setSelected(null)} onOpenReader={() => applyPrefs({ lastView: 'reader' })} /> )} @@ -289,9 +290,10 @@ function PanoramaHome({ overview, onSelect }: { overview: CockpitOverview; onSel ) } -function PanoramaNode({ pid, selection, overview, childPage, onClear, onOpenReader }: { +function PanoramaNode({ pid, selection, overview, childPage, density, onClear, onOpenReader }: { pid: string; selection: Selection; overview: CockpitOverview childPage?: { items: CockpitTreeNode[]; nextCursor?: string; hasMore: boolean; meta?: CockpitMeta } + density: Density onClear: () => void onOpenReader: () => void }) { @@ -302,7 +304,14 @@ function PanoramaNode({ pid, selection, overview, childPage, onClear, onOpenRead const g = ++gen.current setDetail(null); setErr('') api.rdmCommand('rdm.cockpit.node', { projectId: pid, kind: selection.ref.kind, id: selection.ref.id }) - .then(d => { if (g === gen.current) setDetail(d) }) + .then(d => { + if (g !== gen.current) return + // 后端空列表可能投影为 null(Go nil slice);统一归一,消费端按数组使用。 + for (const k of ['sources', 'history', 'impacts', 'conflicts'] as const) { + if (d?.[k] && !Array.isArray(d[k].items)) d[k].items = [] + } + setDetail(d) + }) .catch(e => { if (g === gen.current) setErr(e.message) }) return () => { gen.current++ } }, [pid, selection.ref.kind, selection.ref.id]) @@ -320,6 +329,9 @@ function PanoramaNode({ pid, selection, overview, childPage, onClear, onOpenRead {detail?.body?.length === 1 && detail.body[0].kind === 'restricted' && (
内容受限({detail.body[0].reason || '权限'})——标题与状态可见,正文不展示
)} + {selection.ref.kind === 'section' && detail?.versions && detail.versions.length > 0 && ( + + )} {detail && detail.meta && !sameSnapshot(detail.meta, overview.meta) && (
节点详情与统计快照不同({detail.meta.snapshotRevision} vs {overview.meta.snapshotRevision})——刷新对齐
)}