Browse Source

feat(ENHANCE-002): auto-resize node when Parameters expands

- Add onExpandChange callback to ModelParameters component
- Remove max-height constraint from expanded parameters
- GenerateImageNode/GenerateVideoNode calculate new height based on parameter count
- Node height grows when expanded, shrinks when collapsed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
6b7ce83377
  1. 23
      src/components/nodes/GenerateImageNode.tsx
  2. 23
      src/components/nodes/GenerateVideoNode.tsx
  3. 10
      src/components/nodes/ModelParameters.tsx

23
src/components/nodes/GenerateImageNode.tsx

@ -1,7 +1,7 @@
"use client";
import { useCallback, useState, useEffect, useMemo } from "react";
import { Handle, Position, NodeProps, Node } from "@xyflow/react";
import { Handle, Position, NodeProps, Node, useReactFlow } from "@xyflow/react";
import { BaseNode } from "./BaseNode";
import { ModelParameters } from "./ModelParameters";
import { useWorkflowStore, saveNanoBananaDefaults } from "@/store/workflowStore";
@ -210,6 +210,26 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
[id, updateNodeData]
);
// Handle parameters expand/collapse - resize node height
const { setNodes } = useReactFlow();
const handleParametersExpandChange = useCallback(
(expanded: boolean, parameterCount: number) => {
// Each parameter row is ~24px, plus some padding
const parameterHeight = expanded ? Math.max(parameterCount * 28 + 16, 60) : 0;
const baseHeight = 300; // Default node height
const newHeight = baseHeight + parameterHeight;
setNodes((nodes) =>
nodes.map((node) =>
node.id === id
? { ...node, style: { ...node.style, height: newHeight } }
: node
)
);
},
[id, setNodes]
);
const handleClearImage = useCallback(() => {
updateNodeData(id, { outputImage: null, status: "idle", error: null });
}, [id, updateNodeData]);
@ -538,6 +558,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
provider={currentProvider}
parameters={nodeData.parameters || {}}
onParametersChange={handleParametersChange}
onExpandChange={handleParametersExpandChange}
/>
)}
</>

23
src/components/nodes/GenerateVideoNode.tsx

@ -1,7 +1,7 @@
"use client";
import { useCallback, useState, useEffect, useMemo } from "react";
import { Handle, Position, NodeProps, Node } from "@xyflow/react";
import { Handle, Position, NodeProps, Node, useReactFlow } from "@xyflow/react";
import { BaseNode } from "./BaseNode";
import { ModelParameters } from "./ModelParameters";
import { useWorkflowStore } from "@/store/workflowStore";
@ -122,6 +122,26 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
[id, updateNodeData]
);
// Handle parameters expand/collapse - resize node height
const { setNodes } = useReactFlow();
const handleParametersExpandChange = useCallback(
(expanded: boolean, parameterCount: number) => {
// Each parameter row is ~24px, plus some padding
const parameterHeight = expanded ? Math.max(parameterCount * 28 + 16, 60) : 0;
const baseHeight = 300; // Default node height
const newHeight = baseHeight + parameterHeight;
setNodes((nodes) =>
nodes.map((node) =>
node.id === id
? { ...node, style: { ...node.style, height: newHeight } }
: node
)
);
},
[id, setNodes]
);
const regenerateNode = useWorkflowStore((state) => state.regenerateNode);
const isRunning = useWorkflowStore((state) => state.isRunning);
@ -304,6 +324,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
provider={currentProvider}
parameters={nodeData.parameters || {}}
onParametersChange={handleParametersChange}
onExpandChange={handleParametersExpandChange}
/>
)}
</div>

10
src/components/nodes/ModelParameters.tsx

@ -10,6 +10,7 @@ interface ModelParametersProps {
provider: ProviderType;
parameters: Record<string, unknown>;
onParametersChange: (parameters: Record<string, unknown>) => void;
onExpandChange?: (expanded: boolean, parameterCount: number) => void;
}
/**
@ -22,6 +23,7 @@ export function ModelParameters({
provider,
parameters,
onParametersChange,
onExpandChange,
}: ModelParametersProps) {
const [schema, setSchema] = useState<ModelParameter[]>([]);
const [isLoading, setIsLoading] = useState(false);
@ -105,7 +107,11 @@ export function ModelParameters({
<div className="shrink-0">
{/* Collapsible header */}
<button
onClick={() => setIsExpanded(!isExpanded)}
onClick={() => {
const newExpanded = !isExpanded;
setIsExpanded(newExpanded);
onExpandChange?.(newExpanded, schema.length);
}}
className="w-full flex items-center justify-between text-[10px] text-neutral-400 hover:text-neutral-300 transition-colors py-0.5"
>
<span className="flex items-center gap-1">
@ -144,7 +150,7 @@ export function ModelParameters({
{/* Parameter inputs (when expanded) */}
{isExpanded && (
<div className="mt-1 space-y-1.5 max-h-[160px] overflow-y-auto">
<div className="mt-1 space-y-1.5">
{error ? (
<span className="text-[9px] text-red-400">{error}</span>
) : isLoading ? (

Loading…
Cancel
Save