@vc-shell/vc-app-skill 2.0.4 → 2.0.6

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 (60) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +7 -7
  3. package/package.json +1 -1
  4. package/runtime/VERSION +1 -1
  5. package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
  6. package/runtime/knowledge/docs/core/api/platform.docs.md +6 -6
  7. package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +1 -1
  8. package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +2 -2
  9. package/runtime/knowledge/docs/core/composables/useApiClient/useApiClient.docs.md +67 -42
  10. package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +2 -2
  11. package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +15 -13
  12. package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +11 -11
  13. package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +17 -14
  14. package/runtime/knowledge/docs/core/composables/useBeforeUnload/useBeforeUnload.docs.md +4 -2
  15. package/runtime/knowledge/docs/core/composables/useBlade/useBlade.docs.md +31 -23
  16. package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +46 -26
  17. package/runtime/knowledge/docs/core/composables/useDashboard/useDashboard.docs.md +1 -0
  18. package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +1 -1
  19. package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +1 -1
  20. package/runtime/knowledge/docs/core/composables/useMenuService/useMenuService.docs.md +1 -0
  21. package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +20 -6
  22. package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +2 -1
  23. package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +2 -2
  24. package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +109 -133
  25. package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +1 -2
  26. package/runtime/knowledge/docs/core/notifications/composables/useBladeNotifications.docs.md +184 -0
  27. package/runtime/knowledge/docs/core/notifications/composables/useBroadcastFilter.docs.md +117 -0
  28. package/runtime/knowledge/docs/core/notifications/composables/useNotificationContext.docs.md +150 -0
  29. package/runtime/knowledge/docs/core/notifications/composables/useNotificationStore.docs.md +113 -0
  30. package/runtime/knowledge/docs/core/notifications/notifications.docs.md +12 -15
  31. package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +1 -1
  32. package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +54 -116
  33. package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +12 -3
  34. package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +20 -20
  35. package/runtime/knowledge/docs/injection-keys.docs.md +1 -1
  36. package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +1 -1
  37. package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +1 -1
  38. package/runtime/knowledge/docs/shell/components/notification-dropdown/notification-dropdown.docs.md +1 -1
  39. package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +1 -1
  40. package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +7 -7
  41. package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +2 -2
  42. package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +1 -1
  43. package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +4 -4
  44. package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +1 -1
  45. package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +21 -1
  46. package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +22 -6
  47. package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +2 -2
  48. package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +32 -26
  49. package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +3 -3
  50. package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +1 -1
  51. package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +1 -1
  52. package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +1 -1
  53. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md +13 -13
  54. package/runtime/knowledge/docs/ui/components/molecules/vc-form/vc-form.docs.md +1 -1
  55. package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +1 -1
  56. package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +4 -4
  57. package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +39 -37
  58. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +17 -17
  59. package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +16 -7
  60. package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +1 -1
@@ -23,14 +23,22 @@ Unified composable for blade navigation, identity, communication, guards, and er
23
23
  <script setup lang="ts">
24
24
  import { useBlade } from "@vc-shell/framework";
25
25
 
26
- // Inside a blade -- full API is available
27
- const { openBlade, closeSelf, param, onBeforeClose } = useBlade();
26
+ // List blade -- typical destructure: open children, expose parent methods, read param
27
+ interface BladeOptions {
28
+ item?: Order;
29
+ }
30
+ const { openBlade, exposeToChildren, param, options, callParent } = useBlade<BladeOptions>();
28
31
 
29
- // Open a child blade
30
- await openBlade({ name: "OrderDetails", param: "order-123" });
32
+ // Expose a reload method so child details blades can refresh the list after save
33
+ async function reload() {
34
+ /* refetch items */
35
+ }
36
+ exposeToChildren({ reload });
31
37
 
