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,367 @@
|
|
|
1
|
+
# Router Tabs Layout Integration
|
|
2
|
+
|
|
3
|
+
This guide explains how the current Cabloy Basic layouts turn `ModelTabs` into visible router shell behavior in Zova.
|
|
4
|
+
|
|
5
|
+
Use this page after [Router View Hosts Guide](/frontend/router-view-hosts-guide) and [Router Tabs Mechanism](/frontend/router-tabs-mechanism) when your next question is no longer “how does the tabs model work?” but “how do the real layout controllers and render beans turn that model into the Admin or Web shell?”.
|
|
6
|
+
|
|
7
|
+
Read this page together with:
|
|
8
|
+
|
|
9
|
+
- [Router View Hosts Guide](/frontend/router-view-hosts-guide)
|
|
10
|
+
- [Router Tabs Introduction](/frontend/router-tabs-introduction)
|
|
11
|
+
- [Router Tabs Mechanism](/frontend/router-tabs-mechanism)
|
|
12
|
+
- [Page Meta Guide](/frontend/page-meta-guide)
|
|
13
|
+
- [Router Tabs Admin and Web Comparison](/frontend/router-tabs-admin-web-comparison)
|
|
14
|
+
- [Zova Source Reading Map](/frontend/zova-source-reading-map)
|
|
15
|
+
|
|
16
|
+
> [!TIP]
|
|
17
|
+
> **Router ecosystem docs path**
|
|
18
|
+
> 1. **[Page Route Guide](/frontend/page-route-guide)** — learn the public route-record and layout surface
|
|
19
|
+
> 2. **[Zova Router Under the Hood](/frontend/zova-router-under-the-hood)** — learn how the core router runtime cooperates
|
|
20
|
+
> 3. **[Router View Hosts Guide](/frontend/router-view-hosts-guide)** — learn how routed pages are actually hosted
|
|
21
|
+
> 4. **[Router Tabs Mechanism](/frontend/router-tabs-mechanism)** — learn how the tabs host turns route visits into state
|
|
22
|
+
> 5. **[Router Tabs Layout Integration](/frontend/router-tabs-layout-integration)** — learn how the current Basic layouts turn that state into visible shell behavior
|
|
23
|
+
> 6. **[Router Tabs Route Meta Cookbook](/frontend/router-tabs-route-meta-cookbook)** — learn how route metadata intentionally drives the model
|
|
24
|
+
>
|
|
25
|
+
> **You are here:** step 5.
|
|
26
|
+
> **Previous pages:** [Router View Hosts Guide](/frontend/router-view-hosts-guide) and [Router Tabs Mechanism](/frontend/router-tabs-mechanism).
|
|
27
|
+
> **Next recommended page:** [Router Tabs Route Meta Cookbook](/frontend/router-tabs-route-meta-cookbook).
|
|
28
|
+
|
|
29
|
+
## Why this page exists
|
|
30
|
+
|
|
31
|
+
The current router-tabs docs already explain:
|
|
32
|
+
|
|
33
|
+
- the business meaning of router tabs
|
|
34
|
+
- the shared `ModelTabs` mechanism
|
|
35
|
+
- the Admin vs Web visual comparison
|
|
36
|
+
- the route-meta inputs that drive the model
|
|
37
|
+
|
|
38
|
+
What contributors and AI workflows still often want next is the layout-integration bridge:
|
|
39
|
+
|
|
40
|
+
- where `ModelTabs` is created inside a real layout controller
|
|
41
|
+
- how the layout chooses `tabsOptions`
|
|
42
|
+
- how the render bean turns `tabs` into a visible shell
|
|
43
|
+
- which parts are shared model semantics and which parts are layout presentation
|
|
44
|
+
|
|
45
|
+
This page is that bridge.
|
|
46
|
+
|
|
47
|
+
If your next question is specifically about how page code feeds task-level title, dirty state, or form scene into the visible shell, continue with [Page Meta Guide](/frontend/page-meta-guide).
|
|
48
|
+
|
|
49
|
+
## The shortest accurate mental model
|
|
50
|
+
|
|
51
|
+
For the current public Cabloy Basic source, the shortest accurate model is:
|
|
52
|
+
|
|
53
|
+
1. the layout controller loads menus and creates a `ModelTabs` selector bean
|
|
54
|
+
2. the layout passes layout-specific `tabsOptions` such as `scene`, `max`, `maxItems`, and `cache`
|
|
55
|
+
3. the shared `ZRouterViewTabs` host keeps route visits and keep-alive behavior synchronized with `ModelTabs`
|
|
56
|
+
4. the layout render bean reads `$$modelTabs.tabs`, `tabCurrent`, and related state to produce the visible shell
|
|
57
|
+
5. Admin and Web reuse the same underlying tabs model but project it into different top-level UI structures
|
|
58
|
+
|
|
59
|
+
That is why layout integration is not merely cosmetic. It is the point where shared router-tabs state becomes the concrete shell experience.
|
|
60
|
+
|
|
61
|
+
## The source files that matter most
|
|
62
|
+
|
|
63
|
+
### Admin layout integration
|
|
64
|
+
|
|
65
|
+
- `zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx`
|
|
66
|
+
- `zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.tabs.tsx`
|
|
67
|
+
- `zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts`
|
|
68
|
+
|
|
69
|
+
### Web layout integration
|
|
70
|
+
|
|
71
|
+
- `zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx`
|
|
72
|
+
- `zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.tabs.tsx`
|
|
73
|
+
- `zova/src/suite/a-home/modules/home-layoutweb/src/config/config.ts`
|
|
74
|
+
|
|
75
|
+
### Shared host/model layer used by both
|
|
76
|
+
|
|
77
|
+
- `zova/src/suite-vendor/a-zova/modules/a-routertabs/src/component/routerViewTabs/controller.tsx`
|
|
78
|
+
- `zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts`
|
|
79
|
+
|
|
80
|
+
## Step-by-step layout integration path
|
|
81
|
+
|
|
82
|
+
### 1. The layout controller, not the render bean, creates `ModelTabs`
|
|
83
|
+
|
|
84
|
+
The real integration starts in the layout controller.
|
|
85
|
+
|
|
86
|
+
In both Admin and Web, the controller is where:
|
|
87
|
+
|
|
88
|
+
- menus are loaded
|
|
89
|
+
- tabs config is read from the layout scope config
|
|
90
|
+
- a selector-scoped `ModelTabs` bean is created
|
|
91
|
+
- later menu changes refresh or reset visible tab info
|
|
92
|
+
|
|
93
|
+
This is the first important source-level fact about layout integration:
|
|
94
|
+
|
|
95
|
+
- **the render bean does not own tabs state**
|
|
96
|
+
- **the layout controller owns the decision to create and configure the tabs model**
|
|
97
|
+
|
|
98
|
+
## 2. Admin layout integration
|
|
99
|
+
|
|
100
|
+
Representative controller source:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Zova-native role
|
|
107
|
+
|
|
108
|
+
The Admin layout controller creates a workbench-oriented tabs model whose top level is anchored to menu-backed business workspaces.
|
|
109
|
+
|
|
110
|
+
### Source-confirmed runtime behavior
|
|
111
|
+
|
|
112
|
+
Inside `_initTabs()` the Admin layout:
|
|
113
|
+
|
|
114
|
+
- reads `this.scope.config.tabs`
|
|
115
|
+
- builds `tabsOptions`
|
|
116
|
+
- uses `this.bean._getBeanSelector('a-routertabs.model.tabs', true, configTabs.scene, tabsOptions)`
|
|
117
|
+
- keeps the selected model on `this.$$modelTabs`
|
|
118
|
+
- watches menu data and calls `updateAllTabInfos()` when menus change
|
|
119
|
+
|
|
120
|
+
The important Admin-specific `tabsOptions` behavior is:
|
|
121
|
+
|
|
122
|
+
- `getInitialTabs()` returns `[{ tabKey: '/', affix: true }]` once menus are available
|
|
123
|
+
- `getTabInfo(tabKey)` resolves title and icon from the menu model by `link`
|
|
124
|
+
|
|
125
|
+
That means the Admin layout does two important things for the shared tabs model:
|
|
126
|
+
|
|
127
|
+
1. it guarantees a fixed affixed top-level home workspace
|
|
128
|
+
2. it derives visible workspace labels from menu-backed business information rather than from temporary page state
|
|
129
|
+
|
|
130
|
+
### Why this matters
|
|
131
|
+
|
|
132
|
+
This is why Admin level-1 tabs feel stable and business-oriented.
|
|
133
|
+
|
|
134
|
+
The model itself is generic, but the layout controller injects business-facing tab identity and the initial affixed workspace rule.
|
|
135
|
+
|
|
136
|
+
## 3. Admin render integration
|
|
137
|
+
|
|
138
|
+
Representative render source:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.tabs.tsx
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Zova-native role
|
|
145
|
+
|
|
146
|
+
The Admin render bean turns `ModelTabs` into an explicit two-level workbench shell.
|
|
147
|
+
|
|
148
|
+
### Source-confirmed runtime behavior
|
|
149
|
+
|
|
150
|
+
The render bean exposes three main surfaces:
|
|
151
|
+
|
|
152
|
+
- `renderTabs()` for level-1 workspace tabs
|
|
153
|
+
- `renderTabItems()` for level-2 task items
|
|
154
|
+
- `_renderRouterViewTabs()` for the actual routed host outlet
|
|
155
|
+
|
|
156
|
+
Important details:
|
|
157
|
+
|
|
158
|
+
- level-1 rows iterate over `$$modelTabs.tabs`
|
|
159
|
+
- clicking a level-1 tab calls `$$modelTabs.activeTab(tabKey)`
|
|
160
|
+
- non-affix level-1 tabs expose `deleteTab(tabKey)`
|
|
161
|
+
- level-2 rows read `$$modelTabs.tabCurrent.items`
|
|
162
|
+
- the anchor item is intentionally skipped when `componentKey === tabKey`
|
|
163
|
+
- clicking a level-2 item calls `activeTabItem(tabKey, componentKey)`
|
|
164
|
+
- deleting a level-2 item calls `deleteTabItem(...)`
|
|
165
|
+
- page-level icon state is derived from `pageMeta` such as `pageDirty` and `formMeta.formScene`
|
|
166
|
+
- the actual routed content still enters through `<ZRouterViewTabs>`
|
|
167
|
+
|
|
168
|
+
For the authoring-side write path that produces those `pageMeta` values, see [Page Meta Guide](/frontend/page-meta-guide).
|
|
169
|
+
|
|
170
|
+
This is the second important source-level fact about layout integration:
|
|
171
|
+
|
|
172
|
+
- **the layout render bean does not replace the router host**
|
|
173
|
+
- **it wraps the shared host with a visible shell that reads the same model state**
|
|
174
|
+
|
|
175
|
+
### What the Admin shell makes visible
|
|
176
|
+
|
|
177
|
+
Admin makes these model semantics explicit:
|
|
178
|
+
|
|
179
|
+
- level-1 workspace grouping
|
|
180
|
+
- level-2 task items
|
|
181
|
+
- dirty indicators
|
|
182
|
+
- create/edit task indicators
|
|
183
|
+
- close actions for both outer and inner levels
|
|
184
|
+
|
|
185
|
+
That is why Admin is the clearest business-meaning specimen for router tabs.
|
|
186
|
+
|
|
187
|
+
## 4. Web layout integration
|
|
188
|
+
|
|
189
|
+
Representative controller source:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Zova-native role
|
|
196
|
+
|
|
197
|
+
The Web layout controller creates a tabs model that is still shared in semantics, but whose initial top-level state is derived from the menu tree rather than from one affixed home workspace.
|
|
198
|
+
|
|
199
|
+
### Source-confirmed runtime behavior
|
|
200
|
+
|
|
201
|
+
Inside `_initTabs()` the Web layout:
|
|
202
|
+
|
|
203
|
+
- reads `this.scope.config.tabs`
|
|
204
|
+
- builds `tabsOptions`
|
|
205
|
+
- creates the same selector-scoped `ModelTabs` bean
|
|
206
|
+
- watches menu data and calls `resetAllTabInfos()` when menus change
|
|
207
|
+
|
|
208
|
+
The important Web-specific `tabsOptions` behavior is:
|
|
209
|
+
|
|
210
|
+
- `getInitialTabs()` returns one item per top-level menu tree entry
|
|
211
|
+
- each initial tab uses `item.folder ? item.name : item.link` as `tabKey`
|
|
212
|
+
- `info` is stored directly from the menu tree item
|
|
213
|
+
|
|
214
|
+
That means the Web layout treats top-level workspace entries more like shell navigation nodes than like one pre-affixed home workspace plus later-opened work areas.
|
|
215
|
+
|
|
216
|
+
### Why this matters
|
|
217
|
+
|
|
218
|
+
This is why the Web shell can feel menu-driven at the top level while still relying on the same `ModelTabs` state underneath.
|
|
219
|
+
|
|
220
|
+
The model stays shared, but the controller chooses a different initialization strategy.
|
|
221
|
+
|
|
222
|
+
## 5. Web render integration
|
|
223
|
+
|
|
224
|
+
Representative render source:
|
|
225
|
+
|
|
226
|
+
```text
|
|
227
|
+
zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.tabs.tsx
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Zova-native role
|
|
231
|
+
|
|
232
|
+
The Web render bean projects the same tabs model into a horizontal menu-like shell.
|
|
233
|
+
|
|
234
|
+
### Source-confirmed runtime behavior
|
|
235
|
+
|
|
236
|
+
The render bean:
|
|
237
|
+
|
|
238
|
+
- iterates over `$$modelTabs.tabs`
|
|
239
|
+
- renders top-level entries through `_renderMenuItem(...)`
|
|
240
|
+
- supports folder, separator, and leaf menu shapes
|
|
241
|
+
- uses `tabKey === $$modelTabs.tabKeyCurrent` for top-level active state
|
|
242
|
+
- lets top-level shell clicks call `$$modelTabs.activeTab(tabKey)`
|
|
243
|
+
- lets nested leaf links navigate through `RouterLink`
|
|
244
|
+
- still renders the actual routed content through `<ZRouterViewTabs>`
|
|
245
|
+
|
|
246
|
+
This is the third important source-level fact about layout integration:
|
|
247
|
+
|
|
248
|
+
- **Web does not abandon the tabs model**
|
|
249
|
+
- **it simply renders the top-level workspace state through a menu-oriented shell instead of an explicit lifted tab row**
|
|
250
|
+
|
|
251
|
+
## 6. Config is part of layout integration, not an afterthought
|
|
252
|
+
|
|
253
|
+
Representative config sources:
|
|
254
|
+
|
|
255
|
+
- `zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts`
|
|
256
|
+
- `zova/src/suite/a-home/modules/home-layoutweb/src/config/config.ts`
|
|
257
|
+
|
|
258
|
+
### Current Basic source values
|
|
259
|
+
|
|
260
|
+
Admin:
|
|
261
|
+
|
|
262
|
+
- `scene: ''`
|
|
263
|
+
- `max: 6`
|
|
264
|
+
- `maxItems: 3`
|
|
265
|
+
- `cache: true`
|
|
266
|
+
- `tabItem.maxWidth: '130px'`
|
|
267
|
+
|
|
268
|
+
Web:
|
|
269
|
+
|
|
270
|
+
- `scene: 'web'`
|
|
271
|
+
- `max: 6`
|
|
272
|
+
- `maxItems: 6`
|
|
273
|
+
- `cache: false`
|
|
274
|
+
|
|
275
|
+
### Why this matters
|
|
276
|
+
|
|
277
|
+
These config differences directly shape shell behavior:
|
|
278
|
+
|
|
279
|
+
- `scene` chooses the selector-space identity of the tabs model
|
|
280
|
+
- `max` and `maxItems` change pruning density
|
|
281
|
+
- `cache` changes whether shell state is restored through cached model state
|
|
282
|
+
- Admin-only `tabItem.maxWidth` shapes inner task-row presentation
|
|
283
|
+
|
|
284
|
+
A practical reading takeaway is:
|
|
285
|
+
|
|
286
|
+
- **layout integration includes controller logic, render logic, and config together**
|
|
287
|
+
|
|
288
|
+
## 7. What is shared vs what is layout-specific
|
|
289
|
+
|
|
290
|
+
### Shared semantics
|
|
291
|
+
|
|
292
|
+
These remain in the shared model/host layer:
|
|
293
|
+
|
|
294
|
+
- route-to-workspace mapping
|
|
295
|
+
- `tabKey` and `componentKey` meaning
|
|
296
|
+
- keep-alive inclusion
|
|
297
|
+
- activation and pruning behavior
|
|
298
|
+
- page-meta storage on tab items
|
|
299
|
+
- routed content entering through `ZRouterViewTabs`
|
|
300
|
+
|
|
301
|
+
### Layout-specific behavior
|
|
302
|
+
|
|
303
|
+
These belong mainly to the layout integration layer:
|
|
304
|
+
|
|
305
|
+
- how top-level entries are initialized from menu state
|
|
306
|
+
- whether there is an affixed home workspace
|
|
307
|
+
- whether the second level is shown explicitly
|
|
308
|
+
- whether the top level looks like tabs or a horizontal menu
|
|
309
|
+
- how close buttons, item width, and icon density are presented
|
|
310
|
+
|
|
311
|
+
This is the key boundary to preserve:
|
|
312
|
+
|
|
313
|
+
- **change shared semantics in the host/model layer only when the framework contract should change**
|
|
314
|
+
- **change visual shell behavior in the layout layer when only presentation should change**
|
|
315
|
+
|
|
316
|
+
## 8. A practical reading order for source readers
|
|
317
|
+
|
|
318
|
+
If your question is specifically about how `ModelTabs` becomes a visible shell, use this order:
|
|
319
|
+
|
|
320
|
+
1. `zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts`
|
|
321
|
+
2. `zova/src/suite-vendor/a-zova/modules/a-routertabs/src/component/routerViewTabs/controller.tsx`
|
|
322
|
+
3. `zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx`
|
|
323
|
+
4. `zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/render.tabs.tsx`
|
|
324
|
+
5. `zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx`
|
|
325
|
+
6. `zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.tabs.tsx`
|
|
326
|
+
7. the two layout config files
|
|
327
|
+
|
|
328
|
+
Use Admin first when you want the clearest expression of the workbench model.
|
|
329
|
+
Use Web next when you want to confirm that the same model can back a different shell style.
|
|
330
|
+
|
|
331
|
+
## Common mistakes to avoid
|
|
332
|
+
|
|
333
|
+
### Mistake 1: treating the layout render bean as the tabs state owner
|
|
334
|
+
|
|
335
|
+
It is not.
|
|
336
|
+
|
|
337
|
+
The render bean projects state visually. The controller and shared model own the state.
|
|
338
|
+
|
|
339
|
+
### Mistake 2: assuming Admin-specific tab rows define the whole router-tabs contract
|
|
340
|
+
|
|
341
|
+
They do not.
|
|
342
|
+
|
|
343
|
+
Admin is one visible projection of a broader routed-host and tabs-model contract.
|
|
344
|
+
|
|
345
|
+
### Mistake 3: assuming Web is not using router tabs because it looks like a menu
|
|
346
|
+
|
|
347
|
+
It is still using `ModelTabs` and `ZRouterViewTabs`.
|
|
348
|
+
|
|
349
|
+
Only the shell projection differs.
|
|
350
|
+
|
|
351
|
+
### Mistake 4: changing layout presentation when the real change belongs in `ModelTabs`
|
|
352
|
+
|
|
353
|
+
If the behavior should be shared across shells, change the shared model/host layer first.
|
|
354
|
+
|
|
355
|
+
If only the visible shell should differ, change the layout layer first.
|
|
356
|
+
|
|
357
|
+
## Edition note
|
|
358
|
+
|
|
359
|
+
This guide is source-confirmed against the current public Cabloy Basic layouts.
|
|
360
|
+
|
|
361
|
+
That means the integration story here is accurate for the current Basic Admin and Web shells, but should not be overgeneralized to every future edition or downstream layout without verification.
|
|
362
|
+
|
|
363
|
+
## Final takeaway
|
|
364
|
+
|
|
365
|
+
If [Router Tabs Mechanism](/frontend/router-tabs-mechanism) explains how the shared tabs model works, this page explains how the real Basic layouts turn that shared model into visible shell behavior.
|
|
366
|
+
|
|
367
|
+
That is the missing bridge between framework-level tabs semantics and the actual layout code contributors edit.
|
|
@@ -4,6 +4,10 @@ This guide explains how the router-tabs mechanism works in Zova within the Cablo
|
|
|
4
4
|
|
|
5
5
|
For the business meaning of the mechanism, see [Router Tabs Overview](/frontend/router-tabs-overview).
|
|
6
6
|
|
|
7
|
+
If you came here from [Router View Hosts Guide](/frontend/router-view-hosts-guide), this page is the next layer down: the host guide explains routed-host choice, while this page explains the shared `ModelTabs` semantics behind that host.
|
|
8
|
+
|
|
9
|
+
If your next question becomes specifically about how a page author should update task-level title, dirty state, or form scene through `$router.setPageMeta(...)`, continue with [Page Meta Guide](/frontend/page-meta-guide).
|
|
10
|
+
|
|
7
11
|
## Why this mechanism exists
|
|
8
12
|
|
|
9
13
|
The router-tabs mechanism is designed to support a workbench-style frontend navigation model.
|
|
@@ -288,6 +292,8 @@ Representative page metadata includes:
|
|
|
288
292
|
|
|
289
293
|
This metadata shapes the visible state of the level-2 tab.
|
|
290
294
|
|
|
295
|
+
For authoring-focused guidance on when page code should call `$router.setPageMeta(...)` and how to keep that separate from route meta, see [Page Meta Guide](/frontend/page-meta-guide).
|
|
296
|
+
|
|
291
297
|
### `pageTitle`
|
|
292
298
|
|
|
293
299
|
`pageTitle` is typically used as the displayed title of the level-2 item.
|
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This guide provides practical route-meta recipes for the router-tabs mechanism in Zova within the Cabloy monorepo.
|
|
4
4
|
|
|
5
|
+
If you came here from [Router View Hosts Guide](/frontend/router-view-hosts-guide), [Router Tabs Mechanism](/frontend/router-tabs-mechanism), or [Router Tabs Layout Integration](/frontend/router-tabs-layout-integration), this page is the authoring layer: the earlier pages explain host/runtime behavior, and this page explains how route metadata intentionally drives it.
|
|
6
|
+
|
|
5
7
|
Read this together with:
|
|
6
8
|
|
|
7
9
|
- [Router Tabs Introduction](/frontend/router-tabs-introduction)
|
|
8
10
|
- [Page Route Guide](/frontend/page-route-guide)
|
|
9
11
|
- [Router Tabs Overview](/frontend/router-tabs-overview)
|
|
10
12
|
- [Router Tabs Mechanism](/frontend/router-tabs-mechanism)
|
|
13
|
+
- [Router Tabs Layout Integration](/frontend/router-tabs-layout-integration)
|
|
11
14
|
|
|
12
15
|
## Why this cookbook exists
|
|
13
16
|
|
|
@@ -39,6 +42,10 @@ Representative source definition:
|
|
|
39
42
|
|
|
40
43
|
Use this decision split first:
|
|
41
44
|
|
|
45
|
+
- [Router View Hosts Guide](/frontend/router-view-hosts-guide) explains where host-level routed identity is consumed
|
|
46
|
+
- [Router Tabs Mechanism](/frontend/router-tabs-mechanism) explains how `ModelTabs` turns route data into tab state
|
|
47
|
+
- this page explains how to choose the route-meta inputs that drive that model
|
|
48
|
+
|
|
42
49
|
- `tabKey` answers: which level-1 workspace should this route belong to?
|
|
43
50
|
- `componentKey` answers: should this route visit reuse an existing page instance or remain separately open?
|
|
44
51
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Router Tabs vs Stack
|
|
2
|
+
|
|
3
|
+
This guide explains when to think in **Router Tabs** and when to think in **Router Stack** in Zova.
|
|
4
|
+
|
|
5
|
+
Use this page when you want to answer questions like:
|
|
6
|
+
|
|
7
|
+
- should this routed host behave like a workbench or like a linear routed stack?
|
|
8
|
+
- when do I need `tabKey` and `componentKey`?
|
|
9
|
+
- when is `fullPath` identity enough?
|
|
10
|
+
- when should page-meta-aware work items exist, and when are they unnecessary?
|
|
11
|
+
|
|
12
|
+
## Why this comparison exists
|
|
13
|
+
|
|
14
|
+
The current frontend docs already explain the two nearby branches separately:
|
|
15
|
+
|
|
16
|
+
- [Router Tabs Introduction](/frontend/router-tabs-introduction) and the rest of the tabs series explain the workbench-tabs branch
|
|
17
|
+
- [Router Stack Guide](/frontend/router-stack-guide) explains the stack branch
|
|
18
|
+
- [Router View Hosts Guide](/frontend/router-view-hosts-guide) explains the shared routed-host layer above both
|
|
19
|
+
|
|
20
|
+
What many readers still need next is a decision page.
|
|
21
|
+
|
|
22
|
+
That is the gap this guide fills.
|
|
23
|
+
|
|
24
|
+
This page is intentionally a chooser between two host models. For the shared host boundary, keep [Router View Hosts Guide](/frontend/router-view-hosts-guide) as the main reference, and use this page only when the host question has already narrowed to tabs vs stack.
|
|
25
|
+
|
|
26
|
+
## The shortest accurate mental model
|
|
27
|
+
|
|
28
|
+
A practical mental model is:
|
|
29
|
+
|
|
30
|
+
- **Router Tabs** = a workbench model with business/workspace grouping plus page-instance identity
|
|
31
|
+
- **Router Stack** = a linear routed-cache model where each route visit is one host identity
|
|
32
|
+
|
|
33
|
+
If you need grouped workspaces and task-level state, think in Tabs.
|
|
34
|
+
|
|
35
|
+
If you need a simple per-visit routed stack, think in Stack.
|
|
36
|
+
|
|
37
|
+
## The core difference in one table
|
|
38
|
+
|
|
39
|
+
| Question | Router Tabs | Router Stack |
|
|
40
|
+
| ------------------------------------------------ | ------------------------------------------- | ------------------------------------------------------- |
|
|
41
|
+
| What owns the host state? | `ModelTabs` | `ModelStack` |
|
|
42
|
+
| What is the host controller? | `ControllerRouterViewTabs` | `ControllerRouterViewStack` |
|
|
43
|
+
| What is the main identity model? | `tabKey` + `componentKey` | `fullPath` |
|
|
44
|
+
| What is `tabKey` for? | level-1 workspace grouping | same as `fullPath` identity |
|
|
45
|
+
| What is `componentKey` for? | level-2 page-instance identity | same as `fullPath` identity |
|
|
46
|
+
| Does it support workbench semantics? | yes | no |
|
|
47
|
+
| Does it support page-meta-aware task updates? | yes | no dedicated stack equivalent |
|
|
48
|
+
| What kind of pruning does it do? | tab/work-item pruning inside the tabs model | linear recency-based pruning |
|
|
49
|
+
| What is the current public Basic shell emphasis? | visible and central | framework primitive, not the main visible shell pattern |
|
|
50
|
+
|
|
51
|
+
## Identity model: Tabs
|
|
52
|
+
|
|
53
|
+
The tabs branch separates two questions:
|
|
54
|
+
|
|
55
|
+
1. which business/workspace does this route belong to?
|
|
56
|
+
2. which page instance inside that workspace is this?
|
|
57
|
+
|
|
58
|
+
That is why `ModelTabs` works with both:
|
|
59
|
+
|
|
60
|
+
- `tabKey`
|
|
61
|
+
- `componentKey`
|
|
62
|
+
|
|
63
|
+
A compact interpretation is:
|
|
64
|
+
|
|
65
|
+
- `tabKey` = level-1 grouping identity
|
|
66
|
+
- `componentKey` = level-2 page-instance identity
|
|
67
|
+
|
|
68
|
+
This is the right model when multiple routed visits should still belong to one durable business workspace.
|
|
69
|
+
|
|
70
|
+
## Identity model: Stack
|
|
71
|
+
|
|
72
|
+
The stack branch collapses routed identity to `fullPath`.
|
|
73
|
+
|
|
74
|
+
In `ModelStack.prepareRouteMeta(...)`, the stack host returns:
|
|
75
|
+
|
|
76
|
+
- `tabKey = route.fullPath`
|
|
77
|
+
- `componentKey = route.fullPath`
|
|
78
|
+
- `fullPath = route.fullPath`
|
|
79
|
+
|
|
80
|
+
That means a stack visit is treated as one linear routed entry.
|
|
81
|
+
|
|
82
|
+
This is the right model when per-visit identity is enough and you do not need a separate workspace grouping layer.
|
|
83
|
+
|
|
84
|
+
## Page-meta and workbench semantics
|
|
85
|
+
|
|
86
|
+
The tabs branch supports richer task/workbench semantics.
|
|
87
|
+
|
|
88
|
+
In the current public source:
|
|
89
|
+
|
|
90
|
+
- `ControllerRouterViewTabs` forwards `setPageMeta(...)`
|
|
91
|
+
- `ModelTabs` stores and updates page-meta information per routed work item
|
|
92
|
+
|
|
93
|
+
That makes tabs a good fit for:
|
|
94
|
+
|
|
95
|
+
- workbench titles
|
|
96
|
+
- dirty state
|
|
97
|
+
- task-level UI state that belongs to an open work item
|
|
98
|
+
|
|
99
|
+
The stack branch does not add that richer page-meta ownership model.
|
|
100
|
+
|
|
101
|
+
That is why stack should not be treated as “tabs with fewer UI decorations.” It is a different host model.
|
|
102
|
+
|
|
103
|
+
## Choose Tabs when
|
|
104
|
+
|
|
105
|
+
Choose Router Tabs when you need:
|
|
106
|
+
|
|
107
|
+
- stable business/workspace grouping
|
|
108
|
+
- more than one open work item inside that grouping
|
|
109
|
+
- page-instance reuse decisions separate from workspace identity
|
|
110
|
+
- task-level page-meta behavior
|
|
111
|
+
- the current public Basic Admin/Web-style workbench semantics
|
|
112
|
+
|
|
113
|
+
This is the normal fit for the existing Router Tabs series.
|
|
114
|
+
|
|
115
|
+
## Choose Stack when
|
|
116
|
+
|
|
117
|
+
Choose Router Stack when you need:
|
|
118
|
+
|
|
119
|
+
- a simpler per-visit routed host
|
|
120
|
+
- one identity per route visit
|
|
121
|
+
- bounded linear routed caching
|
|
122
|
+
- recency-based pruning without workbench grouping
|
|
123
|
+
- no tabs-style page-meta/workspace semantics
|
|
124
|
+
|
|
125
|
+
This is the normal fit when `fullPath` identity is the main thing that matters.
|
|
126
|
+
|
|
127
|
+
## Current Cabloy Basic visibility note
|
|
128
|
+
|
|
129
|
+
In the current public Basic source:
|
|
130
|
+
|
|
131
|
+
- Router Tabs are the visibly emphasized shell model in the existing public layout docs
|
|
132
|
+
- Router Stack exists as a real framework host primitive
|
|
133
|
+
- Router Stack should therefore be understood as an available routed-host strategy, not as the most prominent visible Basic shell pattern
|
|
134
|
+
|
|
135
|
+
This distinction matters because the framework capability and the currently emphasized public shell are not always the same thing.
|
|
136
|
+
|
|
137
|
+
## Suggested decision rule
|
|
138
|
+
|
|
139
|
+
Use this quick rule:
|
|
140
|
+
|
|
141
|
+
1. do you need a durable business/workspace grouping layer?
|
|
142
|
+
- yes -> choose **Router Tabs**
|
|
143
|
+
- no -> continue
|
|
144
|
+
2. do you only need each route visit to behave like one linear cached routed item?
|
|
145
|
+
- yes -> choose **Router Stack**
|
|
146
|
+
- no -> re-check whether you actually need tabs-level semantics
|
|
147
|
+
|
|
148
|
+
## Read together with
|
|
149
|
+
|
|
150
|
+
Use this page together with:
|
|
151
|
+
|
|
152
|
+
- [Router View Hosts Guide](/frontend/router-view-hosts-guide)
|
|
153
|
+
- [Router Tabs Introduction](/frontend/router-tabs-introduction)
|
|
154
|
+
- [Router Tabs Mechanism](/frontend/router-tabs-mechanism)
|
|
155
|
+
- [Router Stack Guide](/frontend/router-stack-guide)
|
|
156
|
+
- [A-Router Guide](/frontend/a-router-guide)
|
|
157
|
+
|
|
158
|
+
## Final takeaway
|
|
159
|
+
|
|
160
|
+
The most accurate distinction is:
|
|
161
|
+
|
|
162
|
+
- **Router Tabs** are for grouped workbench semantics
|
|
163
|
+
- **Router Stack** is for linear routed-cache semantics
|
|
164
|
+
|
|
165
|
+
If you need workspace grouping, task identity, and page-meta-aware work items, think in Tabs.
|
|
166
|
+
|
|
167
|
+
If you need one identity per route visit with simpler recency-based caching, think in Stack.
|