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
This commit is contained in:
Joffrey JAFFEUX 2022-04-19 13:31:43 +02:00 committed by GitHub
parent 137e06a316
commit 01727da9b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 193 additions and 113 deletions

View File

@ -1,20 +1,17 @@
import discourseComputed, { import discourseComputed from "discourse-common/utils/decorators";
observes,
on,
} from "discourse-common/utils/decorators";
import { i18n, propertyEqual } from "discourse/lib/computed"; import { i18n, propertyEqual } from "discourse/lib/computed";
import Component from "@ember/component"; import Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
import UserField from "admin/models/user-field"; import UserField from "admin/models/user-field";
import { bufferedProperty } from "discourse/mixins/buffered-content"; import { bufferedProperty } from "discourse/mixins/buffered-content";
import { empty } from "@ember/object/computed";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { popupAjaxError } from "discourse/lib/ajax-error"; 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"), { export default Component.extend(bufferedProperty("userField"), {
editing: empty("userField.id"), tagName: "",
classNameBindings: [":user-field"], isEditing: false,
cantMoveUp: propertyEqual("userField", "firstField"), cantMoveUp: propertyEqual("userField", "firstField"),
cantMoveDown: propertyEqual("userField", "lastField"), cantMoveDown: propertyEqual("userField", "lastField"),
@ -26,21 +23,21 @@ export default Component.extend(bufferedProperty("userField"), {
return UserField.fieldTypeById(fieldType); return UserField.fieldTypeById(fieldType);
}, },
@on("didInsertElement") didInsertElement() {
@observes("editing") this._super(...arguments);
_focusOnEdit() {
if (this.editing) { this._focusName();
scheduleOnce("afterRender", this, "_focusName");
}
}, },
_focusName() { _focusName() {
$(".user-field-name").select(); schedule("afterRender", () => {
document.querySelector(".user-field-name")?.focus();
});
}, },
@discourseComputed("userField.field_type") @discourseComputed("userField.field_type")
fieldName(fieldType) { fieldName(fieldType) {
return UserField.fieldTypeById(fieldType).get("name"); return UserField.fieldTypeById(fieldType)?.name;
}, },
@discourseComputed( @discourseComputed(
@ -67,10 +64,9 @@ export default Component.extend(bufferedProperty("userField"), {
return ret.join(", "); return ret.join(", ");
}, },
actions: { @action
save() { save() {
const buffered = this.buffered; const attrs = this.buffered.getProperties(
const attrs = buffered.getProperties(
"name", "name",
"description", "description",
"field_type", "field_type",
@ -82,27 +78,32 @@ export default Component.extend(bufferedProperty("userField"), {
"options" "options"
); );
this.userField return this.userField
.save(attrs) .save(attrs)
.then(() => { .then(() => {
this.set("editing", false); if (this.isDestroying || this.isDestroyed) {
return;
}
this.set("isEditing", false);
this.commitBuffer(); this.commitBuffer();
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, },
@action
edit() { edit() {
this.set("editing", true); this.set("isEditing", true);
this._focusName();
}, },
@action
cancel() { cancel() {
const id = this.get("userField.id"); if (isEmpty(this.userField?.id)) {
if (isEmpty(id)) {
this.destroyAction(this.userField); this.destroyAction(this.userField);
} else { } else {
this.rollbackBuffer(); this.rollbackBuffer();
this.set("editing", false); this.set("isEditing", false);
} }
}, },
},
}); });

View File

@ -1,4 +1,5 @@
{{#if editing}} <div class="user-field">
{{#if (or isEditing (not userField.id))}}
{{#admin-form-row label="admin.user_fields.type"}} {{#admin-form-row label="admin.user_fields.type"}}
{{combo-box {{combo-box
content=fieldTypes content=fieldTypes
@ -42,24 +43,24 @@
{{/admin-form-row}} {{/admin-form-row}}
{{#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 "save") class="btn-primary save" icon="check" label="admin.user_fields.save"}}
{{d-button action=(action "cancel") class="btn-danger" icon="times" label="admin.user_fields.cancel"}} {{d-button action=(action "cancel") class="btn-danger cancel" icon="times" label="admin.user_fields.cancel"}}
{{/admin-form-row}} {{/admin-form-row}}
{{else}} {{else}}
<div class="row"> <div class="row">
<div class="form-display"> <div class="form-display">
<strong>{{userField.name}}</strong> <b class="name">{{userField.name}}</b>
<br> <br>
{{html-safe userField.description}} <span class="description">{{html-safe userField.description}}</span>
</div> </div>
<div class="form-display">{{fieldName}}</div> <div class="form-display field-type">{{fieldName}}</div>
<div class="form-element controls"> <div class="form-element controls">
{{d-button action=(action "edit") class="btn-default" icon="pencil-alt" label="admin.user_fields.edit"}} {{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" icon="far-trash-alt" label="admin.user_fields.delete"}} {{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=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}} {{d-button action=moveDownAction actionParam=userField class="btn-default" icon="arrow-down" disabled=cantMoveDown}}
</div> </div>
</div> </div>
<div class="row">{{flags}}</div> <div class="row">{{flags}}</div>
{{/if}} {{/if}}
<div class="clearfix"></div> </div>

View File

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