32
- // Read the parameter passed when this blade was opened
33
- console.log(param.value); // "order-123"
38
+ // Open a child details blade
39
+ function onRowClick(order: Order) {
40
+ openBlade({ name: "OrderDetails", param: order.id, options: { item: order } });
41
+ }
34
42
  </script>
35
43
  ```
36
44
 
@@ -41,7 +49,7 @@ import { useBlade } from "@vc-shell/framework";
41
49
  // Outside a blade (e.g. dashboard widget) -- only navigation works
42
50
  const { openBlade } = useBlade();
43
51
 
44
- openBlade({ name: "OrderDetails", param: "order-123" });
52
+ openBlade({ name: "OrdersList", isWorkspace: true });
45
53
  </script>
46
54
  ```
47
55
 
@@ -49,13 +57,14 @@ openBlade({ name: "OrderDetails", param: "order-123" });
49
57
  <script setup lang="ts">
50
58
  import { useBlade } from "@vc-shell/framework";
51
59
 
52
- // Typed options no manual casting needed
53
- interface BladeOptions {
54
- sellerProduct?: SellerProduct;
55
- }
56
- const { param, options, callParent } = useBlade<BladeOptions>();
60
+ // Details blade -- call back into the parent after save
61
+ const { param, options, callParent, closeSelf } = useBlade<{ item?: Order }>();
57
62
 
58
- console.log(options.value?.sellerProduct); // typed as SellerProduct | undefined
63
+ async function onSave() {
64
+ await saveOrder();
65
+ await callParent("reload");
66
+ await closeSelf();
67
+ }
59
68
  </script>
60
69
  ```
61
70
 
@@ -518,7 +527,7 @@ The most common pattern: a list workspace that opens a details blade on row clic
518
527
  <script setup lang="ts">
519
528
  import { useBlade } from "@vc-shell/framework";
520
529
 
521
- defineOptions({ name: "ProductsList", url: "/products", isWorkspace: true });
530
+ defineBlade({ name: "ProductsList", url: "/products", isWorkspace: true });
522
531
 
523
532
  const { openBlade } = useBlade();
524
533
  const selectedItemId = ref<string>();
@@ -552,7 +561,7 @@ defineExpose({ reload, title: "Products" });
552
561
  <script setup lang="ts">
553
562
  import { useBlade, usePopup } from "@vc-shell/framework";
554
563
 
555
- defineOptions({ name: "ProductDetails", url: "/product-details" });
564
+ defineBlade({ name: "ProductDetails", url: "/product-details" });
556
565
 
557
566
  const { param, onBeforeClose, closeSelf, callParent } = useBlade();
558
567
  const { showConfirmation } = usePopup();
@@ -764,11 +773,10 @@ if (param.value) {
764
773
 
765
774
  ## Related
766
775
 
767
- | Resource | Description |
768
- | ------------------------------------------------------------------------- | ------------------------------------------------------------ |
769
- | [`defineBladeContext` / `injectBladeContext`](../useBladeContext.docs.md) | Share reactive blade data with descendant widgets |
770
- | [`useBladeRegistry`](../useBladeRegistry/) | Look up registered blade components by name |
771
- | [`VcBlade`](../../../ui/components/organisms/vc-blade/) | The blade UI shell component (header, toolbar, content area) |
772
- | [`VcBladeNavigation`](../../../shared/components/blade-navigation/) | The container component that renders the blade stack |
773
- | [`useToolbar`](../../../shared/composables/useToolbar/) | Dynamic toolbar management for blades |
774
- | [`usePopup`](../../../shared/composables/usePopup/) | Confirmation dialogs, commonly used in close guards |
776
+ | Resource | Description |
777
+ | ---------------------------------------------------------------------------- | ------------------------------------------------------------ |
778
+ | [`defineBladeContext` / `injectBladeContext`](../bladeContext/index.docs.md) | Share reactive blade data with descendant widgets |
779
+ | [`useBladeRegistry`](../useBladeRegistry/) | Look up registered blade components by name |
780
+ | [`VcBlade`](../../../ui/components/organisms/vc-blade/vc-blade.docs.md) | The blade UI shell component (header, toolbar, content area) |
781
+ | [`useToolbar`](../useToolbar/useToolbar.docs.md) | Dynamic toolbar management for blades |
782
+ | [`usePopup`](../usePopup/usePopup.docs.md) | Confirmation dialogs, commonly used in close guards |
@@ -24,34 +24,54 @@ Headless widgets are defined as plain configuration objects with reactive refs f
24
24
 
25
25
  ## Basic Usage
26
26
 
27
- ```typescript
28
- import { useBladeWidgets } from "@vc-shell/framework";
27
+ In production apps, the widget array is almost never declared inline in the blade's `<script setup>`. The recommended pattern is to extract widget setup into a sibling composable (`useXxxWidgets.ts`) so the blade stays clean, the widgets are testable in isolation, and they can be reused across blades that share a domain.
29
28
 
