Skip to content

fix: web配置组件,手风琴子项内部分配置组件无法正常渲染嵌套字段#664

Merged
ikenxuan merged 1 commit into
mainfrom
fix-hyw
Jul 7, 2026
Merged

fix: web配置组件,手风琴子项内部分配置组件无法正常渲染嵌套字段#664
ikenxuan merged 1 commit into
mainfrom
fix-hyw

Conversation

@ikenxuan

@ikenxuan ikenxuan commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary by Sourcery

将 Web 开关配置组件与 react-hook-form 的 control 集成,以支持嵌套字段路径,并在复杂布局中实现正确的点击处理。

Bug 修复:

  • 通过使用带有基础路径感知字段名的 react-hook-form Controller,修复嵌套或手风琴式配置项中的开关字段无法正确渲染或绑定的问题。
  • 通过将容器点击处理限制在专用控制区域内,防止在直接点击开关时出现重复切换行为。

增强:

  • 更新开关组件的集成方式,从使用 register 改为使用表单 control,以便在处理嵌套值时实现更灵活的表单状态管理。

构建:

  • 更新核心包元数据的时间戳。
Original summary in English

Summary by Sourcery

Integrate the web switch configuration component with react-hook-form control to support nested field paths and correct click handling in complex layouts.

Bug Fixes:

  • Fix switch fields inside nested or accordion configuration items not rendering or binding correctly by using react-hook-form Controller with base path-aware field names.
  • Prevent duplicate toggle behavior when clicking directly on the switch by scoping container click handling to a dedicated control area.

Enhancements:

  • Update switch component integration to use form control instead of register for more flexible form state management with nested values.

Build:

  • Update core package metadata timestamp.

Summary by CodeRabbit

  • Bug Fixes
    • Improved switch controls so they stay correctly in sync with form state, including within nested configuration sections.
    • Fixed switch interactions to respond more reliably when toggled.

@sourcery-ai

sourcery-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

审查者指南

重构了 Web 开关配置组件,使其使用 react-hook-form 的 Controller 并支持嵌套字段命名,从而避免重复的切换事件,并且可以在手风琴项中正确渲染嵌套的开关字段;同时将新的 API 接入配置插件渲染器,并更新 core 包的元数据。

使用 Controller 集成后,开关点击处理的时序图

sequenceDiagram
  actor User
  participant SwitchContainer
  participant HeroSwitch
  participant Controller

  User->>SwitchContainer: click
  SwitchContainer->>SwitchContainer: handleContainerClick(event)
  alt [isDisabled]
    SwitchContainer-->>User: return
  else [click in description-area]
    SwitchContainer-->>User: return
  else [click in switch-control-area]
    SwitchContainer-->>User: return
  else [normal container click]
    SwitchContainer->>SwitchContainer: querySelector([data-switch-key=name])
    SwitchContainer->>HeroSwitch: click()
  end

  rect rgb(230,230,250)
    Controller-->>HeroSwitch: render(field value, onChange, onBlur, name, ref)
    HeroSwitch-->>Controller: onValueChange(onChange)
  end
Loading

支持嵌套字段渲染开关的流程图

flowchart LR
  RenderComponent[RenderComponent]
  createSwitch[createSwitch]
  Controller[Controller]
  HeroSwitch[HeroSwitch]

  RenderComponent -->|option.componentType === switch\ncontrol, basePath| createSwitch
  createSwitch -->|compute name = basePath.key.value| createSwitch
  createSwitch -->|name, control, defaultValue| Controller
  Controller -->|render field props| HeroSwitch
  HeroSwitch -->|data-switch-key = name\nsubmit value via onValueChange| Controller
Loading

文件级变更

变更 详情 文件
开关配置组件现在使用支持嵌套字段的 react-hook-form Controller,而不再使用 register,从而避免重复的切换事件。
  • createSwitch 中用 FormControl 和可选的 basePath 参数替换基于 FormRegister 的 API,以支持嵌套表单字段路径。
  • 为开关推导出包含 basePath.value 的完整字段名,并将该名称同时用于表单控制和 DOM data 属性。
  • 用 react-hook-form 的 Controller 包裹 HeroSwitch,将 isSelectedonValueChangeonBlurnameref 绑定到表单状态,并通过 Controller 设置 defaultValue,而不是使用 defaultSelected/register
  • 调整点击处理逻辑,使容器点击同时忽略描述区域和 switch-control-area 本身,并使用新的基于字段名的 data-switch-key 来进行编程式点击。
packages/web/src/components/heroui/switchs.tsx
渲染流水线已更新,以将 react-hook-form 的 controlbasePath 传入开关组件。
  • 更新 RenderComponent,使其使用 optioncontrolbasePath 调用 createSwitch,而不是传入 register 函数,从而与新的 createSwitch 函数签名保持一致。
