feat: add local admin login

This commit is contained in:
thibaud-leclere 2026-05-06 08:44:14 +02:00
parent 4c30592ae4
commit b17375eb16
5 changed files with 79 additions and 1 deletions

View file

@ -305,6 +305,7 @@
"continue_email": "Continue with Email",
"continue_github": "Continue with Github",
"continue_google": "Continue with Google",
"continue_local": "Continue with username",
"continue_microsoft": "Continue with Microsoft",
"copied_to_clipboard": "Copied to clipboard",
"create_team_failure": "Failed to create workspace!!",
@ -345,6 +346,7 @@
"login_using_email": "Please ask the user to check their email or share the link below",
"login_using_link": "Please ask the user to login using the link below",
"logout": "Logout",
"local_signin_failure": "Failed to login with username and password",
"magic_link_sign_in": "Click on the link to sign in.",
"magic_link_success": "We sent a magic link to",
"microsoft_signin_failure": "Failed to login with Microsoft",
@ -352,6 +354,7 @@
"non_admin_logged_in": "Logged in as non admin user.",
"non_admin_login": "You are logged in. But you're not an admin",
"owner_not_present": "Atleast one owner should be present in the team!!",
"password": "Password",
"privacy_policy": "Privacy Policy",
"reenter_email": "Re-enter email",
"remove_admin_failure": "Failed to remove admin status!!",
@ -380,12 +383,14 @@
"send_magic_link": "Send magic link",
"setup_failure": "Setup has failed!!",
"setup_success": "Setup completed successfully!!",
"sign_in": "Sign in",
"sign_in_agreement": "By signing in, you are agreeing to our",
"sign_in_options": "All sign in option",
"sign_out": "Sign out",
"something_went_wrong": "Something went wrong",
"team_name_too_short": "Workspace name should be atleast 6 characters long!!",
"user_already_invited": "Failed to send invite. User is already invited!!",
"username": "Username",
"user_not_found": "User not found in the infra!!",
"users_to_admin_success": "Selected users are elevated to admin status!!",
"users_to_admin_failure": "Failed to elevate selected users to admin status!!"

View file

@ -13,5 +13,12 @@
"username_format": "Lidentifiant ne peut contenir que des lettres, chiffres, points, tirets et underscores.",
"username_min_length": "Lidentifiant doit contenir au moins 3 caractères."
}
},
"state": {
"continue_local": "Continuer avec un identifiant",
"local_signin_failure": "Connexion avec identifiant et mot de passe impossible",
"password": "Mot de passe",
"sign_in": "Se connecter",
"username": "Identifiant"
}
}

View file

@ -51,6 +51,12 @@
:label="t('state.continue_email')"
@click="mode = 'email'"
/>
<HoppSmartItem
v-if="allowedAuthProviders.includes('LOCAL')"
:icon="IconKeyRound"
:label="t('state.continue_local')"
@click="mode = 'local'"
/>
</div>
<form
v-if="mode === 'email' && allowedAuthProviders"
@ -71,6 +77,32 @@
:label="t('state.send_magic_link')"
/>
</form>
<form
v-if="mode === 'local' && allowedAuthProviders"
class="flex flex-col space-y-4"
@submit.prevent="signInWithUsernamePassword"
>
<HoppSmartInput
v-model="form.username"
type="text"
placeholder=" "
input-styles="floating-input"
:label="t('state.username')"
/>
<HoppSmartInput
v-model="form.password"
type="password"
placeholder=" "
input-styles="floating-input"
:label="t('state.password')"
/>
<HoppButtonPrimary
:loading="signingInWithLocal"
type="submit"
:label="t('state.sign_in')"
/>
</form>
<div
v-if="!allowedAuthProviders?.length"
class="flex flex-col items-center text-center"
@ -139,7 +171,7 @@
:label="t('state.privacy_policy')"
/>
</div>
<div v-if="mode === 'email'">
<div v-if="mode === 'email' || mode === 'local'">
<HoppButtonSecondary
:label="t('state.sign_in_options')"
:icon="IconArrowLeft"
@ -175,6 +207,7 @@ import IconGoogle from '~icons/auth/google';
import IconMicrosoft from '~icons/auth/microsoft';
import IconArrowLeft from '~icons/lucide/arrow-left';
import IconFileText from '~icons/lucide/file-text';
import IconKeyRound from '~icons/lucide/key-round';
const t = useI18n();
const toast = useToast();
@ -184,6 +217,8 @@ const privacyPolicyLink = import.meta.env.VITE_APP_PRIVACY_POLICY_LINK;
const form = ref({
email: '',
username: '',
password: '',
});
const fetching = ref(false);
const error = ref(false);
@ -191,6 +226,7 @@ const signingInWithGoogle = ref(false);
const signingInWithGitHub = ref(false);
const signingInWithMicrosoft = ref(false);
const signingInWithEmail = ref(false);
const signingInWithLocal = ref(false);
const mode = ref('sign-in');
const nonAdminUser = ref(false);
@ -265,6 +301,26 @@ const signInWithEmail = async () => {
signingInWithEmail.value = false;
};
const signInWithUsernamePassword = async () => {
signingInWithLocal.value = true;
try {
await auth.signInWithUsernamePassword(
form.value.username,
form.value.password,
);
if (auth.getCurrentUser()?.isAdmin) {
window.location.href = import.meta.env.VITE_ADMIN_URL;
} else {
nonAdminUser.value = true;
}
} catch (e) {
console.error(e);
toast.error(t('state.local_signin_failure'));
}
signingInWithLocal.value = false;
};
const getAllowedAuthProviders = async () => {
fetching.value = true;
try {

View file

@ -222,6 +222,11 @@ export const auth = {
}
},
signInWithUsernamePassword: async (username: string, password: string) => {
await authQuery.signInLocal(username, password);
await setInitialUser();
},
performAuthRefresh: async () => {
const isRefreshSuccess = await refreshToken();

View file

@ -34,6 +34,11 @@ export default {
username,
password,
}),
signInLocal: (username: string, password: string) =>
restApi.post('/auth/local/signin', {
username,
password,
}),
getFirstTimeInfraSetupStatus: () => restApi.get('/site/setup'),
updateFirstTimeInfraSetupStatus: () => restApi.put('/site/setup'),
addOnBoardingConfigs: (config: Record<string, any>) =>