fix(fields): 记录选择器筛选面板保留 select 选项作者声明的类型 (#3422) - #3428
Merged
Conversation
…n's authored type (#3422) Radix Select speaks strings: the filter panel rendered each option as `String(opt.value)` and stored the string `onValueChange` handed back, so a `select` filter whose option values are numbers or booleans queried `{ level: "1" }` against records storing `level: 1` — an option that plainly has records returned an empty list. The `lookup_filters` auto-derivation is where this bites: its `in`/`notIn` options carry whatever the author wrote (`LookupFilterDef.value` is `unknown`), so every non-string option was unfilterable. Map the control's string back through `col.options` at the CONTROL boundary (`matchOptionValue` / `toControlValue`, replicating the #3090 semantics from `packages/components/src/renderers/form/option-value.ts`) rather than coercing in `filterValuesToRecord`, which would have to guess whether `"1"` meant `1` or `"1"`. Schema-derived options are strings by spec and round-trip unchanged; the `number` / `boolean` inputs already converted explicitly and are untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3422
问题
Radix
Select只讲字符串:选项渲染成String(opt.value),onValueChange回传的也是那个字符串。筛选面板把它原样存进filterValues,而filterValuesToRecord的select分支又原样透传 —— 于是选项值不是字符串时,下发的$filter与库里存的值类型不符,选了一个明明有记录的选项,列表却空了。受影响的是
lookup_filters自动派生这条路径:in/notIn的数组值直接成为选项值,类型完全由作者写的元数据决定(LookupFilterDef.value声明为unknown),所以派生出的每一个非字符串选项都筛不出记录。复现:
lookup_filters: [{ field: 'level', operator: 'in', value: [1, 2, 3] }]→ 打开记录选择器 → 选1→ 下发$filter: { level: "1" },而记录里level是数字1。修法:在控件边界回映射,不在下游猜类型
在
handleFilterChange处按col.options把控件的字符串反查回作者写的原值 —— 控件讲字符串,payload 保留作者声明的类型。复用表单侧 #3090 已经确立的matchOptionValue/toControlValue语义(packages/components/src/renderers/form/option-value.ts,当时解决的是标准表单 select 上一模一样的类型漂移)。没有在
filterValuesToRecord里做 coerce:那样就得去猜"1"到底是1还是"1",而选项列表本来就精确地回答了这个问题 —— 把区分权交给消费端猜,正是 AGENTS.md #0.1 说的"宽松兜底把错误约定固化成第二套事实契约"。关于复制而非复用:
packages/fields确实依赖@object-ui/components,但这两个函数是该包的模块私有实现(公开 barrel 未导出,包也没有发布深层子路径)。为共享这四行去拓宽另一个包的公共 API 不划算,因此在 fields 内保留一份副本,并在注释里注明 #3090 这个先例。边界情况(已在代码注释与测试中写明)
String()撞车(1与'1',或两个都打印成[object Object]的对象值):取第一个匹配项。这种选项列表本来就渲染不出来(Radix 会拿到两个同value的SelectItem,React 拿到两个同 key 的子节点),这条 tie-break 是为了让结果确定,不是为了让有歧义的列表"能用"。''的选项值无法表达成一个生效的筛选。这一点在 [fields] 记录选择器筛选面板:select 筛选项一律按字符串下发,lookup_filters 派生的数字/布尔选项筛不出记录 #3422 之前就是如此,本次不变 —— 回映射恢复的是选项的类型,不重新定义什么算"空选择"。SelectOptionSchema.value是string),原样往返,[fields] lookup 记录选择器筛选面板:select 类型筛选项不带 options,下拉为空 #3336 那条新路径不受影响。number/boolean分支:原本就已显式Number(raw)/Boolean(checked),不动。issue 指出的"三个分支行为不一致"是靠把select抬到它们的标准来消除的,不是反过来。测试
扩展 #3421 建立的
RecordPickerDialog.filterOptions.test.tsx(拿到正确的可选项、与选中后下发正确的值,是同一个控件的两半,并排钉住):1、布尔选项下发false,断言用toBe加显式typeof——"1" == 1松散断言在坏版本上会误绿。number与boolean输入维持原有转换。反向验证(先定方向再跑):只回退
RecordPickerDialog.tsx、保留测试,预测 12 项中恰好 3 项转红 —— 两个复现用例加同样走回映射的撞车用例。实测完全吻合:消费半径(
RecordPickerFilterColumn的下游)一并跑过:pnpm exec vitest run packages/fields→ 60 files / 929 tests passedAccessExplainPanel+AssignedUsersSection+packages/plugin-detail(含RelatedList) → 52 files / 453 tests passedpnpm --filter @object-ui/fields type-check→ 干净(注意全新 worktree 里必须先pnpm --filter '@object-ui/fields^...' build,否则依赖缺d.ts,报错看起来像本次改动弄坏了 import)eslint两个改动文件 → 0 error(54 条既有 warning 均不在新增行上)Generated by Claude Code