Skip to content

Commit 449df69

Browse files
Merge pull request #1378 from CrowleyRajapakse/new_main
Fix UI issues in admin and devportal for custom keymanager configs
2 parents cb1b249 + 656d12d commit 449df69

5 files changed

Lines changed: 110 additions & 13 deletions

File tree

portals/admin/src/main/webapp/source/src/app/components/KeyManagers/AddEditKeyManager.jsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,13 @@ function AddEditKeyManager(props) {
400400
}
401401
break;
402402
case 'keyconfig':
403+
if (fieldValue === '' || (Array.isArray(fieldValue) && !fieldValue.length)) {
404+
error = intl.formatMessage({
405+
id: 'KeyManagers.AddEditKeyManager.is.empty.error.key.config',
406+
defaultMessage: 'Required field is empty.',
407+
});
408+
}
409+
break;
403410
case 'displayName':
404411
case 'issuer':
405412
case 'clientRegistrationEndpoint':
@@ -472,7 +479,9 @@ function AddEditKeyManager(props) {
472479
const checkConfigErrors = (configurations) => {
473480
for (const config of configurations) {
474481
if (config.required && (!additionalProperties[config.name]
475-
|| additionalProperties[config.name] === '')) {
482+
|| additionalProperties[config.name] === ''
483+
|| (Array.isArray(additionalProperties[config.name])
484+
&& !additionalProperties[config.name].length))) {
476485
return true;
477486
}
478487

portals/admin/src/main/webapp/source/src/app/components/KeyManagers/KeyManagerConfiguration.jsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ export default function KeyManagerConfiguration(props) {
131131
} else {
132132
finalValue = [];
133133
}
134+
// Coerce to an array in case the value was seeded/stored as a comma-separated string.
135+
if (!Array.isArray(finalValue)) {
136+
finalValue = (typeof finalValue === 'string' && finalValue !== '')
137+
? finalValue.split(',').map((item) => item.trim()) : [];
138+
} else {
139+
finalValue = [...finalValue];
140+
}
134141
if (e.target.checked) {
135142
finalValue.push(value);
136143
} else {
@@ -238,7 +245,15 @@ export default function KeyManagerConfiguration(props) {
238245
const defaultVal = keymanagerConnectorConfiguration.default
239246
|| keymanagerConnectorConfiguration.defaultValue;
240247
if (typeof defaultVal === 'string'
241-
&& ['input', 'select', 'options', 'dropdown'].includes(keymanagerConnectorConfiguration.type)
248+
&& keymanagerConnectorConfiguration.type === 'select'
249+
) {
250+
// 'select' renders a checkbox group, so its value must be an array.
251+
setAdditionalProperties(
252+
keymanagerConnectorConfiguration.name,
253+
defaultVal.split(',').map((item) => item.trim()),
254+
);
255+
} else if (typeof defaultVal === 'string'
256+
&& ['input', 'options', 'dropdown'].includes(keymanagerConnectorConfiguration.type)
242257
) {
243258
onChange({
244259
target: {
@@ -314,7 +329,13 @@ export default function KeyManagerConfiguration(props) {
314329
);
315330
} else if (keymanagerConnectorConfiguration.type === 'select') {
316331
return (
317-
<FormControl variant='standard' component='fieldset' disabled={disabled}>
332+
<FormControl
333+
variant='standard'
334+
component='fieldset'
335+
disabled={disabled}
336+
error={keymanagerConnectorConfiguration.required
337+
&& Boolean(hasErrors('keyconfig', value, validating))}
338+
>
318339
<FormLabel component='legend'>
319340
<span>
320341
{keymanagerConnectorConfiguration.label}
@@ -338,6 +359,11 @@ export default function KeyManagerConfiguration(props) {
338359
/>
339360
))}
340361
</FormGroup>
362+
<FormHelperText>
363+
{(keymanagerConnectorConfiguration.required
364+
&& hasErrors('keyconfig', value, validating))
365+
|| keymanagerConnectorConfiguration.tooltip}
366+
</FormHelperText>
341367
</FormControl>
342368
);
343369
} else if (keymanagerConnectorConfiguration.type === 'checkbox') {
@@ -370,7 +396,13 @@ export default function KeyManagerConfiguration(props) {
370396
);
371397
} else if (keymanagerConnectorConfiguration.type === 'options') {
372398
return (
373-
<FormControl variant='standard' component='fieldset' disabled={disabled}>
399+
<FormControl
400+
variant='standard'
401+
component='fieldset'
402+
disabled={disabled}
403+
error={keymanagerConnectorConfiguration.required
404+
&& Boolean(hasErrors('keyconfig', value, validating))}
405+
>
374406
<FormLabel component='legend'>
375407
<span>
376408
{keymanagerConnectorConfiguration.label}
@@ -398,6 +430,11 @@ export default function KeyManagerConfiguration(props) {
398430
);
399431
})}
400432
</RadioGroup>
433+
<FormHelperText>
434+
{(keymanagerConnectorConfiguration.required
435+
&& hasErrors('keyconfig', value, validating))
436+
|| keymanagerConnectorConfiguration.tooltip}
437+
</FormHelperText>
401438
</FormControl>
402439
);
403440
} else if (keymanagerConnectorConfiguration.type === 'dropdown') {

portals/devportal/src/main/webapp/source/src/app/components/Shared/AppsAndKeys/AppConfiguration.jsx

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,22 @@ const AppConfiguration = (props) => {
196196
},
197197
});
198198

199+
/**
200+
* Checks whether a required field is empty.
201+
* @param {*} fieldValue the current value of the field.
202+
* @returns {string|boolean} the error message when empty, otherwise false.
203+
*/
204+
const hasMandatoryError = (fieldValue) => {
205+
let error = false;
206+
if (fieldValue === '' || (Array.isArray(fieldValue) && !fieldValue.length)) {
207+
error = props.intl.formatMessage({
208+
defaultMessage: 'Required field is empty',
209+
id: 'Shared.AppsAndKeys.KeyConfCiguration.required.empty.error',
210+
});
211+
}
212+
return error;
213+
};
214+
199215
/**
200216
* This method is used to handle the updating of key generation
201217
* request object.
@@ -211,7 +227,8 @@ const AppConfiguration = (props) => {
211227
const result = validateConstraint(newValue, constraint, props.intl, constraintMessages);
212228
setConstraintError(result.valid ? '' : result.message);
213229
if (onValidationError) {
214-
onValidationError(config.name, !result.valid);
230+
const mandatoryInvalid = config.required && Boolean(hasMandatoryError(newValue));
231+
onValidationError(config.name, !result.valid || mandatoryInvalid);
215232
}
216233

217234
handleChange('additionalProperties', event);
@@ -244,7 +261,11 @@ const AppConfiguration = (props) => {
244261
setIsOrgWideAppUpdateEnabled(orgWideAppUpdateEnabled);
245262
// Validate the values against constraint on load
246263
if (onValidationError) {
247-
onValidationError(config.name, !validateConstraint(String(previousValue ?? ''), config.constraint, null, null).valid);
264+
const constraintInvalid = !validateConstraint(
265+
String(previousValue ?? ''), config.constraint, null, null,
266+
).valid;
267+
const mandatoryInvalid = config.required && Boolean(hasMandatoryError(previousValue));
268+
onValidationError(config.name, constraintInvalid || mandatoryInvalid);
248269
}
249270
}, [previousValue, settingsContext]);
250271

@@ -274,7 +295,10 @@ const AppConfiguration = (props) => {
274295
value={selectedValue}
275296
name={config.name}
276297
onChange={e => handleAppRequestChange(e)}
277-
helperText={getAppConfigToolTip()}
298+
required={config.required}
299+
error={config.required && Boolean(hasMandatoryError(selectedValue))}
300+
helperText={(config.required && hasMandatoryError(selectedValue))
301+
|| getAppConfigToolTip()}
278302
margin='dense'
279303
variant='outlined'
280304
size='small'
@@ -336,7 +360,14 @@ const AppConfiguration = (props) => {
336360
</>
337361
) : (
338362
<>
339-
<FormControl variant="outlined" className={classes.formControl} fullWidth error={!!constraintError}>
363+
<FormControl
364+
variant="outlined"
365+
className={classes.formControl}
366+
fullWidth
367+
required={config.required}
368+
error={!!constraintError
369+
|| (config.required && Boolean(hasMandatoryError(selectedValue)))}
370+
>
340371
<InputLabel id="multi-select-label">{config.label}</InputLabel>
341372
<Select
342373
variant="standard"
@@ -372,7 +403,11 @@ const AppConfiguration = (props) => {
372403
</MenuItem>
373404
))}
374405
</Select>
375-
<FormHelperText>{getAppConfigToolTip()}</FormHelperText>
406+
<FormHelperText>
407+
{constraintError
408+
|| (config.required && hasMandatoryError(selectedValue))
409+
|| getAppConfigToolTip()}
410+
</FormHelperText>
376411
</FormControl>
377412
</>
378413
) : (config.type === 'input' && config.multiple === true) ? (
@@ -421,8 +456,12 @@ const AppConfiguration = (props) => {
421456
value={selectedValue}
422457
name={config.name}
423458
onChange={e => handleAppRequestChange(e)}
424-
error={!!constraintError}
425-
helperText={constraintError || getAppConfigToolTip()}
459+
required={config.required}
460+
error={!!constraintError
461+
|| (config.required && Boolean(hasMandatoryError(selectedValue)))}
462+
helperText={constraintError
463+
|| (config.required && hasMandatoryError(selectedValue))
464+
|| getAppConfigToolTip()}
426465
FormHelperTextProps={constraintError ? { error: true } : {}}
427466
margin='dense'
428467
size='small'

portals/devportal/src/main/webapp/source/src/app/components/Shared/AppsAndKeys/KeyConfiguration.jsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,14 @@ const KeyConfiguration = (props) => {
346346
if (config.multiple && typeof defaultValue === 'string' && defaultValue === '') {
347347
defaultValue = [];
348348
}
349-
return isPreviousValueSet ? additionalProperties[config.name] : defaultValue;
349+
const previousValue = isPreviousValueSet ? additionalProperties[config.name] : defaultValue;
350+
// A multi-select field must always resolve to an array so the multi-select renders correctly,
351+
// even if the stored/default value arrives as a comma-separated string.
352+
if (config.type === 'select' && config.multiple && !Array.isArray(previousValue)) {
353+
return (typeof previousValue === 'string' && previousValue !== '')
354+
? previousValue.split(',').map((item) => item.trim()) : [];
355+
}
356+
return previousValue;
350357
};
351358
/**
352359
*

portals/devportal/src/main/webapp/source/src/app/components/Shared/AppsAndKeys/TokenManager.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,12 @@ class TokenManager extends React.Component {
334334
const additionalProperties = {};
335335

336336
applicationConfiguration.forEach((confItem) => {
337-
additionalProperties[confItem.name] = confItem.default || '';
337+
if (confItem.type === 'select' && confItem.multiple) {
338+
additionalProperties[confItem.name] = (confItem.default
339+
&& confItem.default.split(',').map((item) => item.trim())) || [];
340+
} else {
341+
additionalProperties[confItem.name] = confItem.default || '';
342+
}
338343
});
339344
return additionalProperties;
340345
}

0 commit comments

Comments
 (0)