@vc-shell/vc-app-skill 2.0.0-alpha.32 → 2.0.0-alpha.33-pr220.455e322

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 +59 -47
  2. package/README.md +18 -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 +94 -0
  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 +31 -27
  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 +75 -19
  29. package/runtime/knowledge/docs/core/composables/useBladeRegistry/useBladeRegistry.docs.md +15 -15
  30. package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +74 -78
  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 +10 -10
  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/usePopup/usePopup.docs.md +32 -24
  46. package/runtime/knowledge/docs/core/composables/useResponsive/useResponsive.docs.md +32 -11
  47. package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +24 -15
  48. package/runtime/knowledge/docs/core/composables/useSettingsMenu/useSettingsMenu.docs.md +7 -7
  49. package/runtime/knowledge/docs/core/composables/useSidebarState/useSidebarState.docs.md +32 -24
  50. package/runtime/knowledge/docs/core/composables/useSlowNetworkDetection/useSlowNetworkDetection.docs.md +21 -17
  51. package/runtime/knowledge/docs/core/composables/useTheme/useTheme.docs.md +24 -24
  52. package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +28 -31
  53. package/runtime/knowledge/docs/core/composables/useUser/useUser.docs.md +43 -24
  54. package/runtime/knowledge/docs/core/composables/useUserManagement/useUserManagement.docs.md +68 -48
  55. package/runtime/knowledge/docs/core/composables/useWebVitals/useWebVitals.docs.md +19 -19
  56. package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +42 -47
  57. package/runtime/knowledge/docs/core/directives/autofocus/autofocus.docs.md +10 -4
  58. package/runtime/knowledge/docs/core/directives/loading/loading.docs.md +35 -20
  59. package/runtime/knowledge/docs/core/notifications/notifications.docs.md +36 -35
  60. package/runtime/knowledge/docs/core/plugins/ai-agent/ai-agent.docs.md +38 -38
  61. package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +107 -91
  62. package/runtime/knowledge/docs/core/plugins/global-error-handler/global-error-handler.docs.md +10 -10
  63. package/runtime/knowledge/docs/core/plugins/i18n/i18n.docs.md +21 -23
  64. package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +98 -90
  65. package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +10 -16
  66. package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +9 -9
  67. package/runtime/knowledge/docs/core/plugins/validation/validation.docs.md +65 -22
  68. package/runtime/knowledge/docs/core/services/services.docs.md +19 -22
  69. package/runtime/knowledge/docs/core/types/types.docs.md +40 -40
  70. package/runtime/knowledge/docs/core/utilities/date/date-utilities.docs.md +27 -27
  71. package/runtime/knowledge/docs/core/utilities/shared-utilities.docs.md +23 -23
  72. package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +22 -25
  73. package/runtime/knowledge/docs/core/utilities/utilities.docs.md +64 -64
  74. package/runtime/knowledge/docs/injection-keys.docs.md +52 -51
  75. package/runtime/knowledge/docs/modules/assets-manager/assets-manager.docs.md +9 -9
  76. package/runtime/knowledge/docs/shell/_internal/popup/common/popup-common.docs.md +23 -43
  77. package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +102 -0
  78. package/runtime/knowledge/docs/shell/auth/ForgotPasswordPage/forgot-password-page.docs.md +5 -5
  79. package/runtime/knowledge/docs/shell/auth/InvitePage/invite-page.docs.md +8 -7
  80. package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +7 -7
  81. package/runtime/knowledge/docs/shell/auth/ResetPasswordPage/reset-password-page.docs.md +8 -7
  82. package/runtime/knowledge/docs/shell/auth/sign-in/sign-in.docs.md +29 -13
  83. package/runtime/knowledge/docs/shell/components/change-password/change-password.docs.md +13 -16
  84. package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +1 -7
  85. package/runtime/knowledge/docs/shell/components/error-interceptor/error-interceptor.docs.md +5 -5
  86. package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +1 -1
  87. package/runtime/knowledge/docs/shell/components/logout-button/logout-button.docs.md +1 -1
  88. package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +17 -9
  89. package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +12 -18
  90. package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +34 -65
  91. package/runtime/knowledge/docs/shell/components/sidebar/sidebar.docs.md +16 -26
  92. package/runtime/knowledge/docs/shell/components/theme-selector/theme-selector.docs.md +2 -2
  93. package/runtime/knowledge/docs/shell/components/user-dropdown-button/user-dropdown-button.docs.md +7 -9
  94. package/runtime/knowledge/docs/shell/dashboard/dashboard-charts/dashboard-charts.docs.md +30 -40
  95. package/runtime/knowledge/docs/shell/dashboard/dashboard-widget-card/dashboard-widget-card.docs.md +26 -19
  96. package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +15 -12
  97. package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +15 -26
  98. package/runtime/knowledge/docs/ui/components/atoms/vc-banner/vc-banner.docs.md +21 -19
  99. package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +83 -67
  100. package/runtime/knowledge/docs/ui/components/atoms/vc-card/vc-card.docs.md +104 -59
  101. package/runtime/knowledge/docs/ui/components/atoms/vc-col/vc-col.docs.md +28 -11
  102. package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +20 -17
  103. package/runtime/knowledge/docs/ui/components/atoms/vc-hint/vc-hint.docs.md +26 -17
  104. package/runtime/knowledge/docs/ui/components/atoms/vc-icon/vc-icon.docs.md +30 -32
  105. package/runtime/knowledge/docs/ui/components/atoms/vc-image/vc-image.docs.md +25 -48
  106. package/runtime/knowledge/docs/ui/components/atoms/vc-label/vc-label.docs.md +29 -24
  107. package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +23 -15
  108. package/runtime/knowledge/docs/ui/components/atoms/vc-loading/vc-loading.docs.md +22 -13
  109. package/runtime/knowledge/docs/ui/components/atoms/vc-progress/vc-progress.docs.md +33 -18
  110. package/runtime/knowledge/docs/ui/components/atoms/vc-row/vc-row.docs.md +56 -15
  111. package/runtime/knowledge/docs/ui/components/atoms/vc-scrollable-container/vc-scrollable-container.docs.md +28 -15
  112. package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +40 -20
  113. package/runtime/knowledge/docs/ui/components/atoms/vc-status/vc-status.docs.md +25 -14
  114. package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +40 -14
  115. package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +54 -42
  116. package/runtime/knowledge/docs/ui/components/atoms/vc-video/vc-video.docs.md +17 -17
  117. package/runtime/knowledge/docs/ui/components/atoms/vc-widget/vc-widget.docs.md +21 -21
  118. package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +23 -10
  119. package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +59 -44
  120. package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +23 -20
  121. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +96 -64
  122. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +26 -35
  123. package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +69 -22
  124. package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +58 -72
  125. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown/vc-dropdown.docs.md +91 -85
  126. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md +38 -42
  127. package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +60 -72
  128. package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +65 -26
  129. package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +46 -49
  130. package/runtime/knowledge/docs/ui/components/molecules/vc-form/vc-form.docs.md +35 -64
  131. package/runtime/knowledge/docs/ui/components/molecules/vc-image-tile/vc-image-tile.docs.md +38 -41
  132. package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +115 -130
  133. package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +53 -87
  134. package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +56 -63
  135. package/runtime/knowledge/docs/ui/components/molecules/vc-input-group/vc-input-group.docs.md +29 -24
  136. package/runtime/knowledge/docs/ui/components/molecules/vc-menu/vc-menu.docs.md +32 -28
  137. package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +63 -64
  138. package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +28 -26
  139. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +59 -19
  140. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md +25 -34
  141. package/runtime/knowledge/docs/ui/components/molecules/vc-rating/vc-rating.docs.md +42 -32
  142. package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +78 -82
  143. package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +25 -15
  144. package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +59 -63
  145. package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +57 -69
  146. package/runtime/knowledge/docs/ui/components/molecules/vc-toast/vc-toast.docs.md +58 -57
  147. package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +49 -26
  148. package/runtime/knowledge/docs/ui/components/organisms/vc-auth-layout/vc-auth-layout.docs.md +82 -28
  149. package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +120 -75
  150. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/composables/table-composables.docs.md +30 -44
  151. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +536 -365
  152. package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +35 -52
  153. package/runtime/knowledge/docs/ui/components/organisms/vc-gallery/vc-gallery.docs.md +33 -62
  154. package/runtime/knowledge/docs/ui/components/organisms/vc-image-upload/vc-image-upload.docs.md +17 -23
  155. package/runtime/knowledge/docs/ui/components/organisms/vc-popup/vc-popup.docs.md +109 -68
  156. package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +82 -44
  157. package/runtime/knowledge/docs/ui/composables/ui-composables.docs.md +8 -8
  158. package/runtime/knowledge/docs/ui/composables/useDataTablePagination.docs.md +164 -0
  159. package/runtime/knowledge/docs/ui/composables/useDataTableSort.docs.md +34 -26
  160. package/runtime/knowledge/docs/ui/composables/useTableSelection.docs.md +48 -40
  161. package/runtime/knowledge/docs/ui/composables/useTableSort.docs.md +30 -17
  162. package/runtime/knowledge/docs/ui/types/ui-types.docs.md +40 -29
  163. package/runtime/knowledge/examples/offers-module.md +15 -13
  164. package/runtime/knowledge/examples/team-module.md +82 -119
  165. package/runtime/knowledge/examples/videos-module.md +44 -17
  166. package/runtime/knowledge/index.md +22 -0
  167. package/runtime/knowledge/migration-prompts/blade-form-migration.md +255 -0
  168. package/runtime/knowledge/migration-prompts/blade-props-migration.md +194 -0
  169. package/runtime/knowledge/migration-prompts/datatable-migration.md +801 -0
  170. package/runtime/knowledge/migration-prompts/icon-migration.md +97 -0
  171. package/runtime/knowledge/migration-prompts/manual-migration-audit.md +117 -0
  172. package/runtime/knowledge/migration-prompts/notifications-migration.md +223 -0
  173. package/runtime/knowledge/migration-prompts/nswag-migration.md +244 -0
  174. package/runtime/knowledge/migration-prompts/use-assets-migration.md +164 -0
  175. package/runtime/knowledge/migration-prompts/use-data-table-pagination-migration.md +176 -0
  176. package/runtime/knowledge/migration-prompts/widgets-migration.md +178 -0
  177. package/runtime/knowledge/patterns/assets-management.md +20 -20
  178. package/runtime/knowledge/patterns/blade-navigation.md +7 -14
  179. package/runtime/knowledge/patterns/blade-widget.md +19 -17
  180. package/runtime/knowledge/patterns/child-blade-flow.md +19 -7
  181. package/runtime/knowledge/patterns/composable-details.md +20 -50
  182. package/runtime/knowledge/patterns/composable-list.md +43 -31
  183. package/runtime/knowledge/patterns/dashboard-widget.md +14 -16
  184. package/runtime/knowledge/patterns/datatable-pattern.md +521 -0
  185. package/runtime/knowledge/patterns/details-blade-pattern.md +78 -116
  186. package/runtime/knowledge/patterns/extension-points-usage.md +53 -44
  187. package/runtime/knowledge/patterns/form-validation.md +28 -64
  188. package/runtime/knowledge/patterns/list-blade-pattern.md +33 -21
  189. package/runtime/knowledge/patterns/module-structure.md +7 -1
  190. package/runtime/knowledge/patterns/multilanguage-fields.md +8 -14
  191. package/runtime/knowledge/patterns/notification-template.md +21 -14
  192. package/runtime/knowledge/patterns/signalr-notifications.md +30 -32
  193. package/runtime/knowledge/patterns/toolbar-pattern.md +18 -20
  194. package/runtime/vc-app.md +354 -49
  195. package/runtime/knowledge/docs/core/constants/constants.docs.md +0 -185
@@ -16,17 +16,26 @@ Uses `createSharedComposable` from VueUse, so all callers across the entire appl
16
16
 
17
17
  ```vue
18
18
  <script setup lang="ts">
19
- import { useUser } from '@vc-shell/framework';
19
+ import { useUser } from "@vc-shell/framework";
20
20
 
21
21
  const { user, isAuthenticated, isAdministrator, loading } = useUser();
22
22
  </script>
23
23
 
24
24
  <template>
25
- <div v-if="loading" class="tw-animate-pulse">Loading user...</div>
25
+ <div
26
+ v-if="loading"
27
+ class="tw-animate-pulse"
28
+ >
29
+ Loading user...
30
+ </div>
26
31
 
27
32
  <div v-else-if="isAuthenticated">
28
33
  <p>Welcome, {{ user?.userName }}</p>
29
- <span v-if="isAdministrator" class="tw-badge tw-badge-primary">Admin</span>
34
+ <span
35
+ v-if="isAdministrator"
36
+ class="tw-badge tw-badge-primary"
37
+ >Admin</span
38
+ >
30
39
  </div>
31
40
 
32
41
  <div v-else>
@@ -43,15 +52,15 @@ None.
43
52
 
44
53
  ### Returns
45
54
 
46
- | Property | Type | Description |
47
- |----------|------|-------------|
48
- | `user` | `ComputedRef<UserDetail \| undefined>` | Current user details (userName, email, id, etc.), or `undefined` if not authenticated. |
49
- | `loading` | `ComputedRef<boolean>` | Whether a user operation (loadUser, signOut) is in progress. |
50
- | `isAuthenticated` | `ComputedRef<boolean>` | Whether a user session is active. Derived from `user.userName != null`. |
51
- | `isAdministrator` | `ComputedRef<boolean \| undefined>` | Whether the current user has admin privileges. `undefined` if user is not loaded. |
52
- | `loadUser` | `() => Promise<UserDetail>` | Loads/reloads user info from the server. Deduplicates concurrent calls -- if two components call `loadUser()` at the same time, only one API request is made. |
53
- | `signOut` | `() => Promise<void>` | Signs out the current user, clears auth data from localStorage, and resets the user state. Handles both standard and external (SSO) sign-out flows. |
54
- | `getAccessToken` | `() => Promise<string \| null>` | Returns the current OAuth access token. Automatically refreshes using the refresh token if the access token has expired or will expire within 60 seconds. Returns `null` if no auth data exists. |
55
+ | Property | Type | Description |
56
+ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
57
+ | `user` | `ComputedRef<UserDetail \| undefined>` | Current user details (userName, email, id, etc.), or `undefined` if not authenticated. |
58
+ | `loading` | `ComputedRef<boolean>` | Whether a user operation (loadUser, signOut) is in progress. |
59
+ | `isAuthenticated` | `ComputedRef<boolean>` | Whether a user session is active. Derived from `user.userName != null`. |
60
+ | `isAdministrator` | `ComputedRef<boolean \| undefined>` | Whether the current user has admin privileges. `undefined` if user is not loaded. |
61
+ | `loadUser` | `() => Promise<UserDetail>` | Loads/reloads user info from the server. Deduplicates concurrent calls -- if two components call `loadUser()` at the same time, only one API request is made. |
62
+ | `signOut` | `() => Promise<void>` | Signs out the current user, clears auth data from localStorage, and resets the user state. Handles both standard and external (SSO) sign-out flows. |
63
+ | `getAccessToken` | `() => Promise<string \| null>` | Returns the current OAuth access token. Automatically refreshes using the refresh token if the access token has expired or will expire within 60 seconds. Returns `null` if no auth data exists. |
55
64
 
56
65
  ## How It Works
57
66
 
@@ -63,14 +72,16 @@ The composable delegates to `_createInternalUserLogic()`, which manages:
63
72
 
64
73
  3. **Token refresh**: `getAccessToken()` checks the expiration time with a 60-second buffer. If the token is expired or about to expire and a refresh token is available, it makes a `POST /connect/token` request with `grant_type: refresh_token`.
65
74
 
66
- 4. **Shared state**: `createSharedComposable` from VueUse ensures all calls to `useUser()` return the same reactive refs. The underlying `user` ref is module-level, so it persists across component lifecycles.
75
+ 4. **Shared state**: `createSharedComposable` from VueUse wraps `_createInternalUserLogic` so every call to `useUser()` or `useUserManagement()` reads from the same singleton internal logic. The `user` ref lives inside that singleton. App bootstrap registers `useUserManagement()` outside any component scope, which pins the singleton for the app lifetime — transient component mount/unmount cycles don't discard it.
67
76
 
68
77
  ## Recipe: Route Guard Based on Authentication
69
78
 
70
79
  ```typescript
71
- import { useUser } from '@vc-shell/framework';
80
+ import { useUser } from "@vc-shell/framework";
72
81
 
73
- const router = createRouter({ /* ... */ });
82
+ const router = createRouter({
83
+ /* ... */
84
+ });
74
85
 
75
86
  router.beforeEach(async (to) => {
76
87
  const { isAuthenticated, loadUser } = useUser();
@@ -85,7 +96,7 @@ router.beforeEach(async (to) => {
85
96
  }
86
97
 
87
98
  if (to.meta.requiresAuth && !isAuthenticated.value) {
88
- return { name: 'SignIn' };
99
+ return { name: "SignIn" };
89
100
  }
90
101
  });
91
102
  ```
@@ -95,25 +106,33 @@ router.beforeEach(async (to) => {
95
106
  ```vue
96
107
  <template>
97
108
  <div class="tw-flex tw-items-center tw-gap-2">
98
- <VcAvatar :name="user?.userName" size="sm" />
109
+ <VcAvatar
110
+ :name="user?.userName"
111
+ size="sm"
112
+ />
99
113
  <div>
100
114
  <p class="tw-text-sm tw-font-medium">{{ user?.userName }}</p>
101
115
  <p class="tw-text-xs tw-text-gray-500">{{ user?.email }}</p>
102
116
  </div>
103
- <VcButton size="sm" variant="ghost" @click="handleSignOut">Sign Out</VcButton>
117
+ <VcButton
118
+ size="sm"
119
+ variant="ghost"
120
+ @click="handleSignOut"
121
+ >Sign Out</VcButton
122
+ >
104
123
  </div>
105
124
  </template>
106
125
 
107
126
  <script setup lang="ts">
108
- import { useUser } from '@vc-shell/framework';
109
- import { useRouter } from 'vue-router';
127
+ import { useUser } from "@vc-shell/framework";
128
+ import { useRouter } from "vue-router";
110
129
 
111
130
  const { user, signOut } = useUser();
112
131
  const router = useRouter();
113
132
 
114
133
  async function handleSignOut() {
115
134
  await signOut();
116
- router.push({ name: 'SignIn' });
135
+ router.push({ name: "SignIn" });
117
136
  }
118
137
  </script>
119
138
  ```
@@ -121,7 +140,7 @@ async function handleSignOut() {
121
140
  ## Recipe: Adding Access Token to Custom API Calls
122
141
 
123
142
  ```typescript
124
- import { useUser } from '@vc-shell/framework';
143
+ import { useUser } from "@vc-shell/framework";
125
144
 
126
145
  const { getAccessToken } = useUser();
127
146
 
@@ -130,7 +149,7 @@ async function fetchCustomEndpoint(url: string) {
130
149
 
131
150
  const response = await fetch(url, {
132
151
  headers: {
133
- Authorization: token ? `Bearer ${token}` : '',
152
+ Authorization: token ? `Bearer ${token}` : "",
134
153
  },
135
154
  });
136
155
 
@@ -140,7 +159,7 @@ async function fetchCustomEndpoint(url: string) {
140
159
 
141
160
  ## Tips
142
161
 
143
- - **`loadUser` deduplicates concurrent calls.** If your app loads multiple blades simultaneously and each calls `loadUser()`, only one API request is made. All calls resolve with the same result.
162
+ - **`loadUser` deduplicates concurrent calls across composables.** If multiple blades call `loadUser()` simultaneously or if `useUser()` and `useUserManagement()` are both used in the same flow — only one API request is made. `useUser` and `useUserManagement` share the singleton internal logic, so request deduplication works across both.
144
163
  - **Token refresh is transparent.** `getAccessToken()` handles expiration checking and refresh internally. You never need to manually check token expiration or call a refresh endpoint.
145
164
  - **`isAuthenticated` checks `userName`, not the token.** A user is considered authenticated if `user.value?.userName` is not null. This means the user could have an expired token but still appear "authenticated" until the next API call fails.
146
165
  - **`signOut` clears localStorage.** After sign-out, the `vc_auth_data` key is removed from localStorage. Any cached tokens are gone permanently.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Shared composable exposing the full user management API: sign-in, sign-out, password reset, token validation, and login type discovery. This composable extends the same internal logic as `useUser` but surfaces the administrative and authentication-flow methods that `useUser` intentionally hides. The separation ensures that regular blades only have access to read-only user state, while auth pages and admin screens get the full API.
4
4
 
5
- Uses `createSharedComposable` from VueUse, so all callers share the same state instance. Internally, it calls `_createInternalUserLogic()` -- the same factory used by `useUser` -- so both composables operate on the same underlying user ref and auth data.
5
+ Both `useUser()` and `useUserManagement()` read from the same singleton internal logic, so everything is shared: the `user` ref, `authData`, the `loading` ref, in-flight request deduplication (`loadUser`), and the underlying `SecurityClient` instance. The two composables are thin selectors over a single source of truth — picking a narrow read-only slice or the full management slice.
6
6
 
7
7
  ## When to Use
8
8
 
@@ -17,29 +17,45 @@ Uses `createSharedComposable` from VueUse, so all callers share the same state i
17
17
 
18
18
  ```vue
19
19
  <script setup lang="ts">
20
- import { useUserManagement } from '@vc-shell/framework';
21
- import { ref } from 'vue';
20
+ import { useUserManagement } from "@vc-shell/framework";
21
+ import { ref } from "vue";
22
22
 
23
23
  const { signIn, loading, isAuthenticated } = useUserManagement();
24
- const username = ref('');
25
- const password = ref('');
26
- const errorMessage = ref('');
24
+ const username = ref("");
25
+ const password = ref("");
26
+ const errorMessage = ref("");
27
27
 
28
28
  async function handleLogin() {
29
- errorMessage.value = '';
29
+ errorMessage.value = "";
30
30
  const result = await signIn(username.value, password.value);
31
31
  if (!result.succeeded) {
32
- errorMessage.value = result.error ?? 'Login failed';
32
+ errorMessage.value = result.error ?? "Login failed";
33
33
  }
34
34
  }
35
35
  </script>
36
36
 
37
37
  <template>
38
38
  <form @submit.prevent="handleLogin">
39
- <VcInput v-model="username" label="Username" />
40
- <VcInput v-model="password" label="Password" type="password" />
41
- <p v-if="errorMessage" class="tw-text-red-500">{{ errorMessage }}</p>
42
- <VcButton type="submit" :loading="loading">Sign In</VcButton>
39
+ <VcInput
40
+ v-model="username"
41
+ label="Username"
42
+ />
43
+ <VcInput
44
+ v-model="password"
45
+ label="Password"
46
+ type="password"
47
+ />
48
+ <p
49
+ v-if="errorMessage"
50
+ class="tw-text-red-500"
51
+ >
52
+ {{ errorMessage }}
53
+ </p>
54
+ <VcButton
55
+ type="submit"
56
+ :loading="loading"
57
+ >Sign In</VcButton
58
+ >
43
59
  </form>
44
60
  </template>
45
61
  ```
@@ -52,25 +68,25 @@ None.
52
68
 
53
69
  ### Returns
54
70
 
55
- | Property | Type | Description |
56
- |----------|------|-------------|
57
- | `user` | `ComputedRef<UserDetail \| undefined>` | Current user details. |
58
- | `loading` | `ComputedRef<boolean>` | Whether any operation is in progress. |
59
- | `isAdministrator` | `ComputedRef<boolean \| undefined>` | Admin status of the current user. |
60
- | `isAuthenticated` | `ComputedRef<boolean>` | Whether user session is active. |
61
- | `signIn` | `(username: string, password: string) => Promise<SignInResult>` | Authenticates with username/password. Performs cookie-based login, obtains an OAuth token with offline_access scope, and loads user details. Returns `{ succeeded: true }` on success or `{ succeeded: false, error: string }` on failure. |
62
- | `signOut` | `() => Promise<void>` | Clears session, auth data, and localStorage. Handles both standard and external SSO sign-out. |
63
- | `loadUser` | `() => Promise<UserDetail>` | Loads/reloads user info from the server. Deduplicates concurrent calls. |
64
- | `validateToken` | `(userId: string, token: string) => Promise<boolean>` | Validates a password-reset token. Returns `true` if valid. |
65
- | `validatePassword` | `(password: string) => Promise<IdentityResult>` | Validates a password against the platform's password policy (length, complexity, etc.). |
66
- | `resetPasswordByToken` | `(userId: string, password: string, token: string) => Promise<SecurityResult>` | Resets a user's password using a reset token. Returns `{ succeeded: true }` on success. |
67
- | `requestPasswordReset` | `(loginOrEmail: string) => Promise<RequestPasswordResult>` | Sends a password-reset email to the user. Returns `{ succeeded: true }` on success. |
68
- | `changeUserPassword` | `(oldPassword: string, newPassword: string) => Promise<SecurityResult \| undefined>` | Changes the current user's password. Requires the old password for verification. |
69
- | `getLoginType` | `() => Promise<LoginType[]>` | Returns available login types (password-based, external SSO providers, etc.). Used to render the appropriate sign-in UI. |
71
+ | Property | Type | Description |
72
+ | ---------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
73
+ | `user` | `ComputedRef<UserDetail \| undefined>` | Current user details. |
74
+ | `loading` | `ComputedRef<boolean>` | Whether any operation is in progress. |
75
+ | `isAdministrator` | `ComputedRef<boolean \| undefined>` | Admin status of the current user. |
76
+ | `isAuthenticated` | `ComputedRef<boolean>` | Whether user session is active. |
77
+ | `signIn` | `(username: string, password: string) => Promise<SignInResult>` | Authenticates with username/password. Performs cookie-based login, obtains an OAuth token with offline_access scope, and loads user details. Returns `{ succeeded: true }` on success or `{ succeeded: false, error: string }` on failure. |
78
+ | `signOut` | `() => Promise<void>` | Clears session, auth data, and localStorage. Handles both standard and external SSO sign-out. |
79
+ | `loadUser` | `() => Promise<UserDetail>` | Loads/reloads user info from the server. Deduplicates concurrent calls. |
80
+ | `validateToken` | `(userId: string, token: string) => Promise<boolean>` | Validates a password-reset token. Returns `true` if valid. |
81
+ | `validatePassword` | `(password: string) => Promise<IdentityResult>` | Validates a password against the platform's password policy (length, complexity, etc.). |
82
+ | `resetPasswordByToken` | `(userId: string, password: string, token: string) => Promise<SecurityResult>` | Resets a user's password using a reset token. Returns `{ succeeded: true }` on success. |
83
+ | `requestPasswordReset` | `(loginOrEmail: string) => Promise<RequestPasswordResult>` | Sends a password-reset email to the user. Returns `{ succeeded: true }` on success. |
84
+ | `changeUserPassword` | `(oldPassword: string, newPassword: string) => Promise<SecurityResult \| undefined>` | Changes the current user's password. Requires the old password for verification. |
85
+ | `getLoginType` | `() => Promise<LoginType[]>` | Returns available login types (password-based, external SSO providers, etc.). Used to render the appropriate sign-in UI. |
70
86
 
71
87
  ## How It Works
72
88
 
73
- The composable creates (or reuses) the internal user logic via `_createInternalUserLogic()`. The `signIn` flow has three phases:
89
+ The composable reads from the singleton internal user logic (instantiated lazily on first call to `useUser()` or `useUserManagement()`). The `signIn` flow has three phases:
74
90
 
75
91
  1. **Cookie login**: Calls `securityClient.login()` to establish a server-side session cookie.
76
92
  2. **OAuth token**: Fetches an OAuth token via `POST /connect/token` with `grant_type: password` and `scope: offline_access`. The refresh token enables automatic token renewal.
@@ -82,9 +98,9 @@ Token data is stored in localStorage under `vc_auth_data` and survives page relo
82
98
 
83
99
  ```vue
84
100
  <script setup lang="ts">
85
- import { useUserManagement } from '@vc-shell/framework';
86
- import { ref } from 'vue';
87
- import { useRoute, useRouter } from 'vue-router';
101
+ import { useUserManagement } from "@vc-shell/framework";
102
+ import { ref } from "vue";
103
+ import { useRoute, useRouter } from "vue-router";
88
104
 
89
105
  const { validateToken, validatePassword, resetPasswordByToken, loading } = useUserManagement();
90
106
  const route = useRoute();
@@ -92,39 +108,39 @@ const router = useRouter();
92
108
 
93
109
  const userId = route.query.userId as string;
94
110
  const token = route.query.token as string;
95
- const newPassword = ref('');
96
- const confirmPassword = ref('');
97
- const error = ref('');
111
+ const newPassword = ref("");
112
+ const confirmPassword = ref("");
113
+ const error = ref("");
98
114
  const tokenValid = ref(false);
99
115
 
100
116
  // Validate the token on mount
101
117
  onMounted(async () => {
102
118
  tokenValid.value = await validateToken(userId, token);
103
119
  if (!tokenValid.value) {
104
- error.value = 'This reset link has expired or is invalid.';
120
+ error.value = "This reset link has expired or is invalid.";
105
121
  }
106
122
  });
107
123
 
108
124
  async function handleReset() {
109
- error.value = '';
125
+ error.value = "";
110
126
 
111
127
  if (newPassword.value !== confirmPassword.value) {
112
- error.value = 'Passwords do not match.';
128
+ error.value = "Passwords do not match.";
113
129
  return;
114
130
  }
115
131
 
116
132
  // Validate against password policy
117
133
  const validation = await validatePassword(newPassword.value);
118
134
  if (!validation.succeeded) {
119
- error.value = validation.errors?.join(', ') ?? 'Password does not meet requirements.';
135
+ error.value = validation.errors?.join(", ") ?? "Password does not meet requirements.";
120
136
  return;
121
137
  }
122
138
 
123
139
  const result = await resetPasswordByToken(userId, newPassword.value, token);
124
140
  if (result.succeeded) {
125
- router.push({ name: 'SignIn', query: { message: 'Password reset successfully' } });
141
+ router.push({ name: "SignIn", query: { message: "Password reset successfully" } });
126
142
  } else {
127
- error.value = result.errors?.join(', ') ?? 'Reset failed.';
143
+ error.value = result.errors?.join(", ") ?? "Reset failed.";
128
144
  }
129
145
  }
130
146
  </script>
@@ -134,8 +150,8 @@ async function handleReset() {
134
150
 
135
151
  ```vue
136
152
  <script setup lang="ts">
137
- import { useUserManagement } from '@vc-shell/framework';
138
- import { ref, onMounted } from 'vue';
153
+ import { useUserManagement } from "@vc-shell/framework";
154
+ import { ref, onMounted } from "vue";
139
155
 
140
156
  const { getLoginType, signIn } = useUserManagement();
141
157
  const loginTypes = ref<LoginType[]>([]);
@@ -144,20 +160,24 @@ const showPasswordForm = ref(false);
144
160
  onMounted(async () => {
145
161
  loginTypes.value = await getLoginType();
146
162
  // Show password form only if password auth is available
147
- showPasswordForm.value = loginTypes.value.some((t) => t.loginProvider === 'password');
163
+ showPasswordForm.value = loginTypes.value.some((t) => t.loginProvider === "password");
148
164
  });
149
165
  </script>
150
166
 
151
167
  <template>
152
168
  <div>
153
- <form v-if="showPasswordForm" @submit.prevent="handlePasswordLogin">
169
+ <form
170
+ v-if="showPasswordForm"
171
+ @submit.prevent="handlePasswordLogin"
172
+ >
154
173
  <!-- standard username/password form -->
155
174
  </form>
156
175
 
157
- <div v-for="provider in loginTypes.filter((t) => t.loginProvider !== 'password')" :key="provider.loginProvider">
158
- <VcButton @click="redirectToSSO(provider)">
159
- Sign in with {{ provider.loginProvider }}
160
- </VcButton>
176
+ <div
177
+ v-for="provider in loginTypes.filter((t) => t.loginProvider !== 'password')"
178
+ :key="provider.loginProvider"
179
+ >
180
+ <VcButton @click="redirectToSSO(provider)"> Sign in with {{ provider.loginProvider }} </VcButton>
161
181
  </div>
162
182
  </div>
163
183
  </template>
@@ -12,16 +12,16 @@ Registers Core Web Vitals observers (FCP, LCP, CLS, INP, TTFB) and reports metri
12
12
  ## Quick Start
13
13
 
14
14
  ```typescript
15
- import { useWebVitals } from '@vc-shell/framework';
15
+ import { useWebVitals } from "@vc-shell/framework";
16
16
 
17
17
  // Option 1: Default behavior -- logs to console.warn in dev mode, silent in production
18
18
  useWebVitals();
19
19
 
20
20
  // Option 2: Custom callback for production analytics
21
21
  useWebVitals((metric) => {
22
- analytics.track('web-vital', {
23
- name: metric.name, // "FCP", "LCP", "CLS", "INP", or "TTFB"
24
- value: metric.value, // milliseconds (or unitless for CLS)
22
+ analytics.track("web-vital", {
23
+ name: metric.name, // "FCP", "LCP", "CLS", "INP", or "TTFB"
24
+ value: metric.value, // milliseconds (or unitless for CLS)
25
25
  rating: metric.rating, // "good", "needs-improvement", or "poor"
26
26
  });
27
27
  });
@@ -32,7 +32,7 @@ Call this once after `app.mount()` in your application entry point:
32
32
  ```typescript
33
33
  // main.ts
34
34
  const app = createApp(App);
35
- app.mount('#app');
35
+ app.mount("#app");
36
36
 
37
37
  // Register Web Vitals observers after mount
38
38
  useWebVitals();
@@ -42,17 +42,17 @@ useWebVitals();
42
42
 
43
43
  ### Parameters
44
44
 
45
- | Parameter | Type | Required | Description |
46
- |---|---|---|---|
47
- | `callback` | `(metric: IWebVitalsMetric) => void` | No | Custom handler for each metric. Defaults to `console.warn` formatted output in dev mode; no-op in production. |
45
+ | Parameter | Type | Required | Description |
46
+ | ---------- | ------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------- |
47
+ | `callback` | `(metric: IWebVitalsMetric) => void` | No | Custom handler for each metric. Defaults to `console.warn` formatted output in dev mode; no-op in production. |
48
48
 
49
49
  ### IWebVitalsMetric
50
50
 
51
- | Field | Type | Description |
52
- |---|---|---|
53
- | `name` | `string` | Metric name: `"FCP"` (First Contentful Paint), `"LCP"` (Largest Contentful Paint), `"CLS"` (Cumulative Layout Shift), `"INP"` (Interaction to Next Paint), `"TTFB"` (Time to First Byte) |
54
- | `value` | `number` | Metric value in milliseconds for all metrics except CLS, which is a unitless score |
55
- | `rating` | `"good" \| "needs-improvement" \| "poor"` | Performance rating based on Google's thresholds (e.g., LCP < 2500ms = "good") |
51
+ | Field | Type | Description |
52
+ | -------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
53
+ | `name` | `string` | Metric name: `"FCP"` (First Contentful Paint), `"LCP"` (Largest Contentful Paint), `"CLS"` (Cumulative Layout Shift), `"INP"` (Interaction to Next Paint), `"TTFB"` (Time to First Byte) |
54
+ | `value` | `number` | Metric value in milliseconds for all metrics except CLS, which is a unitless score |
55
+ | `rating` | `"good" \| "needs-improvement" \| "poor"` | Performance rating based on Google's thresholds (e.g., LCP < 2500ms = "good") |
56
56
 
57
57
  ### Returns
58
58
 
@@ -75,7 +75,7 @@ The default callback formats CLS values to 4 decimal places (since CLS is a dime
75
75
  ## Recipe: Sending Web Vitals to Application Insights
76
76
 
77
77
  ```typescript
78
- import { useWebVitals, useAppInsights } from '@vc-shell/framework';
78
+ import { useWebVitals, useAppInsights } from "@vc-shell/framework";
79
79
 
80
80
  const { appInsights } = useAppInsights();
81
81
 
@@ -96,14 +96,14 @@ This sends each Web Vital as a custom metric to Application Insights, where you
96
96
  ## Recipe: Conditional Reporting Based on Rating
97
97
 
98
98
  ```typescript
99
- import { useWebVitals } from '@vc-shell/framework';
99
+ import { useWebVitals } from "@vc-shell/framework";
100
100
 
101
101
  useWebVitals((metric) => {
102
102
  // Only report poor metrics to reduce noise
103
- if (metric.rating === 'poor') {
104
- fetch('/api/telemetry/web-vitals', {
105
- method: 'POST',
106
- headers: { 'Content-Type': 'application/json' },
103
+ if (metric.rating === "poor") {
104
+ fetch("/api/telemetry/web-vitals", {
105
+ method: "POST",
106
+ headers: { "Content-Type": "application/json" },
107
107
  body: JSON.stringify({
108
108
  metric: metric.name,
109
109
  value: metric.value,
@@ -14,15 +14,15 @@ Also exports `provideWidgetService()` for framework-level initialization and `re
14
14
  ## Quick Start
15
15
 
16
16
  ```typescript
17
- import { useWidgets } from '@vc-shell/framework';
17
+ import { useWidgets } from "@vc-shell/framework";
18
18
 
19
19
  const widgetService = useWidgets();
20
20
 
21
21
  // Query all widgets registered for a specific blade
22
- const widgets = widgetService.getWidgets('order-details');
22
+ const widgets = widgetService.getWidgets("order-details");
23
23
 
24
24
  // Check if a widget is currently active (visible and expanded)
25
- if (widgetService.isActiveWidget('order-status-widget')) {
25
+ if (widgetService.isActiveWidget("order-status-widget")) {
26
26
  // widget is currently in focus
27
27
  }
28
28
  ```
@@ -35,29 +35,29 @@ None.
35
35
 
36
36
  ### Returns (`IWidgetService`)
37
37
 
38
- | Property / Method | Type | Description |
39
- |-------------------|------|-------------|
40
- | `registerWidget` | `(widget: IWidget, bladeId: string) => void` | Registers a widget for a specific blade. The widget will appear in that blade's widget area. |
41
- | `unregisterWidget` | `(widgetId: string, bladeId: string) => void` | Removes a widget from a blade by ID. |
42
- | `getWidgets` | `(bladeId: string) => IWidget[]` | Returns all widgets registered for a specific blade. |
43
- | `clearBladeWidgets` | `(bladeId: string) => void` | Removes all widgets for a blade (used during blade teardown). |
44
- | `registeredWidgets` | `IWidgetRegistration[]` | All widget registrations across all blades. |
45
- | `isActiveWidget` | `(id: string) => boolean` | Checks if a widget is currently active (selected/expanded). |
46
- | `setActiveWidget` | `(args) => void` | Sets a widget as active with its exposed instance. |
47
- | `updateActiveWidget` | `() => void` | Triggers the active widget's update function. Deprecated -- use headless widgets instead. |
48
- | `isWidgetRegistered` | `(id: string) => boolean` | Checks if a widget ID exists in any blade's registry. |
49
- | `updateWidget` | `(args) => void` | Updates properties of a registered widget (trigger, badge, etc.). |
50
- | `resolveWidgetProps` | `(widget, bladeData) => Record<string, unknown>` | Resolves widget props from blade data. Deprecated. |
51
- | `getExternalWidgetsForBlade` | `(bladeId: string) => IExternalWidgetRegistration[]` | Gets external widgets that target a specific blade (registered by other modules). |
52
- | `getAllExternalWidgets` | `() => IExternalWidgetRegistration[]` | Gets all registered external widgets across all modules. |
38
+ | Property / Method | Type | Description |
39
+ | ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------- |
40
+ | `registerWidget` | `(widget: IWidget, bladeId: string) => void` | Registers a widget for a specific blade. The widget will appear in that blade's widget area. |
41
+ | `unregisterWidget` | `(widgetId: string, bladeId: string) => void` | Removes a widget from a blade by ID. |
42
+ | `getWidgets` | `(bladeId: string) => IWidget[]` | Returns all widgets registered for a specific blade. |
43
+ | `clearBladeWidgets` | `(bladeId: string) => void` | Removes all widgets for a blade (used during blade teardown). |
44
+ | `registeredWidgets` | `IWidgetRegistration[]` | All widget registrations across all blades. |
45
+ | `isActiveWidget` | `(id: string) => boolean` | Checks if a widget is currently active (selected/expanded). |
46
+ | `setActiveWidget` | `(args) => void` | Sets a widget as active with its exposed instance. |
47
+ | `updateActiveWidget` | `() => void` | Triggers the active widget's update function. Deprecated -- use headless widgets instead. |
48
+ | `isWidgetRegistered` | `(id: string) => boolean` | Checks if a widget ID exists in any blade's registry. |
49
+ | `updateWidget` | `(args) => void` | Updates properties of a registered widget (trigger, badge, etc.). |
50
+ | `resolveWidgetProps` | `(widget, bladeData) => Record<string, unknown>` | Resolves widget props from blade data. Deprecated. |
51
+ | `getExternalWidgetsForBlade` | `(bladeId: string) => IExternalWidgetRegistration[]` | Gets external widgets that target a specific blade (registered by other modules). |
52
+ | `getAllExternalWidgets` | `() => IExternalWidgetRegistration[]` | Gets all registered external widgets across all modules. |
53
53
 
54
54
  ### Additional Exports
55
55
 
56
- | Export | Description |
57
- |--------|-------------|
58
- | `provideWidgetService()` | Creates and provides the widget service via Vue injection. Idempotent -- returns existing service if already provided. Cleans up via `onScopeDispose`. |
59
- | `registerWidget(widget, bladeId)` | Global pre-registration. Widgets registered this way are picked up when `provideWidgetService()` creates the service. Use in module `install()`. |
60
- | `registerExternalWidget(registration)` | Global pre-registration for cross-module widgets. These widgets are rendered in blades owned by other modules. |
56
+ | Export | Description |
57
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
58
+ | `provideWidgetService()` | Creates and provides the widget service via Vue injection. Idempotent -- returns existing service if already provided. Cleans up via `onScopeDispose`. |
59
+ | `registerWidget(widget, bladeId)` | Global pre-registration. Widgets registered this way are picked up when `provideWidgetService()` creates the service. Use in module `install()`. |
60
+ | `registerExternalWidget(registration)` | Global pre-registration for cross-module widgets. These widgets are rendered in blades owned by other modules. |
61
61
 
62
62
  ## How It Works
63
63
 
@@ -75,20 +75,20 @@ The service tracks active widgets (which widget is currently expanded/focused) s
75
75
 
76
76
  ```typescript
77
77
  // my-module/index.ts
78
- import { registerWidget } from '@vc-shell/framework';
79
- import { markRaw } from 'vue';
80
- import OrderStatusWidget from './widgets/OrderStatusWidget.vue';
78
+ import { registerWidget } from "@vc-shell/framework";
79
+ import { markRaw } from "vue";
80
+ import OrderStatusWidget from "./widgets/OrderStatusWidget.vue";
81
81
 
82
82
  export default {
83
83
  install() {
84
84
  registerWidget(
85
85
  {
86
- id: 'order-status',
87
- title: 'Order Status',
86
+ id: "order-status",
87
+ title: "Order Status",
88
88
  component: markRaw(OrderStatusWidget),
89
- icon: 'fas fa-clipboard-check',
89
+ icon: "fas fa-clipboard-check",
90
90
  },
91
- 'order-details', // blade ID where this widget appears
91
+ "order-details", // blade ID where this widget appears
92
92
  );
93
93
  },
94
94
  };
@@ -100,18 +100,18 @@ A shipping module can add a widget to the order module's detail blade:
100
100
 
101
101
  ```typescript
102
102
  // shipping-module/index.ts
103
- import { registerExternalWidget } from '@vc-shell/framework';
104
- import { markRaw } from 'vue';
105
- import ShippingTracker from './widgets/ShippingTracker.vue';
103
+ import { registerExternalWidget } from "@vc-shell/framework";
104
+ import { markRaw } from "vue";
105
+ import ShippingTracker from "./widgets/ShippingTracker.vue";
106
106
 
107
107
  export default {
108
108
  install() {
109
109
  registerExternalWidget({
110
- widgetId: 'shipping-tracker',
111
- bladeId: 'order-details', // target blade from another module
110
+ widgetId: "shipping-tracker",
111
+ bladeId: "order-details", // target blade from another module
112
112
  component: markRaw(ShippingTracker),
113
- title: 'Shipping',
114
- icon: 'fas fa-truck',
113
+ title: "Shipping",
114
+ icon: "fas fa-truck",
115
115
  });
116
116
  },
117
117
  };
@@ -121,21 +121,16 @@ export default {
121
121
 
122
122
  ```vue
123
123
  <script setup lang="ts">
124
- import { useWidgets } from '@vc-shell/framework';
125
- import { computed } from 'vue';
124
+ import { useWidgets } from "@vc-shell/framework";
125
+ import { computed } from "vue";
126
126
 
127
127
  const props = defineProps<{ bladeId: string }>();
128
128
  const widgetService = useWidgets();
129
129
 
130
130
  const bladeWidgets = computed(() => widgetService.getWidgets(props.bladeId));
131
- const externalWidgets = computed(() =>
132
- widgetService.getExternalWidgetsForBlade(props.bladeId),
133
- );
134
-
135
- const allWidgets = computed(() => [
136
- ...bladeWidgets.value,
137
- ...externalWidgets.value,
138
- ]);
131
+ const externalWidgets = computed(() => widgetService.getExternalWidgetsForBlade(props.bladeId));
132
+
133
+ const allWidgets = computed(() => [...bladeWidgets.value, ...externalWidgets.value]);
139
134
  </script>
140
135
  ```
141
136