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,496 @@
|
|
|
1
|
+
# Table + Resource CRUD Cookbook
|
|
2
|
+
|
|
3
|
+
This cookbook explains how Zova Table fits into Cabloy Basic’s resource-driven CRUD list pages.
|
|
4
|
+
|
|
5
|
+
Use this page when your next question is practical rather than framework-neutral:
|
|
6
|
+
|
|
7
|
+
- how should I assemble a standard resource list page?
|
|
8
|
+
- where do filter, toolbar, table, and pager blocks come from?
|
|
9
|
+
- how does `ModelResource` feed schema and data into `ZTable`?
|
|
10
|
+
- where should list-page customization happen without breaking the existing runtime?
|
|
11
|
+
|
|
12
|
+
Use this page together with:
|
|
13
|
+
|
|
14
|
+
- [Table Guide](/frontend/table-guide)
|
|
15
|
+
- [TableCell Authoring Cookbook](/frontend/table-cell-cookbook)
|
|
16
|
+
- [Zova Table Under the Hood](/frontend/zova-table-under-the-hood)
|
|
17
|
+
- [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern)
|
|
18
|
+
- [Rest Resource Under the Hood](/frontend/rest-resource-under-the-hood)
|
|
19
|
+
- [Rest Resource Source Reading Map](/frontend/rest-resource-source-reading-map)
|
|
20
|
+
- [Backend Metadata to Frontend Table Actions](/fullstack/backend-metadata-to-frontend-table-actions)
|
|
21
|
+
- [Tutorial 2: Create Your First CRUD](/fullstack/tutorial-2-first-crud)
|
|
22
|
+
- [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing)
|
|
23
|
+
- [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing)
|
|
24
|
+
|
|
25
|
+
## What this cookbook is for
|
|
26
|
+
|
|
27
|
+
If your next question is how the resource list page runtime is assembled under the hood, continue with [Resource List Page Deep Dive](/frontend/resource-list-page-deep-dive). If your next question is why row or bulk actions are visible or hidden, continue with [Table Action Visibility and Permission Flow Guide](/frontend/table-action-visibility-permission-flow-guide).
|
|
28
|
+
|
|
29
|
+
A Cabloy Basic CRUD list page is usually not authored as:
|
|
30
|
+
|
|
31
|
+
- one page-local table component
|
|
32
|
+
- one page-local fetch call
|
|
33
|
+
- one page-local pager state
|
|
34
|
+
- one page-local filter form
|
|
35
|
+
|
|
36
|
+
The more typical Zova-native shape is:
|
|
37
|
+
|
|
38
|
+
- one resource-owner model
|
|
39
|
+
- one page block that owns query and permissions
|
|
40
|
+
- several reusable blocks for filter, bulk toolbar, table, and pager
|
|
41
|
+
- schema and metadata driving the visible UI
|
|
42
|
+
|
|
43
|
+
That means the practical CRUD question becomes less:
|
|
44
|
+
|
|
45
|
+
- “how do I hand-build one list page?”
|
|
46
|
+
|
|
47
|
+
and more:
|
|
48
|
+
|
|
49
|
+
- “how do I plug my resource into the existing resource-page runtime?”
|
|
50
|
+
|
|
51
|
+
## The shortest correct mental model
|
|
52
|
+
|
|
53
|
+
If you only remember one idea, remember this one:
|
|
54
|
+
|
|
55
|
+
> In Cabloy Basic CRUD list pages, `ZTable` is usually one block inside a larger resource-page runtime owned by `basic-page:blockPage` and backed by `ModelResource`.
|
|
56
|
+
|
|
57
|
+
That larger runtime usually owns:
|
|
58
|
+
|
|
59
|
+
- resource bootstrap
|
|
60
|
+
- list query state
|
|
61
|
+
- filter state
|
|
62
|
+
- permissions
|
|
63
|
+
- row schema
|
|
64
|
+
- paged response state
|
|
65
|
+
- coordination among filter, table, and pager
|
|
66
|
+
|
|
67
|
+
## One running example through this guide: Student list page
|
|
68
|
+
|
|
69
|
+
To keep the guide concrete, the examples below all use the same teaching thread:
|
|
70
|
+
|
|
71
|
+
- resource: `training-student:student`
|
|
72
|
+
- list-page concerns: filter, row actions, create action, pagination
|
|
73
|
+
- metadata sources: backend row DTO and row-action metadata
|
|
74
|
+
|
|
75
|
+
This is the same general shape already used in the built-in specimen:
|
|
76
|
+
|
|
77
|
+
- `vona/src/suite-vendor/a-test/modules/test-rest/src/dto/productSelectResItem.tsx`
|
|
78
|
+
|
|
79
|
+
## Step 1: Start from the generated CRUD contract, not from page-local UI
|
|
80
|
+
|
|
81
|
+
For a standard CRUD list page, begin with the generated backend thread.
|
|
82
|
+
|
|
83
|
+
The first useful entrypoint is still the CRUD generator:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm run vona :tools:crud student -- --module=training-student
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
That generated thread already gives you the important contract anchors such as:
|
|
90
|
+
|
|
91
|
+
- backend entity
|
|
92
|
+
- select request DTO
|
|
93
|
+
- select response DTO
|
|
94
|
+
- select row-item DTO
|
|
95
|
+
|
|
96
|
+
A practical rule is:
|
|
97
|
+
|
|
98
|
+
- treat the generated resource contract as the list-page foundation
|
|
99
|
+
- refine schema and metadata before hand-building frontend list code
|
|
100
|
+
|
|
101
|
+
For the first generated CRUD walkthrough, see [Tutorial 2: Create Your First CRUD](/fullstack/tutorial-2-first-crud).
|
|
102
|
+
|
|
103
|
+
## Step 2: Understand the block chain for a standard list page
|
|
104
|
+
|
|
105
|
+
A standard resource list page is usually declared through backend-owned block metadata like this:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
ZovaRender.block('basic-page:blockPage', {
|
|
109
|
+
blocks: [
|
|
110
|
+
ZovaRender.block('basic-page:blockFilter'),
|
|
111
|
+
ZovaRender.block('basic-page:blockToolbarBulk', {
|
|
112
|
+
actions: [ZovaRender.tableActionBulk('basic-table:actionCreate')],
|
|
113
|
+
}),
|
|
114
|
+
ZovaRender.block('basic-page:blockTable'),
|
|
115
|
+
ZovaRender.block('basic-page:blockPager'),
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
That declaration is important because it shows the intended authoring direction clearly:
|
|
121
|
+
|
|
122
|
+
- backend or shared contract metadata chooses the block composition
|
|
123
|
+
- frontend block implementations provide the runtime behavior
|
|
124
|
+
- the page is assembled from existing building blocks rather than from ad hoc local wiring
|
|
125
|
+
|
|
126
|
+
A practical reading takeaway is:
|
|
127
|
+
|
|
128
|
+
- **the block list is the public page composition surface**
|
|
129
|
+
- **the frontend block controllers are the runtime owners**
|
|
130
|
+
|
|
131
|
+
## Step 3: Know what `basic-page:blockPage` owns
|
|
132
|
+
|
|
133
|
+
The main runtime owner for a resource list page is:
|
|
134
|
+
|
|
135
|
+
- `basic-page:blockPage`
|
|
136
|
+
|
|
137
|
+
Its controller is responsible for:
|
|
138
|
+
|
|
139
|
+
- resolving the `ModelResource` selector for the current resource
|
|
140
|
+
- preparing page-level JSX/CEL support
|
|
141
|
+
- creating query state
|
|
142
|
+
- loading schema and paged data
|
|
143
|
+
- exposing `data`, `schemaRow`, `schemaFilter`, `permissions`, and `paged`
|
|
144
|
+
- refreshing table metadata when permissions change
|
|
145
|
+
|
|
146
|
+
This is one of the most important architecture facts about CRUD pages.
|
|
147
|
+
|
|
148
|
+
The page block does not only render layout. It owns the list-page resource state.
|
|
149
|
+
|
|
150
|
+
A practical rule is:
|
|
151
|
+
|
|
152
|
+
- if the concern is about resource query, schema, or permissions, start debugging in `blockPage`
|
|
153
|
+
- if the concern is about one visual block, continue to the corresponding block controller next
|
|
154
|
+
|
|
155
|
+
## Step 4: Let `blockFilter` own filter-form behavior
|
|
156
|
+
|
|
157
|
+
The standard filter block is:
|
|
158
|
+
|
|
159
|
+
- `basic-page:blockFilter`
|
|
160
|
+
|
|
161
|
+
This block uses `ZForm` with:
|
|
162
|
+
|
|
163
|
+
- `schema={$$page.schemaFilter}`
|
|
164
|
+
- `schemaScene="filter"`
|
|
165
|
+
- inline layout
|
|
166
|
+
- page-owned filter data
|
|
167
|
+
|
|
168
|
+
Its job is not to duplicate the list query logic.
|
|
169
|
+
|
|
170
|
+
Its job is to:
|
|
171
|
+
|
|
172
|
+
- render the filter form from resource filter schema
|
|
173
|
+
- normalize submitted filter data
|
|
174
|
+
- call `$$page.onFilter(...)`
|
|
175
|
+
|
|
176
|
+
A practical rule is:
|
|
177
|
+
|
|
178
|
+
- if you need to refine which filter fields exist, start from backend filter-side metadata and schema
|
|
179
|
+
- if you need to refine how filter submission affects the list, inspect `blockFilter` and `blockPage.onFilter(...)`
|
|
180
|
+
|
|
181
|
+
## Step 5: Let `blockToolbarBulk` own bulk-action display
|
|
182
|
+
|
|
183
|
+
The standard bulk toolbar block is:
|
|
184
|
+
|
|
185
|
+
- `basic-page:blockToolbarBulk`
|
|
186
|
+
|
|
187
|
+
This block is intentionally thin.
|
|
188
|
+
|
|
189
|
+
Its main job is to:
|
|
190
|
+
|
|
191
|
+
- inspect the configured bulk actions
|
|
192
|
+
- filter them by permission
|
|
193
|
+
- render each action through the page JSX runtime
|
|
194
|
+
|
|
195
|
+
That means the toolbar block usually should not become a second action-semantics layer.
|
|
196
|
+
|
|
197
|
+
A practical rule is:
|
|
198
|
+
|
|
199
|
+
- if the page only needs standard create or other bulk actions, keep the existing block and adjust the metadata
|
|
200
|
+
- if an action is reusable, prefer a reusable action render resource rather than page-local ad hoc code
|
|
201
|
+
|
|
202
|
+
## Step 6: Let `blockTable` bridge page state into `ZTable`
|
|
203
|
+
|
|
204
|
+
The standard table block is:
|
|
205
|
+
|
|
206
|
+
- `basic-page:blockTable`
|
|
207
|
+
|
|
208
|
+
Its bridge role is very clear:
|
|
209
|
+
|
|
210
|
+
- render `ZTable`
|
|
211
|
+
- pass page data into `data`
|
|
212
|
+
- pass row schema into `schema`
|
|
213
|
+
- pass page CEL scope into `tableScope`
|
|
214
|
+
- capture the table controller through `controllerRef`
|
|
215
|
+
|
|
216
|
+
That means `blockTable` does not own list fetching or pagination logic.
|
|
217
|
+
|
|
218
|
+
It owns the handoff from page resource state to the reusable table runtime.
|
|
219
|
+
|
|
220
|
+
A practical rule is:
|
|
221
|
+
|
|
222
|
+
- if the table shows the wrong rows or wrong schema, inspect `blockPage` first
|
|
223
|
+
- if the handoff from page to table looks wrong, inspect `blockTable`
|
|
224
|
+
- if one column or cell renders incorrectly, continue into `a-table` and `tableCell` logic
|
|
225
|
+
|
|
226
|
+
## Step 7: Let `blockPager` own page navigation UI
|
|
227
|
+
|
|
228
|
+
The standard pager block is:
|
|
229
|
+
|
|
230
|
+
- `basic-page:blockPager`
|
|
231
|
+
|
|
232
|
+
This block reads the paged response from `$$page.paged` and renders:
|
|
233
|
+
|
|
234
|
+
- total items
|
|
235
|
+
- total pages
|
|
236
|
+
- previous-page button
|
|
237
|
+
- current page indicator
|
|
238
|
+
- next-page button
|
|
239
|
+
|
|
240
|
+
It delegates actual page movement back to the page block through `gotoPage(...)`.
|
|
241
|
+
|
|
242
|
+
That means the pager block owns the visible pager UI, while the page block still owns pagination state.
|
|
243
|
+
|
|
244
|
+
A practical rule is:
|
|
245
|
+
|
|
246
|
+
- if the pager UI looks wrong, inspect `blockPager`
|
|
247
|
+
- if paging requests or totals are wrong, inspect `blockPage` and the resource model/query side
|
|
248
|
+
|
|
249
|
+
## Step 8: Know where the table columns and row actions really come from
|
|
250
|
+
|
|
251
|
+
In a standard CRUD list page, the table contents are usually not first defined in the block controller.
|
|
252
|
+
|
|
253
|
+
They come from the backend resource contract, especially row DTO metadata.
|
|
254
|
+
|
|
255
|
+
A representative example is:
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
@Api.field(
|
|
259
|
+
v.title($locale('Operations')),
|
|
260
|
+
ZovaRender.order(1, 'max'),
|
|
261
|
+
ZovaRender.cell('basic-table:actionOperationsRow', {
|
|
262
|
+
actions: [
|
|
263
|
+
ZovaRender.tableActionRow('basic-table:actionUpdate'),
|
|
264
|
+
ZovaRender.tableActionRow('basic-table:actionDelete'),
|
|
265
|
+
],
|
|
266
|
+
}),
|
|
267
|
+
)
|
|
268
|
+
_operationsRow?: unknown;
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
This is the practical reverse-sharing model:
|
|
272
|
+
|
|
273
|
+
- the backend row contract chooses the table cell resource identity
|
|
274
|
+
- the frontend table runtime resolves that resource
|
|
275
|
+
- the page block and table block do not need page-local hard-coded row-action wiring
|
|
276
|
+
|
|
277
|
+
For the built-in metadata-sharing teaching path, see [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing).
|
|
278
|
+
|
|
279
|
+
For the forward-chain row-action teaching path, see [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing).
|
|
280
|
+
|
|
281
|
+
## Step 9: The common extension points
|
|
282
|
+
|
|
283
|
+
For standard CRUD list pages, most customization should happen in one of these places.
|
|
284
|
+
|
|
285
|
+
### Extension point A: backend row schema metadata
|
|
286
|
+
|
|
287
|
+
Use this when:
|
|
288
|
+
|
|
289
|
+
- a field should change order
|
|
290
|
+
- a column should be visible or hidden
|
|
291
|
+
- a field should use a different built-in or custom `tableCell`
|
|
292
|
+
|
|
293
|
+
This is usually the first and best extension point.
|
|
294
|
+
|
|
295
|
+
### Extension point B: backend block composition metadata
|
|
296
|
+
|
|
297
|
+
Use this when:
|
|
298
|
+
|
|
299
|
+
- the page should add or remove a standard block
|
|
300
|
+
- the page should include bulk actions
|
|
301
|
+
- the page should change list-page composition order
|
|
302
|
+
|
|
303
|
+
### Extension point C: custom `tableCell` resources
|
|
304
|
+
|
|
305
|
+
Use this when:
|
|
306
|
+
|
|
307
|
+
- a field needs business-specific table rendering
|
|
308
|
+
- one action cell should be reusable across pages
|
|
309
|
+
- one operations row should orchestrate several child actions
|
|
310
|
+
|
|
311
|
+
For concrete patterns, continue with [TableCell Authoring Cookbook](/frontend/table-cell-cookbook).
|
|
312
|
+
|
|
313
|
+
### Extension point D: page-level block implementation
|
|
314
|
+
|
|
315
|
+
Use this only when:
|
|
316
|
+
|
|
317
|
+
- the existing block runtime is structurally insufficient
|
|
318
|
+
- the behavior really belongs to the block runtime rather than to metadata
|
|
319
|
+
- you have already confirmed that schema, metadata, and cell resources are not enough
|
|
320
|
+
|
|
321
|
+
A practical rule is:
|
|
322
|
+
|
|
323
|
+
- prefer metadata and cell resources before changing block controllers
|
|
324
|
+
|
|
325
|
+
## Step 10: Distinguish list page from entry page
|
|
326
|
+
|
|
327
|
+
A common source-reading mistake is to mix `basic-page` list runtime with `basic-pageentry` form runtime.
|
|
328
|
+
|
|
329
|
+
They are related but they do not own the same concerns.
|
|
330
|
+
|
|
331
|
+
### `basic-page` list runtime
|
|
332
|
+
|
|
333
|
+
Typical responsibilities:
|
|
334
|
+
|
|
335
|
+
- filter form
|
|
336
|
+
- bulk toolbar
|
|
337
|
+
- table
|
|
338
|
+
- pager
|
|
339
|
+
- list query
|
|
340
|
+
- row schema and permissions
|
|
341
|
+
|
|
342
|
+
### `basic-pageentry` entry runtime
|
|
343
|
+
|
|
344
|
+
Typical responsibilities:
|
|
345
|
+
|
|
346
|
+
- view/create/edit form scene
|
|
347
|
+
- form schema and form data
|
|
348
|
+
- form submission
|
|
349
|
+
- page dirty state and page title
|
|
350
|
+
|
|
351
|
+
A practical rule is:
|
|
352
|
+
|
|
353
|
+
- if the page is about rows in a list, stay in `basic-page`
|
|
354
|
+
- if the page is about one entry form, stay in `basic-pageentry`
|
|
355
|
+
|
|
356
|
+
This distinction prevents a lot of source-reading confusion.
|
|
357
|
+
|
|
358
|
+
## Pattern 1: The standard generated CRUD list page
|
|
359
|
+
|
|
360
|
+
Use this pattern when:
|
|
361
|
+
|
|
362
|
+
- the CRUD generator already created the resource thread
|
|
363
|
+
- built-in page blocks are enough
|
|
364
|
+
- backend metadata can express the list behavior
|
|
365
|
+
|
|
366
|
+
Recommended path:
|
|
367
|
+
|
|
368
|
+
1. generate the CRUD thread
|
|
369
|
+
2. inspect row DTO metadata
|
|
370
|
+
3. keep the standard block chain
|
|
371
|
+
4. verify the list page in Admin
|
|
372
|
+
|
|
373
|
+
This should be the default choice for first CRUD pages.
|
|
374
|
+
|
|
375
|
+
## Pattern 2: Add a filter field through contract refinement
|
|
376
|
+
|
|
377
|
+
Use this pattern when:
|
|
378
|
+
|
|
379
|
+
- the list page needs one more search field
|
|
380
|
+
- the field belongs in the resource contract
|
|
381
|
+
- the filter form should stay schema-driven
|
|
382
|
+
|
|
383
|
+
Recommended path:
|
|
384
|
+
|
|
385
|
+
1. refine backend field and query DTO metadata
|
|
386
|
+
2. verify `schemaFilter`
|
|
387
|
+
3. reuse `basic-page:blockFilter`
|
|
388
|
+
4. avoid page-local manual filter UI unless really necessary
|
|
389
|
+
|
|
390
|
+
## Pattern 3: Add row actions through backend metadata
|
|
391
|
+
|
|
392
|
+
Use this pattern when:
|
|
393
|
+
|
|
394
|
+
- the row should expose update/delete/summary/deleteForce-like actions
|
|
395
|
+
- the action identity belongs in the contract
|
|
396
|
+
- the frontend should reuse `tableCell` resources
|
|
397
|
+
|
|
398
|
+
Recommended path:
|
|
399
|
+
|
|
400
|
+
1. define or refine backend row-action metadata
|
|
401
|
+
2. point the action cell to built-in or custom table-cell resources
|
|
402
|
+
3. if needed, add generated API and thin model helpers
|
|
403
|
+
4. verify the list page row actions in Admin
|
|
404
|
+
|
|
405
|
+
## Pattern 4: Add a business-specific cell for one field
|
|
406
|
+
|
|
407
|
+
Use this pattern when:
|
|
408
|
+
|
|
409
|
+
- one field such as `level`, `status`, or `score` needs module-owned UI behavior
|
|
410
|
+
- the list page should remain resource-driven overall
|
|
411
|
+
|
|
412
|
+
Recommended path:
|
|
413
|
+
|
|
414
|
+
1. create a custom `tableCell` bean
|
|
415
|
+
2. point backend field metadata to it
|
|
416
|
+
3. keep `basic-page:blockTable` and `ZTable` unchanged
|
|
417
|
+
|
|
418
|
+
This is the preferred path when the customization belongs to a field rather than to page structure.
|
|
419
|
+
|
|
420
|
+
## Common mistakes to avoid
|
|
421
|
+
|
|
422
|
+
### Mistake 1: Rebuilding list-page fetch state inside the table block
|
|
423
|
+
|
|
424
|
+
`blockTable` is only the page-to-table bridge. Query ownership lives in `blockPage` and `ModelResource`.
|
|
425
|
+
|
|
426
|
+
### Mistake 2: Hand-writing table columns before checking row schema metadata
|
|
427
|
+
|
|
428
|
+
For most CRUD pages, the row schema is the first source of truth.
|
|
429
|
+
|
|
430
|
+
### Mistake 3: Mixing list-page and entry-page concerns
|
|
431
|
+
|
|
432
|
+
`basic-page` and `basic-pageentry` are related, but they own different runtime responsibilities.
|
|
433
|
+
|
|
434
|
+
### Mistake 4: Modifying block controllers when metadata or `tableCell` resources are enough
|
|
435
|
+
|
|
436
|
+
Most business customization should happen before block-controller changes.
|
|
437
|
+
|
|
438
|
+
### Mistake 5: Treating row actions as only frontend-local UI
|
|
439
|
+
|
|
440
|
+
In Cabloy, row actions often belong to a broader contract chain involving backend metadata, generated API, model helpers, and table-cell resources.
|
|
441
|
+
|
|
442
|
+
## A practical authoring order
|
|
443
|
+
|
|
444
|
+
If you want the shortest path to a real CRUD list page, use this order:
|
|
445
|
+
|
|
446
|
+
1. generate or confirm the backend CRUD contract thread
|
|
447
|
+
2. confirm the resource-owner model already exposes the required schemas and permissions
|
|
448
|
+
3. keep the standard `blockPage -> blockFilter -> blockToolbarBulk -> blockTable -> blockPager` chain
|
|
449
|
+
4. refine backend row metadata for visible columns and row actions
|
|
450
|
+
5. reuse built-in `tableCell` resources first
|
|
451
|
+
6. add custom `tableCell` resources only where the UI becomes business-specific
|
|
452
|
+
7. change block controllers only when the existing runtime is structurally insufficient
|
|
453
|
+
8. continue with [Table Guide](/frontend/table-guide) for the public `ZTable` surface
|
|
454
|
+
9. continue with [TableCell Authoring Cookbook](/frontend/table-cell-cookbook) for custom cell patterns
|
|
455
|
+
10. continue with [Backend Metadata to Frontend Table Actions](/fullstack/backend-metadata-to-frontend-table-actions) when the visible row actions belong to a larger contract-loop chain
|
|
456
|
+
11. continue with [Zova Table Under the Hood](/frontend/zova-table-under-the-hood) when you want the controller-level runtime explanation
|
|
457
|
+
12. continue with [Zova Table Source Reading Map](/frontend/zova-table-source-reading-map) when you need targeted file-order guidance for the table runtime
|
|
458
|
+
|
|
459
|
+
## Verification checklist
|
|
460
|
+
|
|
461
|
+
When authoring or documenting a resource CRUD list page, verify in this order:
|
|
462
|
+
|
|
463
|
+
1. confirm the generated or existing backend CRUD contract files are present
|
|
464
|
+
2. confirm the block composition still matches the intended standard page chain
|
|
465
|
+
3. confirm row schema metadata points to the intended built-in or custom render resources
|
|
466
|
+
4. make sure the local dev workflow is running:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
npm run dev
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
5. open `http://localhost:7102/admin/`
|
|
473
|
+
6. enter the target list page and verify:
|
|
474
|
+
- filter works
|
|
475
|
+
- bulk actions render correctly
|
|
476
|
+
- table columns and row actions match metadata
|
|
477
|
+
- pager updates the list correctly
|
|
478
|
+
7. if you changed docs, build the docs site:
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
npm run docs:build
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## Final takeaway
|
|
485
|
+
|
|
486
|
+
A good Cabloy Basic CRUD list page is usually not a custom page-local table stack.
|
|
487
|
+
|
|
488
|
+
It is a resource-driven composition of:
|
|
489
|
+
|
|
490
|
+
- one resource-owner model
|
|
491
|
+
- one page block
|
|
492
|
+
- one schema-driven table runtime
|
|
493
|
+
- several reusable page blocks
|
|
494
|
+
- optional custom `tableCell` resources
|
|
495
|
+
|
|
496
|
+
That is the path that keeps CRUD list pages consistent, extensible, and aligned with the Zova-native architecture.
|