@vc-shell/vc-app-skill 2.1.0-pr255.4dc5c0d → 2.1.0-pr256.0fe3abb

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 (139) hide show
  1. package/package.json +1 -1
  2. package/runtime/knowledge/docs/core/api/platform.docs.md +20 -18
  3. package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +43 -34
  4. package/runtime/knowledge/docs/core/blade-navigation/table-query-state/useTableQueryState.docs.md +95 -0
  5. package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +5 -3
  6. package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +12 -10
  7. package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +7 -5
  8. package/runtime/knowledge/docs/core/composables/useAssets/useAssets.docs.md +8 -6
  9. package/runtime/knowledge/docs/core/composables/useAssetsManager/useAssetsManager.docs.md +3 -1
  10. package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +1 -1
  11. package/runtime/knowledge/docs/core/composables/useBladeRegistry/useBladeRegistry.docs.md +8 -5
  12. package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +12 -12
  13. package/runtime/knowledge/docs/core/composables/useBreadcrumbs/useBreadcrumbs.docs.md +3 -3
  14. package/runtime/knowledge/docs/core/composables/useConnectionStatus/useConnectionStatus.docs.md +4 -3
  15. package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +1 -0
  16. package/runtime/knowledge/docs/core/composables/useFunctions/useFunctions.docs.md +3 -3
  17. package/runtime/knowledge/docs/core/composables/useKeyboardNavigation/useKeyboardNavigation.docs.md +5 -4
  18. package/runtime/knowledge/docs/core/composables/useLanguages/useLanguages.docs.md +3 -3
  19. package/runtime/knowledge/docs/core/composables/useLoading/useLoading.docs.md +2 -0
  20. package/runtime/knowledge/docs/core/composables/useModificationTracker/useModificationTracker.docs.md +1 -2
  21. package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +1 -1
  22. package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +3 -3
  23. package/runtime/knowledge/docs/core/composables/usePlatformLocaleSync/usePlatformLocaleSync.docs.md +35 -0
  24. package/runtime/knowledge/docs/core/composables/usePopup/usePopup.docs.md +1 -1
  25. package/runtime/knowledge/docs/core/composables/useResponsive/useResponsive.docs.md +2 -2
  26. package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +2 -1
  27. package/runtime/knowledge/docs/core/composables/useSettingsMenu/useSettingsMenu.docs.md +18 -18
  28. package/runtime/knowledge/docs/core/composables/useSidebarState/useSidebarState.docs.md +3 -3
  29. package/runtime/knowledge/docs/core/composables/useSlowNetworkDetection/useSlowNetworkDetection.docs.md +10 -7
  30. package/runtime/knowledge/docs/core/composables/useTheme/useTheme.docs.md +7 -7
  31. package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +18 -12
  32. package/runtime/knowledge/docs/core/composables/useUser/useUser.docs.md +2 -2
  33. package/runtime/knowledge/docs/core/composables/useUserManagement/useUserManagement.docs.md +20 -20
  34. package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +15 -24
  35. package/runtime/knowledge/docs/core/directives/loading/loading.docs.md +2 -2
  36. package/runtime/knowledge/docs/core/notifications/composables/useBladeNotifications.docs.md +183 -0
  37. package/runtime/knowledge/docs/core/notifications/composables/useBroadcastFilter.docs.md +117 -0
  38. package/runtime/knowledge/docs/core/notifications/composables/useNotificationContext.docs.md +150 -0
  39. package/runtime/knowledge/docs/core/notifications/composables/useNotificationStore.docs.md +114 -0
  40. package/runtime/knowledge/docs/core/notifications/notifications.docs.md +50 -30
  41. package/runtime/knowledge/docs/core/plugins/ai-agent/ai-agent.docs.md +30 -11
  42. package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +1 -1
  43. package/runtime/knowledge/docs/core/plugins/global-error-handler/global-error-handler.docs.md +2 -3
  44. package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +26 -26
  45. package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +2 -3
  46. package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +11 -50
  47. package/runtime/knowledge/docs/core/plugins/validation/validation.docs.md +9 -6
  48. package/runtime/knowledge/docs/core/services/services.docs.md +15 -13
  49. package/runtime/knowledge/docs/core/types/types.docs.md +37 -40
  50. package/runtime/knowledge/docs/core/utilities/date/date-utilities.docs.md +1 -2
  51. package/runtime/knowledge/docs/core/utilities/shared-utilities.docs.md +21 -30
  52. package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +2 -2
  53. package/runtime/knowledge/docs/core/utilities/utilities.docs.md +9 -8
  54. package/runtime/knowledge/docs/injection-keys.docs.md +6 -11
  55. package/runtime/knowledge/docs/modules/assets/assets-details.docs.md +123 -0
  56. package/runtime/knowledge/docs/modules/assets-manager/assets-manager.docs.md +1 -1
  57. package/runtime/knowledge/docs/shell/_internal/popup/common/popup-common.docs.md +20 -12
  58. package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +10 -10
  59. package/runtime/knowledge/docs/shell/auth/ForgotPasswordPage/forgot-password-page.docs.md +6 -6
  60. package/runtime/knowledge/docs/shell/auth/InvitePage/invite-page.docs.md +4 -4
  61. package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +16 -14
  62. package/runtime/knowledge/docs/shell/auth/ResetPasswordPage/reset-password-page.docs.md +1 -1
  63. package/runtime/knowledge/docs/shell/auth/sign-in/sign-in.docs.md +12 -11
  64. package/runtime/knowledge/docs/shell/components/change-password/change-password.docs.md +10 -3
  65. package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +3 -3
  66. package/runtime/knowledge/docs/shell/components/error-interceptor/error-interceptor.docs.md +9 -2
  67. package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +4 -2
  68. package/runtime/knowledge/docs/shell/components/logout-button/logout-button.docs.md +1 -1
  69. package/runtime/knowledge/docs/shell/components/notification-dropdown/notification-dropdown.docs.md +35 -31
  70. package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +17 -11
  71. package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +8 -7
  72. package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +23 -21
  73. package/runtime/knowledge/docs/shell/components/sidebar/sidebar.docs.md +5 -3
  74. package/runtime/knowledge/docs/shell/components/theme-selector/theme-selector.docs.md +7 -7
  75. package/runtime/knowledge/docs/shell/components/user-dropdown-button/user-dropdown-button.docs.md +11 -11
  76. package/runtime/knowledge/docs/shell/dashboard/dashboard-charts/dashboard-charts.docs.md +28 -16
  77. package/runtime/knowledge/docs/shell/dashboard/dashboard-widget-card/dashboard-widget-card.docs.md +17 -19
  78. package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/dashboard-widget-skeleton.docs.md +33 -0
  79. package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +21 -0
  80. package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +2 -1
  81. package/runtime/knowledge/docs/ui/components/atoms/vc-banner/vc-banner.docs.md +2 -2
  82. package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +15 -14
  83. package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +9 -6
  84. package/runtime/knowledge/docs/ui/components/atoms/vc-environment-banner/vc-environment-banner.docs.md +42 -0
  85. package/runtime/knowledge/docs/ui/components/atoms/vc-hint/vc-hint.docs.md +1 -1
  86. package/runtime/knowledge/docs/ui/components/atoms/vc-icon/vc-icon.docs.md +10 -9
  87. package/runtime/knowledge/docs/ui/components/atoms/vc-image/vc-image.docs.md +19 -4
  88. package/runtime/knowledge/docs/ui/components/atoms/vc-label/vc-label.docs.md +2 -2
  89. package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +5 -4
  90. package/runtime/knowledge/docs/ui/components/atoms/vc-loading/vc-loading.docs.md +5 -4
  91. package/runtime/knowledge/docs/ui/components/atoms/vc-progress/vc-progress.docs.md +9 -8
  92. package/runtime/knowledge/docs/ui/components/atoms/vc-scrollable-container/vc-scrollable-container.docs.md +7 -0
  93. package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +1 -1
  94. package/runtime/knowledge/docs/ui/components/atoms/vc-status/vc-status.docs.md +2 -2
  95. package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +1 -1
  96. package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +11 -10
  97. package/runtime/knowledge/docs/ui/components/atoms/vc-video/vc-video.docs.md +28 -8
  98. package/runtime/knowledge/docs/ui/components/atoms/vc-widget/vc-widget.docs.md +22 -19
  99. package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +8 -8
  100. package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +16 -6
  101. package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +9 -8
  102. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +42 -34
  103. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +1 -1
  104. package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +14 -1
  105. package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +3 -1
  106. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown/vc-dropdown.docs.md +34 -33
  107. package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +26 -24
  108. package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +12 -14
  109. package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +30 -30
  110. package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +2 -2
  111. package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +1 -1
  112. package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +34 -31
  113. package/runtime/knowledge/docs/ui/components/molecules/vc-input-group/vc-input-group.docs.md +14 -12
  114. package/runtime/knowledge/docs/ui/components/molecules/vc-menu/vc-menu.docs.md +1 -1
  115. package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +36 -27
  116. package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +5 -1
  117. package/runtime/knowledge/docs/ui/components/molecules/{vc-dropdown-panel/vc-dropdown-panel.docs.md → vc-popover/vc-popover.docs.md} +26 -25
  118. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +10 -9
  119. package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +44 -19
  120. package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +11 -11
  121. package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +15 -14
  122. package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +15 -15
  123. package/runtime/knowledge/docs/ui/components/molecules/vc-toast/vc-toast.docs.md +15 -13
  124. package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +5 -1
  125. package/runtime/knowledge/docs/ui/components/organisms/vc-auth-layout/vc-auth-layout.docs.md +18 -0
  126. package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +48 -78
  127. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/composables/table-composables.docs.md +9 -11
  128. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +71 -43
  129. package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +27 -20
  130. package/runtime/knowledge/docs/ui/components/organisms/vc-gallery/vc-gallery.docs.md +2 -2
  131. package/runtime/knowledge/docs/ui/components/organisms/vc-image-upload/vc-image-upload.docs.md +12 -12
  132. package/runtime/knowledge/docs/ui/components/organisms/vc-popup/vc-popup.docs.md +33 -24
  133. package/runtime/knowledge/docs/ui/components/organisms/vc-scheduler/vc-scheduler.docs.md +412 -0
  134. package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +43 -26
  135. package/runtime/knowledge/docs/ui/composables/ui-composables.docs.md +15 -9
  136. package/runtime/knowledge/docs/ui/composables/useDataTableSort.docs.md +8 -6
  137. package/runtime/knowledge/docs/ui/composables/useTableSearch.docs.md +130 -0
  138. package/runtime/knowledge/docs/ui/composables/useTableSelection.docs.md +4 -4
  139. package/runtime/knowledge/docs/ui/composables/useTableSort.docs.md +2 -3
