fix(frontend): remove debug wrapper nodes from flow graph

Remove WrapperInfo type, SHOW_DEBUG_WRAPPERS flag, buildDebugWrapperNodes
helper, DebugWrapperNode component, and all related plumbing in
FlowGraphV2. The bbox computation now uses groupLayouts directly,
keeping layout correctness without any debug wrapper overhead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Guilhem
2026-03-04 10:25:57 +00:00
co-authored by Claude Opus 4.6
parent 78371e97a2
commit 5a3efd7d84
3 changed files with 6 additions and 219 deletions
@@ -70,8 +70,7 @@
import type { MoveManager } from './moveManager.svelte'
import DragCoordinator from './DragCoordinator.svelte'
import type { ModulesTestStates } from '../modulesTest.svelte'
import { compoundLayout, buildDebugWrapperNodes, type WrapperInfo } from './compoundLayout'
import DebugWrapperNode from './renderers/nodes/DebugWrapperNode.svelte'
import { compoundLayout } from './compoundLayout'
import { deepEqual } from 'fast-equals'
import type { AssetWithAltAccessType } from '../assets/lib'
import type { ModuleActionInfo } from '$lib/components/flows/flowDiff'
@@ -324,7 +323,6 @@
}
type NodePos = { position: { x: number; y: number } }
let lastNodes: [NodeDep[], (NodeDep & NodePos)[]] | undefined = undefined
let lastWrappers: WrapperInfo[] = []
let lastXCenter = 0
function layoutNodes(nodes: NodeDep[]): (NodeDep & NodePos)[] {
@@ -348,15 +346,13 @@
)
// Run recursive compound layout
const { positions, bbox, wrappers } = compoundLayout(nodes, edges, {
const { positions, bbox } = compoundLayout(nodes, edges, {
nodeWidth: NODE.width,
nodeHeight: NODE.height,
gapH: NODE.gap.horizontal,
gapV: NODE.gap.vertical
})
lastWrappers = wrappers
// Center horizontally
const xCenter =
(fullSize ? fullWidth : width) / 2 - bbox.width / 2 - (width - fullWidth) / 2
@@ -618,11 +614,7 @@
}
// update nodes
nodes = [
...finalNodes,
...buildDebugWrapperNodes(lastWrappers, lastXCenter),
...(noteNodesResult?.noteNodes ?? [])
]
nodes = [...finalNodes, ...(noteNodesResult?.noteNodes ?? [])]
edges = [
...(assetNodesResult?.newAssetEdges ?? []),
@@ -668,8 +660,7 @@
assetsOverflowed: AssetsOverflowedNode,
aiTool: AiToolNode,
newAiTool: NewAiToolNode,
note: NoteNode,
debugWrapper: DebugWrapperNode
note: NoteNode
} as any
const edgeTypes = {
@@ -971,7 +962,7 @@
{@render leftHeader()}
</div>
{:else}
<Controls position="top-right" orientation="horizontal" showLock={false} fitViewOptions={{ nodes: nodes.filter((n) => n.type !== 'debugWrapper' && n.type !== 'note') }}>
<Controls position="top-right" orientation="horizontal" showLock={false} fitViewOptions={{ nodes: nodes.filter((n) => n.type !== 'note') }}>
{#if multiSelectEnabled}
<div class="flex items-center gap-2">
<Tooltip>
@@ -23,33 +23,12 @@ type CompoundGroup = {
}[]
}
export type WrapperInfo = {
id: string
headId: string
type: CompoundGroup['type']
level: 'group' | 'branch' | 'loop-body'
label: string
x: number
y: number
width: number
height: number
}
type LayoutResult = {
positions: Map<string, { x: number; y: number }>
bbox: { width: number; height: number }
wrappers: WrapperInfo[]
contentMinX: number
}
/**
* ----- DEBUG -----
* Flip to `true` to compute and visualize compound-layout wrapper boxes.
* When enabled, the layout returns WrapperInfo[] objects that FlowGraphV2
* renders as colored dashed/dotted rectangles around groups and branches.
*/
export const SHOW_DEBUG_WRAPPERS = false
const LOOP_INDENT = 25
/**
@@ -301,7 +280,6 @@ function layoutLevel(
return {
positions,
bbox: { width: constants.nodeWidth, height: 0 },
wrappers: [],
contentMinX: 0
}
}
@@ -543,89 +521,6 @@ function layoutLevel(
}
}
// ----- DEBUG: wrapper visualization data -----
const wrappers: WrapperInfo[] = []
if (SHOW_DEBUG_WRAPPERS) {
for (const [headId, gl] of groupLayouts) {
const wrapperPos = sugResult.positions.get(headId)
if (!wrapperPos) continue
// Overall group wrapper
wrappers.push({
id: `__wrapper__${headId}`,
headId,
type: gl.group.type,
level: 'group',
label: `${gl.group.type} (${headId})`,
x: wrapperPos.x,
y: wrapperPos.y,
width: gl.wrapperWidth,
height: gl.wrapperHeight
})
const rowHeight = constants.nodeHeight + constants.gapV
const isBranch = gl.group.type === 'branchall' || gl.group.type === 'branchone'
if (isBranch) {
const branchWidths = gl.branchLayouts.map((bl) =>
Math.max(bl.bbox.width, constants.nodeWidth)
)
const totalWidth =
branchWidths.reduce((s, w) => s + w, 0) +
Math.max(0, branchWidths.length - 1) * constants.gapH
let cx = wrapperPos.x - totalWidth / 2
for (let bi = 0; bi < gl.branchLayouts.length; bi++) {
const bl = gl.branchLayouts[bi]
const bw = branchWidths[bi]
const branchCenterX = cx + bw / 2
// Per-branch wrapper
wrappers.push({
id: `__wrapper__${headId}__branch_${bi}`,
headId,
type: gl.group.type,
level: 'branch',
label: `branch ${bi} (${bl.labelId})`,
x: branchCenterX,
y: wrapperPos.y + rowHeight,
width: bw,
height: bl.bbox.height
})
// Child wrappers from recursive layout
for (const cw of bl.result.wrappers) {
wrappers.push({ ...cw, x: branchCenterX + cw.x, y: wrapperPos.y + rowHeight + cw.y })
}
cx += bw + constants.gapH
}
} else {
const bl = gl.branchLayouts[0]
if (bl) {
// Loop body wrapper
wrappers.push({
id: `__wrapper__${headId}__body`,
headId,
type: gl.group.type,
level: 'loop-body',
label: `loop body (${bl.labelId})`,
x: wrapperPos.x + LOOP_INDENT,
y: wrapperPos.y + rowHeight,
width: bl.bbox.width,
height: bl.bbox.height
})
// Child wrappers from recursive layout
for (const cw of bl.result.wrappers) {
wrappers.push({
...cw,
x: wrapperPos.x + LOOP_INDENT + cw.x,
y: wrapperPos.y + rowHeight + cw.y
})
}
}
}
}
}
// Compute overall bbox (nodes + group wrapper extents)
let minX = Infinity
let maxX = -Infinity
@@ -654,7 +549,7 @@ function layoutLevel(
width: Math.max(bboxWidth, constants.nodeWidth),
height: Math.max(bboxHeight, 0)
}
return { positions, bbox: finalBbox, wrappers, contentMinX }
return { positions, bbox: finalBbox, contentMinX }
}
/**
@@ -693,11 +588,6 @@ export function compoundLayout(
for (const pos of result.positions.values()) {
pos.x -= minX
}
if (SHOW_DEBUG_WRAPPERS) {
for (const w of result.wrappers) {
w.x -= minX
}
}
}
}
@@ -712,37 +602,3 @@ export function compoundLayout(
return result
}
/** Build SvelteFlow nodes for debug wrappers. Returns [] when SHOW_DEBUG_WRAPPERS is false. */
export function buildDebugWrapperNodes(
wrappers: WrapperInfo[],
xCenter: number
): {
id: string
type: string
position: { x: number; y: number }
data: Record<string, unknown>
selectable: boolean
draggable: boolean
zIndex: number
style: string
}[] {
if (!SHOW_DEBUG_WRAPPERS) return []
return wrappers.map((w) => ({
id: w.id,
type: 'debugWrapper',
position: { x: w.x + xCenter - w.width / 2, y: w.y },
data: {
headId: w.headId,
type: w.type,
level: w.level,
label: w.label,
wrapperWidth: w.width,
wrapperHeight: w.height
},
selectable: false,
draggable: false,
zIndex: w.level === 'group' ? -10 : -5,
style: `width: ${w.width}px; height: ${w.height}px;`
}))
}
@@ -1,60 +0,0 @@
<script lang="ts">
interface Props {
data: {
headId: string
type: string
level: 'group' | 'branch' | 'loop-body'
label: string
wrapperWidth: number
wrapperHeight: number
}
}
let { data }: Props = $props()
// Group wrappers: solid bg, thicker border
// Branch wrappers: lighter bg, thinner border
const groupColors: Record<string, { bg: string; border: string }> = {
branchall: { bg: 'rgba(59, 130, 246, 0.08)', border: 'rgba(59, 130, 246, 0.5)' },
branchone: { bg: 'rgba(168, 85, 247, 0.08)', border: 'rgba(168, 85, 247, 0.5)' },
forloop: { bg: 'rgba(34, 197, 94, 0.08)', border: 'rgba(34, 197, 94, 0.5)' },
whileloop: { bg: 'rgba(234, 179, 8, 0.08)', border: 'rgba(234, 179, 8, 0.5)' }
}
const branchColors: Record<string, { bg: string; border: string }> = {
branchall: { bg: 'rgba(59, 130, 246, 0.12)', border: 'rgba(59, 130, 246, 0.7)' },
branchone: { bg: 'rgba(168, 85, 247, 0.12)', border: 'rgba(168, 85, 247, 0.7)' },
forloop: { bg: 'rgba(34, 197, 94, 0.12)', border: 'rgba(34, 197, 94, 0.7)' },
whileloop: { bg: 'rgba(234, 179, 8, 0.12)', border: 'rgba(234, 179, 8, 0.7)' }
}
const fallback = { bg: 'rgba(100,100,100,0.06)', border: 'rgba(100,100,100,0.4)' }
const colors = data.level === 'group'
? (groupColors[data.type] ?? fallback)
: (branchColors[data.type] ?? fallback)
const borderWidth = data.level === 'group' ? 2 : 1.5
const borderStyle = data.level === 'group' ? 'dashed' : 'dotted'
</script>
<div
style="
width: {data.wrapperWidth}px;
height: {data.wrapperHeight}px;
background: {colors.bg};
border: {borderWidth}px {borderStyle} {colors.border};
border-radius: {data.level === 'group' ? 10 : 6}px;
pointer-events: none;
position: relative;
"
>
<span
style="
position: absolute;
{data.level === 'group' ? 'top: 2px; left: 6px;' : 'bottom: 2px; right: 6px;'}
font-size: 9px;
color: {colors.border};
font-family: monospace;
opacity: 0.85;
"
>
{data.label} {data.wrapperWidth}×{data.wrapperHeight}
</span>
</div>