Skip to content

Commit 15067c9

Browse files
committed
Policy Field: Add MaxLen, Required Priority and Fix Decimal issues
1 parent 0239de6 commit 15067c9

5 files changed

Lines changed: 59 additions & 7 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-dcm': patch
3+
---
4+
5+
Fix policy form validation for Description and Priority fields.
6+
7+
- Add a 255-character max-length Yup rule to the Description field, with inline error
8+
feedback matching the Display Name pattern (validation error on blur rather than
9+
hard-blocking input at the DOM level).
10+
- Add `.integer()` and `.required()` Yup rules to the Priority field so decimal values
11+
(e.g. 500.5) and an empty field are rejected with an explicit error message instead of
12+
silently coercing to an integer or defaulting to 500.
13+
- Add `step={1}` to the Priority number input and block `.`/`e`/`E` characters via
14+
`onKeyDown` and `onChange` guards to prevent decimal strings from bypassing the Yup
15+
integer check through JavaScript's `Number()` coercion.
16+
- Update the Priority label to "Priority \*" to indicate it is a required field.

workspaces/dcm/plugins/dcm/src/pages/policies/PoliciesTabContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export function PoliciesTabContent() {
172172
title: 'Enabled',
173173
field: 'enabled',
174174
render: p => {
175-
const isEnabled = p.enabled === true;
175+
const isEnabled = p.enabled ?? true;
176176
return (
177177
<Chip
178178
label={isEnabled ? 'Yes' : 'No'}
@@ -204,7 +204,7 @@ export function PoliciesTabContent() {
204204
render: p => {
205205
const id = p.id ?? '';
206206
const isToggling = togglingIds.has(id);
207-
const isEnabled = p.enabled !== false;
207+
const isEnabled = p.enabled ?? true;
208208
return (
209209
<Box className={classes.actionsCellBox}>
210210
<Tooltip

workspaces/dcm/plugins/dcm/src/pages/policies/components/PolicyFormFields.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,15 @@ export function PolicyFormFields({
7171

7272
<TextField
7373
label="Description"
74-
helperText="Optional — describe the purpose of this policy"
74+
helperText={
75+
err('description') ?? 'Optional — describe the purpose of this policy'
76+
}
77+
error={Boolean(err('description'))}
7578
value={form.description}
7679
onChange={e =>
7780
setForm(prev => ({ ...prev, description: e.target.value }))
7881
}
82+
onBlur={() => touch('description')}
7983
fullWidth
8084
variant="outlined"
8185
size="small"
@@ -111,19 +115,29 @@ export function PolicyFormFields({
111115
</FormControl>
112116

113117
<TextField
114-
label="Priority"
118+
label="Priority *"
115119
helperText={
116-
err('priority') ?? '1 (highest) – 1000 (lowest), default 500'
120+
err('priority') ??
121+
'1 (highest) – 1000 (lowest), default 500 — must be unique per policy type'
117122
}
118123
error={Boolean(err('priority'))}
119124
value={form.priority}
120-
onChange={e => setForm(prev => ({ ...prev, priority: e.target.value }))}
125+
onChange={e => {
126+
if (/^\d*$/.test(e.target.value)) {
127+
setForm(prev => ({ ...prev, priority: e.target.value }));
128+
}
129+
}}
130+
onKeyDown={e => {
131+
if (e.key === '.' || e.key === 'e' || e.key === 'E') {
132+
e.preventDefault();
133+
}
134+
}}
121135
onBlur={() => touch('priority')}
122136
fullWidth
123137
variant="outlined"
124138
size="small"
125139
type="number"
126-
inputProps={{ min: 1, max: 1000 }}
140+
inputProps={{ min: 1, max: 1000, step: 1 }}
127141
/>
128142

129143
<TextField

workspaces/dcm/plugins/dcm/src/pages/policies/policyFormTypes.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ describe('validatePolicyForm', () => {
5252

5353
const ok = validatePolicyForm({ ...valid(), priority: '500' });
5454
expect(ok.priority).toBeUndefined();
55+
56+
const decimal = validatePolicyForm({ ...valid(), priority: '500.5' });
57+
expect(decimal.priority).toBeDefined();
58+
59+
const empty = validatePolicyForm({ ...valid(), priority: '' });
60+
expect(empty.priority).toBeDefined();
61+
});
62+
63+
it('rejects description longer than 255 characters', () => {
64+
const errors = validatePolicyForm({
65+
...valid(),
66+
description: 'a'.repeat(256),
67+
});
68+
expect(errors.description).toBeDefined();
69+
70+
const ok = validatePolicyForm({ ...valid(), description: 'a'.repeat(255) });
71+
expect(ok.description).toBeUndefined();
5572
});
5673

5774
it('accepts only GLOBAL or USER as policy_type', () => {

workspaces/dcm/plugins/dcm/src/pages/policies/policyFormTypes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,18 @@ const policySchema = yup.object({
3737
.required('Display name is required')
3838
.min(1, 'Display name cannot be empty')
3939
.max(255, 'Display name must be at most 255 characters'),
40+
description: yup
41+
.string()
42+
.max(255, 'Description must be at most 255 characters'),
4043
policy_type: yup
4144
.string()
4245
.required('Policy type is required')
4346
.oneOf(['GLOBAL', 'USER'], 'Must be GLOBAL or USER'),
4447
priority: yup
4548
.number()
4649
.typeError('Priority must be a number')
50+
.required('Priority is required')
51+
.integer('Priority must be a whole number')
4752
.min(1, 'Priority must be at least 1')
4853
.max(1000, 'Priority must be at most 1000'),
4954
rego_code: yup

0 commit comments

Comments
 (0)