packages/web/src/components/config/plugin/render.tsx
更新了 core 包的元数据时间戳。
  • packages/core/package.json 中的 "time" 字段提升为更新的 ISO 时间戳。
packages/core/package.json

可能关联的问题

  • #Bug: 手风琴Pro组件渲染数据出错:该 PR 将开关改为使用 basePathController,从而使 AccordionPro 的子项能正确渲染嵌套的默认值。

技巧与命令

与 Sourcery 互动

  • 触发新的审查: 在 pull request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub Issue: 在审查评论下回复,要求 Sourcery 从该评论创建一个 issue。你也可以在审查评论下回复 @sourcery-ai issue 来从该评论创建一个 issue。
  • 生成 pull request 标题: 在 pull request 标题中任意位置写上 @sourcery-ai 即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文中任意位置写上 @sourcery-ai summary,即可在指定位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary 来在任意时间(重新)生成摘要。
  • 生成审查者指南: 在 pull request 中评论 @sourcery-ai guide,即可在任意时间(重新)生成审查者指南。
  • 一次性解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,即可将所有 Sourcery 评论标记为已解决。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 撤销所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,即可撤销所有已有的 Sourcery 审查。特别适用于你想从头开始一次新的审查——别忘了再评论 @sourcery-ai review 来触发新的审查!

自定义你的体验

前往你的 控制面板 来:

  • 启用或禁用诸如 Sourcery 自动生成的 pull request 摘要、审查者指南等审查功能。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

Refactors the web switch configuration component to use react-hook-form's Controller with nested field naming support, preventing duplicate toggle events and enabling proper rendering of nested switch fields within accordion items, and wires the new API into the config plugin renderer while updating core package metadata.

Sequence diagram for switch click handling with Controller integration

sequenceDiagram
  actor User
  participant SwitchContainer
  participant HeroSwitch
  participant Controller

  User->>SwitchContainer: click
  SwitchContainer->>SwitchContainer: handleContainerClick(event)
  alt [isDisabled]
    SwitchContainer-->>User: return
  else [click in description-area]
    SwitchContainer-->>User: return
  else [click in switch-control-area]
    SwitchContainer-->>User: return
  else [normal container click]
    SwitchContainer->>SwitchContainer: querySelector([data-switch-key=name])
    SwitchContainer->>HeroSwitch: click()
  end

  rect rgb(230,230,250)
    Controller-->>HeroSwitch: render(field value, onChange, onBlur, name, ref)
    HeroSwitch-->>Controller: onValueChange(onChange)
  end
Loading

Flow diagram for rendering switch with nested field support

flowchart LR
  RenderComponent[RenderComponent]
  createSwitch[createSwitch]
  Controller[Controller]
  HeroSwitch[HeroSwitch]

  RenderComponent -->|option.componentType === switch\ncontrol, basePath| createSwitch
  createSwitch -->|compute name = basePath.key.value| createSwitch
  createSwitch -->|name, control, defaultValue| Controller
  Controller -->|render field props| HeroSwitch
  HeroSwitch -->|data-switch-key = name\nsubmit value via onValueChange| Controller
Loading

File-Level Changes

Change Details Files
Switch config component now uses react-hook-form Controller with nested field support instead of register, avoiding duplicate toggle events.
  • Replace FormRegister-based API with FormControl and an optional basePath argument in createSwitch to support nested form field paths.
  • Derive a full field name including basePath and '.value' for the switch, and use this name for both form control and DOM data attributes.
  • Wrap HeroSwitch in react-hook-form Controller, binding isSelected, onValueChange, onBlur, name, and ref to form state, and set defaultValue via Controller instead of defaultSelected/register.
  • Adjust click handling so container clicks ignore both the description area and the switch-control-area itself, and use the new field name-based data-switch-key for programmatic clicks.
packages/web/src/components/heroui/switchs.tsx
Render pipeline updated to pass react-hook-form control and basePath into switch components.
  • Update RenderComponent to call createSwitch with option, control, and basePath instead of the register function, aligning with the new createSwitch signature.
packages/web/src/components/config/plugin/render.tsx
Core package metadata timestamp updated.
  • Bump the "time" field in packages/core/package.json to a newer ISO timestamp.
packages/core/package.json

Possibly linked issues

  • #Bug: 手风琴Pro组件渲染数据出错: PR changes switch to use basePath and Controller so AccordionPro children correctly render nested default values.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Refactors the createSwitch component to use react-hook-form's Controller API in place of register, updating its function signature to accept control and an optional basePath, and adjusts the caller in RenderComponent accordingly. Also updates a package timestamp field.

