mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Support category, float, group and tag inputs for objects theme setting (#26113)
Continue from https://github.com/discourse/discourse/pull/25673 and https://github.com/discourse/discourse/pull/25811. This PR adds support for category, float, group and tag types for schema theme settings.
This commit is contained in:
parent
de00c9a3d3
commit
3a4f4abdc9
@ -1,8 +1,12 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import BooleanField from "./types/boolean";
|
import BooleanField from "./types/boolean";
|
||||||
|
import CategoryField from "./types/category";
|
||||||
import EnumField from "./types/enum";
|
import EnumField from "./types/enum";
|
||||||
|
import FloatField from "./types/float";
|
||||||
|
import GroupField from "./types/group";
|
||||||
import IntegerField from "./types/integer";
|
import IntegerField from "./types/integer";
|
||||||
import StringField from "./types/string";
|
import StringField from "./types/string";
|
||||||
|
import TagField from "./types/tag";
|
||||||
|
|
||||||
export default class SchemaThemeSettingField extends Component {
|
export default class SchemaThemeSettingField extends Component {
|
||||||
get component() {
|
get component() {
|
||||||
@ -11,10 +15,18 @@ export default class SchemaThemeSettingField extends Component {
|
|||||||
return StringField;
|
return StringField;
|
||||||
case "integer":
|
case "integer":
|
||||||
return IntegerField;
|
return IntegerField;
|
||||||
|
case "float":
|
||||||
|
return FloatField;
|
||||||
case "boolean":
|
case "boolean":
|
||||||
return BooleanField;
|
return BooleanField;
|
||||||
case "enum":
|
case "enum":
|
||||||
return EnumField;
|
return EnumField;
|
||||||
|
case "category":
|
||||||
|
return CategoryField;
|
||||||
|
case "tag":
|
||||||
|
return TagField;
|
||||||
|
case "group":
|
||||||
|
return GroupField;
|
||||||
default:
|
default:
|
||||||
throw new Error("unknown type");
|
throw new Error("unknown type");
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import CategoryChooser from "select-kit/components/category-chooser";
|
||||||
|
|
||||||
|
export default class SchemaThemeSettingTypeCategory extends Component {
|
||||||
|
@tracked value = this.args.value;
|
||||||
|
|
||||||
|
@action
|
||||||
|
onInput(newVal) {
|
||||||
|
this.value = newVal;
|
||||||
|
this.args.onChange(newVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CategoryChooser
|
||||||
|
@value={{this.value}}
|
||||||
|
@onChange={{this.onInput}}
|
||||||
|
@options={{hash allowUncategorized=false}}
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -4,12 +4,7 @@ import { action } from "@ember/object";
|
|||||||
import ComboBox from "select-kit/components/combo-box";
|
import ComboBox from "select-kit/components/combo-box";
|
||||||
|
|
||||||
export default class SchemaThemeSettingTypeEnum extends Component {
|
export default class SchemaThemeSettingTypeEnum extends Component {
|
||||||
@tracked value;
|
@tracked value = this.args.value;
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super(...arguments);
|
|
||||||
this.value = this.args.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get content() {
|
get content() {
|
||||||
return this.args.spec.choices.map((choice) => {
|
return this.args.spec.choices.map((choice) => {
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { Input } from "@ember/component";
|
||||||
|
import { on } from "@ember/modifier";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
|
export default class SchemaThemeSettingTypeFloat extends Component {
|
||||||
|
@action
|
||||||
|
onInput(event) {
|
||||||
|
this.args.onChange(parseFloat(event.currentTarget.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Input
|
||||||
|
@value={{@value}}
|
||||||
|
{{on "input" this.onInput}}
|
||||||
|
@type="number"
|
||||||
|
step="0.1"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import Group from "discourse/models/group";
|
||||||
|
import GroupChooser from "select-kit/components/group-chooser";
|
||||||
|
|
||||||
|
export default class SchemaThemeSettingTypeGroup extends Component {
|
||||||
|
@tracked value = this.args.value;
|
||||||
|
@tracked groups = Group.findAll().then((groups) => {
|
||||||
|
this.groups = groups;
|
||||||
|
});
|
||||||
|
|
||||||
|
@action
|
||||||
|
onInput(newVal) {
|
||||||
|
this.value = newVal[0];
|
||||||
|
this.args.onChange(newVal[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<GroupChooser
|
||||||
|
@content={{this.groups}}
|
||||||
|
@value={{this.value}}
|
||||||
|
@onChange={{this.onInput}}
|
||||||
|
@options={{hash maximum=1}}
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -6,7 +6,7 @@ import { action } from "@ember/object";
|
|||||||
export default class SchemaThemeSettingTypeInteger extends Component {
|
export default class SchemaThemeSettingTypeInteger extends Component {
|
||||||
@action
|
@action
|
||||||
onInput(event) {
|
onInput(event) {
|
||||||
this.args.onChange(event.currentTarget.value);
|
this.args.onChange(parseInt(event.currentTarget.value, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import TagChooser from "select-kit/components/tag-chooser";
|
||||||
|
|
||||||
|
export default class SchemaThemeSettingTypeTag extends Component {
|
||||||
|
@tracked value = this.args.value;
|
||||||
|
|
||||||
|
@action
|
||||||
|
onInput(newVal) {
|
||||||
|
this.value = newVal;
|
||||||
|
this.args.onChange(newVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<TagChooser
|
||||||
|
@tags={{this.value}}
|
||||||
|
@onChange={{this.onInput}}
|
||||||
|
@options={{hash allowAny=false}}
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -172,12 +172,24 @@ export default function schemaAndData(version = 1) {
|
|||||||
integer_field: {
|
integer_field: {
|
||||||
type: "integer",
|
type: "integer",
|
||||||
},
|
},
|
||||||
|
float_field: {
|
||||||
|
type: "float",
|
||||||
|
},
|
||||||
boolean_field: {
|
boolean_field: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
},
|
},
|
||||||
enum_field: {
|
enum_field: {
|
||||||
type: "enum",
|
type: "enum",
|
||||||
choices: ["nice", "awesome", "cool"]
|
choices: ["nice", "awesome", "cool"]
|
||||||
|
},
|
||||||
|
category_field: {
|
||||||
|
type: "category",
|
||||||
|
},
|
||||||
|
group_field: {
|
||||||
|
type: "group",
|
||||||
|
},
|
||||||
|
tag_field: {
|
||||||
|
type: "tag",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ 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";
|
||||||
@ -292,6 +293,47 @@ module(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("input fields are rendered even if they're not present in the data", async function (assert) {
|
||||||
|
const schema = {
|
||||||
|
name: "something",
|
||||||
|
identifier: "id",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
id: "bu1",
|
||||||
|
name: "Big U",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fi2",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
await render(<template>
|
||||||
|
<AdminSchemaThemeSettingEditor @schema={{schema}} @data={{data}} />
|
||||||
|
</template>);
|
||||||
|
|
||||||
|
const inputFields = new InputFieldsFromDOM();
|
||||||
|
|
||||||
|
assert.strictEqual(inputFields.count, 2);
|
||||||
|
assert.dom(inputFields.fields.id.inputElement).hasValue("bu1");
|
||||||
|
assert.dom(inputFields.fields.name.inputElement).hasValue("Big U");
|
||||||
|
|
||||||
|
const tree = new TreeFromDOM();
|
||||||
|
await click(tree.nodes[1].element);
|
||||||
|
inputFields.refresh();
|
||||||
|
|
||||||
|
assert.strictEqual(inputFields.count, 2);
|
||||||
|
assert.dom(inputFields.fields.id.inputElement).hasValue("fi2");
|
||||||
|
assert.dom(inputFields.fields.name.inputElement).hasNoValue();
|
||||||
|
});
|
||||||
|
|
||||||
test("input fields for items at different levels", async function (assert) {
|
test("input fields for items at different levels", async function (assert) {
|
||||||
const setting = schemaAndData(2);
|
const setting = schemaAndData(2);
|
||||||
|
|
||||||
@ -371,6 +413,36 @@ module(
|
|||||||
.hasValue("922229");
|
.hasValue("922229");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("input fields of type float", async function (assert) {
|
||||||
|
const [schema, data] = schemaAndData(3);
|
||||||
|
await render(<template>
|
||||||
|
<AdminSchemaThemeSettingEditor @schema={{schema}} @data={{data}} />
|
||||||
|
</template>);
|
||||||
|
|
||||||
|
const inputFields = new InputFieldsFromDOM();
|
||||||
|
assert
|
||||||
|
.dom(inputFields.fields.float_field.labelElement)
|
||||||
|
.hasText("float_field");
|
||||||
|
assert.dom(inputFields.fields.float_field.inputElement).hasValue("");
|
||||||
|
|
||||||
|
await fillIn(inputFields.fields.float_field.inputElement, "6934.24");
|
||||||
|
|
||||||
|
const tree = new TreeFromDOM();
|
||||||
|
await click(tree.nodes[1].element);
|
||||||
|
|
||||||
|
inputFields.refresh();
|
||||||
|
|
||||||
|
assert.dom(inputFields.fields.float_field.inputElement).hasValue("");
|
||||||
|
|
||||||
|
tree.refresh();
|
||||||
|
await click(tree.nodes[0].element);
|
||||||
|
inputFields.refresh();
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(inputFields.fields.float_field.inputElement)
|
||||||
|
.hasValue("6934.24");
|
||||||
|
});
|
||||||
|
|
||||||
test("input fields of type boolean", async function (assert) {
|
test("input fields of type boolean", async function (assert) {
|
||||||
const setting = schemaAndData(3);
|
const setting = schemaAndData(3);
|
||||||
|
|
||||||
@ -428,6 +500,103 @@ module(
|
|||||||
assert.strictEqual(enumSelector.header().value(), "nice");
|
assert.strictEqual(enumSelector.header().value(), "nice");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("input fields of type category", async function (assert) {
|
||||||
|
const [schema, data] = schemaAndData(3);
|
||||||
|
await render(<template>
|
||||||
|
<AdminSchemaThemeSettingEditor @schema={{schema}} @data={{data}} />
|
||||||
|
</template>);
|
||||||
|
|
||||||
|
const inputFields = new InputFieldsFromDOM();
|
||||||
|
const categorySelector = selectKit(
|
||||||
|
`${inputFields.fields.category_field.selector} .select-kit`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(categorySelector.header().value(), null);
|
||||||
|
|
||||||
|
await categorySelector.expand();
|
||||||
|
await categorySelector.selectRowByIndex(1);
|
||||||
|
|
||||||
|
const selectedCategoryId = categorySelector.header().value();
|
||||||
|
assert.ok(selectedCategoryId);
|
||||||
|
|
||||||
|
const tree = new TreeFromDOM();
|
||||||
|
await click(tree.nodes[1].element);
|
||||||
|
assert.strictEqual(categorySelector.header().value(), null);
|
||||||
|
|
||||||
|
tree.refresh();
|
||||||
|
|
||||||
|
await click(tree.nodes[0].element);
|
||||||
|
assert.strictEqual(categorySelector.header().value(), selectedCategoryId);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input fields of type tag", async function (assert) {
|
||||||
|
const [schema, data] = schemaAndData(3);
|
||||||
|
await render(<template>
|
||||||
|
<AdminSchemaThemeSettingEditor @schema={{schema}} @data={{data}} />
|
||||||
|
</template>);
|
||||||
|
|
||||||
|
const inputFields = new InputFieldsFromDOM();
|
||||||
|
const tagSelector = selectKit(
|
||||||
|
`${inputFields.fields.tag_field.selector} .select-kit`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(tagSelector.header().value(), null);
|
||||||
|
|
||||||
|
await tagSelector.expand();
|
||||||
|
await tagSelector.selectRowByIndex(1);
|
||||||
|
await tagSelector.selectRowByIndex(3);
|
||||||
|
|
||||||
|
assert.strictEqual(tagSelector.header().value(), "gazelle,cat");
|
||||||
|
|
||||||
|
const tree = new TreeFromDOM();
|
||||||
|
await click(tree.nodes[1].element);
|
||||||
|
assert.strictEqual(tagSelector.header().value(), null);
|
||||||
|
|
||||||
|
tree.refresh();
|
||||||
|
|
||||||
|
await click(tree.nodes[0].element);
|
||||||
|
assert.strictEqual(tagSelector.header().value(), "gazelle,cat");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("input fields of type group", async function (assert) {
|
||||||
|
pretender.get("/groups/search.json", () => {
|
||||||
|
return response(200, [
|
||||||
|
{ id: 23, name: "testers" },
|
||||||
|
{ id: 74, name: "devs" },
|
||||||
|
{ id: 89, name: "customers" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const [schema, data] = schemaAndData(3);
|
||||||
|
await render(<template>
|
||||||
|
<AdminSchemaThemeSettingEditor @schema={{schema}} @data={{data}} />
|
||||||
|
</template>);
|
||||||
|
|
||||||
|
const inputFields = new InputFieldsFromDOM();
|
||||||
|
const groupSelector = selectKit(
|
||||||
|
`${inputFields.fields.group_field.selector} .select-kit`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(groupSelector.header().value(), null);
|
||||||
|
|
||||||
|
await groupSelector.expand();
|
||||||
|
await groupSelector.selectRowByValue(74);
|
||||||
|
assert.strictEqual(groupSelector.header().value(), "74");
|
||||||
|
|
||||||
|
const tree = new TreeFromDOM();
|
||||||
|
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("identifier field instantly updates in the navigation tree when the input field is changed", async function (assert) {
|
test("identifier field instantly updates in the navigation tree when the input field is changed", async function (assert) {
|
||||||
const setting = schemaAndData(2);
|
const setting = schemaAndData(2);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user