30
- const { refreshAll } = useBladeWidgets([
31
- {
32
- id: "OffersWidget",
33
- icon: "lucide-tag",
34
- title: "OFFERS.TITLE",
35
- badge: offersCount,
36
- loading: offersLoading,
37
- onClick: () => openBlade({ name: "OffersList" }),
38
- onRefresh: () => reloadOffers(),
39
- },
40
- {
41
- id: "ReviewsWidget",
42
- icon: "lucide-star",
43
- title: "REVIEWS.TITLE",
44
- badge: reviewsCount,
45
- isVisible: computed(() => !!item.value?.id),
46
- onClick: () => openBlade({ name: "ReviewsList" }),
47
- },
48
- ]);
29
+ ```typescript title="modules/products/widgets/useProductWidgets.ts"
30
+ import { useBlade, useBladeWidgets, type UseBladeWidgetsReturn } from "@vc-shell/framework";
31
+ import type { Ref, ComputedRef } from "vue";
32
+ import { useOfferCount } from "./useOfferCount";
33
+
34
+ interface Options {
35
+ item: Ref<Product | undefined>;
36
+ isVisible: ComputedRef<boolean>;
37
+ }
38
+
39
+ export function useProductWidgets({ item, isVisible }: Options): UseBladeWidgetsReturn {
40
+ const { openBlade } = useBlade();
41
+ const { count: offersCount, loading, refresh } = useOfferCount(item);
42
+
43
+ return useBladeWidgets([
44
+ {
45
+ id: "OffersWidget",
46
+ icon: "lucide-tag",
47
+ title: "OFFERS.TITLE",
48
+ badge: offersCount,
49
+ loading,
50
+ isVisible,
51
+ onClick: () => openBlade({ name: "OffersList", options: { productId: item.value?.id } }),
52
+ onRefresh: refresh,
53
+ },
54
+ ]);
55
+ }
56
+ ```
49
57
 
50
- // After a save, refresh all widget data
51
- await saveEntity();
52
- refreshAll();
58
+ ```vue title="modules/products/pages/product-details.vue"
59
+ <script setup lang="ts">
60
+ import { useProductWidgets } from "../widgets/useProductWidgets";
61
+
62
+ const { item } = useProductDetails();
63
+ const isVisible = computed(() => !!item.value?.id);
64
+ const { refreshAll } = useProductWidgets({ item, isVisible });
65
+
66
+ async function onSave() {
67
+ await saveProduct();
68
+ refreshAll();
69
+ }
70
+ </script>
53
71
  ```
54
72
 
73
+ Inline `useBladeWidgets([...])` is fine for one-off widgets, but extracting becomes essential when widget data comes from API calls (which need their own composables anyway).
74
+
55
75
  ## API
56
76
 
57
77
  ### Parameters
@@ -119,7 +139,7 @@ A complete example of an external widget that shows an unread message count and
119
139
  **1. Register the external widget (module index.ts):**
