@vc-shell/vc-app-skill 2.0.0-alpha.33 → 2.0.0-alpha.34

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 (195) hide show
  1. package/CHANGELOG.md +78 -54
  2. package/README.md +42 -12
  3. package/package.json +4 -4
  4. package/runtime/VERSION +1 -1
  5. package/runtime/agents/api-analyzer.md +31 -16
  6. package/runtime/agents/blade-enhancer.md +15 -9
  7. package/runtime/agents/details-blade-generator.md +47 -31
  8. package/runtime/agents/list-blade-generator.md +21 -37
  9. package/runtime/agents/locales-generator.md +3 -0
  10. package/runtime/agents/migration-agent.md +18 -7
  11. package/runtime/agents/module-analyzer.md +2 -0
  12. package/runtime/agents/module-assembler.md +15 -0
  13. package/runtime/agents/promote-agent.md +15 -4
  14. package/runtime/agents/type-checker.md +11 -0
  15. package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
  16. package/runtime/knowledge/docs/core/api/platform.docs.md +30 -30
  17. package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +41 -41
  18. package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +12 -10
  19. package/runtime/knowledge/docs/core/composables/useApiClient/useApiClient.docs.md +11 -14
  20. package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +35 -35
  21. package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +35 -35
  22. package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +15 -15
  23. package/runtime/knowledge/docs/core/composables/useAssets/useAssets.docs.md +21 -18
  24. package/runtime/knowledge/docs/core/composables/useAssetsManager/useAssetsManager.docs.md +28 -24
  25. package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +90 -61
  26. package/runtime/knowledge/docs/core/composables/useBeforeUnload/useBeforeUnload.docs.md +19 -18
  27. package/runtime/knowledge/docs/core/composables/useBlade/useBlade.docs.md +89 -68
  28. package/runtime/knowledge/docs/core/composables/useBladeForm/useBladeForm.docs.md +27 -25
  29. package/runtime/knowledge/docs/core/composables/useBladeRegistry/useBladeRegistry.docs.md +15 -15
  30. package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +43 -47
  31. package/runtime/knowledge/docs/core/composables/useBreadcrumbs/useBreadcrumbs.docs.md +11 -11
  32. package/runtime/knowledge/docs/core/composables/useConnectionStatus/useConnectionStatus.docs.md +27 -15
  33. package/runtime/knowledge/docs/core/composables/useDashboard/useDashboard.docs.md +30 -30
  34. package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +34 -36
  35. package/runtime/knowledge/docs/core/composables/useErrorHandler/useErrorHandler.docs.md +44 -23
  36. package/runtime/knowledge/docs/core/composables/useFunctions/useFunctions.docs.md +14 -11
  37. package/runtime/knowledge/docs/core/composables/useKeyboardNavigation/useKeyboardNavigation.docs.md +47 -38
  38. package/runtime/knowledge/docs/core/composables/useLanguages/useLanguages.docs.md +37 -28
  39. package/runtime/knowledge/docs/core/composables/useLoading/useLoading.docs.md +23 -17
  40. package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +9 -9
  41. package/runtime/knowledge/docs/core/composables/useMenuService/useMenuService.docs.md +42 -42
  42. package/runtime/knowledge/docs/core/composables/useModificationTracker/useModificationTracker.docs.md +22 -12
  43. package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +33 -41
  44. package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +16 -16
  45. package/runtime/knowledge/docs/core/composables/usePlatformLocaleSync/usePlatformLocaleSync.docs.md +28 -0
  46. package/runtime/knowledge/docs/core/composables/usePopup/usePopup.docs.md +32 -24
  47. package/runtime/knowledge/docs/core/composables/useResponsive/useResponsive.docs.md +32 -11
  48. package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +22 -13
  49. package/runtime/knowledge/docs/core/composables/useSettingsMenu/useSettingsMenu.docs.md +7 -7
  50. package/runtime/knowledge/docs/core/composables/useSidebarState/useSidebarState.docs.md +32 -24
  51. package/runtime/knowledge/docs/core/composables/useSlowNetworkDetection/useSlowNetworkDetection.docs.md +21 -17
  52. package/runtime/knowledge/docs/core/composables/useTheme/useTheme.docs.md +24 -24
  53. package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +28 -31
  54. package/runtime/knowledge/docs/core/composables/useUser/useUser.docs.md +43 -24
  55. package/runtime/knowledge/docs/core/composables/useUserManagement/useUserManagement.docs.md +68 -48
  56. package/runtime/knowledge/docs/core/composables/useWebVitals/useWebVitals.docs.md +19 -19
  57. package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +42 -47
  58. package/runtime/knowledge/docs/core/directives/autofocus/autofocus.docs.md +10 -4
  59. package/runtime/knowledge/docs/core/directives/loading/loading.docs.md +35 -20
  60. package/runtime/knowledge/docs/core/notifications/notifications.docs.md +36 -35
  61. package/runtime/knowledge/docs/core/plugins/ai-agent/ai-agent.docs.md +38 -38
  62. package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +79 -62
  63. package/runtime/knowledge/docs/core/plugins/global-error-handler/global-error-handler.docs.md +10 -10
  64. package/runtime/knowledge/docs/core/plugins/i18n/i18n.docs.md +21 -23
  65. package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +91 -83
  66. package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +10 -16
  67. package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +9 -9
  68. package/runtime/knowledge/docs/core/plugins/validation/validation.docs.md +65 -22
  69. package/runtime/knowledge/docs/core/services/services.docs.md +19 -22
  70. package/runtime/knowledge/docs/core/types/types.docs.md +40 -40
  71. package/runtime/knowledge/docs/core/utilities/date/date-utilities.docs.md +27 -27
  72. package/runtime/knowledge/docs/core/utilities/shared-utilities.docs.md +23 -23
  73. package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +22 -25
  74. package/runtime/knowledge/docs/core/utilities/utilities.docs.md +64 -64
  75. package/runtime/knowledge/docs/injection-keys.docs.md +52 -51
  76. package/runtime/knowledge/docs/modules/assets-manager/assets-manager.docs.md +9 -9
  77. package/runtime/knowledge/docs/shell/_internal/popup/common/popup-common.docs.md +23 -43
  78. package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +5 -5
  79. package/runtime/knowledge/docs/shell/auth/ForgotPasswordPage/forgot-password-page.docs.md +5 -5
  80. package/runtime/knowledge/docs/shell/auth/InvitePage/invite-page.docs.md +8 -7
  81. package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +7 -7
  82. package/runtime/knowledge/docs/shell/auth/ResetPasswordPage/reset-password-page.docs.md +8 -7
  83. package/runtime/knowledge/docs/shell/auth/sign-in/sign-in.docs.md +29 -13
  84. package/runtime/knowledge/docs/shell/components/change-password/change-password.docs.md +13 -16
  85. package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +1 -7
  86. package/runtime/knowledge/docs/shell/components/error-interceptor/error-interceptor.docs.md +5 -5
  87. package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +1 -1
  88. package/runtime/knowledge/docs/shell/components/logout-button/logout-button.docs.md +1 -1
  89. package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +17 -9
  90. package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +11 -17
  91. package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +34 -65
  92. package/runtime/knowledge/docs/shell/components/sidebar/sidebar.docs.md +16 -26
  93. package/runtime/knowledge/docs/shell/components/theme-selector/theme-selector.docs.md +2 -2
  94. package/runtime/knowledge/docs/shell/components/user-dropdown-button/user-dropdown-button.docs.md +7 -9
  95. package/runtime/knowledge/docs/shell/dashboard/dashboard-charts/dashboard-charts.docs.md +30 -40
  96. package/runtime/knowledge/docs/shell/dashboard/dashboard-widget-card/dashboard-widget-card.docs.md +26 -19
  97. package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +15 -12
  98. package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +15 -26
  99. package/runtime/knowledge/docs/ui/components/atoms/vc-banner/vc-banner.docs.md +21 -19
  100. package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +83 -67
  101. package/runtime/knowledge/docs/ui/components/atoms/vc-card/vc-card.docs.md +100 -59
  102. package/runtime/knowledge/docs/ui/components/atoms/vc-col/vc-col.docs.md +28 -11
  103. package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +20 -17
  104. package/runtime/knowledge/docs/ui/components/atoms/vc-hint/vc-hint.docs.md +26 -17
  105. package/runtime/knowledge/docs/ui/components/atoms/vc-icon/vc-icon.docs.md +30 -32
  106. package/runtime/knowledge/docs/ui/components/atoms/vc-image/vc-image.docs.md +25 -48
  107. package/runtime/knowledge/docs/ui/components/atoms/vc-label/vc-label.docs.md +29 -24
  108. package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +23 -15
  109. package/runtime/knowledge/docs/ui/components/atoms/vc-loading/vc-loading.docs.md +22 -13
  110. package/runtime/knowledge/docs/ui/components/atoms/vc-progress/vc-progress.docs.md +33 -18
  111. package/runtime/knowledge/docs/ui/components/atoms/vc-row/vc-row.docs.md +56 -15
  112. package/runtime/knowledge/docs/ui/components/atoms/vc-scrollable-container/vc-scrollable-container.docs.md +28 -15
  113. package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +40 -20
  114. package/runtime/knowledge/docs/ui/components/atoms/vc-status/vc-status.docs.md +25 -14
  115. package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +40 -14
  116. package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +54 -42
  117. package/runtime/knowledge/docs/ui/components/atoms/vc-video/vc-video.docs.md +17 -17
  118. package/runtime/knowledge/docs/ui/components/atoms/vc-widget/vc-widget.docs.md +21 -21
  119. package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +23 -10
  120. package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +55 -44
  121. package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +23 -20
  122. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +92 -65
  123. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +22 -36
  124. package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +65 -23
  125. package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +52 -73
  126. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown/vc-dropdown.docs.md +91 -85
  127. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md +38 -42
  128. package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +56 -73
  129. package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +61 -27
  130. package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +42 -50
  131. package/runtime/knowledge/docs/ui/components/molecules/vc-form/vc-form.docs.md +35 -64
  132. package/runtime/knowledge/docs/ui/components/molecules/vc-image-tile/vc-image-tile.docs.md +38 -41
  133. package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +109 -131
  134. package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +47 -88
  135. package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +50 -64
  136. package/runtime/knowledge/docs/ui/components/molecules/vc-input-group/vc-input-group.docs.md +29 -24
  137. package/runtime/knowledge/docs/ui/components/molecules/vc-menu/vc-menu.docs.md +32 -28
  138. package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +57 -65
  139. package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +28 -26
  140. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +55 -20
  141. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md +21 -35
  142. package/runtime/knowledge/docs/ui/components/molecules/vc-rating/vc-rating.docs.md +38 -33
  143. package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +72 -83
  144. package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +21 -16
  145. package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +55 -64
  146. package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +51 -70
  147. package/runtime/knowledge/docs/ui/components/molecules/vc-toast/vc-toast.docs.md +58 -57
  148. package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +49 -26
  149. package/runtime/knowledge/docs/ui/components/organisms/vc-auth-layout/vc-auth-layout.docs.md +82 -28
  150. package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +90 -75
  151. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/composables/table-composables.docs.md +99 -48
  152. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +548 -367
  153. package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +35 -52
  154. package/runtime/knowledge/docs/ui/components/organisms/vc-gallery/vc-gallery.docs.md +33 -62
  155. package/runtime/knowledge/docs/ui/components/organisms/vc-image-upload/vc-image-upload.docs.md +17 -23
  156. package/runtime/knowledge/docs/ui/components/organisms/vc-popup/vc-popup.docs.md +109 -68
  157. package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +82 -44
  158. package/runtime/knowledge/docs/ui/composables/ui-composables.docs.md +8 -8
  159. package/runtime/knowledge/docs/ui/composables/useDataTablePagination.docs.md +164 -0
  160. package/runtime/knowledge/docs/ui/composables/useDataTableSort.docs.md +34 -26
  161. package/runtime/knowledge/docs/ui/composables/useTableSelection.docs.md +48 -40
  162. package/runtime/knowledge/docs/ui/composables/useTableSort.docs.md +30 -17
  163. package/runtime/knowledge/docs/ui/types/ui-types.docs.md +40 -29
  164. package/runtime/knowledge/examples/offers-module.md +15 -13
  165. package/runtime/knowledge/examples/team-module.md +82 -119
  166. package/runtime/knowledge/examples/videos-module.md +44 -17
  167. package/runtime/knowledge/index.md +22 -0
  168. package/runtime/knowledge/migration-prompts/blade-form-migration.md +17 -8
  169. package/runtime/knowledge/migration-prompts/blade-props-migration.md +1 -2
  170. package/runtime/knowledge/migration-prompts/datatable-migration.md +801 -0
  171. package/runtime/knowledge/migration-prompts/icon-migration.md +97 -0
  172. package/runtime/knowledge/migration-prompts/manual-migration-audit.md +117 -0
  173. package/runtime/knowledge/migration-prompts/notifications-migration.md +8 -3
  174. package/runtime/knowledge/migration-prompts/nswag-migration.md +25 -29
  175. package/runtime/knowledge/migration-prompts/use-assets-migration.md +164 -0
  176. package/runtime/knowledge/migration-prompts/use-data-table-pagination-migration.md +176 -0
  177. package/runtime/knowledge/migration-prompts/widgets-migration.md +48 -27
  178. package/runtime/knowledge/patterns/assets-management.md +20 -20
  179. package/runtime/knowledge/patterns/blade-navigation.md +7 -14
  180. package/runtime/knowledge/patterns/blade-widget.md +19 -17
  181. package/runtime/knowledge/patterns/child-blade-flow.md +19 -7
  182. package/runtime/knowledge/patterns/composable-details.md +20 -50
  183. package/runtime/knowledge/patterns/composable-list.md +43 -31
  184. package/runtime/knowledge/patterns/dashboard-widget.md +14 -16
  185. package/runtime/knowledge/patterns/datatable-pattern.md +521 -0
  186. package/runtime/knowledge/patterns/details-blade-pattern.md +78 -116
  187. package/runtime/knowledge/patterns/extension-points-usage.md +53 -44
  188. package/runtime/knowledge/patterns/form-validation.md +28 -64
  189. package/runtime/knowledge/patterns/list-blade-pattern.md +33 -21
  190. package/runtime/knowledge/patterns/module-structure.md +7 -1
  191. package/runtime/knowledge/patterns/multilanguage-fields.md +8 -14
  192. package/runtime/knowledge/patterns/notification-template.md +21 -14
  193. package/runtime/knowledge/patterns/signalr-notifications.md +30 -32
  194. package/runtime/knowledge/patterns/toolbar-pattern.md +18 -20
  195. package/runtime/vc-app.md +241 -62
