From f8a4c983d1ab4c68e46cce8db2e435053e69bb2a Mon Sep 17 00:00:00 2001 From: Kelv Date: Thu, 9 Jan 2025 08:20:21 +0800 Subject: [PATCH] DEV: replace nameValidation mixin with helper class (#30615) This PR moves the logic from the nameValidation mixin to a helper class. I've opted to maintain the interface of the previous classes through native getters in combination with dependentKeyCompat so that we limit the amount of changes here (these are referenced in the string form and across classes/templates), and avoid introducing more computed properties from the old reactivity system (alias, readOnly etc.). We now return a POJO for nameValidation since returning an EmberObject makes no difference here. Deprecation warning added to the nameValidation mixin as it's still used in a plugin. --- .../app/components/modal/create-account.js | 22 +++++++++--- .../discourse/app/controllers/invites-show.js | 14 ++++++-- .../discourse/app/controllers/signup.js | 22 +++++++++--- .../app/lib/name-validation-helper.js | 36 +++++++++++++++++++ .../discourse/app/mixins/name-validation.js | 13 +++++++ .../discourse/app/templates/invites/show.hbs | 4 ++- 6 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 app/assets/javascripts/discourse/app/lib/name-validation-helper.js diff --git a/app/assets/javascripts/discourse/app/components/modal/create-account.js b/app/assets/javascripts/discourse/app/components/modal/create-account.js index 1efd081b796..ad56ee7495c 100644 --- a/app/assets/javascripts/discourse/app/components/modal/create-account.js +++ b/app/assets/javascripts/discourse/app/components/modal/create-account.js @@ -1,6 +1,7 @@ import { A } from "@ember/array"; import Component from "@ember/component"; import EmberObject, { action } from "@ember/object"; +import { dependentKeyCompat } from "@ember/object/compat"; import { alias, notEmpty } from "@ember/object/computed"; import { service } from "@ember/service"; import { isEmpty } from "@ember/utils"; @@ -9,9 +10,9 @@ import { Promise } from "rsvp"; import { ajax } from "discourse/lib/ajax"; import { setting } from "discourse/lib/computed"; import cookie, { removeCookie } from "discourse/lib/cookie"; +import NameValidationHelper from "discourse/lib/name-validation-helper"; import { userPath } from "discourse/lib/url"; import { emailValid } from "discourse/lib/utilities"; -import NameValidation from "discourse/mixins/name-validation"; import PasswordValidation from "discourse/mixins/password-validation"; import UserFieldsValidation from "discourse/mixins/user-fields-validation"; import UsernameValidation from "discourse/mixins/username-validation"; @@ -24,7 +25,6 @@ import { i18n } from "discourse-i18n"; export default class CreateAccount extends Component.extend( PasswordValidation, UsernameValidation, - NameValidation, UserFieldsValidation ) { @service site; @@ -41,6 +41,7 @@ export default class CreateAccount extends Component.extend( maskPassword = true; passwordValidationVisible = false; emailValidationVisible = false; + nameValidationHelper = new NameValidationHelper(this); @notEmpty("model.authOptions") hasAuthOptions; @setting("enable_local_logins") canCreateLocal; @@ -69,6 +70,19 @@ export default class CreateAccount extends Component.extend( } } + get nameTitle() { + return this.nameValidationHelper.nameTitle; + } + + get nameValidation() { + return this.nameValidationHelper.nameValidation; + } + + @dependentKeyCompat + get forceValidationReason() { + return this.nameValidationHelper.forceValidationReason; + } + @bind actionOnEnter(event) { if (!this.submitDisabled && event.key === "Enter") { @@ -510,7 +524,7 @@ export default class CreateAccount extends Component.extend( @action createAccount() { this.set("flash", ""); - this.set("forceValidationReason", true); + this.nameValidationHelper.forceValidationReason = true; this.set("emailValidationVisible", true); this.set("passwordValidationVisible", true); @@ -538,7 +552,7 @@ export default class CreateAccount extends Component.extend( return; } - this.set("forceValidationReason", false); + this.nameValidationHelper.forceValidationReason = false; this.performAccountCreation(); } } diff --git a/app/assets/javascripts/discourse/app/controllers/invites-show.js b/app/assets/javascripts/discourse/app/controllers/invites-show.js index 6a98e19b7da..f285e57fa1e 100644 --- a/app/assets/javascripts/discourse/app/controllers/invites-show.js +++ b/app/assets/javascripts/discourse/app/controllers/invites-show.js @@ -1,12 +1,13 @@ import Controller from "@ember/controller"; import EmberObject, { action } from "@ember/object"; +import { dependentKeyCompat } from "@ember/object/compat"; import { alias, bool, not, readOnly } from "@ember/object/computed"; import { isEmpty } from "@ember/utils"; import { ajax } from "discourse/lib/ajax"; import { extractError } from "discourse/lib/ajax-error"; +import NameValidationHelper from "discourse/lib/name-validation-helper"; import DiscourseURL from "discourse/lib/url"; import { emailValid } from "discourse/lib/utilities"; -import NameValidation from "discourse/mixins/name-validation"; import PasswordValidation from "discourse/mixins/password-validation"; import UserFieldsValidation from "discourse/mixins/user-fields-validation"; import UsernameValidation from "discourse/mixins/username-validation"; @@ -18,10 +19,10 @@ import { i18n } from "discourse-i18n"; export default class InvitesShowController extends Controller.extend( PasswordValidation, UsernameValidation, - NameValidation, UserFieldsValidation ) { queryParams = ["t"]; + nameValidationHelper = new NameValidationHelper(this); @readOnly("model.invited_by") invitedBy; @alias("model.email") email; @@ -44,6 +45,15 @@ export default class InvitesShowController extends Controller.extend( rejectedEmails = []; maskPassword = true; + get nameTitle() { + return this.nameValidationHelper.nameTitle; + } + + @dependentKeyCompat + get nameValidation() { + return this.nameValidationHelper.nameValidation; + } + authenticationComplete(options) { const props = { accountUsername: options.username, diff --git a/app/assets/javascripts/discourse/app/controllers/signup.js b/app/assets/javascripts/discourse/app/controllers/signup.js index 69aeebf39df..161c12489af 100644 --- a/app/assets/javascripts/discourse/app/controllers/signup.js +++ b/app/assets/javascripts/discourse/app/controllers/signup.js @@ -1,6 +1,7 @@ import { A } from "@ember/array"; import Controller from "@ember/controller"; import EmberObject, { action } from "@ember/object"; +import { dependentKeyCompat } from "@ember/object/compat"; import { notEmpty } from "@ember/object/computed"; import { service } from "@ember/service"; import { isEmpty } from "@ember/utils"; @@ -9,9 +10,9 @@ import { Promise } from "rsvp"; import { ajax } from "discourse/lib/ajax"; import { setting } from "discourse/lib/computed"; import cookie, { removeCookie } from "discourse/lib/cookie"; +import NameValidationHelper from "discourse/lib/name-validation-helper"; import { userPath } from "discourse/lib/url"; import { emailValid } from "discourse/lib/utilities"; -import NameValidation from "discourse/mixins/name-validation"; import PasswordValidation from "discourse/mixins/password-validation"; import UserFieldsValidation from "discourse/mixins/user-fields-validation"; import UsernameValidation from "discourse/mixins/username-validation"; @@ -24,7 +25,6 @@ import { i18n } from "discourse-i18n"; export default class SignupPageController extends Controller.extend( PasswordValidation, UsernameValidation, - NameValidation, UserFieldsValidation ) { @service site; @@ -41,6 +41,7 @@ export default class SignupPageController extends Controller.extend( maskPassword = true; passwordValidationVisible = false; emailValidationVisible = false; + nameValidationHelper = new NameValidationHelper(this); @notEmpty("authOptions") hasAuthOptions; @setting("enable_local_logins") canCreateLocal; @@ -56,6 +57,19 @@ export default class SignupPageController extends Controller.extend( this.fetchConfirmationValue(); } + get nameTitle() { + return this.nameValidationHelper.nameTitle; + } + + get nameValidation() { + return this.nameValidationHelper.nameValidation; + } + + @dependentKeyCompat + get forceValidationReason() { + return this.nameValidationHelper.forceValidationReason; + } + @bind actionOnEnter(event) { if (!this.submitDisabled && event.key === "Enter") { @@ -502,7 +516,7 @@ export default class SignupPageController extends Controller.extend( @action createAccount() { this.set("flash", ""); - this.set("forceValidationReason", true); + this.nameValidationHelper.forceValidationReason = true; this.set("emailValidationVisible", true); this.set("passwordValidationVisible", true); @@ -530,7 +544,7 @@ export default class SignupPageController extends Controller.extend( return; } - this.set("forceValidationReason", false); + this.nameValidationHelper.forceValidationReason = false; this.performAccountCreation(); } } diff --git a/app/assets/javascripts/discourse/app/lib/name-validation-helper.js b/app/assets/javascripts/discourse/app/lib/name-validation-helper.js new file mode 100644 index 00000000000..13d18e8bdcf --- /dev/null +++ b/app/assets/javascripts/discourse/app/lib/name-validation-helper.js @@ -0,0 +1,36 @@ +import { tracked } from "@glimmer/tracking"; +import { isEmpty } from "@ember/utils"; +import { i18n } from "discourse-i18n"; + +export default class NameValidationHelper { + @tracked forceValidationReason = false; + + constructor(owner) { + this.owner = owner; + } + + get nameTitle() { + return i18n( + this.owner.site.full_name_required_for_signup + ? "user.name.title" + : "user.name.title_optional" + ); + } + + get nameValidation() { + if ( + this.owner.site.full_name_required_for_signup && + isEmpty(this.owner.get("accountName")) + ) { + return { + failed: true, + ok: false, + message: i18n("user.name.required"), + reason: this.forceValidationReason ? i18n("user.name.required") : null, + element: document.querySelector("#new-account-name"), + }; + } + + return { ok: true }; + } +} diff --git a/app/assets/javascripts/discourse/app/mixins/name-validation.js b/app/assets/javascripts/discourse/app/mixins/name-validation.js index 3677e7347d1..834fd1458bb 100644 --- a/app/assets/javascripts/discourse/app/mixins/name-validation.js +++ b/app/assets/javascripts/discourse/app/mixins/name-validation.js @@ -1,9 +1,22 @@ import EmberObject, { computed } from "@ember/object"; import Mixin from "@ember/object/mixin"; import { isEmpty } from "@ember/utils"; +import deprecated from "discourse-common/lib/deprecated"; import { i18n } from "discourse-i18n"; export default Mixin.create({ + init() { + this._super(...arguments); + + deprecated( + "NameValidation mixin is deprecated. Use the helper class from discourse/lib/name-validation-helper instead.", + { + id: "discourse.name-validation-mixin", + since: "v3.4.0.beta4-dev", + } + ); + }, + get nameTitle() { return i18n( this.site.full_name_required_for_signup diff --git a/app/assets/javascripts/discourse/app/templates/invites/show.hbs b/app/assets/javascripts/discourse/app/templates/invites/show.hbs index 1c1f9ea6b4d..49010cc7658 100644 --- a/app/assets/javascripts/discourse/app/templates/invites/show.hbs +++ b/app/assets/javascripts/discourse/app/templates/invites/show.hbs @@ -17,7 +17,9 @@ {{else}}

{{i18n "invites.invited_by"}}

-

+

+ +

{{#if this.associateHtml}}