Changes

Switch Component Controller Migration

Layer / File(s) Summary
createSwitch signature and Controller import
packages/web/src/components/heroui/switchs.tsx
Imports Controller from react-hook-form and changes createSwitch's signature from register: FormRegister to control: FormControl, basePath?: string, updating JSDoc.
Field name computation and click handling
packages/web/src/components/heroui/switchs.tsx
Computes the form field name from basePath/key and updates handleContainerClick's element query to use this computed name via data-switch-key.
Controller-driven rendering
packages/web/src/components/heroui/switchs.tsx
Replaces register-based defaultSelected/spread props with a Controller that maps field values (isSelected, onValueChange, onBlur, ref) onto HeroSwitch.
Caller update
packages/web/src/components/config/plugin/render.tsx
Updates the switch branch to call createSwitch(option, control, basePath) instead of the previous register-based call.

Unrelated Package Metadata

Layer / File(s) Summary
Timestamp bump
packages/core/package.json
Updates the top-level time field to a newer timestamp.

Estimated code review effort: 2 (Simple) | ~10 minutes

Related PRs: None identified from the provided information.

Suggested labels: refactor, frontend

Suggested reviewers: None identified from the provided information.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main fix: nested fields inside web accordion child config components not rendering correctly.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-hyw

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - 我给出了几点整体性的反馈:

  • 使用 basePath 构造 name 会改变在 querySelector 中使用的 data-switch-key,因此更安全的做法是确保添加到 name 的任何字符(比如点号)不会影响属性选择或后续的 DOM 查询,可以通过对该 key 进行规范化或转义来避免问题。
  • Controller 中的 defaultValue={(defaultSelected ?? false) as never} 类型转换看起来更像是为了满足类型约束而不是基于实际值;可以考虑收紧 FormControl/字段的类型,使得 defaultValue 可以在不使用 as never 的情况下传入,这样可以让运行时行为预期更加清晰。
  • 既然这个开关已经完全通过 react-hook-form 进行受控管理,那么在 HeroSwitch 上显式设置 key={key} 可能已经不再必要,可以移除以避免在 key 变化时出现非预期的重新挂载。
供 AI Agent 使用的提示
请根据这次代码评审中的评论进行修改:

## 整体性评论
- 使用 `basePath` 构造 `name` 会改变在 `querySelector` 中使用的 `data-switch-key`,因此更安全的做法是确保添加到 `name` 的任何字符(比如点号)不会影响属性选择或后续的 DOM 查询,可以通过对该 key 进行规范化或转义来避免问题。
-`Controller` 中的 `defaultValue={(defaultSelected ?? false) as never}` 类型转换看起来更像是为了满足类型约束而不是基于实际值;可以考虑收紧 `FormControl`/字段的类型,使得 `defaultValue` 可以在不使用 `as never` 的情况下传入,这样可以让运行时行为预期更加清晰。
- 既然这个开关已经完全通过 `react-hook-form` 进行受控管理,那么在 `HeroSwitch` 上显式设置 `key={key}` 可能已经不再必要,可以移除以避免在 `key` 变化时出现非预期的重新挂载。

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

Hey - I've left some high level feedback:

  • The name construction with basePath changes the data-switch-key used in querySelector, so it would be safer to ensure any characters added to name (like dots) don’t interfere with attribute selection or future DOM queries by normalizing or escaping the key.
  • The defaultValue={(defaultSelected ?? false) as never} cast in the Controller looks type-driven rather than value-driven; consider tightening the FormControl/field types so defaultValue can be passed without as never, which will make runtime expectations clearer.
  • Now that the switch is fully controlled via react-hook-form, the explicit key={key} on HeroSwitch may no longer be necessary and could be removed to avoid unintended remounts when key changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `name` construction with `basePath` changes the `data-switch-key` used in `querySelector`, so it would be safer to ensure any characters added to `name` (like dots) don’t interfere with attribute selection or future DOM queries by normalizing or escaping the key.
- The `defaultValue={(defaultSelected ?? false) as never}` cast in the `Controller` looks type-driven rather than value-driven; consider tightening the `FormControl`/field types so `defaultValue` can be passed without `as never`, which will make runtime expectations clearer.
- Now that the switch is fully controlled via `react-hook-form`, the explicit `key={key}` on `HeroSwitch` may no longer be necessary and could be removed to avoid unintended remounts when `key` changes.

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.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

你可以通过以下命令安装该版本:

