diff --git a/app/assets/javascripts/discourse/app/components/modal/login.hbs b/app/assets/javascripts/discourse/app/components/modal/login.hbs
index a37b43e8663..78c13dc0490 100644
--- a/app/assets/javascripts/discourse/app/components/modal/login.hbs
+++ b/app/assets/javascripts/discourse/app/components/modal/login.hbs
@@ -9,78 +9,97 @@
<:body>
- {{#if this.site.mobileView}}
-
- {{#if this.showLoginButtons}}
-
- {{/if}}
- {{/if}}
-
- {{#if this.canLoginLocal}}
+ {{#if this.hasNoLoginOptions}}
-
+
- {{/unless}}
- {{#if this.hasAtLeastOneLoginButton}}
-
+
+ {{else}}
+ {{#if this.site.mobileView}}
+
+ {{#if this.showLoginButtons}}
+ {{/if}}
+ {{/if}}
+
+ {{#if this.canLoginLocal}}
+
+ {{#if this.site.desktopView}}
+
+ {{/if}}
+
+
{{/if}}
+
+ {{#if (and this.showLoginButtons this.site.desktopView)}}
+ {{#unless this.canLoginLocal}}
+
+
+
+ {{/unless}}
+ {{#if this.hasAtLeastOneLoginButton}}
+
+
+
+ {{/if}}
+ {{/if}}
{{/if}}
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/modal/login.js b/app/assets/javascripts/discourse/app/components/modal/login.js
index d401c8586a5..ee8f71a72da 100644
--- a/app/assets/javascripts/discourse/app/components/modal/login.js
+++ b/app/assets/javascripts/discourse/app/components/modal/login.js
@@ -16,6 +16,7 @@ import {
import { findAll } from "discourse/models/login-method";
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
import escape from "discourse-common/lib/escape";
+import getURL from "discourse-common/lib/get-url";
import I18n from "discourse-i18n";
export default class Login extends Component {
@@ -96,6 +97,10 @@ export default class Login extends Component {
return findAll().length > 0 || this.canUsePasskeys;
}
+ get hasNoLoginOptions() {
+ return !this.hasAtLeastOneLoginButton && !this.canLoginLocal;
+ }
+
get loginButtonLabel() {
return this.loggingIn ? "login.logging_in" : "login.title";
}
@@ -106,6 +111,10 @@ export default class Login extends Component {
);
}
+ get adminLoginPath() {
+ return getURL("/u/admin-login");
+ }
+
@action
async passkeyLogin(mediation = "optional") {
try {
diff --git a/app/assets/javascripts/discourse/tests/acceptance/modal/login/login-test.js b/app/assets/javascripts/discourse/tests/acceptance/modal/login/login-test.js
index 840949295ca..4babc46bd88 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/modal/login/login-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/modal/login/login-test.js
@@ -117,3 +117,20 @@ acceptance("Modal - Login - Passkeys on mobile", function (needs) {
assert.dom(".dialog-body").exists();
});
});
+
+acceptance("Modal - Login - With no way to login", function (needs) {
+ needs.settings({
+ enable_local_logins: false,
+ enable_facebook_logins: false,
+ });
+ needs.site({ auth_providers: [] });
+
+ test("Displays a helpful message", async function (assert) {
+ await visit("/");
+ await click("header .login-button");
+
+ assert.dom("#login-account-name").doesNotExist();
+ assert.dom("#login-button").doesNotExist();
+ assert.dom(".no-login-methods-configured").exists();
+ });
+});
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 3c353a55eab..ba25786bfcb 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2270,6 +2270,9 @@ en:
totp: "Use an authenticator app instead"
backup_code: "Use a backup code instead"
security_key: "Use a security key instead"
+ no_login_methods:
+ title: "No login methods"
+ description: "No login methods are configured. Administrators can visit
%{adminLoginPath} to reconfigure the site."
invites:
accept_title: "Invitation"
welcome_to: "Welcome to %{site_name}!"