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.