Resource List Page Deep Dive
This guide explains the runtime path of a resource list page in Zova through the current public Cabloy Basic source.
Use this page when you want to understand:
- how a
/rest/resource/:resourceroute becomes a working list page - where the thin
rest-resourcelist shell stops - how
basic-page:blockPagetakes over the deeper list runtime - where
blockFilter,blockTable, andblockPagerfit into that runtime - how
ZTableandModelResourcecooperate under the list-page shell
Why this page exists
Several existing docs already explain important parts of the story:
- Generated Contract Consumption: List Branch explains the consumer-side handoff before the deeper runtime begins
- Rest Resource Under the Hood explains the module-level runtime bridge
- Rest Resource Source Reading Map explains the shortest file path into the module
- Table Guide and Zova Table Under the Hood explain the table runtime
- Table + Resource CRUD Cookbook explains authoring-oriented CRUD assembly
What those pages do not isolate directly is the one cohesive list-page runtime path from route entry into the deeper Basic page and table runtime.
That is the gap this page fills.
The shortest accurate mental model
A practical mental model is:
rest-resourcedeclares the generic resource list route- a generated page wrapper binds that route to
ControllerPageResource ControllerPageResourceis a thin shell that resolves the currentresource, loads top-level schema state, and rendersschemaRow.rest.blocks- those blocks usually enter
basic-page:blockPage blockPagebecomes the deeper list runtime owner for filter state, paging state, query state, and resource-backed list datablockFilter,blockTable, andblockPagerare specialized consumers of that shared page runtime/contextZTableis the final schema-driven table runtime endpoint under that list-page runtime
That means the resource list page is not one controller doing everything. It is a route shell plus downstream reusable list/runtime blocks.
This page focuses only on the list-page branch. For the broader module-level shell-to-runtime map shared by both list and entry pages, keep Rest Resource Source Reading Map as the general reference.
Source-confirmed reading path
When reading this topic, use this order:
zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/routes.tszova/src/suite-vendor/a-cabloy/modules/rest-resource/src/.metadata/page/resource.tszova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controller.tsxzova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.tszova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsxzova/src/suite/cabloy-basic/modules/basic-page/src/component/blockFilter/controller.tsxzova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsxzova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPager/controller.tsxzova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsxzova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx
That order moves from public route surface, to route wrapper, to list shell, to resource owner, to deeper list runtime, and finally to the schema-driven table runtime endpoint.
Runtime path by layer
1. Route list entry
The public route surface lives in:
zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/routes.tsThe list route is:
:resource
That already shows the public list-page contract:
- the route is generic
- runtime identity comes from
route.params.resource - the shared
tabKey(route)keeps list and entry pages grouped under one resource-oriented workspace
2. Generated page wrapper
The list-page wrapper lives in:
zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/.metadata/page/resource.tsThis file shows that the route enters runtime through the standard Zova page-controller path:
createZovaComponentPage(ControllerPageResource, ...)
That means the list page still begins as a controller-oriented page surface, not as ad hoc local route code.
3. Thin rest-resource list shell
The list shell lives in:
zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/page/resource/controller.tsxIts main jobs are:
- resolve the current selector-backed
ModelResource - autoload select API schemas
- read
schemaRow?.rest?.blocks - render those blocks through
ZovaJsx
This is the first key architectural boundary:
ControllerPageResourceis a thin list shell- it does not own the whole list runtime by itself
Its role is to interpret resource context, load top-level schema state, and let schema-defined blocks take over the deeper behavior.
4. ModelResource as the stable owner boundary
The owner model lives in:
zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.tsIts main jobs are:
- bootstrap the resource API path
- expose
permissions - expose schema surfaces such as
schemaFilterandschemaRow - expose
select(query)for list data - expose item/view/create/update/delete mutation/query helpers
This is the core owner boundary for the list page.
It is the stable resource-level runtime, even though the deeper list behavior is later assembled through Basic blocks.
5. basic-page:blockPage becomes the deeper list runtime owner
The most important current Basic list-runtime file is:
zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsxThis controller becomes the deeper owner for:
- selector-backed
ModelResource queryFilterDataqueryPaged- computed
query select(this.query)list dataschemaFilter,schemaRow, andpermissions- the shared page JSX/render context (
$$page) - permission-driven table-meta refresh through
tableRef.refreshMeta()
This is the second key architectural boundary:
- the route shell chooses the resource context
blockPageowns the real list/runtime state after blocks are rendered
6. blockFilter consumes the shared list-page context
The filter block lives in:
zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockFilter/controller.tsxThis block is a specialized consumer of the shared $$page runtime context.
Its role is to turn schema-driven filter UI into filter-state updates that flow back into the list-page query path.
That means filter state is not a separate unrelated subsystem. It is part of the shared list-page runtime owned by blockPage.
7. blockTable bridges the page runtime into ZTable
The table bridge lives in:
zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsxThis controller consumes $$page and passes the canonical page-owned values into ZTable, including:
dataschemaRowtableScope
It also captures the table controller ref back onto $$page.tableRef.
This is the clearest proof that blockTable is a bridge into table runtime, not the main owner of list state.
8. blockPager consumes paged state
The pager block lives in:
zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPager/controller.tsxIts role is to read paged state and delegate page changes back into the shared list-page runtime.
Like the filter and table blocks, it is another specialized consumer of the page runtime owned by blockPage.
9. ZTable is the schema-driven runtime endpoint
The deeper table endpoint lives in:
zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx
zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsxThis table runtime:
- loads schema properties for table rendering
- computes table metadata and columns
- creates column renderers
- turns schema-driven row metadata into visible table output
This is the final endpoint under the list-page runtime chain.
The shared handoff model
A useful rule is:
- the route shell resolves resource context
- schema-defined blocks choose which deeper list runtime pieces should appear
blockPagebecomes the shared host runtime ownerblockFilter,blockTable, andblockPagerare specialized consumers of that host-owned contextZTableis the final schema-driven render endpoint for rows and cells
That means the shared handoff is through $$page, not through scattered local page state.
What this guide does not re-explain
This page does not fully re-explain:
- the internals of
ModelResourceownership -> see Model Resource Owner Pattern - the internals of
ZTableitself -> see Zova Table Under the Hood - table authoring recipes -> see Table + Resource CRUD Cookbook
Its job is only to explain how the list-page runtime is assembled across route shell, resource owner, Basic blocks, and table runtime.
Debugging checklist
If a resource list page behaves unexpectedly, ask:
- is the route resolving the expected
resource? - is
ControllerPageResourceloading the expectedschemaRow.rest.blocks? - is the expected
basic-page:*block actually present in the schema? - is
blockPageresolving the expectedModelResourceselector state? - is filter state flowing into
queryFilterDataas expected? - is pager state flowing into
queryPagedas expected? - is
blockTablereceiving the expectedschemaRow,data, andpermissionsscope? - is table meta stale because the permission-driven refresh path is not firing where expected?
Where to read next
Use these next steps depending on your question:
- if you want the resource module bridge: Rest Resource Under the Hood
- if you want the shortest source map: Rest Resource Source Reading Map
- if you want the owner internals behind this runtime: ModelResource Internals Deep Dive
- if you want the narrower filter/query/select data path: Filter to Query to Select Data Flow Guide
- if you want the table runtime branch: Zova Table Under the Hood
- if you want row/bulk action visibility and permission gating: Table Action Visibility and Permission Flow Guide
- if you want the entry-page counterpart: Resource Entry Page Deep Dive
Final takeaway
The most accurate way to read a resource list page in the current Basic frontend is:
rest-resourcelist page is the thin route shellModelResourceis the stable owner boundarybasic-page:blockPageowns the real list runtimeblockFilter,blockTable, andblockPagerconsume the same shared page runtime contextZTableis the schema-driven runtime endpoint under that list-page chain
That is the source-confirmed list-page runtime path in the current Cabloy Basic frontend architecture.