Skip to content

Commit bb9c562

Browse files
committed
Wizard: Show error with duplicated values
This show an error when user imports duplicate values to a `<LabelInput>` field.
1 parent a92d087 commit bb9c562

3 files changed

Lines changed: 136 additions & 25 deletions

File tree

src/Components/CreateImageWizard/LabelInput.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,36 @@ const LabelInput = ({
4848
const dispatch = useAppDispatch();
4949

5050
const [inputValue, setInputValue] = useState('');
51-
const [errorText, setErrorText] = useState(stepValidation.errors[fieldName]);
51+
const [onStepInputErrorText, setOnStepInputErrorText] = useState('');
52+
let [invalidImports, duplicateImports] = ['', ''];
53+
54+
if (stepValidation.errors[fieldName]) {
55+
[invalidImports, duplicateImports] =
56+
stepValidation.errors[fieldName].split('|');
57+
}
5258

5359
const onTextInputChange = (
5460
_event: React.FormEvent<HTMLInputElement>,
5561
value: string
5662
) => {
5763
setInputValue(value);
58-
setErrorText('');
64+
setOnStepInputErrorText('');
5965
};
6066

6167
const addItem = (value: string) => {
6268
if (list?.includes(value) || requiredList?.includes(value)) {
63-
setErrorText(`${item} already exists.`);
69+
setOnStepInputErrorText(`${item} already exists.`);
6470
return;
6571
}
6672

6773
if (!validator(value)) {
68-
setErrorText('Invalid format.');
74+
setOnStepInputErrorText('Invalid format.');
6975
return;
7076
}
7177

7278
dispatch(addAction(value));
7379
setInputValue('');
74-
setErrorText('');
80+
setOnStepInputErrorText('');
7581
};
7682

7783
const handleKeyDown = (e: React.KeyboardEvent, value: string) => {
@@ -87,14 +93,18 @@ const LabelInput = ({
8793

8894
const handleRemoveItem = (e: React.MouseEvent, value: string) => {
8995
dispatch(removeAction(value));
90-
setErrorText('');
9196
};
9297

9398
const handleClear = () => {
9499
setInputValue('');
95-
setErrorText('');
100+
setOnStepInputErrorText('');
96101
};
97102

103+
const errors = [];
104+
if (onStepInputErrorText) errors.push(onStepInputErrorText);
105+
if (invalidImports) errors.push(invalidImports);
106+
if (duplicateImports) errors.push(duplicateImports);
107+
98108
return (
99109
<>
100110
<TextInputGroup>
@@ -125,9 +135,13 @@ const LabelInput = ({
125135
/>
126136
</TextInputGroupUtilities>
127137
</TextInputGroup>
128-
{errorText && (
138+
{errors.length > 0 && (
129139
<HelperText>
130-
<HelperTextItem variant={'error'}>{errorText}</HelperTextItem>
140+
{errors.map((error, index) => (
141+
<HelperTextItem key={index} variant={'error'}>
142+
{error}
143+
</HelperTextItem>
144+
))}
131145
</HelperText>
132146
)}
133147
{requiredList && requiredList.length > 0 && (
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const getListOfDuplicates = (list: string[]) => {
2+
const duplicates = list.filter((item, index) => list.indexOf(item) !== index);
3+
const uniqueDuplicates = [...new Set(duplicates)];
4+
5+
return uniqueDuplicates;
6+
};

src/Components/CreateImageWizard/utilities/useValidation.tsx

Lines changed: 107 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import React, { useEffect, useState } from 'react';
33
import { CheckCircleIcon } from '@patternfly/react-icons';
44
import { jwtDecode, JwtPayload } from 'jwt-decode';
55

6+
import { getListOfDuplicates } from './getListOfDuplicates';
7+
68
import { UNIQUE_VALIDATION_DELAY } from '../../../constants';
79
import { useLazyGetBlueprintsQuery } from '../../../store/backendApi';
810
import { useAppSelector } from '../../../store/hooks';
@@ -281,14 +283,26 @@ export function useTimezoneValidation(): StepValidation {
281283
}
282284
}
283285

286+
const duplicateNtpServers = getListOfDuplicates(ntpServers || []);
287+
284288
const timezoneError =
285289
timezone && !timezones.includes(timezone) ? 'Unknown timezone' : '';
286290
const ntpServersError =
287291
invalidServers.length > 0 ? `Invalid NTP servers: ${invalidServers}` : '';
292+
const duplicateNtpServersError =
293+
duplicateNtpServers.length > 0
294+
? `Includes duplicate NTP servers: ${duplicateNtpServers.join(', ')}`
295+
: '';
288296

289297
return {
290-
errors: { timezone: timezoneError, ntpServers: ntpServersError },
291-
disabledNext: timezoneError !== '' || invalidServers.length > 0,
298+
errors: {
299+
timezone: timezoneError,
300+
ntpServers: ntpServersError + '|' + duplicateNtpServersError,
301+
},
302+
disabledNext:
303+
timezoneError !== '' ||
304+
invalidServers.length > 0 ||
305+
duplicateNtpServers.length > 0,
292306
};
293307
}
294308

@@ -363,15 +377,28 @@ export function useKernelValidation(): StepValidation {
363377
}
364378
}
365379

380+
const duplicateKernelArgs = getListOfDuplicates(kernel.append);
381+
366382
const kernelNameError =
367383
kernel.name && !isKernelNameValid(kernel.name) ? 'Invalid format.' : '';
368384

369385
const kernelAppendError =
370386
invalidArgs.length > 0 ? `Invalid kernel arguments: ${invalidArgs}` : '';
371387

388+
const duplicateKernelArgsError =
389+
duplicateKernelArgs.length > 0
390+
? `Includes duplicate kernel arguments: ${duplicateKernelArgs.join(', ')}`
391+
: '';
392+
372393
return {
373-
errors: { kernel: kernelNameError, kernelAppend: kernelAppendError },
374-
disabledNext: kernelNameError !== '' || kernelAppendError !== '',
394+
errors: {
395+
kernel: kernelNameError,
396+
kernelAppend: kernelAppendError + '|' + duplicateKernelArgsError,
397+
},
398+
disabledNext:
399+
kernelNameError !== '' ||
400+
kernelAppendError !== '' ||
401+
duplicateKernelArgs.length > 0,
375402
};
376403
}
377404

@@ -405,8 +432,32 @@ export function useFirewallValidation(): StepValidation {
405432
}
406433
}
407434

435+
const duplicatePorts = getListOfDuplicates(firewall.ports);
436+
const duplicateDisabledServices = getListOfDuplicates(
437+
firewall.services.disabled
438+
);
439+
const duplicateEnabledServices = getListOfDuplicates(
440+
firewall.services.enabled
441+
);
442+
408443
const portsError =
409444
invalidPorts.length > 0 ? `Invalid ports: ${invalidPorts}` : '';
445+
const duplicatePortsError =
446+
duplicatePorts.length > 0
447+
? `Includes duplicate ports: ${duplicatePorts.join(', ')}`
448+
: '';
449+
const duplicateDisabledServicesError =
450+
duplicateDisabledServices.length > 0
451+
? `Includes duplicate disabled services: ${duplicateDisabledServices.join(
452+
', '
453+
)}`
454+
: '';
455+
const duplicateEnabledServicesError =
456+
duplicateEnabledServices.length > 0
457+
? `Includes duplicate enabled services: ${duplicateEnabledServices.join(
458+
', '
459+
)}`
460+
: '';
410461
const disabledServicesError =
411462
invalidDisabled.length > 0
412463
? `Invalid disabled services: ${invalidDisabled}`
@@ -418,14 +469,19 @@ export function useFirewallValidation(): StepValidation {
418469

419470
return {
420471
errors: {
421-
ports: portsError,
422-
disabledServices: disabledServicesError,
423-
enabledServices: enabledServicesError,
472+
ports: portsError + '|' + duplicatePortsError,
473+
disabledServices:
474+
disabledServicesError + '|' + duplicateDisabledServicesError,
475+
enabledServices:
476+
enabledServicesError + '|' + duplicateEnabledServicesError,
424477
},
425478
disabledNext:
426479
invalidPorts.length > 0 ||
427480
invalidDisabled.length > 0 ||
428-
invalidEnabled.length > 0,
481+
invalidEnabled.length > 0 ||
482+
duplicatePorts.length > 0 ||
483+
duplicateDisabledServices.length > 0 ||
484+
duplicateEnabledServices.length > 0,
429485
};
430486
}
431487

@@ -460,6 +516,10 @@ export function useServicesValidation(): StepValidation {
460516
}
461517
}
462518

519+
const duplicateDisabledServices = getListOfDuplicates(services.disabled);
520+
const duplicateMaskedServices = getListOfDuplicates(services.masked);
521+
const duplicateEnabledServices = getListOfDuplicates(services.enabled);
522+
463523
const disabledSystemdServicesError =
464524
invalidDisabled.length > 0
465525
? `Invalid disabled services: ${invalidDisabled}`
@@ -470,17 +530,41 @@ export function useServicesValidation(): StepValidation {
470530
invalidEnabled.length > 0
471531
? `Invalid enabled services: ${invalidEnabled}`
472532
: '';
533+
const duplicateDisabledServicesError =
534+
duplicateDisabledServices.length > 0
535+
? `Includes duplicate disabled services: ${duplicateDisabledServices.join(
536+
', '
537+
)}`
538+
: '';
539+
const duplicateMaskedServicesError =
540+
duplicateMaskedServices.length > 0
541+
? `Includes duplicate masked services: ${duplicateMaskedServices.join(
542+
', '
543+
)}`
544+
: '';
545+
const duplicateEnabledServicesError =
546+
duplicateEnabledServices.length > 0
547+
? `Includes duplicate enabled services: ${duplicateEnabledServices.join(
548+
', '
549+
)}`
550+
: '';
473551

474552
return {
475553
errors: {
476-
disabledSystemdServices: disabledSystemdServicesError,
477-
maskedSystemdServices: maskedSystemdServicesError,
478-
enabledSystemdServices: enabledSystemdServicesError,
554+
disabledSystemdServices:
555+
disabledSystemdServicesError + '|' + duplicateDisabledServicesError,
556+
maskedSystemdServices:
557+
maskedSystemdServicesError + '|' + duplicateMaskedServicesError,
558+
enabledSystemdServices:
559+
enabledSystemdServicesError + '|' + duplicateEnabledServicesError,
479560
},
480561
disabledNext:
481562
invalidDisabled.length > 0 ||
482563
invalidMasked.length > 0 ||
483-
invalidEnabled.length > 0,
564+
invalidEnabled.length > 0 ||
565+
duplicateDisabledServices.length > 0 ||
566+
duplicateMaskedServices.length > 0 ||
567+
duplicateEnabledServices.length > 0,
484568
};
485569
}
486570

@@ -544,20 +628,27 @@ export function useUsersValidation(): UsersStepValidation {
544628
}
545629
}
546630

547-
const groupsError =
631+
const duplicateGroups = getListOfDuplicates(users[index].groups);
632+
633+
const invalidError =
548634
invalidGroups.length > 0 ? `Invalid user groups: ${invalidGroups}` : '';
635+
const duplicateError =
636+
duplicateGroups.length > 0
637+
? `Includes duplicate groups: ${duplicateGroups.join(', ')}`
638+
: '';
549639

550640
if (
551641
userNameError ||
552642
sshKeyError ||
553643
(users[index].password && !isPasswordValid) ||
554-
groupsError
644+
invalidError ||
645+
duplicateError
555646
) {
556-
errors[`${index}`] = {
647+
errors[index] = {
557648
userName: userNameError,
558649
userSshKey: sshKeyError,
559650
userPassword: passwordError,
560-
groups: groupsError,
651+
groups: invalidError + '|' + duplicateError,
561652
};
562653
}
563654
}

0 commit comments

Comments
 (0)