mirror of
https://github.com/discourse/discourse.git
synced 2026-08-11 02:59:07 +08:00
Part of the effort to convert site setting components to FormKit. Several places now need to render and edit a typed setting (or setting-like field) inside a FormKit form — the category type setup form, discourse-ai feature settings, workflows — and each does it with its own ad-hoc `type → control` chain plus duplicated `|`-delimited list (de)serialization. This introduces one shared, plugin-extensible component for that, and migrates the first two consumers onto it. ### `de8be6cc` — Add a reusable FormKit field for typed settings - A `registerSettingFieldType` registry + `resolveSettingFieldType` (resolution: `subtype` → `list`+`list_type` collapse → `type` → string fallback), generalizing the pattern from the workflows node configurator. - `SettingDefinitionField` owns the `<form.Field>` and renders the registry entry's control; built-in renderers for `bool`, `integer`, `enum`, `string`, `group_list`, `category_list`, `compact_list` and `duration`. - `settingFieldValidation` derives a field's FormKit validation from its definition. - Migrates the **category type setup** form off its inline `if/else` chain onto the shared component (−158 lines there). - Registry unit test + component integration test. ### `212e1cd` — Convert discourse-ai feature settings to SettingDefinitionField - The AI features edit page delegated to a bespoke `AiFeatureSettingField` + a hand-written control chain duplicated across two template branches. It now uses `SettingDefinitionField`, normalizing each `SiteSetting` into a field definition with a small adapter (`settingToDefinition`). - Deletes `AiFeatureSettingField`, the duplicated chain, and the controller's `getValidationFor` (validation now lives in core). **+24 / −336.** ### Behaviour notes - AI `group_list` settings now render with the shared **group chooser** (matching the rest of the admin) instead of the generic list-setting widget; value-compatible (`"1|2"`). - AI `bool`/`integer` fields inherit the registry's per-type widths. ### Testing - Unit + integration tests in core. - System specs pass together: discourse-ai AI features, plus the solved / events / ideas category-type setup specs. ### Follow-ups (deliberately out of scope here) - Canonicalize the `choices` vs `valid_values` descriptor shape. - Thread `allow_any` through free-form list settings; restore the category-list async race-guard. - Add a `float` registry entry; promote the `SiteSetting → definition` adapter to core when a second core consumer (workflows / the all-settings page) adopts the component.
96 lines
2.8 KiB
JavaScript
Vendored
96 lines
2.8 KiB
JavaScript
Vendored
import { setupTest } from "ember-qunit";
|
|
import { module, test } from "qunit";
|
|
|
|
module(
|
|
"Unit | Controller | admin-plugins/show/discourse-ai-features/edit",
|
|
function (hooks) {
|
|
setupTest(hooks);
|
|
|
|
test("valuesEqual compares using toString", function (assert) {
|
|
const controller = this.owner.lookup(
|
|
"controller:admin-plugins/show/discourse-ai-features/edit"
|
|
);
|
|
|
|
assert.true(
|
|
controller.valuesEqual("123", 123),
|
|
"string '123' should equal number 123"
|
|
);
|
|
assert.true(
|
|
controller.valuesEqual(true, "true"),
|
|
"boolean true should equal string 'true'"
|
|
);
|
|
assert.true(
|
|
controller.valuesEqual(false, "false"),
|
|
"boolean false should equal string 'false'"
|
|
);
|
|
assert.true(
|
|
controller.valuesEqual("abc", "abc"),
|
|
"identical strings should be equal"
|
|
);
|
|
assert.false(
|
|
controller.valuesEqual("123", "456"),
|
|
"different values should not be equal"
|
|
);
|
|
});
|
|
|
|
test("valuesEqual handles null and undefined", function (assert) {
|
|
const controller = this.owner.lookup(
|
|
"controller:admin-plugins/show/discourse-ai-features/edit"
|
|
);
|
|
|
|
assert.false(
|
|
controller.valuesEqual(null, "null"),
|
|
"null should not equal string 'null'"
|
|
);
|
|
assert.false(
|
|
controller.valuesEqual(undefined, "undefined"),
|
|
"undefined should not equal string 'undefined'"
|
|
);
|
|
assert.true(controller.valuesEqual(null, null), "null should equal null");
|
|
assert.true(
|
|
controller.valuesEqual(undefined, undefined),
|
|
"undefined should equal undefined"
|
|
);
|
|
assert.false(
|
|
controller.valuesEqual(null, undefined),
|
|
"null should not equal undefined"
|
|
);
|
|
});
|
|
|
|
test("findSetting returns correct setting by name", function (assert) {
|
|
const controller = this.owner.lookup(
|
|
"controller:admin-plugins/show/discourse-ai-features/edit"
|
|
);
|
|
|
|
controller.settings = [
|
|
{ setting: "setting_one", value: "value1" },
|
|
{ setting: "setting_two", value: "value2" },
|
|
{ setting: "setting_three", value: "value3" },
|
|
];
|
|
|
|
const result = controller.findSetting("setting_two");
|
|
|
|
assert.deepEqual(
|
|
result,
|
|
{ setting: "setting_two", value: "value2" },
|
|
"should return the correct setting"
|
|
);
|
|
});
|
|
|
|
test("findSetting returns undefined for non-existent setting", function (assert) {
|
|
const controller = this.owner.lookup(
|
|
"controller:admin-plugins/show/discourse-ai-features/edit"
|
|
);
|
|
|
|
controller.settings = [{ setting: "setting_one", value: "value1" }];
|
|
|
|
const result = controller.findSetting("nonexistent");
|
|
|
|
assert.strictEqual(
|
|
result,
|
|
undefined,
|
|
"should return undefined for non-existent setting"
|
|
);
|
|
});
|
|
}
|
|
);
|