From 588fd549636df2a976f56886fabe2c454e0d3997 Mon Sep 17 00:00:00 2001 From: railgun19457 Date: Mon, 18 May 2026 20:51:50 +0800 Subject: [PATCH 1/5] fix: improve template list config handling --- .../src/components/shared/AstrBotConfigV4.vue | 50 ++++++++++++++++--- .../components/shared/TemplateListEditor.vue | 1 + 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/dashboard/src/components/shared/AstrBotConfigV4.vue b/dashboard/src/components/shared/AstrBotConfigV4.vue index b08357e85b..b00be9c898 100644 --- a/dashboard/src/components/shared/AstrBotConfigV4.vue +++ b/dashboard/src/components/shared/AstrBotConfigV4.vue @@ -25,13 +25,25 @@ const props = defineProps({ searchKeyword: { type: String, default: '' + }, + pluginName: { + type: String, + default: '' + }, + pluginI18n: { + type: Object, + default: () => ({}) + }, + pathPrefix: { + type: String, + default: '' } }) const { t } = useI18n() const { getRaw } = useModuleI18n('features/config-metadata') const { tm: tmConfig } = useModuleI18n('features/config') -const { translateIfKey } = useConfigTextResolver() +const { translateIfKey, resolveConfigText } = useConfigTextResolver(props) const hintMarkdown = new MarkdownIt({ linkify: true, @@ -114,6 +126,18 @@ function createSelectorModel(selector) { }) } +function getItemPath(key) { + return props.pathPrefix ? `${props.pathPrefix}.${key}` : key +} + +function getItemDescription(itemKey, itemMeta) { + return resolveConfigText(getItemPath(itemKey), 'description', itemMeta?.description) || itemKey +} + +function getItemHint(itemKey, itemMeta) { + return resolveConfigText(getItemPath(itemKey), 'hint', itemMeta?.hint) +} + function openEditorDialog(key, value, theme, language) { currentEditingKey.value = key currentEditingLanguage.value = language || 'json' @@ -143,8 +167,8 @@ function shouldShowItem(itemMeta, itemKey) { const searchableText = [ itemKey, - translateIfKey(itemMeta?.description || ''), - translateIfKey(itemMeta?.hint || '') + getItemDescription(itemKey, itemMeta), + getItemHint(itemKey, itemMeta) ].join(' ').toLowerCase() return searchableText.includes(keyword) @@ -259,13 +283,13 @@ function getSpecialSubtype(value) { - {{ translateIfKey(itemMeta?.description) || itemKey }} + {{ getItemDescription(itemKey, itemMeta) }} ({{ itemKey }}) ‼️ - + @@ -274,12 +298,18 @@ function getSpecialSubtype(value) { v-if="itemMeta?.type === 'template_list'" v-model="createSelectorModel(itemKey).value" :templates="itemMeta?.templates || {}" + :plugin-name="pluginName" + :plugin-i18n="pluginI18n" + :config-path="getItemPath(itemKey)" class="config-field" /> @@ -339,13 +369,13 @@ function getSpecialSubtype(value) { - {{ translateIfKey(itemMeta?.description) || itemKey }} + {{ getItemDescription(itemKey, itemMeta) }} ({{ itemKey }}) ‼️ - + @@ -354,12 +384,18 @@ function getSpecialSubtype(value) { v-if="itemMeta?.type === 'template_list'" v-model="createSelectorModel(itemKey).value" :templates="itemMeta?.templates || {}" + :plugin-name="pluginName" + :plugin-i18n="pluginI18n" + :config-path="getItemPath(itemKey)" class="config-field" /> diff --git a/dashboard/src/components/shared/TemplateListEditor.vue b/dashboard/src/components/shared/TemplateListEditor.vue index 9b4b4c1838..81164464d9 100644 --- a/dashboard/src/components/shared/TemplateListEditor.vue +++ b/dashboard/src/components/shared/TemplateListEditor.vue @@ -201,6 +201,7 @@ const defaultValueMap = { string: '', text: '', list: [], + file: [], object: {}, template_list: [] } From a18e16b521b02dea5b0744f6aeb93590c0fe0339 Mon Sep 17 00:00:00 2001 From: railgun19457 Date: Mon, 18 May 2026 21:17:38 +0800 Subject: [PATCH 2/5] feat(webui): show template list display item --- .../components/shared/TemplateListEditor.vue | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/dashboard/src/components/shared/TemplateListEditor.vue b/dashboard/src/components/shared/TemplateListEditor.vue index 81164464d9..998dca6aeb 100644 --- a/dashboard/src/components/shared/TemplateListEditor.vue +++ b/dashboard/src/components/shared/TemplateListEditor.vue @@ -57,6 +57,9 @@
{{ templateLabel(entry.__template_key) }} + + {{ templateDisplayText(entry) }} + {{ templateText(entry.__template_key, 'hint', getTemplate(entry)?.hint || getTemplate(entry)?.description) }} @@ -349,6 +352,43 @@ function getTemplate(entry) { return props.templates?.[key] || null } +function getItemMetaBySelector(itemsMeta = {}, selector = '') { + const keys = selector.split('.').filter(Boolean) + let currentItems = itemsMeta + let currentMeta = null + + for (let i = 0; i < keys.length; i++) { + currentMeta = currentItems?.[keys[i]] + if (!currentMeta) return null + if (i < keys.length - 1) { + if (currentMeta.type !== 'object') return null + currentItems = currentMeta.items || {} + } + } + + return currentMeta +} + +function templateDisplayText(entry) { + const template = getTemplate(entry) + const displayItem = template?.display_item + if (!template || typeof displayItem !== 'string' || !displayItem) return '' + + const displayMeta = getItemMetaBySelector(template.items || {}, displayItem) + if (displayMeta?.type !== 'string') return '' + + const value = getValueBySelector(entry, displayItem) + if (typeof value !== 'string' || !value.trim()) return '' + + const label = templateItemText( + entry.__template_key, + displayItem, + 'description', + displayMeta.description || displayItem, + ) + return `${label}: ${value.trim()}` +} + function getValueBySelector(obj, selector) { const keys = selector.split('.') let current = obj @@ -451,6 +491,11 @@ function hasVisibleItemsAfter(entries, currentIndex, entry) { margin-top: 2px; } +.entry-display-text { + color: var(--v-theme-primary); + font-weight: 500; +} + .property-key { font-size: 0.85em; opacity: 0.7; From e4ff9b6e18f40b7560edd0bd7e7c53f47a8e9821 Mon Sep 17 00:00:00 2001 From: railgun19457 Date: Mon, 18 May 2026 21:24:58 +0800 Subject: [PATCH 3/5] feat(webui): allow hiding template list hints --- dashboard/src/components/shared/TemplateListEditor.vue | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dashboard/src/components/shared/TemplateListEditor.vue b/dashboard/src/components/shared/TemplateListEditor.vue index 998dca6aeb..ecfda28f58 100644 --- a/dashboard/src/components/shared/TemplateListEditor.vue +++ b/dashboard/src/components/shared/TemplateListEditor.vue @@ -60,8 +60,8 @@ {{ templateDisplayText(entry) }} - - {{ templateText(entry.__template_key, 'hint', getTemplate(entry)?.hint || getTemplate(entry)?.description) }} + + {{ templateHintText(entry) }}
@@ -352,6 +352,12 @@ function getTemplate(entry) { return props.templates?.[key] || null } +function templateHintText(entry) { + const template = getTemplate(entry) + if (!template || template.hide_hint_in_list) return '' + return templateText(entry.__template_key, 'hint', template.hint || template.description || '') +} + function getItemMetaBySelector(itemsMeta = {}, selector = '') { const keys = selector.split('.').filter(Boolean) let currentItems = itemsMeta From db79fdd559d4139a4d84cf8303679ddef17d1c83 Mon Sep 17 00:00:00 2001 From: railgun19457 Date: Mon, 18 May 2026 21:34:42 +0800 Subject: [PATCH 4/5] docs: document template list metadata fields --- docs/en/dev/star/guides/plugin-config.md | 13 +++++++++++++ docs/zh/dev/star/guides/plugin-config.md | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/docs/en/dev/star/guides/plugin-config.md b/docs/en/dev/star/guides/plugin-config.md index 1e02472143..cf05c94818 100644 --- a/docs/en/dev/star/guides/plugin-config.md +++ b/docs/en/dev/star/guides/plugin-config.md @@ -146,7 +146,14 @@ Plugin developers can add a template-style configuration to `_conf_schema` in th "template_1": { "name": "Template One", "hint":"hint", + "display_item": "attr_name", + "hide_hint_in_list": true, "items": { + "attr_name": { + "description": "Attribute Name", + "type": "string", + "default": "" + }, "attr_a": { "description": "Attribute A", "type": "int", @@ -187,6 +194,7 @@ Saved config example: "field_id": [ { "__template_key": "template_1", + "attr_name": "", "attr_a": 10, "attr_b": true }, @@ -198,6 +206,11 @@ Saved config example: ] ``` +Templates also support these optional fields: + +- `display_item`: Specifies the key of a `string` item inside the template `items`. When set, the WebUI shows that field's current value in the collapsed list of added template entries, for example `Attribute Name: my-adapter`, making it easier to distinguish multiple entries created from the same template. Dot paths are supported for fields inside nested objects, for example `meta.name`. +- `hide_hint_in_list`: When set to `true`, the WebUI hides the template `hint` in the collapsed list of added template entries. The template selection dropdown still shows the `hint`, and hints for fields inside the expanded entry are not affected. + image diff --git a/docs/zh/dev/star/guides/plugin-config.md b/docs/zh/dev/star/guides/plugin-config.md index 8374cdcd1f..ff2c9d99ce 100644 --- a/docs/zh/dev/star/guides/plugin-config.md +++ b/docs/zh/dev/star/guides/plugin-config.md @@ -146,7 +146,14 @@ AstrBot 提供了“强大”的配置解析和可视化功能。能够让用户 "template_1": { "name": "Template One", "hint":"hint", + "display_item": "attr_name", + "hide_hint_in_list": true, "items": { + "attr_name": { + "description": "Attribute Name", + "type": "string", + "default": "" + }, "attr_a": { "description": "Attribute A", "type": "int", @@ -187,6 +194,7 @@ AstrBot 提供了“强大”的配置解析和可视化功能。能够让用户 "field_id": [ { "__template_key": "template_1", + "attr_name": "", "attr_a": 10, "attr_b": true }, @@ -198,6 +206,11 @@ AstrBot 提供了“强大”的配置解析和可视化功能。能够让用户 ] ``` +模板本身还支持以下可选字段: + +- `display_item`: 指定模板 `items` 中一个 `string` 类型字段的 key。设置后,WebUI 会在已添加模板条目的折叠列表中显示该字段当前值,例如 `Attribute Name: my-adapter`,便于添加多个同类型模板时快速区分。支持用点号选择嵌套 object 中的字段,例如 `meta.name`。 +- `hide_hint_in_list`: 设置为 `true` 时,WebUI 会在已添加模板条目的折叠列表中隐藏该模板的 `hint`。添加模板时的下拉菜单仍会显示 `hint`,展开条目后各配置项自己的 `hint` 也不受影响。 + image ## 在插件中使用配置 From b47c5084952da422e6c3d0c6bcfb6cef2f1b1c15 Mon Sep 17 00:00:00 2001 From: railgun19457 Date: Mon, 18 May 2026 22:16:32 +0800 Subject: [PATCH 5/5] fix: support file fields in template list configs --- astrbot/dashboard/routes/config.py | 2 +- astrbot/dashboard/routes/util.py | 21 ++++++- tests/unit/test_dashboard_util.py | 88 ++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test_dashboard_util.py diff --git a/astrbot/dashboard/routes/config.py b/astrbot/dashboard/routes/config.py index 9ec24d254d..3c37a2b788 100644 --- a/astrbot/dashboard/routes/config.py +++ b/astrbot/dashboard/routes/config.py @@ -95,7 +95,7 @@ def _validate_template_list(value, meta, path_key, errors, validate_fn) -> None: validate_fn( item, template_meta.get("items", {}), - path=f"{item_path}.", + path=f"{path_key}.templates.{template_key}.", ) diff --git a/astrbot/dashboard/routes/util.py b/astrbot/dashboard/routes/util.py index 1056198158..d08af03eed 100644 --- a/astrbot/dashboard/routes/util.py +++ b/astrbot/dashboard/routes/util.py @@ -16,6 +16,7 @@ def get_schema_item(schema: dict | None, key_path: str) -> dict | None: 同时支持: - 扁平 schema(直接 key 命中) - 嵌套 object schema({type: "object", items: {...}}) + - template_list schema(.templates.