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")
+ );
+ },
+ });
+ }
+);