Browse Source

fix: move panel height correction from loadWorkflow into BaseNode render

The pre-subtraction in loadWorkflow was overridden by React Flow's
dimension reconciliation. Instead, correct at the source: in BaseNode's
expand timeout, read _settingsPanelHeight from node data and only add
the delta (measured - saved) so reloaded nodes don't double-count.
Also clear _settingsPanelHeight on collapse to avoid stale values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
f7864197b8
  1. 15
      src/components/nodes/BaseNode.tsx
  2. 53
      src/store/workflowStore.ts

15
src/components/nodes/BaseNode.tsx

@ -108,7 +108,10 @@ export function BaseNode({
if (node.id !== id) return node;
const currentHeight = getNodeDimension(node, "height");
const newHeight = Math.max(minHeight, currentHeight - heightToRemove);
return applyNodeDimensions(node, getNodeDimension(node, "width"), newHeight);
return {
...applyNodeDimensions(node, getNodeDimension(node, "width"), newHeight),
data: { ...node.data, _settingsPanelHeight: 0 },
};
})
);
@ -134,15 +137,21 @@ export function BaseNode({
animationTimeoutRef.current = setTimeout(() => {
isAnimatingRef.current = false;
// Apply the final panel height in one shot, then unlock the wrapper
// Apply the final panel height in one shot, then unlock the wrapper.
// Subtract any previously saved panel height to avoid double-counting
// on workflow reload (saved node height already includes panel).
const finalHeight = trackedSettingsHeightRef.current;
if (finalHeight > 0) {
setNodes((nodes) =>
nodes.map((node) => {
if (node.id !== id) return node;
const savedPanelHeight = typeof (node.data as Record<string, unknown>)?._settingsPanelHeight === "number"
? (node.data as Record<string, unknown>)._settingsPanelHeight as number
: 0;
const heightToAdd = finalHeight - savedPanelHeight;
const currentHeight = getNodeDimension(node, "height");
return {
...applyNodeDimensions(node, getNodeDimension(node, "width"), currentHeight + finalHeight),
...applyNodeDimensions(node, getNodeDimension(node, "width"), currentHeight + heightToAdd),
data: { ...node.data, _settingsPanelHeight: finalHeight },
};
})

53
src/store/workflowStore.ts

@ -1712,54 +1712,17 @@ const workflowStoreImpl: StateCreator<WorkflowStore> = (set, get) => ({
// Load cost data for this workflow
const costData = workflow.id ? loadWorkflowCostData(workflow.id) : null;
// Subtract saved settings panel height so BaseNode's expand effect
// re-adds the real panel height from a clean baseline (prevents
// height accumulation on each save/reload cycle).
const INLINE_PARAM_NODE_TYPES = new Set([
"nanoBanana", "generateVideo", "generate3d", "generateAudio", "llmGenerate",
]);
const inlineParamsEnabled = (() => {
try { return localStorage.getItem("node-banana-inline-parameters") === "true"; }
catch { return false; }
})();
set({
// Clear selected state - selection should not be persisted across sessions
// Also validate position to ensure coordinates are finite numbers
nodes: hydratedWorkflow.nodes.map(node => {
let adjustedNode = {
...node,
selected: false,
position: {
x: isFinite(node.position?.x) ? node.position.x : 0,
y: isFinite(node.position?.y) ? node.position.y : 0,
},
};
// Subtract panel height for inline-param nodes so the expand effect
// can re-add the real measured height without double-counting
const data = node.data as Record<string, unknown>;
const panelHeight = typeof data?._settingsPanelHeight === "number" ? data._settingsPanelHeight : 0;
if (
INLINE_PARAM_NODE_TYPES.has(node.type ?? "") &&
inlineParamsEnabled &&
(data?.parametersExpanded ?? true) === true &&
panelHeight > 0
) {
const currentHeight = (node.style?.height as number) ?? (defaultNodeDimensions[node.type as NodeType]?.height ?? 300);
const minHeight = defaultNodeDimensions[node.type as NodeType]?.height ?? 300;
const newHeight = Math.max(minHeight, currentHeight - panelHeight);
adjustedNode = {
...adjustedNode,
width: undefined,
height: undefined,
measured: undefined,
style: { ...adjustedNode.style, height: newHeight },
} as typeof adjustedNode;
}
return adjustedNode;
}),
nodes: hydratedWorkflow.nodes.map(node => ({
...node,
selected: false,
position: {
x: isFinite(node.position?.x) ? node.position.x : 0,
y: isFinite(node.position?.y) ? node.position.y : 0,
},
})),
edges: hydratedWorkflow.edges,
edgeStyle: hydratedWorkflow.edgeStyle || "angular",
groups: hydratedWorkflow.groups || {},

Loading…
Cancel
Save