cabloy 5.1.162 → 5.1.164

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 (96) hide show
  1. package/.cabloy-version +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/README.md +2 -0
  4. package/package.json +1 -1
  5. package/repo-docs/backend/shared-rbac-architecture.md +4 -0
  6. package/repo-docs/blogs/ai-spec-driven-development/cover-en-v1.png +0 -0
  7. package/repo-docs/blogs/ai-spec-driven-development/implementation-burndown.png +0 -0
  8. package/repo-docs/blogs/ai-spec-driven-development/implementation-gantt.png +0 -0
  9. package/repo-docs/blogs/ai-spec-driven-development/index.md +217 -0
  10. package/repo-docs/blogs/index.md +15 -0
  11. package/repo-docs/editions/overview.md +2 -0
  12. package/repo-docs/frontend/environment-config-guide.md +43 -10
  13. package/repo-docs/frontend/resource-list-page-deep-dive.md +14 -1
  14. package/repo-docs/frontend/table-action-visibility-permission-flow-guide.md +20 -0
  15. package/repo-docs/frontend/table-guide.md +42 -0
  16. package/repo-docs/frontend/table-resource-crud-cookbook.md +25 -1
  17. package/repo-e2e/docs/specs/blogs-index.spec.ts +45 -9
  18. package/repo-e2e/specs/cabloy-basic.spec.ts +249 -2
  19. package/vona/packages-cli/cli/package.json +1 -1
  20. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/controller/{{resourceName}}.ts_ +17 -6
  21. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}DeleteBulk.tsx_ +14 -0
  22. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}SelectResItem.tsx_ +7 -1
  23. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/service/{{resourceName}}.ts_ +6 -0
  24. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/3-en-us.ts +12 -1
  25. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/4-zh-cn.ts +12 -1
  26. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/controller/{{resourceName}}.ts_ +8 -0
  27. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}DeleteBulk.tsx_ +14 -0
  28. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}SelectResItem.tsx_ +7 -1
  29. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/service/{{resourceName}}.ts_ +6 -0
  30. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/snippets/3-en-us.ts +1 -0
  31. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/snippets/4-zh-cn.ts +1 -0
  32. package/vona/packages-cli/cli-set-api/package.json +1 -1
  33. package/vona/packages-vona/vona/package.json +1 -1
  34. package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +9 -0
  35. package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +1 -0
  36. package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +1 -0
  37. package/vona/src/suite/a-training/modules/training-student/src/controller/student.ts +9 -0
  38. package/vona/src/suite/a-training/modules/training-student/src/dto/studentDeleteBulk.tsx +14 -0
  39. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +7 -1
  40. package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +6 -0
  41. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +114 -2
  42. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
  43. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/.metadata/index.ts +24 -3
  44. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/.metadata/locales.ts +18 -0
  45. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/bean/bean.rbacResourceBulk.ts +50 -0
  46. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/bean/index.ts +1 -0
  47. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/config/errors.ts +18 -0
  48. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/config/locale/en-us.ts +6 -0
  49. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/config/locale/zh-cn.ts +6 -0
  50. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/src/index.ts +1 -0
  51. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/test/resourceBulk.test.ts +128 -0
  52. package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
  53. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  54. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  55. package/zova/packages-cli/cli/package.json +2 -2
  56. package/zova/packages-cli/cli-set-front/cli/templates/create/component/boilerplateTableActionBulk/controller.tsx_ +2 -2
  57. package/zova/packages-cli/cli-set-front/package.json +1 -1
  58. package/zova/packages-zova/zova/package.json +2 -2
  59. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +16 -12
  60. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +66 -7
  61. package/zova/src/suite/a-training/modules/training-student/src/api/trainingStudent.ts +18 -0
  62. package/zova/src/suite/a-training/modules/training-student/src/apiSchema/trainingStudent.ts +5 -0
  63. package/zova/src/suite/cabloy-basic/modules/basic-commands/src/.metadata/index.ts +16 -0
  64. package/zova/src/suite/cabloy-basic/modules/basic-commands/src/bean/command.deleteBulk.tsx +35 -0
  65. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +143 -7
  66. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +3 -2
  67. package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockToolbarBulk/controller.tsx +76 -4
  68. package/zova/src/suite/cabloy-basic/modules/basic-page/src/config/locale/en-us.ts +7 -0
  69. package/zova/src/suite/cabloy-basic/modules/basic-page/src/config/locale/zh-cn.ts +6 -0
  70. package/zova/src/suite/cabloy-basic/modules/basic-page/src/lib/selection.ts +84 -0
  71. package/zova/src/suite/cabloy-basic/modules/basic-page/test/lib/selection.test.ts +99 -0
  72. package/zova/src/suite/cabloy-basic/modules/basic-table/src/.metadata/component/actionDeleteBulk.ts +31 -0
  73. package/zova/src/suite/cabloy-basic/modules/basic-table/src/.metadata/index.ts +13 -0
  74. package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/actionCreate/controller.tsx +5 -2
  75. package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/actionDeleteBulk/controller.tsx +57 -0
  76. package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +35 -7
  77. package/zova/src/suite/cabloy-basic/modules/basic-table/src/config/locale/en-us.ts +4 -0
  78. package/zova/src/suite/cabloy-basic/modules/basic-table/src/config/locale/zh-cn.ts +4 -0
  79. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  80. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/lib/selectedIds.ts +15 -0
  81. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +57 -0
  82. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/test/lib/selectedIds.test.ts +20 -0
  83. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  84. package/zova/src/suite-vendor/a-zova/modules/a-command/package.json +1 -1
  85. package/zova/src/suite-vendor/a-zova/modules/a-command/src/lib/beanCommandSelectedBase.ts +33 -0
  86. package/zova/src/suite-vendor/a-zova/modules/a-command/src/lib/index.ts +1 -0
  87. package/zova/src/suite-vendor/a-zova/modules/a-command/src/types/command.ts +5 -0
  88. package/zova/src/suite-vendor/a-zova/modules/a-command/test/lib/beanCommandSelectedBase.test.ts +47 -0
  89. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  90. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/action.ts +3 -0
  91. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/resource/tableActionBulk.ts +19 -0
  92. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  93. package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +86 -26
  94. package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx +30 -6
  95. package/zova/src/suite-vendor/a-zova/modules/a-table/src/types/table.ts +2 -0
  96. package/zova/src/suite-vendor/a-zova/package.json +4 -4
