Permission, formScene, and Action Visibility Guide
This guide explains how action visibility works in current Cabloy Basic entry pages when formScene participates in the decision.
Use this page when you want to understand:
- how
permissionHint.formSceneworks - how it interacts with
$$pageEntry.formMeta.formScene - how that differs from
$passport.checkPermission(...) - why some actions can be scene-gated while others cannot
- why bulk actions do not currently support
formScene
Why this page exists
Several existing docs already explain nearby pieces:
- Form Scene to Page Meta Guide explains how
formScenebecomesformMeta, thenpageMeta - Page Meta Guide explains shell/task presentation
- Model Resource Owner Pattern and related resource-model docs explain permissions as part of resource ownership
What those pages do not isolate directly is the specific runtime rule for entry-page action visibility.
That is the gap this page fills.
In the current Basic source, formScene participates in action visibility as a UI visibility filter layered in front of the normal permission authorization check.
The shortest accurate mental model
A practical mental model is:
- page-entry runtime decides the current
formScene formMetaFromFormScene(...)derivesformMeta$$pageEntry.formMeta.formScenebecomes the current scene surface for entry-page blocksblockToolbarRowreadspermissionHint.formScene- if the current scene does not match, the action is hidden immediately
- if the scene matches,
$passport.checkPermission(...)still decides whether the action is allowed by permission rules - the action renders only if both checks pass
That means formScene is not itself a permission engine. It is a scene-aware visibility prefilter.
What this guide is not
This page is not a general permission guide for every frontend action surface.
It is specifically about the current entry-page action visibility flow.
It is also not a guide to page-meta propagation. pageMeta.formMeta is part of the surrounding story, but the actual visibility authority for entry-page actions is the local page-entry runtime context.
Source-confirmed reading path
When reading this topic, use this order:
zova/src/suite-vendor/a-zova/modules/a-form/src/lib/utils.tszova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsxzova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockToolbarRow/controller.tsxzova/src/suite-vendor/a-zova/modules/a-openapi/src/types/permissions.tszova/src/suite-vendor/a-zova/modules/a-openapi/src/types/resource/formActionRow.tszova/src/suite-vendor/a-zova/modules/a-openapi/src/types/resource/tableActionRow.tszova/src/suite-vendor/a-zova/modules/a-openapi/src/types/resource/tableActionBulk.ts- optional comparison:
zova/src/suite/cabloy-basic/modules/basic-table/src/bean/tableCell.actionOperationsRow.tsx
That order moves from scene/meta translation, to page-entry runtime ownership, to action-row filtering, to permission-hint typing, and finally to the bulk-action limitation and row-action comparison.
Visibility flow step by step
1. formScene becomes canonical runtime metadata
The canonical helper lives in:
zova/src/suite-vendor/a-zova/modules/a-form/src/lib/utils.tsThe current source confirms:
view->formMode: 'view'create->formMode: 'edit', editMode: 'create'edit->formMode: 'edit', editMode: 'update'
This matters because action visibility does not read an arbitrary raw string from anywhere in the app. It reads the current page-entry scene after that scene has already become part of the page-entry runtime metadata.
2. blockPageEntry exposes the current scene through $$pageEntry
The key entry-page runtime file is:
zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsxThis controller:
- resolves
formScene - computes
formMeta - builds the shared JSX render context
- exposes
$$pageEntryinto that context
That is the key boundary for action visibility:
- entry-page actions do not need to rediscover the current scene
- they can read it from
$$pageEntry.formMeta.formScene
3. blockToolbarRow checks scene first, then permission
The most important source file for this guide is:
zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockToolbarRow/controller.tsxIts action loop does two different checks:
_checkFormScene(permissionHint)$passport.checkPermission(...)
The order matters.
Scene prefilter
_checkFormScene(...):
- reads
$$pageEntry.formMeta.formScene - reads
permissionHint?.formScene - accepts a single scene or an array of scenes
- treats no
formScenehint as “all scenes”
If the scene does not match, the action does not continue into the permission check.
Authorization check
Only after the scene passes does the controller call:
$passport.checkPermission(this.permissions, actionName, permissionHint)
This is the critical source-confirmed distinction:
- scene filtering decides whether this action should even be considered in the current page-entry scene
- permission checking decides whether the user is allowed to perform it
4. What permissionHint.formScene really means
permissionHint.formScene should be read as:
- a UI visibility filter tied to the current page-entry scene
It should not be read as:
- a replacement for permission authorization
- a generic global permission-engine rule
- a page-meta-driven shell rule
A practical reading rule is:
- if the scene is wrong, hide the action
- if the scene is right, still run the real permission check
5. What the permission types confirm
The permission hint types live in:
zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/permissions.tsThe important source-confirmed detail is:
IPermissionHintGeneralcan carryformSceneIPermissionHintTableActionRowcan carryformSceneIPermissionHintTableActionBulkdoes not carryformScene
This matches the current runtime split:
- entry-page row/form action visibility can be scene-aware
- bulk-action visibility is not scene-aware in the same way today
6. Row/form action types vs bulk action types
The row/form action option types live in:
a-openapi/src/types/resource/formActionRow.tsa-openapi/src/types/resource/tableActionRow.ts
They both use permission?: IPermissionHintTableActionRow.
That means row-style action definitions can express formScene in their permission hints.
By contrast, bulk action options live in:
a-openapi/src/types/resource/tableActionBulk.ts
That type uses:
permission?: IPermissionHintTableActionBulk
And that bulk hint type does not have formScene.
This is the clearest public type-level explanation for the current limitation.
7. Why bulk actions are different today
Bulk actions are typed around bulk permission hints, not row/form-scene hints.
So in current Basic source, you should not claim that bulk actions support scene-based filtering the same way entry-page toolbar actions do.
This is not only a docs distinction. It is a source-confirmed contract distinction.
8. Comparison with table row actions
A useful comparison file is:
zova/src/suite/cabloy-basic/modules/basic-table/src/bean/tableCell.actionOperationsRow.tsxThis table-row action surface uses permission checks, but it does not add the same local page-entry formScene prefilter path as blockToolbarRow.
That makes the current entry-page toolbar flow more specific:
- it is tied to entry-page runtime context
- it is not the universal rule for every action surface in the frontend
9. Boundary with page meta
A common confusion is to think that because formMeta also becomes part of page meta, page meta is the authority for action visibility.
That is not the current source-confirmed rule.
The better boundary is:
pageMeta.formMetais shell/task presentation state$$pageEntry.formMeta.formSceneis the local page-entry runtime surface thatblockToolbarRowreads for scene filtering
So for action visibility, the local page-entry context is the authority.
10. Bulk-action limitation
The current public Basic source supports this rule clearly:
- row/form action hints can be scene-aware
- bulk action hints are not scene-aware today
If a contributor needs scene-aware bulk visibility, they should first verify whether the type and runtime contracts are being extended, rather than assuming the row-action rule applies automatically.
Where to read next
Use these next steps depending on your question:
- if you want the full
formScene -> formMeta -> pageMeta -> shell/tabbridge, read Form Scene to Page Meta Guide - if you want the broader entry-page runtime path, read Resource Entry Page Deep Dive
- if you want the list-page row/bulk contrast, read Table Action Visibility and Permission Flow Guide
- if you want shell/task presentation semantics, read Page Meta Guide
- if you want the underlying resource permission/model context, read Model Resource Owner Pattern
Final takeaway
The most accurate rule for current Cabloy Basic entry-page action visibility is:
permissionHint.formSceneis a scene-aware visibility prefilter$$pageEntry.formMeta.formSceneis the current scene source$passport.checkPermission(...)is still the actual authorization check- the action renders only if both layers pass
- bulk actions do not currently carry
formScenein their permission hints
That is the source-confirmed permission / formScene / action visibility path in the current Basic frontend architecture.