Browse Source

feat(06-04): add parameter validation and reset on model/provider change

- Add inline validation for number/integer parameters with min/max bounds
- Show red border and error text for out-of-range values
- Clear parameters when switching provider or model (schemas differ)
- Validation shows specific constraints (Min/Max values, integer requirement)
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
609ce62f0a
  1. 9
      src/components/nodes/GenerateImageNode.tsx
  2. 6
      src/components/nodes/GenerateVideoNode.tsx
  3. 29
      src/components/nodes/ModelParameters.tsx

9
src/components/nodes/GenerateImageNode.tsx

@ -125,7 +125,8 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
modelId: nodeData.model || "nano-banana-pro",
displayName: GEMINI_IMAGE_MODELS.find(m => m.value === (nodeData.model || "nano-banana-pro"))?.label || "Nano Banana Pro",
};
updateNodeData(id, { selectedModel: newSelectedModel });
// Clear parameters when switching providers (different providers have different schemas)
updateNodeData(id, { selectedModel: newSelectedModel, parameters: {} });
} else {
// Set placeholder for external provider
const newSelectedModel: SelectedModel = {
@ -133,7 +134,8 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
modelId: "",
displayName: "Select model...",
};
updateNodeData(id, { selectedModel: newSelectedModel });
// Clear parameters when switching providers
updateNodeData(id, { selectedModel: newSelectedModel, parameters: {} });
}
},
[id, nodeData.model, updateNodeData]
@ -150,7 +152,8 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
modelId: model.id,
displayName: model.name,
};
updateNodeData(id, { selectedModel: newSelectedModel });
// Clear parameters when changing models (different models have different schemas)
updateNodeData(id, { selectedModel: newSelectedModel, parameters: {} });
}
},
[id, currentProvider, externalModels, updateNodeData]

6
src/components/nodes/GenerateVideoNode.tsx

@ -87,7 +87,8 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
modelId: "",
displayName: "Select model...",
};
updateNodeData(id, { selectedModel: newSelectedModel });
// Clear parameters when switching providers (different providers have different schemas)
updateNodeData(id, { selectedModel: newSelectedModel, parameters: {} });
},
[id, updateNodeData]
);
@ -103,7 +104,8 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
modelId: model.id,
displayName: model.name,
};
updateNodeData(id, { selectedModel: newSelectedModel });
// Clear parameters when changing models (different models have different schemas)
updateNodeData(id, { selectedModel: newSelectedModel, parameters: {} });
}
},
[id, currentProvider, externalModels, updateNodeData]

29
src/components/nodes/ModelParameters.tsx

@ -227,8 +227,24 @@ function ParameterInput({ param, value, onChange }: ParameterInputProps) {
}
if (param.type === "number" || param.type === "integer") {
// Number: render as number input
// Number: render as number input with validation
const numValue = value !== undefined ? Number(value) : "";
const hasMin = param.minimum !== undefined;
const hasMax = param.maximum !== undefined;
// Validate current value against constraints
let validationError: string | null = null;
if (value !== undefined && value !== "" && !isNaN(Number(value))) {
const num = Number(value);
if (hasMin && num < param.minimum!) {
validationError = `Min: ${param.minimum}`;
} else if (hasMax && num > param.maximum!) {
validationError = `Max: ${param.maximum}`;
} else if (param.type === "integer" && !Number.isInteger(num)) {
validationError = "Must be integer";
}
}
return (
<div className="flex flex-col gap-0.5">
<label
@ -236,7 +252,7 @@ function ParameterInput({ param, value, onChange }: ParameterInputProps) {
title={param.description || undefined}
>
{displayName}
{param.minimum !== undefined && param.maximum !== undefined && (
{hasMin && hasMax && (
<span className="text-neutral-500">
({param.minimum}-{param.maximum})
</span>
@ -258,8 +274,15 @@ function ParameterInput({ param, value, onChange }: ParameterInputProps) {
}
}}
placeholder={param.default !== undefined ? `Default: ${param.default}` : undefined}
className="w-full text-[9px] py-0.5 px-1 border border-neutral-700 rounded bg-neutral-900/50 focus:outline-none focus:ring-1 focus:ring-neutral-600 text-neutral-300 placeholder:text-neutral-600"
className={`w-full text-[9px] py-0.5 px-1 border rounded bg-neutral-900/50 focus:outline-none focus:ring-1 text-neutral-300 placeholder:text-neutral-600 ${
validationError
? "border-red-500 focus:ring-red-500"
: "border-neutral-700 focus:ring-neutral-600"
}`}
/>
{validationError && (
<span className="text-[8px] text-red-400">{validationError}</span>
)}
</div>
);
}

Loading…
Cancel
Save