@@ -366,10 +366,10 @@ export type ApiSchemaCommerceCatalogDtoProductPublicDetail_2d063d28bc7243bed02eb
366
366
  components['schemas']['commerce-catalog.dto.productPublicDetail_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
367
367
  export type ApiSchemaCommerceCatalogDtoProductPublicDetail_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
368
368
  Partial<ApiSchemaCommerceCatalogDtoProductPublicDetail_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
369
- export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7 =
370
- components['schemas']['commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7'];
371
- export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7Partial =
372
- Partial<ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7>;
369
+ export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57 =
370
+ components['schemas']['commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57'];
371
+ export type ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57Partial =
372
+ Partial<ApiSchemaCommerceCatalogDtoProductView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57>;
373
373
  export type ApiSchemaCommerceCatalogDtoProductUpdate =
374
374
  components['schemas']['commerce-catalog.dto.productUpdate'];
375
375
  export type ApiSchemaCommerceCatalogDtoProductUpdatePartial =
@@ -435,10 +435,10 @@ export type ApiSchemaAImageDtoImageView = components['schemas']['a-image.dto.ima
435
435
  export type ApiSchemaAImageDtoImageViewPartial = Partial<ApiSchemaAImageDtoImageView>;
436
436
  export type ApiSchemaAFileDtoFileView = components['schemas']['a-file.dto.fileView'];
437
437
  export type ApiSchemaAFileDtoFileViewPartial = Partial<ApiSchemaAFileDtoFileView>;
438
- export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875 =
439
- components['schemas']['training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875'];
440
- export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875Partial =
441
- Partial<ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875>;
438
+ export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347 =
439
+ components['schemas']['training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347'];
440
+ export type ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347Partial =
441
+ Partial<ApiSchemaTrainingRecordDtoRecordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347>;
442
442
  export type ApiSchemaTrainingRecordDtoRecordUpdate =
443
443
  components['schemas']['training-record.dto.recordUpdate'];
444
444
  export type ApiSchemaTrainingRecordDtoRecordUpdatePartial =
@@ -463,10 +463,10 @@ export type ApiSchemaAImageDtoImageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1
463
463
  components['schemas']['a-image.dto.imageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1_2d063d28bc7243bed02ebd8bddf1212a93c6305b_efb37794d7c03c65122279f90d79919f009c34e5_1816ff740d81c738ec055c7038bbd93beb9405a7_537cd6552a384183a9457fb6a920bbae337277f6'];
464
464
  export type ApiSchemaAImageDtoImageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1_2d063d28bc7243bed02ebd8bddf1212a93c6305b_efb37794d7c03c65122279f90d79919f009c34e5_1816ff740d81c738ec055c7038bbd93beb9405a7_537cd6552a384183a9457fb6a920bbae337277f6Partial =
465
465
  Partial<ApiSchemaAImageDtoImageView_a83c3e638bca4b30ec8675860cdc52d66f6a16d1_2d063d28bc7243bed02ebd8bddf1212a93c6305b_efb37794d7c03c65122279f90d79919f009c34e5_1816ff740d81c738ec055c7038bbd93beb9405a7_537cd6552a384183a9457fb6a920bbae337277f6>;
466
- export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_93b863fbe913f9389386c3f524075f08b39f48ac =
467
- components['schemas']['training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_93b863fbe913f9389386c3f524075f08b39f48ac'];
468
- export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_93b863fbe913f9389386c3f524075f08b39f48acPartial =
469
- Partial<ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_93b863fbe913f9389386c3f524075f08b39f48ac>;
466
+ export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60 =
467
+ components['schemas']['training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60'];
468
+ export type ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60Partial =
469
+ Partial<ApiSchemaTrainingStudentDtoStudentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60>;
470
470
  export type ApiSchemaTrainingStudentDtoStudentUpdate =
471
471
  components['schemas']['training-student.dto.studentUpdate'];
472
472
  export type ApiSchemaTrainingStudentDtoStudentUpdatePartial =
@@ -475,6 +475,10 @@ export type ApiSchemaTrainingStudentDtoStudentSummary_2d063d28bc7243bed02ebd8bdd
475
475
  components['schemas']['training-student.dto.studentSummary_2d063d28bc7243bed02ebd8bddf1212a93c6305b'];
476
476
  export type ApiSchemaTrainingStudentDtoStudentSummary_2d063d28bc7243bed02ebd8bddf1212a93c6305bPartial =
477
477
  Partial<ApiSchemaTrainingStudentDtoStudentSummary_2d063d28bc7243bed02ebd8bddf1212a93c6305b>;
478
+ export type ApiSchemaTrainingStudentDtoStudentDeleteBulk =
479
+ components['schemas']['training-student.dto.studentDeleteBulk'];
480
+ export type ApiSchemaTrainingStudentDtoStudentDeleteBulkPartial =
481
+ Partial<ApiSchemaTrainingStudentDtoStudentDeleteBulk>;
478
482
  export type ApiSchemaBasicMetricsDtoMetricsSnapshot =
479
483
  components['schemas']['basic-metrics.dto.metricsSnapshot'];
480
484
  export type ApiSchemaBasicMetricsDtoMetricsSnapshotPartial =
@@ -1344,6 +1344,23 @@ export interface paths {
1344
1344
  patch?: never;
1345
1345
  trace?: never;
1346
1346
  };
1347
+ '/api/training/student/bulk/delete': {
1348
+ parameters: {
1349
+ query?: never;
1350
+ header?: never;
1351
+ path?: never;
1352
+ cookie?: never;
1353
+ };
1354
+ get?: never;
1355
+ put?: never;
1356
+ /** Bulk Delete */
1357
+ post: operations['TrainingStudent_deleteBulk'];
1358
+ delete?: never;
1359
+ options?: never;
1360
+ head?: never;
1361
+ patch?: never;
1362
+ trace?: never;
1363
+ };
1347
1364
  '/api/training/student/deleteForce/{id}': {
1348
1365
  parameters: {
1349
1366
  query?: never;
@@ -2674,6 +2691,8 @@ export interface components {
2674
2691
  }
2675
2692
  | undefined;
2676
2693
  siteIds: string[];
2694
+ /** @default false */
2695
+ builtin?: boolean;
2677
2696
  };
2678
2697
  'home-user.dto.passportJwt': {
2679
2698
  passport: components['schemas']['home-user.dto.passport'];
@@ -3550,6 +3569,7 @@ export interface components {
3550
3569
  /** @description Description */
3551
3570
  description?: string | undefined;
3552
3571
  };
3572
+ /** @description Create product */
3553
3573
  'commerce-catalog.dto.productCreate': {
3554
3574
  /** @description Product title */
3555
3575
  title: string;
@@ -3674,7 +3694,8 @@ export interface components {
3674
3694
  descriptionHtml?: string | undefined;
3675
3695
  }
3676
3696
  | undefined;
3677
- 'commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7':
3697
+ /** @description Product details */
3698
+ 'commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57':
3678
3699
  | {
3679
3700
  /**
3680
3701
  * Format: date-time
@@ -3729,6 +3750,7 @@ export interface components {
3729
3750
  };
3730
3751
  }
3731
3752
  | undefined;
3753
+ /** @description Update product */
3732
3754
  'commerce-catalog.dto.productUpdate': {
3733
3755
  /** @description Product title */
3734
3756
  title: string;
@@ -3948,6 +3970,7 @@ export interface components {
3948
3970
  siteId: string;
3949
3971
  title: string;
3950
3972
  };
3973
+ /** @description Add Student Training Record */
3951
3974
  'training-record.dto.recordCreate': {
3952
3975
  /** @description Training Record Name */
3953
3976
  name: string;
@@ -4089,7 +4112,8 @@ export interface components {
4089
4112
  /** @default true */
4090
4113
  signed?: boolean;
4091
4114
  };
4092
- 'training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875':
4115
+ /** @description View Student Training Record */
4116
+ 'training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347':
4093
4117
  | {
4094
4118
  /**
4095
4119
  * Format: date-time
@@ -4164,6 +4188,7 @@ export interface components {
4164
4188
  | undefined;
4165
4189
  }
4166
4190
  | undefined;
4191
+ /** @description Edit Student Training Record */
4167
4192
  'training-record.dto.recordUpdate': {
4168
4193
  /** @description Training Record Name */
4169
4194
  name: string;
@@ -4208,6 +4233,7 @@ export interface components {
4208
4233
  | components['schemas']['training-record.dto.detailRecordSubjectResItem'][]
4209
4234
  | undefined;
4210
4235
  };
4236
+ /** @description Add Student */
4211
4237
  'training-student.dto.studentCreate': {
4212
4238
  /** @description Student Name */
4213
4239
  name: string;
@@ -4412,7 +4438,8 @@ export interface components {
4412
4438
  signed?: boolean;
4413
4439
  }
4414
4440
  | undefined;
4415
- 'training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_93b863fbe913f9389386c3f524075f08b39f48ac':
4441
+ /** @description View Student */
4442
+ 'training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60':
4416
4443
  | {
4417
4444
  /**
4418
4445
  * Format: date-time
@@ -4530,6 +4557,7 @@ export interface components {
4530
4557
  _descriptionMarkdown?: string | undefined;
4531
4558
  }
4532
4559
  | undefined;
4560
+ /** @description Edit Student */
4533
4561
  'training-student.dto.studentUpdate': {
4534
4562
  /** @description Student Name */
4535
4563
  name: string;
@@ -4655,6 +4683,9 @@ export interface components {
4655
4683
  summaryText: string;
4656
4684
  }
4657
4685
  | undefined;
4686
+ 'training-student.dto.studentDeleteBulk': {
4687
+ ids: (number | string)[];
4688
+ };
4658
4689
  'basic-metrics.dto.metricsSnapshot': {
4659
4690
  enabled: boolean;
4660
4691
  runtime: components['schemas']['basic-metrics.dto.metricsRuntime'];
@@ -7589,7 +7620,7 @@ export interface operations {
7589
7620
  'application/json': {
7590
7621
  code: string;
7591
7622
  message: string;
7592
- data?: components['schemas']['commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_9a6ea970b2f00d574b88030d8c96cbf7b1e699d7'];
7623
+ data?: components['schemas']['commerce-catalog.dto.productView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_a2f92cabb46b0630848b50414c0d4c60efb47a57'];
7593
7624
  };
7594
7625
  };
7595
7626
  };
@@ -7910,7 +7941,7 @@ export interface operations {
7910
7941
  pageSize?: number;
7911
7942
  createdAt?: string | undefined;
7912
7943
  name?: string | undefined;
7913
- studentId?: number | undefined;
7944
+ studentId?: string | undefined;
7914
7945
  };
7915
7946
  header?: never;
7916
7947
  path?: never;
@@ -7980,7 +8011,7 @@ export interface operations {
7980
8011
  'application/json': {
7981
8012
  code: string;
7982
8013
  message: string;
7983
- data?: components['schemas']['training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_425dbecccd52e19e24888f99e1b1670233afa875'];
8014
+ data?: components['schemas']['training-record.dto.recordView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_7d715789d9643740a04e8a6c0f6fb951884bc347'];
7984
8015
  };
7985
8016
  };
7986
8017
  };
@@ -8127,7 +8158,7 @@ export interface operations {
8127
8158
  'application/json': {
8128
8159
  code: string;
8129
8160
  message: string;
8130
- data?: components['schemas']['training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_93b863fbe913f9389386c3f524075f08b39f48ac'];
8161
+ data?: components['schemas']['training-student.dto.studentView_2d063d28bc7243bed02ebd8bddf1212a93c6305b_4826fc678e47603ec467782ddb0d02463792cd60'];
8131
8162
  };
8132
8163
  };
8133
8164
  };
@@ -8216,6 +8247,34 @@ export interface operations {
8216
8247
  };
8217
8248
  authToken: true;
8218
8249
  };
8250
+ TrainingStudent_deleteBulk: {
8251
+ parameters: {
8252
+ query?: never;
8253
+ header?: never;
8254
+ path?: never;
8255
+ cookie?: never;
8256
+ };
8257
+ requestBody: {
8258
+ content: {
8259
+ 'application/json': components['schemas']['training-student.dto.studentDeleteBulk'];
8260
+ };
8261
+ };
8262
+ responses: {
8263
+ 200: {
8264
+ headers: {
8265
+ [name: string]: unknown;
8266
+ };
8267
+ content: {
8268
+ 'application/json': {
8269
+ code: string;
8270
+ message: string;
8271
+ data: undefined;
8272
+ };
8273
+ };
8274
+ };
8275
+ };
8276
+ authToken: true;
8277
+ };
8219
8278
  TrainingStudent_deleteForce: {
8220
8279
  parameters: {
8221
8280
  query?: never;
@@ -62,6 +62,15 @@ export type ApiApiTrainingStudentsummaryRequestParams =
62
62
  export type ApiApiTrainingStudentsummaryResponseBody =
63
63
  paths[ApiApiTrainingStudentsummaryPath][ApiApiTrainingStudentsummaryMethod]['responses']['200']['content']['application/json']['data'];
64
64
 
65
+ /** TrainingStudent_deleteBulk */
66
+ export const ApiApiTrainingStudentdeleteBulkPath = '/api/training/student/bulk/delete';
67
+ export type ApiApiTrainingStudentdeleteBulkPath = '/api/training/student/bulk/delete';
68
+ export type ApiApiTrainingStudentdeleteBulkMethod = 'post';
69
+ export type ApiApiTrainingStudentdeleteBulkRequestBody =
70
+ components['schemas']['training-student.dto.studentDeleteBulk'];
71
+ export type ApiApiTrainingStudentdeleteBulkResponseBody =
72
+ paths[ApiApiTrainingStudentdeleteBulkPath][ApiApiTrainingStudentdeleteBulkMethod]['responses']['200']['content']['application/json']['data'];
73
+
65
74
  /** TrainingStudent_deleteForce */
66
75
  export const ApiApiTrainingStudentdeleteForcePath = '/api/training/student/deleteForce/{id}';
67
76
  export type ApiApiTrainingStudentdeleteForcePath = '/api/training/student/deleteForce/{id}';
@@ -138,6 +147,15 @@ export class ApiTrainingStudent extends BeanApiBase {
138
147
  );
139
148
  }
140
149
 
150
+ /** Bulk Delete */
151
+ deleteBulk(body: ApiApiTrainingStudentdeleteBulkRequestBody, options?: IApiActionOptions) {
152
+ return this.$fetch.post<any, ApiApiTrainingStudentdeleteBulkResponseBody>(
153
+ ApiApiTrainingStudentdeleteBulkPath,
154
+ body,
155
+ this.$configPrepare(OpenApiBaseURL(this.sys), options, true),
156
+ );
157
+ }
158
+
141
159
  deleteForce(
142
160
  options: {
143
161
  params: ApiApiTrainingStudentdeleteForceRequestParams;
@@ -10,6 +10,7 @@ import {
10
10
  ApiApiTrainingStudentdeletePath,
11
11
  ApiApiTrainingStudentupdatePath,
12
12
  ApiApiTrainingStudentsummaryPath,
13
+ ApiApiTrainingStudentdeleteBulkPath,
13
14
  ApiApiTrainingStudentdeleteForcePath,
14
15
  } from '../api/trainingStudent.js';
15
16
 
@@ -39,6 +40,10 @@ export class ApiSchemaTrainingStudent extends BeanBase {
39
40
  return this.$sdk.createApiSchemas(ApiApiTrainingStudentsummaryPath, 'get', options);
40
41
  }
41
42
 
43
+ deleteBulk(options?: IApiSchemaOptions) {
44
+ return this.$sdk.createApiSchemas(ApiApiTrainingStudentdeleteBulkPath, 'post', options);
45
+ }
46
+
42
47
  deleteForce(options?: IApiSchemaOptions) {
43
48
  return this.$sdk.createApiSchemas(ApiApiTrainingStudentdeleteForcePath, 'delete', options);
44
49
  }
@@ -5,6 +5,7 @@ export * from '../bean/command.confirm.jsx';
5
5
  export * from '../bean/command.copy.jsx';
6
6
  export * from '../bean/command.create.jsx';
7
7
  export * from '../bean/command.delete.jsx';
8
+ export * from '../bean/command.deleteBulk.jsx';
8
9
  export * from '../bean/command.edit.jsx';
9
10
  export * from '../bean/command.prompt.jsx';
10
11
  export * from '../bean/command.setValue.jsx';
@@ -14,6 +15,7 @@ import { ICommandOptionsConfirm } from '../bean/command.confirm.jsx';
14
15
  import { ICommandOptionsCopy } from '../bean/command.copy.jsx';
15
16
  import { ICommandOptionsCreate } from '../bean/command.create.jsx';
16
17
  import { ICommandOptionsDelete } from '../bean/command.delete.jsx';
18
+ import { ICommandOptionsDeleteBulk } from '../bean/command.deleteBulk.jsx';
17
19
  import { ICommandOptionsEdit } from '../bean/command.edit.jsx';
18
20
  import { ICommandOptionsPrompt } from '../bean/command.prompt.jsx';
19
21
  import { ICommandOptionsSetValue } from '../bean/command.setValue.jsx';
@@ -27,6 +29,7 @@ declare module 'zova-module-a-command' {
27
29
  'basic-commands:copy': ICommandOptionsCopy;
28
30
  'basic-commands:create': ICommandOptionsCreate;
29
31
  'basic-commands:delete': ICommandOptionsDelete;
32
+ 'basic-commands:deleteBulk': ICommandOptionsDeleteBulk;
30
33
  'basic-commands:edit': ICommandOptionsEdit;
31
34
  'basic-commands:prompt': ICommandOptionsPrompt;
32
35
  'basic-commands:setValue': ICommandOptionsSetValue;
@@ -92,6 +95,17 @@ declare module 'zova-module-basic-commands' {
92
95
  get $onionOptions(): ICommandOptionsDelete;
93
96
  }
94
97
 
98
+ export interface CommandDeleteBulk {
99
+ /** @internal */
100
+ get scope(): ScopeModuleBasicCommands;
101
+ }
102
+
103
+ export interface CommandDeleteBulk {
104
+ get $beanFullName(): 'basic-commands.command.deleteBulk';
105
+ get $onionName(): 'basic-commands:deleteBulk';
106
+ get $onionOptions(): ICommandOptionsDeleteBulk;
107
+ }
108
+
95
109
  export interface CommandEdit {
96
110
  /** @internal */
97
111
  get scope(): ScopeModuleBasicCommands;
@@ -143,6 +157,7 @@ import { CommandConfirm } from '../bean/command.confirm.jsx';
143
157
  import { CommandCopy } from '../bean/command.copy.jsx';
144
158
  import { CommandCreate } from '../bean/command.create.jsx';
145
159
  import { CommandDelete } from '../bean/command.delete.jsx';
160
+ import { CommandDeleteBulk } from '../bean/command.deleteBulk.jsx';
146
161
  import { CommandEdit } from '../bean/command.edit.jsx';
147
162
  import { CommandPrompt } from '../bean/command.prompt.jsx';
148
163
  import { CommandSetValue } from '../bean/command.setValue.jsx';
@@ -155,6 +170,7 @@ declare module 'zova' {
155
170
  'basic-commands.command.copy': CommandCopy;
156
171
  'basic-commands.command.create': CommandCreate;
157
172
  'basic-commands.command.delete': CommandDelete;
173
+ 'basic-commands.command.deleteBulk': CommandDeleteBulk;
158
174
  'basic-commands.command.edit': CommandEdit;
159
175
  'basic-commands.command.prompt': CommandPrompt;
160
176
  'basic-commands.command.setValue': CommandSetValue;
@@ -0,0 +1,35 @@
1
+ import type {
2
+ ICommandExecute,
3
+ ICommandSelectedOptionsBase,
4
+ NextCommandExecute,
5
+ } from 'zova-module-a-command';
6
+ import type { IJsxRenderContextBase, IJsxRenderContextPage } from 'zova-module-a-openapi';
7
+
8
+ import { BeanCommandSelectedBase, Command } from 'zova-module-a-command';
9
+
10
+ export type TypeCommandDeleteBulkResult = unknown;
11
+
12
+ export interface ICommandOptionsDeleteBulk extends ICommandSelectedOptionsBase<TypeCommandDeleteBulkResult> {}
13
+
14
+ @Command<ICommandOptionsDeleteBulk>()
15
+ export class CommandDeleteBulk extends BeanCommandSelectedBase implements ICommandExecute {
16
+ async execute(
17
+ options: ICommandOptionsDeleteBulk,
18
+ renderContext: IJsxRenderContextBase,
19
+ next: NextCommandExecute,
20
+ ) {
21
+ const { resource, ids } = this.getResourceAndIds(options, renderContext);
22
+ const { ctx } = renderContext;
23
+ const modelResource = await ctx.bean._getBeanSelector(
24
+ 'rest-resource.model.resource',
25
+ true,
26
+ resource,
27
+ );
28
+ const mutation = modelResource.deleteBulk();
29
+ await mutation.mutateAsync({ ids });
30
+ if (renderContext.$scene === 'page') {
31
+ (renderContext as IJsxRenderContextPage).$$page.clearSelectionAfterMutation(ids);
32
+ }
33
+ return next();
34
+ }
35
+ }
@@ -1,4 +1,5 @@
1
- import type { SortingState } from '@tanstack/vue-table';
1
+ import type { RowSelectionState, SortingState } from '@tanstack/vue-table';
2
+ import type { TableIdentity } from 'table-identity';
2
3
  import type { IComponentOptions } from 'zova';
3
4
  import type {
4
5
  IJsxRenderContextPage,
@@ -20,6 +21,8 @@ import { $QueriesEnsureLoaded } from 'zova-module-a-model';
20
21
  import { BeanControllerTableBase } from 'zova-module-a-table';
21
22
  import { ModelResource } from 'zova-module-rest-resource';
22
23
 
24
+ import { reconcileSelection, selectionKey, selectionRowId } from '../../lib/selection.js';
25
+
23
26
  declare module 'zova-module-a-openapi' {
24
27
  export interface IResourceBlockRecord {
25
28
  'basic-page:blockPage'?: ControllerBlockPageProps;
@@ -31,6 +34,7 @@ export interface ControllerBlockPageProps extends IResourceBlockOptionsBase {
31
34
  resource?: string;
32
35
  pageSize?: number;
33
36
  queryFixed?: ITableQuery;
37
+ selectionPolicy?: 'always' | 'onDemand' | false;
34
38
  }
35
39
 
36
40
  @Controller()
@@ -55,6 +59,12 @@ export class ControllerBlockPage<TData extends {} = {}> extends BeanControllerBa
55
59
  sorting: SortingState;
56
60
  queryPaged: ITablePaged;
57
61
 
62
+ rowSelection: RowSelectionState;
63
+ selectedIds: TableIdentity[];
64
+ selectedRows: Map<string, TData>;
65
+ selectionVisible = false;
66
+ selectionRequiredCount = 0;
67
+
58
68
  $$modelResource: ModelResource<TData>;
59
69
 
60
70
  protected async __init__() {
@@ -70,12 +80,23 @@ export class ControllerBlockPage<TData extends {} = {}> extends BeanControllerBa
70
80
  this.queryFilterData = {};
71
81
  this.querySortingData = {};
72
82
  this.sorting = [];
83
+ this.rowSelection = {};
84
+ this.selectedIds = [];
85
+ this.selectedRows = new Map();
73
86
  this.$watch(
74
87
  () => this.$props.queryFixed,
75
88
  queryFixed => {
76
89
  this.setQueryFixed(queryFixed);
77
90
  },
78
91
  );
92
+ this.$watch(
93
+ () => this.$props.resource,
94
+ (resource, oldResource) => {
95
+ if (resource === oldResource) return;
96
+ this.clearSelection();
97
+ this.selectionVisible = false;
98
+ },
99
+ );
79
100
  this.queryPaged = { pageNo: 1, pageSize: this.$props.pageSize };
80
101
  // load schema/data
81
102
  await $QueriesEnsureLoaded(
@@ -90,6 +111,12 @@ export class ControllerBlockPage<TData extends {} = {}> extends BeanControllerBa
90
111
  await this._requestTableMetaRefresh();
91
112
  },
92
113
  );
114
+ this.$watch(
115
+ () => this.data,
116
+ data => {
117
+ this._refreshSelectedRows((data ?? []) as unknown as Record<string, unknown>[]);
118
+ },
119
+ );
93
120
  }
94
121
 
95
122
  get resource() {
@@ -136,6 +163,98 @@ export class ControllerBlockPage<TData extends {} = {}> extends BeanControllerBa
136
163
  return this.$$modelResource.permissions;
137
164
  }
138
165
 
166
+ get selection() {
167
+ return {
168
+ ids: this.selectedIds,
169
+ rows: this.selectedIds.flatMap(id => {
170
+ const row = this.selectedRows.get(selectionKey(id));
171
+ return row ? [row] : [];
172
+ }),
173
+ count: this.selectedIds.length,
174
+ };
175
+ }
176
+
177
+ get selectionAvailable() {
178
+ const policy = this.$props.selectionPolicy;
179
+ return (
180
+ policy === 'always' ||
181
+ policy === 'onDemand' ||
182
+ (policy === undefined && this.selectionRequiredCount > 0)
183
+ );
184
+ }
185
+
186
+ get selectionToggleAvailable() {
187
+ return this.selectionAvailable && this.$props.selectionPolicy !== 'always';
188
+ }
189
+
190
+ get selectionEnabled() {
191
+ const policy = this.$props.selectionPolicy;
192
+ return policy === 'always' || (this.selectionVisible && policy !== false);
193
+ }
194
+
195
+ onRowSelectionChange(
196
+ updater: RowSelectionState | ((old: RowSelectionState) => RowSelectionState),
197
+ ) {
198
+ const data = (this.data ?? []) as unknown as Record<string, unknown>[];
199
+ const next = functionalUpdate(updater, this.rowSelection);
200
+ this.rowSelection = reconcileSelection(this.rowSelection, data, next);
201
+ this._reconcileSelectedRows(data);
202
+ }
203
+
204
+ clearSelection() {
205
+ this.rowSelection = {};
206
+ this.selectedIds = [];
207
+ this.selectedRows = new Map();
208
+ }
209
+
210
+ private _refreshSelectedRows(data: readonly Record<string, unknown>[]) {
211
+ if (this.selectedIds.length === 0) return;
212
+ this._reconcileSelectedRows(data);
213
+ }
214
+
215
+ private _reconcileSelectedRows(data: readonly Record<string, unknown>[]) {
216
+ const selectedIds = [...this.selectedIds];
217
+ const selectedRows = new Map(this.selectedRows);
218
+ for (const row of data) {
219
+ const id = selectionRowId(row);
220
+ const key = selectionKey(id);
221
+ if (this.rowSelection[key]) {
222
+ if (!selectedIds.some(selectedId => selectionKey(selectedId) === key)) {
223
+ selectedIds.push(id);
224
+ }
225
+ selectedRows.set(key, row as TData);
226
+ } else {
227
+ const index = selectedIds.findIndex(selectedId => selectionKey(selectedId) === key);
228
+ if (index !== -1) selectedIds.splice(index, 1);
229
+ selectedRows.delete(key);
230
+ }
231
+ }
232
+ this.selectedIds = selectedIds;
233
+ this.selectedRows = selectedRows;
234
+ }
235
+
236
+ toggleSelection() {
237
+ if (this.selectionVisible) {
238
+ this.clearSelection();
239
+ }
240
+ this.selectionVisible = !this.selectionVisible;
241
+ }
242
+
243
+ setSelectionRequired(required: boolean) {
244
+ this.selectionRequiredCount += required ? 1 : -1;
245
+ if (this.selectionRequiredCount < 0) this.selectionRequiredCount = 0;
246
+ }
247
+
248
+ clearSelectionAfterMutation(ids: readonly TableIdentity[]) {
249
+ const keys = new Set(ids.map(selectionKey));
250
+ if (keys.size === 0) return;
251
+ this.rowSelection = Object.fromEntries(
252
+ Object.entries(this.rowSelection).filter(([key]) => !keys.has(key)),
253
+ );
254
+ this.selectedIds = this.selectedIds.filter(id => !keys.has(selectionKey(id)));
255
+ this.selectedRows = new Map([...this.selectedRows].filter(([key]) => !keys.has(key)));
256
+ }
257
+
139
258
  gotoPage(pageNo: number) {
140
259
  if (this.queryPaged.pageNo !== pageNo) {
141
260
  this.queryPaged.pageNo = pageNo;
@@ -144,26 +263,34 @@ export class ControllerBlockPage<TData extends {} = {}> extends BeanControllerBa
144
263
 
145
264
  setPageSize(pageSize: number) {
146
265
  if (this.queryPaged.pageSize !== pageSize) {
266
+ this.clearSelection();
147
267
  this.queryPaged.pageSize = pageSize;
268
+ this.queryPaged.pageNo = 1;
148
269
  }
149
270
  }
150
271
 
151
272
  setQueryFixed(queryFixed?: ITableQuery) {
152
- this.queryFixedData = queryFixed ?? {};
273
+ const next = queryFixed ?? {};
274
+ if (deepEqual(this.queryFixedData, next)) return;
275
+ this.clearSelection();
276
+ this.queryFixedData = next;
153
277
  this.queryPaged.pageNo = 1;
154
278
  }
155
279
 
156
280
  onFilter(data: ITableQuery) {
281
+ if (deepEqual(this.queryFilterData, data)) return;
282
+ this.clearSelection();
157
283
  this.queryFilterData = data;
158
284
  this.queryPaged.pageNo = 1;
159
285
  }
160
286
 
161
287
  onSortingChange(updater: SortingState | ((old: SortingState) => SortingState)) {
162
- this.sorting = functionalUpdate(updater, this.sorting).slice(0, 1);
163
- const sorting = this.sorting[0];
164
- this.querySortingData = sorting
165
- ? { orders: [[sorting.id, sorting.desc ? 'desc' : 'asc']] }
166
- : {};
288
+ const sorting = functionalUpdate(updater, this.sorting).slice(0, 1);
289
+ if (deepEqual(this.sorting, sorting)) return;
290
+ this.clearSelection();
291
+ this.sorting = sorting;
292
+ const first = this.sorting[0];
293
+ this.querySortingData = first ? { orders: [[first.id, first.desc ? 'desc' : 'asc']] } : {};
167
294
  this.queryPaged.pageNo = 1;
168
295
  }
169
296
 
@@ -231,9 +358,18 @@ export class ControllerBlockPage<TData extends {} = {}> extends BeanControllerBa
231
358
  set(_value) {},
232
359
  };
233
360
  }) as any;
361
+ const selection = this.$customRef(() => {
362
+ return {
363
+ get() {
364
+ return self.selection;
365
+ },
366
+ set(_value) {},
367
+ };
368
+ }) as any;
234
369
  return {
235
370
  resource: this.resource,
236
371
  permissions,
372
+ selection,
237
373
  };
238
374
  }
239
375
 
@@ -27,8 +27,6 @@ export class ControllerBlockTable<TData extends {} = {}> extends BeanControllerB
27
27
  @Use({ injectionScope: 'host' })
28
28
  $$renderContext: IJsxRenderContextPage;
29
29
 
30
- protected async __init__() {}
31
-
32
30
  get permissions() {
33
31
  return this.$$renderContext.$celScope.permissions;
34
32
  }
@@ -47,6 +45,9 @@ export class ControllerBlockTable<TData extends {} = {}> extends BeanControllerB
47
45
  schemaOrder={$$page.schemaOrder}
48
46
  sorting={$$page.sorting}
49
47
  onSortingChange={updater => $$page.onSortingChange(updater)}
48
+ enableRowSelection={$$page.selectionEnabled}
49
+ rowSelection={$$page.rowSelection}
50
+ onRowSelectionChange={updater => $$page.onRowSelectionChange(updater)}
50
51
  tableScope={$$page.jsxCelScope}
51
52
  ></ZTable>
52
53
  </div>