diff --git a/src/Components/CreateImageWizard/CreateImageWizard.tsx b/src/Components/CreateImageWizard/CreateImageWizard.tsx
index f81211e3a..69ea205ee 100644
--- a/src/Components/CreateImageWizard/CreateImageWizard.tsx
+++ b/src/Components/CreateImageWizard/CreateImageWizard.tsx
@@ -39,6 +39,7 @@ import {
useDetailsValidation,
useRegistrationValidation,
useHostnameValidation,
+ useUsersValidation,
} from './utilities/useValidation';
import {
isAwsAccountIdValid,
@@ -225,6 +226,8 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
const firstBootValidation = useFirstBootValidation();
// Details
const detailsValidation = useDetailsValidation();
+ // Users
+ const usersValidation = useUsersValidation();
let startIndex = 1; // default index
if (isEdit) {
@@ -457,7 +460,9 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
key="wizard-users"
isHidden={!isUsersEnabled}
footer={
-
+
}
>
diff --git a/src/Components/CreateImageWizard/steps/Users/component/UserInfo.tsx b/src/Components/CreateImageWizard/steps/Users/component/UserInfo.tsx
index 48b433cdc..ad633f724 100644
--- a/src/Components/CreateImageWizard/steps/Users/component/UserInfo.tsx
+++ b/src/Components/CreateImageWizard/steps/Users/component/UserInfo.tsx
@@ -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 (
<>
diff --git a/src/Components/CreateImageWizard/utilities/useValidation.tsx b/src/Components/CreateImageWizard/utilities/useValidation.tsx
index 2307c6d2d..91b2152ce 100644
--- a/src/Components/CreateImageWizard/utilities/useValidation.tsx
+++ b/src/Components/CreateImageWizard/utilities/useValidation.tsx
@@ -19,6 +19,8 @@ import {
selectActivationKey,
selectRegistrationType,
selectHostname,
+ selectUserNameByIndex,
+ selectUsers,
} from '../../../store/wizardSlice';
import {
getDuplicateMountPoints,
@@ -27,6 +29,7 @@ import {
isMountpointMinSizeValid,
isSnapshotValid,
isHostnameValid,
+ isUserNameValid,
} from '../validators';
export type StepValidation = {
@@ -155,6 +158,26 @@ export function useHostnameValidation(): StepValidation {
return { errors: {}, disabledNext: false };
}
+export function useUsersValidation(): StepValidation {
+ const index = 0;
+ const userNameSelector = selectUserNameByIndex(index);
+ const userName = useAppSelector(userNameSelector);
+ const userNameValid = isUserNameValid(userName);
+ const users = useAppSelector(selectUsers);
+ const canProceed =
+ // Case 1: there is no users
+ users.length === 0 ||
+ // Case 2: All fields are empty
+ userNameValid;
+
+ return {
+ errors: {
+ userName: !userNameValid ? 'Invalid user name' : '',
+ },
+ disabledNext: !canProceed,
+ };
+}
+
export function useDetailsValidation(): StepValidation {
const name = useAppSelector(selectBlueprintName);
const description = useAppSelector(selectBlueprintDescription);
diff --git a/src/Components/CreateImageWizard/validators.ts b/src/Components/CreateImageWizard/validators.ts
index 9704b36e2..74950058d 100644
--- a/src/Components/CreateImageWizard/validators.ts
+++ b/src/Components/CreateImageWizard/validators.ts
@@ -67,6 +67,19 @@ export const isFileSystemConfigValid = (partitions: Partition[]) => {
return duplicates.length === 0;
};
+export const isUserNameValid = (userName: string) => {
+ const isLengthValid =
+ userName !== undefined && userName.length >= 1 && userName.length <= 32;
+
+ // Check if the username follows the pattern:
+ // Starts and ends with a valid character (not a dot).
+ // Can contain alphanumeric characters, underscores, hyphens, and periods in the middle.
+ const isPatternValid = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*[a-zA-Z0-9_]$/.test(
+ userName
+ );
+ return isLengthValid && isPatternValid;
+};
+
export const getDuplicateMountPoints = (partitions: Partition[]): string[] => {
const mountPointSet: Set = new Set();
const duplicates: string[] = [];