@@ -75,21 +75,21 @@ None.
75
75
 
76
76
  ### Returns
77
77
 
78
- | Property | Type | Description |
79
- | ---------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
80
- | `user` | `ComputedRef<UserDetail \| undefined>` | Current user details. |
81
- | `loading` | `ComputedRef<boolean>` | Whether any operation is in progress. |
82
- | `isAdministrator` | `ComputedRef<boolean \| undefined>` | Admin status of the current user. |
83
- | `isAuthenticated` | `ComputedRef<boolean>` | Whether user session is active. |
84
- | `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. |
85
- | `signOut` | `() => Promise<void>` | Clears session, auth data, and localStorage. Handles both standard and external SSO sign-out. |
86
- | `loadUser` | `() => Promise<UserDetail>` | Loads/reloads user info from the server. Deduplicates concurrent calls. |
87
- | `validateToken` | `(userId: string, token: string) => Promise<boolean>` | Validates a password-reset token. Returns `true` if valid. |
88
- | `validatePassword` | `(password: string) => Promise<IdentityResult>` | Validates a password against the platform's password policy (length, complexity, etc.). |
89
- | `resetPasswordByToken` | `(userId: string, password: string, token: string) => Promise<SecurityResult>` | Resets a user's password using a reset token. Returns `{ succeeded: true }` on success. |
90
- | `requestPasswordReset` | `(loginOrEmail: string) => Promise<RequestPasswordResult>` | Sends a password-reset email to the user. Returns `{ succeeded: true }` on success. |
91
- | `changeUserPassword` | `(oldPassword: string, newPassword: string) => Promise<SecurityResult \| undefined>` | Changes the current user's password. Requires the old password for verification. |
92
- | `getLoginType` | `() => Promise<LoginType[]>` | Returns available login types (password-based, external SSO providers, etc.). Used to render the appropriate sign-in UI. |
78
+ | Property | Type | Description |
79
+ | ---------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
80
+ | `user` | `ComputedRef<UserDetail \| undefined>` | Current user details. |
81
+ | `loading` | `ComputedRef<boolean>` | Whether any operation is in progress. |
82
+ | `isAdministrator` | `ComputedRef<boolean \| undefined>` | Admin status of the current user. |
83
+ | `isAuthenticated` | `ComputedRef<boolean>` | Whether user session is active. |
84
+ | `signIn` | `(username: string, password: string) => Promise<SignInResult \| { succeeded: boolean; error?: any }>` | 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. |
85
+ | `signOut` | `() => Promise<void>` | Clears session, auth data, and localStorage. Handles both standard and external SSO sign-out. |
86
+ | `loadUser` | `() => Promise<UserDetail>` | Loads/reloads user info from the server. Deduplicates concurrent calls. |
87
+ | `validateToken` | `(userId: string, token: string) => Promise<boolean>` | Validates a password-reset token. Returns `true` if valid. |
88
+ | `validatePassword` | `(password: string) => Promise<IdentityResult>` | Validates a password against the platform's password policy (length, complexity, etc.). |
89
+ | `resetPasswordByToken` | `(userId: string, password: string, token: string) => Promise<SecurityResult>` | Resets a user's password using a reset token. Returns `{ succeeded: true }` on success. |
90
+ | `requestPasswordReset` | `(loginOrEmail: string) => Promise<RequestPasswordResult>` | Sends a password-reset email to the user. Returns `{ succeeded: true }` on success. |
91
+ | `changeUserPassword` | `(oldPassword: string, newPassword: string) => Promise<SecurityResult \| undefined>` | Changes the current user's password. Requires the old password for verification. |
92
+ | `getLoginType` | `() => Promise<LoginType[]>` | Returns available login types (password-based, external SSO providers, etc.). Used to render the appropriate sign-in UI. |
93
93
 
94
94
  ## How It Works
95
95
 
@@ -139,7 +139,7 @@ async function handleReset() {
139
139
  // Validate against password policy
140
140
  const validation = await validatePassword(newPassword.value);
141
141
  if (!validation.succeeded) {
142
- error.value = validation.errors?.join(", ") ?? "Password does not meet requirements.";
142
+ error.value = validation.errors?.map((e) => e.description).join(", ") ?? "Password does not meet requirements.";
143
143
  return;
144
144
  }
145
145
 
@@ -167,7 +167,7 @@ const showPasswordForm = ref(false);
167
167
  onMounted(async () => {
168
168
  loginTypes.value = await getLoginType();
169
169
  // Show password form only if password auth is available
170
- showPasswordForm.value = loginTypes.value.some((t) => t.loginProvider === "password");
170
+ showPasswordForm.value = loginTypes.value.some((t) => t.hasLoginForm);
171
171
  });
172
172
  </script>
173
173
 
@@ -181,10 +181,10 @@ onMounted(async () => {
181
181
  </form>
182
182
 
183
183
  <div
184
- v-for="provider in loginTypes.filter((t) => t.loginProvider !== 'password')"
185
- :key="provider.loginProvider"
184
+ v-for="provider in loginTypes.filter((t) => !t.hasLoginForm)"
185
+ :key="provider.authenticationType"
186
186
  >
187
- <VcButton @click="redirectToSSO(provider)"> Sign in with {{ provider.loginProvider }} </VcButton>
187
+ <VcButton @click="redirectToSSO(provider)"> Sign in with {{ provider.authenticationType }} </VcButton>
188
188
  </div>
189
189
  </div>
190
190
  </template>
@@ -6,7 +6,7 @@ group: services
6
6
 
7
7
  # useWidgets
8
8
 
9
- Provides access to the `IWidgetService` singleton for managing blade widget registrations, activation state, and external widgets. This is the low-level composable for direct widget service interaction. It exposes the full widget lifecycle API: registering widgets to specific blades, querying registered widgets, tracking active widget state, and managing external (cross-module) widget registrations.
9
+ Provides access to the `IWidgetService` singleton for managing blade widget registrations and external widgets. This is the low-level composable for direct widget service interaction. It exposes the widget lifecycle API: registering widgets to specific blades, querying and updating registered widgets, and managing external (cross-module) widget registrations.
10
10
 
11
11
  Also exports `provideWidgetService()` for framework-level initialization and `registerWidget()` / `registerExternalWidget()` for global pre-registration before the service is created.
12
12
 
@@ -27,10 +27,8 @@ const widgetService = useWidgets();
27
27
  // Query all widgets registered for a specific blade
28
28
  const widgets = widgetService.getWidgets("order-details");
29
29
 
30
- // Check if a widget is currently active (visible and expanded)
31
- if (widgetService.isActiveWidget("order-status-widget")) {
32
- // widget is currently in focus
33
- }
30
+ // Query external widgets contributed by other modules
31
+ const externalWidgets = widgetService.getExternalWidgetsForBlade("order-details");
34
32
  ```
