UX: Improve group selector in theme objects editor (#26312)

Why this change?

Prior to this change, the group selector was using the `<GroupChooser>`
component which is a `<MultiSelectComponent>` and is not ideal in our
situation when we only allow a single group to be selected.

The other problem is that we are doing an async load of the groups when
it is already loaded and available in the `Site` service.
This commit is contained in:
Alan Guo Xiang Tan 2024-03-22 10:29:33 +08:00 committed by GitHub
parent ec9597db5a
commit 2417b090a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 37 deletions

View File

@ -1,29 +1,36 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import { hash } from "@ember/helper";
import { action } from "@ember/object"; import { action } from "@ember/object";
import Group from "discourse/models/group"; import { service } from "@ember/service";
import FieldInputDescription from "admin/components/schema-theme-setting/field-input-description"; import FieldInputDescription from "admin/components/schema-theme-setting/field-input-description";
import GroupChooser from "select-kit/components/group-chooser"; import ComboBoxComponent from "select-kit/components/combo-box";
export default class SchemaThemeSettingTypeGroup extends Component { export default class SchemaThemeSettingTypeGroup extends Component {
@service site;
@tracked value = this.args.value; @tracked value = this.args.value;
@tracked groups = Group.findAll().then((groups) => {
this.groups = groups; required = this.args.spec.required;
});
@action @action
onInput(newVal) { onInput(newVal) {
this.value = newVal[0]; this.value = newVal;
this.args.onChange(newVal[0]); this.args.onChange(newVal);
}
get groupChooserOptions() {
return {
clearable: !this.required,
filterable: true,
none: null,
};
} }
<template> <template>
<GroupChooser <ComboBoxComponent
@content={{this.groups}} @content={{this.site.groups}}
@value={{this.value}} @value={{this.value}}
@onChange={{this.onInput}} @onChange={{this.onInput}}
@options={{hash maximum=1}} @options={{this.groupChooserOptions}}
/> />
<FieldInputDescription @description={{@description}} /> <FieldInputDescription @description={{@description}} />

View File

@ -268,6 +268,10 @@ export default function selectKit(selector) {
return rowHelper(query(selector).querySelector(".select-kit-row.none")); return rowHelper(query(selector).querySelector(".select-kit-row.none"));
}, },
clearButton() {
return query(selector).querySelector(".btn-clear");
},
validationMessage() { validationMessage() {
const validationMessage = query(selector).querySelector( const validationMessage = query(selector).querySelector(
".validation-message" ".validation-message"

View File

@ -2,7 +2,6 @@ import { click, fillIn, render } from "@ember/test-helpers";
import { module, test } from "qunit"; import { module, test } from "qunit";
import schemaAndData from "discourse/tests/fixtures/theme-setting-schema-data"; import schemaAndData from "discourse/tests/fixtures/theme-setting-schema-data";
import { setupRenderingTest } from "discourse/tests/helpers/component-test"; import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import { queryAll } from "discourse/tests/helpers/qunit-helpers"; import { queryAll } from "discourse/tests/helpers/qunit-helpers";
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
@ -729,43 +728,57 @@ module(
}); });
test("input fields of type group", async function (assert) { test("input fields of type group", async function (assert) {
pretender.get("/groups/search.json", () => { const setting = ThemeSettings.create({
return response(200, [ setting: "objects_setting",
{ id: 23, name: "testers" }, objects_schema: {
{ id: 74, name: "devs" }, name: "something",
{ id: 89, name: "customers" }, identifier: "id",
]); properties: {
required_group: {
type: "group",
required: true,
},
not_required_group: {
type: "group",
},
},
},
value: [
{
required_group: 6,
},
],
}); });
const setting = schemaAndData(3);
await render(<template> await render(<template>
<AdminSchemaThemeSettingEditor @themeId="1" @setting={{setting}} /> <AdminSchemaThemeSettingEditor @themeId="1" @setting={{setting}} />
</template>); </template>);
const inputFields = new InputFieldsFromDOM(); const inputFields = new InputFieldsFromDOM();
const groupSelector = selectKit(
`${inputFields.fields.group_field.selector} .select-kit` assert
.dom(inputFields.fields.required_group.labelElement)
.hasText("required_group*");
let groupSelector = selectKit(
`${inputFields.fields.required_group.selector} .select-kit`
); );
assert.strictEqual(groupSelector.header().value(), null); assert.strictEqual(groupSelector.header().value(), "6");
assert.dom(groupSelector.clearButton()).doesNotExist("is not clearable");
assert
.dom(inputFields.fields.not_required_group.labelElement)
.hasText("not_required_group");
groupSelector = selectKit(
`${inputFields.fields.not_required_group.selector} .select-kit`
);
await groupSelector.expand(); await groupSelector.expand();
await groupSelector.selectRowByValue(74); await groupSelector.selectRowByIndex(1);
assert.strictEqual(groupSelector.header().value(), "74");
const tree = new TreeFromDOM(); assert.dom(groupSelector.clearButton()).exists("is clearable");
await click(tree.nodes[1].element);
assert.strictEqual(groupSelector.header().value(), null);
await groupSelector.expand();
await groupSelector.selectRowByValue(23);
assert.strictEqual(groupSelector.header().value(), "23");
tree.refresh();
await click(tree.nodes[0].element);
assert.strictEqual(groupSelector.header().value(), "74");
}); });
test("generic identifier is used when identifier is not specified in the schema", async function (assert) { test("generic identifier is used when identifier is not specified in the schema", async function (assert) {