Skip to content

Commit 365c88a

Browse files
committed
enum fixes for the schema builder
1 parent ba447ba commit 365c88a

File tree

2 files changed

+92
-24
lines changed

2 files changed

+92
-24
lines changed

src/ui/src/components/json-schema-builder/SchemaCanvas.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,16 @@ const SortableAttributeItem = ({
9797
};
9898

9999
const getConstBadge = () => {
100-
if (attribute.const === undefined) return null;
100+
// Check both attribute level and items level (for simple arrays)
101+
const hasConst = attribute.const !== undefined || (attribute.type === 'array' && attribute.items?.const !== undefined);
102+
if (!hasConst) return null;
101103
return <Badge color="blue">const</Badge>;
102104
};
103105

104106
const getEnumBadge = () => {
105-
if (!attribute.enum) return null;
107+
// Check both attribute level and items level (for simple arrays)
108+
const hasEnum = attribute.enum || (attribute.type === 'array' && attribute.items?.enum);
109+
if (!hasEnum) return null;
106110
return <Badge color="blue">enum</Badge>;
107111
};
108112

src/ui/src/components/json-schema-builder/constraints/ValueConstraints.jsx

Lines changed: 86 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,49 @@ const ValueConstraints = ({ attribute, onUpdate }) => {
88
const [constInput, setConstInput] = useState('');
99
const [enumInput, setEnumInput] = useState('');
1010

11+
// For arrays with simple item types (not $ref), enum/const should be on items, not the array itself
12+
const isSimpleArray = attribute.type === 'array' && attribute.items && !attribute.items.$ref;
13+
const effectiveType = isSimpleArray ? attribute.items?.type : attribute.type;
14+
15+
// Get enum value from the correct location (items for simple arrays, attribute otherwise)
16+
const currentEnum = isSimpleArray ? attribute.items?.enum : attribute.enum;
17+
const currentConst = isSimpleArray ? attribute.items?.const : attribute.const;
18+
1119
// Initialize local state from attribute values
1220
useEffect(() => {
13-
setConstInput(formatValueForInput(attribute.const));
14-
}, [attribute.const]);
21+
setConstInput(formatValueForInput(currentConst));
22+
}, [currentConst]);
1523

1624
// Initialize enum input as empty (it's only shown when no enum exists yet)
1725
useEffect(() => {
18-
if (!attribute.enum || attribute.enum.length === 0) {
26+
if (!currentEnum || currentEnum.length === 0) {
1927
setEnumInput('');
2028
}
21-
}, [attribute.enum]);
29+
}, [currentEnum]);
30+
31+
// Helper to update enum/const at the correct level (items for simple arrays)
32+
const updateValueConstraint = (updates) => {
33+
if (isSimpleArray) {
34+
// Place enum/const inside items for simple arrays
35+
onUpdate({
36+
items: {
37+
...attribute.items,
38+
...updates,
39+
},
40+
});
41+
} else {
42+
onUpdate(updates);
43+
}
44+
};
2245

2346
// Handle Const field blur - parse and update parent state
2447
const handleConstBlur = () => {
2548
if (!constInput) {
26-
onUpdate({ const: undefined });
49+
updateValueConstraint({ const: undefined });
2750
return;
2851
}
29-
const parsed = parseInputValue(constInput, attribute.type);
30-
onUpdate({ const: parsed });
52+
const parsed = parseInputValue(constInput, effectiveType);
53+
updateValueConstraint({ const: parsed });
3154
};
3255

3356
// Handle Enum field blur - parse and update parent state
@@ -36,66 +59,101 @@ const ValueConstraints = ({ attribute, onUpdate }) => {
3659
if (value) {
3760
try {
3861
const parsed = JSON.parse(`[${value}]`);
39-
onUpdate({ enum: parsed });
62+
updateValueConstraint({ enum: parsed });
4063
} catch {
4164
const enumValues = value
4265
.split(',')
4366
.map((v) => v.trim())
4467
.filter((v) => v);
45-
onUpdate({ enum: enumValues.length > 0 ? enumValues : undefined });
68+
updateValueConstraint({ enum: enumValues.length > 0 ? enumValues : undefined });
4669
}
4770
// Clear the input after successful processing
4871
setEnumInput('');
4972
}
5073
};
5174