120
140
 
121
141
  ```typescript
122
- import { createAppModule, registerExternalWidget, BladeDescriptor } from "@vc-shell/framework";
142
+ import { registerExternalWidget, BladeDescriptor } from "@vc-shell/framework";
123
143
  import { markRaw } from "vue";
124
144
  import { MessageWidget } from "./components/widgets";
125
145
 
@@ -304,7 +324,7 @@ const { refreshAll } = useBladeWidgets([]);
304
324
 
305
325
  ## Related
306
326
 
307
- - [`defineBladeContext` / `injectBladeContext`](../bladeContext/) -- expose/consume blade data in external widgets
327
+ - [`defineBladeContext` / `injectBladeContext`](../bladeContext/index.docs.md) -- expose/consume blade data in external widgets
308
328
  - `registerExternalWidget` -- register a component-based widget globally for target blades
309
329
 
310
330
  <!-- internal:start -->
@@ -270,6 +270,7 @@ export function registerAnalyticsDashboard() {
270
270
  ### Widget Component Template
271
271
 
272
272
  ```typescript
273
+ // pseudo-code: replace OrderClient with your generated API client
273
274
  <!-- widgets/OrdersSummary.vue -->
274
275
  <script setup lang="ts">
275
276
  import { ref, onMounted } from "vue";
@@ -163,4 +163,4 @@ useDynamicProperties/
163
163
  ## Related
164
164
 
165
165
  - [useBladeForm](../useBladeForm/useBladeForm.docs.md) — form state management that uses `semanticEqual` for modification detection. `cleanEmptyValues` ensures compatibility.