pnpm add https://pkg.pr.new/node-karin@a4630c2 -w

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the switch component rendering to use react-hook-form's Controller instead of direct registration, supporting dynamic nested paths via a new basePath parameter. It also resolves a duplicate toggle issue when clicking directly on the switch control. The feedback suggests simplifying the TypeScript type assertions within the Controller by casting the dynamic name to any, which avoids verbose type assertions like 'as never' and simplifies the selection state check.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/web/src/components/heroui/switchs.tsx
@ikenxuan ikenxuan merged commit 03ff932 into main Jul 7, 2026
4 of 5 checks passed
@ikenxuan ikenxuan deleted the fix-hyw branch July 7, 2026 03:32
@github-actions github-actions Bot mentioned this pull request Jul 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/web/src/components/heroui/switchs.tsx (1)

102-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reconsider the as never / as unknown casts.

(defaultSelected ?? false) as never and (value as unknown) === true fully bypass type checking rather than aligning with the actual field-value type from FormControl/DefaultValues. This can silently hide real type mismatches (e.g., if value were ever a string) that a properly-typed boolean comparison would catch at compile time.

♻️ Suggested direction
-            defaultValue={(defaultSelected ?? false) as never}
+            defaultValue={defaultSelected ?? false}
             render={({ field: { value, onChange, onBlur, name, ref } }) => (
               <HeroSwitch
                 ...
-                isSelected={(value as unknown) === true}
+                isSelected={Boolean(value)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/components/heroui/switchs.tsx` around lines 102 - 124, The
`Controller` render in `HeroSwitch` is using unsafe casts that bypass type
checking. Replace `(defaultSelected ?? false) as never` and `(value as unknown)
=== true` with properly typed boolean handling so the field value from
`FormControl`/`DefaultValues` stays aligned with the actual switch state. Update
the `Controller`/`HeroSwitch` wiring to use the real boolean type for
`defaultValue` and `isSelected`, keeping the existing `onChange`, `onBlur`, and
`name` props unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web/src/components/heroui/switchs.tsx`:
- Around line 9-19: The JSDoc for createSwitch has a copied description for
props that still says “输入框属性” instead of switch-related props. Update the
comment above createSwitch so the `@param` props description accurately describes
SwitchProps and matches the component’s purpose, keeping the rest of the
docblock consistent with the function signature.

---

Nitpick comments:
In `@packages/web/src/components/heroui/switchs.tsx`:
- Around line 102-124: The `Controller` render in `HeroSwitch` is using unsafe
casts that bypass type checking. Replace `(defaultSelected ?? false) as never`
and `(value as unknown) === true` with properly typed boolean handling so the
field value from `FormControl`/`DefaultValues` stays aligned with the actual
switch state. Update the `Controller`/`HeroSwitch` wiring to use the real
boolean type for `defaultValue` and `isSelected`, keeping the existing
`onChange`, `onBlur`, and `name` props unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 08fa435b-1e72-477d-8b85-280530a9faed

📥 Commits

Reviewing files that changed from the base of the PR and between a707017 and a4630c2.

📒 Files selected for processing (3)
  • packages/core/package.json
  • packages/web/src/components/config/plugin/render.tsx
  • packages/web/src/components/heroui/switchs.tsx

Comment on lines 9 to +19
/**
* 渲染开关组件
* @param props - 输入框属性
* @param register - 表单注册器
* @param control - 表单控制器
* @param basePath - 基础路径
* @returns 渲染后的输入框组件
*/
export const createSwitch = (
props: SwitchProps,
register: FormRegister
control: FormControl,
basePath?: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale JSDoc: props still described as “输入框属性” (input-box props).

This is createSwitch, but the @param props description was copied from an input component's docstring. Should describe switch properties instead.

📝 Proposed fix
 /**
  * 渲染开关组件
- * `@param` props - 输入框属性
+ * `@param` props - 开关属性
  * `@param` control - 表单控制器
  * `@param` basePath - 基础路径
  * `@returns` 渲染后的输入框组件
  */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* 渲染开关组件
* @param props - 输入框属性
* @param register - 表单注册器
* @param control - 表单控制器
* @param basePath - 基础路径
* @returns 渲染后的输入框组件
*/
export const createSwitch = (
props: SwitchProps,
register: FormRegister
control: FormControl,
basePath?: string
/**
* 渲染开关组件
* `@param` props - 开关属性
* `@param` control - 表单控制器
* `@param` basePath - 基础路径
* `@returns` 渲染后的输入框组件
*/
export const createSwitch = (
props: SwitchProps,
control: FormControl,
basePath?: string
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/components/heroui/switchs.tsx` around lines 9 - 19, The
JSDoc for createSwitch has a copied description for props that still says
“输入框属性” instead of switch-related props. Update the comment above createSwitch
so the `@param` props description accurately describes SwitchProps and matches the
component’s purpose, keeping the rest of the docblock consistent with the
function signature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant