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.
This commit is contained in:
Kelv 2025-01-09 08:20:21 +08:00 committed by GitHub
parent f599f7155e
commit f8a4c983d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 100 additions and 11 deletions

View File

@ -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();
}
}

View File

@ -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,

View File

@ -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();
}
}

View File

@ -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 };
}
}

View File

@ -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

View File

@ -17,7 +17,9 @@
{{else}}
<div class="invited-by">
<p>{{i18n "invites.invited_by"}}</p>
<p><UserInfo @user={{this.invitedBy}} /></p>
<p>
<UserInfo @user={{this.invitedBy}} />
</p>
</div>
{{#if this.associateHtml}}