cabloy 5.1.166 → 5.1.167

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.
Files changed (48) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/scheduled_tasks.lock +1 -1
  3. package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +1 -0
  4. package/CHANGELOG.md +13 -0
  5. package/package.json +1 -1
  6. package/repo-docs/frontend/page-params-guide.md +1 -1
  7. package/repo-docs/frontend/page-query-guide.md +6 -0
  8. package/repo-docs/frontend/zod-guide.md +9 -7
  9. package/repo-e2e/specs/routed-dialog.spec.ts +368 -0
  10. package/vona/pnpm-lock.yaml +6 -0
  11. package/zova/package.original.json +1 -1
  12. package/zova/packages-cli/cli/package.json +2 -2
  13. package/zova/packages-cli/cli-set-front/package.json +1 -1
  14. package/zova/packages-cli/cli-set-front/src/lib/bean/toolsMetadata/generateBeanGenerals.ts +1 -1
  15. package/zova/packages-cli/cli-set-front/src/lib/bean/toolsMetadata/generateScopeResources.ts +1 -1
  16. package/zova/packages-zova/zova/package.json +2 -2
  17. package/zova/pnpm-lock.yaml +2014 -2053
  18. package/zova/pnpm-workspace.yaml +1 -1
  19. package/zova/src/suite/a-demo/modules/demo-basic/src/.metadata/index.ts +66 -18
  20. package/zova/src/suite/a-demo/modules/demo-basic/src/.metadata/page/routedDialog.ts +9 -0
  21. package/zova/src/suite/a-demo/modules/demo-basic/src/.metadata/page/routedDialogDetail.ts +23 -0
  22. package/zova/src/suite/a-demo/modules/demo-basic/src/.metadata/page/routedDialogEntry.ts +23 -0
  23. package/zova/src/suite/a-demo/modules/demo-basic/src/page/routedDialog/controller.tsx +301 -0
  24. package/zova/src/suite/a-demo/modules/demo-basic/src/page/routedDialogDetail/controller.tsx +135 -0
  25. package/zova/src/suite/a-demo/modules/demo-basic/src/page/routedDialogEntry/controller.tsx +108 -0
  26. package/zova/src/suite/a-demo/modules/demo-basic/src/routes.ts +19 -0
  27. package/zova/src/suite/cabloy-basic/modules/basic-app/src/.metadata/component/routedDialog.ts +63 -0
  28. package/zova/src/suite/cabloy-basic/modules/basic-app/src/.metadata/index.ts +44 -2
  29. package/zova/src/suite/cabloy-basic/modules/basic-app/src/bean/behavior.appModal.tsx +306 -18
  30. package/zova/src/suite/cabloy-basic/modules/basic-app/src/component/routedDialog/controller.tsx +51 -0
  31. package/zova/src/suite/cabloy-basic/modules/basic-app/src/config/config.ts +19 -0
  32. package/zova/src/suite/cabloy-basic/modules/basic-app/src/config/locale/en-us.ts +1 -0
  33. package/zova/src/suite/cabloy-basic/modules/basic-app/src/config/locale/zh-cn.ts +1 -0
  34. package/zova/src/suite/cabloy-basic/modules/basic-app/src/lib/routedDialogHistory.ts +76 -0
  35. package/zova/src/suite/cabloy-basic/modules/basic-app/src/service/appModal.ts +156 -1
  36. package/zova/src/suite/cabloy-basic/modules/basic-app/src/types/appModal.ts +92 -13
  37. package/zova/src/suite/cabloy-basic/modules/basic-app/test/lib/routedDialogHistory.test.ts +92 -0
  38. package/zova/src/suite/cabloy-basic/modules/basic-app/test/lib/routedDialogRouter.test.ts +35 -0
  39. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  40. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +1 -1
  41. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  42. package/zova/src/suite-vendor/a-zova/modules/a-router/package.json +1 -1
  43. package/zova/src/suite-vendor/a-zova/modules/a-router/src/.metadata/index.ts +6 -6
  44. package/zova/src/suite-vendor/a-zova/modules/a-router/src/bean/bean.router.ts +60 -3
  45. package/zova/src/suite-vendor/a-zova/modules/a-router/src/bean/sys.router.ts +12 -0
  46. package/zova/src/suite-vendor/a-zova/modules/a-router/src/component/routerViewEmpty/controller.tsx +4 -1
  47. package/zova/src/suite-vendor/a-zova/modules/a-router/src/lib/routerViewBase.tsx +5 -1
  48. package/zova/src/suite-vendor/a-zova/package.json +2 -2
