feat: collapsible component and collapsible formitem - #7809
Conversation
* 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 目录
- 将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表单应用
|
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds 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 Changes
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 inform-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 usingscopedfor component styles.The styles are defined without
scoped, which means they could leak to other components. While the.vben-collapsible-paramsclass namespace provides some isolation, usingscopedwould 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
apps/web-naive/package.jsonapps/web-naive/src/views/demos/form/basic.vuepackages/@core/base/icons/src/lucide.tspackages/@core/ui-kit/form-ui/src/components/form-actions.vuepackages/@core/ui-kit/form-ui/src/form-render/form-field.vuepackages/@core/ui-kit/form-ui/src/form-render/form-label.vuepackages/@core/ui-kit/form-ui/src/types.tspackages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.tspackages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.tspackages/@core/ui-kit/shadcn-ui/src/components/index.tsplayground/src/locales/langs/en-US/examples.jsonplayground/src/locales/langs/zh-CN/examples.jsonplayground/src/router/routes/modules/examples.tsplayground/src/views/examples/form/collapsible.vue
💤 Files with no reviewable changes (1)
- packages/@core/ui-kit/form-ui/src/components/form-actions.vue
| @apply bg-accent items-center rounded-t-[0.5rem] border-b; | ||
| } |
There was a problem hiding this comment.
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.
| @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.
| 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); | ||
| } |
There was a problem hiding this comment.
Same Zod chaining bug and type mismatch with .default(null).
Two issues:
- Same bug as in
basic.vue:.min()and.max()return new schemas that are discarded. .default(null)setsnullas the default, but the validator expects anumber. 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.
| 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).
There was a problem hiding this comment.
使用optional会在重置后被绕过校验,zod校验没有生效,.default(null) 可以避免重置问题
There was a problem hiding this comment.
@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.
…llll/vue-vben-admin into feature-collapsible-component
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (1)
57-61:⚠️ Potential issue | 🔴 CriticalGuard model initialization and stop clobbering incoming values.
Line 59 can throw when
v-model:valueis initiallyundefined, and currentinit()also overwrites existing caller-provided values on setup. InitializemodelValueto 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
📒 Files selected for processing (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vuepackages/@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
|
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 |
There was a problem hiding this comment.
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
📒 Files selected for processing (6)
apps/web-naive/src/views/demos/form/basic.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vuepackages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.tsplayground/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
| 参数名称 | ||
| </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" | ||
| > | ||
| 说明 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (2)
112-125:⚠️ Potential issue | 🟡 MinorLocalize the shared labels instead of hardcoding them.
These strings bypass the locale layer in a
@core/ui-kitcomponent, 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 | 🟠 MajorKeep defaults synced when
paramschanges 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-shotinit()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
📒 Files selected for processing (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vuepackages/@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
There was a problem hiding this comment.
♻️ Duplicate comments (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue (2)
48-55:⚠️ Potential issue | 🟠 MajorApply
maxHeightonly when expanded.
bodyStylestill setsmaxHeighteven when collapsed. Withoverflow-y-hiddenon 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 | 🟠 MajorInitialization is not reactive to
paramschanges.Line 92 runs
init()only once. Ifprops.paramsis loaded/changed later, new keys won’t get default values unlessresetValue()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
📒 Files selected for processing (2)
packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vuepackages/@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
New Features
Documentation