166
- - [VcDynamicProperty](../../../../ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md) — UI component that renders dynamic properties
166
+ - [VcDynamicProperty](../../../ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md) — UI component that renders dynamic properties
@@ -76,7 +76,7 @@ const isVisuallyExpanded = computed(() => isExpanded.value || isHoverExpanded.va
76
76
 
77
77
  ## Details
78
78
 
79
- - **Storage key scoping**: The key is scoped per application using the first URL path segment: `VC_APP_MENU_EXPANDED_{appName}`. For example, if the app is hosted at `/vendor-portal/`, the key is `VC_APP_MENU_EXPANDED_vendor-portal`. This allows multiple vc-shell apps on the same domain to maintain independent sidebar states.
79
+ - **Storage key scoping**: The key is scoped per application using the first URL path segment: `VC_APP_MENU_EXPANDED_{appName}`. For example, if the app is hosted at `/operations/`, the key is `VC_APP_MENU_EXPANDED_operations`. This allows multiple vc-shell apps on the same domain to maintain independent sidebar states.
80
80
  - **Hover delay**: Opening uses a 200ms debounce to prevent accidental expansion when the cursor briefly passes over the sidebar. Closing is immediate to feel responsive.
81
81
  - **Cleanup**: Pending hover timeouts are cleaned up via `onScopeDispose` to prevent memory leaks when the composable's effect scope is destroyed.
82
82
  - **Default state**: The sidebar starts pinned open (`true`) on first visit, which is the most user-friendly default for new users.
@@ -193,6 +193,7 @@ removeRegisteredMenuItem({ routeId: "ReturnsList" } as MenuItem);
193
193
  ### Dynamic Badge Based on API Data
194
194
 
195
195
  ```typescript
196
+ // pseudo-code: replace OrderClient with your generated API client
196
197
  <script setup lang="ts">
197
198
  import { onMounted, ref } from "vue";
198
199
  import { setMenuBadge, useApiClient } from "@vc-shell/framework";
@@ -18,22 +18,36 @@ Provides access to the push-notification system: reading notification history, f
18
18
 
19
19
  ## Quick Start
20
20
 
21
+ In new code, prefer `useBladeNotifications` — it integrates with the blade effect scope and auto-cleans on unmount.
22
+
23
+ ```typescript
24
+ import { useBladeNotifications } from "@vc-shell/framework";
25
+
26
+ // Blade-scoped subscription with automatic cleanup
27
+ const { messages, unreadCount, markAsRead } = useBladeNotifications({
28
+ types: ["OrderStatusChanged"],
29
+ filter: (msg) => msg.orderId === currentOrderId.value,
30
+ onMessage: () => refreshOrderList(),
31
+ });
32
+ ```
33
+
34
+ Use `useNotifications` (this composable) only in legacy code or when you need to subscribe outside a blade scope:
35
+
21
36
  ```typescript
22
37
  import { useNotifications } from "@vc-shell/framework";
23
38
 
24
- // Subscribe to specific notification types
25
- const { notifications, moduleNotifications, loadFromHistory, markAsRead, markAllAsRead, setNotificationHandler } = useNotifications("OrderStatusChanged");
39
+ // Legacy: type-filtered subscription with manual lifecycle
40
+ const { notifications, setNotificationHandler, loadFromHistory } = useNotifications("OrderStatusChanged");
26
41
 
27
- // Register a handler for real-time notifications
28
42
  setNotificationHandler((notification) => {
29
- console.log("Order status changed:", notification);
30
43
  refreshOrderList();
31
44
  });
32
45
 
33
- // Load historical notifications on mount
34
46
  onMounted(() => loadFromHistory(50));
35
47
  ```
36
48
 
49
+ For the canonical blade-side example and the registration of notification types at module load, see the [Notifications system reference](../../notifications/notifications.docs.md).
50
+
37
51
  ## API
38
52
 
39
53
  ### Parameters
@@ -155,6 +169,6 @@ onMounted(refreshInventory);
155
169
 
156
170
  ## Related
157
171
 
158
- - [useBladeNotifications](../useBladeNotifications/) -- preferred replacement with blade lifecycle integration
172
+ - [Notification system reference](../../notifications/notifications.docs.md) -- includes the recommended `useBladeNotifications` composable with blade lifecycle integration
159
173
  - `useNotificationStore()` -- direct Pinia-based store access for full control
160
174
  - `MIGRATION_GUIDE.md#notifications` -- migration guide from useNotifications to useBladeNotifications
@@ -38,6 +38,7 @@ The `hasAccess` function evaluates permissions from the current user object (loa
38
38
  | Input | Result |
39
39
  | -------------------------------- | ------------------------------------------------------------------- |
40
40
  | `undefined` | `true` -- no permission required, everyone has access |
41
+ | `[]` (empty array) | `true` -- empty array means no restriction, same as `undefined` |
41
42
  | `"order:read"` | `true` if the user has this exact permission string |
42
43
  | `["order:read", "order:update"]` | `true` if the user has **any** of the listed permissions (OR logic) |
43
44
  | Any value, administrator user | Always `true` -- administrators bypass all checks |
@@ -279,7 +280,7 @@ if (hasAccess("order:delete")) {
279
280
  - Permissions are read from `useUserManagement().user.value.permissions` at composable initialization.
280
281
  - If `user.value.isAdministrator` is `true`, `hasAccess` always returns `true` regardless of the input.
281
282
  - An array input uses OR logic: the user needs at least one of the listed permissions.
282
- - Passing `undefined` returns `true`, allowing unrestricted access by default.
283
+ - Passing `undefined` or an empty array (`[]`) returns `true`, allowing unrestricted access by default.
283
284
 
284
285
  ## Related
285
286
 
@@ -94,8 +94,8 @@ const { applySettings } = useSettings();
94
94
 
95
95
  // Override default platform settings with module-specific branding
96
96
  applySettings({
97
- logo: "/modules/vendor-portal/logo.svg",
98
- title: "Vendor Portal",
97
+ logo: "/modules/operations-console/logo.svg",
98
+ title: "Operations Console",
99
99
  });
100
100
  </script>
101
101
  ```