Repository navigation
fix(OptionEditor): render nested options under multi-select (checkbox) options - #398
xzy1997123 wants to merge 1 commit into
Conversation
…) options `getSelectedCase()` returned `undefined` for checkbox options, so `nestedOptionKeys` was always empty and no child option was ever rendered below a multi-select parent. Only switch and select parents had a nested option block; checkbox groups such as `战斗检测目标舰种` (12 cases, each with its own sub-options) silently fell through, leaving the sub-options unreachable from the UI. - add `getSelectedCasesWithOptions()`: for checkbox returns every checked case that declares sub-options, in `cases` order; switch/select keep the previous single-case behaviour; input/hotkey return an empty list - use it in `OptionEditor`, and render the collected groups in the checkbox branch by reusing the existing collapse arrow and grid animation - group sub-options per case and only show the case label when more than one checked case contributes sub-options - add tests for the regression: 2 checked cases with 3 sub-options each must yield 6 entries (the old implementation yielded 0) Refs MaaXYZ#187
There was a problem hiding this comment.
你好——我发现了 4 个问题
面向 AI 代理的提示
请处理此次代码审查中的评论:
## 单条评论
### 评论 1
<location path="src/components/OptionEditor.tsx" line_range="744" />
<code_context>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**嵌套编辑不会影响输出**
当选中的复选框分支包含嵌套选项,且这些选项的值应影响任务流水线或前置任务时,`collectOptionOverrides` 和 `generateTaskPipelineOverride` 只添加所选分支自身的覆盖值,而 `collectPretaskOptionValues` 会在复选框处返回;子选项的值因此未包含在任务和前置任务的输出中。
请让流水线覆盖值和前置任务收集器递归遍历所选分支的选项键。
另请查看 `src/components/OptionEditor.tsx:743`。
</issue_to_address>
### 评论 2
<location path="src/components/OptionEditor.tsx" line_range="744" />
<code_context>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**无效的嵌套选择未通过校验**
当选中的复选框分支包含一个嵌套复选框,而其选择违反了配置的数量限制时,`validateOptionKeys` 在检查外层复选框后就会返回,不会遍历所选分支的选项键。因此,`validateInstanceCheckboxCounts` 会漏掉嵌套选项的数量限制违规,程序启动时仍会采用无效选择。
请让复选框校验递归遍历所选分支的选项键。
</issue_to_address>
### 评论 3
<location path="src/components/OptionEditor.tsx" line_range="744" />
<code_context>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**循环引用的选项会导致渲染崩溃**
当选中复选框分支中的某个嵌套选项引用了祖先路径上已有的选项时,`OptionEditor` 会递归渲染被引用的子项,却不跟踪已访问的选项键。如果某个选中的复选框分支直接或通过另一个复选框引用自身,就会导致组件不断递归渲染,直到界面发生堆栈溢出,而不是安全地显示该选项。
请在递归渲染期间跟踪祖先选项键,并在渲染重复选项之前停止递归或报告循环引用。
</issue_to_address>
### 评论 4
<location path="src/components/OptionEditor.tsx" line_range="743-744" />
<code_context>
+ </span>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**共享设置会重复显示**
当两个同时选中的复选框分支引用同一个嵌套选项键时,`nestedGroups.map` 会为每个引用都渲染一个编辑器,而每个编辑器都会读取和写入同一个 `allOptionValues[nestedKey]`;用户会看到同一设置的多个控件,修改其中任意一个都会同时影响其他控件。
请为每个唯一的嵌套选项键只渲染一个编辑器。
</issue_to_address>Original comment in English
Hey - I've found 4 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/components/OptionEditor.tsx" line_range="744" />
<code_context>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**Nested edits never reach outputs**
When a selected checkbox case has nested options whose values should affect a task pipeline or pretask, `collectOptionOverrides` and `generateTaskPipelineOverride` add only the selected case’s own override, while `collectPretaskOptionValues` returns at the checkbox; child values are omitted from task and pretask output.
Make the pipeline override and pretask collectors recurse into the selected cases’ option keys.
Also at `src/components/OptionEditor.tsx:743`.
</issue_to_address>
### Comment 2
<location path="src/components/OptionEditor.tsx" line_range="744" />
<code_context>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**Invalid nested selections pass validation**
When a selected checkbox case contains a nested checkbox whose selection violates its configured count limits, `validateOptionKeys` returns after checking the outer checkbox without visiting its selected cases’ option keys, so `validateInstanceCheckboxCounts` misses the nested count violation and startup proceeds with an invalid selection.
Make checkbox validation recurse into the option keys of selected cases.
</issue_to_address>
### Comment 3
<location path="src/components/OptionEditor.tsx" line_range="744" />
<code_context>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**Cyclic options crash rendering**
When a selected checkbox case’s nested option references an option already on its ancestor path, `OptionEditor` recursively renders the referenced child without tracking visited option keys. A selected checkbox case that refers back to itself (directly or through another checkbox) causes recursive component rendering until the UI hits a stack overflow instead of displaying the option safely.
Track ancestor option keys during recursive rendering and stop or report a cycle before rendering the repeated option.
</issue_to_address>
### Comment 4
<location path="src/components/OptionEditor.tsx" line_range="743-744" />
<code_context>
+ </span>
+ </div>
+ )}
+ {group.optionKeys.map((nestedKey) => (
+ <OptionEditor
+ key={`${group.caseName}:${nestedKey}`}
+ instanceId={instanceId}
</code_context>
<issue_to_address>
**Shared settings appear twice**
When two simultaneously selected checkbox cases reference the same nested option key, `nestedGroups.map` renders an editor for each reference, and each editor reads and writes the same `allOptionValues[nestedKey]`; callers see duplicate controls for one setting, and changing either changes both.
Render only one editor for each unique nested option key.
</issue_to_address>| </div> | ||
| )} | ||
| {group.optionKeys.map((nestedKey) => ( | ||
| <OptionEditor |
There was a problem hiding this comment.
🟠 高 · 嵌套编辑不会影响输出
当选中的复选框分支包含嵌套选项,且这些选项的值应影响任务流水线或前置任务时,collectOptionOverrides 和 generateTaskPipelineOverride 只添加所选分支自身的覆盖值,而 collectPretaskOptionValues 会在复选框处返回;子选项的值因此未包含在任务和前置任务的输出中。
请让流水线覆盖值和前置任务收集器递归遍历所选分支的选项键。
另请查看 src/components/OptionEditor.tsx:743。
面向 AI 代理的提示
在 `src/components/OptionEditor.tsx` 第 744 行:
**嵌套编辑不会影响输出**
当选中的复选框分支包含嵌套选项,且这些选项的值应影响任务流水线或前置任务时,`collectOptionOverrides` 和 `generateTaskPipelineOverride` 只添加所选分支自身的覆盖值,而 `collectPretaskOptionValues` 会在复选框处返回;子选项的值因此未包含在任务和前置任务的输出中。
请让流水线覆盖值和前置任务收集器递归遍历所选分支的选项键。
另请查看 `src/components/OptionEditor.tsx:743`。Original comment in English
🟠 High · Nested edits never reach outputs
When a selected checkbox case has nested options whose values should affect a task pipeline or pretask, collectOptionOverrides and generateTaskPipelineOverride add only the selected case’s own override, while collectPretaskOptionValues returns at the checkbox; child values are omitted from task and pretask output.
Make the pipeline override and pretask collectors recurse into the selected cases’ option keys.
Also at src/components/OptionEditor.tsx:743.
Prompt for AI agents
In `src/components/OptionEditor.tsx` at line 744:
**Nested edits never reach outputs**
When a selected checkbox case has nested options whose values should affect a task pipeline or pretask, `collectOptionOverrides` and `generateTaskPipelineOverride` add only the selected case’s own override, while `collectPretaskOptionValues` returns at the checkbox; child values are omitted from task and pretask output.
Make the pipeline override and pretask collectors recurse into the selected cases’ option keys.
Also at `src/components/OptionEditor.tsx:743`.| </div> | ||
| )} | ||
| {group.optionKeys.map((nestedKey) => ( | ||
| <OptionEditor |
There was a problem hiding this comment.
🟡 中 · 无效的嵌套选择未通过校验
当选中的复选框分支包含一个嵌套复选框,而其选择违反了配置的数量限制时,validateOptionKeys 在检查外层复选框后就会返回,不会遍历所选分支的选项键。因此,validateInstanceCheckboxCounts 会漏掉嵌套选项的数量限制违规,程序启动时仍会采用无效选择。
请让复选框校验递归遍历所选分支的选项键。
面向 AI 代理的提示
在 `src/components/OptionEditor.tsx` 第 744 行:
**无效的嵌套选择未通过校验**
当选中的复选框分支包含一个嵌套复选框,而其选择违反了配置的数量限制时,`validateOptionKeys` 在检查外层复选框后就会返回,不会遍历所选分支的选项键。因此,`validateInstanceCheckboxCounts` 会漏掉嵌套选项的数量限制违规,程序启动时仍会采用无效选择。
请让复选框校验递归遍历所选分支的选项键。Original comment in English
🟡 Medium · Invalid nested selections pass validation
When a selected checkbox case contains a nested checkbox whose selection violates its configured count limits, validateOptionKeys returns after checking the outer checkbox without visiting its selected cases’ option keys, so validateInstanceCheckboxCounts misses the nested count violation and startup proceeds with an invalid selection.
Make checkbox validation recurse into the option keys of selected cases.
Prompt for AI agents
In `src/components/OptionEditor.tsx` at line 744:
**Invalid nested selections pass validation**
When a selected checkbox case contains a nested checkbox whose selection violates its configured count limits, `validateOptionKeys` returns after checking the outer checkbox without visiting its selected cases’ option keys, so `validateInstanceCheckboxCounts` misses the nested count violation and startup proceeds with an invalid selection.
Make checkbox validation recurse into the option keys of selected cases.| </div> | ||
| )} | ||
| {group.optionKeys.map((nestedKey) => ( | ||
| <OptionEditor |
There was a problem hiding this comment.
🟡 中 · 循环引用的选项会导致渲染崩溃
当选中复选框分支中的某个嵌套选项引用了祖先路径上已有的选项时,OptionEditor 会递归渲染被引用的子项,却不跟踪已访问的选项键。如果某个选中的复选框分支直接或通过另一个复选框引用自身,就会导致组件不断递归渲染,直到界面发生堆栈溢出,而不是安全地显示该选项。
请在递归渲染期间跟踪祖先选项键,并在渲染重复选项之前停止递归或报告循环引用。
面向 AI 代理的提示
在 `src/components/OptionEditor.tsx` 第 744 行:
**循环引用的选项会导致渲染崩溃**
当选中复选框分支中的某个嵌套选项引用了祖先路径上已有的选项时,`OptionEditor` 会递归渲染被引用的子项,却不跟踪已访问的选项键。如果某个选中的复选框分支直接或通过另一个复选框引用自身,就会导致组件不断递归渲染,直到界面发生堆栈溢出,而不是安全地显示该选项。
请在递归渲染期间跟踪祖先选项键,并在渲染重复选项之前停止递归或报告循环引用。Original comment in English
🟡 Medium · Cyclic options crash rendering
When a selected checkbox case’s nested option references an option already on its ancestor path, OptionEditor recursively renders the referenced child without tracking visited option keys. A selected checkbox case that refers back to itself (directly or through another checkbox) causes recursive component rendering until the UI hits a stack overflow instead of displaying the option safely.
Track ancestor option keys during recursive rendering and stop or report a cycle before rendering the repeated option.
Prompt for AI agents
In `src/components/OptionEditor.tsx` at line 744:
**Cyclic options crash rendering**
When a selected checkbox case’s nested option references an option already on its ancestor path, `OptionEditor` recursively renders the referenced child without tracking visited option keys. A selected checkbox case that refers back to itself (directly or through another checkbox) causes recursive component rendering until the UI hits a stack overflow instead of displaying the option safely.
Track ancestor option keys during recursive rendering and stop or report a cycle before rendering the repeated option.| {group.optionKeys.map((nestedKey) => ( | ||
| <OptionEditor |
There was a problem hiding this comment.
🟡 中 · 共享设置会重复显示
当两个同时选中的复选框分支引用同一个嵌套选项键时,nestedGroups.map 会为每个引用都渲染一个编辑器,而每个编辑器都会读取和写入同一个 allOptionValues[nestedKey];用户会看到同一设置的多个控件,修改其中任意一个都会同时影响其他控件。
请为每个唯一的嵌套选项键只渲染一个编辑器。
面向 AI 代理的提示
在 `src/components/OptionEditor.tsx` 第 743–744 行:
**共享设置会重复显示**
当两个同时选中的复选框分支引用同一个嵌套选项键时,`nestedGroups.map` 会为每个引用都渲染一个编辑器,而每个编辑器都会读取和写入同一个 `allOptionValues[nestedKey]`;用户会看到同一设置的多个控件,修改其中任意一个都会同时影响其他控件。
请为每个唯一的嵌套选项键只渲染一个编辑器。Original comment in English
🟡 Medium · Shared settings appear twice
When two simultaneously selected checkbox cases reference the same nested option key, nestedGroups.map renders an editor for each reference, and each editor reads and writes the same allOptionValues[nestedKey]; callers see duplicate controls for one setting, and changing either changes both.
Render only one editor for each unique nested option key.
Prompt for AI agents
In `src/components/OptionEditor.tsx` at lines 743-744:
**Shared settings appear twice**
When two simultaneously selected checkbox cases reference the same nested option key, `nestedGroups.map` renders an editor for each reference, and each editor reads and writes the same `allOptionValues[nestedKey]`; callers see duplicate controls for one setting, and changing either changes both.
Render only one editor for each unique nested option key.
问题
PI V2 协议允许
option.cases[].option无限嵌套,但 MXU 目前只在switch(开关)和select(下拉框)父项下渲染子选项,checkbox(多选按钮组)父项的子选项完全不渲染。以 MRA 的「自动出征」为例:
战斗检测目标舰种是 12 个 case 的 checkbox(节点1舰种1 … 节点6舰种2),每个 case 都挂了 3 个子项:{ "name": "节点2舰种1", "option": ["节点2检测目标名", "节点2反向检测目标", "节点2检测目标后操作"] }界面上勾选「节点2舰种1」后,这三项没有任何输入位置。用户想把「节点2检测目标名」改成"补给"、把「节点2反向检测目标」改成"没检测到目标",完全无从下手。
更麻烦的是它不报错:子项会随父项 case 被激活并按自己的 default 生效,所以表现是"配了但永远匹配不上",而不是"配不了"。统计 MRA 一个项目就有 9 个任务、133 个子项属于这种「只在 checkbox case 里嵌套」的情形。
根因
src/components/OptionEditor.tsx的getSelectedCase()(原 L479-493):于是
nestedOptionKeys恒为空。同时 checkbox 的渲染分支(原 L606-715)里也没有任何子项渲染代码,而 switch(L559-600)、select(L808+)都有。改动
src/utils/optionHelpers.ts— 新增getSelectedCasesWithOptions(optionDef, value),统一三类父项的选中语义:checkbox 返回「所有被勾选且声明了 option 的 case」,按cases顺序;switch / select 仍最多返回 1 个;input / hotkey 返回空数组。原findSwitchCase的调用点收进这个函数。src/components/OptionEditor.tsx— 调用点改用新函数;checkbox 分支补上折叠箭头与子项渲染块,复用 switch / select 已有的OptionCollapseArrow与grid-template-rows展开动画;多选时常量多组子项按 case 分组,组数 > 1 才显示来源标签,避免来源混淆。tests/optionHelpers.test.ts(新增)— 13 条用例,含回归断言:「2 个被勾选 case × 各 3 子项 = 6 条」,旧实现返回 0。未新增任何面向用户的字符串,label 走既有的
isMxuOption ? t(...) : resolveI18nText(...)分支,符合 AGENTS.md 3.2 的 i18n 要求。验证
tsc --noEmit→ 0 errorvite build→ 通过node tests/run.mjs→ 21 passed / 0 failedprettier --check→ 通过出征.json(12 case × 各 3 子项)跑:勾 1 个 → 3 条,勾 2 个 → 6 条;旧实现两种都是 0兼容性
task.option顶层(绕过手法),会出现重复渲染,需要一并撤掉。说明
本 PR 由 WorkBuddy 智能体(模型 ds 4.1f)代 @xzy1997123 提交 —— 他是在配置 MRA 出征选项时撞上这个问题的玩家,复现步骤和实际效果都由他提供。代码请照常严格 review,有问题我会继续改。
Fixes #187
Sourcery 总结
渲染并解析已选复选框项的嵌套选项,使所有已启用的子设置都可配置。
新功能:
错误修复:
改进:
测试:
Original summary in English
Summary by Sourcery
Render and resolve nested options for selected checkbox cases so all active child settings are configurable.
New Features:
Bug Fixes:
Enhancements:
Tests: