Skip to content

Commit 1071c86

Browse files
baozhoutaoclaude
andcommitted
feat(showcase): 加回 record.owner_id == os.user.id 归属门,并纠正一段已经过期的注释
合 main 之后重新实测:这条谓词现在**校验通过**。#5378 已经把答案放进 `packages/spec/src/data/injected-system-columns.ts`,让作者时校验能推导出平台注入 列 —— 我原先注释里写的「校验器拒绝它,已上报」在合并后的树上是**假话**,不能就 这么随 PR 发出去。 于是不只是改注释,而是把这条谓词作为正式标本加回来(`showcase_zoo_owner_gate` + 类型园里的 `showcase_zoo_t_owner`,三个记录面 + 两个视图的 `bulkActions`)。 它值得独立一条,因为 `owner_id` 是注入列而非声明字段,同时压两个面: - 作者时:它就是 #5378 落地的活证据; - 运行时:列表 `$select` 按对象声明字段构造,消费方若不认识平台列就会把它当拼错 丢掉、让谓词在缺席键上 fault —— 即 objectui#3501 的 `PLATFORM_RECORD_COLUMNS`。 与既有的 `showcase_zoo_user_gate`(声明的 `user` 字段)成对:注入列与声明字段必须 门控一致。 标签当场补 zh-CN,棘轮仍是 451、`check-i18n-coverage: OK (none new)`; `pnpm validate` exit 0、`typecheck` 通过、146 tests passed。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent d99e262 commit 1071c86

3 files changed

Lines changed: 44 additions & 10 deletions

File tree

