Skip to content

Commit 0be6371

Browse files
baozhoutaoclaude
andcommitted
feat(showcase): 动作显隐矩阵——四个动作面 × 三种 visible 写法 × requiredPermissions × 每种字段类型的谓词
给 `showcase_field_zoo` 加一整套可证伪的动作门控夹具,覆盖决定「按钮出不出现」的两件事: `visible`(记录上的 CEL 谓词)与 `requiredPermissions`(ADR-0066 D4 能力门)。 两条种子记录是可证伪性的来源:Specimen — Full(字段全填)必须出现, Specimen — Minimal(多数为 null)必须消失——写错的表现是按钮出现在错误的地方, 而不是一个悄悄变绿的测试。 - **四面一致性**:同一个动作声明在行内 kebab / 记录页头 / ⋯ 菜单,并被视图的 `bulkActions` 提升进批量栏。关系比关系(`f_lookup == f_lookups[0]`)是最利的 一条:两个操作数都是 lookup,谁被展开谁就变成对象,比较就静默为假。 `gated_columns` 视图把 `f_lookup` 设为列(于是被 `populate=`),默认列表两个都不展开 —— 同样的记录、同样的谓词,两个视图必须给出同一结论(objectui#3501)。 - **三种 visible 写法**:裸 CEL 字符串 / `P` 标签模板 / `{ dialect, source }` 信封, 同一条谓词并排钉住;三者若在同一条记录上分歧,就是某个渲染器把某一种当特例了。 布尔 visible 不在此列——`ExpressionInput` 不接受它,`objectstack build` 发不出这种 形状,由 objectui 自己的单测钉(objectui#3492)。 - **requiredPermissions**:持有 / 不持有 / 两个取 AND / 空声明四种,四个面同一结论。 新增 `showcase.restricted_ops` 能力:**定义了但不授予任何权限集**——门的可证伪一半, 正是批量栏当初整个忽略 `requiredPermissions` 时无人察觉的原因。 - **字段类型谓词园**:每种字段类型一条 `visible`,含 lookup(单/多/空)、master_detail、 tree、user、文本族、数值族、时间族、布尔/选项族、json/location/address/composite/ repeater/vector,以及 AND/OR/NOT/三元。全部对着真实 runtime 的 CEL 引擎实测过, 不是照着规范猜的。 顺带钉住三条实测得到的作者规则:必须 `record.` 前缀;遍历/调方法前必须判空 (`null` 没有成员也没有方法,不判空在 Minimal 上直接 fault);用 `contains()` / `matches()` 而不是 `startsWith()` / `endsWith()`(后者不是 CEL,objectui 会降级到遗留 JS 引擎并告警)。 `showcase_zoo_dialect_split` 是故意留下的**红色夹具**:同一个 `.contains()` 谓词在行内 kebab 里正常、在记录页头被判抛错并隐藏——页头不走 CEL 引擎(objectui#3521)。 按仓库规矩不粉饰,改成一屏可对比的现场。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 7b005b4 commit 0be6371

6 files changed

Lines changed: 655 additions & 3 deletions

File tree

examples/app-showcase/objectstack.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { setupShowcaseExternalDatasource } from './src/system/datasources/extern
2020
import { registerRecalcEndpoint } from './src/system/server/recalc-endpoint.js';
2121
import { registerShowcasePositionBindings } from './src/security/bind-position-sets.js';
2222
import { registerShowcaseApprovalDemo } from './src/security/seed-approval-demo.js';
23-
import { TaskViews, ProjectViews, InquiryViews, BusinessUnitViews, ContactViews } from './src/ui/views/index.js';
23+
import { TaskViews, ProjectViews, InquiryViews, BusinessUnitViews, ContactViews, FieldZooViews } from './src/ui/views/index.js';
2424
import { ShowcaseApp } from './src/ui/apps/index.js';
2525
import { ChartGalleryDashboard, OpsDashboard, RevenuePulseDashboard } from './src/ui/dashboards/index.js';
2626
import { ShowcaseTaskDataset, ShowcaseProjectDataset, ShowcaseInvoiceDataset, ShowcaseAccountDataset } from './src/ui/datasets/index.js';
@@ -193,7 +193,7 @@ export default defineStack({
193193

194194
// UI
195195
apps: [ShowcaseApp],
196-
views: [TaskViews, ProjectViews, InquiryViews, BusinessUnitViews, ContactViews],
196+
views: [TaskViews, ProjectViews, InquiryViews, BusinessUnitViews, ContactViews, FieldZooViews],
197197
pages: [CapabilityMapPage, StartHerePage, ComponentGalleryPage, ProjectWorkspacePage, ProjectDetailPage, TaskWorkbenchPage, TaskTriagePage, TaskBoardPage, TaskCalendarPage, TaskGalleryPage, TaskSchedulePage, TaskTimelinePage, TaskMapPage, TaskAllViewsPage, ActiveProjectsPage, TaskDetailPage, ReviewQueuePage, NewProjectWizardPage, MyWorkPage, SettingsPage, StylingGalleryPage, CommandCenterPage, CommandCenterJsxPage, CrmWorkbenchPage, TaskDeskPage, PageVariablesPage, ContactFormPage, RenewalsPipelinePage],
198198
dashboards: [ChartGalleryDashboard, OpsDashboard, RevenuePulseDashboard],
199199
books: allBooks,

examples/app-showcase/src/security/capabilities.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,27 @@ export const ExportDataCapability = defineCapability({
5757
packageId: 'com.example.showcase',
5858
});
5959

60-
export const allCapabilities = [ExportDataCapability];
60+
/**
61+
* A capability that is DEFINED and granted to NOBODY — the falsifiable half of
62+
* the ADR-0066 three-way separation, and the one a demo usually leaves out.
63+
*
64+
* Its whole job is to be required and never held: `showcase_zoo_perm_missing`
65+
* (and the AND-gate specimen next to it, see ui/actions/predicate-matrix.action.ts)
66+
* lists it in `requiredPermissions`, so those buttons must be absent for every
67+
* caller on every one of the four action surfaces. Without a capability nobody
68+
* holds there is nothing to notice when a surface stops applying the gate —
69+
* which is exactly how the selection bar shipped ignoring `requiredPermissions`
70+
* outright (objectui#3492) while three other surfaces honoured it.
71+
*
72+
* Deliberately absent from every permission set. If a future set grants it, the
73+
* two specimens stop testing anything.
74+
*/
75+
export const RestrictedOpsCapability = defineCapability({
76+
name: 'showcase.restricted_ops',
77+
label: 'Restricted Showcase Operations',
78+
description: 'Reserved for the capability-gate specimens — intentionally granted to no permission set.',
79+
scope: 'org',
80+
packageId: 'com.example.showcase',
81+
});
82+
83+
export const allCapabilities = [ExportDataCapability, RestrictedOpsCapability];

examples/app-showcase/src/ui/actions/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
import { defineAction } from '@objectstack/spec/ui';
44

5+
// The action-GATING matrix (`visible` / `requiredPermissions` across all four
6+
// action surfaces, and one predicate per field type) lives in its own file —
7+
// it is a coverage fixture for the gates, not another ActionType specimen.
8+
import { allPredicateMatrixActions } from './predicate-matrix.action.js';
9+
10+
export * from './predicate-matrix.action.js';
11+
512
const task = 'showcase_task';
613
const invoice = 'showcase_invoice';
714
const fieldZoo = 'showcase_field_zoo';
@@ -375,4 +382,5 @@ export const allActions = [
375382
ActionParamGalleryAction,
376383
ArchiveTaskAction,
377384
PortfolioSnapshotAction,
385+
...allPredicateMatrixActions,
378386
];

0 commit comments

Comments
 (0)