cabloy 5.1.60 → 5.1.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/contract-loop-gate.ts +296 -0
- package/.claude/settings.json +16 -0
- package/.claude/skills/cabloy-backend-scaffold/SKILL.md +2 -0
- package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +1 -0
- package/.claude/skills/cabloy-contract-loop/SKILL.md +89 -16
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +102 -14
- package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +4 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +32 -14
- package/.claude/skills/cabloy-domain-planning/SKILL.md +212 -0
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +13 -0
- package/.claude/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +2 -0
- package/.claude/skills/cabloy-module-removal/SKILL.md +144 -0
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +7 -0
- package/.claude/skills/cabloy-zova-source-reading/SKILL.md +221 -0
- package/.claude/skills/cabloy-zova-source-reading/references/analysis-modes.md +91 -0
- package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +117 -0
- package/CHANGELOG.md +64 -0
- package/CLAUDE.md +11 -0
- package/cabloy-docs/.vitepress/config.mjs +197 -5
- package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
- package/cabloy-docs/ai/docs-skills-rules-mapping.md +22 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +12 -7
- package/cabloy-docs/ai/introduction.md +1 -0
- package/cabloy-docs/ai/playbook-backend-module.md +6 -0
- package/cabloy-docs/ai/playbook-module-removal.md +164 -0
- package/cabloy-docs/ai/skills.md +12 -0
- package/cabloy-docs/backend/backend-contract-emission-output-inspection.md +189 -0
- package/cabloy-docs/backend/backend-contract-emission-source-reading-map.md +160 -0
- package/cabloy-docs/backend/backend-contract-emission-specimen.md +170 -0
- package/cabloy-docs/backend/backend-resource-module-contract-chain.md +323 -0
- package/cabloy-docs/backend/backend-source-reading-debug-checklist.md +173 -0
- package/cabloy-docs/backend/backend-source-reading-roadmap.md +129 -0
- package/cabloy-docs/backend/backend-source-reading-verify-playbook.md +166 -0
- package/cabloy-docs/backend/bean-scene-authoring.md +4 -4
- package/cabloy-docs/backend/broadcast-guide.md +3 -3
- package/cabloy-docs/backend/cli.md +20 -11
- package/cabloy-docs/backend/config-guide.md +4 -4
- package/cabloy-docs/backend/controller-aop-guide.md +10 -10
- package/cabloy-docs/backend/controller-guide.md +12 -2
- package/cabloy-docs/backend/crud-workflow.md +7 -3
- package/cabloy-docs/backend/dto-guide.md +18 -2
- package/cabloy-docs/backend/dto-infer-generation.md +201 -25
- package/cabloy-docs/backend/election-guide.md +2 -2
- package/cabloy-docs/backend/entity-guide.md +30 -3
- package/cabloy-docs/backend/error-guide.md +3 -3
- package/cabloy-docs/backend/event-guide.md +4 -4
- package/cabloy-docs/backend/external-aop-guide.md +2 -2
- package/cabloy-docs/backend/field-indexes.md +9 -3
- package/cabloy-docs/backend/foundation.md +8 -8
- package/cabloy-docs/backend/i18n-guide.md +6 -6
- package/cabloy-docs/backend/internal-aop-guide.md +2 -2
- package/cabloy-docs/backend/introduction.md +15 -0
- package/cabloy-docs/backend/migration-and-changes.md +3 -3
- package/cabloy-docs/backend/model-guide.md +16 -6
- package/cabloy-docs/backend/openapi-guide.md +3 -0
- package/cabloy-docs/backend/queue-guide.md +3 -3
- package/cabloy-docs/backend/redlock-guide.md +2 -2
- package/cabloy-docs/backend/schedule-guide.md +2 -2
- package/cabloy-docs/backend/scripts.md +8 -0
- package/cabloy-docs/backend/serialization-guide.md +12 -2
- package/cabloy-docs/backend/service-guide.md +18 -9
- package/cabloy-docs/backend/startup-guide.md +5 -5
- package/cabloy-docs/backend/status-guide.md +271 -0
- package/cabloy-docs/backend/unit-testing.md +3 -3
- package/cabloy-docs/backend/vona-source-reading-map.md +157 -0
- package/cabloy-docs/backend/websocket-protocol-guide.md +5 -5
- package/cabloy-docs/backend/websocket-usage-guide.md +15 -8
- package/cabloy-docs/frontend/a-model-under-the-hood.md +281 -0
- package/cabloy-docs/frontend/a-openapi-under-the-hood.md +248 -0
- package/cabloy-docs/frontend/a-router-guide.md +307 -0
- package/cabloy-docs/frontend/api-guide.md +6 -4
- package/cabloy-docs/frontend/api-schema-guide.md +1 -0
- package/cabloy-docs/frontend/app-startup-guide.md +7 -4
- package/cabloy-docs/frontend/bean-scene-authoring.md +3 -1
- package/cabloy-docs/frontend/behavior-guide.md +16 -16
- package/cabloy-docs/frontend/cli.md +14 -2
- package/cabloy-docs/frontend/command-scene-authoring.md +504 -0
- package/cabloy-docs/frontend/component-guide.md +5 -5
- package/cabloy-docs/frontend/component-props-guide.md +1 -1
- package/cabloy-docs/frontend/component-v-model-guide.md +2 -2
- package/cabloy-docs/frontend/design-principles.md +6 -0
- package/cabloy-docs/frontend/fetch-interceptor-guide.md +440 -0
- package/cabloy-docs/frontend/filter-query-select-data-flow-guide.md +260 -0
- package/cabloy-docs/frontend/form-guide.md +786 -0
- package/cabloy-docs/frontend/form-scene-to-page-meta-guide.md +303 -0
- package/cabloy-docs/frontend/foundation.md +33 -0
- package/cabloy-docs/frontend/frontend-source-reading-roadmap.md +249 -0
- package/cabloy-docs/frontend/generated-contract-consumption-debug-checklist.md +190 -0
- package/cabloy-docs/frontend/generated-contract-consumption-entry-branch.md +205 -0
- package/cabloy-docs/frontend/generated-contract-consumption-list-branch.md +157 -0
- package/cabloy-docs/frontend/generated-contract-consumption-specimen.md +203 -0
- package/cabloy-docs/frontend/generated-contract-consumption-verify-playbook.md +189 -0
- package/cabloy-docs/frontend/generic-component-guide.md +1 -1
- package/cabloy-docs/frontend/introduction.md +38 -5
- package/cabloy-docs/frontend/ioc-and-beans.md +6 -0
- package/cabloy-docs/frontend/mock-guide.md +1 -0
- package/cabloy-docs/frontend/model-architecture.md +288 -39
- package/cabloy-docs/frontend/model-resource-best-practices.md +379 -0
- package/cabloy-docs/frontend/model-resource-cookbook.md +508 -0
- package/cabloy-docs/frontend/model-resource-internals-deep-dive.md +238 -0
- package/cabloy-docs/frontend/model-resource-owner-pattern.md +402 -0
- package/cabloy-docs/frontend/model-resource-usage-guide.md +334 -0
- package/cabloy-docs/frontend/model-state-guide.md +371 -15
- package/cabloy-docs/frontend/module-scope.md +8 -8
- package/cabloy-docs/frontend/modules-and-suites.md +2 -1
- package/cabloy-docs/frontend/navigation-guards-guide.md +7 -0
- package/cabloy-docs/frontend/openapi-sdk-guide.md +17 -6
- package/cabloy-docs/frontend/page-guide.md +15 -9
- package/cabloy-docs/frontend/page-meta-guide.md +466 -0
- package/cabloy-docs/frontend/page-params-guide.md +3 -3
- package/cabloy-docs/frontend/page-query-guide.md +2 -2
- package/cabloy-docs/frontend/page-route-guide.md +6 -0
- package/cabloy-docs/frontend/permission-formscene-action-visibility-guide.md +263 -0
- package/cabloy-docs/frontend/quickstart.md +18 -2
- package/cabloy-docs/frontend/reading-zova-for-vue-developers.md +266 -0
- package/cabloy-docs/frontend/resource-entry-page-deep-dive.md +271 -0
- package/cabloy-docs/frontend/resource-list-page-deep-dive.md +279 -0
- package/cabloy-docs/frontend/rest-resource-source-reading-map.md +522 -0
- package/cabloy-docs/frontend/rest-resource-under-the-hood.md +622 -0
- package/cabloy-docs/frontend/root-behaviors-guide.md +282 -0
- package/cabloy-docs/frontend/route-alias-guide.md +6 -0
- package/cabloy-docs/frontend/router-stack-guide.md +229 -0
- package/cabloy-docs/frontend/router-tabs-introduction.md +26 -3
- package/cabloy-docs/frontend/router-tabs-layout-integration.md +367 -0
- package/cabloy-docs/frontend/router-tabs-mechanism.md +6 -0
- package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +7 -0
- package/cabloy-docs/frontend/router-tabs-vs-stack.md +167 -0
- package/cabloy-docs/frontend/router-view-hosts-guide.md +450 -0
- package/cabloy-docs/frontend/server-data.md +4 -1
- package/cabloy-docs/frontend/system-startup-guide.md +2 -2
- package/cabloy-docs/frontend/table-action-visibility-permission-flow-guide.md +263 -0
- package/cabloy-docs/frontend/table-cell-cookbook.md +568 -0
- package/cabloy-docs/frontend/table-guide.md +373 -0
- package/cabloy-docs/frontend/table-resource-crud-cookbook.md +496 -0
- package/cabloy-docs/frontend/zova-app-guide.md +251 -0
- package/cabloy-docs/frontend/zova-form-source-reading-map.md +293 -0
- package/cabloy-docs/frontend/zova-form-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-reactivity-under-the-hood.md +320 -0
- package/cabloy-docs/frontend/zova-router-under-the-hood.md +561 -0
- package/cabloy-docs/frontend/zova-source-reading-map.md +421 -0
- package/cabloy-docs/frontend/zova-table-controller-render-supplement.md +225 -0
- package/cabloy-docs/frontend/zova-table-source-reading-map.md +317 -0
- package/cabloy-docs/frontend/zova-table-under-the-hood.md +532 -0
- package/cabloy-docs/frontend/zova-vs-vue3-comparison.md +308 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-debug-checklist.md +245 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-source-reading-map.md +139 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions-verify-playbook.md +248 -0
- package/cabloy-docs/fullstack/backend-metadata-to-frontend-table-actions.md +511 -0
- package/cabloy-docs/fullstack/contract-loop-playbook.md +356 -0
- package/cabloy-docs/fullstack/edition-collaboration-differences.md +6 -0
- package/cabloy-docs/fullstack/frontend-metadata-to-backend.md +199 -23
- package/cabloy-docs/fullstack/introduction.md +15 -1
- package/cabloy-docs/fullstack/openapi-to-sdk.md +135 -11
- package/cabloy-docs/fullstack/suites-and-modules.md +333 -0
- package/cabloy-docs/fullstack/tutorial-1-first-module.md +3 -0
- package/cabloy-docs/fullstack/tutorial-2-first-crud.md +4 -0
- package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +6 -2
- package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +60 -23
- package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +14 -7
- package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +6 -0
- package/cabloy-docs/fullstack/tutorials-overview.md +17 -4
- package/cabloy-docs/reference/bean-scene-boilerplates.md +15 -13
- package/cabloy-docs/reference/package-map.md +4 -3
- package/package.json +2 -1
- package/scripts/init.ts +2 -18
- package/scripts/initTestData.ts +25 -0
- package/scripts/upgrade.ts +17 -2
- package/vona/pnpm-lock.yaml +48 -194
- package/vona/src/suite/a-training/modules/training-student/package.json +53 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +400 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +18 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.index.ts +12 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +21 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/ssrMenu.student.ts +29 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +15 -0
- package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +74 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectReq.tsx +44 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectRes.tsx +11 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +45 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +42 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +28 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +25 -0
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +84 -0
- package/vona/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +10 -0
- package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +57 -0
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +173 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.build.json +11 -0
- package/vona/src/suite/a-training/modules/training-student/tsconfig.json +7 -0
- package/vona/src/suite/a-training/package.json +12 -0
- package/vona/src/suite/a-training/tsconfig.base.json +4 -0
- package/vona/src/suite/a-training/tsconfig.json +10 -0
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/module/openapi.config.ts +6 -1
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +34 -4
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +416 -690
- package/zova/src/suite/a-training/modules/training-student/cli/openapi.config.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/package.json +52 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/component/formFieldLevel.ts +31 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/index.ts +258 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/locales.ts +7 -0
- package/zova/src/suite/a-training/modules/training-student/src/.metadata/this.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/index.ts +3 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +196 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +4146 -0
- package/zova/src/suite/a-training/modules/training-student/src/api/trainingStudent.ts +151 -0
- package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +43 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionDeleteForce.tsx +51 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +56 -0
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.level.tsx +63 -0
- package/zova/src/suite/a-training/modules/training-student/src/component/formFieldLevel/controller.tsx +117 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +9 -0
- package/zova/src/suite/a-training/modules/training-student/src/index.ts +2 -0
- package/zova/src/suite/a-training/modules/training-student/src/model/student.ts +42 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.build.json +13 -0
- package/zova/src/suite/a-training/modules/training-student/tsconfig.json +5 -0
- package/zova/src/suite/a-training/package.json +12 -0
- package/zova/src/suite/a-training/tsconfig.base.json +4 -0
- package/zova/src/suite/a-training/tsconfig.json +4 -0
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +29 -7
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/select/controller.tsx +34 -11
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +3 -3
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/lib/tableCell.ts +1 -1
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
# Backend Metadata to Frontend Table Actions
|
|
2
|
+
|
|
3
|
+
This page explains one of the most practical fullstack contract chains in Cabloy Basic:
|
|
4
|
+
|
|
5
|
+
> backend field and row metadata can drive visible frontend table actions, while frontend action resources and generated contract consumers stay aligned with that backend truth.
|
|
6
|
+
|
|
7
|
+
This page sits between the pure direction guides:
|
|
8
|
+
|
|
9
|
+
- [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk)
|
|
10
|
+
- [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
|
|
11
|
+
|
|
12
|
+
It is not only a forward-chain page and not only a reverse-chain page.
|
|
13
|
+
|
|
14
|
+
Instead, it explains one concrete business thread where both directions usually cooperate.
|
|
15
|
+
|
|
16
|
+
Use this page together with:
|
|
17
|
+
|
|
18
|
+
- [Contract Loop Playbook](/fullstack/contract-loop-playbook)
|
|
19
|
+
- [Backend OpenAPI to Frontend SDK](/fullstack/openapi-to-sdk)
|
|
20
|
+
- [Frontend Metadata Back to Backend](/fullstack/frontend-metadata-to-backend)
|
|
21
|
+
- [Table Guide](/frontend/table-guide)
|
|
22
|
+
- [TableCell Authoring Cookbook](/frontend/table-cell-cookbook)
|
|
23
|
+
- [Table + Resource CRUD Cookbook](/frontend/table-resource-crud-cookbook)
|
|
24
|
+
- [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing)
|
|
25
|
+
- [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing)
|
|
26
|
+
- [Backend Metadata to Frontend Table Actions Verify Playbook](/fullstack/backend-metadata-to-frontend-table-actions-verify-playbook)
|
|
27
|
+
- [Backend Metadata to Frontend Table Actions Debug Checklist](/fullstack/backend-metadata-to-frontend-table-actions-debug-checklist)
|
|
28
|
+
- [Backend Metadata to Frontend Table Actions Source Reading Map](/fullstack/backend-metadata-to-frontend-table-actions-source-reading-map)
|
|
29
|
+
|
|
30
|
+
## Why this page exists
|
|
31
|
+
|
|
32
|
+
Several Cabloy docs already explain parts of this story:
|
|
33
|
+
|
|
34
|
+
- backend field contracts
|
|
35
|
+
- OpenAPI generation
|
|
36
|
+
- frontend metadata sharing
|
|
37
|
+
- custom table-cell authoring
|
|
38
|
+
- resource-driven CRUD pages
|
|
39
|
+
|
|
40
|
+
What contributors and AI workflows often still want is one continuous answer to this narrower question:
|
|
41
|
+
|
|
42
|
+
> how does one row action or one table-cell decision travel from backend metadata to a visible frontend list page?
|
|
43
|
+
|
|
44
|
+
This page answers that question by treating table actions as one complete contract chain rather than as disconnected snippets.
|
|
45
|
+
|
|
46
|
+
## The shortest correct mental model
|
|
47
|
+
|
|
48
|
+
If you only remember one idea, remember this one:
|
|
49
|
+
|
|
50
|
+
> in Cabloy Basic, a visible frontend table action usually belongs to a larger contract chain: backend metadata chooses the action resource identity, frontend runtime resolves that resource, and generated API/model layers keep the action semantics aligned with the backend contract.
|
|
51
|
+
|
|
52
|
+
That means the visible button or link in a table row is often only the last step of the chain, not the first.
|
|
53
|
+
|
|
54
|
+
## The main chain in one view
|
|
55
|
+
|
|
56
|
+
A practical row-action chain often looks like this:
|
|
57
|
+
|
|
58
|
+
1. backend resource entity or row DTO defines field or row-action metadata
|
|
59
|
+
2. that metadata uses `ZovaRender.cell(...)`, `ZovaRender.tableActionRow(...)`, `ZovaRender.tableActionBulk(...)`, or `ZovaRender.block(...)`
|
|
60
|
+
3. frontend resource/page runtime consumes the generated schema or DTO-backed block metadata
|
|
61
|
+
4. `basic-page:blockPage` and `basic-page:blockTable` feed row schema and data into `ZTable`
|
|
62
|
+
5. the `a-table` runtime resolves the referenced `tableCell` resource
|
|
63
|
+
6. the `tableCell` bean renders the visible action and may delegate to commands or model methods
|
|
64
|
+
7. if the action uses custom backend endpoints, frontend generated API and thin model facades keep the action semantics aligned with backend truth
|
|
65
|
+
|
|
66
|
+
That is the chain this page makes explicit.
|
|
67
|
+
|
|
68
|
+
## Two common categories of table action work
|
|
69
|
+
|
|
70
|
+
Before diving into files, separate two cases.
|
|
71
|
+
|
|
72
|
+
### Case A: metadata-only or built-in action path
|
|
73
|
+
|
|
74
|
+
Use this mental model when:
|
|
75
|
+
|
|
76
|
+
- built-in actions are enough
|
|
77
|
+
- row actions such as view/update/delete/create already exist
|
|
78
|
+
- the backend mainly needs to point to existing frontend resources
|
|
79
|
+
|
|
80
|
+
Representative examples include:
|
|
81
|
+
|
|
82
|
+
- `basic-table:actionView`
|
|
83
|
+
- `basic-table:actionUpdate`
|
|
84
|
+
- `basic-table:actionDelete`
|
|
85
|
+
- `basic-table:actionCreate`
|
|
86
|
+
- `basic-table:actionOperationsRow`
|
|
87
|
+
|
|
88
|
+
In this case, the main work is usually on the reverse-sharing side:
|
|
89
|
+
|
|
90
|
+
- backend metadata chooses frontend resource identities
|
|
91
|
+
- frontend runtime consumes them
|
|
92
|
+
|
|
93
|
+
### Case B: custom action path with backend contract changes
|
|
94
|
+
|
|
95
|
+
Use this mental model when:
|
|
96
|
+
|
|
97
|
+
- the row action corresponds to a new backend endpoint such as `summary/:id` or `deleteForce/:id`
|
|
98
|
+
- frontend should consume a newly generated API surface
|
|
99
|
+
- the same resource-owner model should stay the semantic owner
|
|
100
|
+
|
|
101
|
+
In this case, both directions cooperate:
|
|
102
|
+
|
|
103
|
+
- **forward chain**: backend controller/DTO changes generate frontend API consumers
|
|
104
|
+
- **reverse chain**: backend metadata points to frontend action resources that expose those new actions in the list page
|
|
105
|
+
|
|
106
|
+
This is the most practical reason to keep the forward and reverse chains conceptually separate but operationally connected.
|
|
107
|
+
|
|
108
|
+
## Step 1: Backend metadata chooses the visible action resource identity
|
|
109
|
+
|
|
110
|
+
The first source of truth for table action visibility often lives in backend field or row DTO metadata.
|
|
111
|
+
|
|
112
|
+
Representative entity-level field example:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
@Api.field(
|
|
116
|
+
v.title($locale('Name')),
|
|
117
|
+
v.min(3, $locale('ZodErrorStringMin')),
|
|
118
|
+
v.required(),
|
|
119
|
+
ZovaRender.order(1),
|
|
120
|
+
ZovaRender.cell('basic-table:actionView'),
|
|
121
|
+
)
|
|
122
|
+
name: string;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Representative row-action-column example:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
@Api.field(
|
|
129
|
+
v.title($locale('Operations')),
|
|
130
|
+
ZovaRender.order(1, 'max'),
|
|
131
|
+
ZovaRender.cell('basic-table:actionOperationsRow', {
|
|
132
|
+
actions: [
|
|
133
|
+
ZovaRender.tableActionRow('basic-table:actionUpdate'),
|
|
134
|
+
ZovaRender.tableActionRow('basic-table:actionDelete'),
|
|
135
|
+
],
|
|
136
|
+
}),
|
|
137
|
+
)
|
|
138
|
+
_operationsRow?: unknown;
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This is one of the most important fullstack facts about list pages.
|
|
142
|
+
|
|
143
|
+
The backend contract is not trying to render the button itself. It is choosing the frontend resource identity that should render the button.
|
|
144
|
+
|
|
145
|
+
A practical reading takeaway is:
|
|
146
|
+
|
|
147
|
+
- **the backend owns the action contract surface**
|
|
148
|
+
- **the frontend owns the action implementation**
|
|
149
|
+
- **metadata is the bridge**
|
|
150
|
+
|
|
151
|
+
## Step 2: Block metadata composes the list page around those actions
|
|
152
|
+
|
|
153
|
+
Table actions do not live in isolation. They appear inside a resource-page block composition.
|
|
154
|
+
|
|
155
|
+
Representative shape:
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
ZovaRender.block('basic-page:blockPage', {
|
|
159
|
+
blocks: [
|
|
160
|
+
ZovaRender.block('basic-page:blockFilter'),
|
|
161
|
+
ZovaRender.block('basic-page:blockToolbarBulk', {
|
|
162
|
+
actions: [ZovaRender.tableActionBulk('basic-table:actionCreate')],
|
|
163
|
+
}),
|
|
164
|
+
ZovaRender.block('basic-page:blockTable'),
|
|
165
|
+
ZovaRender.block('basic-page:blockPager'),
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
That means the row-action chain usually sits inside a larger page contract chain:
|
|
171
|
+
|
|
172
|
+
- block composition decides the page shape
|
|
173
|
+
- row or field metadata decides the cell/action resources
|
|
174
|
+
- frontend blocks and table runtime consume both surfaces together
|
|
175
|
+
|
|
176
|
+
## Step 3: `ModelResource` becomes the stable frontend resource owner
|
|
177
|
+
|
|
178
|
+
On the frontend side, the standard list runtime begins with the resource-owner model:
|
|
179
|
+
|
|
180
|
+
- `rest-resource.model.resource`
|
|
181
|
+
|
|
182
|
+
Its responsibilities include:
|
|
183
|
+
|
|
184
|
+
- resource bootstrap
|
|
185
|
+
- permissions
|
|
186
|
+
- `schemaFilter`
|
|
187
|
+
- `schemaRow`
|
|
188
|
+
- list query state
|
|
189
|
+
- item query state
|
|
190
|
+
- mutation ownership
|
|
191
|
+
|
|
192
|
+
This matters because the page runtime is not expected to rediscover resource contracts ad hoc.
|
|
193
|
+
|
|
194
|
+
A practical reading takeaway is:
|
|
195
|
+
|
|
196
|
+
- **pages consume resource semantics**
|
|
197
|
+
- **the model owns query and mutation semantics**
|
|
198
|
+
|
|
199
|
+
When a custom row action still belongs to the same business resource, keep that action inside the existing resource-owner story instead of inventing a competing owner.
|
|
200
|
+
|
|
201
|
+
## Step 4: `basic-page` feeds the row schema into `ZTable`
|
|
202
|
+
|
|
203
|
+
On a standard CRUD list page:
|
|
204
|
+
|
|
205
|
+
- `basic-page:blockPage` owns the resource state
|
|
206
|
+
- `basic-page:blockTable` passes `data`, `schemaRow`, and `tableScope` into `ZTable`
|
|
207
|
+
|
|
208
|
+
That means the backend metadata chain becomes visible in the table only after this resource-page handoff:
|
|
209
|
+
|
|
210
|
+
1. backend row schema / row DTO metadata exists
|
|
211
|
+
2. `ModelResource` exposes the row schema
|
|
212
|
+
3. `blockPage` exposes that schema to the page runtime
|
|
213
|
+
4. `blockTable` passes it into `ZTable`
|
|
214
|
+
5. `a-table` resolves the cell render resources from table-scene schema metadata
|
|
215
|
+
|
|
216
|
+
A practical rule is:
|
|
217
|
+
|
|
218
|
+
- if the action metadata looks right but the page still does not show it, inspect the page-block handoff before changing the cell bean itself
|
|
219
|
+
|
|
220
|
+
## Step 5: `a-table` resolves the referenced `tableCell` resources
|
|
221
|
+
|
|
222
|
+
Inside the table runtime, `ControllerTable` resolves the `render` metadata into a real render provider.
|
|
223
|
+
|
|
224
|
+
Important behaviors include:
|
|
225
|
+
|
|
226
|
+
- no render -> text fallback
|
|
227
|
+
- onion-like render string -> resolve through the `tableCell` scene
|
|
228
|
+
- `tableCell` bean options merge with column props
|
|
229
|
+
- `checkVisible(...)` can filter a render before the column/cell is shown
|
|
230
|
+
|
|
231
|
+
This is why `ZovaRender.cell('basic-table:actionView')` or `ZovaRender.cell('basic-table:actionOperationsRow', ...)` is enough on the backend side.
|
|
232
|
+
|
|
233
|
+
The frontend runtime already knows how to turn that contract identity into a real action render.
|
|
234
|
+
|
|
235
|
+
## Step 6: `tableCell` beans become the visible action implementations
|
|
236
|
+
|
|
237
|
+
Representative built-in row-action implementations include:
|
|
238
|
+
|
|
239
|
+
- `basic-table:actionView`
|
|
240
|
+
- `basic-table:actionUpdate`
|
|
241
|
+
- `basic-table:actionDelete`
|
|
242
|
+
- `basic-table:actionOperationsRow`
|
|
243
|
+
|
|
244
|
+
Their responsibilities usually stay small and focused.
|
|
245
|
+
|
|
246
|
+
### `actionView`
|
|
247
|
+
|
|
248
|
+
Typical responsibility:
|
|
249
|
+
|
|
250
|
+
- render a visible link
|
|
251
|
+
- call `$performCommand('basic-commands:view', ...)`
|
|
252
|
+
|
|
253
|
+
### `actionUpdate`
|
|
254
|
+
|
|
255
|
+
Typical responsibility:
|
|
256
|
+
|
|
257
|
+
- render an edit button
|
|
258
|
+
- call `$performCommand('basic-commands:edit', ...)`
|
|
259
|
+
|
|
260
|
+
### `actionDelete`
|
|
261
|
+
|
|
262
|
+
Typical responsibility:
|
|
263
|
+
|
|
264
|
+
- render a delete button
|
|
265
|
+
- confirm the action
|
|
266
|
+
- call `$performCommand('basic-commands:delete', ...)`
|
|
267
|
+
|
|
268
|
+
### `actionOperationsRow`
|
|
269
|
+
|
|
270
|
+
Typical responsibility:
|
|
271
|
+
|
|
272
|
+
- inspect the `actions` list
|
|
273
|
+
- filter actions by permission
|
|
274
|
+
- preload nested renders
|
|
275
|
+
- render each child action through `$$table.cellRender(...)`
|
|
276
|
+
|
|
277
|
+
A practical reading takeaway is:
|
|
278
|
+
|
|
279
|
+
- **single-action cells adapt render interaction to commands**
|
|
280
|
+
- **operations-row cells orchestrate several action resources together**
|
|
281
|
+
|
|
282
|
+
For deeper cell-authoring detail, continue with [TableCell Authoring Cookbook](/frontend/table-cell-cookbook).
|
|
283
|
+
|
|
284
|
+
## Step 7: Bulk actions follow the same contract idea at page level
|
|
285
|
+
|
|
286
|
+
The same mental model also appears in bulk or page-level actions.
|
|
287
|
+
|
|
288
|
+
Representative example:
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
actions: [ZovaRender.tableActionBulk('basic-table:actionCreate')];
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
And the corresponding frontend implementation can render a button that performs:
|
|
295
|
+
|
|
296
|
+
- `basic-commands:create`
|
|
297
|
+
|
|
298
|
+
This is the same contract idea at a different UI level:
|
|
299
|
+
|
|
300
|
+
- backend or shared page metadata chooses the action resource identity
|
|
301
|
+
- frontend runtime resolves that identity to a visible action implementation
|
|
302
|
+
|
|
303
|
+
## Step 8: Where the forward chain enters for custom actions
|
|
304
|
+
|
|
305
|
+
So far, everything could still be handled by built-in commands and built-in resources.
|
|
306
|
+
|
|
307
|
+
The forward chain becomes important when the action itself depends on a new backend API contract.
|
|
308
|
+
|
|
309
|
+
Representative examples include actions such as:
|
|
310
|
+
|
|
311
|
+
- `summary/:id`
|
|
312
|
+
- `deleteForce/:id`
|
|
313
|
+
|
|
314
|
+
In that case, the practical chain becomes:
|
|
315
|
+
|
|
316
|
+
1. backend controller exposes the custom endpoint
|
|
317
|
+
2. backend DTOs define request/response contracts
|
|
318
|
+
3. frontend OpenAPI generation produces typed API consumers
|
|
319
|
+
4. the frontend module model wraps those generated consumers thinly
|
|
320
|
+
5. a custom `tableCell.actionSummary.tsx` or `tableCell.actionDeleteForce.tsx` triggers the corresponding semantic action path
|
|
321
|
+
6. backend row metadata points the visible row action at that frontend resource identity
|
|
322
|
+
|
|
323
|
+
This is why Tutorial 5 is a forward-chain tutorial even though the visible result is a row action in a table.
|
|
324
|
+
|
|
325
|
+
The action semantics are forward-generated; the visible table exposure is reverse-shared.
|
|
326
|
+
|
|
327
|
+
## Step 9: Why the resource-owner model should stay the semantic owner
|
|
328
|
+
|
|
329
|
+
When a custom action still belongs to the same business resource, do not create a competing cache owner only because the action is custom.
|
|
330
|
+
|
|
331
|
+
Instead:
|
|
332
|
+
|
|
333
|
+
- generate the new frontend API contract from backend truth
|
|
334
|
+
- wrap it in the existing module model as a thin semantic facade
|
|
335
|
+
- keep invalidation and resource ownership coherent
|
|
336
|
+
|
|
337
|
+
This matters because row actions often affect:
|
|
338
|
+
|
|
339
|
+
- current row state
|
|
340
|
+
- list query invalidation
|
|
341
|
+
- related item views
|
|
342
|
+
- page refresh expectations
|
|
343
|
+
|
|
344
|
+
A practical rule is:
|
|
345
|
+
|
|
346
|
+
- if the action still belongs to the same resource, prefer extending the existing resource owner over inventing a second one
|
|
347
|
+
|
|
348
|
+
## Step 10: A practical end-to-end example matrix
|
|
349
|
+
|
|
350
|
+
Here is the most useful way to think about common action types.
|
|
351
|
+
|
|
352
|
+
### Built-in view action
|
|
353
|
+
|
|
354
|
+
Chain:
|
|
355
|
+
|
|
356
|
+
1. backend field metadata uses `ZovaRender.cell('basic-table:actionView')`
|
|
357
|
+
2. row schema reaches `ZTable`
|
|
358
|
+
3. `a-table` resolves `basic-table:actionView`
|
|
359
|
+
4. the frontend action cell performs `basic-commands:view`
|
|
360
|
+
|
|
361
|
+
This is mostly a reverse-sharing path.
|
|
362
|
+
|
|
363
|
+
### Built-in operations row
|
|
364
|
+
|
|
365
|
+
Chain:
|
|
366
|
+
|
|
367
|
+
1. backend row DTO metadata uses `ZovaRender.cell('basic-table:actionOperationsRow', { actions: [...] })`
|
|
368
|
+
2. nested row-action metadata uses `ZovaRender.tableActionRow(...)`
|
|
369
|
+
3. `actionOperationsRow` filters and renders child actions
|
|
370
|
+
4. each child action delegates to its own command-oriented cell resource
|
|
371
|
+
|
|
372
|
+
This is also mainly a reverse-sharing path.
|
|
373
|
+
|
|
374
|
+
### Custom summary action
|
|
375
|
+
|
|
376
|
+
Chain:
|
|
377
|
+
|
|
378
|
+
1. backend controller and DTOs define `summary/:id`
|
|
379
|
+
2. frontend OpenAPI generation creates the API consumer
|
|
380
|
+
3. frontend model wraps the consumer thinly
|
|
381
|
+
4. custom `tableCell.actionSummary.tsx` exposes the visible row action
|
|
382
|
+
5. backend row metadata includes that action in the operations row
|
|
383
|
+
|
|
384
|
+
This uses both forward and reverse directions.
|
|
385
|
+
|
|
386
|
+
## Step 11: How to classify the work before editing anything
|
|
387
|
+
|
|
388
|
+
Use this quick decision map.
|
|
389
|
+
|
|
390
|
+
### Mostly reverse-chain work
|
|
391
|
+
|
|
392
|
+
Use this path when:
|
|
393
|
+
|
|
394
|
+
- you are only changing which built-in or existing frontend render resource a field or row should use
|
|
395
|
+
- no new backend endpoint is needed
|
|
396
|
+
- the visible change is mostly metadata-driven
|
|
397
|
+
|
|
398
|
+
Typical examples:
|
|
399
|
+
|
|
400
|
+
- switch one field to `basic-table:actionView`
|
|
401
|
+
- add an operations row using existing update/delete actions
|
|
402
|
+
- add a custom table-cell renderer that backend metadata points to
|
|
403
|
+
|
|
404
|
+
### Mostly forward-chain work
|
|
405
|
+
|
|
406
|
+
Use this path when:
|
|
407
|
+
|
|
408
|
+
- the action semantics need a new backend endpoint or changed response contract
|
|
409
|
+
- frontend typed consumers must regenerate
|
|
410
|
+
- the row action is only the last visible step of a larger API-contract change
|
|
411
|
+
|
|
412
|
+
Typical examples:
|
|
413
|
+
|
|
414
|
+
- add summary, archive, approve, or force-delete actions with new backend contracts
|
|
415
|
+
|
|
416
|
+
### Consumer drift
|
|
417
|
+
|
|
418
|
+
Suspect this when:
|
|
419
|
+
|
|
420
|
+
- generated artifacts already contain the expected action contracts or resource keys
|
|
421
|
+
- but the visible frontend behavior still looks stale
|
|
422
|
+
|
|
423
|
+
### Local dependency drift
|
|
424
|
+
|
|
425
|
+
Suspect this when:
|
|
426
|
+
|
|
427
|
+
- generated `.zova-rest` output or SDK output looks correct
|
|
428
|
+
- but backend or frontend local consumers still do not see the refreshed shared types or resource identities
|
|
429
|
+
|
|
430
|
+
## Common mistakes to avoid
|
|
431
|
+
|
|
432
|
+
### Mistake 1: Treating the visible button as the start of the design
|
|
433
|
+
|
|
434
|
+
Usually the visible button is the end of the design. Start from the contract and metadata chain first.
|
|
435
|
+
|
|
436
|
+
### Mistake 2: Adding a custom backend endpoint but manually duplicating its frontend contract
|
|
437
|
+
|
|
438
|
+
Prefer the forward-generation path before hand-writing request code.
|
|
439
|
+
|
|
440
|
+
### Mistake 3: Creating a competing frontend state owner for an action that still belongs to the same resource
|
|
441
|
+
|
|
442
|
+
Prefer reusing the existing resource-owner model.
|
|
443
|
+
|
|
444
|
+
### Mistake 4: Patching page-local table code when metadata already expresses the action correctly
|
|
445
|
+
|
|
446
|
+
If the contract is metadata-driven, keep it metadata-driven.
|
|
447
|
+
|
|
448
|
+
### Mistake 5: Mixing up built-in action resources and custom action semantics
|
|
449
|
+
|
|
450
|
+
Built-in action resources often only adapt UI to commands. Custom action semantics may still need generated API and model work behind them.
|
|
451
|
+
|
|
452
|
+
## A practical authoring order
|
|
453
|
+
|
|
454
|
+
If you want the shortest path to a correct table-action implementation, use this order:
|
|
455
|
+
|
|
456
|
+
1. decide whether the work is mostly reverse-chain or forward-chain
|
|
457
|
+
2. if forward-chain, change backend controller/DTO truth first
|
|
458
|
+
3. regenerate frontend API consumers when backend contract changes
|
|
459
|
+
4. keep frontend model follow-up thin and semantic
|
|
460
|
+
5. point backend row metadata to the intended built-in or custom table-action resources
|
|
461
|
+
6. verify the resource-page block chain still feeds the right schema into `ZTable`
|
|
462
|
+
7. verify the visible row action in Admin
|
|
463
|
+
|
|
464
|
+
## Verification checklist
|
|
465
|
+
|
|
466
|
+
When documenting or implementing this chain, verify in this order:
|
|
467
|
+
|
|
468
|
+
1. confirm the backend metadata anchors actually point to the intended `ZovaRender.*(...)` resources
|
|
469
|
+
2. confirm the page block composition still includes the intended list blocks
|
|
470
|
+
3. confirm the current frontend `tableCell` resources exist and match the named identities
|
|
471
|
+
4. if custom backend actions were added, regenerate the frontend contract surface first
|
|
472
|
+
5. make sure the local dev workflow is running:
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
npm run dev
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
6. open `http://localhost:7102/admin/`
|
|
479
|
+
7. verify the visible list page behavior:
|
|
480
|
+
- bulk create action if relevant
|
|
481
|
+
- row operations visibility
|
|
482
|
+
- row action execution
|
|
483
|
+
- list invalidation or refresh after mutations
|
|
484
|
+
8. if reverse-chain frontend resources changed, run the representative Basic handoff flow when needed:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
npm run zova :tools:metadata <module-name>
|
|
488
|
+
npm run build:zova:admin
|
|
489
|
+
npm run deps:vona
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
9. if docs changed, build the docs site:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
npm run docs:build
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Final takeaway
|
|
499
|
+
|
|
500
|
+
A frontend table action in Cabloy Basic is often not just a frontend button.
|
|
501
|
+
|
|
502
|
+
It is the visible result of a contract chain that may include:
|
|
503
|
+
|
|
504
|
+
- backend field or row metadata
|
|
505
|
+
- page block composition metadata
|
|
506
|
+
- generated frontend contract consumers
|
|
507
|
+
- resource-owner model semantics
|
|
508
|
+
- `tableCell` bean-scene resources
|
|
509
|
+
- `basic-page` list runtime
|
|
510
|
+
|
|
511
|
+
Once you read the system through that chain, row actions stop looking like scattered UI details and start looking like one coherent fullstack workflow.
|