@vc-shell/vc-app-skill 2.0.0-alpha.33 → 2.0.0-alpha.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -54
- package/README.md +42 -12
- package/package.json +4 -4
- package/runtime/VERSION +1 -1
- package/runtime/agents/api-analyzer.md +31 -16
- package/runtime/agents/blade-enhancer.md +15 -9
- package/runtime/agents/details-blade-generator.md +47 -31
- package/runtime/agents/list-blade-generator.md +21 -37
- package/runtime/agents/locales-generator.md +3 -0
- package/runtime/agents/migration-agent.md +18 -7
- package/runtime/agents/module-analyzer.md +2 -0
- package/runtime/agents/module-assembler.md +15 -0
- package/runtime/agents/promote-agent.md +15 -4
- package/runtime/agents/type-checker.md +11 -0
- package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
- package/runtime/knowledge/docs/core/api/platform.docs.md +30 -30
- package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +41 -41
- package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +12 -10
- package/runtime/knowledge/docs/core/composables/useApiClient/useApiClient.docs.md +11 -14
- package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +35 -35
- package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +35 -35
- package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +15 -15
- package/runtime/knowledge/docs/core/composables/useAssets/useAssets.docs.md +21 -18
- package/runtime/knowledge/docs/core/composables/useAssetsManager/useAssetsManager.docs.md +28 -24
- package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +90 -61
- package/runtime/knowledge/docs/core/composables/useBeforeUnload/useBeforeUnload.docs.md +19 -18
- package/runtime/knowledge/docs/core/composables/useBlade/useBlade.docs.md +89 -68
- package/runtime/knowledge/docs/core/composables/useBladeForm/useBladeForm.docs.md +27 -25
- package/runtime/knowledge/docs/core/composables/useBladeRegistry/useBladeRegistry.docs.md +15 -15
- package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +43 -47
- package/runtime/knowledge/docs/core/composables/useBreadcrumbs/useBreadcrumbs.docs.md +11 -11
- package/runtime/knowledge/docs/core/composables/useConnectionStatus/useConnectionStatus.docs.md +27 -15
- package/runtime/knowledge/docs/core/composables/useDashboard/useDashboard.docs.md +30 -30
- package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +34 -36
- package/runtime/knowledge/docs/core/composables/useErrorHandler/useErrorHandler.docs.md +44 -23
- package/runtime/knowledge/docs/core/composables/useFunctions/useFunctions.docs.md +14 -11
- package/runtime/knowledge/docs/core/composables/useKeyboardNavigation/useKeyboardNavigation.docs.md +47 -38
- package/runtime/knowledge/docs/core/composables/useLanguages/useLanguages.docs.md +37 -28
- package/runtime/knowledge/docs/core/composables/useLoading/useLoading.docs.md +23 -17
- package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +9 -9
- package/runtime/knowledge/docs/core/composables/useMenuService/useMenuService.docs.md +42 -42
- package/runtime/knowledge/docs/core/composables/useModificationTracker/useModificationTracker.docs.md +22 -12
- package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +33 -41
- package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +16 -16
- package/runtime/knowledge/docs/core/composables/usePlatformLocaleSync/usePlatformLocaleSync.docs.md +28 -0
- package/runtime/knowledge/docs/core/composables/usePopup/usePopup.docs.md +32 -24
- package/runtime/knowledge/docs/core/composables/useResponsive/useResponsive.docs.md +32 -11
- package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +22 -13
- package/runtime/knowledge/docs/core/composables/useSettingsMenu/useSettingsMenu.docs.md +7 -7
- package/runtime/knowledge/docs/core/composables/useSidebarState/useSidebarState.docs.md +32 -24
- package/runtime/knowledge/docs/core/composables/useSlowNetworkDetection/useSlowNetworkDetection.docs.md +21 -17
- package/runtime/knowledge/docs/core/composables/useTheme/useTheme.docs.md +24 -24
- package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +28 -31
- package/runtime/knowledge/docs/core/composables/useUser/useUser.docs.md +43 -24
- package/runtime/knowledge/docs/core/composables/useUserManagement/useUserManagement.docs.md +68 -48
- package/runtime/knowledge/docs/core/composables/useWebVitals/useWebVitals.docs.md +19 -19
- package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +42 -47
- package/runtime/knowledge/docs/core/directives/autofocus/autofocus.docs.md +10 -4
- package/runtime/knowledge/docs/core/directives/loading/loading.docs.md +35 -20
- package/runtime/knowledge/docs/core/notifications/notifications.docs.md +36 -35
- package/runtime/knowledge/docs/core/plugins/ai-agent/ai-agent.docs.md +38 -38
- package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +79 -62
- package/runtime/knowledge/docs/core/plugins/global-error-handler/global-error-handler.docs.md +10 -10
- package/runtime/knowledge/docs/core/plugins/i18n/i18n.docs.md +21 -23
- package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +91 -83
- package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +10 -16
- package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +9 -9
- package/runtime/knowledge/docs/core/plugins/validation/validation.docs.md +65 -22
- package/runtime/knowledge/docs/core/services/services.docs.md +19 -22
- package/runtime/knowledge/docs/core/types/types.docs.md +40 -40
- package/runtime/knowledge/docs/core/utilities/date/date-utilities.docs.md +27 -27
- package/runtime/knowledge/docs/core/utilities/shared-utilities.docs.md +23 -23
- package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +22 -25
- package/runtime/knowledge/docs/core/utilities/utilities.docs.md +64 -64
- package/runtime/knowledge/docs/injection-keys.docs.md +52 -51
- package/runtime/knowledge/docs/modules/assets-manager/assets-manager.docs.md +9 -9
- package/runtime/knowledge/docs/shell/_internal/popup/common/popup-common.docs.md +23 -43
- package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +5 -5
- package/runtime/knowledge/docs/shell/auth/ForgotPasswordPage/forgot-password-page.docs.md +5 -5
- package/runtime/knowledge/docs/shell/auth/InvitePage/invite-page.docs.md +8 -7
- package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +7 -7
- package/runtime/knowledge/docs/shell/auth/ResetPasswordPage/reset-password-page.docs.md +8 -7
- package/runtime/knowledge/docs/shell/auth/sign-in/sign-in.docs.md +29 -13
- package/runtime/knowledge/docs/shell/components/change-password/change-password.docs.md +13 -16
- package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +1 -7
- package/runtime/knowledge/docs/shell/components/error-interceptor/error-interceptor.docs.md +5 -5
- package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/logout-button/logout-button.docs.md +1 -1
- package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +17 -9
- package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +11 -17
- package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +34 -65
- package/runtime/knowledge/docs/shell/components/sidebar/sidebar.docs.md +16 -26
- package/runtime/knowledge/docs/shell/components/theme-selector/theme-selector.docs.md +2 -2
- package/runtime/knowledge/docs/shell/components/user-dropdown-button/user-dropdown-button.docs.md +7 -9
- package/runtime/knowledge/docs/shell/dashboard/dashboard-charts/dashboard-charts.docs.md +30 -40
- package/runtime/knowledge/docs/shell/dashboard/dashboard-widget-card/dashboard-widget-card.docs.md +26 -19
- package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +15 -12
- package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +15 -26
- package/runtime/knowledge/docs/ui/components/atoms/vc-banner/vc-banner.docs.md +21 -19
- package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +83 -67
- package/runtime/knowledge/docs/ui/components/atoms/vc-card/vc-card.docs.md +100 -59
- package/runtime/knowledge/docs/ui/components/atoms/vc-col/vc-col.docs.md +28 -11
- package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +20 -17
- package/runtime/knowledge/docs/ui/components/atoms/vc-hint/vc-hint.docs.md +26 -17
- package/runtime/knowledge/docs/ui/components/atoms/vc-icon/vc-icon.docs.md +30 -32
- package/runtime/knowledge/docs/ui/components/atoms/vc-image/vc-image.docs.md +25 -48
- package/runtime/knowledge/docs/ui/components/atoms/vc-label/vc-label.docs.md +29 -24
- package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +23 -15
- package/runtime/knowledge/docs/ui/components/atoms/vc-loading/vc-loading.docs.md +22 -13
- package/runtime/knowledge/docs/ui/components/atoms/vc-progress/vc-progress.docs.md +33 -18
- package/runtime/knowledge/docs/ui/components/atoms/vc-row/vc-row.docs.md +56 -15
- package/runtime/knowledge/docs/ui/components/atoms/vc-scrollable-container/vc-scrollable-container.docs.md +28 -15
- package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +40 -20
- package/runtime/knowledge/docs/ui/components/atoms/vc-status/vc-status.docs.md +25 -14
- package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +40 -14
- package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +54 -42
- package/runtime/knowledge/docs/ui/components/atoms/vc-video/vc-video.docs.md +17 -17
- package/runtime/knowledge/docs/ui/components/atoms/vc-widget/vc-widget.docs.md +21 -21
- package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +23 -10
- package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +55 -44
- package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +23 -20
- package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +92 -65
- package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +22 -36
- package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +65 -23
- package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +52 -73
- package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown/vc-dropdown.docs.md +91 -85
- package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown-panel/vc-dropdown-panel.docs.md +38 -42
- package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +56 -73
- package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +61 -27
- package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +42 -50
- package/runtime/knowledge/docs/ui/components/molecules/vc-form/vc-form.docs.md +35 -64
- package/runtime/knowledge/docs/ui/components/molecules/vc-image-tile/vc-image-tile.docs.md +38 -41
- package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +109 -131
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +47 -88
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +50 -64
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-group/vc-input-group.docs.md +29 -24
- package/runtime/knowledge/docs/ui/components/molecules/vc-menu/vc-menu.docs.md +32 -28
- package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +57 -65
- package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +28 -26
- package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +55 -20
- package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md +21 -35
- package/runtime/knowledge/docs/ui/components/molecules/vc-rating/vc-rating.docs.md +38 -33
- package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +72 -83
- package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +21 -16
- package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +55 -64
- package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +51 -70
- package/runtime/knowledge/docs/ui/components/molecules/vc-toast/vc-toast.docs.md +58 -57
- package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +49 -26
- package/runtime/knowledge/docs/ui/components/organisms/vc-auth-layout/vc-auth-layout.docs.md +82 -28
- package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +90 -75
- package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/composables/table-composables.docs.md +99 -48
- package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +548 -367
- package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +35 -52
- package/runtime/knowledge/docs/ui/components/organisms/vc-gallery/vc-gallery.docs.md +33 -62
- package/runtime/knowledge/docs/ui/components/organisms/vc-image-upload/vc-image-upload.docs.md +17 -23
- package/runtime/knowledge/docs/ui/components/organisms/vc-popup/vc-popup.docs.md +109 -68
- package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +82 -44
- package/runtime/knowledge/docs/ui/composables/ui-composables.docs.md +8 -8
- package/runtime/knowledge/docs/ui/composables/useDataTablePagination.docs.md +164 -0
- package/runtime/knowledge/docs/ui/composables/useDataTableSort.docs.md +34 -26
- package/runtime/knowledge/docs/ui/composables/useTableSelection.docs.md +48 -40
- package/runtime/knowledge/docs/ui/composables/useTableSort.docs.md +30 -17
- package/runtime/knowledge/docs/ui/types/ui-types.docs.md +40 -29
- package/runtime/knowledge/examples/offers-module.md +15 -13
- package/runtime/knowledge/examples/team-module.md +82 -119
- package/runtime/knowledge/examples/videos-module.md +44 -17
- package/runtime/knowledge/index.md +22 -0
- package/runtime/knowledge/migration-prompts/blade-form-migration.md +17 -8
- package/runtime/knowledge/migration-prompts/blade-props-migration.md +1 -2
- package/runtime/knowledge/migration-prompts/datatable-migration.md +801 -0
- package/runtime/knowledge/migration-prompts/icon-migration.md +97 -0
- package/runtime/knowledge/migration-prompts/manual-migration-audit.md +117 -0
- package/runtime/knowledge/migration-prompts/notifications-migration.md +8 -3
- package/runtime/knowledge/migration-prompts/nswag-migration.md +25 -29
- package/runtime/knowledge/migration-prompts/use-assets-migration.md +164 -0
- package/runtime/knowledge/migration-prompts/use-data-table-pagination-migration.md +176 -0
- package/runtime/knowledge/migration-prompts/widgets-migration.md +48 -27
- package/runtime/knowledge/patterns/assets-management.md +20 -20
- package/runtime/knowledge/patterns/blade-navigation.md +7 -14
- package/runtime/knowledge/patterns/blade-widget.md +19 -17
- package/runtime/knowledge/patterns/child-blade-flow.md +19 -7
- package/runtime/knowledge/patterns/composable-details.md +20 -50
- package/runtime/knowledge/patterns/composable-list.md +43 -31
- package/runtime/knowledge/patterns/dashboard-widget.md +14 -16
- package/runtime/knowledge/patterns/datatable-pattern.md +521 -0
- package/runtime/knowledge/patterns/details-blade-pattern.md +78 -116
- package/runtime/knowledge/patterns/extension-points-usage.md +53 -44
- package/runtime/knowledge/patterns/form-validation.md +28 -64
- package/runtime/knowledge/patterns/list-blade-pattern.md +33 -21
- package/runtime/knowledge/patterns/module-structure.md +7 -1
- package/runtime/knowledge/patterns/multilanguage-fields.md +8 -14
- package/runtime/knowledge/patterns/notification-template.md +21 -14
- package/runtime/knowledge/patterns/signalr-notifications.md +30 -32
- package/runtime/knowledge/patterns/toolbar-pattern.md +18 -20
- package/runtime/vc-app.md +241 -62
|
@@ -30,21 +30,21 @@ const { uiSettings, loading } = useSettings();
|
|
|
30
30
|
|
|
31
31
|
### Returns
|
|
32
32
|
|
|
33
|
-
| Property
|
|
34
|
-
|
|
35
|
-
| `uiSettings`
|
|
36
|
-
| `loading`
|
|
33
|
+
| Property | Type | Description |
|
|
34
|
+
| --------------- | --------------------------------------------------- | --------------------------------------------------------- |
|
|
35
|
+
| `uiSettings` | `Ref<IUISetting>` | Reactive object with current UI customization values |
|
|
36
|
+
| `loading` | `ComputedRef<boolean>` | Whether settings are being fetched from the API |
|
|
37
37
|
| `applySettings` | `(args: { logo?, title?, avatar?, role? }) => void` | Override settings with custom values (prevents API fetch) |
|
|
38
38
|
|
|
39
39
|
### IUISetting
|
|
40
40
|
|
|
41
|
-
| Property
|
|
42
|
-
|
|
41
|
+
| Property | Type | Description |
|
|
42
|
+
| --------------- | --------- | ------------------------------------------ |
|
|
43
43
|
| `contrast_logo` | `string?` | Logo variant for dark/contrast backgrounds |
|
|
44
|
-
| `logo`
|
|
45
|
-
| `title`
|
|
46
|
-
| `avatar`
|
|
47
|
-
| `role`
|
|
44
|
+
| `logo` | `string?` | Primary application logo URL |
|
|
45
|
+
| `title` | `string?` | Application title |
|
|
46
|
+
| `avatar` | `string?` | Current user avatar URL |
|
|
47
|
+
| `role` | `string?` | Current user role display name |
|
|
48
48
|
|
|
49
49
|
## Common Patterns
|
|
50
50
|
|
|
@@ -58,14 +58,20 @@ const { uiSettings, loading } = useSettings();
|
|
|
58
58
|
</script>
|
|
59
59
|
|
|
60
60
|
<template>
|
|
61
|
-
<div
|
|
61
|
+
<div
|
|
62
|
+
v-loading="loading"
|
|
63
|
+
class="tw-min-h-[40px]"
|
|
64
|
+
>
|
|
62
65
|
<img
|
|
63
66
|
v-if="uiSettings.logo"
|
|
64
67
|
:src="uiSettings.logo"
|
|
65
68
|
:alt="uiSettings.title ?? 'Application Logo'"
|
|
66
69
|
class="tw-h-10"
|
|
67
70
|
/>
|
|
68
|
-
<span
|
|
71
|
+
<span
|
|
72
|
+
v-if="uiSettings.title"
|
|
73
|
+
class="tw-ml-2 tw-text-lg tw-font-semibold"
|
|
74
|
+
>
|
|
69
75
|
{{ uiSettings.title }}
|
|
70
76
|
</span>
|
|
71
77
|
</div>
|
|
@@ -117,7 +123,10 @@ watch(user, (currentUser) => {
|
|
|
117
123
|
alt="User avatar"
|
|
118
124
|
class="tw-w-8 tw-h-8 tw-rounded-full"
|
|
119
125
|
/>
|
|
120
|
-
<span
|
|
126
|
+
<span
|
|
127
|
+
v-if="uiSettings.role"
|
|
128
|
+
class="tw-text-sm tw-text-gray-500"
|
|
129
|
+
>
|
|
121
130
|
{{ uiSettings.role }}
|
|
122
131
|
</span>
|
|
123
132
|
</div>
|
|
@@ -29,16 +29,16 @@ const items = settingsMenu.items.value;
|
|
|
29
29
|
|
|
30
30
|
### Returns (`ISettingsMenuService`)
|
|
31
31
|
|
|
32
|
-
| Property
|
|
33
|
-
|
|
34
|
-
| `register`
|
|
35
|
-
| `unregister` | `(id: string) => void`
|
|
36
|
-
| `items`
|
|
32
|
+
| Property | Type | Description |
|
|
33
|
+
| ------------ | ------------------------------------------------------ | ---------------------------------------------------- |
|
|
34
|
+
| `register` | `(options: RegisterSettingsMenuItemOptions) => string` | Register a settings menu item; returns the item ID |
|
|
35
|
+
| `unregister` | `(id: string) => void` | Remove a settings menu item by ID |
|
|
36
|
+
| `items` | `ComputedRef<ISettingsMenuItem[]>` | Reactive array of all registered settings menu items |
|
|
37
37
|
|
|
38
38
|
### Related Exports
|
|
39
39
|
|
|
40
|
-
| Export
|
|
41
|
-
|
|
40
|
+
| Export | Description |
|
|
41
|
+
| ----------------------- | -------------------------------------------------- |
|
|
42
42
|
| `provideSettingsMenu()` | Create and provide the service in a root component |
|
|
43
43
|
|
|
44
44
|
## Common Patterns
|
|
@@ -15,7 +15,7 @@ Internally, it delegates to `useMenuExpanded()` to share reactive state with oth
|
|
|
15
15
|
|
|
16
16
|
```vue
|
|
17
17
|
<script setup lang="ts">
|
|
18
|
-
import { useSidebarState } from
|
|
18
|
+
import { useSidebarState } from "@vc-shell/framework";
|
|
19
19
|
|
|
20
20
|
const { isExpanded, isPinned, togglePin, openMenu, closeMenu } = useSidebarState();
|
|
21
21
|
</script>
|
|
@@ -24,10 +24,17 @@ const { isExpanded, isPinned, togglePin, openMenu, closeMenu } = useSidebarState
|
|
|
24
24
|
<div class="tw-flex tw-items-center">
|
|
25
25
|
<!-- Show full label when expanded, icon-only when collapsed -->
|
|
26
26
|
<VcIcon icon="fas fa-box" />
|
|
27
|
-
<span
|
|
27
|
+
<span
|
|
28
|
+
v-if="isExpanded"
|
|
29
|
+
class="tw-ml-2"
|
|
30
|
+
>Products</span
|
|
31
|
+
>
|
|
28
32
|
|
|
29
33
|
<!-- Pin/unpin toggle button -->
|
|
30
|
-
<button
|
|
34
|
+
<button
|
|
35
|
+
@click="togglePin"
|
|
36
|
+
class="tw-ml-auto"
|
|
37
|
+
>
|
|
31
38
|
<VcIcon :icon="isPinned ? 'fas fa-thumbtack' : 'fas fa-thumbtack tw-rotate-45'" />
|
|
32
39
|
</button>
|
|
33
40
|
</div>
|
|
@@ -38,21 +45,21 @@ const { isExpanded, isPinned, togglePin, openMenu, closeMenu } = useSidebarState
|
|
|
38
45
|
|
|
39
46
|
### Returns -- State
|
|
40
47
|
|
|
41
|
-
| Property
|
|
42
|
-
|
|
43
|
-
| `isPinned`
|
|
44
|
-
| `isHoverExpanded` | `Ref<boolean>`
|
|
45
|
-
| `isMenuOpen`
|
|
46
|
-
| `isExpanded`
|
|
48
|
+
| Property | Type | Description |
|
|
49
|
+
| ----------------- | ---------------------- | ------------------------------------------------------------------------------------------ | --- | ------------------------------------------------------------------------------------ |
|
|
50
|
+
| `isPinned` | `Ref<boolean>` | Sidebar is pinned open by the user. Persisted to localStorage so it survives page reloads. |
|
|
51
|
+
| `isHoverExpanded` | `Ref<boolean>` | Sidebar is temporarily expanded because the mouse is hovering over it (desktop only). |
|
|
52
|
+
| `isMenuOpen` | `Ref<boolean>` | Mobile menu overlay is visible. |
|
|
53
|
+
| `isExpanded` | `ComputedRef<boolean>` | Derived: `isPinned | | isHoverExpanded`. Use this when you just need to know if sidebar content is visible. |
|
|
47
54
|
|
|
48
55
|
### Returns -- Actions
|
|
49
56
|
|
|
50
|
-
| Property
|
|
51
|
-
|
|
52
|
-
| `togglePin`
|
|
57
|
+
| Property | Type | Description |
|
|
58
|
+
| ------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| `togglePin` | `() => void` | Toggle pinned state. Persists the new value to localStorage immediately. |
|
|
53
60
|
| `setHoverExpanded` | `(value: boolean) => void` | Set hover expansion. Opening has a 200ms delay to prevent flicker from brief mouse passes; closing is immediate. |
|
|
54
|
-
| `openMenu`
|
|
55
|
-
| `closeMenu`
|
|
61
|
+
| `openMenu` | `() => void` | Show the mobile menu overlay. |
|
|
62
|
+
| `closeMenu` | `() => void` | Hide the mobile menu overlay. |
|
|
56
63
|
|
|
57
64
|
## Setup
|
|
58
65
|
|
|
@@ -60,7 +67,7 @@ const { isExpanded, isPinned, togglePin, openMenu, closeMenu } = useSidebarState
|
|
|
60
67
|
|
|
61
68
|
```typescript
|
|
62
69
|
// Inside VcApp.vue setup
|
|
63
|
-
import { provideSidebarState } from
|
|
70
|
+
import { provideSidebarState } from "@vc-shell/framework";
|
|
64
71
|
|
|
65
72
|
provideSidebarState();
|
|
66
73
|
```
|
|
@@ -69,8 +76,8 @@ provideSidebarState();
|
|
|
69
76
|
|
|
70
77
|
```vue
|
|
71
78
|
<script setup lang="ts">
|
|
72
|
-
import { useSidebarState } from
|
|
73
|
-
import { useBladeContext } from
|
|
79
|
+
import { useSidebarState } from "@vc-shell/framework";
|
|
80
|
+
import { useBladeContext } from "@vc-shell/framework";
|
|
74
81
|
|
|
75
82
|
const { closeMenu, isMenuOpen } = useSidebarState();
|
|
76
83
|
const { openBlade } = useBladeContext();
|
|
@@ -83,7 +90,7 @@ async function navigateToProducts() {
|
|
|
83
90
|
|
|
84
91
|
await openBlade({
|
|
85
92
|
component: ProductListBlade,
|
|
86
|
-
param: { catalogId:
|
|
93
|
+
param: { catalogId: "default" },
|
|
87
94
|
});
|
|
88
95
|
}
|
|
89
96
|
</script>
|
|
@@ -100,18 +107,19 @@ async function navigateToProducts() {
|
|
|
100
107
|
|
|
101
108
|
```vue
|
|
102
109
|
<script setup lang="ts">
|
|
103
|
-
import { useSidebarState } from
|
|
104
|
-
import { computed } from
|
|
110
|
+
import { useSidebarState } from "@vc-shell/framework";
|
|
111
|
+
import { computed } from "vue";
|
|
105
112
|
|
|
106
113
|
const { isExpanded } = useSidebarState();
|
|
107
114
|
|
|
108
|
-
const contentClass = computed(() =>
|
|
109
|
-
isExpanded.value ? 'tw-ml-64' : 'tw-ml-16',
|
|
110
|
-
);
|
|
115
|
+
const contentClass = computed(() => (isExpanded.value ? "tw-ml-64" : "tw-ml-16"));
|
|
111
116
|
</script>
|
|
112
117
|
|
|
113
118
|
<template>
|
|
114
|
-
<div
|
|
119
|
+
<div
|
|
120
|
+
:class="contentClass"
|
|
121
|
+
class="tw-transition-all tw-duration-200"
|
|
122
|
+
>
|
|
115
123
|
<slot />
|
|
116
124
|
</div>
|
|
117
125
|
</template>
|
|
@@ -17,14 +17,18 @@ The composable is initialized automatically at app startup. To reactively read t
|
|
|
17
17
|
|
|
18
18
|
```vue
|
|
19
19
|
<script setup lang="ts">
|
|
20
|
-
import { useSlowNetworkDetection } from
|
|
20
|
+
import { useSlowNetworkDetection } from "@vc-shell/framework";
|
|
21
21
|
|
|
22
22
|
const { isSlowNetwork } = useSlowNetworkDetection();
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
25
|
<template>
|
|
26
26
|
<VcBlade title="Products">
|
|
27
|
-
<VcBanner
|
|
27
|
+
<VcBanner
|
|
28
|
+
v-if="isSlowNetwork"
|
|
29
|
+
variant="warning"
|
|
30
|
+
icon="lucide-wifi"
|
|
31
|
+
>
|
|
28
32
|
<template #title>Slow connection</template>
|
|
29
33
|
Loading may take longer than usual.
|
|
30
34
|
</VcBanner>
|
|
@@ -38,19 +42,19 @@ const { isSlowNetwork } = useSlowNetworkDetection();
|
|
|
38
42
|
|
|
39
43
|
### Returns
|
|
40
44
|
|
|
41
|
-
| Property
|
|
42
|
-
|
|
43
|
-
| `isSlowNetwork`
|
|
44
|
-
| `trackRequest`
|
|
45
|
-
| `untrackRequest` | `(id: string) => void`
|
|
45
|
+
| Property | Type | Description |
|
|
46
|
+
| ---------------- | ------------------------ | ------------------------------------------------------------------------------- |
|
|
47
|
+
| `isSlowNetwork` | `Readonly<Ref<boolean>>` | `true` when the network is slow (either channel active). Read-only. |
|
|
48
|
+
| `trackRequest` | `(id: string) => void` | Start tracking a request. If it isn't untracked within 10 s, it counts as slow. |
|
|
49
|
+
| `untrackRequest` | `(id: string) => void` | Stop tracking a request. Cancels the timer or decrements the slow count. |
|
|
46
50
|
|
|
47
51
|
### Constants
|
|
48
52
|
|
|
49
|
-
| Name
|
|
50
|
-
|
|
51
|
-
| `SLOW_REQUEST_THRESHOLD_MS` | `10000`
|
|
52
|
-
| `DISMISS_DELAY_MS`
|
|
53
|
-
| `SLOW_EFFECTIVE_TYPES`
|
|
53
|
+
| Name | Value | Purpose |
|
|
54
|
+
| --------------------------- | ------------------- | --------------------------------------------------- |
|
|
55
|
+
| `SLOW_REQUEST_THRESHOLD_MS` | `10000` | Time before a pending request is considered slow |
|
|
56
|
+
| `DISMISS_DELAY_MS` | `3000` | Delay before hiding the notification after recovery |
|
|
57
|
+
| `SLOW_EFFECTIVE_TYPES` | `["slow-2g", "2g"]` | Connection types flagged as slow |
|
|
54
58
|
|
|
55
59
|
## How It Works
|
|
56
60
|
|
|
@@ -74,18 +78,18 @@ The fetch interceptor in `framework/core/interceptors/index.ts` calls `trackRequ
|
|
|
74
78
|
|
|
75
79
|
```vue
|
|
76
80
|
<script setup lang="ts">
|
|
77
|
-
import { watch } from
|
|
78
|
-
import { useSlowNetworkDetection } from
|
|
81
|
+
import { watch } from "vue";
|
|
82
|
+
import { useSlowNetworkDetection } from "@vc-shell/framework";
|
|
79
83
|
|
|
80
84
|
const { isSlowNetwork } = useSlowNetworkDetection();
|
|
81
85
|
|
|
82
86
|
// Switch to a lightweight polling interval when the network is slow
|
|
83
|
-
const pollInterval = computed(() => isSlowNetwork.value ? 30000 : 5000);
|
|
87
|
+
const pollInterval = computed(() => (isSlowNetwork.value ? 30000 : 5000));
|
|
84
88
|
|
|
85
89
|
// Warn before navigating away during slow network + unsaved changes
|
|
86
90
|
watch(isSlowNetwork, (slow) => {
|
|
87
91
|
if (slow) {
|
|
88
|
-
console.info(
|
|
92
|
+
console.info("Network is slow — consider disabling auto-refresh");
|
|
89
93
|
}
|
|
90
94
|
});
|
|
91
95
|
</script>
|
|
@@ -96,7 +100,7 @@ watch(isSlowNetwork, (slow) => {
|
|
|
96
100
|
If you bypass the standard fetch interceptor (e.g., direct `XMLHttpRequest` or third-party SDK), you can manually track the request:
|
|
97
101
|
|
|
98
102
|
```ts
|
|
99
|
-
import { useSlowNetworkDetection } from
|
|
103
|
+
import { useSlowNetworkDetection } from "@vc-shell/framework";
|
|
100
104
|
|
|
101
105
|
const { trackRequest, untrackRequest } = useSlowNetworkDetection();
|
|
102
106
|
|
|
@@ -13,15 +13,15 @@ Manages color theme registration, switching, and persistence. Themes are applied
|
|
|
13
13
|
|
|
14
14
|
```vue
|
|
15
15
|
<script setup lang="ts">
|
|
16
|
-
import { useTheme } from
|
|
16
|
+
import { useTheme } from "@vc-shell/framework";
|
|
17
17
|
|
|
18
18
|
const { themes, currentThemeKey, currentLocalizedName, next, setTheme, register } = useTheme();
|
|
19
19
|
|
|
20
20
|
// Register a dark theme from your module
|
|
21
|
-
register({ key:
|
|
21
|
+
register({ key: "dark", localizationKey: "CORE.THEMES.DARK" });
|
|
22
22
|
|
|
23
23
|
// Switch to it explicitly
|
|
24
|
-
setTheme(
|
|
24
|
+
setTheme("dark");
|
|
25
25
|
|
|
26
26
|
// Or cycle through all registered themes (light -> dark -> light -> ...)
|
|
27
27
|
next();
|
|
@@ -39,28 +39,28 @@ next();
|
|
|
39
39
|
|
|
40
40
|
### Returns
|
|
41
41
|
|
|
42
|
-
| Property
|
|
43
|
-
|
|
44
|
-
| `themes`
|
|
45
|
-
| `currentThemeKey`
|
|
46
|
-
| `currentLocalizedName` | `ComputedRef<string>`
|
|
47
|
-
| `next`
|
|
48
|
-
| `setTheme`
|
|
49
|
-
| `register`
|
|
50
|
-
| `unregister`
|
|
42
|
+
| Property | Type | Description |
|
|
43
|
+
| ---------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `themes` | `ComputedRef<DisplayTheme[]>` | All registered themes with their `key` and localized `name`. Reactive -- updates when themes are registered/unregistered. |
|
|
45
|
+
| `currentThemeKey` | `Ref<string>` | Active theme key (e.g., `"light"`, `"dark"`). Two-way reactive -- setting it switches the theme. |
|
|
46
|
+
| `currentLocalizedName` | `ComputedRef<string>` | Localized display name of the active theme (e.g., "Light", "Dark"). Falls back to capitalized key. |
|
|
47
|
+
| `next` | `() => void` | Cycle to the next registered theme in order. Wraps around at the end. |
|
|
48
|
+
| `setTheme` | `(themeKey: string) => void` | Switch to a specific registered theme. Logs a warning if the key is not registered. |
|
|
49
|
+
| `register` | `(themes: ThemeDefinition \| ThemeDefinition[]) => void` | Add one or more themes to the global registry. Duplicates (by key) are silently ignored. |
|
|
50
|
+
| `unregister` | `(keys: string \| string[]) => void` | Remove themes from the registry by key. |
|
|
51
51
|
|
|
52
52
|
### ThemeDefinition
|
|
53
53
|
|
|
54
|
-
| Field
|
|
55
|
-
|
|
56
|
-
| `key`
|
|
57
|
-
| `localizationKey` | `string` | No
|
|
54
|
+
| Field | Type | Required | Description |
|
|
55
|
+
| ----------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| `key` | `string` | Yes | Unique theme identifier. Used as the `data-theme` attribute value on `<html>` and as the localStorage persistence key. |
|
|
57
|
+
| `localizationKey` | `string` | No | i18n key for the display name (e.g., `"CORE.THEMES.DARK"`). Falls back to the capitalized `key` (e.g., `"Dark"`). |
|
|
58
58
|
|
|
59
59
|
### DisplayTheme
|
|
60
60
|
|
|
61
|
-
| Field
|
|
62
|
-
|
|
63
|
-
| `key`
|
|
61
|
+
| Field | Type | Description |
|
|
62
|
+
| ------ | -------- | ---------------------------------------------------------------------------- |
|
|
63
|
+
| `key` | `string` | Theme identifier |
|
|
64
64
|
| `name` | `string` | Localized display name, resolved from `localizationKey` or capitalized `key` |
|
|
65
65
|
|
|
66
66
|
## How It Works
|
|
@@ -77,16 +77,16 @@ next();
|
|
|
77
77
|
|
|
78
78
|
```typescript
|
|
79
79
|
// my-module/index.ts
|
|
80
|
-
import type { App } from
|
|
81
|
-
import { useTheme } from
|
|
80
|
+
import type { App } from "vue";
|
|
81
|
+
import { useTheme } from "@vc-shell/framework";
|
|
82
82
|
|
|
83
83
|
export default {
|
|
84
84
|
install(app: App) {
|
|
85
85
|
const { register } = useTheme();
|
|
86
86
|
|
|
87
87
|
register([
|
|
88
|
-
{ key:
|
|
89
|
-
{ key:
|
|
88
|
+
{ key: "ocean", localizationKey: "MY_MODULE.THEMES.OCEAN" },
|
|
89
|
+
{ key: "forest", localizationKey: "MY_MODULE.THEMES.FOREST" },
|
|
90
90
|
]);
|
|
91
91
|
},
|
|
92
92
|
};
|
|
@@ -113,7 +113,7 @@ Then define your theme's CSS variables scoped by the `data-theme` attribute:
|
|
|
113
113
|
|
|
114
114
|
```vue
|
|
115
115
|
<script setup lang="ts">
|
|
116
|
-
import { useTheme } from
|
|
116
|
+
import { useTheme } from "@vc-shell/framework";
|
|
117
117
|
|
|
118
118
|
const { themes, currentThemeKey, setTheme } = useTheme();
|
|
119
119
|
</script>
|
|
@@ -170,10 +170,7 @@ By default, all methods operate on the current blade. Pass an explicit `targetBl
|
|
|
170
170
|
|
|
171
171
|
```typescript
|
|
172
172
|
// Register a button on a specific child blade
|
|
173
|
-
registerToolbarItem(
|
|
174
|
-
{ id: "child-action", title: "Action", clickHandler: () => {} },
|
|
175
|
-
"ChildBlade",
|
|
176
|
-
);
|
|
173
|
+
registerToolbarItem({ id: "child-action", title: "Action", clickHandler: () => {} }, "ChildBlade");
|
|
177
174
|
|
|
178
175
|
// Clear another blade's toolbar
|
|
179
176
|
clearBladeToolbarItems("ChildBlade");
|
|
@@ -325,42 +322,42 @@ function helperFunction() {
|
|
|
325
322
|
|
|
326
323
|
### Parameters
|
|
327
324
|
|
|
328
|
-
| Parameter | Type
|
|
329
|
-
|
|
330
|
-
| `options` | `UseToolbarOptions` | No
|
|
325
|
+
| Parameter | Type | Required | Default | Description |
|
|
326
|
+
| --------- | ------------------- | -------- | ------- | --------------------- |
|
|
327
|
+
| `options` | `UseToolbarOptions` | No | `{}` | Configuration options |
|
|
331
328
|
|
|
332
329
|
#### UseToolbarOptions
|
|
333
330
|
|
|
334
|
-
| Option
|
|
335
|
-
|
|
336
|
-
| `autoCleanup` | `boolean` | `true`
|
|
331
|
+
| Option | Type | Default | Description |
|
|
332
|
+
| ------------- | --------- | ------- | ------------------------------------------------------------------ |
|
|
333
|
+
| `autoCleanup` | `boolean` | `true` | Clear all toolbar items for the current blade on component unmount |
|
|
337
334
|
|
|
338
335
|
### Returns: `UseToolbarReturn`
|
|
339
336
|
|
|
340
|
-
| Property
|
|
341
|
-
|
|
342
|
-
| `registerToolbarItem`
|
|
343
|
-
| `unregisterToolbarItem`
|
|
344
|
-
| `updateToolbarItem`
|
|
345
|
-
| `getToolbarItems`
|
|
346
|
-
| `clearBladeToolbarItems`
|
|
347
|
-
| `isToolbarItemRegistered` | `(id: string) => boolean`
|
|
348
|
-
| `registeredToolbarItems`
|
|
337
|
+
| Property | Type | Description |
|
|
338
|
+
| ------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------- |
|
|
339
|
+
| `registerToolbarItem` | `(item: IToolbarItem, targetBladeId?: string) => void` | Register a toolbar button (scoped to current blade by default) |
|
|
340
|
+
| `unregisterToolbarItem` | `(id: string, targetBladeId?: string) => void` | Remove a toolbar button by ID |
|
|
341
|
+
| `updateToolbarItem` | `(id: string, partial: Partial<IToolbarItem>, targetBladeId?: string) => void` | Update properties of an existing toolbar button |
|
|
342
|
+
| `getToolbarItems` | `(targetBladeId?: string) => IToolbarItem[]` | Get all toolbar items for a blade |
|
|
343
|
+
| `clearBladeToolbarItems` | `(targetBladeId?: string) => void` | Remove all toolbar items for a blade |
|
|
344
|
+
| `isToolbarItemRegistered` | `(id: string) => boolean` | Check if a toolbar item with the given ID exists |
|
|
345
|
+
| `registeredToolbarItems` | `IToolbarRegistration[]` | All registered toolbar items across all blades |
|
|
349
346
|
|
|
350
347
|
### IToolbarItem
|
|
351
348
|
|
|
352
|
-
| Property
|
|
353
|
-
|
|
354
|
-
| `id`
|
|
355
|
-
| `title`
|
|
356
|
-
| `icon`
|
|
357
|
-
| `clickHandler` | `(app?) => void`
|
|
358
|
-
| `disabled`
|
|
359
|
-
| `isVisible`
|
|
360
|
-
| `priority`
|
|
361
|
-
| `separator`
|
|
362
|
-
| `permissions`
|
|
363
|
-
| `bladeId`
|
|
349
|
+
| Property | Type | Required | Description |
|
|
350
|
+
| -------------- | -------------------------------------------------------------------------- | -------- | -------------------------------------------------------------- |
|
|
351
|
+
| `id` | `string` | Yes | Unique identifier for the button |
|
|
352
|
+
| `title` | `string \| Ref<string> \| ComputedRef<string>` | No | Button label (supports reactive values) |
|
|
353
|
+
| `icon` | `string \| (() => string)` | No | Icon class (e.g., `"fas fa-save"`) or a function returning one |
|
|
354
|
+
| `clickHandler` | `(app?) => void` | No | Click callback |
|
|
355
|
+
| `disabled` | `boolean \| ComputedRef<boolean>` | No | Whether the button is disabled |
|
|
356
|
+
| `isVisible` | `boolean \| Ref<boolean> \| ComputedRef<boolean> \| ((blade?) => boolean)` | No | Controls button visibility |
|
|
357
|
+
| `priority` | `number` | No | Sort order (higher = displayed first, default `0`) |
|
|
358
|
+
| `separator` | `"left" \| "right" \| "both"` | No | Adds a visual divider next to the button |
|
|
359
|
+
| `permissions` | `string \| string[]` | No | Required permission(s) to display the button |
|
|
360
|
+
| `bladeId` | `string` | No | Target blade ID (auto-resolved from context) |
|
|
364
361
|
|
|
365
362
|
## Related
|
|
366
363
|
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
47
|
-
|
|
48
|
-
| `user`
|
|
49
|
-
| `loading`
|
|
50
|
-
| `isAuthenticated` | `ComputedRef<boolean>`
|
|
51
|
-
| `isAdministrator` | `ComputedRef<boolean \| undefined>`
|
|
52
|
-
| `loadUser`
|
|
53
|
-
| `signOut`
|
|
54
|
-
| `getAccessToken`
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
109
|
-
import { useRouter } from
|
|
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:
|
|
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
|
|
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
|
|
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.
|