examples/app-showcase/src/system/translations/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ export const ShowcaseTranslationBundle = {
452452
},
453453
showcase_zoo_relation_gate: { label: '查找 == 多值第一项', successMessage: '两个关系都解析到同一个 id。' },
454454
showcase_zoo_user_gate: { label: '指派给我(user 字段)', successMessage: '你是这条标本的指派用户。' },
455+
showcase_zoo_owner_gate: { label: '归我所有(owner_id)', successMessage: '这条标本归你所有。' },
455456
showcase_zoo_dialect_split: { label: '仅 CEL:contains()' },
456457
showcase_zoo_toolbar_gate: { label: '仅登录可见(工具栏)', successMessage: '工具栏门通过。' },
457458
showcase_zoo_visible_string: { label: 'visible:字符串' },
@@ -469,6 +470,7 @@ export const ShowcaseTranslationBundle = {
469470
showcase_zoo_t_tree: { label: 'tree —— 未设置' },
470471
showcase_zoo_t_user: { label: 'user —— 未设置' },
471472
showcase_zoo_t_user_identity: { label: 'user —— 是我' },
473+
showcase_zoo_t_owner: { label: 'owner_id(注入列)—— 属于我' },
472474
showcase_zoo_t_text: { label: 'text —— name 非空' },
473475
showcase_zoo_t_textarea: { label: 'textarea —— contains' },
474476
showcase_zoo_t_email: { label: 'email —— matches' },

examples/app-showcase/src/ui/actions/predicate-matrix.action.ts

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,41 @@ export const ZooRelationGateAction = defineAction({
137137
});
138138

139139
/**
140-
* The identity spelling over a declared `user` relation. `f_user` is unseeded
141-
* by design — `sys_user` rows come from sign-up, not seeds (see the note on
140+
* **The ownership gate every app writes first**, over the platform-injected
141+
* `owner_id` column. Both specimens are owned by the seeding user, so the
142+
* honest reading is: this appears on all four surfaces for whoever seeded the
143+
* workspace, and on none of them for anyone else.
144+
*
145+
* `owner_id` is injected by `applySystemFields` and is NOT among the object's
146+
* declared fields, which is what makes it worth a specimen of its own on two
147+
* counts. Author-time: it was rejected as `unknown field owner_id` until #5378
148+
* taught the linter to derive the injected set (`packages/spec/src/data/
149+
* injected-system-columns.ts`) — this predicate is the live proof that landed.
150+
* Run time: a list's `$select` is built from the object's declared fields, so
151+
* a consumer harvesting the fields a predicate reads has to know the platform
152+
* columns too, or drop this one as a typo and leave the predicate faulting on
153+
* an absent key (objectui#3501's `PLATFORM_RECORD_COLUMNS`).
154+
*/
155+
export const ZooOwnerGateAction = defineAction({
156+
name: 'showcase_zoo_owner_gate',
157+
label: 'Mine (owner_id)',
158+
icon: 'user-check',
159+
objectName: zoo,
160+
type: 'script',
161+
body: echo,
162+
successMessage: 'You own this specimen.',
163+
visible: 'record.owner_id == os.user.id',
164+
locations: [...RECORD_SURFACES],
165+
refreshAfter: false,
166+
});
167+
168+
/**
169+
* The same idea over a DECLARED `user` relation. `f_user` is unseeded by design
170+
* — `sys_user` rows come from sign-up, not seeds (see the note on
142171
* field-zoo.object.ts) — so this is HIDDEN on both specimens out of the box and
143172
* becomes visible on whichever record you assign to yourself in the UI. That
144-
* makes it the manual half of the matrix, and the one that most resembles what
145-
* an app actually writes.
146-
*
147-
* Note what it is NOT written against: `record.owner_id`, the platform-injected
148-
* ownership column. That is the predicate every app reaches for first, and the
149-
* author-time validator rejects it — `unknown field owner_id` — because
150-
* injected columns are absent from published object metadata. Filed upstream
151-
* rather than worked around here.
173+
* makes it the manual half of the matrix, and the pair with `owner_id` above is
174+
* the point: an injected column and a declared field must gate identically.
152175
*/
153176
export const ZooUserIdentityGateAction = defineAction({
154177
name: 'showcase_zoo_user_gate',
@@ -389,6 +412,7 @@ export const ZooTypeGates = [
389412
zooTypeGate('tree', 'tree — unset', 'record.f_tree == null'),
390413
zooTypeGate('user', 'user — unset', 'record.f_user == null'),
391414
zooTypeGate('user_identity', 'user — is me', 'record.f_user == os.user.id'),
415+
zooTypeGate('owner', 'owner_id (injected) — mine', 'record.owner_id == os.user.id'),
392416

393417
// ── Text family: contains() / matches(), never startsWith() ──────────────
394418
zooTypeGate('text', 'text — name non-empty', 'record.name != null && record.name.size() > 0'),
@@ -443,6 +467,7 @@ export const ZooTypeGates = [
443467

444468
export const allPredicateMatrixActions = [
445469
ZooRelationGateAction,
470+
ZooOwnerGateAction,
446471
ZooUserIdentityGateAction,
447472
ZooDialectSplitAction,
448473
ZooToolbarGateAction,

examples/app-showcase/src/ui/views/field-zoo.view.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export const FieldZooViews = defineView({
6868
* • `showcase_zoo_relation_gate` — offered (Full's two lookups resolve
6969
* to the same account id), and offered identically in the row `⋮` menu
7070
* and the record header. Three surfaces, one verdict.
71+
* • `showcase_zoo_owner_gate` — offered to whoever seeded the workspace
72+
* (both specimens are theirs). `owner_id` is a platform-INJECTED column
73+
* that object metadata never publishes, so it is also what proves a
74+
* `$select` harvest knows the platform columns and does not drop it as
75+
* a typo (objectui#3501).
7176
* • `showcase_zoo_user_gate` — absent until you assign `f_user` to
7277
* yourself on a record; `sys_user` rows cannot be seeded.
7378
* • `showcase_zoo_visible_*` — the three authoring forms of one
@@ -83,6 +88,7 @@ export const FieldZooViews = defineView({
8388
*/
8489
bulkActions: [
8590
'showcase_zoo_relation_gate',
91+
'showcase_zoo_owner_gate',
8692
'showcase_zoo_user_gate',
8793
'showcase_zoo_visible_string',
8894
'showcase_zoo_visible_tagged',
@@ -118,6 +124,7 @@ export const FieldZooViews = defineView({
118124
],
119125
bulkActions: [
120126
'showcase_zoo_relation_gate',
127+
'showcase_zoo_owner_gate',
121128
'showcase_zoo_user_gate',
122129
'showcase_zoo_visible_string',
123130
'showcase_zoo_visible_tagged',

0 commit comments

Comments
 (0)