cabloy 5.1.158 → 5.1.160
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/.cabloy-version +1 -1
- package/.claude/skills/cabloy-contract-loop/SKILL.md +24 -7
- package/.claude/skills/cabloy-contract-loop/evals/evals.json +12 -0
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +28 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +19 -2
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +18 -0
- package/.claude/skills/cabloy-zova-source-reading/SKILL.md +14 -0
- package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +10 -0
- package/.github/workflows/docs-pages.yml +18 -2
- package/CHANGELOG.md +31 -0
- package/package.json +2 -1
- package/repo-docs/.vitepress/config.mjs +45 -4
- package/repo-docs/.vitepress/theme/components/GitHubRepositoriesNav.vue +255 -0
- package/repo-docs/.vitepress/theme/custom.css +21 -0
- package/repo-docs/.vitepress/theme/index.js +7 -1
- package/repo-docs/backend/department-management.md +98 -0
- package/repo-docs/backend/menu-authorization.md +124 -0
- package/repo-docs/backend/rbac-authorization.md +117 -0
- package/repo-docs/backend/resource-field-update.md +49 -2
- package/repo-docs/backend/role-management.md +92 -0
- package/repo-docs/backend/shared-rbac-architecture.md +339 -0
- package/repo-docs/backend/user-management.md +92 -0
- package/repo-docs/blogs/index.md +2 -0
- package/repo-docs/frontend/form-layout-guide.md +6 -6
- package/repo-docs/frontend/model-resource-owner-pattern.md +2 -0
- package/repo-docs/frontend/page-guide.md +12 -0
- package/repo-docs/frontend/page-meta-guide.md +27 -0
- package/repo-docs/frontend/permission-formscene-action-visibility-guide.md +5 -3
- package/repo-docs/frontend/ssr-architecture-overview.md +4 -0
- package/repo-docs/frontend/ssr-build-deploy-guide.md +1 -1
- package/repo-docs/frontend/table-action-visibility-permission-flow-guide.md +2 -0
- package/repo-docs/frontend/table-guide.md +75 -22
- package/repo-docs/frontend/table-resource-crud-cookbook.md +25 -4
- package/repo-docs/frontend/zova-form-source-reading-map.md +2 -2
- package/repo-docs/frontend/zova-form-under-the-hood.md +1 -1
- package/repo-docs/frontend/zova-reactivity-under-the-hood.md +65 -9
- package/repo-docs/frontend/zova-table-source-reading-map.md +54 -19
- package/repo-docs/frontend/zova-table-under-the-hood.md +70 -39
- package/repo-docs/fullstack/contract-loop-playbook.md +2 -0
- package/repo-docs/fullstack/ssr-site-and-flavor-setup.md +198 -0
- package/repo-docs/fullstack/vona-zova-integration.md +2 -0
- package/repo-e2e/docs/playwright.config.ts +37 -0
- package/repo-e2e/docs/specs/blogs-index.spec.ts +180 -0
- package/repo-e2e/docs/specs/github-repositories-nav.spec.ts +69 -0
- package/repo-e2e/docs/test-results/.last-run.json +4 -0
- package/repo-e2e/specs/cabloy-basic.spec.ts +136 -2
- package/test-results/.last-run.json +20 -2
- package/test-results/a-commerce-ATP-ADDR-01-aut-11dea-ss-through-Web-self-service/error-context.md +238 -0
- package/test-results/a-commerce-ATP-SPC-01-Coup-ef380-mantic-Admin-field-controls/error-context.md +240 -0
- package/test-results/a-commerce-ATP-SPC-02-Cate-9f120-on-and-publication-controls/error-context.md +238 -0
- package/test-results/a-commerce-ATP-SPC-02-Prod-5f92a-on-and-publication-controls/error-context.md +238 -0
- package/test-results/a-commerce-ATP-SPC-02-SKU--2e61e-ency-and-lifecycle-controls/error-context.md +238 -0
- package/test-results/a-commerce-ATP-SPC-04-Stoc-fa895--readonly-and-mutation-free/error-context.md +235 -0
- package/test-results/a-commerce-ATP-SPC-05-syst-fb406-e-without-mutation-controls/error-context.md +238 -0
- package/test-results/a-commerce-Commerce-sessio-4e963-ie-selects-raw-server-theme/error-context.md +226 -0
- package/test-results/a-commerce-Commerce-theme--062fe--without-hydration-mismatch/error-context.md +229 -0
- package/test-results/a-commerce-PayPal-browser--8672c-t-or-open-an-awaiting-order/error-context.md +238 -0
- package/test-results/a-commerce-Payment-callbac-f56c2--reconciles-after-hydration/error-context.md +238 -0
- package/test-results/a-commerce-Payment-cancell-3fc74-ified-provider-confirmation/error-context.md +238 -0
- package/test-results/a-commerce-Phase-50-60-aut-71d61--observes-operator-shipment/error-context.md +238 -0
- package/test-results/a-commerce-Phase-60-custom-407cd-ecutes-a-whole-order-refund/error-context.md +238 -0
- package/test-results/cabloy-basic-ATP-BASIC-TAB-e7253-and-pins-configured-columns/error-context.md +240 -0
- package/test-results/markdown-ATP-SPC-02-Produc-9d5c2-link-toolbar-edits-Markdown/error-context.md +211 -0
- package/test-results/markdown-ATP-SPC-02-Produc-9d6ea-t-editor-and-saves-Markdown/error-context.md +238 -0
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/entity/{{resourceName}}.tsx_ +1 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/entity/{{resourceName}}.tsx_ +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +79 -52
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/en-us.ts +3 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/zh-cn.ts +3 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productCreate.tsx +2 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productUpdate.tsx +2 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productView.tsx +2 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordCreate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectReq.tsx +3 -7
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordUpdate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +8 -0
- package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +51 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +3 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +3 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +10 -1
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +99 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/src/bean/pipe.filter.ts +85 -57
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/cli/templates/rest/render.ts +2 -0
- package/zova/packages-cli/cli-set-front/cli/templates/rest/rest.ts +13 -3
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +16 -16
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +31 -11
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +3 -0
- package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx +1 -1
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +68 -8
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +4 -0
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-form/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-form/src/lib/formLayout.ts +0 -6
- package/zova/src/suite-vendor/a-zova/modules/a-form/test/lib/formLayout.test.ts +16 -9
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +4 -0
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +13 -2
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/schema.ts +1 -0
- 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 +50 -0
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx +60 -7
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/types/table.ts +6 -4
- package/zova/src/suite-vendor/a-zova/package.json +4 -4
|
@@ -47,7 +47,7 @@ If you only remember one idea, remember this one:
|
|
|
47
47
|
That leads to three common authoring surfaces:
|
|
48
48
|
|
|
49
49
|
- `ZTable` — the root table component
|
|
50
|
-
- schema `
|
|
50
|
+
- schema metadata — `ZovaRender.column(...)` supplies table-column layout/capability metadata, while shared/table-scene overlays supply effective visibility, order, and render metadata
|
|
51
51
|
- `tableCell` beans — the main extension surface for reusable cell rendering
|
|
52
52
|
|
|
53
53
|
## One running example through this guide: Student list page
|
|
@@ -123,17 +123,12 @@ A practical reading takeaway is:
|
|
|
123
123
|
|
|
124
124
|
In the default path, `ZTable` reads table-scene metadata from the row schema.
|
|
125
125
|
|
|
126
|
-
The
|
|
127
|
-
|
|
128
|
-
- `order`
|
|
129
|
-
- `visible`
|
|
130
|
-
- `render`
|
|
131
|
-
- `columnProps`
|
|
126
|
+
The table sees the **effective table metadata**, not only one literal source object. It combines shared field `rest` metadata with the table-scene `rest.table` overlay, then orders the resulting properties by effective `rest.order`.
|
|
132
127
|
|
|
133
128
|
A simplified mental model is:
|
|
134
129
|
|
|
135
130
|
```text
|
|
136
|
-
schema row ->
|
|
131
|
+
schema row -> merge table metadata -> sort by order -> filter by visible -> build columns -> render cells
|
|
137
132
|
```
|
|
138
133
|
|
|
139
134
|
That means the default list-page question becomes less:
|
|
@@ -146,6 +141,58 @@ and more:
|
|
|
146
141
|
|
|
147
142
|
This is why table work often belongs in the broader contract loop when the real source of truth is backend field metadata.
|
|
148
143
|
|
|
144
|
+
## Step 4: Configure physical columns with `ZovaRender.column(...)`
|
|
145
|
+
|
|
146
|
+
`ZovaRender.column(...)` is a shared Cabloy/Zova schema-metadata API available in both Cabloy Basic and Cabloy Start. It returns a schema transformer that writes column options under `rest.table`; it does **not** register a frontend column or render a cell by itself.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
@Api.field(
|
|
150
|
+
v.title($locale('Name')),
|
|
151
|
+
ZovaRender.column({
|
|
152
|
+
align: 'left',
|
|
153
|
+
width: 240,
|
|
154
|
+
fixed: 'left',
|
|
155
|
+
enableSorting: true,
|
|
156
|
+
sortDescFirst: true,
|
|
157
|
+
}),
|
|
158
|
+
v.string(),
|
|
159
|
+
)
|
|
160
|
+
name: string;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The current options are:
|
|
164
|
+
|
|
165
|
+
| Option | Meaning in the table runtime |
|
|
166
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
167
|
+
| `order` | Orders this property among the effective table properties. For shared field order, `ZovaRender.order(...)` is usually clearer. |
|
|
168
|
+
| `align` | Applies `left`, `center`, or `right` text alignment to the header and cells. |
|
|
169
|
+
| `width` | Supplies the TanStack column size and current renderers apply it as pixel width and minimum width. |
|
|
170
|
+
| `fixed` | Pins the column to the `left` or `right`; the table runtime calculates pinning and renderers apply sticky offsets. |
|
|
171
|
+
| `enableSorting` | Requests a sortable header, subject to the order-schema capability described below. |
|
|
172
|
+
| `sortDescFirst` | Makes the first header toggle descend; it does not change backend order syntax. |
|
|
173
|
+
|
|
174
|
+
`ZovaRender.column(...)` configures the physical column. `ZovaRender.cell(...)` independently selects the cell renderer and its options. For example, a virtual Operations field can be right-pinned and centered while its content comes from a reusable `tableCell` resource:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
@Api.field(
|
|
178
|
+
v.title($locale('Operations')),
|
|
179
|
+
ZovaRender.order(1, 'max'),
|
|
180
|
+
ZovaRender.column({ align: 'center', width: 360, fixed: 'right' }),
|
|
181
|
+
ZovaRender.cell('basic-table:actionOperationsRow', { actions }),
|
|
182
|
+
)
|
|
183
|
+
_operationsRow?: unknown;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The `basic-table:*` renderer key in this example is Cabloy Basic-specific. The `ZovaRender.column(...)` contract itself is shared; use the active edition's renderer keys when selecting a cell resource.
|
|
187
|
+
|
|
188
|
+
### Enable server-backed sorting
|
|
189
|
+
|
|
190
|
+
`enableSorting: true` is necessary but not sufficient. The same field, canonical key, or schema alias must also exist in `schemaOrder`; otherwise the table deliberately creates a non-sortable column.
|
|
191
|
+
|
|
192
|
+
A direct `ZTable` consumer owns and passes `schemaOrder`, controlled `sorting`, and `onSortingChange`. In the standard Cabloy Basic resource-page path, `basic-page:blockTable` passes those values from `basic-page:blockPage`; the page translates one manual table sort into backend `orders` and reloads the resource query. The loaded page is not client-side sorted by TanStack.
|
|
193
|
+
|
|
194
|
+
For relation-order rewriting, see [Existing Resource Field Update](/backend/resource-field-update#filter-and-sort-a-relation-by-its-display-field). For the resource-page bridge, see [Table + Resource CRUD Cookbook](/frontend/table-resource-crud-cookbook).
|
|
195
|
+
|
|
149
196
|
A practical expression example is a schema-driven cell display that formats the current row value through CEL:
|
|
150
197
|
|
|
151
198
|
```text
|
|
@@ -156,7 +203,7 @@ In the shared table CEL scope, `getValue(name)` reads the current row value and
|
|
|
156
203
|
|
|
157
204
|
For the schema side of that contract, also see [API Schema Guide](/frontend/api-schema-guide).
|
|
158
205
|
|
|
159
|
-
## Step
|
|
206
|
+
## Step 5: Use built-in or custom `tableCell` render resources
|
|
160
207
|
|
|
161
208
|
A column render is usually chosen through schema metadata such as:
|
|
162
209
|
|
|
@@ -184,7 +231,7 @@ A practical rule is:
|
|
|
184
231
|
- use built-in `tableCell` resources first
|
|
185
232
|
- add a custom `tableCell` bean only when the business UI really needs module-owned rendering behavior
|
|
186
233
|
|
|
187
|
-
## Step
|
|
234
|
+
## Step 6: Create a custom `tableCell` bean
|
|
188
235
|
|
|
189
236
|
When a built-in renderer is not enough, use the existing CLI-backed scene workflow.
|
|
190
237
|
|
|
@@ -230,7 +277,7 @@ That scaffold is useful because it starts from the correct Zova scene contract:
|
|
|
230
277
|
|
|
231
278
|
For the broader scene system behind this decorator, see [Bean Scene Authoring](/frontend/bean-scene-authoring).
|
|
232
279
|
|
|
233
|
-
## Step
|
|
280
|
+
## Step 7: Add page-local custom columns with `getColumns(...)`
|
|
234
281
|
|
|
235
282
|
When most columns should stay schema-driven but one column should be page-local, use `getColumns(...)`.
|
|
236
283
|
|
|
@@ -275,7 +322,7 @@ A practical caveat is:
|
|
|
275
322
|
|
|
276
323
|
So a mixed table does **not** mean bypassing Zova. It means extending the existing runtime through its own hooks.
|
|
277
324
|
|
|
278
|
-
## Step
|
|
325
|
+
## Step 8: Use resource-driven page blocks for CRUD list pages
|
|
279
326
|
|
|
280
327
|
For standard resource pages, the more common public surface is not direct `ZTable` usage. It is the block-based page runtime:
|
|
281
328
|
|
|
@@ -299,7 +346,7 @@ This gives you a cohesive CRUD path where:
|
|
|
299
346
|
|
|
300
347
|
For the resource ownership side of that page shape, see [Model Resource Owner Pattern](/frontend/model-resource-owner-pattern).
|
|
301
348
|
|
|
302
|
-
## Step
|
|
349
|
+
## Step 9: Know when to use `BeanControllerPageTableBase`
|
|
303
350
|
|
|
304
351
|
If your table belongs directly to a page controller rather than a reusable component controller, the page-oriented base class already exists:
|
|
305
352
|
|
|
@@ -322,15 +369,19 @@ TanStack Table is still important, but the business-facing runtime is controller
|
|
|
322
369
|
|
|
323
370
|
For many resource pages, the faster path is to let `rest.table` metadata describe the default columns first.
|
|
324
371
|
|
|
325
|
-
### Mistake 3:
|
|
372
|
+
### Mistake 3: Treating `ZovaRender.column(...)` as a cell renderer
|
|
373
|
+
|
|
374
|
+
`ZovaRender.column(...)` supplies column layout and sorting metadata. Use `ZovaRender.cell(...)` to name the cell render target, and use a `tableCell` bean when that reusable renderer needs module-owned behavior.
|
|
375
|
+
|
|
376
|
+
### Mistake 4: Bypassing `tableCell` beans for reusable cell behavior
|
|
326
377
|
|
|
327
378
|
If a renderer should be shared across pages or modules, prefer a `tableCell` resource over repeated page-local callbacks.
|
|
328
379
|
|
|
329
|
-
### Mistake
|
|
380
|
+
### Mistake 5: Treating `controllerRef` like a generic Vue DOM ref
|
|
330
381
|
|
|
331
382
|
`controllerRef` gives you the table controller instance, not a plain DOM element.
|
|
332
383
|
|
|
333
|
-
### Mistake
|
|
384
|
+
### Mistake 6: Rebuilding CRUD list wiring manually when `basic-page` already owns it
|
|
334
385
|
|
|
335
386
|
For standard resource pages, prefer the existing block/page runtime before hand-building a custom table flow.
|
|
336
387
|
|
|
@@ -340,12 +391,12 @@ If you want the shortest accurate path to a real business table, use this order:
|
|
|
340
391
|
|
|
341
392
|
1. make sure the backend row schema is already the right contract truth
|
|
342
393
|
2. start with a resource page or direct `ZTable`
|
|
343
|
-
3. let schema metadata drive the default columns
|
|
344
|
-
4.
|
|
394
|
+
3. let schema metadata drive the default columns; add `ZovaRender.column(...)` only where layout, pinning, or sorting metadata is needed
|
|
395
|
+
4. use `ZovaRender.cell(...)` and built-in `tableCell` renderers for cell content first
|
|
345
396
|
5. add page-local `getColumns(...)` only where needed
|
|
346
397
|
6. create custom `tableCell` beans only where the UI becomes business-specific
|
|
347
398
|
7. continue with [TableCell Authoring Cookbook](/frontend/table-cell-cookbook) when you want concrete patterns for custom cell beans and row actions
|
|
348
|
-
8. continue with [Table + Resource CRUD Cookbook](/frontend/table-resource-crud-cookbook) when you want the standard resource-page integration path for filter, bulk actions, table, and
|
|
399
|
+
8. continue with [Table + Resource CRUD Cookbook](/frontend/table-resource-crud-cookbook) when you want the standard resource-page integration path for filter, bulk actions, table, pager, and server sorting
|
|
349
400
|
9. continue with [Zova Table Under the Hood](/frontend/zova-table-under-the-hood) when you want the runtime explanation behind the public authoring surface
|
|
350
401
|
10. continue with [Zova Table Source Reading Map](/frontend/zova-table-source-reading-map) when you need framework-level source details and targeted file-order guidance
|
|
351
402
|
|
|
@@ -359,9 +410,11 @@ When documenting or changing a table workflow, verify in this order:
|
|
|
359
410
|
npm run zova :create:bean --help
|
|
360
411
|
```
|
|
361
412
|
|
|
362
|
-
2. confirm the `
|
|
363
|
-
3. confirm the
|
|
364
|
-
4.
|
|
413
|
+
2. confirm the `ZovaRender.column(...)` option contract and table-scene metadata merge still match current source
|
|
414
|
+
3. confirm the `tableCell` scene metadata still exists in the current `a-table` module
|
|
415
|
+
4. for sortable resource columns, verify header state, fixed-column layout/overflow where relevant, and the backend `orders` request
|
|
416
|
+
5. confirm the runtime claims against the current `a-table`, `basic-table`, and `basic-page` source
|
|
417
|
+
6. if you changed docs, build the docs site:
|
|
365
418
|
|
|
366
419
|
```bash
|
|
367
420
|
npm run docs:build
|
|
@@ -269,6 +269,8 @@ Its bridge role is very clear:
|
|
|
269
269
|
- render `ZTable`
|
|
270
270
|
- pass page data into `data`
|
|
271
271
|
- pass row schema into `schema`
|
|
272
|
+
- pass the resource order schema into `schemaOrder`
|
|
273
|
+
- pass controlled `sorting` and `onSortingChange`
|
|
272
274
|
- pass page CEL scope into `tableScope`
|
|
273
275
|
- capture the table controller through `controllerRef`
|
|
274
276
|
|
|
@@ -329,10 +331,13 @@ _operationsRow?: unknown;
|
|
|
329
331
|
|
|
330
332
|
This is the practical reverse-sharing model:
|
|
331
333
|
|
|
332
|
-
-
|
|
334
|
+
- `ZovaRender.column(...)` configures physical-column behavior such as alignment, width, pinning, and sorting eligibility
|
|
335
|
+
- `ZovaRender.cell(...)` chooses the table-cell resource identity and its options
|
|
333
336
|
- the frontend table runtime resolves that resource
|
|
334
337
|
- the page block and table block do not need page-local hard-coded row-action wiring
|
|
335
338
|
|
|
339
|
+
For example, an Operations field can add `ZovaRender.column({ align: 'center', width: 360, fixed: 'right' })` beside the existing `ZovaRender.cell(...)`. `ZovaRender.column(...)` is a shared Basic/Start capability; the `basic-table:*` cell key remains a Cabloy Basic choice.
|
|
340
|
+
|
|
336
341
|
For the built-in metadata-sharing teaching path, see [Tutorial 3: Frontend Metadata Sharing](/fullstack/tutorial-3-frontend-metadata-sharing).
|
|
337
342
|
|
|
338
343
|
For the forward-chain row-action teaching path, see [Tutorial 5: Backend Contract Sharing](/fullstack/tutorial-5-backend-contract-sharing).
|
|
@@ -346,10 +351,24 @@ For standard CRUD list pages, most customization should happen in one of these p
|
|
|
346
351
|
Use this when:
|
|
347
352
|
|
|
348
353
|
- a field should change order
|
|
354
|
+
- a column should change alignment, width, or left/right pinning
|
|
355
|
+
- a server-authorized field should expose a sortable header
|
|
349
356
|
- a column should be visible or hidden
|
|
350
357
|
- a field should use a different built-in or custom `tableCell`
|
|
351
358
|
|
|
352
|
-
This is usually the first and best extension point.
|
|
359
|
+
This is usually the first and best extension point. Use `ZovaRender.column(...)` for the column metadata and `ZovaRender.cell(...)` for the cell renderer; do not treat either helper as a replacement for the other.
|
|
360
|
+
|
|
361
|
+
### Enable standard resource-page sorting
|
|
362
|
+
|
|
363
|
+
For a normal Cabloy Basic resource list, backend field metadata can request a sortable column with:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
ZovaRender.column({ enableSorting: true });
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
The field must also be present in the resource `schemaOrder`; that order schema remains the authority for whether the header is actually sortable. `blockTable` forwards the order schema plus controlled sorting state into `ZTable`, and `blockPage` turns one header selection into backend `orders` before reloading the resource query. This is server sorting, not local reordering of the current page.
|
|
370
|
+
|
|
371
|
+
For the full shared `ZovaRender.column(...)` contract, see [Table Guide](/frontend/table-guide#configure-physical-columns-with-zovarendercolumn). For relation-backed order rewriting, see [Existing Resource Field Update](/backend/resource-field-update#filter-and-sort-a-relation-by-its-display-field).
|
|
353
372
|
|
|
354
373
|
### Extension point B: backend block composition metadata
|
|
355
374
|
|
|
@@ -505,8 +524,8 @@ If you want the shortest path to a real CRUD list page, use this order:
|
|
|
505
524
|
1. generate or confirm the backend CRUD contract thread
|
|
506
525
|
2. confirm the resource-owner model already exposes the required schemas and permissions
|
|
507
526
|
3. keep the standard `blockPage -> blockFilter -> blockToolbarBulk -> blockTable -> blockPager` chain
|
|
508
|
-
4. refine backend row metadata for visible columns and row actions
|
|
509
|
-
5. reuse built-in `tableCell` resources first
|
|
527
|
+
4. refine backend row metadata for visible columns, layout/pinning/sort capability through `ZovaRender.column(...)`, and row actions
|
|
528
|
+
5. reuse `ZovaRender.cell(...)` with built-in `tableCell` resources first
|
|
510
529
|
6. add custom `tableCell` resources only where the UI becomes business-specific
|
|
511
530
|
7. change block controllers only when the existing runtime is structurally insufficient
|
|
512
531
|
8. continue with [Table Guide](/frontend/table-guide) for the public `ZTable` surface
|
|
@@ -533,6 +552,8 @@ When authoring or documenting a resource CRUD list page, verify in this order:
|
|
|
533
552
|
- filter works
|
|
534
553
|
- bulk actions render correctly
|
|
535
554
|
- table columns and row actions match metadata
|
|
555
|
+
- fixed columns, widths, and overflow behave as intended when configured
|
|
556
|
+
- sortable headers expose the expected state and reload with the intended backend `orders`
|
|
536
557
|
- pager updates the list correctly
|
|
537
558
|
7. if you changed docs, build the docs site:
|
|
538
559
|
|
|
@@ -233,7 +233,7 @@ Use this path when you are asking questions like:
|
|
|
233
233
|
- where does `formLayout` come from in a resource DTO?
|
|
234
234
|
- how are fields, embedded blocks, sections, groups, and tabs normalized before rendering?
|
|
235
235
|
- how do canonical keys, preserved schema aliases, and unique relation-prefix shorthand resolve to one field?
|
|
236
|
-
- why
|
|
236
|
+
- why do omitted fields not render, or duplicate fields get removed?
|
|
237
237
|
- where does Cabloy Basic render responsive grids and tab error badges?
|
|
238
238
|
|
|
239
239
|
### Read the docs first
|
|
@@ -266,7 +266,7 @@ Use this path when you are asking questions like:
|
|
|
266
266
|
- the resolver filters visible fields, resolves exact canonical keys before unique aliases and unique prefixes, and records duplicate identity and tab paths by canonical key
|
|
267
267
|
- the Basic block controller renders sections, groups, tabs, field spans, and embedded blocks while delegating canonical field names to `$$form.renderField(...)`
|
|
268
268
|
- `blockFilterActions` shows how a block rendered inside Form Layout reuses the inherited form CEL scope to invoke `$$filter`
|
|
269
|
-
- the OpenAPI and Form Layout unit tests verify canonicalization, alias precedence, ambiguity, duplicates, visibility,
|
|
269
|
+
- the OpenAPI and Form Layout unit tests verify canonicalization, explicit field inclusion, alias precedence, ambiguity, duplicates, visibility, and tab paths
|
|
270
270
|
- the Student test verifies emitted metadata nesting, columns, spans, embedded action blocks, and optional IDs; it is not a browser rendering test
|
|
271
271
|
|
|
272
272
|
## 8. Resource-driven CRUD page integration
|
|
@@ -454,7 +454,7 @@ That means automatic schema-driven rendering is not happening magically in the w
|
|
|
454
454
|
|
|
455
455
|
When `ZForm` receives a nonempty block list, the render bean delegates body rendering to those blocks instead of iterating schema fields directly. For Cabloy Basic structural forms, `basic-form:blockFormLayout` resolves `formLayout` against the form's current schema properties and calls `$$form.renderField(...)` for each surviving layout field.
|
|
456
456
|
|
|
457
|
-
For a field declaration, the shared resolver first accepts an exact canonical key, then a uniquely mapped preserved schema alias, and then a unique relation-prefix shorthand. It rewrites an alias or shorthand to the canonical key before calling `$$form.renderField(...)`. Exact canonical keys win over colliding aliases; ambiguous aliases or prefixes are reported as `unknownField`.
|
|
457
|
+
For a field declaration, the shared resolver first accepts an exact canonical key, then a uniquely mapped preserved schema alias, and then a unique relation-prefix shorthand. It rewrites an alias or shorthand to the canonical key before calling `$$form.renderField(...)`. Exact canonical keys win over colliding aliases; ambiguous aliases or prefixes are reported as `unknownField`. A configured Form Layout is an explicit allow-list: only fields represented by surviving declarations render. Duplicate tracking and tab-path bookkeeping use the canonical key. See [Form Layout Guide](/frontend/form-layout-guide#how-the-resolver-handles-the-declared-tree) for the full DTO authoring rules.
|
|
458
458
|
|
|
459
459
|
Form Layout also supports a leaf `block` node. It wraps an existing resource block descriptor and the Basic renderer invokes it with the inherited `IJsxRenderContextForm`, including the same JSX runtime and CEL scope. The node has no schema property or field value; for example, a filter can place `basic-page:blockFilterActions` inside a flow section while that action block continues to read `$$filter` from the filter-owned form scope.
|
|
460
460
|
|
|
@@ -151,6 +151,62 @@ This is one of the most important source-level facts for understanding Zova.
|
|
|
151
151
|
|
|
152
152
|
Zova does not require the business author to write `reactive({ ... })` around controller state, because the framework already treats the controller bean as the reactive object.
|
|
153
153
|
|
|
154
|
+
#### Construction-time `this` and the exposed reactive bean
|
|
155
|
+
|
|
156
|
+
There is one lifecycle boundary that matters when a callback closes over `this`:
|
|
157
|
+
|
|
158
|
+
1. the container first constructs the raw class instance with `new BeanClass(...)`;
|
|
159
|
+
2. it then exposes the framework-managed reactive/proxied bean; and
|
|
160
|
+
3. it invokes `__init__()` only after that preparation completes.
|
|
161
|
+
|
|
162
|
+
That distinction is normally invisible when a controller uses ordinary methods and render-time `this.member` access. It matters for a class-field arrow callback that mutates controller state, because the arrow is created during construction and lexically captures the construction-time raw `this`:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
class ControllerPageCounter {
|
|
166
|
+
count = 0;
|
|
167
|
+
|
|
168
|
+
// Avoid for a state-mutating controller callback.
|
|
169
|
+
onIncrement = () => {
|
|
170
|
+
this.count++;
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The field can change on the raw instance, but the mutation bypasses the reactive/proxied bean through which render dependencies were collected. Vue therefore receives no invalidation notification. A later update to another dependency can rerender the component and reveal the changed underlying value, which can make this look intermittent.
|
|
176
|
+
|
|
177
|
+
Prefer an ordinary controller method for a normal TSX action:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
class ControllerPageCounter {
|
|
181
|
+
count = 0;
|
|
182
|
+
|
|
183
|
+
increment() {
|
|
184
|
+
this.count++;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
protected render() {
|
|
188
|
+
return <button onClick={() => this.increment()}>Increment</button>;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If an external API requires a stable stored callback, create that closure in `__init__()` instead. At that point, its lexical `this` is the framework-exposed reactive/proxied bean:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
class ControllerPageCounter {
|
|
197
|
+
count = 0;
|
|
198
|
+
onIncrement: () => void;
|
|
199
|
+
|
|
200
|
+
protected async __init__() {
|
|
201
|
+
this.onIncrement = () => {
|
|
202
|
+
this.count++;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
This is not a rule that arrow functions are generally non-reactive. The narrow hazard is a **class-field arrow callback that captures construction-time `this` and mutates bean state**.
|
|
209
|
+
|
|
154
210
|
### 4. `$computed()` is an instance-scoped wrapper around Vue `computed(...)`
|
|
155
211
|
|
|
156
212
|
In:
|
|
@@ -238,21 +294,21 @@ A practical reading takeaway is:
|
|
|
238
294
|
|
|
239
295
|
### 7. Field mutation becomes normal reactive invalidation and rerender
|
|
240
296
|
|
|
241
|
-
Once
|
|
297
|
+
Once render has read fields through the framework-exposed reactive/proxied controller, a mutation through that same identity, such as:
|
|
242
298
|
|
|
243
299
|
```typescript
|
|
244
300
|
this.count++;
|
|
245
301
|
```
|
|
246
302
|
|
|
247
|
-
|
|
303
|
+
behaves the way a Vue reader would expect at the reactive-engine level:
|
|
248
304
|
|
|
249
305
|
- the field change invalidates dependencies
|
|
250
306
|
- computed values depending on that field are recomputed
|
|
251
307
|
- the next render sees the updated values
|
|
252
308
|
|
|
253
|
-
|
|
309
|
+
The construction-time class-field arrow case described above is the exception: its raw `this` can change the underlying field without triggering the dependency that render collected through the exposed bean.
|
|
254
310
|
|
|
255
|
-
The architectural surface is what changed.
|
|
311
|
+
So the runtime behavior is still recognizably Vue-like. The architectural surface, including the bean lifecycle and identity boundary, is what changed.
|
|
256
312
|
|
|
257
313
|
## A compact call-flow sketch
|
|
258
314
|
|
|
@@ -260,13 +316,13 @@ The architectural surface is what changed.
|
|
|
260
316
|
useControllerPage(...)
|
|
261
317
|
-> _useController(...)
|
|
262
318
|
-> ctx.bean._newBeanInner(..., markReactive = true)
|
|
263
|
-
-> BeanContainer
|
|
264
|
-
-> BeanContainer
|
|
265
|
-
-> controller __init__ wires $computed / $watch helpers
|
|
319
|
+
-> BeanContainer constructs the raw controller bean
|
|
320
|
+
-> BeanContainer exposes the reactive/proxied controller bean
|
|
321
|
+
-> controller __init__ wires $computed / $watch helpers and any stored callbacks
|
|
266
322
|
-> component render is patched toward controller/render bean
|
|
267
323
|
-> render-time controller data update refreshes page route data
|
|
268
|
-
-> render reads
|
|
269
|
-
->
|
|
324
|
+
-> render reads fields through the exposed bean
|
|
325
|
+
-> mutation through that same identity invalidates dependencies
|
|
270
326
|
-> rerender produces updated UI
|
|
271
327
|
```
|
|
272
328
|
|
|
@@ -120,7 +120,8 @@ Use this path when you are asking questions like:
|
|
|
120
120
|
Use this path when you are asking questions like:
|
|
121
121
|
|
|
122
122
|
- how does a row schema become visible columns?
|
|
123
|
-
- where do `
|
|
123
|
+
- where do `order`, `align`, `width`, `fixed`, `enableSorting`, and `sortDescFirst` come from?
|
|
124
|
+
- where do `visible`, `render`, and `columnProps` come from?
|
|
124
125
|
- how does the table scene differ from form or filter scenes?
|
|
125
126
|
|
|
126
127
|
### Read the docs first
|
|
@@ -130,17 +131,51 @@ Use this path when you are asking questions like:
|
|
|
130
131
|
|
|
131
132
|
### Then read source in this order
|
|
132
133
|
|
|
134
|
+
1. `zova/packages-cli/cli-set-front/cli/templates/rest/rest.ts`
|
|
135
|
+
2. `zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts`
|
|
136
|
+
3. `zova/src/suite-vendor/a-zova/modules/a-openapi/src/lib/schema.ts`
|
|
137
|
+
4. `zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx`
|
|
138
|
+
5. `zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx`
|
|
139
|
+
|
|
140
|
+
### What each file clarifies
|
|
141
|
+
|
|
142
|
+
- `cli/templates/rest/rest.ts` shows that `ZovaRender.column(...)` writes `ITableColumnOptions` under `rest.table`
|
|
143
|
+
- `types/rest.ts` defines `order`, `align`, `width`, `fixed`, `enableSorting`, and `sortDescFirst`
|
|
144
|
+
- `schema.ts` shows `loadSchemaProperties(...)`, `$ref` resolution, and the merge of shared `rest` metadata with table-scene overlays
|
|
145
|
+
- `controller.tsx` shows `_createProperties()`, `_createTableMeta()`, `_createColumnsMiddle()`, order-schema sorting eligibility, and pinning
|
|
146
|
+
- `render.tsx` shows how effective metadata becomes alignment, dimensions, fixed-column styles, and sortable header DOM
|
|
147
|
+
|
|
148
|
+
## 4. Column metadata, sortable headers, and resource orders
|
|
149
|
+
|
|
150
|
+
Use this path when you are asking questions like:
|
|
151
|
+
|
|
152
|
+
- why did `ZovaRender.column({ enableSorting: true })` not make a header sortable?
|
|
153
|
+
- how do fixed columns become sticky left/right columns?
|
|
154
|
+
- how does one header click become a resource request `orders` value?
|
|
155
|
+
|
|
156
|
+
### Read the docs first
|
|
157
|
+
|
|
158
|
+
- [Table Guide](/frontend/table-guide)
|
|
159
|
+
- [Table + Resource CRUD Cookbook](/frontend/table-resource-crud-cookbook)
|
|
160
|
+
- [Existing Resource Field Update](/backend/resource-field-update#filter-and-sort-a-relation-by-its-display-field)
|
|
161
|
+
|
|
162
|
+
### Then read source in this order
|
|
163
|
+
|
|
133
164
|
1. `zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx`
|
|
134
|
-
2. `zova/src/suite-vendor/a-zova/modules/a-
|
|
135
|
-
3. `zova/src/suite
|
|
165
|
+
2. `zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx`
|
|
166
|
+
3. `zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx`
|
|
167
|
+
4. `zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx`
|
|
136
168
|
|
|
137
169
|
### What each file clarifies
|
|
138
170
|
|
|
139
|
-
- `controller.tsx` shows `
|
|
140
|
-
- `
|
|
141
|
-
- `
|
|
171
|
+
- `controller.tsx` shows that `enableSorting` also requires the property key or aliases to exist in `schemaOrder`, and shows left/right pinning construction
|
|
172
|
+
- `render.tsx` shows the header toggle, `aria-sort`, indicators, and sticky styles
|
|
173
|
+
- `blockTable/controller.tsx` shows the handoff of `schemaOrder`, controlled sorting, and `onSortingChange`
|
|
174
|
+
- `blockPage/controller.tsx` shows conversion of the single current sort into backend `orders` and query reload
|
|
175
|
+
|
|
176
|
+
The result is a controlled, manual server-sorting path: the standard resource page does not client-side sort rows that have already been fetched. The `basic-page` files are Cabloy Basic specimens; the metadata API and base Zova Table behavior are shared with Cabloy Start, whose page module paths must be resolved in that edition.
|
|
142
177
|
|
|
143
|
-
##
|
|
178
|
+
## 5. `tableCell` bean-scene contract and decorator surface
|
|
144
179
|
|
|
145
180
|
Use this path when you are asking questions like:
|
|
146
181
|
|
|
@@ -168,7 +203,7 @@ Use this path when you are asking questions like:
|
|
|
168
203
|
- `package.json` shows `zovaModule.onions.tableCell` and boilerplate metadata
|
|
169
204
|
- the boilerplate files show the intended scaffold shape for normal cells and row-action cells
|
|
170
205
|
|
|
171
|
-
##
|
|
206
|
+
## 6. Cell render pipeline and CEL/JSX scope
|
|
172
207
|
|
|
173
208
|
Use this path when you are asking questions like:
|
|
174
209
|
|
|
@@ -193,7 +228,7 @@ Use this path when you are asking questions like:
|
|
|
193
228
|
- `tableColumn.ts` shows column scope, cell scope, and table column render types
|
|
194
229
|
- `tableCell.ts` shows the render-context contract received by a `tableCell` bean
|
|
195
230
|
|
|
196
|
-
##
|
|
231
|
+
## 7. Representative built-in cell renderers
|
|
197
232
|
|
|
198
233
|
Use this path when you are asking questions like:
|
|
199
234
|
|
|
@@ -220,7 +255,7 @@ Use this path when you are asking questions like:
|
|
|
220
255
|
- `tableCell.select.tsx` shows value-to-item mapping
|
|
221
256
|
- `actionOperationsRow.tsx` shows advanced visibility checks, nested action rendering, and permission-aware orchestration
|
|
222
257
|
|
|
223
|
-
##
|
|
258
|
+
## 8. Custom columns through `getColumns(...)`
|
|
224
259
|
|
|
225
260
|
Use this path when you are asking questions like:
|
|
226
261
|
|
|
@@ -243,15 +278,15 @@ Use this path when you are asking questions like:
|
|
|
243
278
|
|
|
244
279
|
- `types/table.ts` shows `TypeTableGetColumns` and `TypeTableCreateColumnRender`
|
|
245
280
|
- `controller.tsx` shows how custom columns are given `next(...)`, `createColumnRender(...)`, and the table controller itself
|
|
246
|
-
- `basic-table/render.tsx`
|
|
281
|
+
- `basic-table/render.tsx` is a Cabloy Basic forwarding wrapper around `ZTable`; it preserves the custom-column hook rather than serving as an executable custom-column specimen
|
|
247
282
|
|
|
248
|
-
##
|
|
283
|
+
## 9. Resource-page integration
|
|
249
284
|
|
|
250
285
|
Use this path when you are asking questions like:
|
|
251
286
|
|
|
252
287
|
- how does a resource list page feed schema and data into `ZTable`?
|
|
253
|
-
- where do `data`, `schemaRow`, and `tableScope` come from?
|
|
254
|
-
- where should permission-sensitive table refresh be debugged?
|
|
288
|
+
- where do `data`, `schemaRow`, `schemaOrder`, and `tableScope` come from?
|
|
289
|
+
- where should permission-sensitive table refresh or resource sorting be debugged?
|
|
255
290
|
|
|
256
291
|
### Read the docs first
|
|
257
292
|
|
|
@@ -266,11 +301,11 @@ Use this path when you are asking questions like:
|
|
|
266
301
|
|
|
267
302
|
### What each file clarifies
|
|
268
303
|
|
|
269
|
-
- `blockPage/controller.tsx` shows resource ownership, query state, page CEL scope, permissions,
|
|
270
|
-
- `blockTable/controller.tsx` shows the direct bridge from page block to `ZTable
|
|
304
|
+
- `blockPage/controller.tsx` shows resource ownership, query state, page CEL scope, permissions, table refresh integration, and `orders` mapping
|
|
305
|
+
- `blockTable/controller.tsx` shows the direct bridge from page block to `ZTable`, including order schema and controlled sorting props
|
|
271
306
|
- the Vona DTO specimen shows the block-based page composition consumed from backend-owned metadata
|
|
272
307
|
|
|
273
|
-
##
|
|
308
|
+
## 10. Representative specimens to read before editing the framework
|
|
274
309
|
|
|
275
310
|
Use this section when you want one small example before reading framework internals.
|
|
276
311
|
|
|
@@ -288,7 +323,7 @@ Use this section when you want one small example before reading framework intern
|
|
|
288
323
|
|
|
289
324
|
Together they give you the public integration, the advanced cell path, and the minimal cell path before you descend into the whole table runtime.
|
|
290
325
|
|
|
291
|
-
##
|
|
326
|
+
## 11. A compact reading strategy
|
|
292
327
|
|
|
293
328
|
When in doubt, use this order:
|
|
294
329
|
|
|
@@ -301,7 +336,7 @@ When in doubt, use this order:
|
|
|
301
336
|
|
|
302
337
|
That order usually gets you to the answer faster than starting from the deepest runtime files first.
|
|
303
338
|
|
|
304
|
-
##
|
|
339
|
+
## 12. Final takeaway
|
|
305
340
|
|
|
306
341
|
The fastest way to read Zova Table accurately is not to memorize every file in `a-table`.
|
|
307
342
|
|