From f689e727a4102ff8622c37915356f0f563cb8317 Mon Sep 17 00:00:00 2001 From: amitkumarashutosh Date: Tue, 24 Feb 2026 18:56:45 +0530 Subject: [PATCH] fix: check username availability against API in setup wizard admin step --- .../setupWizard/contexts/SetupWizardContext.tsx | 2 ++ .../setupWizard/providers/SetupWizardProvider.tsx | 15 +++++++++++++++ .../src/views/setupWizard/steps/AdminInfoStep.tsx | 10 +++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/ui-client/src/views/setupWizard/contexts/SetupWizardContext.tsx b/packages/ui-client/src/views/setupWizard/contexts/SetupWizardContext.tsx index 6ce73e16a3f2f..d7fd94c6e2e1a 100644 --- a/packages/ui-client/src/views/setupWizard/contexts/SetupWizardContext.tsx +++ b/packages/ui-client/src/views/setupWizard/contexts/SetupWizardContext.tsx @@ -34,6 +34,7 @@ type SetupWizarContextValue = { saveOrganizationData: (data: SetupWizardData['organizationData']) => Promise; completeSetupWizard: () => Promise; maxSteps: number; + checkUsernameAvailability: (username: string) => Promise; }; export const SetupWizardContext = createContext({ @@ -67,6 +68,7 @@ export const SetupWizardContext = createContext({ currentStep: 1, completeSetupWizard: async () => undefined, maxSteps: 4, + checkUsernameAvailability: async () => true, }); export const useSetupWizardContext = (): SetupWizarContextValue => useContext(SetupWizardContext); diff --git a/packages/ui-client/src/views/setupWizard/providers/SetupWizardProvider.tsx b/packages/ui-client/src/views/setupWizard/providers/SetupWizardProvider.tsx index 74b58c4931cda..76ce86c6dee5f 100644 --- a/packages/ui-client/src/views/setupWizard/providers/SetupWizardProvider.tsx +++ b/packages/ui-client/src/views/setupWizard/providers/SetupWizardProvider.tsx @@ -52,6 +52,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle const loginWithPassword = useLoginWithPassword(); const setForceLogin = useSessionDispatch('forceLogin'); const createRegistrationIntent = useEndpoint('POST', '/v1/cloud.createRegistrationIntent'); + const checkUsernameAvailabilityEndpoint = useEndpoint('GET', '/v1/users.checkUsernameAvailability'); const goToPreviousStep = useCallback(() => setCurrentStep((currentStep) => currentStep - 1), [setCurrentStep]); const goToNextStep = useCallback(() => setCurrentStep((currentStep) => currentStep + 1), [setCurrentStep]); @@ -68,6 +69,18 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle [t], ); + const checkUsernameAvailability = useCallback( + async (username: string): Promise => { + try { + const { result } = await checkUsernameAvailabilityEndpoint({ username }); + return result; + } catch { + return false; + } + }, + [checkUsernameAvailabilityEndpoint], + ); + const registerAdminUser = useCallback( async ({ fullname, @@ -207,6 +220,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle saveOrganizationData, completeSetupWizard, maxSteps: data.serverAlreadyRegistered ? 2 : 4, + checkUsernameAvailability, }), [ setupWizardData, @@ -224,6 +238,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle saveWorkspaceData, saveOrganizationData, completeSetupWizard, + checkUsernameAvailability, ], ); diff --git a/packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx b/packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx index a3ab153f32ea6..0561f568daf18 100644 --- a/packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx +++ b/packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx @@ -17,7 +17,7 @@ const AdminInfoStep = (): ReactElement => { const regexpForUsernameValidation = useSetting('UTF8_User_Names_Validation'); const usernameRegExp = new RegExp(`^${regexpForUsernameValidation}$`); - const { currentStep, validateEmail, registerAdminUser, maxSteps } = useSetupWizardContext(); + const { currentStep, validateEmail, registerAdminUser, maxSteps, checkUsernameAvailability } = useSetupWizardContext(); const passwordPolicyOptions = usePasswordPolicyOptions(); const validatePasswordPolicy = usePasswordPolicy(passwordPolicyOptions); @@ -39,12 +39,16 @@ const AdminInfoStep = (): ReactElement => { .join(', '); }, [passwordPolicyValidations.validations, t]); - // TODO: check if username exists - const validateUsername = (username: string): boolean | string => { + const validateUsername = async (username: string): Promise => { if (!usernameRegExp.test(username) || hasBlockedName(username)) { return t('Invalid_username'); } + const isAvailable = await checkUsernameAvailability(username); + if (!isAvailable) { + return t('Username_already_exist'); + } + return true; };