@@ -18,7 +18,7 @@ For each blade that calls `registerWidget()`, create a `widgets/useXxxWidgets.ts
18
18
  import { useWidgets, useBlade } from "@vc-shell/framework";
19
19
  import type { BladeInstance } from "@vc-shell/framework";
20
20
  import { onMounted, onUnmounted } from "vue";
21
- import OffersWidget from "../widgets/OffersWidget.vue";
21
+ import ChildListWidget from "../widgets/ChildListWidget.vue";
22
22
 
23
23
  const { registerWidget, clearBladeWidgets } = useWidgets();
24
24
  const { openBlade } = useBlade();
@@ -26,11 +26,11 @@ const { openBlade } = useBlade();
26
26
  onMounted(() => {
27
27
  registerWidget(
28
28
  {
29
- id: "OffersWidget",
30
- component: OffersWidget,
29
+ id: "ChildListWidget",
30
+ component: ChildListWidget,
31
31
  props: {
32
- count: offersCount,
33
- onClick: () => openBlade({ name: "OffersList", options: { productId: entity.value.id } }),
32
+ count: childCount,
33
+ onClick: () => openBlade({ name: "ChildEntityList", options: { entityId: entity.value.id } }),
34
34
  },
35
35
  },
36
36
  bladeContext.id,
@@ -45,35 +45,35 @@ onUnmounted(() => {
45
45
  **AFTER:**
46
46
 
47
47
  ```typescript
