Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-list): UserFilters buttons declare type="button" (objectstack#6952) - #3948
Merged
Merged
Conversation
…ack#6952) An HTML <button> defaults to type="submit" inside a <form>. Three UserFilters buttons declared no type: the dropdown chip trigger (filter-badge-*), the overflow trigger (user-filters-more) and the preset tab (filter-tab-*). All three now declare it, joining the session-tab buttons objectstack#5236 already covered. Only one of the three was actually at risk, measured by reverting the change: the chip and overflow triggers are PopoverTrigger asChild children, and Radix's PopoverTrigger renders Primitive.button type="button", which its Slot merges onto a child declaring no type — both already rendered as `button`. The plain preset tab button read `null`, i.e. submit. So this is one real (dormant) fix plus two contracts moved out of an upstream implementation detail into local source, the same reasoning objectui#3344 wrote onto the Combobox trigger. Dormant rather than live: the only mount point today is ListView's toolbar, which is not inside a form. The new tests assert every rendered UserFilters button in both modes, so a future button cannot land at the submit default and an upstream Radix change surfaces here instead of in a user's form. Also corrects the in-file comment claiming "a Radix trigger keeps the HTML default of submit" — the inaccuracy that propagated into objectstack#6952's premise.
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
commented
Aug 9, 2026
CollaboratorAuthor
✅ 验收通过,前提修正采纳(objectui 分片 PM,session CI 亲读终态:20 检查全 completed、0 失败。要点:
Generated by Claude Code |
yinlianghui
marked this pull request as ready for review
August 9, 2026 14:02
Uh oh!
There was an error while loading. Please reload this page.
akarma-synetal pushed a commit
to akarma-synetal/objectui
that referenced
this pull request
Aug 10, 2026
…bjectstack-ai#3831) (objectstack-ai#3908) `record:related_list.add.picker.filter` 被 spec 声明为「Restrict which records the picker offers」,渲染器从未读过它:`RelatedList` 挂 `RecordPickerDialog` 时传 `objectName` / `title` / `displayField` / `columns` / `cellRenderer` / `fieldsMeta` / `multiple` / `onSelect` / `onSelectRecords`,没有任何 filter。作者 写下「只允许指派 active 的岗位」「只允许挂未过期的许可」,拿到的是 `picker.object` 的全部记录;选中后直接建链接行或改父,`os validate` / `os build` 全绿,运行时零诊断。 现在它按原样传给 `baseFilter` —— 不是 `lookupFilters`,后者会把条件渲染成用户可编辑 的筛选栏行,等于把作者的硬性限制降级成建议。 ## 为什么改到了 packages/fields `baseFilter` 声明为 `Record<string, any>`、以对象展开合并,这个形状服务依赖型 lookup 链(objectstack-ai#2215)恰好正确,却根本装不下 spec 的 `ViewFilterRule[]`:TS 接受数组塞进该槽位 (数组满足 `any` 的字符串索引),展开把它压成 `{"0": rule, "1": rule}`,查询于是去过滤 名为 `0` / `1` 的列 —— 类型全绿、查询错误、无任何诊断。绕开它只剩「在 objectui 里再写 一份 spec-operator 词汇表」一条路,而这份词汇表已有两份(spec 的 `AST_OPERATOR_MAP`、 data-objectstack 的 `FILTER_OPERATOR_ALIASES`),objectstack-ai#3948 就是两份的代价。 所以槽位按结构判别(`Array.isArray`)接受两种形状,判别子是精确的而非启发式的 —— AST 节点必是数组、规则必是普通对象,与 `toFilterNode` 同一谓词: - 记录形式保持键覆盖语义**逐字节不变**:级联父值必须**替换**同字段上过期的 `lookupFilters` 条目,而不是与之求交(`account = 'stale' AND account = 'a1'` 会返回 零行)。`LookupField.dependsOn.test.tsx` 一行未动且保持绿。 - 规则数组经 `mergeFilterNodes`(仓内唯一 filter 下沉口,与 plugin-list 的 `buildEffectiveFilter`、plugin-view 的 ObjectView 共用)下沉,19 个 operator 全部 无损,包括记录形式没有 `$op` 可用的 `before` / `after` / `is_empty` / `is_not_empty`。不新增第二份词汇表。 槽位类型同时收紧为 `unknown`,`useRecordQuery` 的 filter 类型与空判随之数组感知 (`Object.keys` 对数组返回下标,旧的记录专用判断对 AST 节点只是碰巧成立)。 ## 顺带 `RelatedListProps.add.picker.filter` 从 `any` 收紧为 spec 的 `ViewFilterRule[]`; `record:related_list.add` 的 input description 删掉 objectstack-ai#3808 按 objectstack-ai#3165 先例写入的 KNOWN GAP 句(gap 兑现之后才删),`recordRelatedListInputs.spec-parity.test.ts` 的 那枚钉子随之翻转 —— 现在它反过来在「gap 警告被放回」或「接线被回滚却仍宣称限制生效」 时报红。 反向验证跑了两向,方向先判后跑:摘掉 RelatedList 的直传 → 数组路钉红且点名 `$filter` undefined,无 filter 用例保持绿;把合并回退成旧的对象展开 → 两个文件共 5 枚钉红,且报的是 `{ '0': { field: 'is_active', … } }` 这一**损坏**形态而非缺失, 记录路钉与 objectstack-ai#2215 六枚钉全绿。 Co-authored-by: Claude <noreply@anthropic.com>
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 freeto 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.
Fixesobjectstack-ai/objectstack#6952
改了什么
packages/plugin-list/src/UserFilters.tsx里 issue 点名的三处 button 元素补上type="button"(以当前origin/main=ebb579dbb实况逐一排查,行号已漂移):type:511filter-badge-*)"button"(Radix 供给):672user-filters-more)"button"(Radix 供给):855filter-tab-*)null(即 submit):883:891:913"button"全文件
git grep共 6 个 button 元素,改后 6/6 都显式声明type="button"。重要:issue 前提只成立三分之一(实测,非阅读推断)
issue 正文断言三处「HTML 默认 submit,在 form 元素内会提交表单」。反向验证推翻了其中两处:把三行
type="button"撤掉重跑,5 条新测试只红 2 条 —— chip 与溢出触发器仍然读到type="button"。原因在 Radix:两者都是
PopoverTrigger asChild的子元素,而PopoverTrigger自己渲染的就是Primitive.button且带type: "button"(node_modules/.pnpm/@radix-ui+react-popover@1.1.23/.../dist/index.mjs:89),Slot 会把它并到「自己没声明 type」的子元素上。只有预设 tab 是普通 button、没人替它供给,改前确实渲染成 submit。所以本 PR = 一处真实(休眠)缺陷 + 两处把契约从上游实现细节搬进本地源码。后者正是 objectui#3344 在 Combobox 触发器上写下的理由(
packages/components/src/custom/combobox.tsx:74-80,那段注释的措辞本来就是准确的)。顺带纠正一行注释:PR #3926 在 add 触发器上写的「a Radix trigger keeps the HTML default of
submit」是错的,而这句错误说法正是 issue 前提的来源(#3344 的准确注释 → #3926 的错误改写 → #6952 的立单前提 → 我第一版草稿也照抄了)。留着它下一个读者会再推一遍同样的错误结论,故就地改正,零行为影响。⛔ 未做(issue 正文提到、PM 明确另裁):让
@object-ui/components的PopoverTrigger原语自带默认type。另外补一条对那张设计卡有用的实测结论 —— Radix 的PopoverTrigger今天已经这么做了,所以那张卡若只针对 Popover 触发器,实际是 no-op;真正没人兜底的是普通 button(如本单的预设 tab)。休眠性
今日唯一挂载点是
ListView工具条,不在 form 元素内,线上无人踩到 —— 与 issue 标finding的判断一致。新测试把「组合变化后依然不提交」钉住。测试
packages/plugin-list/src/__tests__/UserFilters.test.tsx就近追加一个 describe(5 条):三处各一条(断言getAttribute('type') === 'button',并在 form 元素内点击、断言onSubmit未被调用),一条 chip 清除 × 的行为(× 在 button 内部且只stopPropagation(),挡不住 submit 按钮的 activation behaviour,靠的是外层 button 自己的type),再加一条扫描式断言:两种模式下渲染出的每一个 button 都必须是type="button"—— 将来新加的 button 不需要谁记得来扩列表。反向验证(撤掉三行
type="button",方向如上所述与模板预期不同,如实记录):changeset:
@object-ui/plugin-listpatch。Generated by Claude Code