mirror of
https://github.com/discourse/discourse.git
synced 2025-03-06 03:09:43 +00:00
FEATURE: Support boolean, enum and integer fields for schema theme settings (#25933)
Continue from https://github.com/discourse/discourse/pull/25673 and https://github.com/discourse/discourse/pull/25811. This commit adds support for boolean, integer and enum types for schema theme settings.
This commit is contained in:
parent
ef292d1fed
commit
8bec0ca083
@ -96,7 +96,7 @@ export default class SchemaThemeSettingEditor extends Component {
|
||||
}
|
||||
list.push({
|
||||
name,
|
||||
type: spec.type,
|
||||
spec,
|
||||
value: node.object[name],
|
||||
});
|
||||
}
|
||||
@ -194,8 +194,8 @@ export default class SchemaThemeSettingEditor extends Component {
|
||||
{{#each this.fields as |field|}}
|
||||
<FieldInput
|
||||
@name={{field.name}}
|
||||
@type={{field.type}}
|
||||
@value={{field.value}}
|
||||
@spec={{field.spec}}
|
||||
@onValueChange={{fn this.inputFieldChanged field}}
|
||||
/>
|
||||
{{/each}}
|
||||
|
@ -1,29 +1,34 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { Input } from "@ember/component";
|
||||
import BooleanField from "./types/boolean";
|
||||
import EnumField from "./types/enum";
|
||||
import IntegerField from "./types/integer";
|
||||
import StringField from "./types/string";
|
||||
|
||||
export default class SchemaThemeSettingField extends Component {
|
||||
#bufferVal;
|
||||
|
||||
get component() {
|
||||
if (this.args.type === "string") {
|
||||
return Input;
|
||||
switch (this.args.spec.type) {
|
||||
case "string":
|
||||
return StringField;
|
||||
case "integer":
|
||||
return IntegerField;
|
||||
case "boolean":
|
||||
return BooleanField;
|
||||
case "enum":
|
||||
return EnumField;
|
||||
default:
|
||||
throw new Error("unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.#bufferVal || this.args.value;
|
||||
}
|
||||
|
||||
set value(v) {
|
||||
this.#bufferVal = v;
|
||||
this.args.onValueChange(v);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="schema-field" data-name={{@name}}>
|
||||
<label>{{@name}}</label>
|
||||
<div class="input">
|
||||
<this.component @value={{this.value}} />
|
||||
<this.component
|
||||
@value={{@value}}
|
||||
@spec={{@spec}}
|
||||
@onChange={{@onValueChange}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -0,0 +1,15 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { Input } from "@ember/component";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class SchemaThemeSettingTypeBoolean extends Component {
|
||||
@action
|
||||
onInput(event) {
|
||||
this.args.onChange(event.currentTarget.checked);
|
||||
}
|
||||
|
||||
<template>
|
||||
<Input @checked={{@value}} {{on "input" this.onInput}} @type="checkbox" />
|
||||
</template>
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import ComboBox from "select-kit/components/combo-box";
|
||||
|
||||
export default class SchemaThemeSettingTypeEnum extends Component {
|
||||
@tracked value;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.value = this.args.value;
|
||||
}
|
||||
|
||||
get content() {
|
||||
return this.args.spec.choices.map((choice) => {
|
||||
return {
|
||||
name: choice,
|
||||
id: choice,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
onInput(newVal) {
|
||||
this.value = newVal;
|
||||
this.args.onChange(newVal);
|
||||
}
|
||||
|
||||
<template>
|
||||
<ComboBox
|
||||
@content={{this.content}}
|
||||
@value={{this.value}}
|
||||
@onChange={{this.onInput}}
|
||||
/>
|
||||
</template>
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { Input } from "@ember/component";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class SchemaThemeSettingTypeInteger extends Component {
|
||||
@action
|
||||
onInput(event) {
|
||||
this.args.onChange(event.currentTarget.value);
|
||||
}
|
||||
|
||||
<template>
|
||||
<Input @value={{@value}} {{on "input" this.onInput}} @type="number" />
|
||||
</template>
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { Input } from "@ember/component";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class SchemaThemeSettingTypeString extends Component {
|
||||
@action
|
||||
onInput(event) {
|
||||
this.args.onChange(event.currentTarget.value);
|
||||
}
|
||||
|
||||
<template>
|
||||
<Input @value={{@value}} {{on "input" this.onInput}} />
|
||||
</template>
|
||||
}
|
@ -4,6 +4,9 @@ export default class AdminCustomizeThemesSchemaController extends Controller {
|
||||
data = [
|
||||
{
|
||||
name: "item 1",
|
||||
width: 143,
|
||||
is_valid: true,
|
||||
enum_prop: 11,
|
||||
children: [
|
||||
{
|
||||
name: "child 1-1",
|
||||
@ -25,6 +28,9 @@ export default class AdminCustomizeThemesSchemaController extends Controller {
|
||||
},
|
||||
{
|
||||
name: "item 2",
|
||||
width: 803,
|
||||
is_valid: false,
|
||||
enum_prop: 22,
|
||||
children: [
|
||||
{
|
||||
name: "child 2-1",
|
||||
@ -53,6 +59,16 @@ export default class AdminCustomizeThemesSchemaController extends Controller {
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
width: {
|
||||
type: "integer",
|
||||
},
|
||||
is_valid: {
|
||||
type: "boolean",
|
||||
},
|
||||
enum_prop: {
|
||||
type: "enum",
|
||||
choices: [11, 22],
|
||||
},
|
||||
children: {
|
||||
type: "objects",
|
||||
schema: {
|
||||
|
@ -159,6 +159,40 @@ export default function schemaAndData(version = 1) {
|
||||
],
|
||||
},
|
||||
];
|
||||
} else if (version === 3) {
|
||||
schema = {
|
||||
name: "something",
|
||||
identifier: "name",
|
||||
properties: {
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
integer_field: {
|
||||
type: "integer",
|
||||
},
|
||||
boolean_field: {
|
||||
type: "boolean",
|
||||
},
|
||||
enum_field: {
|
||||
type: "enum",
|
||||
choices: ["nice", "awesome", "cool"]
|
||||
}
|
||||
},
|
||||
};
|
||||
data = [
|
||||
{
|
||||
name: "lamb",
|
||||
integer_field: 92,
|
||||
boolean_field: true,
|
||||
enum_field: "awesome"
|
||||
},
|
||||
{
|
||||
name: "cow",
|
||||
integer_field: 820,
|
||||
boolean_field: false,
|
||||
enum_field: "cool"
|
||||
},
|
||||
];
|
||||
} else {
|
||||
throw new Error("unknown fixture version");
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { module, test } from "qunit";
|
||||
import schemaAndData from "discourse/tests/fixtures/theme-setting-schema-data";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { queryAll } from "discourse/tests/helpers/qunit-helpers";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import I18n from "discourse-i18n";
|
||||
import AdminSchemaThemeSettingEditor from "admin/components/schema-theme-setting/editor";
|
||||
|
||||
@ -47,6 +48,7 @@ class InputFieldsFromDOM {
|
||||
this.fields[field.dataset.name] = {
|
||||
labelElement: field.querySelector("label"),
|
||||
inputElement: field.querySelector(".input").children[0],
|
||||
selector: `.schema-field[data-name="${field.dataset.name}"]`,
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -329,6 +331,93 @@ module(
|
||||
assert.dom(inputFields.fields.icon.inputElement).hasValue("asterisk");
|
||||
});
|
||||
|
||||
test("input fields of type integer", 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.integer_field.labelElement)
|
||||
.hasText("integer_field");
|
||||
assert.dom(inputFields.fields.integer_field.inputElement).hasValue("92");
|
||||
assert
|
||||
.dom(inputFields.fields.integer_field.inputElement)
|
||||
.hasAttribute("type", "number");
|
||||
await fillIn(inputFields.fields.integer_field.inputElement, "922229");
|
||||
|
||||
const tree = new TreeFromDOM();
|
||||
await click(tree.nodes[1].element);
|
||||
|
||||
inputFields.refresh();
|
||||
|
||||
assert.dom(inputFields.fields.integer_field.inputElement).hasValue("820");
|
||||
|
||||
tree.refresh();
|
||||
await click(tree.nodes[0].element);
|
||||
inputFields.refresh();
|
||||
|
||||
assert
|
||||
.dom(inputFields.fields.integer_field.inputElement)
|
||||
.hasValue("922229");
|
||||
});
|
||||
|
||||
test("input fields of type boolean", 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.boolean_field.labelElement)
|
||||
.hasText("boolean_field");
|
||||
assert.dom(inputFields.fields.boolean_field.inputElement).isChecked();
|
||||
await click(inputFields.fields.boolean_field.inputElement);
|
||||
|
||||
const tree = new TreeFromDOM();
|
||||
await click(tree.nodes[1].element);
|
||||
|
||||
inputFields.refresh();
|
||||
assert
|
||||
.dom(inputFields.fields.boolean_field.labelElement)
|
||||
.hasText("boolean_field");
|
||||
assert.dom(inputFields.fields.boolean_field.inputElement).isNotChecked();
|
||||
|
||||
tree.refresh();
|
||||
await click(tree.nodes[0].element);
|
||||
inputFields.refresh();
|
||||
|
||||
assert.dom(inputFields.fields.boolean_field.inputElement).isNotChecked();
|
||||
});
|
||||
|
||||
test("input fields of type enum", async function (assert) {
|
||||
const [schema, data] = schemaAndData(3);
|
||||
await render(<template>
|
||||
<AdminSchemaThemeSettingEditor @schema={{schema}} @data={{data}} />
|
||||
</template>);
|
||||
|
||||
const inputFields = new InputFieldsFromDOM();
|
||||
const enumSelector = selectKit(
|
||||
`${inputFields.fields.enum_field.selector} .select-kit`
|
||||
);
|
||||
assert.strictEqual(enumSelector.header().value(), "awesome");
|
||||
|
||||
await enumSelector.expand();
|
||||
await enumSelector.selectRowByValue("nice");
|
||||
assert.strictEqual(enumSelector.header().value(), "nice");
|
||||
|
||||
const tree = new TreeFromDOM();
|
||||
await click(tree.nodes[1].element);
|
||||
assert.strictEqual(enumSelector.header().value(), "cool");
|
||||
|
||||
tree.refresh();
|
||||
|
||||
await click(tree.nodes[0].element);
|
||||
assert.strictEqual(enumSelector.header().value(), "nice");
|
||||
});
|
||||
|
||||
test("identifier field instantly updates in the navigation tree when the input field is changed", async function (assert) {
|
||||
const [schema, data] = schemaAndData(2);
|
||||
await render(<template>
|
||||
|
Loading…
x
Reference in New Issue
Block a user