35
33
 
36
34
  ## API
@@ -41,21 +39,15 @@ None.
41
39
 
42
40
  ### Returns (`IWidgetService`)
43
41
 
44
- | Property / Method | Type | Description |
45
- | ---------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------- |
46
- | `registerWidget` | `(widget: IWidget, bladeId: string) => void` | Registers a widget for a specific blade. The widget will appear in that blade's widget area. |
47
- | `unregisterWidget` | `(widgetId: string, bladeId: string) => void` | Removes a widget from a blade by ID. |
48
- | `getWidgets` | `(bladeId: string) => IWidget[]` | Returns all widgets registered for a specific blade. |
49
- | `clearBladeWidgets` | `(bladeId: string) => void` | Removes all widgets for a blade (used during blade teardown). |
50
- | `registeredWidgets` | `IWidgetRegistration[]` | All widget registrations across all blades. |
51
- | `isActiveWidget` | `(id: string) => boolean` | Checks if a widget is currently active (selected/expanded). |
52
- | `setActiveWidget` | `(args) => void` | Sets a widget as active with its exposed instance. |
53
- | `updateActiveWidget` | `() => void` | Triggers the active widget's update function. Deprecated -- use headless widgets instead. |
54
- | `isWidgetRegistered` | `(id: string) => boolean` | Checks if a widget ID exists in any blade's registry. |
55
- | `updateWidget` | `(args) => void` | Updates properties of a registered widget (trigger, badge, etc.). |
56
- | `resolveWidgetProps` | `(widget, bladeData) => Record<string, unknown>` | Resolves widget props from blade data. Deprecated. |
57
- | `getExternalWidgetsForBlade` | `(bladeId: string) => IExternalWidgetRegistration[]` | Gets external widgets that target a specific blade (registered by other modules). |
58
- | `getAllExternalWidgets` | `() => IExternalWidgetRegistration[]` | Gets all registered external widgets across all modules. |
42
+ | Property / Method | Type | Description |
43
+ | ---------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
44
+ | `registerWidget` | `(widget: IWidget, bladeId: string) => void` | Registers a widget for a specific blade. The widget will appear in that blade's widget area. |
45
+ | `unregisterWidget` | `(widgetId: string, bladeId: string) => void` | Removes a widget from a blade by ID. |
46
+ | `getWidgets` | `(bladeId: string) => IWidget[]` | Returns all widgets registered for a specific blade. |
47
+ | `updateWidget` | `({ id, bladeId, widget }: { id: string; bladeId: string; widget: Partial<IWidget> }) => void` | Updates properties of a registered widget (trigger, badge, etc.). |
48
+ | `getExternalWidgetsForBlade` | `(bladeId: string) => IExternalWidgetRegistration[]` | Gets external widgets that target a specific blade (registered by other modules). |
49
+ | `getAllExternalWidgets` | `() => IExternalWidgetRegistration[]` | Gets all registered external widgets across all modules. |
50
+ | `cloneWidget` | `<T extends IWidget \| IExternalWidgetRegistration>(widget: T) => T` | Returns a deep-ish clone of a widget or external widget registration. |
59
51
 