75+
// Get placeholder examples based on effective type
76+
const getEnumPlaceholder = () => {
77+
switch (effectiveType) {
78+
case 'number':
79+
case 'integer':
80+
return 'e.g., 1, 2, 3';
81+
case 'boolean':
82+
return 'e.g., true, false';
83+
default:
84+
return 'e.g., active, pending, completed';
85+
}
86+
};
87+
88+
const getConstPlaceholder = () => {
89+
switch (effectiveType) {
90+
case 'number':
91+
case 'integer':
92+
return 'e.g., 42';
93+
case 'boolean':
94+
return 'e.g., true';
95+
default:
96+
return 'e.g., active';
97+
}
98+
};
99+
100+
// Build description with JSON Schema context
101+
const enumDescription = isSimpleArray
102+
? 'Allowed values for each item in the array (JSON Schema enum). Comma-separated list.'
103+
: 'Allowed values for this field (JSON Schema enum). Comma-separated list.';
104+
105+
const constDescription = isSimpleArray
106+
? 'Each item in the array must be exactly this value (JSON Schema const).'
107+
: 'Field must be exactly this value (JSON Schema const).';
108+
52109
return (
53110
<>
54-
<Header variant="h4">Value Constraints</Header>
111+
<Header variant="h4">Value Constraints (JSON Schema)</Header>
55112

56-
<FormField label="Const (Single Constant Value)" description="Field must be exactly this value">
113+
<FormField label="Const (Single Constant Value)" description={constDescription} constraintText={`Example: ${getConstPlaceholder()}`}>
57114
<Input
58115
value={constInput}
59116
onChange={({ detail }) => setConstInput(detail.value)}
60117
onBlur={handleConstBlur}
61-
placeholder='e.g., "active", 42, or JSON value'
62-
disabled={attribute.enum && attribute.enum.length > 0}
118+
placeholder={getConstPlaceholder()}
119+
disabled={currentEnum && currentEnum.length > 0}
63120
/>
64121
</FormField>
65122

66123
<FormField
67-
label="Enum Values (Multiple Allowed Values)"
68-
description="Comma-separated list of allowed values (mutually exclusive with const)"
124+
label="Enum (Allowed Values)"
125+
description={enumDescription}
126+
constraintText={`Example: ${getEnumPlaceholder()} - Values are comma-separated`}
69127
>
70-
{attribute.enum && attribute.enum.length > 0 ? (
128+
{currentEnum && currentEnum.length > 0 ? (
71129
<SpaceBetween size="xs">
72130
<TokenGroup
73-
items={attribute.enum.map((val) => ({
131+
items={currentEnum.map((val) => ({
74132
label: typeof val === 'object' ? JSON.stringify(val) : String(val),
75133
dismissLabel: `Remove ${val}`,
76134
}))}
77135
onDismiss={({ detail: { itemIndex } }) => {
78-
const newEnum = [...(attribute.enum || [])];
136+
const newEnum = [...(currentEnum || [])];
79137
newEnum.splice(itemIndex, 1);
80-
onUpdate({ enum: newEnum.length > 0 ? newEnum : undefined });
138+
updateValueConstraint({ enum: newEnum.length > 0 ? newEnum : undefined });
81139
}}
82140
/>
83141
<Button
84142
variant="link"
85143
onClick={() => {
86-
onUpdate({ enum: undefined });
144+
updateValueConstraint({ enum: undefined });
87145
}}
88146
>
89147
Clear all enum values
90148
</Button>
91149
</SpaceBetween>
92150
) : (
93151
<Input
94-
placeholder="value1, value2, value3"
152+
placeholder={getEnumPlaceholder()}
95153
value={enumInput}
96154
onChange={({ detail }) => setEnumInput(detail.value)}
97155
onBlur={handleEnumBlur}
98-
disabled={attribute.const !== undefined}
156+
disabled={currentConst !== undefined}
99157
/>
100158
)}
101159
</FormField>
@@ -108,6 +166,12 @@ ValueConstraints.propTypes = {
108166
type: PropTypes.string,
109167
const: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool, PropTypes.object, PropTypes.array]),
110168
enum: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool, PropTypes.object, PropTypes.array])),
169+
items: PropTypes.shape({
170+
type: PropTypes.string,
171+
$ref: PropTypes.string,
172+
const: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool, PropTypes.object, PropTypes.array]),
173+
enum: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool, PropTypes.object, PropTypes.array])),
174+
}),
111175
}).isRequired,
112176
onUpdate: PropTypes.func.isRequired,
113177
};

0 commit comments

Comments
 (0)