From 365c88ad0b2543d48275c9207a67cc3ed64965cf Mon Sep 17 00:00:00 2001 From: "Kazmer, Nagy-Betegh" Date: Wed, 3 Dec 2025 15:04:00 +0000 Subject: [PATCH 1/7] enum fixes for the schema builder --- .../json-schema-builder/SchemaCanvas.jsx | 8 +- .../constraints/ValueConstraints.jsx | 108 ++++++++++++++---- 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/src/ui/src/components/json-schema-builder/SchemaCanvas.jsx b/src/ui/src/components/json-schema-builder/SchemaCanvas.jsx index a3b75de82..51502e5a7 100644 --- a/src/ui/src/components/json-schema-builder/SchemaCanvas.jsx +++ b/src/ui/src/components/json-schema-builder/SchemaCanvas.jsx @@ -97,12 +97,16 @@ const SortableAttributeItem = ({ }; const getConstBadge = () => { - if (attribute.const === undefined) return null; + // Check both attribute level and items level (for simple arrays) + const hasConst = attribute.const !== undefined || (attribute.type === 'array' && attribute.items?.const !== undefined); + if (!hasConst) return null; return const; }; const getEnumBadge = () => { - if (!attribute.enum) return null; + // Check both attribute level and items level (for simple arrays) + const hasEnum = attribute.enum || (attribute.type === 'array' && attribute.items?.enum); + if (!hasEnum) return null; return enum; }; diff --git a/src/ui/src/components/json-schema-builder/constraints/ValueConstraints.jsx b/src/ui/src/components/json-schema-builder/constraints/ValueConstraints.jsx index d08e9541f..a9b262105 100644 --- a/src/ui/src/components/json-schema-builder/constraints/ValueConstraints.jsx +++ b/src/ui/src/components/json-schema-builder/constraints/ValueConstraints.jsx @@ -8,26 +8,49 @@ const ValueConstraints = ({ attribute, onUpdate }) => { const [constInput, setConstInput] = useState(''); const [enumInput, setEnumInput] = useState(''); + // For arrays with simple item types (not $ref), enum/const should be on items, not the array itself + const isSimpleArray = attribute.type === 'array' && attribute.items && !attribute.items.$ref; + const effectiveType = isSimpleArray ? attribute.items?.type : attribute.type; + + // Get enum value from the correct location (items for simple arrays, attribute otherwise) + const currentEnum = isSimpleArray ? attribute.items?.enum : attribute.enum; + const currentConst = isSimpleArray ? attribute.items?.const : attribute.const; + // Initialize local state from attribute values useEffect(() => { - setConstInput(formatValueForInput(attribute.const)); - }, [attribute.const]); + setConstInput(formatValueForInput(currentConst)); + }, [currentConst]); // Initialize enum input as empty (it's only shown when no enum exists yet) useEffect(() => { - if (!attribute.enum || attribute.enum.length === 0) { + if (!currentEnum || currentEnum.length === 0) { setEnumInput(''); } - }, [attribute.enum]); + }, [currentEnum]); + + // Helper to update enum/const at the correct level (items for simple arrays) + const updateValueConstraint = (updates) => { + if (isSimpleArray) { + // Place enum/const inside items for simple arrays + onUpdate({ + items: { + ...attribute.items, + ...updates, + }, + }); + } else { + onUpdate(updates); + } + }; // Handle Const field blur - parse and update parent state const handleConstBlur = () => { if (!constInput) { - onUpdate({ const: undefined }); + updateValueConstraint({ const: undefined }); return; } - const parsed = parseInputValue(constInput, attribute.type); - onUpdate({ const: parsed }); + const parsed = parseInputValue(constInput, effectiveType); + updateValueConstraint({ const: parsed }); }; // Handle Enum field blur - parse and update parent state @@ -36,54 +59,89 @@ const ValueConstraints = ({ attribute, onUpdate }) => { if (value) { try { const parsed = JSON.parse(`[${value}]`); - onUpdate({ enum: parsed }); + updateValueConstraint({ enum: parsed }); } catch { const enumValues = value .split(',') .map((v) => v.trim()) .filter((v) => v); - onUpdate({ enum: enumValues.length > 0 ? enumValues : undefined }); + updateValueConstraint({ enum: enumValues.length > 0 ? enumValues : undefined }); } // Clear the input after successful processing setEnumInput(''); } }; + // Get placeholder examples based on effective type + const getEnumPlaceholder = () => { + switch (effectiveType) { + case 'number': + case 'integer': + return 'e.g., 1, 2, 3'; + case 'boolean': + return 'e.g., true, false'; + default: + return 'e.g., active, pending, completed'; + } + }; + + const getConstPlaceholder = () => { + switch (effectiveType) { + case 'number': + case 'integer': + return 'e.g., 42'; + case 'boolean': + return 'e.g., true'; + default: + return 'e.g., active'; + } + }; + + // Build description with JSON Schema context + const enumDescription = isSimpleArray + ? 'Allowed values for each item in the array (JSON Schema enum). Comma-separated list.' + : 'Allowed values for this field (JSON Schema enum). Comma-separated list.'; + + const constDescription = isSimpleArray + ? 'Each item in the array must be exactly this value (JSON Schema const).' + : 'Field must be exactly this value (JSON Schema const).'; + return ( <> -
Value Constraints
+
Value Constraints (JSON Schema)
- + setConstInput(detail.value)} onBlur={handleConstBlur} - placeholder='e.g., "active", 42, or JSON value' - disabled={attribute.enum && attribute.enum.length > 0} + placeholder={getConstPlaceholder()} + disabled={currentEnum && currentEnum.length > 0} /> - {attribute.enum && attribute.enum.length > 0 ? ( + {currentEnum && currentEnum.length > 0 ? ( ({ + items={currentEnum.map((val) => ({ label: typeof val === 'object' ? JSON.stringify(val) : String(val), dismissLabel: `Remove ${val}`, }))} onDismiss={({ detail: { itemIndex } }) => { - const newEnum = [...(attribute.enum || [])]; + const newEnum = [...(currentEnum || [])]; newEnum.splice(itemIndex, 1); - onUpdate({ enum: newEnum.length > 0 ? newEnum : undefined }); + updateValueConstraint({ enum: newEnum.length > 0 ? newEnum : undefined }); }} />