60
52
  ### Additional Exports
61
53
 
@@ -77,7 +69,7 @@ The widget system has three layers:
77
69
 
78
70
  3. **Runtime access** (`useWidgets()`): Components inject the service and use it to query or modify widget state.
79
71
 
80
- The service tracks active widgets (which widget is currently expanded/focused) separately from registrations, enabling the widget panel to highlight the active widget and call its update function.
72
+ The service stores widget registrations per blade and returns cloned widget definitions on query. It does not track active/expanded/focused state.
81
73
 
82
74
  <!-- internal:end -->
83
75
 
@@ -117,11 +109,10 @@ import ShippingTracker from "./widgets/ShippingTracker.vue";
117
109
  export default {
118
110
  install() {
119
111
  registerExternalWidget({
120
- widgetId: "shipping-tracker",
121
- bladeId: "order-details", // target blade from another module
112
+ id: "shipping-tracker",
113
+ targetBlades: ["order-details"], // target blades from other modules
122
114
  component: markRaw(ShippingTracker),
123
115
  title: "Shipping",
124
- icon: "fas fa-truck",
125
116
  });
126
117
  },
127
118
  };
@@ -25,7 +25,7 @@ Unlike a standalone loading component, `v-loading` scopes the overlay to the ele
25
25
  | ----------------------- | ---------------- | ------------------------------------ |
26
26
  | `v-loading="true"` | `boolean` | Show/hide the loading overlay |
27
27
  | `v-loading="options"` | `LoadingOptions` | Show with configuration (see below) |
28
- | `v-loading:1000="true"` | `arg: string` | Set custom z-index (default: `9999`) |
28
+ | `v-loading:1000="true"` | `arg: string` | Set custom z-index (default: `9000`) |
29
29
 
30
30
  ### LoadingOptions
31
31
 
@@ -108,7 +108,7 @@ async function loadOrder() {
108
108
  <!-- Use a lower z-index so popups can render above the spinner -->
109
109
  <div v-loading:500="isLoading">Content</div>
110
110
 
111
- <!-- Default z-index is 9999 -->
111
+ <!-- Default z-index is 9000 -->
112
112
  <div v-loading="isLoading">Content</div>
113
113
  </template>
114
114
  ```
@@ -0,0 +1,183 @@
1
+ ---
2
+ title: useBladeNotifications
3
+ category: composables
4
+ group: notifications
5
+ ---
6
+
7
+ # useBladeNotifications
8
+
9
+ Subscribes a blade to one or more push-notification types from the platform's SignalR stream. The composable returns a reactive list of matching unread messages, an unread count, and a `markAsRead` action. The subscription is bound to the current effect scope, so it disappears the moment the blade closes — no manual unsubscribe.
10
+
11
+ This is the **Level 2** entry point in the notification system. Level 1 — `defineAppModule({ notifications })` — registers types globally with their toast configuration and is the always-on path. Level 2 layers blade-specific behavior on top of that: refresh a list, update a progress UI, mark a job complete.
12
+
13
+ ## When to use
14
+
15
+ - A list blade needs to refresh when an entity is created, updated, or deleted elsewhere.
16
+ - A long-running operation has a dedicated blade and the blade should update as `processedCount` / `errorCount` flow in.
17
+ - A blade wants to surface an inline "N new" badge for messages of a specific type.
18
+ - When NOT to use: app-wide toasts already come from the Level 1 module config — the blade does not need to subscribe just to show a toast. Reach for the blade subscription only when you also need to _react_ to the event in code.
19
+
20
+ ## Quick Start
21
+
22
+ ```ts
23
+ import { useBladeNotifications } from "@vc-shell/framework";
24
+
25
+ useBladeNotifications({
26
+ types: ["OfferDeletedDomainEvent"],
27
+ onMessage: () => reload(),
28
+ });
29
+ ```
30
+
31
+ That is the full recipe for "refresh this list when an offer is deleted somewhere in the app." The handler runs once per matching message; the framework cleans up the subscription when the blade unmounts.
32
+
33
+ ## API
34
+
35
+ ### Parameters
36
+
37
+ ```typescript
38
+ interface BladeNotificationOptions<T extends PushNotification = PushNotification> {
39
+ types: string[];
40
+ filter?: (msg: T) => boolean;
41
+ onMessage?: (msg: T) => void;
42
+ }
43
+ ```
44
+
45
+ | Field | Type | Required | Description |
46
+ | ----------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
47
+ | `types` | `string[]` | Yes | Notification types to subscribe to. Must match the `notifyType` field on incoming messages. |
48
+ | `filter` | `(msg: T) => boolean` | No | Narrow the subscription further (for example, only events for the entity this blade is editing). |
49
+ | `onMessage` | `(msg: T) => void` | No | Callback fired once per matching message. Use it to refresh data, mark progress, or update local state. |
50
+
51
+ ### Returns
52
+
53
+ ```typescript
54
+ interface BladeNotificationReturn<T extends PushNotification = PushNotification> {
55
+ messages: ComputedRef<T[]>;
56
+ unreadCount: ComputedRef<number>;
57
+ markAsRead: (msg: T) => void;
58
+ }
59
+ ```
60
+
61
+ | Property | Type | Description |
62
+ | ------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
63
+ | `messages` | `ComputedRef<T[]>` | Realtime messages matching `types` and `filter` that are still unread. Updates reactively as new messages arrive. |
64
+ | `unreadCount` | `ComputedRef<number>` | `messages.value.length`. Bind to a badge. |
65
+ | `markAsRead` | `(msg: T) => void` | Mark a specific message as read. Removes it from `messages` (and reduces the global unread badge in the bell dropdown). |
66
+
67
+ ## Typed payloads
68
+
69
+ Notification payloads often extend `PushNotification` with domain fields. Pass the type parameter so `onMessage` and `messages` are typed:
70
+
71
+ ```ts
72
+ import type { PushNotification } from "@vc-shell/framework";
73
+
74
+ interface ImportPushNotification extends PushNotification {
75
+ jobId: string;
76
+ profileId: string;
77
+ profileName?: string;
78
+ processedCount: number;
79
+ errorCount: number;
80
+ finished: boolean;
81
+ }
82
+
83
+ const { messages, markAsRead } = useBladeNotifications<ImportPushNotification>({
84
+ types: ["ImportPushNotification"],
85
+ onMessage: (message) => {
86
+ if (message.finished) {
87
+ reload();
88
+ markAsRead(message);
89
+ }
90
+ },
91
+ });
92
+ ```
93
+
94
+ ## Common patterns
95
+
96
+ ### Refresh a list on any matching event
97
+
98
+ ```ts
99
+ useBladeNotifications({
100
+ types: ["OfferDeletedDomainEvent"],
101
+ onMessage: () => reload(),
102
+ });
103
+ ```
104
+
105
+ Drop-in for a list blade that needs to stay in sync with deletions happening anywhere in the app.
106
+
107
+ ### Filter to the entity this blade owns
108
+
109
+ ```ts
110
+ useBladeNotifications<ImportPushNotification>({
111
+ types: ["ImportPushNotification"],
112
+ onMessage: (message) => {
113
+ if (message.profileId !== param.value) return; // not our job
114
+ if (!message.finished) updateProgress(message);
115
+ else finalizeImport(message);
116
+ },
117
+ });
118
+ ```
119
+
120
+ Two open import blades will both receive the stream; each one filters by its own `profileId` so they do not step on each other.
121
+
122
+ ### Drive a manual progress toast
123
+
124
+ When the platform sends progress updates for a long-running job, you may want to render one persistent toast that you update as messages arrive — instead of letting Level 1 spawn a new toast per event.
125
+
126
+ Set the Level 1 type to `silent` and drive the toast yourself:
127
+
128
+ ```ts title="src/modules/import/index.ts"
129
+ defineAppModule({
130
+ notifications: {
131
+ ImportPushNotification: { toast: { mode: "silent" } },
132
+ },
133
+ // ...
134
+ });
135
+ ```
136
+
137
+ ```ts title="pages/import-process.vue"
138
+ import { useBladeNotifications, notification } from "@vc-shell/framework";
139
+
140
+ let toastId: string | undefined;
141
+
142
+ useBladeNotifications<ImportPushNotification>({
143
+ types: ["ImportPushNotification"],
144
+ onMessage: (message) => {
145
+ const content = message.profileName ? `${message.profileName}: ${message.title}` : message.title;
146
+
147
+ if (!toastId) {
148
+ toastId = notification(content, { timeout: false });
149
+ } else if (!message.finished) {
150
+ notification.update(toastId, { content });
151
+ } else {
152
+ notification.update(toastId, {
153
+ content,
154
+ timeout: 5000,
155
+ type: message.errorCount ? "error" : "success",
156
+ onClose: () => (toastId = undefined),
157
+ });
158
+ }
159
+ },
160
+ });
161
+ ```
162
+
163
+ The `notification()` helper returns the toast id; `notification.update` mutates it in place. The bell-dropdown history still grows — `silent` only suppresses the auto-toast.
164
+
165
+ ## Lifecycle
166
+
167
+ `useBladeNotifications` calls `useNotificationStore().subscribe(...)` and registers `onScopeDispose(unsub)` against the current effect scope. Inside a Vue `setup()` (component or `<script setup>`) the scope is the component's; the subscription dies with the component.
168
+
169
+ If you call the composable from a manually managed `effectScope()`, the cleanup runs when that scope is stopped. Calling it outside any scope is a bug — the subscription would never be released.
170
+
171
+ ## Tips
172
+
173
+ - **Listen, do not declare.** `useBladeNotifications` does not register the notification type with the framework. Types must already be declared by some module via `defineAppModule({ notifications })`, otherwise nothing reaches `onMessage`.
174
+ - **`messages` shows only unread.** `markAsRead(msg)` removes a message from `messages` (and from the global unread count). The notification stays in history.
175
+ - **One subscription per call.** Calling `useBladeNotifications` multiple times in the same blade creates independent subscriptions. Combine handlers if you only need one.
176
+ - **Type strings are case-sensitive.** The string in `types` must exactly equal the `notifyType` field on incoming messages.
177
+
178
+ ## Related
179
+
180
+ - [useNotificationStore](./useNotificationStore.md) — direct store access for app-shell features (dropdown, badge).
181
+ - [useNotificationContext](./useNotificationContext.md) — read the current notification inside a custom template.
182
+ - [useBroadcastFilter](./useBroadcastFilter.md) — control which `SendSystemEvents` broadcasts reach the store.
183
+ - [Notifications overview.](../notifications.md)
@@ -0,0 +1,117 @@
1
+ ---
2
+ title: useBroadcastFilter
3
+ category: composables
4
+ group: notifications
5
+ ---
6
+
7
+ # useBroadcastFilter
8
+
9
+ Controls which **broadcast** push notifications reach the store. The platform SignalR hub delivers messages through two channels: `Send` (targeted to a specific user) and `SendSystemEvents` (broadcast to everyone connected). Broadcasts run through the filter installed here; targeted messages are always accepted.
10
+
11
+ This is the standard mechanism for scoping a multi-tenant app — show a seller only the broadcasts that mention them, hide events from other tenants. Without a filter every broadcast lands in every user's history.
12
+
13
+ ## When to use
14
+
15
+ - Multi-tenant apps where the same broadcast topic carries events for different tenants (sellers, organizations, departments) and each user should only see their slice.
16
+ - Apps that want to drop noisy maintenance broadcasts for non-admin roles. (Note: `IndexProgressPushNotification` is already globally dropped via `EXCLUDED_NOTIFICATION_TYPES` and needs no filter.)
17
+ - When NOT to use: filtering targeted notifications. The platform already delivers `Send` messages only to the addressed user; `useBroadcastFilter` does not see them.
18
+
19
+ ## Quick Start
20
+
21
+ ```ts
22
+ import { useBroadcastFilter, useUser } from "@vc-shell/framework";
23
+ import { onMounted } from "vue";
24
+
25
+ const { user } = useUser();
26
+ const { setBroadcastFilter } = useBroadcastFilter();
27
+
28
+ onMounted(() => {
29
+ setBroadcastFilter((msg) => msg.creator === user.value?.userName);
30
+ });
31
+ ```
32
+
33
+ Install the filter once at app bootstrap (or whenever the active user changes). Every incoming broadcast is run through it; messages that return `false` are dropped before they touch history, toasts, or subscribers.
34
+
35
+ ## API
36
+
37
+ ### Returns
38
+
39
+ ```typescript
40
+ interface UseBroadcastFilterReturn {
41
+ setBroadcastFilter(fn: (msg: PushNotification) => boolean): void;
42
+ clearBroadcastFilter(): void;
43
+ }
44
+ ```
45
+
46
+ | Method | Type | Description |
47
+ | ---------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------- |
48
+ | `setBroadcastFilter` | `((msg: PushNotification) => boolean) => void` | Install the filter. Replaces any previous filter — there is at most one active at a time. |
49
+ | `clearBroadcastFilter` | `() => void` | Remove the filter. All subsequent broadcasts are accepted. |
50
+
51
+ The filter returns `true` to **accept** a message, `false` to **drop** it.
52
+
53
+ ## Common patterns
54
+
55
+ ### Scope by current user
56
+
57
+ ```ts
58
+ onMounted(() => {
59
+ setBroadcastFilter((msg) => msg.creator === user.value?.userName);
60
+ });
61
+ ```
62
+
63
+ `creator` is the user that originated the event on the platform side. This is the canonical "show me my own broadcasts" filter in multi-tenant back-office apps.
64
+
65
+ ### Scope by tenant id
66
+
67
+ ```ts
68
+ onMounted(() => {
69
+ setBroadcastFilter((msg) => (msg as TenantPush).sellerId === currentSellerId.value);
70
+ });
71
+ ```
72
+
73
+ When your broadcast payloads carry a tenant id, gate on it instead of `creator`. The cast clarifies typing without expanding `PushNotification` for every caller.
74
+
75
+ ### Re-install on user switch
76
+
77
+ ```ts
78
+ import { watch } from "vue";
79
+
80
+ watch(
81
+ () => user.value?.userName,
82
+ (name) => {
83
+ if (!name) clearBroadcastFilter();
84
+ else setBroadcastFilter((msg) => msg.creator === name);
85
+ },
86
+ { immediate: true },
87
+ );
88
+ ```
89
+
90
+ If the app supports user switching without a full reload (impersonation, multi-account), re-install the filter on every change. There is only one slot — installing again replaces the previous filter.
91
+
92
+ ### Drop a noisy type entirely
93
+
94
+ ```ts
95
+ setBroadcastFilter((msg) => msg.notifyType !== "BulkActionPushNotification");
96
+ ```
97
+
98
+ Broadcast-only suppression. To suppress targeted messages too, set `toast: false` or `toast: { mode: "silent" }` on the type's `defineAppModule({ notifications })` config — that controls the toast surface; the history still records the event.
99
+
100
+ ## Behavior
101
+
102
+ - The filter applies only to messages ingested with the `broadcast: true` flag (the SignalR `SendSystemEvents` channel).
103
+ - Targeted messages (`Send`) bypass the filter entirely.
104
+ - Installing a filter mid-session does not retroactively prune `history` or `realtime`. Past broadcasts stay; only future ones are filtered.
105
+ - The filter is a single function. To compose multiple predicates, `&&` them inside one callback.
106
+
107
+ ## Tips
108
+
109
+ - **Install once, early.** Setting the filter in `App.vue` `onMounted` (after authentication) is the canonical placement, so messages arriving before the first blade mounts are already scoped.
110
+ - **A throwing predicate is not caught.** `ingest` calls the filter without a try/catch, so an exception propagates up through ingestion — it is not logged and the message is not silently dropped. Guard field access inside the predicate (e.g. optional chaining) when reading potentially missing fields.
111
+ - **Do not query the store from inside the filter.** The store is `useBroadcastFilter`'s parent — calling back into it during ingestion causes re-entrancy.
112
+
113
+ ## Related
114
+
115
+ - [useNotificationStore](./useNotificationStore.md) — exposes the same set/clear methods plus the rest of the store API.
116
+ - [useBladeNotifications](./useBladeNotifications.md) — blade-scoped subscription that sees broadcasts after filtering.
117
+ - [Notifications concept page — broadcasts.](../../concepts/notifications.md#broadcast-vs-targeted)
@@ -0,0 +1,150 @@
1
+ ---
2
+ title: useNotificationContext
3
+ category: composables
4
+ group: notifications
5
+ ---
6
+
7
+ # useNotificationContext
8
+
9
+ Reads the current `PushNotification` payload inside a custom notification template. The framework provides the message via Vue's `inject()` from the dropdown or toast surface that hosts the template — the composable returns a reactive `ComputedRef` over it.
10
+
11
+ This is the one piece you write when a notification type registered with `defineAppModule({ notifications: { Type: { template } } })` needs a richer rendering than the default `NotificationTemplate` chrome — for example, formatting a domain-specific status, deriving a colored accent, or wiring a click handler that opens the relevant blade.
12
+
13
+ ## When to use
14
+
15
+ - Implementing the `template` component for a notification type registered through `defineAppModule({ notifications })`.
16
+ - Reading typed payload fields (status, entity name, job id) to drive the template's layout, color, or actions.
17
+ - When NOT to use: anywhere outside a notification template. The composable throws if the inject context is not present.
18
+
19
+ ## Quick Start
20
+
21
+ ```vue
22
+ <script lang="ts" setup>
23
+ import { PushNotification, NotificationTemplate, useNotificationContext } from "@vc-shell/framework";
24
+ import { computed } from "vue";
25
+
26
+ interface IOrderPushNotification extends PushNotification {
27
+ orderId: string;
28
+ total: number;
29
+ }
30
+
31
+ const notificationRef = useNotificationContext<IOrderPushNotification>();
32
+ const notification = computed(() => notificationRef.value);
33
+ </script>
34
+
35
+ <template>
36
+ <NotificationTemplate
37
+ :title="notification.title ?? ''"
38
+ :notification="notification"
39
+ >
40
+ <p>Order {{ notification.orderId }} — ${{ notification.total }}</p>
41
+ </NotificationTemplate>
42
+ </template>
43
+ ```
44
+
45
+ ## API
46
+
47
+ ### Parameters
48
+
49
+ None. The composable is always called without arguments. Generic type parameter narrows the payload shape:
50
+
51
+ ```typescript
52
+ function useNotificationContext<T extends PushNotification = PushNotification>(): ComputedRef<T>;
53
+ ```
54
+
55
+ ### Returns
56
+
57
+ `ComputedRef<T>` — reactive reference to the current `PushNotification` (or your extended subtype via the generic). Update reactively if the same template instance is reused for a refreshed payload (for example, when a progress message is updated through `notification.update`).
58
+
59
+ ## Common patterns
60
+
61
+ ### Compute display strings from payload fields
62
+
63
+ ```vue
64
+ <script lang="ts" setup>
65
+ import { PushNotification, useNotificationContext, NotificationTemplate } from "@vc-shell/framework";
66
+ import { computed } from "vue";
67
+ import { useI18n } from "vue-i18n";
68
+
69
+ interface IProductPush extends PushNotification {
70
+ productName?: string;
71
+ newStatus?: string;
72
+ }
73
+
74
+ const ctx = useNotificationContext<IProductPush>();
75
+ const notification = computed(() => ctx.value);
76
+ const { t } = useI18n({ useScope: "global" });
77
+
78
+ const title = computed(() => (notification.value.productName ? `${t("PRODUCTS.PUSH.PRODUCT")} "${notification.value.productName}" ${t("PRODUCTS.PUSH.UPDATE")}` : (notification.value.title ?? "")));
79
+ </script>
80
+ ```
81
+
82
+ ### Open a blade on click
83
+
84
+ ```vue
85
+ <script lang="ts" setup>
86
+ import { useBlade, useNotificationContext, NotificationTemplate } from "@vc-shell/framework";
87
+ import { computed } from "vue";
88
+
89
+ const { openBlade } = useBlade();
90
+ const ctx = useNotificationContext<IOrderPush>();
91
+ const notification = computed(() => ctx.value);
92
+
93
+ function onClick() {
94
+ if (!notification.value.orderId) return;
95
+ openBlade({ name: "OrderDetails", param: notification.value.orderId });
96
+ }
97
+ </script>
98
+
99
+ <template>
100
+ <NotificationTemplate
101
+ :title="notification.title ?? ''"
102
+ :notification="notification"
103
+ @click="onClick"
104
+ >
105
+ <p>{{ notification.description }}</p>
106
+ </NotificationTemplate>
107
+ </template>
108
+ ```
109
+
110
+ `NotificationTemplate` re-emits the click event so the host (dropdown row, toast) can close itself before your handler runs.
111
+
112
+ ### Color the template by status
113
+
114
+ ```ts
115
+ const notificationStyle = computed(() => {
116
+ switch (notification.value.newStatus) {
117
+ case "Approved":
118
+ return { color: "var(--success-400)", icon: "lucide-check-circle" };
119
+ case "RequestChanges":
120
+ return { color: "var(--danger-400)", icon: "lucide-alert-circle" };
121
+ case "WaitForApproval":
122
+ return { color: "var(--warning-600)", icon: "lucide-clock" };
123
+ default:
124
+ return { color: "var(--primary-400)", icon: "lucide-bell" };
125
+ }
126
+ });
127
+ ```
128
+
129
+ `NotificationTemplate` accepts `:color` and `:icon` props that line up with these computeds — the dropdown row and the toast use the same template, so the styling stays consistent across surfaces.
130
+
131
+ ## Where the template runs
132
+
133
+ Notification templates render in two places:
134
+
135
+ - **In the bell dropdown**, as one row in the history list.
136
+ - **As a toast**, when the type's `toast.mode` is `"auto"` or `"progress"` (set the mode to `"silent"` to render only in the dropdown).
137
+
138
+ The template component must be **the same** in both — register it once on `defineAppModule({ notifications })` and the framework reuses it everywhere.
139
+
140
+ ## Tips
141
+
142
+ - **Always type the generic.** `useNotificationContext<MyPushType>()` enables autocompletion on payload fields. Without it everything degrades to `PushNotification`.
143
+ - **`computed(() => ctx.value)` is idiomatic** in the example apps because consumers want a regular `Ref` shape to pass into child components and template bindings. Direct access via `ctx.value` is fine too.
144
+ - **Do not subscribe inside a template.** The template renders one message; if you need to react to other notifications, do that in a blade with `useBladeNotifications`.
145
+
146
+ ## Related
147
+
148
+ - [useBladeNotifications](./useBladeNotifications.md) — subscribe to types inside a blade.
149
+ - [useNotificationStore](./useNotificationStore.md) — access the underlying store.
150
+ - [Notifications concept page.](../../concepts/notifications.md)