@@ -48,7 +48,7 @@ overrides:
48
48
  '@vue/reactivity': 'npm:@cabloy/vue-reactivity@^3.5.16'
49
49
  '@vue/server-renderer': 'npm:@cabloy/vue-server-renderer@^3.5.18'
50
50
  '@vue/shared': '3.5.13'
51
- vue-router: 'npm:@cabloy/vue-router@^4.4.16'
51
+ vue-router: 'npm:@cabloy/vue-router@^4.4.18'
52
52
  zod: 'npm:@cabloy/zod@4.3.8'
53
53
 
54
54
  allowBuilds:
@@ -26,7 +26,7 @@ declare module 'zova-module-demo-basic' {
26
26
  }
27
27
  /** model: end */
28
28
  /** model: begin */
29
- import { ModelTest } from '../model/test.js';
29
+ import type { ModelTest } from '../model/test.js';
30
30
  import 'zova';
31
31
  declare module 'zova' {
32
32
  export interface IBeanRecordGeneral {
@@ -44,6 +44,9 @@ export * from '../page/locale/controller.jsx';
44
44
  export * from '../page/routeParams/controller.jsx';
45
45
  export * from '../page/routeQuery/controller.jsx';
46
46
  export * from '../page/routeQueryB/controller.jsx';
47
+ export * from '../page/routedDialog/controller.jsx';
48
+ export * from '../page/routedDialogDetail/controller.jsx';
49
+ export * from '../page/routedDialogEntry/controller.jsx';
47
50
  export * from '../page/state/controller.jsx';
48
51
  export * from '../page/style/controller.jsx';
49
52
  export * from '../page/toolMinimal/controller.jsx';
@@ -102,6 +105,21 @@ declare module 'zova-module-demo-basic' {
102
105
  get scope(): ScopeModuleDemoBasic;
103
106
  }
104
107
 
108
+ export interface ControllerPageRoutedDialog {
109
+ /** @internal */
110
+ get scope(): ScopeModuleDemoBasic;
111
+ }
112
+
113
+ export interface ControllerPageRoutedDialogDetail {
114
+ /** @internal */
115
+ get scope(): ScopeModuleDemoBasic;
116
+ }
117
+
118
+ export interface ControllerPageRoutedDialogEntry {
119
+ /** @internal */
120
+ get scope(): ScopeModuleDemoBasic;
121
+ }
122
+
105
123
  export interface ControllerPageState {
106
124
  /** @internal */
107
125
  get scope(): ScopeModuleDemoBasic;
@@ -129,20 +147,23 @@ declare module 'zova-module-demo-basic' {
129
147
  }
130
148
  /** controller: end */
131
149
  /** controller: begin */
132
- import { ControllerActionView } from '../component/actionView/controller.jsx';
133
- import { ControllerCard } from '../component/card/controller.jsx';
134
- import { ControllerFormFieldTest } from '../component/formFieldTest/controller.jsx';
135
- import { ControllerTableCellTest } from '../component/tableCellTest/controller.jsx';
136
- import { ControllerPageComponent } from '../page/component/controller.jsx';
137
- import { ControllerPageLocale } from '../page/locale/controller.jsx';
138
- import { ControllerPageRouteParams } from '../page/routeParams/controller.jsx';
139
- import { ControllerPageRouteQuery } from '../page/routeQuery/controller.jsx';
140
- import { ControllerPageRouteQueryB } from '../page/routeQueryB/controller.jsx';
141
- import { ControllerPageState } from '../page/state/controller.jsx';
142
- import { ControllerPageStyle } from '../page/style/controller.jsx';
143
- import { ControllerPageToolMinimal } from '../page/toolMinimal/controller.jsx';
144
- import { ControllerPageToolOne } from '../page/toolOne/controller.jsx';
145
- import { ControllerPageToolTwo } from '../page/toolTwo/controller.jsx';
150
+ import type { ControllerActionView } from '../component/actionView/controller.jsx';
151
+ import type { ControllerCard } from '../component/card/controller.jsx';
152
+ import type { ControllerFormFieldTest } from '../component/formFieldTest/controller.jsx';
153
+ import type { ControllerTableCellTest } from '../component/tableCellTest/controller.jsx';
154
+ import type { ControllerPageComponent } from '../page/component/controller.jsx';
155
+ import type { ControllerPageLocale } from '../page/locale/controller.jsx';
156
+ import type { ControllerPageRouteParams } from '../page/routeParams/controller.jsx';
157
+ import type { ControllerPageRouteQuery } from '../page/routeQuery/controller.jsx';
158
+ import type { ControllerPageRouteQueryB } from '../page/routeQueryB/controller.jsx';
159
+ import type { ControllerPageRoutedDialog } from '../page/routedDialog/controller.jsx';
160
+ import type { ControllerPageRoutedDialogDetail } from '../page/routedDialogDetail/controller.jsx';
161
+ import type { ControllerPageRoutedDialogEntry } from '../page/routedDialogEntry/controller.jsx';
162
+ import type { ControllerPageState } from '../page/state/controller.jsx';
163
+ import type { ControllerPageStyle } from '../page/style/controller.jsx';
164
+ import type { ControllerPageToolMinimal } from '../page/toolMinimal/controller.jsx';
165
+ import type { ControllerPageToolOne } from '../page/toolOne/controller.jsx';
166
+ import type { ControllerPageToolTwo } from '../page/toolTwo/controller.jsx';
146
167
  import 'zova';
147
168
  declare module 'zova' {
148
169
  export interface IBeanRecordLocal {
@@ -155,6 +176,9 @@ declare module 'zova' {
155
176
  'demo-basic.controller.pageRouteParams': ControllerPageRouteParams;
156
177
  'demo-basic.controller.pageRouteQuery': ControllerPageRouteQuery;
157
178
  'demo-basic.controller.pageRouteQueryB': ControllerPageRouteQueryB;
179
+ 'demo-basic.controller.pageRoutedDialog': ControllerPageRoutedDialog;
180
+ 'demo-basic.controller.pageRoutedDialogDetail': ControllerPageRoutedDialogDetail;
181
+ 'demo-basic.controller.pageRoutedDialogEntry': ControllerPageRoutedDialogEntry;
158
182
  'demo-basic.controller.pageState': ControllerPageState;
159
183
  'demo-basic.controller.pageStyle': ControllerPageStyle;
160
184
  'demo-basic.controller.pageToolMinimal': ControllerPageToolMinimal;
@@ -172,6 +196,11 @@ export * from './page/routeQuery.js';
172
196
  import { NSControllerPageRouteQuery } from './page/routeQuery.js';
173
197
  export * from './page/routeQueryB.js';
174
198
  import { NSControllerPageRouteQueryB } from './page/routeQueryB.js';
199
+ export * from './page/routedDialog.js';
200
+ export * from './page/routedDialogDetail.js';
201
+ import { NSControllerPageRoutedDialogDetail } from './page/routedDialogDetail.js';
202
+ export * from './page/routedDialogEntry.js';
203
+ import { NSControllerPageRoutedDialogEntry } from './page/routedDialogEntry.js';
175
204
  export * from './page/state.js';
176
205
  export * from './page/style.js';
177
206
  export * from './page/toolMinimal.js';
@@ -189,6 +218,9 @@ export interface IPagePathRecord {
189
218
  '/demo/basic/routeParams/:id?': TypePagePathSchema<NSControllerPageRouteParams.ParamsInput,NSControllerPageRouteParams.QueryInput>;
190
219
  '/demo/basic/routeQuery': TypePagePathSchema<NSControllerPageRouteQuery.ParamsInput,NSControllerPageRouteQuery.QueryInput>;
191
220
  '/demo/basic/routeQueryB': TypePagePathSchema<NSControllerPageRouteQueryB.ParamsInput,NSControllerPageRouteQueryB.QueryInput>;
221
+ '/demo/basic/routedDialog': TypePagePathSchema<undefined,undefined>;
222
+ '/demo/basic/routedDialogDetail/:id': TypePagePathSchema<NSControllerPageRoutedDialogDetail.ParamsInput,NSControllerPageRoutedDialogDetail.QueryInput>;
223
+ '/demo/basic/routedDialogEntry': TypePagePathSchema<NSControllerPageRoutedDialogEntry.ParamsInput,NSControllerPageRoutedDialogEntry.QueryInput>;
192
224
  '/demo/basic/state': TypePagePathSchema<undefined,undefined>;
193
225
  '/demo/basic/style': TypePagePathSchema<undefined,undefined>;
194
226
  '/demo/basic/toolMinimal': TypePagePathSchema<undefined,undefined>;
@@ -197,6 +229,7 @@ export interface IPagePathRecord {
197
229
  }
198
230
  export interface IPageNameRecord {
199
231
  'demo-basic:routeParams': TypePagePathSchema<NSControllerPageRouteParams.ParamsInput,NSControllerPageRouteParams.QueryInput>;
232
+ 'demo-basic:routedDialogDetail': TypePagePathSchema<NSControllerPageRoutedDialogDetail.ParamsInput,NSControllerPageRoutedDialogDetail.QueryInput>;
200
233
  'demo-basic:toolMinimal': TypePagePathSchema<undefined,undefined>;
201
234
  'demo-basic:toolOne': TypePagePathSchema<NSControllerPageToolOne.ParamsInput,NSControllerPageToolOne.QueryInput>;
202
235
  'demo-basic:toolTwo': TypePagePathSchema<NSControllerPageToolTwo.ParamsInput,NSControllerPageToolTwo.QueryInput>;
@@ -209,12 +242,19 @@ export const pagePathSchemas = {
209
242
  '/demo/basic/routeQueryB': {
210
243
  query: NSControllerPageRouteQueryB.querySchema,
211
244
  },
245
+ '/demo/basic/routedDialogEntry': {
246
+ query: NSControllerPageRoutedDialogEntry.querySchema,
247
+ },
212
248
  };
213
249
  export const pageNameSchemas = {
214
250
  'demo-basic:routeParams': {
215
251
  params: NSControllerPageRouteParams.paramsSchema,
216
252
  query: NSControllerPageRouteParams.querySchema,
217
253
  },
254
+ 'demo-basic:routedDialogDetail': {
255
+ params: NSControllerPageRoutedDialogDetail.paramsSchema,
256
+ query: NSControllerPageRoutedDialogDetail.querySchema,
257
+ },
218
258
  'demo-basic:toolOne': {
219
259
  params: NSControllerPageToolOne.paramsSchema,
220
260
  query: NSControllerPageToolOne.querySchema,
@@ -237,6 +277,14 @@ export interface ControllerPageRouteQueryB {
237
277
  $params: NSControllerPageRouteQueryB.ParamsOutput;
238
278
  $query: NSControllerPageRouteQueryB.QueryOutput;
239
279
  }
280
+ export interface ControllerPageRoutedDialogDetail {
281
+ $params: NSControllerPageRoutedDialogDetail.ParamsOutput;
282
+ $query: NSControllerPageRoutedDialogDetail.QueryOutput;
283
+ }
284
+ export interface ControllerPageRoutedDialogEntry {
285
+ $params: NSControllerPageRoutedDialogEntry.ParamsOutput;
286
+ $query: NSControllerPageRoutedDialogEntry.QueryOutput;
287
+ }
240
288
  export interface ControllerPageToolOne {
241
289
  $params: NSControllerPageToolOne.ParamsOutput;
242
290
  $query: NSControllerPageToolOne.QueryOutput;
@@ -296,7 +344,7 @@ declare module 'zova-module-demo-basic' {
296
344
  }
297
345
  /** render: end */
298
346
  /** render: begin */
299
- import { RenderPageToolOne } from '../page/toolOne/render.jsx';
347
+ import type { RenderPageToolOne } from '../page/toolOne/render.jsx';
300
348
  import 'zova';
301
349
  declare module 'zova' {
302
350
  export interface IBeanRecordLocal {
@@ -331,7 +379,7 @@ declare module 'zova-module-demo-basic' {
331
379
  }
332
380
  /** behavior: end */
333
381
  /** behavior: begin */
334
- import { BehaviorFormFieldLayout } from '../bean/behavior.formFieldLayout.jsx';
382
+ import type { BehaviorFormFieldLayout } from '../bean/behavior.formFieldLayout.jsx';
335
383
  import 'zova';
336
384
  declare module 'zova' {
337
385
  export interface IBeanRecordLocal {
@@ -385,7 +433,7 @@ declare module 'zova-module-demo-basic' {
385
433
  }
386
434
  /** tableCell: end */
387
435
  /** tableCell: begin */
388
- import { TableCellTest } from '../bean/tableCell.test.jsx';
436
+ import type { TableCellTest } from '../bean/tableCell.test.jsx';
389
437
  import 'zova';
390
438
  declare module 'zova' {
391
439
  export interface IBeanRecordGeneral {
@@ -0,0 +1,9 @@
1
+ import { createZovaComponentPage } from 'zova';
2
+
3
+ import { ControllerPageRoutedDialog } from '../../page/routedDialog/controller.jsx';
4
+
5
+ export const ZPageRoutedDialog = createZovaComponentPage(
6
+ ControllerPageRoutedDialog,
7
+ undefined,
8
+ undefined,
9
+ );
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ import { createZovaComponentPage } from 'zova';
3
+
4
+ import { ControllerPageRoutedDialogDetail } from '../../page/routedDialogDetail/controller.jsx';
5
+ import {
6
+ ControllerPageRoutedDialogDetailSchemaParams,
7
+ ControllerPageRoutedDialogDetailSchemaQuery,
8
+ } from '../../page/routedDialogDetail/controller.jsx';
9
+ export namespace NSControllerPageRoutedDialogDetail {
10
+ export const paramsSchema = ControllerPageRoutedDialogDetailSchemaParams;
11
+ export type ParamsInput = z.input<typeof ControllerPageRoutedDialogDetailSchemaParams>;
12
+ export type ParamsOutput = z.output<typeof ControllerPageRoutedDialogDetailSchemaParams>;
13
+
14
+ export const querySchema = ControllerPageRoutedDialogDetailSchemaQuery;
15
+ export type QueryInput = z.input<typeof ControllerPageRoutedDialogDetailSchemaQuery>;
16
+ export type QueryOutput = z.output<typeof ControllerPageRoutedDialogDetailSchemaQuery>;
17
+ }
18
+
19
+ export const ZPageRoutedDialogDetail = createZovaComponentPage(
20
+ ControllerPageRoutedDialogDetail,
21
+ undefined,
22
+ undefined,
23
+ );
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ import { createZovaComponentPage } from 'zova';
3
+
4
+ import { ControllerPageRoutedDialogEntry } from '../../page/routedDialogEntry/controller.jsx';
5
+ import {
6
+ ControllerPageRoutedDialogEntrySchemaParams,
7
+ ControllerPageRoutedDialogEntrySchemaQuery,
8
+ } from '../../page/routedDialogEntry/controller.jsx';
9
+ export namespace NSControllerPageRoutedDialogEntry {
10
+ export const paramsSchema = ControllerPageRoutedDialogEntrySchemaParams;
11
+ export type ParamsInput = z.input<typeof ControllerPageRoutedDialogEntrySchemaParams>;
12
+ export type ParamsOutput = z.output<typeof ControllerPageRoutedDialogEntrySchemaParams>;
13
+
14
+ export const querySchema = ControllerPageRoutedDialogEntrySchemaQuery;
15
+ export type QueryInput = z.input<typeof ControllerPageRoutedDialogEntrySchemaQuery>;
16
+ export type QueryOutput = z.output<typeof ControllerPageRoutedDialogEntrySchemaQuery>;
17
+ }
18
+
19
+ export const ZPageRoutedDialogEntry = createZovaComponentPage(
20
+ ControllerPageRoutedDialogEntry,
21
+ undefined,
22
+ undefined,
23
+ );
@@ -0,0 +1,301 @@
1
+ import type {
2
+ IModalRoutedDialogPresentationOptions,
3
+ IRoutedDialogHandle,
4
+ } from 'zova-module-basic-app';
5
+
6
+ import { BeanControllerPageBase } from 'zova';
7
+ import { Controller } from 'zova-module-a-bean';
8
+ import { ZPage } from 'zova-module-home-base';
9
+
10
+ @Controller()
11
+ export class ControllerPageRoutedDialog extends BeanControllerPageBase {
12
+ handleA?: IRoutedDialogHandle;
13
+ handleB?: IRoutedDialogHandle;
14
+ statusA = 'idle';
15
+ statusB = 'idle';
16
+ browserUrl = '-';
17
+ browserUrlAtOpen?: string;
18
+ mainRouteAtOpen?: string;
19
+ events: string[] = [];
20
+
21
+ protected async __init__() {
22
+ this.$ssr.handleDirectOrOnHydrated(() => {
23
+ this.browserUrl = window.location.href;
24
+ });
25
+ }
26
+
27
+ openA() {
28
+ this._open('A');
29
+ }
30
+
31
+ openB() {
32
+ this._open('B');
33
+ }
34
+
35
+ openAAndB() {
36
+ this._open('A');
37
+ this._open('B');
38
+ }
39
+
40
+ openAWithHandlePush() {
41
+ const handle = this._open('A');
42
+ void this._navigateHandle(handle, 'push');
43
+ }
44
+
45
+ openAWithHandleReplace() {
46
+ const handle = this._open('A');
47
+ void this._navigateHandle(handle, 'replace');
48
+ }
49
+
50
+ openAWithBackdropClose() {
51
+ this._open('A', true);
52
+ }
53
+
54
+ openAAndClose() {
55
+ const handle = this._open('A');
56
+ void this._closeHandleAfterReady(handle);
57
+ }
58
+
59
+ openAWithScalarWidth() {
60
+ this._open('A', false, { maxWidth: 720 });
61
+ }
62
+
63
+ openAWithPartialResponsiveWidth() {
64
+ this._open('A', false, { maxWidth: { md: 800 } });
65
+ }
66
+
67
+ openAWithScalarTopGutter() {
68
+ this._open('A', false, { topGutter: 80 });
69
+ }
70
+
71
+ openAWithPartialResponsiveTopGutter() {
72
+ this._open('A', false, { topGutter: { md: 64 } });
73
+ }
74
+
75
+ private _open(
76
+ dialog: 'A' | 'B',
77
+ closeOnBackdrop = false,
78
+ dialogOptions?: IModalRoutedDialogPresentationOptions,
79
+ ) {
80
+ const route = this.$router.getPagePath('/demo/basic/routedDialogEntry', {
81
+ query: {
82
+ dialog,
83
+ token: `dialog-${dialog.toLowerCase()}-entry`,
84
+ via: 'open',
85
+ step: 0,
86
+ },
87
+ });
88
+ this.mainRouteAtOpen = this.$pageRoute?.fullPath;
89
+ this.browserUrlAtOpen = typeof window === 'undefined' ? undefined : window.location.href;
90
+ const handle = this.$appModal.routedDialog(
91
+ {
92
+ route,
93
+ title: `Routed Dialog ${dialog}`,
94
+ onClose: () => {
95
+ this._record(`${dialog}: onClose`);
96
+ if (dialog === 'A') {
97
+ this.statusA = 'closed';
98
+ this.handleA = undefined;
99
+ } else {
100
+ this.statusB = 'closed';
101
+ this.handleB = undefined;
102
+ }
103
+ },
104
+ },
105
+ {
106
+ closeOnBackdrop,
107
+ closeOnEscape: true,
108
+ showCloseButton: true,
109
+ ...dialogOptions,
110
+ },
111
+ );
112
+ if (dialog === 'A') {
113
+ this.handleA = handle;
114
+ this.statusA = 'loading';
115
+ } else {
116
+ this.handleB = handle;
117
+ this.statusB = 'loading';
118
+ }
119
+ void this._awaitReady(dialog, handle);
120
+ return handle;
121
+ }
122
+
123
+ private async _awaitReady(dialog: 'A' | 'B', handle: IRoutedDialogHandle) {
124
+ try {
125
+ await handle.ready;
126
+ if (dialog === 'A') this.statusA = 'ready';
127
+ else this.statusB = 'ready';
128
+ this._record(`${dialog}: ready`);
129
+ } catch (error) {
130
+ if (dialog === 'A') this.statusA = 'error';
131
+ else this.statusB = 'error';
132
+ this._record(`${dialog}: ${String(error)}`);
133
+ }
134
+ }
135
+
136
+ private async _navigateHandle(handle: IRoutedDialogHandle, action: 'push' | 'replace') {
137
+ try {
138
+ await handle.ready;
139
+ const route = this.$router.getPagePath('/demo/basic/routedDialogDetail/:id', {
140
+ params: { id: action === 'push' ? 101 : 202 },
141
+ query: {
142
+ dialog: 'A',
143
+ token: `dialog-a-handle-${action}`,
144
+ via: `handle-${action}`,
145
+ step: action === 'push' ? 1 : 2,
146
+ },
147
+ });
148
+ if (action === 'push') await handle.push(route);
149
+ else await handle.replace(route);
150
+ this._record(`A: handle.${action}`);
151
+ } catch (error) {
152
+ this._record(`A: handle.${action} ${String(error)}`);
153
+ }
154
+ }
155
+
156
+ private async _closeHandleAfterReady(handle: IRoutedDialogHandle) {
157
+ try {
158
+ await handle.ready;
159
+ this._record('A: ready for delayed handle.close');
160
+ setTimeout(() => {
161
+ handle.close();
162
+ this._record('A: handle.close');
163
+ }, 1500);
164
+ } catch (error) {
165
+ this._record(`A: delayed close ${String(error)}`);
166
+ }
167
+ }
168
+
169
+ private _record(event: string) {
170
+ this.events = [...this.events, event];
171
+ }
172
+
173
+ private async openStudentList() {
174
+ const route = this.$router.getPagePath('/rest/resource/:resource', {
175
+ params: {
176
+ resource: 'training-student:student',
177
+ },
178
+ });
179
+ this.$appModal.routedDialog({
180
+ route,
181
+ title: 'Student List',
182
+ });
183
+ }
184
+
185
+ protected render() {
186
+ return (
187
+ <ZPage>
188
+ <div class="mx-auto flex max-w-4xl flex-col gap-6">
189
+ <div>
190
+ <h1 class="text-2xl font-bold">Routed Dialog Manual Validation</h1>
191
+ <p class="mt-2 text-base-content/70">
192
+ Open a memory-history dialog and verify that every dialog route stays separate from
193
+ this browser route.
194
+ </p>
195
+ </div>
196
+
197
+ <div class="grid gap-4 md:grid-cols-2">
198
+ <div class="card bg-base-200">
199
+ <div class="card-body gap-2">
200
+ <h2 class="card-title text-base">Main route sentinel</h2>
201
+ <code class="break-all">{this.$pageRoute?.fullPath ?? '-'}</code>
202
+ <code class="break-all">{this.browserUrl}</code>
203
+ </div>
204
+ </div>
205
+ <div class="card bg-base-200">
206
+ <div class="card-body gap-2">
207
+ <h2 class="card-title text-base">Route at latest open</h2>
208
+ <code class="break-all">{this.mainRouteAtOpen ?? '-'}</code>
209
+ <code class="break-all">{this.browserUrlAtOpen ?? '-'}</code>
210
+ </div>
211
+ </div>
212
+ </div>
213
+
214
+ <div class="flex flex-wrap gap-2">
215
+ <button class="btn btn-primary" onClick={() => this.openA()}>
216
+ Open A
217
+ </button>
218
+ <button class="btn btn-secondary" onClick={() => this.openB()}>
219
+ Open B
220
+ </button>
221
+ <button class="btn btn-outline" onClick={() => this.openAAndB()}>
222
+ Open A and B
223
+ </button>
224
+ <button class="btn btn-outline" onClick={() => this.openAWithHandlePush()}>
225
+ Open A with handle.push
226
+ </button>
227
+ <button class="btn btn-outline" onClick={() => this.openAWithHandleReplace()}>
228
+ Open A with handle.replace
229
+ </button>
230
+ <button class="btn btn-outline" onClick={() => this.openAWithBackdropClose()}>
231
+ Open A (backdrop close)
232
+ </button>
233
+ <button class="btn btn-outline" onClick={() => this.openAAndClose()}>
234
+ Open A then handle.close
235
+ </button>
236
+ <button class="btn btn-outline" onClick={() => this.openAWithScalarWidth()}>
237
+ Open A (720px width)
238
+ </button>
239
+ <button class="btn btn-outline" onClick={() => this.openAWithPartialResponsiveWidth()}>
240
+ Open A (md 800px width)
241
+ </button>
242
+ <button class="btn btn-outline" onClick={() => this.openAWithScalarTopGutter()}>
243
+ Open A (80px top gutter)
244
+ </button>
245
+ <button
246
+ class="btn btn-outline"
247
+ onClick={() => this.openAWithPartialResponsiveTopGutter()}
248
+ >
249
+ Open A (md 64px top gutter)
250
+ </button>
251
+ </div>
252
+
253
+ <div class="overflow-x-auto">
254
+ <table class="table">
255
+ <thead>
256
+ <tr>
257
+ <th>Dialog</th>
258
+ <th>Status</th>
259
+ <th>Handle</th>
260
+ </tr>
261
+ </thead>
262
+ <tbody>
263
+ <tr>
264
+ <td>A</td>
265
+ <td>{this.statusA}</td>
266
+ <td>{this.handleA ? 'active' : '-'}</td>
267
+ </tr>
268
+ <tr>
269
+ <td>B</td>
270
+ <td>{this.statusB}</td>
271
+ <td>{this.handleB ? 'active' : '-'}</td>
272
+ </tr>
273
+ </tbody>
274
+ </table>
275
+ </div>
276
+
277
+ <div class="card bg-base-200">
278
+ <div class="card-body">
279
+ <h2 class="card-title text-base">Lifecycle log</h2>
280
+ <ol class="list-inside list-decimal font-mono text-sm">
281
+ {this.events.map((event, index) => (
282
+ <li key={`${index}-${event}`}>{event}</li>
283
+ ))}
284
+ </ol>
285
+ </div>
286
+ </div>
287
+ <div>
288
+ <button
289
+ class="btn btn-outline"
290
+ onClick={() => {
291
+ this.openStudentList();
292
+ }}
293
+ >
294
+ Student List
295
+ </button>
296
+ </div>
297
+ </div>
298
+ </ZPage>
299
+ );
300
+ }
301
+ }
@@ -0,0 +1,135 @@
1
+ import { RouterLink } from '@cabloy/vue-router';
2
+ import { z } from 'zod';
3
+ import { BeanControllerPageBase } from 'zova';
4
+ import { Controller } from 'zova-module-a-bean';
5
+ import { ZPage } from 'zova-module-home-base';
6
+
7
+ export const ControllerPageRoutedDialogDetailSchemaParams = z.object({
8
+ id: z.number(),
9
+ });
10
+
11
+ export const ControllerPageRoutedDialogDetailSchemaQuery = z.object({
12
+ dialog: z.enum(['A', 'B']).optional().default('A'),
13
+ token: z.string().optional().default('detail'),
14
+ via: z.string().optional().default('unknown'),
15
+ step: z.number().optional().default(0),
16
+ });
17
+
18
+ @Controller()
19
+ export class ControllerPageRoutedDialogDetail extends BeanControllerPageBase {
20
+ get entryRoute() {
21
+ return this.$router.getPagePath('/demo/basic/routedDialogEntry', {
22
+ query: {
23
+ ...this.$query,
24
+ token: `${this.$query.token}-entry`,
25
+ via: 'detail-entry',
26
+ step: this.$query.step + 1,
27
+ },
28
+ });
29
+ }
30
+
31
+ pushNextDetail() {
32
+ const route = this.$router.getPagePath('/demo/basic/routedDialogDetail/:id', {
33
+ params: { id: this.$params.id + 1 },
34
+ query: {
35
+ ...this.$query,
36
+ token: `${this.$query.token}-push`,
37
+ via: 'detail-push',
38
+ step: this.$query.step + 1,
39
+ },
40
+ });
41
+ this.$router.push(route);
42
+ }
43
+
44
+ replaceNextDetail() {
45
+ const route = this.$router.getPagePath('/demo/basic/routedDialogDetail/:id', {
46
+ params: { id: this.$params.id + 10 },
47
+ query: {
48
+ ...this.$query,
49
+ token: `${this.$query.token}-replace`,
50
+ via: 'detail-replace',
51
+ step: this.$query.step + 10,
52
+ },
53
+ });
54
+ this.$router.replace(route);
55
+ }
56
+
57
+ protected render() {
58
+ return (
59
+ <ZPage>
60
+ <div class="flex flex-col gap-4 p-1">
61
+ <div>
62
+ <h1 class="text-xl font-bold">Routed Dialog Detail</h1>
63
+ <p class="text-base-content/70">
64
+ The typed route state below belongs to this routed-dialog instance only.
65
+ </p>
66
+ </div>
67
+
68
+ <div class="overflow-x-auto">
69
+ <table class="table">
70
+ <thead>
71
+ <tr>
72
+ <th>Name</th>
73
+ <th>Value</th>
74
+ <th>Type</th>
75
+ </tr>
76
+ </thead>
77
+ <tbody>
78
+ <tr>
79
+ <td>$pageRoute.fullPath</td>
80
+ <td class="break-all">{this.$pageRoute?.fullPath}</td>
81
+ <td>string</td>
82
+ </tr>
83
+ <tr>
84
+ <td>$route.fullPath</td>
85
+ <td class="break-all">{this.$route.fullPath}</td>
86
+ <td>string</td>
87
+ </tr>
88
+ <tr>
89
+ <td>$params.id</td>
90
+ <td>{this.$params.id}</td>
91
+ <td>{typeof this.$params.id}</td>
92
+ </tr>
93
+ <tr>
94
+ <td>$query.dialog</td>
95
+ <td>{this.$query.dialog}</td>
96
+ <td>{typeof this.$query.dialog}</td>
97
+ </tr>
98
+ <tr>
99
+ <td>$query.token</td>
100
+ <td>{this.$query.token}</td>
101
+ <td>{typeof this.$query.token}</td>
102
+ </tr>
103
+ <tr>
104
+ <td>$query.via</td>
105
+ <td>{this.$query.via}</td>
106
+ <td>{typeof this.$query.via}</td>
107
+ </tr>
108
+ <tr>
109
+ <td>$query.step</td>
110
+ <td>{this.$query.step}</td>
111
+ <td>{typeof this.$query.step}</td>
112
+ </tr>
113
+ </tbody>
114
+ </table>
115
+ </div>
116
+
117
+ <div class="flex flex-wrap gap-2">
118
+ <button class="btn btn-primary" onClick={() => this.pushNextDetail()}>
119
+ Local push next detail
120
+ </button>
121
+ <button class="btn btn-secondary" onClick={() => this.replaceNextDetail()}>
122
+ Local replace next detail
123
+ </button>
124
+ <button class="btn btn-outline" onClick={() => this.$router.back()}>
125
+ Local router.back
126
+ </button>
127
+ <RouterLink class="btn btn-outline" to={this.entryRoute}>
128
+ RouterLink back to entry
129
+ </RouterLink>
130
+ </div>
131
+ </div>
132
+ </ZPage>
133
+ );
134
+ }
135
+ }