Wizard: Show error with duplicated values

This show an error when user imports duplicate values to a `<LabelInput>` field.
This commit is contained in:
regexowl 2025-06-26 16:04:42 +02:00 committed by Klara Simickova
parent a92d087014
commit bb9c5620ee
3 changed files with 136 additions and 25 deletions

View file

@ -48,30 +48,36 @@ const LabelInput = ({
const dispatch = useAppDispatch();
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 = (
_event: React.FormEvent<HTMLInputElement>,
value: string
) => {
setInputValue(value);
setErrorText('');
setOnStepInputErrorText('');
};
const addItem = (value: string) => {
if (list?.includes(value) || requiredList?.includes(value)) {
setErrorText(`${item} already exists.`);
setOnStepInputErrorText(`${item} already exists.`);
return;
}
if (!validator(value)) {
setErrorText('Invalid format.');
setOnStepInputErrorText('Invalid format.');
return;
}
dispatch(addAction(value));
setInputValue('');
setErrorText('');
setOnStepInputErrorText('');
};
const handleKeyDown = (e: React.KeyboardEvent, value: string) => {
@ -87,14 +93,18 @@ const LabelInput = ({
const handleRemoveItem = (e: React.MouseEvent, value: string) => {
dispatch(removeAction(value));
setErrorText('');
};
const handleClear = () => {
setInputValue('');
setErrorText('');
setOnStepInputErrorText('');
};
const errors = [];
if (onStepInputErrorText) errors.push(onStepInputErrorText);
if (invalidImports) errors.push(invalidImports);
if (duplicateImports) errors.push(duplicateImports);
return (
<>
<TextInputGroup>
@ -125,9 +135,13 @@ const LabelInput = ({
/>
</TextInputGroupUtilities>
</TextInputGroup>
{errorText && (
{errors.length > 0 && (
<HelperText>
<HelperTextItem variant={'error'}>{errorText}</HelperTextItem>
{errors.map((error, index) => (
<HelperTextItem key={index} variant={'error'}>
{error}
</HelperTextItem>
))}
</HelperText>
)}
{requiredList && requiredList.length > 0 && (

View file

@ -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;
};

View file

@ -3,6 +3,8 @@ import React, { useEffect, useState } from 'react';
import { CheckCircleIcon } from '@patternfly/react-icons';
import { jwtDecode, JwtPayload } from 'jwt-decode';
import { getListOfDuplicates } from './getListOfDuplicates';
import { UNIQUE_VALIDATION_DELAY } from '../../../constants';
import { useLazyGetBlueprintsQuery } from '../../../store/backendApi';
import { useAppSelector } from '../../../store/hooks';
@ -281,14 +283,26 @@ export function useTimezoneValidation(): StepValidation {
}
}
const duplicateNtpServers = getListOfDuplicates(ntpServers || []);
const timezoneError =
timezone && !timezones.includes(timezone) ? 'Unknown timezone' : '';
const ntpServersError =
invalidServers.length > 0 ? `Invalid NTP servers: ${invalidServers}` : '';
const duplicateNtpServersError =
duplicateNtpServers.length > 0
? `Includes duplicate NTP servers: ${duplicateNtpServers.join(', ')}`
: '';
return {
errors: { timezone: timezoneError, ntpServers: ntpServersError },
disabledNext: timezoneError !== '' || invalidServers.length > 0,
errors: {
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 =
kernel.name && !isKernelNameValid(kernel.name) ? 'Invalid format.' : '';
const kernelAppendError =
invalidArgs.length > 0 ? `Invalid kernel arguments: ${invalidArgs}` : '';
const duplicateKernelArgsError =
duplicateKernelArgs.length > 0
? `Includes duplicate kernel arguments: ${duplicateKernelArgs.join(', ')}`
: '';
return {
errors: { kernel: kernelNameError, kernelAppend: kernelAppendError },
disabledNext: kernelNameError !== '' || kernelAppendError !== '',
errors: {
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 =
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 =
invalidDisabled.length > 0
? `Invalid disabled services: ${invalidDisabled}`
@ -418,14 +469,19 @@ export function useFirewallValidation(): StepValidation {
return {
errors: {
ports: portsError,
disabledServices: disabledServicesError,
enabledServices: enabledServicesError,
ports: portsError + '|' + duplicatePortsError,
disabledServices:
disabledServicesError + '|' + duplicateDisabledServicesError,
enabledServices:
enabledServicesError + '|' + duplicateEnabledServicesError,
},
disabledNext:
invalidPorts.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 =
invalidDisabled.length > 0
? `Invalid disabled services: ${invalidDisabled}`
@ -470,17 +530,41 @@ export function useServicesValidation(): StepValidation {
invalidEnabled.length > 0
? `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 {
errors: {
disabledSystemdServices: disabledSystemdServicesError,
maskedSystemdServices: maskedSystemdServicesError,
enabledSystemdServices: enabledSystemdServicesError,
disabledSystemdServices:
disabledSystemdServicesError + '|' + duplicateDisabledServicesError,
maskedSystemdServices:
maskedSystemdServicesError + '|' + duplicateMaskedServicesError,
enabledSystemdServices:
enabledSystemdServicesError + '|' + duplicateEnabledServicesError,
},
disabledNext:
invalidDisabled.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}` : '';
const duplicateError =
duplicateGroups.length > 0
? `Includes duplicate groups: ${duplicateGroups.join(', ')}`
: '';
if (
userNameError ||
sshKeyError ||
(users[index].password && !isPasswordValid) ||
groupsError
invalidError ||
duplicateError
) {
errors[`${index}`] = {
errors[index] = {
userName: userNameError,
userSshKey: sshKeyError,
userPassword: passwordError,
groups: groupsError,
groups: invalidError + '|' + duplicateError,
};
}
}