Skip to content

feat: collapsible component and collapsible formitem - #7809

Closed
2yllll wants to merge 49 commits into
vbenjs:mainfrom
2yllll:feature-collapsible-component
Closed

feat: collapsible component and collapsible formitem#7809
2yllll wants to merge 49 commits into
vbenjs:mainfrom
2yllll:feature-collapsible-component

Conversation

@2yllll

@2yllll 2yllll commented Apr 13, 2026

Copy link
Copy Markdown
Contributor
  • shadcn-ui 增加 collapsible组件,collapsible-params组件
  • form新增支持单项折叠
  • collapsible-params组件在Form表单应用
  • New Features

    • Collapsible form fields and a dedicated collapsible-parameters UI with per-field controls, reset, and validation.
    • Per-form layout switching (vertical/horizontal) and preset parameter population from header controls.
    • New demo page and route to try the collapsible form and parameter editor.
  • Documentation

    • Added English and Chinese locale entries for the collapsible form example.

xingyu4j and others added 30 commits April 13, 2026 17:52
* perf: replace `onUnMounted` to `tryOnScopeDispose`

* perf: replace `onUnMounted` to `tryOnScopeDispose`
1. remove unknown rule out of oxlint
2. add the corresponding back to eslint-config
3. fixed the eslint error for package.json
- 关闭 vitest/require-mock-type-parameters 规则
- 添加 rootDir 编译选项指向 ./src 目录
- 保持现有编译配置不变
- 排除测试文件和 node_modules 目录
jinmao88 and others added 7 commits April 13, 2026 17:52
- 将index.html中的<%= VITE_APP_TITLE %>替换为%VITE_APP_TITLE%
- 更新web-antd、web-antdv-next、web-ele、web-naive、web-tdesign应用
- 修改文档中loading组件的VITE_APP_TITLE引用方式
- 修复vite-config插件中默认加载模板的变量语法
- 统一所有应用和模板中的环境变量引用格式
* feat: allow api-component labels to be derived from option data

ApiComponent already normalizes option records into the label/value shape used by
consuming controls, but label text could only come from a single field. Add
labelFn so callers can build labels from the full option record while keeping
labelField as the fallback path.

This keeps the change inside the existing component instead of introducing a
wrapper, and it also normalizes direct options through the same transform path
as API-loaded options for consistent behavior.

Constraint: Must extend the existing ApiComponent API instead of adding a second
Constraint: wrapper component
Rejected: Add a separate ApiLabelComponent wrapper |
Rejected: extra surface area for one option-mapping concern
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep labelFn as a presentation transform and preserve labelField
Directive: fallback for existing callers
Tested: pnpm exec eslint api-component.vue index.ts types.ts
Tested: pnpm exec vue-tsc --noEmit -p packages/effects/common-ui/tsconfig.json
Not-tested: runtime integration in consuming select/tree-select components

