Skip to content

Conversation

@NayukiChiba
Copy link
Contributor

@NayukiChiba NayukiChiba commented Jan 10, 2026

修复 #4297

fixes: #4297

问题描述

在插件配置页面中,当用户清除列表类型配置项的内容并保存时,保存的数据为 [""](包含一个空字符串的数组)而非预期的 [](空数组)。

解决方案

ExtensionPage.vueupdateConfig 函数中添加数据清理逻辑,在保存配置前递归过滤掉数组中的空字符串。

修改文件

  • dashboard/src/views/ExtensionPage.vue - 添加 cleanEmptyListItems 函数并在保存前调用
  • dashboard/src/components/shared/ListConfigItem.vue - 增强输入处理逻辑

测试

  • 清空列表配置项后保存,验证配置文件中为 []
  • 添加多个项目后删除部分,验证只保留非空项

Summary by Sourcery

确保在保存之前清空或编辑后,列表类型的插件配置值不再保留空字符串项。

Bug 修复:

  • 通过在持久化插件配置前移除空字符串项,防止已清空的列表配置项被保存为 [""]
  • 规范化 ListConfigItem 的值,当输入被清空或批量编辑时,输出空数组,而不是包含空白字符串的数组。
Original summary in English

Summary by Sourcery

Ensure list-type plugin configuration values no longer persist empty-string entries when cleared or edited before saving.

Bug Fixes:

  • Prevent cleared list configuration items from being saved as [""] by stripping empty-string entries before persisting plugin configs.
  • Normalize ListConfigItem values to emit empty arrays instead of arrays containing blank strings when inputs are cleared or batch-edited.

@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. area:webui The bug / feature is about webui(dashboard) of astrbot. labels Jan 10, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些总体反馈:

  • ListConfigItem.vue 中,confirmDialog 在没有进行类型检查的情况下调用了 item.trim(),如果列表中将来出现非字符串项,就会抛出异常;建议与 watcher 中的逻辑保持一致,在调用 trim 前先用 typeof item === 'string' 做类型判断。
  • 现在清空列表的逻辑既存在于 ListConfigItem.vue 中,也存在于通用的 cleanEmptyListItems 帮助函数中;建议将这部分行为进行统一,以避免在 UI 组件和全局配置清理之间,对空值处理方式出现细微差异。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
-`ListConfigItem.vue` 中,`confirmDialog` 在没有进行类型检查的情况下调用了 `item.trim()`,如果列表中将来出现非字符串项,就会抛出异常;建议与 watcher 中的逻辑保持一致,在调用 `trim` 前先用 `typeof item === 'string'` 做类型判断。
- 现在清空列表的逻辑既存在于 `ListConfigItem.vue` 中,也存在于通用的 `cleanEmptyListItems` 帮助函数中;建议将这部分行为进行统一,以避免在 UI 组件和全局配置清理之间,对空值处理方式出现细微差异。

## Individual Comments

### Comment 1
<location> `dashboard/src/components/shared/ListConfigItem.vue:207-209` </location>
<code_context>
 const singleItemValue = computed({
   get: () => props.modelValue?.[0] ?? '',
   set: (value) => {
-    const newItems = [...(props.modelValue || [])]
+    // 如果值为空或只有空白字符,emit 空数组
+    if (value.trim() === '') {
+      emit('update:modelValue', [])
+      return
</code_context>

<issue_to_address>
**issue (bug_risk):** 在 setter 中调用 `trim` 之前需要对非字符串值进行保护。

当前的 setter 假设 `value` 始终为字符串,并直接调用 `value.trim()`。如果传入非字符串值(例如来自非文本输入或不同的绑定),就会抛出异常。请在使用 `trim` 前先收窄类型(`typeof value === 'string' && value.trim() === ''`),或者先进行强制转换(`String(value).trim()`)。
</issue_to_address>

### Comment 2
<location> `dashboard/src/components/shared/ListConfigItem.vue:295` </location>
<code_context>
 function confirmDialog() {
-  emit('update:modelValue', [...localItems.value])
+  // 过滤空字符串
+  const filteredItems = localItems.value.filter(item => item.trim() !== '')
+  emit('update:modelValue', filteredItems)
   dialog.value = false
</code_context>

<issue_to_address>
**issue (bug_risk):** 对对话框列表项进行过滤时,应当能够稳健地处理非字符串条目。

`item.trim()` 假设 `localItems` 中的每一项都是字符串,如果列表中将来通过程序等方式加入了非字符串项,就会抛出异常。为了与 watcher 中的逻辑保持一致,建议增加类型保护:`filter(item => typeof item === 'string' ? item.trim() !== '' : true)`。
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的代码评审有帮助,请考虑分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈来改进后续的评审。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In ListConfigItem.vue, confirmDialog calls item.trim() without a type check, which will throw if non-string items are ever used in this list; consider aligning this with the watcher logic that guards with typeof item === 'string' before trimming.
  • There is now list-emptying logic both in ListConfigItem.vue and in the generic cleanEmptyListItems helper; consider centralizing this behavior to avoid subtle differences in how empty values are treated between the UI component and the global config cleaning.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ListConfigItem.vue`, `confirmDialog` calls `item.trim()` without a type check, which will throw if non-string items are ever used in this list; consider aligning this with the watcher logic that guards with `typeof item === 'string'` before trimming.
- There is now list-emptying logic both in `ListConfigItem.vue` and in the generic `cleanEmptyListItems` helper; consider centralizing this behavior to avoid subtle differences in how empty values are treated between the UI component and the global config cleaning.

## Individual Comments

### Comment 1
<location> `dashboard/src/components/shared/ListConfigItem.vue:207-209` </location>
<code_context>
 const singleItemValue = computed({
   get: () => props.modelValue?.[0] ?? '',
   set: (value) => {
-    const newItems = [...(props.modelValue || [])]
+    // 如果值为空或只有空白字符,emit 空数组
+    if (value.trim() === '') {
+      emit('update:modelValue', [])
+      return
</code_context>

<issue_to_address>
**issue (bug_risk):** Guard against non-string values before calling `trim` in the setter.

The setter currently assumes `value` is always a string and calls `value.trim()`, which will throw if a non-string is ever passed (e.g., from a non-text input or different binding). Please either narrow the type first (`typeof value === 'string' && value.trim() === ''`) or coerce it (`String(value).trim()`) before using `trim`.
</issue_to_address>

### Comment 2
<location> `dashboard/src/components/shared/ListConfigItem.vue:295` </location>
<code_context>
 function confirmDialog() {
-  emit('update:modelValue', [...localItems.value])
+  // 过滤空字符串
+  const filteredItems = localItems.value.filter(item => item.trim() !== '')
+  emit('update:modelValue', filteredItems)
   dialog.value = false
</code_context>

<issue_to_address>
**issue (bug_risk):** Filtering dialog items should be robust to non-string entries.

`item.trim()` assumes every `localItems` entry is a string and will throw if a non-string ever gets into the list (e.g., via future programmatic updates). To align with the watcher logic, consider guarding the type: `filter(item => typeof item === 'string' ? item.trim() !== '' : true)`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Soulter Soulter changed the title fix (#4297): 修复列表配置项删除后保存为[""]而非[]的问题 fix (#4297): fix list config being saved as [""] instead of [] after deletion Jan 11, 2026
过滤逻辑已在 ListConfigItem.vue 源头处理,保存配置时无需再次过滤。
@dosubot dosubot bot added size:S This PR changes 10-29 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jan 11, 2026
@Soulter Soulter merged commit 131950b into AstrBotDevs:master Jan 11, 2026
6 checks passed
@NayukiChiba NayukiChiba deleted the fix/issue-4297-empty-list-config branch January 11, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]插件配置list类型出现意料之外的空字符串

2 participants