From 01727da9b04a68c8b993191f633764d3e8b80e50 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 Apr 2022 13:31:43 +0200 Subject: [PATCH] REFACTOR: admin-user-field-item (#16499) - drops jquery - removes a deprecation caused by overriding a computed property (isEditing) - adds basic tests - drops observers - uses @action - tagless --- .../addon/components/admin-user-field-item.js | 101 +++++++------- .../components/admin-user-field-item.hbs | 127 +++++++++--------- .../components/admin-user-field-item-test.js | 78 +++++++++++ 3 files changed, 193 insertions(+), 113 deletions(-) create mode 100644 app/assets/javascripts/discourse/tests/integration/components/admin-user-field-item-test.js diff --git a/app/assets/javascripts/admin/addon/components/admin-user-field-item.js b/app/assets/javascripts/admin/addon/components/admin-user-field-item.js index be2674ec6c4..73ad07612ca 100644 --- a/app/assets/javascripts/admin/addon/components/admin-user-field-item.js +++ b/app/assets/javascripts/admin/addon/components/admin-user-field-item.js @@ -1,20 +1,17 @@ -import discourseComputed, { - observes, - on, -} from "discourse-common/utils/decorators"; +import discourseComputed from "discourse-common/utils/decorators"; import { i18n, propertyEqual } from "discourse/lib/computed"; import Component from "@ember/component"; import I18n from "I18n"; import UserField from "admin/models/user-field"; import { bufferedProperty } from "discourse/mixins/buffered-content"; -import { empty } from "@ember/object/computed"; import { isEmpty } from "@ember/utils"; import { popupAjaxError } from "discourse/lib/ajax-error"; -import { scheduleOnce } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import { action } from "@ember/object"; export default Component.extend(bufferedProperty("userField"), { - editing: empty("userField.id"), - classNameBindings: [":user-field"], + tagName: "", + isEditing: false, cantMoveUp: propertyEqual("userField", "firstField"), cantMoveDown: propertyEqual("userField", "lastField"), @@ -26,21 +23,21 @@ export default Component.extend(bufferedProperty("userField"), { return UserField.fieldTypeById(fieldType); }, - @on("didInsertElement") - @observes("editing") - _focusOnEdit() { - if (this.editing) { - scheduleOnce("afterRender", this, "_focusName"); - } + didInsertElement() { + this._super(...arguments); + + this._focusName(); }, _focusName() { - $(".user-field-name").select(); + schedule("afterRender", () => { + document.querySelector(".user-field-name")?.focus(); + }); }, @discourseComputed("userField.field_type") fieldName(fieldType) { - return UserField.fieldTypeById(fieldType).get("name"); + return UserField.fieldTypeById(fieldType)?.name; }, @discourseComputed( @@ -67,42 +64,46 @@ export default Component.extend(bufferedProperty("userField"), { return ret.join(", "); }, - actions: { - save() { - const buffered = this.buffered; - const attrs = buffered.getProperties( - "name", - "description", - "field_type", - "editable", - "required", - "show_on_profile", - "show_on_user_card", - "searchable", - "options" - ); + @action + save() { + const attrs = this.buffered.getProperties( + "name", + "description", + "field_type", + "editable", + "required", + "show_on_profile", + "show_on_user_card", + "searchable", + "options" + ); - this.userField - .save(attrs) - .then(() => { - this.set("editing", false); - this.commitBuffer(); - }) - .catch(popupAjaxError); - }, + return this.userField + .save(attrs) + .then(() => { + if (this.isDestroying || this.isDestroyed) { + return; + } - edit() { - this.set("editing", true); - }, + this.set("isEditing", false); + this.commitBuffer(); + }) + .catch(popupAjaxError); + }, - cancel() { - const id = this.get("userField.id"); - if (isEmpty(id)) { - this.destroyAction(this.userField); - } else { - this.rollbackBuffer(); - this.set("editing", false); - } - }, + @action + edit() { + this.set("isEditing", true); + this._focusName(); + }, + + @action + cancel() { + if (isEmpty(this.userField?.id)) { + this.destroyAction(this.userField); + } else { + this.rollbackBuffer(); + this.set("isEditing", false); + } }, }); diff --git a/app/assets/javascripts/admin/addon/templates/components/admin-user-field-item.hbs b/app/assets/javascripts/admin/addon/templates/components/admin-user-field-item.hbs index 06ab7a286e2..6cb97de9a0d 100644 --- a/app/assets/javascripts/admin/addon/templates/components/admin-user-field-item.hbs +++ b/app/assets/javascripts/admin/addon/templates/components/admin-user-field-item.hbs @@ -1,65 +1,66 @@ -{{#if editing}} - {{#admin-form-row label="admin.user_fields.type"}} - {{combo-box - content=fieldTypes - value=buffered.field_type - onChange=(action (mut buffered.field_type)) - }} - {{/admin-form-row}} - - {{#admin-form-row label="admin.user_fields.name"}} - {{input value=buffered.name class="user-field-name" maxlength="255"}} - {{/admin-form-row}} - - {{#admin-form-row label="admin.user_fields.description"}} - {{input value=buffered.description class="user-field-desc" maxlength="255"}} - {{/admin-form-row}} - - {{#if bufferedFieldType.hasOptions}} - {{#admin-form-row label="admin.user_fields.options"}} - {{value-list values=buffered.options inputType="array"}} +
+ {{#if (or isEditing (not userField.id))}} + {{#admin-form-row label="admin.user_fields.type"}} + {{combo-box + content=fieldTypes + value=buffered.field_type + onChange=(action (mut buffered.field_type)) + }} {{/admin-form-row}} + + {{#admin-form-row label="admin.user_fields.name"}} + {{input value=buffered.name class="user-field-name" maxlength="255"}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.user_fields.description"}} + {{input value=buffered.description class="user-field-desc" maxlength="255"}} + {{/admin-form-row}} + + {{#if bufferedFieldType.hasOptions}} + {{#admin-form-row label="admin.user_fields.options"}} + {{value-list values=buffered.options inputType="array"}} + {{/admin-form-row}} + {{/if}} + + {{#admin-form-row wrapLabel="true"}} + {{input type="checkbox" checked=buffered.editable}} {{i18n "admin.user_fields.editable.title"}} + {{/admin-form-row}} + + {{#admin-form-row wrapLabel="true"}} + {{input type="checkbox" checked=buffered.required}} {{i18n "admin.user_fields.required.title"}} + {{/admin-form-row}} + + {{#admin-form-row wrapLabel="true"}} + {{input type="checkbox" checked=buffered.show_on_profile}} {{i18n "admin.user_fields.show_on_profile.title"}} + {{/admin-form-row}} + + {{#admin-form-row wrapLabel="true"}} + {{input type="checkbox" checked=buffered.show_on_user_card}} {{i18n "admin.user_fields.show_on_user_card.title"}} + {{/admin-form-row}} + + {{#admin-form-row wrapLabel="true"}} + {{input type="checkbox" checked=buffered.searchable}} {{i18n "admin.user_fields.searchable.title"}} + {{/admin-form-row}} + + {{#admin-form-row}} + {{d-button action=(action "save") class="btn-primary save" icon="check" label="admin.user_fields.save"}} + {{d-button action=(action "cancel") class="btn-danger cancel" icon="times" label="admin.user_fields.cancel"}} + {{/admin-form-row}} + {{else}} +
+
+ {{userField.name}} +
+ {{html-safe userField.description}} +
+
{{fieldName}}
+
+ {{d-button action=(action "edit") class="btn-default edit" icon="pencil-alt" label="admin.user_fields.edit"}} + {{d-button action=destroyAction actionParam=userField class="btn-danger cancel" icon="far-trash-alt" label="admin.user_fields.delete"}} + {{d-button action=moveUpAction actionParam=userField class="btn-default" icon="arrow-up" disabled=cantMoveUp}} + {{d-button action=moveDownAction actionParam=userField class="btn-default" icon="arrow-down" disabled=cantMoveDown}} +
+
+
{{flags}}
{{/if}} - - {{#admin-form-row wrapLabel="true"}} - {{input type="checkbox" checked=buffered.editable}} {{i18n "admin.user_fields.editable.title"}} - {{/admin-form-row}} - - {{#admin-form-row wrapLabel="true"}} - {{input type="checkbox" checked=buffered.required}} {{i18n "admin.user_fields.required.title"}} - {{/admin-form-row}} - - {{#admin-form-row wrapLabel="true"}} - {{input type="checkbox" checked=buffered.show_on_profile}} {{i18n "admin.user_fields.show_on_profile.title"}} - {{/admin-form-row}} - - {{#admin-form-row wrapLabel="true"}} - {{input type="checkbox" checked=buffered.show_on_user_card}} {{i18n "admin.user_fields.show_on_user_card.title"}} - {{/admin-form-row}} - - {{#admin-form-row wrapLabel="true"}} - {{input type="checkbox" checked=buffered.searchable}} {{i18n "admin.user_fields.searchable.title"}} - {{/admin-form-row}} - - {{#admin-form-row}} - {{d-button action=(action "save") class="btn-primary" icon="check" label="admin.user_fields.save"}} - {{d-button action=(action "cancel") class="btn-danger" icon="times" label="admin.user_fields.cancel"}} - {{/admin-form-row}} -{{else}} -
-
- {{userField.name}} -
- {{html-safe userField.description}} -
-
{{fieldName}}
-
- {{d-button action=(action "edit") class="btn-default" icon="pencil-alt" label="admin.user_fields.edit"}} - {{d-button action=destroyAction actionParam=userField class="btn-danger" icon="far-trash-alt" label="admin.user_fields.delete"}} - {{d-button action=moveUpAction actionParam=userField class="btn-default" icon="arrow-up" disabled=cantMoveUp}} - {{d-button action=moveDownAction actionParam=userField class="btn-default" icon="arrow-down" disabled=cantMoveDown}} -
-
-
{{flags}}
-{{/if}} -
+
diff --git a/app/assets/javascripts/discourse/tests/integration/components/admin-user-field-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/admin-user-field-item-test.js new file mode 100644 index 00000000000..f8501c3df1e --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/admin-user-field-item-test.js @@ -0,0 +1,78 @@ +import componentTest, { + setupRenderingTest, +} from "discourse/tests/helpers/component-test"; +import { + discourseModule, + exists, + query, +} from "discourse/tests/helpers/qunit-helpers"; +import hbs from "htmlbars-inline-precompile"; +import I18n from "I18n"; +import { click } from "@ember/test-helpers"; + +discourseModule( + "Integration | Component | admin-user-field-item", + function (hooks) { + setupRenderingTest(hooks); + + componentTest("user field without an id", { + template: hbs`{{admin-user-field-item userField=userField}}`, + + async test(assert) { + assert.ok(exists(".save"), "displays editing mode"); + }, + }); + + componentTest("cancel action", { + template: hbs`{{admin-user-field-item isEditing=isEditing destroyAction=destroyAction userField=userField}}`, + + beforeEach() { + this.set("userField", { id: 1, field_type: "text" }); + this.set("isEditing", true); + }, + + async test(assert) { + await click(".cancel"); + assert.ok(exists(".edit")); + }, + }); + + componentTest("edit action", { + template: hbs`{{admin-user-field-item destroyAction=destroyAction userField=userField}}`, + + beforeEach() { + this.set("userField", { id: 1, field_type: "text" }); + }, + + async test(assert) { + await click(".edit"); + assert.ok(exists(".save")); + }, + }); + + componentTest("user field with an id", { + template: hbs`{{admin-user-field-item userField=userField}}`, + + beforeEach() { + this.set("userField", { + id: 1, + field_type: "text", + name: "foo", + description: "what is foo", + }); + }, + + async test(assert) { + assert.equal(query(".name").innerText, this.userField.name); + assert.equal( + query(".description").innerText, + this.userField.description + ); + assert.equal( + query(".field-type").innerText, + I18n.t("admin.user_fields.field_types.text") + ); + }, + }); + } +);