From bdaea2157470932ad2bb2f6d0c6465e209101fc2 Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 2 Aug 2026 03:34:39 -0400 Subject: [PATCH] P6-02: project document tree and properties --- src/App.tsx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 6d0c6da..fbfb73d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -276,7 +276,7 @@ function Workspace({ workbench, setWorkbench, leftTab, setLeftTab, rightTab, set
@@ -305,16 +305,18 @@ function FunctionRail({ workbench, facade, showNotice }: { workbench: Workbench; function ModelTree({ document, selectedObject, setSelectedObject, showNotice }: { document: DocumentSnapshot; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) { const [expanded, setExpanded] = useState>({ origin: false, body: true, reference: false }) + const itemsById = new Map(document.tree.map((item) => [item.id, item])) + const childIds = new Set(document.tree.flatMap((item) => item.children || [])) return
{document.label}v{document.version}
- {document.tree.map((item) => setExpanded((current) => ({ ...current, [item.id]: !current[item.id] }))} selectedObject={selectedObject} setSelectedObject={setSelectedObject} showNotice={showNotice} />)} + {document.tree.filter((item) => !childIds.has(item.id)).map((item) => setExpanded((current) => ({ ...current, [item.id]: !current[item.id] }))} itemsById={itemsById} selectedObject={selectedObject} setSelectedObject={setSelectedObject} showNotice={showNotice} />)}
ValidNeeds review
} -function TreeItem({ item, level, expanded, onToggle, selectedObject, setSelectedObject, showNotice }: { item: ModelTreeItem; level: number; expanded?: boolean; onToggle: () => void; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) { +function TreeItem({ item, level, expanded, onToggle, itemsById, selectedObject, setSelectedObject, showNotice }: { item: ModelTreeItem; level: number; expanded?: boolean; onToggle: () => void; itemsById: Map; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) { const hasChildren = item.children && item.children.length > 0 const itemIcon = item.type === 'body' ? Box : item.type === 'sketch' ? CircleDot : item.type === 'feature' ? SquareStack : Layers3 const ItemIcon = itemIcon @@ -326,7 +328,7 @@ function TreeItem({ item, level, expanded, onToggle, selectedObject, setSelected {item.state === 'warning' && } {item.state === 'active' && } - {expanded && hasChildren &&
{item.children?.map((child) =>
{child}
)}
} + {expanded && hasChildren &&
{item.children?.map((childId) => { const child = itemsById.get(childId); const ChildIcon = child?.type === 'sketch' ? CircleDot : child?.type === 'feature' ? SquareStack : Circle; return child ? :
{childId}
})}
} } @@ -336,9 +338,13 @@ function TaskPanel({ workbench, facade, showNotice }: { workbench: Workbench; fa return
Active command

{isSketch ? 'Edit Sketch' : definition.taskTitle}

Preview
1
{isSketch ? 'Geometry and constraints' : definition.objectType}{definition.taskSummary}
Changes remain local until the document is recomputed.
} -function DataProperties({ selectedObject, showNotice }: { selectedObject: string; showNotice: (message: string) => void }) { - const isPocket = selectedObject === 'pocket' - return
Identity
showNotice('Label editor opened')} />
Parameters
showNotice('Length editor opened')} /> showNotice('Boolean editor opened')} />
Dependencies
Expressions
Length42 mm
+function DataProperties({ selectedObject, selectedItem, showNotice }: { selectedObject: string; selectedItem?: ModelTreeItem; showNotice: (message: string) => void }) { + const label = selectedItem?.label || 'Body' + const isPocket = label.toLowerCase().startsWith('pocket') + const isSketch = selectedItem?.type === 'sketch' + const objectType = selectedItem?.type === 'body' ? 'PartDesign::Body' : isSketch ? 'Sketcher::SketchObject' : isPocket ? 'PartDesign::Pocket' : 'PartDesign::Feature' + const status = selectedItem?.state === 'warning' ? 'Warning' : selectedItem?.state === 'readonly' ? 'Read-only' : 'Valid' + return
Identity
showNotice('Label editor opened')} />
Parameters
showNotice('Length editor opened')} /> showNotice('Boolean editor opened')} />
Dependencies
Expressions
Length42 mm
} function PropertyRow({ label, value, editable = false, link = false, tone, onClick }: { label: string; value: string; editable?: boolean; link?: boolean; tone?: 'amber' | 'green'; onClick?: () => void }) { @@ -364,7 +370,7 @@ function Viewport({ selectedObject, setSelectedObject, workbench, facade, showNo adapter.dispose() } }, [facade, showNotice, selectedObject]) - return
{workbench}Body / Fillet
setSelectedObject('')}>
{ event.stopPropagation(); setSelectedObject('pad'); showNotice('Selected Pad') }}>
Pad
SelectedEdgesDatum
+ return
{workbench}Body / Fillet
setSelectedObject('')}>
{ event.stopPropagation(); setSelectedObject('pad'); showNotice('Selected Pad') }}>
Pad
SelectedEdgesDatum
} function PageFrame({ page, onNavigate, onOpenWorkspace, showNotice }: { page: Page; onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void }) {