this commit add validation to name field in Users step
This commit is contained in:
parent
5a7ce1efee
commit
30d77faeb5
5 changed files with 78 additions and 5 deletions
|
|
@ -41,6 +41,7 @@ import {
|
|||
useRegistrationValidation,
|
||||
useHostnameValidation,
|
||||
useKernelValidation,
|
||||
useUsersValidation,
|
||||
} from './utilities/useValidation';
|
||||
import {
|
||||
isAwsAccountIdValid,
|
||||
|
|
@ -230,6 +231,8 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
|
|||
const firstBootValidation = useFirstBootValidation();
|
||||
// Details
|
||||
const detailsValidation = useDetailsValidation();
|
||||
// Users
|
||||
const usersValidation = useUsersValidation();
|
||||
|
||||
let startIndex = 1; // default index
|
||||
if (isEdit) {
|
||||
|
|
@ -462,7 +465,10 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
|
|||
key="wizard-users"
|
||||
isHidden={!isUsersEnabled}
|
||||
footer={
|
||||
<CustomWizardFooter disableNext={false} optional={true} />
|
||||
<CustomWizardFooter
|
||||
disableNext={usersValidation.disabledNext}
|
||||
optional={true}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<UsersStep />
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
setUserPasswordByIndex,
|
||||
setUserSshKeyByIndex,
|
||||
} from '../../../../../store/wizardSlice';
|
||||
import { useUsersValidation } from '../../../utilities/useValidation';
|
||||
import { HookValidatedInput } from '../../../ValidatedTextInput';
|
||||
const UserInfo = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
|
@ -45,10 +46,7 @@ const UserInfo = () => {
|
|||
dispatch(setUserSshKeyByIndex({ index: index, sshKey: value }));
|
||||
};
|
||||
|
||||
const stepValidation = {
|
||||
errors: {},
|
||||
disabledNext: false,
|
||||
};
|
||||
const stepValidation = useUsersValidation();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ import {
|
|||
selectRegistrationType,
|
||||
selectHostname,
|
||||
selectKernel,
|
||||
selectUserNameByIndex,
|
||||
selectUsers,
|
||||
selectUserPasswordByIndex,
|
||||
selectUserSshKeyByIndex,
|
||||
} from '../../../store/wizardSlice';
|
||||
import {
|
||||
getDuplicateMountPoints,
|
||||
|
|
@ -29,6 +33,7 @@ import {
|
|||
isSnapshotValid,
|
||||
isHostnameValid,
|
||||
isKernelNameValid,
|
||||
isUserNameValid,
|
||||
} from '../validators';
|
||||
|
||||
export type StepValidation = {
|
||||
|
|
@ -173,6 +178,31 @@ export function useKernelValidation(): StepValidation {
|
|||
return { errors: {}, disabledNext: false };
|
||||
}
|
||||
|
||||
export function useUsersValidation(): StepValidation {
|
||||
const index = 0;
|
||||
const userNameSelector = selectUserNameByIndex(index);
|
||||
const userName = useAppSelector(userNameSelector);
|
||||
const userPasswordSelector = selectUserPasswordByIndex(index);
|
||||
const userPassword = useAppSelector(userPasswordSelector);
|
||||
const userSshKeySelector = selectUserSshKeyByIndex(index);
|
||||
const userSshKey = useAppSelector(userSshKeySelector);
|
||||
const users = useAppSelector(selectUsers);
|
||||
const canProceed =
|
||||
// Case 1: there is no users
|
||||
users.length === 0 ||
|
||||
// Case 2: All fields are empty
|
||||
(userName === '' && userPassword === '' && userSshKey === '') ||
|
||||
// Case 3: userName is valid
|
||||
(userName && isUserNameValid(userName));
|
||||
|
||||
return {
|
||||
errors: {
|
||||
userName: !isUserNameValid(userName) ? 'Invalid user name' : '',
|
||||
},
|
||||
disabledNext: !canProceed,
|
||||
};
|
||||
}
|
||||
|
||||
export function useDetailsValidation(): StepValidation {
|
||||
const name = useAppSelector(selectBlueprintName);
|
||||
const description = useAppSelector(selectBlueprintDescription);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,17 @@ export const isFileSystemConfigValid = (partitions: Partition[]) => {
|
|||
return duplicates.length === 0;
|
||||
};
|
||||
|
||||
export const isUserNameValid = (userName: string) => {
|
||||
if (userName === undefined) return false;
|
||||
const isLengthValid = userName.length <= 32;
|
||||
const isNotNumericOnly = !/^\d+$/.test(userName);
|
||||
const isPatternValid = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*[a-zA-Z0-9_$]$/.test(
|
||||
userName
|
||||
);
|
||||
|
||||
return isLengthValid && isNotNumericOnly && isPatternValid;
|
||||
};
|
||||
|
||||
export const getDuplicateMountPoints = (partitions: Partition[]): string[] => {
|
||||
const mountPointSet: Set<string> = new Set();
|
||||
const duplicates: string[] = [];
|
||||
|
|
|
|||
|
|
@ -72,6 +72,24 @@ const addValidUser = async () => {
|
|||
await waitFor(() => expect(nextButton).toBeEnabled());
|
||||
};
|
||||
|
||||
const addInvalidUser = async () => {
|
||||
const user = userEvent.setup();
|
||||
const addUser = await screen.findByRole('button', { name: /add a user/i });
|
||||
expect(addUser).toBeEnabled();
|
||||
await waitFor(() => user.click(addUser));
|
||||
const enterUserName = screen.getByRole('textbox', {
|
||||
name: /blueprint user name/i,
|
||||
});
|
||||
const nextButton = await getNextButton();
|
||||
await waitFor(() => user.type(enterUserName, '..'));
|
||||
await waitFor(() => expect(enterUserName).toHaveValue('..'));
|
||||
const enterSshKey = await screen.findByRole('textbox', {
|
||||
name: /public SSH key/i,
|
||||
});
|
||||
await waitFor(() => user.type(enterSshKey, 'ssh-rsa d'));
|
||||
await waitFor(() => expect(nextButton).toBeDisabled());
|
||||
};
|
||||
|
||||
describe('Step Users', () => {
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
|
|
@ -145,6 +163,16 @@ describe('Step Users', () => {
|
|||
expect(receivedRequest).toEqual(expectedRequest);
|
||||
});
|
||||
});
|
||||
|
||||
test('with invalid name', async () => {
|
||||
await renderCreateMode();
|
||||
await goToRegistrationStep();
|
||||
await clickRegisterLater();
|
||||
await goToUsersStep();
|
||||
await addInvalidUser();
|
||||
const invalidUserMessage = screen.getByText(/invalid user name/i);
|
||||
await waitFor(() => expect(invalidUserMessage));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Users edit mode', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue