Wizard: Show error with duplicated values
This show an error when user imports duplicate values to a `<LabelInput>` field.
This commit is contained in:
parent
a92d087014
commit
bb9c5620ee
3 changed files with 136 additions and 25 deletions
|
|
@ -48,30 +48,36 @@ const LabelInput = ({
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const [errorText, setErrorText] = useState(stepValidation.errors[fieldName]);
|
const [onStepInputErrorText, setOnStepInputErrorText] = useState('');
|
||||||
|
let [invalidImports, duplicateImports] = ['', ''];
|
||||||
|
|
||||||
|
if (stepValidation.errors[fieldName]) {
|
||||||
|
[invalidImports, duplicateImports] =
|
||||||
|
stepValidation.errors[fieldName].split('|');
|
||||||
|
}
|
||||||
|
|
||||||
const onTextInputChange = (
|
const onTextInputChange = (
|
||||||
_event: React.FormEvent<HTMLInputElement>,
|
_event: React.FormEvent<HTMLInputElement>,
|
||||||
value: string
|
value: string
|
||||||
) => {
|
) => {
|
||||||
setInputValue(value);
|
setInputValue(value);
|
||||||
setErrorText('');
|
setOnStepInputErrorText('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const addItem = (value: string) => {
|
const addItem = (value: string) => {
|
||||||
if (list?.includes(value) || requiredList?.includes(value)) {
|
if (list?.includes(value) || requiredList?.includes(value)) {
|
||||||
setErrorText(`${item} already exists.`);
|
setOnStepInputErrorText(`${item} already exists.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validator(value)) {
|
if (!validator(value)) {
|
||||||
setErrorText('Invalid format.');
|
setOnStepInputErrorText('Invalid format.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(addAction(value));
|
dispatch(addAction(value));
|
||||||
setInputValue('');
|
setInputValue('');
|
||||||
setErrorText('');
|
setOnStepInputErrorText('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent, value: string) => {
|
const handleKeyDown = (e: React.KeyboardEvent, value: string) => {
|
||||||
|
|
@ -87,14 +93,18 @@ const LabelInput = ({
|
||||||
|
|
||||||
const handleRemoveItem = (e: React.MouseEvent, value: string) => {
|
const handleRemoveItem = (e: React.MouseEvent, value: string) => {
|
||||||
dispatch(removeAction(value));
|
dispatch(removeAction(value));
|
||||||
setErrorText('');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
setInputValue('');
|
setInputValue('');
|
||||||
setErrorText('');
|
setOnStepInputErrorText('');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const errors = [];
|
||||||
|
if (onStepInputErrorText) errors.push(onStepInputErrorText);
|
||||||
|
if (invalidImports) errors.push(invalidImports);
|
||||||
|
if (duplicateImports) errors.push(duplicateImports);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TextInputGroup>
|
<TextInputGroup>
|
||||||
|
|
@ -125,9 +135,13 @@ const LabelInput = ({
|
||||||
/>
|
/>
|
||||||
</TextInputGroupUtilities>
|
</TextInputGroupUtilities>
|
||||||
</TextInputGroup>
|
</TextInputGroup>
|
||||||
{errorText && (
|
{errors.length > 0 && (
|
||||||
<HelperText>
|
<HelperText>
|
||||||
<HelperTextItem variant={'error'}>{errorText}</HelperTextItem>
|
{errors.map((error, index) => (
|
||||||
|
<HelperTextItem key={index} variant={'error'}>
|
||||||
|
{error}
|
||||||
|
</HelperTextItem>
|
||||||
|
))}
|
||||||
</HelperText>
|
</HelperText>
|
||||||
)}
|
)}
|
||||||
{requiredList && requiredList.length > 0 && (
|
{requiredList && requiredList.length > 0 && (
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const getListOfDuplicates = (list: string[]) => {
|
||||||
|
const duplicates = list.filter((item, index) => list.indexOf(item) !== index);
|
||||||
|
const uniqueDuplicates = [...new Set(duplicates)];
|
||||||
|
|
||||||
|
return uniqueDuplicates;
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,8 @@ import React, { useEffect, useState } from 'react';
|
||||||
import { CheckCircleIcon } from '@patternfly/react-icons';
|
import { CheckCircleIcon } from '@patternfly/react-icons';
|
||||||
import { jwtDecode, JwtPayload } from 'jwt-decode';
|
import { jwtDecode, JwtPayload } from 'jwt-decode';
|
||||||
|
|
||||||
|
import { getListOfDuplicates } from './getListOfDuplicates';
|
||||||
|
|
||||||
import { UNIQUE_VALIDATION_DELAY } from '../../../constants';
|
import { UNIQUE_VALIDATION_DELAY } from '../../../constants';
|
||||||
import { useLazyGetBlueprintsQuery } from '../../../store/backendApi';
|
import { useLazyGetBlueprintsQuery } from '../../../store/backendApi';
|
||||||
import { useAppSelector } from '../../../store/hooks';
|
import { useAppSelector } from '../../../store/hooks';
|
||||||
|
|
@ -281,14 +283,26 @@ export function useTimezoneValidation(): StepValidation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duplicateNtpServers = getListOfDuplicates(ntpServers || []);
|
||||||
|
|
||||||
const timezoneError =
|
const timezoneError =
|
||||||
timezone && !timezones.includes(timezone) ? 'Unknown timezone' : '';
|
timezone && !timezones.includes(timezone) ? 'Unknown timezone' : '';
|
||||||
const ntpServersError =
|
const ntpServersError =
|
||||||
invalidServers.length > 0 ? `Invalid NTP servers: ${invalidServers}` : '';
|
invalidServers.length > 0 ? `Invalid NTP servers: ${invalidServers}` : '';
|
||||||
|
const duplicateNtpServersError =
|
||||||
|
duplicateNtpServers.length > 0
|
||||||
|
? `Includes duplicate NTP servers: ${duplicateNtpServers.join(', ')}`
|
||||||
|
: '';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errors: { timezone: timezoneError, ntpServers: ntpServersError },
|
errors: {
|
||||||
disabledNext: timezoneError !== '' || invalidServers.length > 0,
|
timezone: timezoneError,
|
||||||
|
ntpServers: ntpServersError + '|' + duplicateNtpServersError,
|
||||||
|
},
|
||||||
|
disabledNext:
|
||||||
|
timezoneError !== '' ||
|
||||||
|
invalidServers.length > 0 ||
|
||||||
|
duplicateNtpServers.length > 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,15 +377,28 @@ export function useKernelValidation(): StepValidation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duplicateKernelArgs = getListOfDuplicates(kernel.append);
|
||||||
|
|
||||||
const kernelNameError =
|
const kernelNameError =
|
||||||
kernel.name && !isKernelNameValid(kernel.name) ? 'Invalid format.' : '';
|
kernel.name && !isKernelNameValid(kernel.name) ? 'Invalid format.' : '';
|
||||||
|
|
||||||
const kernelAppendError =
|
const kernelAppendError =
|
||||||
invalidArgs.length > 0 ? `Invalid kernel arguments: ${invalidArgs}` : '';
|
invalidArgs.length > 0 ? `Invalid kernel arguments: ${invalidArgs}` : '';
|
||||||
|
|
||||||
|
const duplicateKernelArgsError =
|
||||||
|
duplicateKernelArgs.length > 0
|
||||||
|
? `Includes duplicate kernel arguments: ${duplicateKernelArgs.join(', ')}`
|
||||||
|
: '';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errors: { kernel: kernelNameError, kernelAppend: kernelAppendError },
|
errors: {
|
||||||
disabledNext: kernelNameError !== '' || kernelAppendError !== '',
|
kernel: kernelNameError,
|
||||||
|
kernelAppend: kernelAppendError + '|' + duplicateKernelArgsError,
|
||||||
|
},
|
||||||
|
disabledNext:
|
||||||
|
kernelNameError !== '' ||
|
||||||
|
kernelAppendError !== '' ||
|
||||||
|
duplicateKernelArgs.length > 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -405,8 +432,32 @@ export function useFirewallValidation(): StepValidation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duplicatePorts = getListOfDuplicates(firewall.ports);
|
||||||
|
const duplicateDisabledServices = getListOfDuplicates(
|
||||||
|
firewall.services.disabled
|
||||||
|
);
|
||||||
|
const duplicateEnabledServices = getListOfDuplicates(
|
||||||
|
firewall.services.enabled
|
||||||
|
);
|
||||||
|
|
||||||
const portsError =
|
const portsError =
|
||||||
invalidPorts.length > 0 ? `Invalid ports: ${invalidPorts}` : '';
|
invalidPorts.length > 0 ? `Invalid ports: ${invalidPorts}` : '';
|
||||||
|
const duplicatePortsError =
|
||||||
|
duplicatePorts.length > 0
|
||||||
|
? `Includes duplicate ports: ${duplicatePorts.join(', ')}`
|
||||||
|
: '';
|
||||||
|
const duplicateDisabledServicesError =
|
||||||
|
duplicateDisabledServices.length > 0
|
||||||
|
? `Includes duplicate disabled services: ${duplicateDisabledServices.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
: '';
|
||||||
|
const duplicateEnabledServicesError =
|
||||||
|
duplicateEnabledServices.length > 0
|
||||||
|
? `Includes duplicate enabled services: ${duplicateEnabledServices.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
: '';
|
||||||
const disabledServicesError =
|
const disabledServicesError =
|
||||||
invalidDisabled.length > 0
|
invalidDisabled.length > 0
|
||||||
? `Invalid disabled services: ${invalidDisabled}`
|
? `Invalid disabled services: ${invalidDisabled}`
|
||||||
|
|
@ -418,14 +469,19 @@ export function useFirewallValidation(): StepValidation {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errors: {
|
errors: {
|
||||||
ports: portsError,
|
ports: portsError + '|' + duplicatePortsError,
|
||||||
disabledServices: disabledServicesError,
|
disabledServices:
|
||||||
enabledServices: enabledServicesError,
|
disabledServicesError + '|' + duplicateDisabledServicesError,
|
||||||
|
enabledServices:
|
||||||
|
enabledServicesError + '|' + duplicateEnabledServicesError,
|
||||||
},
|
},
|
||||||
disabledNext:
|
disabledNext:
|
||||||
invalidPorts.length > 0 ||
|
invalidPorts.length > 0 ||
|
||||||
invalidDisabled.length > 0 ||
|
invalidDisabled.length > 0 ||
|
||||||
invalidEnabled.length > 0,
|
invalidEnabled.length > 0 ||
|
||||||
|
duplicatePorts.length > 0 ||
|
||||||
|
duplicateDisabledServices.length > 0 ||
|
||||||
|
duplicateEnabledServices.length > 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -460,6 +516,10 @@ export function useServicesValidation(): StepValidation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duplicateDisabledServices = getListOfDuplicates(services.disabled);
|
||||||
|
const duplicateMaskedServices = getListOfDuplicates(services.masked);
|
||||||
|
const duplicateEnabledServices = getListOfDuplicates(services.enabled);
|
||||||
|
|
||||||
const disabledSystemdServicesError =
|
const disabledSystemdServicesError =
|
||||||
invalidDisabled.length > 0
|
invalidDisabled.length > 0
|
||||||
? `Invalid disabled services: ${invalidDisabled}`
|
? `Invalid disabled services: ${invalidDisabled}`
|
||||||
|
|
@ -470,17 +530,41 @@ export function useServicesValidation(): StepValidation {
|
||||||
invalidEnabled.length > 0
|
invalidEnabled.length > 0
|
||||||
? `Invalid enabled services: ${invalidEnabled}`
|
? `Invalid enabled services: ${invalidEnabled}`
|
||||||
: '';
|
: '';
|
||||||
|
const duplicateDisabledServicesError =
|
||||||
|
duplicateDisabledServices.length > 0
|
||||||
|
? `Includes duplicate disabled services: ${duplicateDisabledServices.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
: '';
|
||||||
|
const duplicateMaskedServicesError =
|
||||||
|
duplicateMaskedServices.length > 0
|
||||||
|
? `Includes duplicate masked services: ${duplicateMaskedServices.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
: '';
|
||||||
|
const duplicateEnabledServicesError =
|
||||||
|
duplicateEnabledServices.length > 0
|
||||||
|
? `Includes duplicate enabled services: ${duplicateEnabledServices.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
: '';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errors: {
|
errors: {
|
||||||
disabledSystemdServices: disabledSystemdServicesError,
|
disabledSystemdServices:
|
||||||
maskedSystemdServices: maskedSystemdServicesError,
|
disabledSystemdServicesError + '|' + duplicateDisabledServicesError,
|
||||||
enabledSystemdServices: enabledSystemdServicesError,
|
maskedSystemdServices:
|
||||||
|
maskedSystemdServicesError + '|' + duplicateMaskedServicesError,
|
||||||
|
enabledSystemdServices:
|
||||||
|
enabledSystemdServicesError + '|' + duplicateEnabledServicesError,
|
||||||
},
|
},
|
||||||
disabledNext:
|
disabledNext:
|
||||||
invalidDisabled.length > 0 ||
|
invalidDisabled.length > 0 ||
|
||||||
invalidMasked.length > 0 ||
|
invalidMasked.length > 0 ||
|
||||||
invalidEnabled.length > 0,
|
invalidEnabled.length > 0 ||
|
||||||
|
duplicateDisabledServices.length > 0 ||
|
||||||
|
duplicateMaskedServices.length > 0 ||
|
||||||
|
duplicateEnabledServices.length > 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -544,20 +628,27 @@ export function useUsersValidation(): UsersStepValidation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupsError =
|
const duplicateGroups = getListOfDuplicates(users[index].groups);
|
||||||
|
|
||||||
|
const invalidError =
|
||||||
invalidGroups.length > 0 ? `Invalid user groups: ${invalidGroups}` : '';
|
invalidGroups.length > 0 ? `Invalid user groups: ${invalidGroups}` : '';
|
||||||
|
const duplicateError =
|
||||||
|
duplicateGroups.length > 0
|
||||||
|
? `Includes duplicate groups: ${duplicateGroups.join(', ')}`
|
||||||
|
: '';
|
||||||
|
|
||||||
if (
|
if (
|
||||||
userNameError ||
|
userNameError ||
|
||||||
sshKeyError ||
|
sshKeyError ||
|
||||||
(users[index].password && !isPasswordValid) ||
|
(users[index].password && !isPasswordValid) ||
|
||||||
groupsError
|
invalidError ||
|
||||||
|
duplicateError
|
||||||
) {
|
) {
|
||||||
errors[`${index}`] = {
|
errors[index] = {
|
||||||
userName: userNameError,
|
userName: userNameError,
|
||||||
userSshKey: sshKeyError,
|
userSshKey: sshKeyError,
|
||||||
userPassword: passwordError,
|
userPassword: passwordError,
|
||||||
groups: groupsError,
|
groups: invalidError + '|' + duplicateError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue