You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 82b29fe
Browse filesBrowse the repository at this point in the historyBrowse files
feat(types): a related list's filter and add-picker filter take a view filter's any-of group (#28466)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuRvUhSZyCbMsUouh25Dmw3S)_Fixes#28462
Clause-②: yes (widening)
Metadata-protocol: none
Skills-docs: none (a TypeScript face widens to what the spec carriers
already declare; no authorable key, value or skill-taught shape moves)
**Landing order: lands after the PR for #28370** (the console reader
that teaches `@object-ui/core`'s `toFilterNode` the `{ or }` group).
Until then a typed author could write a group the related list does not
yet lower. Recorded on the card as claim amendment 6548122377.
## 维护者速读
- 改了什么:记录页相关列表的 `filter` 和"添加"选择器的 `filter`,在
`@object-ui/types`、`@object-ui/plugin-detail` 的 `RelatedList`
属性、`@object-ui/react` 的相关操作输入三处,类型从"只收普通规则"放宽为"普通规则或 `{ or: [...] }`
任一组"。
- 为什么改:spec 自 #28020 起这两个键就收任一组,界面这一侧的类型还只收普通规则,TS 作者写不出 spec 认可的组。
- 风险与回滚:只改类型,不改运行时代码;回滚即 revert 本 PR。唯一风险是落地顺序:要排在 #28370 的 PR 之后。
-
先看:`ui/packages/types/src/record-components.ts`(两个字段)、`ui/packages/plugin-detail/src/RelatedList.tsx`(两条
prop)、`ui/packages/types/src/__tests__/related-list-filter-or-group-28462.test.ts`。
- 两分钟验证:`cd ui && pnpm exec vitest run
packages/types/src/__tests__/related-list-filter-or-group-28462.test.ts`,预期
18 个用例全过。
- 需要你做的:无,席位落地。
## What changes
- `RecordRelatedListComponentProps.filter` and `.add.picker.filter`
(`@object-ui/types`): `ViewFilterRule[]` → `ViewFilterElement[]` from
`@objectstack/spec/ui`, the element `RecordRelatedListProps` declares
for both keys.
- `RelatedListProps.filter` (`ViewFilterElement[] | FilterNode`) and
`RelatedListProps.add.picker.filter` (`ViewFilterElement[]`) in
`@object-ui/plugin-detail`.
- `ResolveRelatedRecordActionsInput.filter` in `@object-ui/react`
(`ViewFilterElement[] | FilterNode`): `record-related-list.tsx` hands it
the resolved list filter. Added to the file surface by claim amendment
6548186999. Its one implementer, app-shell's
`RelatedRecordActionsBridge`, passes it to
`exactRecordListFilter(sources: readonly unknown[])`, so nothing there
changes.
- The sibling pins `related-list-filter-rule-array-10199` and
`related-list-add-picker-filter-mirror-9964` held the face at "the
contract minus the group" until the console read it. They now hold the
face **equal** to the contract.
- No runtime code changes. No zod mirror in `@object-ui/types` carries
these keys (the `record:related_list` node is spec-owned by reference in
`zod-mirror-parity.test.ts`), so no zod twin or parity row moves.
## Tests
- New
`ui/packages/types/src/__tests__/related-list-filter-or-group-28462.test.ts`.
For each key (`filter`, `add.picker.filter`) it compiles authored values
against the real mirror source: a group alone and a group beside a rule
are accepted; a nested group, a group of tuples and `{ any: [...] }` are
refused; plus two controls. Every compiler verdict is compared with the
protocol's own parse. A second leg compiles against the mirror with that
one key put back to `ViewFilterRule[]` and must flip exactly the two
accepted groups. Type-level legs include `@ts-expect-error` for a nested
group, and a reader that reads `.field` without narrowing.
- New
`ui/packages/plugin-detail/src/__tests__/RelatedList.filterOrGroup-28462.test.ts`:
type-level `Equal` legs for the two `RelatedList` props and the react
input, and the authoring face flowing into all three without a cast.
## Acceptance notes
- The card's "lowers to an `or` node beside the parent scope" assertion
is not in this PR. The lowering is #28370's `toFilterNode` change, and
on `main` `4bc963ca` `toFilterNode` passes a group element through
unlowered. Agreed with the seat: types only here, and this PR lands
after #28370's PR.
- Branch is the harness-assigned `claude/project-thread-l8kwol` (not
`claude/issue-28462-*`), as named in the claim.
## Verification
<details><summary>Premise on main 4bc963c: widening only the mirror
reds Type Check UI</summary>
`pnpm --filter @object-ui/plugin-detail type-check` → exit 2, three
TS2322 in `src/renderers/record-related-list.tsx`: L308 (`filter:
resolvedListFilter` → `ResolveRelatedRecordActionsInput.filter`), L693
(`filter={schema.filter}`), L695 (`add={…}` → `picker.filter`).
</details>
<details><summary>Type-checks and tests (head fa7ade4)</summary>
- `pnpm --filter @object-ui/types type-check`, `@object-ui/react
type-check`, `@object-ui/plugin-detail type-check`: all exit 0 (each
runs `tsc -p tsconfig.test.json`, so the new type legs are compiled).
- Downstream: `pnpm exec turbo run build
--filter='@object-ui/app-shell^...'` then `pnpm --filter
@object-ui/app-shell type-check`: VERDICT command-exit 0.
- `cd ui && pnpm exec vitest run packages/types/
…RelatedList.filterOrGroup-28462… RelatedList.listFilter`: 388 files,
10461 tests passed.
- `cd ui && pnpm exec vitest run packages/plugin-detail/
packages/react/src/context/`: 371 files passed (1 skipped), 3325 tests
passed (18 skipped).
- eslint on the 7 changed source and test files: 0 errors (102 warnings,
all pre-existing lines; none in the new files).
</details>
<details><summary>Ablation (fix committed first; restore leg blob ==
HEAD)</summary>
1. `RelatedList.tsx` picker prop back to `ViewFilterRule[]` (via
`scripts/ablation-replace.mjs`, anchor 1 → 0): `pnpm --filter
@object-ui/plugin-detail type-check` exit 2, TS2322 at
`record-related-list.tsx(695,9)`. Restored: blob `a60e4b47` == HEAD
blob, `git diff HEAD` empty.
2. `record-components.ts` `add.picker.filter` back to
`ViewFilterRule[]`: the new types test → 4 failed / 14 passed (both
accepted-group cases, the parse-agreement case and the flip case on the
picker key). Restored: blob `d57883f6` == HEAD blob.
</details>
<details><summary>Derived gates (dispatch-gates --commands at
fa7ade4)</summary>
34 commands run, every one exit 0 (incl. `check-sdui-manifest.mjs` and
its `--self-test`, `check:nul-bytes`, `check:published-files`,
`check:type-check-coverage`, `check:type-check-debt`,
`check:undeclared-dep-imports`). `--ran` reconcile: 34 derived, 34 run,
0 NOT-MEASURED, 0 UNRUN. Type Check UI and the other type-check lanes
are CI's.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgX3FadPoTM1W7TqHHf)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01L6bhgX3FadPoTM1W7TqHHf
Co-authored-by: Claude <noreply@anthropic.com>
feat(types): a related list's `filter` and its add-picker `filter` take a view filter's any-of group `{ or: [...] }`, as the spec carriers do
8
+
9
+
Clause-②: yes (widening)
10
+
Metadata-protocol: none
11
+
12
+
`RecordRelatedListComponentProps.filter` and `.add.picker.filter` in `@object-ui/types` are now `ViewFilterElement[]` (a flat rule or an any-of group `{ or: [rule, ...] }`, from `@objectstack/spec/ui`), the element the protocol's `RecordRelatedListProps` already declares for both keys. The props the related-list renderer hands those values to move with them: `RelatedListProps.filter` and `RelatedListProps.add.picker.filter` in `@object-ui/plugin-detail`, and `ResolveRelatedRecordActionsInput.filter` in `@object-ui/react`. Every value these types accepted before is still accepted; a nested group or a group of tuples is still refused by `tsc`, as the protocol's parse refuses it.
13
+
14
+
Types only: no runtime code changes. The related list and its picker lower the group through `@object-ui/core`'s `toFilterNode`, which the console reader change for the any-of group teaches to read it.
// @ts-expect-error objectui#9964 — the PRE-FIX declaration, asserted to be WRONG: `unknown` must not satisfy this pin. This directive going unused (TS2578) means the mirror went back to `unknown`.
0 commit comments