48
- // widgets/useProductWidgets.ts
48
+ // widgets/useEntityWidgets.ts
49
49
  import { useBladeWidgets, useBlade } from "@vc-shell/framework";
50
50
  import type { UseBladeWidgetsReturn } from "@vc-shell/framework";
51
51
  import { computed, type Ref } from "vue";
52
52
 
53
- interface UseProductWidgetsOptions {
54
- item: Ref<Product | undefined>;
53
+ interface UseEntityWidgetsOptions {
54
+ item: Ref<Entity | undefined>;
55
55
  isVisible: Ref<boolean> | boolean;
56
- offersCount: Ref<number>;
56
+ childCount: Ref<number>;
57
57
  }
58
58
 
59
- export function useProductWidgets(options: UseProductWidgetsOptions): UseBladeWidgetsReturn {
60
- const { item, isVisible, offersCount } = options;
59
+ export function useEntityWidgets(options: UseEntityWidgetsOptions): UseBladeWidgetsReturn {
60
+ const { item, isVisible, childCount } = options;
61
61
  const { openBlade } = useBlade();
62
62
 
63
63
  return useBladeWidgets([
64
64
  {
65
- id: "OffersWidget",
65
+ id: "ChildListWidget",
66
66
  icon: "lucide-tag",
67
- title: "PRODUCTS.WIDGETS.OFFERS.TITLE",
68
- badge: computed(() => offersCount.value),
67
+ title: "MODULE.WIDGETS.CHILD_LIST.TITLE",
68
+ badge: computed(() => childCount.value),
69
69
  isVisible,
70
70
  onClick: () =>
71
71
  openBlade({
72
- name: "OffersList",
73
- options: { productId: item.value?.id },
72
+ name: "ChildEntityList",
73
+ options: { entityId: item.value?.id },
74
74
  }),
75
75
  onRefresh: async () => {
76
- // load offers count logic here
76
+ // load child count logic here
77
77
  },
78
78
  },
79
79
  ]);
@@ -89,14 +89,14 @@ Import the new composable and destructure `{ refreshAll }`.
89
89
  ```typescript
90
90
  // XxxDetails.vue <script setup>
91
91
  import { useWidgets } from "@vc-shell/framework";
92
- import OffersWidget from "../widgets/OffersWidget.vue";
93
- import AssociationsWidget from "../widgets/AssociationsWidget.vue";
92
+ import ChildListWidget from "../widgets/ChildListWidget.vue";
93
+ import RelatedItemsWidget from "../widgets/RelatedItemsWidget.vue";
94
94
 
95
95
  const { registerWidget, clearBladeWidgets } = useWidgets();
96
96
 
97
97
  onMounted(() => {
98
- registerWidget({ id: "OffersWidget", component: OffersWidget, props: { ... } }, bladeId);
99
- registerWidget({ id: "AssociationsWidget", component: AssociationsWidget, props: { ... } }, bladeId);
98
+ registerWidget({ id: "ChildListWidget", component: ChildListWidget, props: { ... } }, bladeId);
99
+ registerWidget({ id: "RelatedItemsWidget", component: RelatedItemsWidget, props: { ... } }, bladeId);
100
100
  });
101
101
 
102
102
  onUnmounted(() => {
@@ -108,17 +108,29 @@ onUnmounted(() => {
108
108
 
109
109
  ```typescript
110
110
  // XxxDetails.vue <script setup>
111
- import { useProductWidgets } from "../widgets/useProductWidgets";
111
+ import { useEntityWidgets } from "../widgets/useEntityWidgets";
112
112
 
113
113
  const isExisting = computed(() => !!param.value);
114
114
 
115
- const { refreshAll } = useProductWidgets({
115
+ const { refreshAll } = useEntityWidgets({
116
116
  item: entity,
117
117
  isVisible: isExisting,
118
- offersCount,
118
+ childCount,
119
119
  });
120
120
  ```
121
121
 
122
+ If the old code used `updateActiveWidget()`, replace it with `refreshAll()` from the widget composable return:
123
+
124
+ ```typescript
125
+ // BEFORE
126
+ const { updateActiveWidget } = useWidgets();
127
+ updateActiveWidget();
128
+
129
+ // AFTER
130
+ const { refreshAll } = useEntityWidgets({ item: entity, isVisible: isExisting, childCount });
131
+ refreshAll();
132
+ ```
133
+
122
134
  ## RULE 3: Remove Widget .vue Components
123
135
 
124
136
  Delete widget `.vue` files that only render a standard sidebar item (icon + title + badge + click handler). These are replaced by the declarative config in `useBladeWidgets()`.
@@ -126,10 +138,12 @@ Delete widget `.vue` files that only render a standard sidebar item (icon + titl
126
138
  **Keep** the `.vue` component only if it has custom rendering beyond the standard widget layout.
127
139
 
128
140
  **Delete:**
129
- - `widgets/OffersWidget.vue` (if it only shows icon, title, badge, click)
130
- - `widgets/AssociationsWidget.vue` (same)
141
+
142
+ - `widgets/ChildListWidget.vue` (if it only shows icon, title, badge, click)
143
+ - `widgets/RelatedItemsWidget.vue` (same)
131
144
 
132
145
  **Keep:**
146
+
133
147
  - `widgets/CustomChartWidget.vue` (has custom chart rendering)
134
148
 
135
149
  ## RULE 4: Remove Old Imports
@@ -142,9 +156,15 @@ import { useWidgets } from "@vc-shell/framework";
142
156
  import type { BladeInstance } from "@vc-shell/framework"; // if only used for widgets
143
157
  import { registerWidget, unregisterWidget, clearBladeWidgets } from "...";
144
158
  import { onUnmounted } from "vue"; // if only used for widget cleanup
145
- import OffersWidget from "../widgets/OffersWidget.vue"; // deleted component
159
+ import ChildListWidget from "../widgets/ChildListWidget.vue"; // deleted component
146
160
  ```
147
161
 
162
+ ## RULE 5: `defineBladeContext` only for external widgets
163
+
164
+ Do not add `defineBladeContext()` by default in this migration.
165
+
166
+ Add it only if the blade hosts external widget components that use `injectBladeContext()`.
167
+
148
168
  ## Verification
149
169
 
150
170
  After migration:
@@ -155,3 +175,4 @@ After migration:
155
175
  4. Confirm clicking a widget opens the correct child blade
156
176
  5. Confirm widgets are hidden when `isVisible` is false (e.g., on "create new" blades)
157
177
  6. Confirm no console errors about widget registration/cleanup on blade close
178
+ 7. Confirm `updateActiveWidget()` calls are removed and replaced with `refreshAll()` from `useEntityWidgets` return
@@ -68,7 +68,9 @@ const { showConfirmation } = usePopup();
68
68
 
69
69
  const images = computed({
70
70
  get: () => item.value?.images ?? [],
71
- set: (val) => { if (item.value) item.value.images = val; },
71
+ set: (val) => {
72
+ if (item.value) item.value.images = val;
73
+ },
72
74
  });
73
75
 
74
76
  const assets = useAssetsManager(images, {
@@ -101,13 +103,7 @@ Use when assets are a secondary concern shown as a widget badge. Clicking the wi
101
103
  ```ts
102
104
  // widgets/useEntityWidgets.ts
103
105
  import { computed, markRaw, type Ref, type ComputedRef } from "vue";
104
- import {
105
- useBlade,
106
- useBladeWidgets,
107
- useAssetsManager,
108
- usePopup,
109
- type UseBladeWidgetsReturn,
110
- } from "@vc-shell/framework";
106
+ import { useBlade, useBladeWidgets, useAssetsManager, usePopup, type UseBladeWidgetsReturn } from "@vc-shell/framework";
111
107
 
112
108
  interface Options {
113
109
  item: Ref<Entity | undefined>;
@@ -145,7 +141,7 @@ export function useEntityWidgets({ item, disabled, isVisible }: Options): UseBla
145
141
  openBlade({
146
142
  name: "AssetsManager",
147
143
  options: {
148
- manager: markRaw(assetsManager), // markRaw prevents Vue from making it reactive
144
+ manager: markRaw(assetsManager), // markRaw prevents Vue from making it reactive
149
145
  disabled: disabled.value,
150
146
  },
151
147
  }),
@@ -186,14 +182,18 @@ Each manager operates on a different writable computed pointing to a different a
186
182
  // Gallery assets (images)
187
183
  const productImages = computed({
188
184
  get: () => item.value.productData?.images ?? [],
189
- set: (val) => { if (item.value.productData) item.value.productData.images = val; },
185
+ set: (val) => {
186
+ if (item.value.productData) item.value.productData.images = val;
187
+ },
190
188
  });
191
189
  const imageAssets = useAssetsManager(productImages, { uploadPath: () => `/catalog/${item.value.id}` });
192
190
 
193
191
  // Widget assets (files)
194
192
  const productFiles = computed({
195
193
  get: () => (item.value?.productData?.assets ?? []) as Asset[],
196
- set: (val) => { if (item.value?.productData) item.value.productData.assets = val; },
194
+ set: (val) => {
195
+ if (item.value?.productData) item.value.productData.assets = val;
196
+ },
197
197
  });
198
198
  const fileAssets = useAssetsManager(productFiles, { uploadPath: () => `/catalog/${item.value.id}` });
199
199
  ```
@@ -202,12 +202,12 @@ const fileAssets = useAssetsManager(productFiles, { uploadPath: () => `/catalog/
202
202
 
203
203
  ## Key Points
204
204
 
205
- | Concern | Approach |
206
- |---|---|
207
- | Binding to entity | Writable `computed` — getter reads nested array, setter writes it back |
208
- | Upload path | Callback `() => string` — resolved at upload time, so entity ID is available |
209
- | Remove confirmation | Pass `confirmRemove` returning `Promise<boolean>` via `usePopup().showConfirmation` |
210
- | Passing to AssetsManager blade | Wrap with `markRaw()` — prevents Vue from making the manager deeply reactive |
211
- | Multiple asset types | Create separate `useAssetsManager` instances per array (images vs files) |
212
- | Gallery edit | Open `AssetsDetails` blade, pass `assetEditHandler` and `assetRemoveHandler` callbacks |
213
- | Widget visibility | Use `isVisible: computed(() => !!param.value)` to hide on "create new" mode |
205
+ | Concern | Approach |
206
+ | ------------------------------ | -------------------------------------------------------------------------------------- |
207
+ | Binding to entity | Writable `computed` — getter reads nested array, setter writes it back |
208
+ | Upload path | Callback `() => string` — resolved at upload time, so entity ID is available |
209
+ | Remove confirmation | Pass `confirmRemove` returning `Promise<boolean>` via `usePopup().showConfirmation` |
210
+ | Passing to AssetsManager blade | Wrap with `markRaw()` — prevents Vue from making the manager deeply reactive |
211
+ | Multiple asset types | Create separate `useAssetsManager` instances per array (images vs files) |
212
+ | Gallery edit | Open `AssetsDetails` blade, pass `assetEditHandler` and `assetRemoveHandler` callbacks |
213
+ | Widget visibility | Use `isVisible: computed(() => !!param.value)` to hide on "create new" mode |
@@ -9,15 +9,7 @@ Blades are stacked panels rendered by `VcBladeNavigation`. Navigation between bl
9
9
  ```ts
10
10
  import { useBlade } from "@vc-shell/framework";
11
11
 
12
- const {
13
- openBlade,
14
- closeSelf,
15
- callParent,
16
- exposeToChildren,
17
- onBeforeClose,
18
- param,
19
- options,
20
- } = useBlade<OptionsType>();
12
+ const { openBlade, closeSelf, callParent, exposeToChildren, onBeforeClose, param, options } = useBlade<OptionsType>();
21
13
  ```
22
14
 
23
15
  `useBlade()` must be called inside `<script setup>` of a blade component. It uses provide/inject to wire the blade hierarchy.
@@ -58,6 +50,7 @@ entity.value.name = options.value?.prefilledName ?? "";
58
50
  ## `openBlade()` — Open a child blade
59
51
 
60
52
  Full signature:
53
+
61
54
  ```ts
62
55
  openBlade({
63
56
  name: string, // defineBlade name of the target blade
@@ -133,7 +126,7 @@ const { callParent } = useBlade();
133
126
 
134
127
  // In details blade after save:
135
128
  await updateXxx(entity.value);
136
- callParent("reload"); // calls parent's reload() function
129
+ callParent("reload"); // calls parent's reload() function
137
130
  closeSelf();
138
131
  ```
139
132
 
@@ -170,19 +163,19 @@ const { showConfirmation } = usePopup();
170
163
  onBeforeClose(async () => {
171
164
  if (modified.value) {
172
165
  // returns true to BLOCK close, false to ALLOW close
173
- return !(await showConfirmation(
174
- unref(computed(() => t("MODULE.PAGES.ALERTS.CLOSE_CONFIRMATION"))),
175
- ));
166
+ return !(await showConfirmation(unref(computed(() => t("MODULE.PAGES.ALERTS.CLOSE_CONFIRMATION")))));
176
167
  }
177
- return false; // no unsaved changes — allow close
168
+ return false; // no unsaved changes — allow close
178
169
  });
179
170
  ```
180
171
 
181
172
  Return value semantics:
173
+
182
174
  - `false` → close is allowed
183
175
  - `true` → close is blocked (user stays on the blade)
184
176
 
185
177
  The pattern `!(await showConfirmation(...))` works as:
178
+
186
179
  - User clicks "Confirm" → `showConfirmation` returns `true` → `!true` = `false` → close allowed
187
180
  - User clicks "Cancel" → `showConfirmation` returns `false` → `!false` = `true` → close blocked
188
181
 
@@ -1,6 +1,6 @@
1
1
  # Blade Widget Pattern
2
2
 
3
- Blade widgets are sidebar items displayed alongside a details blade. They allow navigation to related child blades (e.g., "Offers for this product", "Associated items"). Each widget shows an icon, a title, and an optional reactive badge count.
3
+ Blade widgets are sidebar items displayed alongside a details blade. They allow navigation to related child blades (e.g., "Children of this entity", "Associated items"). Each widget shows an icon, a title, and an optional reactive badge count.
4
4
 
5
5
  Blade widgets use `useBladeWidgets()` — the headless widget API. No `.vue` component is needed per widget; the framework renders a standard `<VcWidget>` from the config object.
6
6
 
@@ -17,18 +17,18 @@ import { useBladeWidgets, useBlade } from "@vc-shell/framework";
17
17
  import { computed } from "vue";
18
18
 
19
19
  const { openBlade } = useBlade();
20
- const offersCount = ref(0);
20
+ const childCount = ref(0);
21
21
 
22
22
  useBladeWidgets([
23
23
  {
24
- id: "OffersWidget",
24
+ id: "ChildListWidget",
25
25
  icon: "lucide-tag",
26
- title: "PRODUCTS.WIDGETS.OFFERS.TITLE",
27
- badge: computed(() => offersCount.value),
28
- isVisible: computed(() => !!param.value), // hide on "create new"
29
- onClick: () => openBlade({ name: "OffersList", options: { productId: entity.value.id } }),
26
+ title: "MODULE.WIDGETS.CHILD_LIST.TITLE",
27
+ badge: computed(() => childCount.value),
28
+ isVisible: computed(() => !!param.value), // hide on "create new"
29
+ onClick: () => openBlade({ name: "ChildEntityList", options: { entityId: entity.value.id } }),
30
30
  onRefresh: async () => {
31
- offersCount.value = await loadOffersCount(entity.value.id);
31
+ childCount.value = await loadChildCount(entity.value.id);
32
32
  },
33
33
  },
34
34
  ]);
@@ -66,10 +66,11 @@ export function useXxxWidgets(options: UseXxxWidgetsOptions): UseBladeWidgetsRet
66
66
  title: "XXX.WIDGETS.RELATED_ITEMS.TITLE",
67
67
  badge: relatedCount,
68
68
  isVisible,
69
- onClick: () => openBlade({
70
- name: "RelatedItemsList",
71
- options: { parentId: item.value?.id },
72
- }),
69
+ onClick: () =>
70
+ openBlade({
71
+ name: "RelatedItemsList",
72
+ options: { parentId: item.value?.id },
73
+ }),
73
74
  },
74
75
  ]);
75
76
  }
@@ -96,9 +97,9 @@ const { refreshAll } = useXxxWidgets({
96
97
 
97
98
  ```ts
98
99
  interface HeadlessWidgetDeclaration {
99
- id: string; // unique within the blade
100
- icon: string; // lucide icon name
101
- title: string; // i18n key or plain string
100
+ id: string; // unique within the blade
101
+ icon: string; // lucide icon name
102
+ title: string; // i18n key or plain string
102
103
  badge?: Ref<number | string> | ComputedRef<number | string>;
103
104
  loading?: Ref<boolean> | ComputedRef<boolean>;
104
105
  disabled?: Ref<boolean> | ComputedRef<boolean> | boolean;
@@ -112,8 +113,8 @@ interface HeadlessWidgetDeclaration {
112
113
 
113
114
  ```ts
114
115
  interface UseBladeWidgetsReturn {
115
- refresh: (widgetId: string) => void; // trigger onRefresh for one widget
116
- refreshAll: () => void; // trigger onRefresh for all widgets
116
+ refresh: (widgetId: string) => void; // trigger onRefresh for one widget
117
+ refreshAll: () => void; // trigger onRefresh for all widgets
117
118
  }
118
119
  ```
119
120
 
@@ -124,6 +125,7 @@ Call `refreshAll()` from `onMounted` or after data loads to populate badge count
124
125
  ## Lifecycle
125
126
 
126
127
  `useBladeWidgets()` automatically:
128
+
127
129
  - Registers all widgets with the `WidgetService` on `onMounted`
128
130
  - Unregisters all widgets from the `WidgetService` on `onUnmounted`
129
131
 
@@ -13,10 +13,14 @@ const { openBlade } = useBlade();
13
13
 
14
14
  openBlade({
15
15
  name: "ProductDetails",
16
- param: product.id, // string — entity ID, appears in URL
17
- options: { mode: "edit", origin: "catalog" }, // object — runtime-only, not in URL
18
- onOpen() { selectedItemId.value = product.id; },
19
- onClose() { selectedItemId.value = undefined; },
16
+ param: product.id, // string — entity ID, appears in URL
17
+ options: { mode: "edit", origin: "catalog" }, // object — runtime-only, not in URL
18
+ onOpen() {
19
+ selectedItemId.value = product.id;
20
+ },
21
+ onClose() {
22
+ selectedItemId.value = undefined;
23
+ },
20
24
  });
21
25
  ```
22
26
 
@@ -93,10 +97,12 @@ onBeforeClose(async () => {
93
97
  ```
94
98
 
95
99
  Return value semantics:
100
+
96
101
  - `false` — close is **allowed**
97
102
  - `true` — close is **blocked** (user stays on the blade)
98
103
 
99
104
  The `!(await showConfirmation(...))` idiom:
105
+
100
106
  - User clicks "Confirm" (discard) -> `true` -> `!true` = `false` -> close allowed
101
107
  - User clicks "Cancel" (stay) -> `false` -> `!false` = `true` -> close blocked
102
108
 
@@ -187,8 +193,12 @@ function onItemClick(event: { data: { id?: string } }) {
187
193
  openBlade({
188
194
  name: "ProductDetails",
189
195
  param: event.data.id,
190
- onOpen() { selectedItemId.value = event.data.id; },
191
- onClose() { selectedItemId.value = undefined; },
196
+ onOpen() {
197
+ selectedItemId.value = event.data.id;
198
+ },
199
+ onClose() {
200
+ selectedItemId.value = undefined;
201
+ },
192
202
  });
193
203
  }
194
204
 
@@ -250,7 +260,9 @@ A "middle" blade acts as both child (calls its parent) and parent (exposes metho
250
260
  const { openBlade, callParent, exposeToChildren, closeSelf } = useBlade();
251
261
 
252
262
  // As a parent — expose reload for child blades
253
- async function reload() { await loadOrder(param.value!); }
263
+ async function reload() {
264
+ await loadOrder(param.value!);
265
+ }
254
266
  exposeToChildren({ reload });
255
267
 
256
268
  // As a child — open sub-details blade
@@ -1,6 +1,6 @@
1
1
  # Details Composable Pattern (`use<Entity>`)
2
2
 
3
- Reference source: `apps/vendor-portal/src/modules/team/composables/useTeamMember/index.ts`
3
+ Generic worked example for the canonical `useTeamMember` / `useEntity` composable shape.
4
4
 
5
5
  ## Overview
6
6
 
@@ -13,19 +13,9 @@ Naming convention: `use<Entity>` (singular) for details, `use<Entity>s` (plural)
13
13
  ## Full Code Skeleton
14
14
 
15
15
  ```ts
16
- import {
17
- useModificationTracker,
18
- useApiClient,
19
- useAsync,
20
- useLoading,
21
- } from "@vc-shell/framework";
16
+ import { useModificationTracker, useApiClient, useAsync, useLoading } from "@vc-shell/framework";
22
17
  import type { AsyncAction } from "@vc-shell/framework";
23
- import {
24
- XxxClient,
25
- XxxType,
26
- CreateXxxCommand,
27
- UpdateXxxCommand,
28
- } from "../../api_client/xxx-client";
18
+ import { XxxClient, XxxType, CreateXxxCommand, UpdateXxxCommand } from "../../api_client/xxx-client";
29
19
  import { computed, ComputedRef, Ref, ref } from "vue";
30
20
 
31
21
  // NOTE: useI18n is NOT imported here. Translations belong in blade components.
@@ -50,15 +40,11 @@ export default (): IUseXxx => {
50
40
  // --- Entity ref and modification tracker ---
51
41
  // entityRef is internal; currentValue is exposed as `entity`
52
42
  const entityRef = ref({} as XxxType) as Ref<XxxType>;
53
- const { currentValue, pristineValue, resetModificationState, isModified } =
54
- useModificationTracker(entityRef);
43
+ const { currentValue, pristineValue, resetModificationState, isModified } = useModificationTracker(entityRef);
55
44
 
56
45
  // --- CRUD operations (each has its own loading ref) ---
57
46
 
58
- const { action: getXxx, loading: getXxxLoading } = useAsync<
59
- { id: string },
60
- void
61
- >(async (args) => {
47
+ const { action: getXxx, loading: getXxxLoading } = useAsync<{ id: string }, void>(async (args) => {
62
48
  if (!args?.id) {
63
49
  throw new Error("Id is required");
64
50
  }
@@ -74,10 +60,7 @@ export default (): IUseXxx => {
74
60
  resetModificationState();
75
61
  });
76
62
 
77
- const { action: createXxx, loading: createXxxLoading } = useAsync<
78
- XxxType,
79
- void
80
- >(async (details) => {
63
+ const { action: createXxx, loading: createXxxLoading } = useAsync<XxxType, void>(async (details) => {
81
64
  const client = await getApiClient();
82
65
 
83
66
  const command = {
@@ -93,10 +76,7 @@ export default (): IUseXxx => {
93
76
  resetModificationState();
94
77
  });
95
78
 
96
- const { action: updateXxx, loading: updateXxxLoading } = useAsync<
97
- XxxType,
98
- void
99
- >(async (details) => {
79
+ const { action: updateXxx, loading: updateXxxLoading } = useAsync<XxxType, void>(async (details) => {
100
80
  if (!details?.id) {
101
81
  throw new Error("Id is required");
102
82
  }
@@ -116,10 +96,7 @@ export default (): IUseXxx => {
116
96
  resetModificationState();
117
97
  });
118
98
 
119
- const { action: deleteXxx, loading: deleteXxxLoading } = useAsync<
120
- { id: string },
121
- void
122
- >(async (args) => {
99
+ const { action: deleteXxx, loading: deleteXxxLoading } = useAsync<{ id: string }, void>(async (args) => {
123
100
  if (!args?.id) {
124
101
  throw new Error("Id is required");
125
102
  }
@@ -138,12 +115,7 @@ export default (): IUseXxx => {
138
115
  // --- Return ---
139
116
  return {
140
117
  // Aggregate all async loading refs into a single computed boolean
141
- loading: useLoading(
142
- getXxxLoading,
143
- createXxxLoading,
144
- updateXxxLoading,
145
- deleteXxxLoading,
146
- ),
118
+ loading: useLoading(getXxxLoading, createXxxLoading, updateXxxLoading, deleteXxxLoading),
147
119
  // currentValue is the reactive entity — alias as `entity` for the blade
148
120
  entity: currentValue,
149
121
  modified: computed(() => isModified.value),
@@ -263,9 +235,9 @@ export default (): IUseXxx => {
263
235
 
264
236
  ---
265
237
 
266
- ## Route Params (when entity scope requires sellerId / tenantId)
238
+ ## Route Params (when entity scope requires a parent ownerId / tenantId)
267
239
 
268
- Some API calls require a scope parameter (e.g., `sellerId`) extracted from the route. Use `useRoute()`:
240
+ Some API calls require a scope parameter (e.g., `ownerId`) extracted from the route. Use `useRoute()`:
269
241
 
270
242
  ```ts
271
243
  import { useRoute } from "vue-router";
@@ -274,20 +246,18 @@ export default (): IUseXxx => {
274
246
  const route = useRoute();
275
247
  const { getApiClient } = useApiClient(XxxClient);
276
248
 
277
- async function getSellerId(): Promise<string> {
278
- return route?.params?.sellerId as string;
249
+ async function getOwnerId(): Promise<string> {
250
+ return route?.params?.ownerId as string;
279
251
  }
280
252
 
281
- const { action: getXxx, loading: getXxxLoading } = useAsync<{ id: string }>(
282
- async (args) => {
283
- const client = await getApiClient();
284
- const sellerId = await getSellerId();
253
+ const { action: getXxx, loading: getXxxLoading } = useAsync<{ id: string }>(async (args) => {
254
+ const client = await getApiClient();
255
+ const ownerId = await getOwnerId();
285
256
 
286
- const result = await client.getXxx(args.id, sellerId);
287
- currentValue.value = result;
288
- resetModificationState();
289
- },
290
- );
257
+ const result = await client.getXxx(args.id, ownerId);
258
+ currentValue.value = result;
259
+ resetModificationState();
260
+ });
291
261
 
292
262
  // ...
293
263
  };