chore(dashboard): address Task 14 + 15 review concerns

Task 14 stale TODO:
- Delete the TODO(Task 14) comment that this very task already
  resolved (selection→container neighbor highlighting now flows
  through isFocusedViaChild).

Task 15 visible container size:
- mergeElkPositions now propagates width/height from the ELK output
  back onto the React Flow node, not just position. After a
  stage1Tick-driven re-layout, the container atom resizes to match
  the actual Stage 2 footprint instead of staying clipped at the
  pre-expansion estimate. ELK echoes back the same width/height we
  pass in for non-container nodes, so this is a no-op for them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lum1104
2026-05-03 16:53:58 +08:00
Unverified
parent ccb52545ad
commit 69a0cd13a9
2 changed files with 32 additions and 12 deletions
@@ -854,12 +854,9 @@ function buildCustomFlowNode(
* Visual overlay: cheap O(n) pass that applies selection, search, and tour
* state onto already-positioned nodes. Avoids triggering ELK relayout.
*
* TODO(Task 14): selection neighbor highlighting currently walks raw graph
* edges with file-id endpoints. When a neighbor lives inside a collapsed
* container, its container atom should still light up (via
* isFocusedViaChild) — but today it doesn't, because the neighbor set
* is keyed by file ids. Map neighbors through nodeToContainer when
* applying overlays to container nodes.
* Container atoms whose children are focused or selected light up via
* `isFocusedViaChild` — neighbor sets are mapped through `nodeToContainer`
* so collapsed containers still show the relationship.
*
* Also folds in Stage 2 outputs:
* - Expanded children are emitted as React Flow children (`parentId` +
@@ -227,12 +227,35 @@ export function mergeElkPositions<T extends Node>(
nodes: T[],
positioned: ElkInput,
): T[] {
const posMap = new Map<string, { x: number; y: number }>();
const positionedMap = new Map<
string,
{ x: number; y: number; width?: number; height?: number }
>();
for (const c of positioned.children ?? []) {
posMap.set(c.id, { x: c.x ?? 0, y: c.y ?? 0 });
positionedMap.set(c.id, {
x: c.x ?? 0,
y: c.y ?? 0,
width: c.width,
height: c.height,
});
}
return nodes.map((n) => ({
...n,
position: posMap.get(n.id) ?? n.position ?? { x: 0, y: 0 },
}));
return nodes.map((n) => {
const merged = positionedMap.get(n.id);
if (!merged) {
return {
...n,
position: n.position ?? { x: 0, y: 0 },
};
}
// Propagate width/height for container nodes so a tick-driven
// Stage 1 re-layout (Task 15) can resize the visible atom to match
// the actual Stage 2 footprint. ELK echoes back the same width/height
// we passed in for non-container nodes, so this is a no-op for them.
return {
...n,
position: { x: merged.x, y: merged.y },
...(merged.width != null ? { width: merged.width } : {}),
...(merged.height != null ? { height: merged.height } : {}),
};
});
}