* Update packages/effects/common-ui/src/components/api-component/api-component.vue

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ng (vbenjs#7804)

* feat(@vben-core/form-ui): support schema valueFormat on getValues

Some form fields emit UI-friendly structures such as time-range arrays,
while consumers and backend APIs often need a different payload shape.
This adds schema-level `valueFormat` hooks so `getValues()` can
normalize field output at read time without forcing callers to
post-process every submission path.

Constraint: Must preserve existing range-time mapping and nested field behavior
Constraint: Must not mutate live vee-validate form state while formatting output
Rejected: Global formatter config | too coarse for per-field payload shaping
Rejected: Post-submit-only transform | misses reset/query/change handlers
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep `getValues()` output derivation side-effect free
Directive: Clone raw form values before formatting derived payloads
Tested: vitest form-api test for valueFormat and existing getValues paths
Tested: oxlint on changed form-ui source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* fix(@vben-core/form-ui): restore mount compatibility and share field path parsing

Follow-up review found two real regressions and one missing assertion in the
new value formatting flow. `FormApi.mount()` had become breaking by requiring
`componentRefMap`, and delete path resolution duplicated field-name parsing
instead of sharing the reader grammar. This patch restores backward
compatibility, centralizes field-name path parsing, and extends the test to
prove formatting does not mutate live form values.

Constraint: Must preserve current valueFormat behavior and nested field support
Constraint: Must not reintroduce mutation of live vee-validate values
Rejected: Keep duplicated delete parsing | risks grammar drift from read path
Rejected: Only loosen mount tests | would leave consumer-facing API breakage
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Reuse shared field-name parsing for read/delete semantics in form-ui
Tested: vitest form-api test suite
Tested: oxlint on changed form-ui files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors
EOF && git push hekx feature-form-value-format

* fix(@vben-core/form-ui): clear stale component refs on unmount

A follow-up review found that `unmount()` left the private component ref map
populated. Because `mount()` now accepts an optional `componentRefMap`, a later
mount without a new map could silently reuse stale refs from a prior form
instance. This change clears the ref map on unmount and adds a regression test
covering remount behavior without a new ref map.

Constraint: Must preserve backward-compatible optional `mount()` ref map behavior
Constraint: Focus and field-ref lookups must not observe stale refs after unmount
Rejected: Clear refs only during next mount | stale state would still leak between lifecycle calls
Rejected: Remove mount fallback entirely | would undo the compatibility fix
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When mount falls back to internal refs, unmount must always reset that cache
Tested: vitest form-api test suite
Tested: oxlint on changed form-api source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* refactor(@vben-core/form-ui): trim redundant valueFormat plumbing

Review feedback identified a few small cleanups in the value formatting path.
This removes an unnecessary shallow clone in `getValues()`, reuses the
already-parsed `rawKey` from `resolveFieldNamePath()` instead of re-resolving
it in multiple helpers, and clarifies the `FormValueFormat` contract for
undefined-as-delete decomposition behavior.

Constraint: Must not change runtime valueFormat behavior or payload shape
Constraint: Documentation and helper cleanup should stay behavior-preserving
Rejected: Leave duplicate raw-key resolution in place | adds needless parsing churn
Rejected: Expand the formatter API further | outside the scope of this cleanup
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep read/format helper plumbing lean and avoid duplicate field-name parsing
Tested: vitest form-api test suite
Tested: oxlint on changed form-ui source and test files
Not-tested: Full repo typecheck baseline has unrelated .vue module resolution errors

* feat(@vben-core/form-ui): document valueFormat with live examples

The new `valueFormat` feature needed a concrete usage path in both the
playground and the docs so users can understand how raw component values differ
from the final payload returned by `getValues()`. This adds a dedicated form
example, wires it into the playground menu, and documents the API with an
interactive docs demo. The preview panels now stay in sync when values are set,
reset, or submitted.

Constraint: Must demonstrate both return-value and setValue decomposition flows
Constraint: Example previews must react to setValues, reset, and manual edits
Rejected: Only document via markdown snippet | insufficient for verifying live payload behavior
Rejected: Reuse an existing basic form page | would bury feature-specific behavior
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep playground and docs demos behaviorally aligned when extending valueFormat examples
Tested: eslint on playground/docs valueFormat demo files and route module
Tested: oxlint on playground route module
Not-tested: Full docs/playground app runtime was not launched in this session

* chore(@vben-core/form-ui): normalize valueFormat demo formatting

The previous feature/docs commit left a few formatter-only adjustments unstaged
after hooks rewrote line wrapping in the new demo and docs pages. This commit
captures those final non-behavioral formatting updates so the branch matches the
current working tree.

Constraint: Must not change runtime behavior or docs meaning
Rejected: Leave post-hook diffs unstaged | branch would not reflect local state
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: After hook-driven rewrites, verify the working tree is clean before final push
Tested: Git diff inspection of remaining changes
Not-tested: No additional runtime verification needed; formatting-only follow-up
EOF && git push hekx feature-form-value-format

* fix(@vben-core/form-ui): remove docs demo dayjs dependency

The docs valueFormat demo imported `dayjs` directly even though the docs
package does not declare it as a dependency. That caused `@vben/docs:build`
to fail in CI during VitePress bundling. This change removes the direct
import, keeps the preview formatter generic for day-like values, and drops
the docs-only preset button that required constructing dayjs instances.

Constraint: Docs build must succeed without adding new package dependencies
Constraint: Playground example should remain unchanged and fully interactive
Rejected: Add dayjs to docs dependencies | unnecessary for a small display demo
Rejected: Externalize dayjs in VitePress build | hides a package boundary issue
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Docs demos should avoid imports only available through transitive deps
Tested: pnpm exec eslint docs/src/demos/vben-form/value-format/index.vue
Tested: pnpm --dir docs run build
Not-tested: No browser-side manual verification of the docs demo in this session

---------

Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
* feat: enable project-scoped preferences extension tabs

Add a typed extension schema so subprojects can define extra settings,
render them in the shared preferences drawer only when configured, and
consume them in playground as a real feature demo. Extension labels now
follow locale keys instead of hardcoded app-specific strings.

Constraint: Reuse the shared preferences drawer and field blocks
Rejected: Add app-specific fields to core preferences | too tightly coupled
Rejected: Inline localized label objects | breaks existing locale-key flow
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep extension labels as locale keys rendered via $t in UI
Tested: Vitest preferences tests
Tested: Turbo typecheck for preferences, layouts, web-antd, and playground
Tested: ESLint for touched preferences and playground files
Not-tested: Manual browser interaction in playground preferences drawer

* fix: satisfy lint formatting for preferences extension demo

Adjust the playground preferences extension demo template so formatter and
Vue template lint rules agree on the rendered markup. This keeps CI green
without changing runtime behavior.

Constraint: Must preserve the existing demo behavior while fixing CI only
Rejected: Disable the Vue newline rule | would weaken shared lint guarantees
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer computed/template structures that avoid formatter-vs-lint conflicts
Tested: pnpm run lint
Not-tested: Manual browser interaction in playground preferences extension demo

* fix: harden custom preferences validation and i18n labels

Tighten custom preferences handling so numeric extension fields respect
min, max, and step constraints. Number inputs now ignore NaN values,
and web-antd extension metadata uses locale keys instead of raw strings.
Also align tip-based hover guards in shared preference inputs/selects.

Constraint: Keep fixes scoped to verified findings only
Rejected: Broader refactor of preferences field components | not needed for these fixes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Reuse the same validation path for updates and cache hydration
Tested: Vitest preferences tests
Tested: ESLint for touched preferences and widget files
Tested: Typecheck for web-antd, layouts, and core preferences
Not-tested: Manual browser interaction for all preference field variants

* fix: remove localized default from playground extension config

Drop the hardcoded Chinese default value from the playground extension
report title field and fall back to an empty string instead. This keeps
extension config locale-neutral while preserving localized labels and
placeholders through translation keys.

Constraint: Keep the fix limited to the verified localized default issue
Rejected: Compute the default from runtime locale in config | unnecessary for this finding
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Avoid embedding localized literals in extension default values
Tested: ESLint for playground/src/preferences.ts
Tested: Oxfmt check for playground/src/preferences.ts
Not-tested: Manual playground preferences interaction

* docs: document project-scoped preferences extension workflow

Add Chinese and English guide sections explaining how to define,
initialize, read, and update project-scoped preferences extensions.
Also document numeric field validation and point readers to the
playground demo for a complete example.

Constraint: Keep this docs-only and aligned with the shipped API
Rejected: Update only Chinese docs | would leave English docs inconsistent
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep zh/en examples and playground demo paths synchronized
Tested: git diff --check; pnpm build:docs
Not-tested: Manual browser review of the rendered docs site

* fix: harden custom preferences defaults and baselines

Use a locale-neutral default for the web-antd report title.
Also stop preference getters from exposing mutable baseline
or extension schema objects, and add a regression test for
external mutation attempts.

Constraint: Keep behavior compatible with the shipped preferences API
Rejected: Return raw refs with readonly typing only | callers could still mutate internals
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep defensive copies for baseline and schema getters unless storage semantics change
Tested: eslint, oxlint, targeted vitest, filtered typecheck, git diff --check
Not-tested: Full monorepo typecheck and test suite

* test: relax custom preference cache key matching

Avoid coupling the custom-number cache test to one exact
localStorage key string. Match the intended cache lookup
more loosely so the test still verifies filtering behavior
without depending on the full namespaced cache key.

Constraint: Focus the test on cache filtering behavior
Rejected: Assert one exact key | brittle with namespace changes
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Prefer behavior tests over literal storage keys
Tested: targeted vitest, eslint, git diff --check
Not-tested: Full monorepo test suite

---------

Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启
- shadcn-ui 增加 collapsible组件,collapsible-params组件
- form新增支持单项折叠
- collapsible-params组件在Form表单应用
@2yllll
2yllll requested review from a team, anncwb, jinmao88, mynetfan and vince292007 as code owners April 13, 2026 11:23
@changeset-bot

changeset-bot Bot commented Apr 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 991408b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds per-field collapsible FormItem support: new shadcn-ui collapsible components and types, integrates collapsible props into form renderer/label/types, exports a chevrons icon, updates demo/example, route, locales, and adds @vben-core/shadcn-ui to web-naive dependencies.

Changes

Cohort / File(s) Summary
Collapsible components & types
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue, .../collapsible-params.vue, .../collapsible-params-item.vue, .../type.ts, .../index.ts
Added VbenCollapsible (v-model:open, toggle, slots), VbenCollapsibleParams (params list, v-model:value, reset/init), CollapsibleParamsItem (per-param model, reset, dynamic field selection), plus types and index exports.
Form integration
packages/@core/ui-kit/form-ui/src/types.ts, .../form-render/form-field.vue, .../form-render/form-label.vue, .../components/form-actions.vue
Extended FormCommonConfig with collapsible/defaultCollapsed; form-field: added collapsible/defaultCollapsed props, collapse state, ChevronsDown trigger, and wrapped control content in VbenCollapsible; form-label: added extra named slot; removed commented code in form-actions.
Icons & component exports
packages/@core/base/icons/src/lucide.ts, packages/@core/ui-kit/shadcn-ui/src/components/index.ts
Exported ChevronsDown icon and re-exported the collapsible module from shadcn-ui components index.
App dependency
apps/web-naive/package.json
Added @vben-core/shadcn-ui as a workspace dependency.
Demo, routing & locales
playground/src/views/examples/form/collapsible.vue, playground/src/router/.../examples.ts, playground/src/locales/langs/en-US/examples.json, playground/src/locales/langs/zh-CN/examples.json
Added example page demonstrating collapsible params, registered route /examples/form/collapsible-test, and added English/Chinese localization keys for the example.

Sequence Diagram(s)

sequenceDiagram
    participant User as "User"
    participant Page as "ExamplePage"
    participant Form as "VbenForm"
    participant Collapsible as "VbenCollapsible"
    participant Params as "VbenCollapsibleParams"
    participant Item as "ParamsItem"

    User->>Page: open page / select layout
    Page->>Form: mount form (schema, layout)
    Form->>Collapsible: render collapsible wrapper for field
    Collapsible->>Params: render visible + collapsible rows
    User->>Item: edit parameter input
    Item-->>Params: emit update (key, value)
    Params-->>Form: emit update:value (full params model)
    User->>Collapsible: click trigger
    Collapsible->>Collapsible: toggle open (v-model:open)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

feature

Suggested reviewers

  • anncwb
  • vince292007
  • mynetfan
  • jinmao88

Poem

🐰
I nibbled a fold and found a way,
Chevrons spin and fields can sway,
Tiny params tucked in rows so neat,
A hop, a click — the form’s complete,
Hooray, the UI feels light and spry!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description provides only high-level bullet points without detailed context. It lacks structured sections like motivation, detailed design rationale, and how changes integrate with the existing system. Expand the description to explain why collapsible components are needed, how they integrate with the form system, and provide more technical detail about the implementation approach and trade-offs considered.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: introduction of a collapsible component and collapsible form item feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@2yllll 2yllll changed the title Feature collapsible component and collapsible formitem feat: collapsible component and collapsible formitem Apr 13, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 8

🧹 Nitpick comments (3)
packages/@core/ui-kit/form-ui/src/form-render/form-field.vue (1)

312-314: Consider removing or documenting the commented-out condition.

The commented code /* && isVertical.value; */ suggests uncertainty about whether collapsible should be restricted to vertical layouts. Either remove the comment if the current behavior is intentional, or add a TODO explaining the reasoning.

♻️ Suggested cleanup

If collapsible should work in all layouts:

 const shouldCollapsible = computed(() => {
-  return collapsible; /* && isVertical.value; */
+  return collapsible;
 });

Or if there's a future consideration:

 const shouldCollapsible = computed(() => {
-  return collapsible; /* && isVertical.value; */
+  // Note: Collapsible works in all layouts; vertical-only restriction removed intentionally
+  return collapsible;
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/`@core/ui-kit/form-ui/src/form-render/form-field.vue around lines
312 - 314, The computed shouldCollapsible currently returns collapsible with a
commented-out condition for isVertical.value; decide whether collapsible should
apply only for vertical layouts and either remove the commented code or add a
short TODO comment explaining the design choice. Specifically, in the
shouldCollapsible computed (referencing shouldCollapsible, collapsible and
isVertical), either delete the "/* && isVertical.value; */" fragment if
collapsible is intended for all layouts, or replace it with a concise TODO
comment like "// TODO: restrict collapsible to vertical layouts if UX requires"
explaining why the vertical check was considered.
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue (1)

30-48: No validation when component is not registered.

If globalShareState.getComponents() doesn't have the expected components (InputNumber, Select, Input), the component will silently render nothing or error. Consider adding a warning similar to the pattern in form-field.vue.

♻️ Suggested improvement
 const FieldComponent = computed(() => {
+  let comp;
   switch (props.data.option.type) {
     case 'exponential':
     case 'number': {
-      return components.InputNumber;
+      comp = components.InputNumber;
+      break;
     }
     case 'select': {
-      return components.Select;
+      comp = components.Select;
+      break;
     }
     case 'string': {
-      return components.Input;
+      comp = components.Input;
+      break;
     }
-
     default: {
-      return components.InputNumber;
+      comp = components.InputNumber;
     }
   }
+  if (!comp) {
+    console.warn(`Component for type "${props.data.option.type}" is not registered`);
+  }
+  return comp;
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
around lines 30 - 48, The FieldComponent computed currently assumes
globalShareState.getComponents() contains InputNumber, Select and Input; add a
guard and warning when a mapped component is missing: inside the FieldComponent
computed (the switch on props.data.option.type), resolve components via const
components = globalShareState.getComponents(); check for the expected symbol
(components.InputNumber, components.Select, components.Input) before returning
it and if undefined call console.warn or use the project logger with a clear
message including props.data.option.type and return a safe fallback (e.g., a
built-in <div> placeholder component or a default components.InputNumber) to
match the pattern used in form-field.vue so the UI fails gracefully when a
component is not registered.
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (1)

157-229: Consider using scoped for component styles.

The styles are defined without scoped, which means they could leak to other components. While the .vben-collapsible-params class namespace provides some isolation, using scoped would be safer.

♻️ Suggested change
-<style lang="css">
+<style lang="css" scoped>
 .vben-collapsible-params {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 157 - 229, Add the scoped attribute to the component's style tag to
prevent style leakage: update the <style lang="css"> block in
collapsible-params.vue to include scoped (e.g., <style lang="css" scoped>) so
the rules for .vben-collapsible-params and its nested selectors (wrapper,
.header, .body, .header-cell, .body-cell, .trigger-bar, etc.) are scoped to this
component only.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web-naive/src/views/demos/form/basic.vue`:
- Around line 32-44: getNumberValidator currently calls zod's .min()/.max() but
discards their return values (they're immutable), so the range constraints are
never applied; fix by capturing and returning the chained schema (e.g., replace
the standalone validator.min(...)/validator.max(...) calls with validator =
validator.min(...).max(...) or chain the returns) inside getNumberValidator so
the final returned schema includes the limit constraints; reference function
getNumberValidator and the .min/.max methods.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue:
- Around line 15-28: finalOption computed currently only applies numeric
defaults when props.data.option.type === 'number', causing 'exponential' inputs
to miss step/precision/min/max; update the computed in finalOption to treat
'exponential' the same as 'number' (e.g., if (type === 'number' || type ===
'exponential') return the object with step: props.data.option.step ?? 1,
precision: props.data.option.precision ?? 0, and min/max copied from
props.data.option) so FieldComponent's mapping to InputNumber receives
consistent defaults.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 57-61: The init() function assigns into
modelValue.value[param.key] but doesn't ensure modelValue.value is an object;
before the loop in init() (which iterates props.params), guard/initialize
modelValue.value (the ref used for the v-model) to an object if it's undefined
or null (e.g. set modelValue.value = modelValue.value ?? {}), then proceed to
set each param.defaultValue into modelValue.value[param.key]; update references
to init() and modelValue.value accordingly so no TypeError occurs when parent
omits an initial value.
- Around line 176-177: The failing rule in the collapsible component stylesheet
uses the unknown utility class `bg-accent` (see the rule applying `@apply
bg-accent items-center rounded-t-[0.5rem] border-b;` in collapsible-params.vue);
either replace `bg-accent` with a recognized Tailwind class (e.g., a neutral bg
like `bg-gray-100` or your design system equivalent) or ensure `bg-accent` is
defined by adding it to the Tailwind theme colors in your Tailwind config (or
add the required `@reference` directive at the top of the component style block if
your setup expects it). Update the rule in collapsible-params.vue (the CSS rule
that uses `bg-accent`) accordingly so the build can resolve the utility.

In `@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue:
- Around line 14-19: The component uses the ClassType type in the props
definition but never imports it; add an import for ClassType (import type {
ClassType } from '@vben-core/typings') at the top of the file so the props
declaration using ClassType (inside defineProps<CollapsibleRootProps & { class?:
ClassType; showTrigger?: boolean; }>) resolves correctly and matches the import
pattern used by other components like tooltip/scrollbar/popover.

In `@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts:
- Around line 1-15: The interfaces CollapsibleParamOption and
CollapsibleParamSchema need to allow missing fields used in practice: mark the
type field on CollapsibleParamOption as optional and mark defaultValue on
CollapsibleParamSchema as optional so consumers can omit them; update the
declarations for CollapsibleParamOption.type and
CollapsibleParamSchema.defaultValue (referencing those exact symbol names) to be
optional types that match the existing unions.

In `@playground/src/views/examples/form/collapsible.vue`:
- Around line 20-32: In getNumberValidator: the calls to validator.min(...) and
validator.max(...) are being ignored because Zod methods return new schemas, and
returning validator.default(null) introduces a type mismatch by setting null as
the default for a number schema; fix by chaining the min/max results into the
validator variable (e.g., reassign validator = validator.min(...) / validator =
validator.max(...)) or build the chain directly, and change default(null) to a
number-compatible default or remove the .default call so the schema remains
number-typed; ensure you only call .default with a number (or make the schema
optional/nullable if null is intended).
- Line 98: The file uses the type CollapsibleParamSchema in a type assertion but
doesn't import it; add a type-only import for CollapsibleParamSchema from the
shadcn-ui package at the top of the script section so the assertion (the array
cast to CollapsibleParamSchema[]) resolves correctly.

---

Nitpick comments:
In `@packages/`@core/ui-kit/form-ui/src/form-render/form-field.vue:
- Around line 312-314: The computed shouldCollapsible currently returns
collapsible with a commented-out condition for isVertical.value; decide whether
collapsible should apply only for vertical layouts and either remove the
commented code or add a short TODO comment explaining the design choice.
Specifically, in the shouldCollapsible computed (referencing shouldCollapsible,
collapsible and isVertical), either delete the "/* && isVertical.value; */"
fragment if collapsible is intended for all layouts, or replace it with a
concise TODO comment like "// TODO: restrict collapsible to vertical layouts if
UX requires" explaining why the vertical check was considered.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue:
- Around line 30-48: The FieldComponent computed currently assumes
globalShareState.getComponents() contains InputNumber, Select and Input; add a
guard and warning when a mapped component is missing: inside the FieldComponent
computed (the switch on props.data.option.type), resolve components via const
components = globalShareState.getComponents(); check for the expected symbol
(components.InputNumber, components.Select, components.Input) before returning
it and if undefined call console.warn or use the project logger with a clear
message including props.data.option.type and return a safe fallback (e.g., a
built-in <div> placeholder component or a default components.InputNumber) to
match the pattern used in form-field.vue so the UI fails gracefully when a
component is not registered.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 157-229: Add the scoped attribute to the component's style tag to
prevent style leakage: update the <style lang="css"> block in
collapsible-params.vue to include scoped (e.g., <style lang="css" scoped>) so
the rules for .vben-collapsible-params and its nested selectors (wrapper,
.header, .body, .header-cell, .body-cell, .trigger-bar, etc.) are scoped to this
component only.
🪄 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: eab96ef9-6d3d-4165-ab03-6ec6e95d5aba

📥 Commits

Reviewing files that changed from the base of the PR and between ccabbf0 and b7774fc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • apps/web-naive/package.json
  • apps/web-naive/src/views/demos/form/basic.vue
  • packages/@core/base/icons/src/lucide.ts
  • packages/@core/ui-kit/form-ui/src/components/form-actions.vue
  • packages/@core/ui-kit/form-ui/src/form-render/form-field.vue
  • packages/@core/ui-kit/form-ui/src/form-render/form-label.vue
  • packages/@core/ui-kit/form-ui/src/types.ts
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts
  • packages/@core/ui-kit/shadcn-ui/src/components/index.ts
  • playground/src/locales/langs/en-US/examples.json
  • playground/src/locales/langs/zh-CN/examples.json
  • playground/src/router/routes/modules/examples.ts
  • playground/src/views/examples/form/collapsible.vue
💤 Files with no reviewable changes (1)
  • packages/@core/ui-kit/form-ui/src/components/form-actions.vue

Comment thread apps/web-naive/src/views/demos/form/basic.vue
Comment thread packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue Outdated
Comment on lines +176 to +177
@apply bg-accent items-center rounded-t-[0.5rem] border-b;
}

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.

⚠️ Potential issue | 🔴 Critical

Build failure: bg-accent utility class not recognized.

The pipeline failed with: "Cannot apply unknown utility class bg-accent". This Tailwind class may not be available in the current configuration or may require a CSS reference directive.

🛠️ Possible fixes

Option 1: Use a standard Tailwind class:

     .header {
-      `@apply` bg-accent items-center rounded-t-[0.5rem] border-b;
+      `@apply` bg-muted items-center rounded-t-[0.5rem] border-b;
     }

Option 2: If bg-accent is a custom theme color, ensure it's defined in the Tailwind config, or add @reference directive at the top of the style block per the error message.

📝 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
@apply bg-accent items-center rounded-t-[0.5rem] border-b;
}
`@apply` bg-muted items-center rounded-t-[0.5rem] border-b;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 176 - 177, The failing rule in the collapsible component stylesheet
uses the unknown utility class `bg-accent` (see the rule applying `@apply
bg-accent items-center rounded-t-[0.5rem] border-b;` in collapsible-params.vue);
either replace `bg-accent` with a recognized Tailwind class (e.g., a neutral bg
like `bg-gray-100` or your design system equivalent) or ensure `bg-accent` is
defined by adding it to the Tailwind theme colors in your Tailwind config (or
add the required `@reference` directive at the top of the component style block if
your setup expects it). Update the rule in collapsible-params.vue (the CSS rule
that uses `bg-accent`) accordingly so the build can resolve the utility.

Comment thread packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts
Comment on lines +20 to +32
function getNumberValidator(key: string, limit?: [number, number]) {
const validator = z.number({
required_error: `${key} 值不能为空`,
invalid_type_error: `${key} 值只能为数字`,
});

if (limit) {
validator.min(limit[0], { message: `${key} 值不在区间范围内` });
validator.max(limit[1], { message: `${key} 值不在区间范围内` });
}

return validator.default(null);
}

@coderabbitai coderabbitai Bot Apr 13, 2026

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.

⚠️ Potential issue | 🔴 Critical

Same Zod chaining bug and type mismatch with .default(null).

Two issues:

  1. Same bug as in basic.vue: .min() and .max() return new schemas that are discarded.
  2. .default(null) sets null as the default, but the validator expects a number. This creates a type contradiction.
🐛 Proposed fix
 function getNumberValidator(key: string, limit?: [number, number]) {
-  const validator = z.number({
+  let validator = z.number({
     required_error: `${key} 值不能为空`,
     invalid_type_error: `${key} 值只能为数字`,
   });
 
   if (limit) {
-    validator.min(limit[0], { message: `${key} 值不在区间范围内` });
-    validator.max(limit[1], { message: `${key} 值不在区间范围内` });
+    validator = validator
+      .min(limit[0], { message: `${key} 值不在区间范围内` })
+      .max(limit[1], { message: `${key} 值不在区间范围内` });
   }
 
-  return validator.default(null);
+  return validator.optional(); // or provide a valid numeric default
 }
📝 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
function getNumberValidator(key: string, limit?: [number, number]) {
const validator = z.number({
required_error: `${key} 值不能为空`,
invalid_type_error: `${key} 值只能为数字`,
});
if (limit) {
validator.min(limit[0], { message: `${key} 值不在区间范围内` });
validator.max(limit[1], { message: `${key} 值不在区间范围内` });
}
return validator.default(null);
}
function getNumberValidator(key: string, limit?: [number, number]) {
let validator = z.number({
required_error: `${key} 值不能为空`,
invalid_type_error: `${key} 值只能为数字`,
});
if (limit) {
validator = validator
.min(limit[0], { message: `${key} 值不在区间范围内` })
.max(limit[1], { message: `${key} 值不在区间范围内` });
}
return validator.optional(); // or provide a valid numeric default
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playground/src/views/examples/form/collapsible.vue` around lines 20 - 32, In
getNumberValidator: the calls to validator.min(...) and validator.max(...) are
being ignored because Zod methods return new schemas, and returning
validator.default(null) introduces a type mismatch by setting null as the
default for a number schema; fix by chaining the min/max results into the
validator variable (e.g., reassign validator = validator.min(...) / validator =
validator.max(...)) or build the chain directly, and change default(null) to a
number-compatible default or remove the .default call so the schema remains
number-typed; ensure you only call .default with a number (or make the schema
optional/nullable if null is intended).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

使用optional会在重置后被绕过校验,zod校验没有生效,.default(null) 可以避免重置问题

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.

@2yllll, that's a valid concern about reset behavior. However, there are two points worth clarifying:

1. The chaining bug is still unresolved (critical)

Your explanation addresses the .default(null) choice, but the primary bug — that .min() and .max() constraints are silently discarded — is completely separate and remains unfixed:

// These two lines do nothing — both .min() and .max() return NEW schemas
// that are thrown away. The min/max limits are never applied.
validator.min(limit[0], { message: `${key} 值不在区间范围内` });
validator.max(limit[1], { message: `${key} 值不在区间范围内` });

This means users can enter any number outside the intended range and it will pass validation.

2. .default(null) won't actually fix the reset issue

In Zod, if a field receives null, it does not treat it as "missing" — null goes through validation like any other value, and if the schema doesn't allow null, the result is a validation error, not a fallback to the default. .default() only triggers when the input is undefined.

So if the form resets fields to null (as many form libraries do), .default(null) on a z.number() won't bypass validation — it will throw a type error because null is not a number.

Suggested fix

Use .nullable() to explicitly allow null (for the reset state), chain .min()/.max() correctly, and add a .refine() if you need to require a non-null value on submission:

function getNumberValidator(key: string, limit?: [number, number]) {
  let validator = z.number({
    required_error: `${key} 值不能为空`,
    invalid_type_error: `${key} 值只能为数字`,
  });

  if (limit) {
    validator = validator
      .min(limit[0], { message: `${key} 值不在区间范围内` })
      .max(limit[1], { message: `${key} 值不在区间范围内` });
  }

  // .nullable() allows null (reset state), while still running number validation on actual input
  return validator.nullable();
}

If you specifically need null to pass through without triggering a validation error even when the field is required, a .transform() / .preprocess() approach would be more appropriate — but the min/max chaining must be fixed either way.

Comment thread playground/src/views/examples/form/collapsible.vue Outdated

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (1)

57-61: ⚠️ Potential issue | 🔴 Critical

Guard model initialization and stop clobbering incoming values.

Line 59 can throw when v-model:value is initially undefined, and current init() also overwrites existing caller-provided values on setup. Initialize modelValue to an object first, then only backfill missing keys.

🔧 Proposed fix
 function init() {
+  if (!modelValue.value || typeof modelValue.value !== 'object') {
+    modelValue.value = {};
+  }
   for (const param of props.params) {
-    modelValue.value[param.key] = param.defaultValue ?? null;
+    if (modelValue.value[param.key] === undefined) {
+      modelValue.value[param.key] = param.defaultValue ?? null;
+    }
   }
 }

Also applies to: 86-86

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 57 - 61, The init() routine is clobbering incoming v-model values
and can throw when modelValue.value is undefined; before iterating props.params
ensure modelValue.value is an object (e.g., set to {} if falsy) and only
backfill missing keys by setting modelValue.value[param.key] only when
modelValue.value[param.key] is undefined (use param.defaultValue ?? null as the
fill), and apply the same guard/backfill change to the other similar
initialization block referenced (the second backfill around line 86).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 57-61: The init() routine is clobbering incoming v-model values
and can throw when modelValue.value is undefined; before iterating props.params
ensure modelValue.value is an object (e.g., set to {} if falsy) and only
backfill missing keys by setting modelValue.value[param.key] only when
modelValue.value[param.key] is undefined (use param.defaultValue ?? null as the
fill), and apply the same guard/backfill change to the other similar
initialization block referenced (the second backfill around line 86).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0da209ff-4b66-4614-8a08-8badd0027d15

📥 Commits

Reviewing files that changed from the base of the PR and between b7774fc and e808fe7.

📒 Files selected for processing (2)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue

@doraemonxxx

Copy link
Copy Markdown
Contributor

Hi can you fix the issues suggested by AI? especially the ClassType, CollapsibleParamSchema and props value mismatched and others?

Admin - please don't merged this PR until changes applied. Thanks

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 57-64: The init() function currently overwrites all keys on
modelValue.value; change it to only set missing keys from props.params (i.e.,
for each param, if modelValue.value[param.key] is undefined/null then assign
param.defaultValue ?? null) and add an optional force boolean (init(force?:
boolean)) that, when true, performs the destructive reset behavior used by
resetValue(); update resetValue() to call init(true). Remove the one-time setup
call to init() and instead add a watcher on props.params (or the incoming value)
with immediate: true that non-destructively syncs missing keys by calling init()
without force so incoming form values are preserved while newly added params get
initialized.
- Around line 113-123: The component collapsible-params.vue currently uses
hardcoded Chinese labels ("参数名称", "配置", "说明" and the instance at line 179) which
bypasses the i18n layer; update the template to source these three header labels
from the app i18n utilities (e.g., use the existing useI18n/$t helper) or accept
them via props/slots (e.g., props.labels.name/config/desc or named slots) and
replace the hardcoded strings with the i18n/prop/slot values so language
switching works correctly; ensure the same change is applied to the repeated
occurrence referenced at line 179.
- Around line 110-124: The header divs containing the texts "参数名称", "配置", and
"说明" are missing the CSS class used to enforce column widths (the .header-cell
rule defined later), so the header stays content-sized and drifts from the
fixed-width body columns; fix this by adding the class name (header-cell) to
each of those three header <div> elements in collapsible-params.vue so they pick
up the column width rules and align with the body columns.
🪄 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: fb9eb36d-7043-416e-8ad8-c45761a5e8ce

📥 Commits

Reviewing files that changed from the base of the PR and between e808fe7 and 12a81a7.

📒 Files selected for processing (6)
  • apps/web-naive/src/views/demos/form/basic.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts
  • playground/src/views/examples/form/collapsible.vue
✅ Files skipped from review due to trivial changes (2)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts
  • playground/src/views/examples/form/collapsible.vue
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web-naive/src/views/demos/form/basic.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue

Comment thread packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue Outdated
Comment on lines +113 to +123
参数名称
</div>
<div
class="pt-2 pb-2 px-5 leading-[1.5rem] flex items-center flex-nowrap"
>
配置
</div>
<div
class="pt-2 pb-2 px-5 leading-[1.5rem] flex items-center flex-nowrap"
>
说明

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.

⚠️ Potential issue | 🟡 Minor

This shared component is still hardcoded to Chinese copy.

Lines 113-123 and Line 179 bypass the locale layer, so language switching won't affect the new collapsible UI even though the PR adds locale entries. Please source these labels from the existing i18n utilities, or make them configurable via props/slots.

Also applies to: 179-179

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 113 - 123, The component collapsible-params.vue currently uses
hardcoded Chinese labels ("参数名称", "配置", "说明" and the instance at line 179) which
bypasses the i18n layer; update the template to source these three header labels
from the app i18n utilities (e.g., use the existing useI18n/$t helper) or accept
them via props/slots (e.g., props.labels.name/config/desc or named slots) and
replace the hardcoded strings with the i18n/prop/slot values so language
switching works correctly; ensure the same change is applied to the repeated
occurrence referenced at line 179.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (2)

112-125: ⚠️ Potential issue | 🟡 Minor

Localize the shared labels instead of hardcoding them.

These strings bypass the locale layer in a @core/ui-kit component, so language switching will leave the new collapsible UI partially untranslated. Please source them from the existing i18n utilities or make them configurable via props/slots.

Also applies to: 181-181

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 112 - 125, The component collapsible-params.vue currently hardcodes
Chinese header labels ("参数名称", "配置", "说明") which bypass the i18n layer; update
the template to source these strings from the shared i18n utilities (e.g. use
the existing $t()/useI18n key lookups) or expose them as props/slots (e.g. props
like columnLabels or named slots for header cells) so language switching is
respected; replace each literal in the header divs with the i18n keys or
prop/slot references and ensure the same change is applied to the duplicate
occurrence mentioned (around line ~181).

57-67: ⚠️ Potential issue | 🟠 Major

Keep defaults synced when params changes after mount.

This only seeds missing keys once during setup. If the parent adds param schemas later, those new rows never receive their default values unless resetValue() is called manually. Replacing the one-shot init() call with an immediate watcher keeps the sync non-destructive and fixes dynamic schema updates.

💡 Suggested fix
-import { computed, nextTick, ref, useTemplateRef } from 'vue';
+import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';-init();
+watch(
+  () => props.params,
+  () => init(),
+  { immediate: true, deep: true },
+);

Also applies to: 92-92

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 57 - 67, The init() function currently seeds missing keys only
once; replace the one-shot call with a watcher on props.params (and/or the param
array) that runs immediately and non-destructively merges defaults into
modelValue.value by iterating props.params and setting nextValue[param.key] =
param.defaultValue ?? null only when nextValue[param.key] is undefined (same
logic as init); ensure the watcher is immediate so existing behavior on mount
remains and that it does not overwrite existing values (i.e., do not clear
keys), and apply the same change where similar seeding occurs (the other
init/reset usage around the code noted near the second occurrence).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 48-55: The computed bodyStyle currently always applies
props.maxHeight which causes collapsed content to be clipped; update the
bodyStyle computed to only include the maxHeight entry when props.open is true
(e.g., conditionally set maxHeight to the px/string value when props.open is
truthy, otherwise omit it or set to undefined/auto). Apply the same conditional
change to the other computed style block referenced around the second occurrence
(lines ~129-135) so both places only cap height in the expanded state; keep the
rest of the object (and existing overflow handling) unchanged.

---

Duplicate comments:
In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 112-125: The component collapsible-params.vue currently hardcodes
Chinese header labels ("参数名称", "配置", "说明") which bypass the i18n layer; update
the template to source these strings from the shared i18n utilities (e.g. use
the existing $t()/useI18n key lookups) or expose them as props/slots (e.g. props
like columnLabels or named slots for header cells) so language switching is
respected; replace each literal in the header divs with the i18n keys or
prop/slot references and ensure the same change is applied to the duplicate
occurrence mentioned (around line ~181).
- Around line 57-67: The init() function currently seeds missing keys only once;
replace the one-shot call with a watcher on props.params (and/or the param
array) that runs immediately and non-destructively merges defaults into
modelValue.value by iterating props.params and setting nextValue[param.key] =
param.defaultValue ?? null only when nextValue[param.key] is undefined (same
logic as init); ensure the watcher is immediate so existing behavior on mount
remains and that it does not overwrite existing values (i.e., do not clear
keys), and apply the same change where similar seeding occurs (the other
init/reset usage around the code noted near the second occurrence).
🪄 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: 7d8e3e21-5f25-46e7-a230-832b282f7c99

📥 Commits

Reviewing files that changed from the base of the PR and between 12a81a7 and f30157f.

📒 Files selected for processing (2)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (2)

48-55: ⚠️ Potential issue | 🟠 Major

Apply maxHeight only when expanded.

bodyStyle still sets maxHeight even when collapsed. With overflow-y-hidden on collapse (Line 132), visible rows can be clipped.

Suggested fix
 const bodyStyle = computed(() => {
+  if (!open.value || props.maxHeight == null) {
+    return undefined;
+  }
+
   return {
     maxHeight:
       typeof props.maxHeight === 'number'
         ? `${props.maxHeight}px`
         : props.maxHeight,
   };
 });

Also applies to: 129-135

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 48 - 55, bodyStyle currently always applies maxHeight from
props.maxHeight; change the computed (bodyStyle) to only include maxHeight when
the collapsible is expanded (check the open/expanded prop — e.g., props.open or
props.modelValue) so that when collapsed the maxHeight is not set and
overflow-y-hidden won't clip visible rows; update bodyStyle to return an empty
object or omit maxHeight when not expanded while still using props.maxHeight
when expanded.

57-67: ⚠️ Potential issue | 🟠 Major

Initialization is not reactive to params changes.

Line 92 runs init() only once. If props.params is loaded/changed later, new keys won’t get default values unless resetValue() is called.

Suggested fix
-import { computed, nextTick, ref, useTemplateRef } from 'vue';
+import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
@@
-init();
+watch(
+  () => props.params,
+  () => init(),
+  { immediate: true, deep: true },
+);

Also applies to: 92-92

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
around lines 57 - 67, The init function currently runs only once and won't pick
up new entries on props.params when they change; add a watcher that calls init
when props.params updates (e.g., watch props.params with deep or by keys and
call init() or init(true) as appropriate) so new param keys receive their
defaultValue automatically; reference the init function, props.params,
modelValue, and resetValue to ensure behavior matches existing reset semantics
(use force only if you need to overwrite existing values).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@packages/`@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue:
- Around line 48-55: bodyStyle currently always applies maxHeight from
props.maxHeight; change the computed (bodyStyle) to only include maxHeight when
the collapsible is expanded (check the open/expanded prop — e.g., props.open or
props.modelValue) so that when collapsed the maxHeight is not set and
overflow-y-hidden won't clip visible rows; update bodyStyle to return an empty
object or omit maxHeight when not expanded while still using props.maxHeight
when expanded.
- Around line 57-67: The init function currently runs only once and won't pick
up new entries on props.params when they change; add a watcher that calls init
when props.params updates (e.g., watch props.params with deep or by keys and
call init() or init(true) as appropriate) so new param keys receive their
defaultValue automatically; reference the init function, props.params,
modelValue, and resetValue to ensure behavior matches existing reset semantics
(use force only if you need to overwrite existing values).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2d70b6ee-8449-437c-ba64-ef76ee006f99

📥 Commits

Reviewing files that changed from the base of the PR and between f30157f and a096073.

📒 Files selected for processing (2)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue

@2yllll 2yllll closed this Apr 14, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators May 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants