feat: prevent duplicate auth form submissions while one is pending (#27416)

* feat: prevent duplicate auth form submissions while one is pending

When a sign in, sign up or LDAP request is slow, the auth form can be submitted again and every extra click or Enter press starts another concurrent authentication request. The form never tracked a pending state, so submitHandler dispatched a new API call on every submit event. This adds a submitting flag that makes submitHandler ignore re-entrant submits, disables both submit buttons with a dimmed style while a request is in flight and resets the flag in a finally block so the form recovers after a failed attempt. Guarding submitHandler covers button clicks and Enter key submits for sign in, sign up and LDAP alike since all of them flow through the single form submit handler.
Fixes #27264

* feat: show a spinner while an auth request is pending

Disabling the submit button stops a second submission but gives no positive sign that the first one is still running, so on a slow identity provider the form looks unresponsive rather than busy. Both submit buttons now render the existing Spinner next to their label while submitting is set, following the same in-button pattern used by the workspace editors.
This commit is contained in:
Classic298
2026-07-27 00:55:41 +02:00
committed by GitHub
parent 381149ea5e
commit 30be10f968
+41 -14
View File
@@ -42,6 +42,8 @@
let ldapUsername = '';
let submitting = false;
const setSessionUser = async (sessionUser, redirectPath: string | null = null) => {
if (sessionUser) {
console.log(sessionUser);
@@ -104,12 +106,21 @@
};
const submitHandler = async () => {
if (mode === 'ldap') {
await ldapSignInHandler();
} else if (mode === 'signin') {
await signInHandler();
} else {
await signUpHandler();
if (submitting) {
return;
}
submitting = true;
try {
if (mode === 'ldap') {
await ldapSignInHandler();
} else if (mode === 'signin') {
await signInHandler();
} else {
await signUpHandler();
}
} finally {
submitting = false;
}
};
@@ -370,21 +381,37 @@
{#if $config?.features.enable_login_form || $config?.features.enable_ldap || form}
{#if mode === 'ldap'}
<button
class="bg-gray-700/5 hover:bg-gray-700/10 dark:bg-gray-100/5 dark:hover:bg-gray-100/10 dark:text-gray-300 dark:hover:text-white transition w-full rounded-full font-normal text-sm py-2.5"
class="bg-gray-700/5 hover:bg-gray-700/10 dark:bg-gray-100/5 dark:hover:bg-gray-100/10 dark:text-gray-300 dark:hover:text-white transition w-full rounded-full font-normal text-sm py-2.5 disabled:opacity-50 flex justify-center"
type="submit"
disabled={submitting}
>
{$i18n.t('Authenticate')}
<div class="self-center">{$i18n.t('Authenticate')}</div>
{#if submitting}
<div class="ml-1.5 self-center">
<Spinner />
</div>
{/if}
</button>
{:else}
<button
class="bg-gray-700/5 hover:bg-gray-700/10 dark:bg-gray-100/5 dark:hover:bg-gray-100/10 dark:text-gray-300 dark:hover:text-white transition w-full rounded-full font-normal text-sm py-2.5"
class="bg-gray-700/5 hover:bg-gray-700/10 dark:bg-gray-100/5 dark:hover:bg-gray-100/10 dark:text-gray-300 dark:hover:text-white transition w-full rounded-full font-normal text-sm py-2.5 disabled:opacity-50 flex justify-center"
type="submit"
disabled={submitting}
>
{mode === 'signin'
? $i18n.t('Sign in')
: ($config?.onboarding ?? false)
? $i18n.t('Create Admin Account')
: $i18n.t('Create Account')}
<div class="self-center">
{mode === 'signin'
? $i18n.t('Sign in')
: ($config?.onboarding ?? false)
? $i18n.t('Create Admin Account')
: $i18n.t('Create Account')}
</div>
{#if submitting}
<div class="ml-1.5 self-center">
<Spinner />
</div>
{/if}
</button>
{#if $config?.features.enable_signup && !($config?.onboarding ?? false)}