@vc-shell/framework 1.2.2 → 1.2.3-beta.0
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/core/composables/index.ts +2 -0
- package/core/composables/useAssets/index.ts +72 -28
- package/core/composables/useAsync/index.ts +4 -1
- package/core/composables/useBladeRegistry/index.ts +6 -5
- package/core/composables/useBreadcrumbs/index.ts +4 -1
- package/core/composables/useErrorHandler/index.ts +4 -1
- package/core/composables/useFunctions/debounce.ts +0 -1
- package/core/composables/useFunctions/delay.ts +0 -1
- package/core/composables/useFunctions/index.ts +0 -1
- package/core/composables/useFunctions/once.ts +0 -1
- package/core/composables/useFunctions/sleep.ts +0 -1
- package/core/composables/useFunctions/throttle.ts +0 -1
- package/core/composables/useGlobalSearch/index.ts +3 -3
- package/core/composables/useMenuService/index.ts +5 -2
- package/core/composables/useNotifications/index.ts +5 -2
- package/core/composables/useTheme/index.ts +4 -1
- package/core/composables/useUser/index.ts +189 -20
- package/core/composables/useWidgets/index.ts +5 -2
- package/core/constants/defaults.ts +76 -0
- package/core/constants/index.ts +2 -0
- package/core/constants/ui.ts +68 -0
- package/core/interceptors/index.ts +5 -2
- package/core/plugins/ai-agent/README.md +336 -0
- package/core/plugins/ai-agent/components/VcAiAgentPanel.vue +125 -0
- package/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue +182 -0
- package/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue +77 -0
- package/core/plugins/ai-agent/components/index.ts +1 -0
- package/core/plugins/ai-agent/composables/index.ts +4 -0
- package/core/plugins/ai-agent/composables/useAiAgent.ts +231 -0
- package/core/plugins/ai-agent/composables/useAiAgentContext.ts +280 -0
- package/core/plugins/ai-agent/constants.ts +89 -0
- package/core/plugins/ai-agent/index.ts +91 -0
- package/core/plugins/ai-agent/services/ai-agent-service.ts +598 -0
- package/core/plugins/ai-agent/types.ts +310 -0
- package/core/plugins/modularity/index.ts +8 -6
- package/core/plugins/modularity/loader.ts +36 -33
- package/core/plugins/signalR/index.ts +6 -3
- package/core/services/app-bar-menu-service.ts +4 -1
- package/core/services/dashboard-service.ts +4 -1
- package/core/services/index.ts +2 -0
- package/core/services/menu-service.ts +4 -1
- package/core/services/settings-menu-service.ts +4 -1
- package/core/services/toolbar-service.ts +18 -3
- package/core/services/widget-service.ts +7 -4
- package/core/types/index.ts +3 -0
- package/core/types/services.ts +194 -0
- package/core/utilities/errorTypes.ts +126 -0
- package/core/utilities/index.ts +2 -0
- package/core/utilities/logger.ts +120 -0
- package/dist/core/composables/useAssets/index.d.ts.map +1 -1
- package/dist/core/composables/useAsync/index.d.ts.map +1 -1
- package/dist/core/composables/useBladeRegistry/index.d.ts.map +1 -1
- package/dist/core/composables/useBreadcrumbs/index.d.ts.map +1 -1
- package/dist/core/composables/useErrorHandler/index.d.ts.map +1 -1
- package/dist/core/composables/useFunctions/debounce.d.ts.map +1 -1
- package/dist/core/composables/useFunctions/delay.d.ts.map +1 -1
- package/dist/core/composables/useFunctions/index.d.ts.map +1 -1
- package/dist/core/composables/useFunctions/once.d.ts.map +1 -1
- package/dist/core/composables/useFunctions/sleep.d.ts.map +1 -1
- package/dist/core/composables/useFunctions/throttle.d.ts.map +1 -1
- package/dist/core/composables/useGlobalSearch/index.d.ts.map +1 -1
- package/dist/core/composables/useMenuService/index.d.ts.map +1 -1
- package/dist/core/composables/useNotifications/index.d.ts.map +1 -1
- package/dist/core/composables/useTheme/index.d.ts.map +1 -1
- package/dist/core/composables/useUser/index.d.ts +8 -0
- package/dist/core/composables/useUser/index.d.ts.map +1 -1
- package/dist/core/composables/useWidgets/index.d.ts.map +1 -1
- package/dist/core/constants/defaults.d.ts +63 -0
- package/dist/core/constants/defaults.d.ts.map +1 -0
- package/dist/core/constants/index.d.ts +2 -0
- package/dist/core/constants/index.d.ts.map +1 -1
- package/dist/core/constants/ui.d.ts +50 -0
- package/dist/core/constants/ui.d.ts.map +1 -0
- package/dist/core/interceptors/index.d.ts.map +1 -1
- package/dist/core/plugins/ai-agent/components/VcAiAgentPanel.vue.d.ts +3 -0
- package/dist/core/plugins/ai-agent/components/VcAiAgentPanel.vue.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue.d.ts +15 -0
- package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue.d.ts +10 -0
- package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/components/index.d.ts +2 -0
- package/dist/core/plugins/ai-agent/components/index.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/composables/index.d.ts +4 -0
- package/dist/core/plugins/ai-agent/composables/index.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/composables/useAiAgent.d.ts +95 -0
- package/dist/core/plugins/ai-agent/composables/useAiAgent.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/composables/useAiAgentContext.d.ts +55 -0
- package/dist/core/plugins/ai-agent/composables/useAiAgentContext.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/constants.d.ts +47 -0
- package/dist/core/plugins/ai-agent/constants.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/index.d.ts +48 -0
- package/dist/core/plugins/ai-agent/index.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/services/ai-agent-service.d.ts +45 -0
- package/dist/core/plugins/ai-agent/services/ai-agent-service.d.ts.map +1 -0
- package/dist/core/plugins/ai-agent/types.d.ts +258 -0
- package/dist/core/plugins/ai-agent/types.d.ts.map +1 -0
- package/dist/core/plugins/modularity/index.d.ts.map +1 -1
- package/dist/core/plugins/modularity/loader.d.ts.map +1 -1
- package/dist/core/plugins/signalR/index.d.ts.map +1 -1
- package/dist/core/services/app-bar-menu-service.d.ts.map +1 -1
- package/dist/core/services/dashboard-service.d.ts.map +1 -1
- package/dist/core/services/menu-service.d.ts.map +1 -1
- package/dist/core/services/settings-menu-service.d.ts.map +1 -1
- package/dist/core/services/toolbar-service.d.ts.map +1 -1
- package/dist/core/services/widget-service.d.ts.map +1 -1
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/services.d.ts +169 -0
- package/dist/core/types/services.d.ts.map +1 -0
- package/dist/core/utilities/errorTypes.d.ts +61 -0
- package/dist/core/utilities/errorTypes.d.ts.map +1 -0
- package/dist/core/utilities/index.d.ts +2 -0
- package/dist/core/utilities/index.d.ts.map +1 -1
- package/dist/core/utilities/logger.d.ts +259 -0
- package/dist/core/utilities/logger.d.ts.map +1 -0
- package/dist/framework.js +9623 -8417
- package/dist/index.css +1 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/injection-keys.d.ts +21 -6
- package/dist/injection-keys.d.ts.map +1 -1
- package/dist/shared/components/app-switcher/composables/useAppSwitcher/index.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/composables/useLayoutPersistence.d.ts.map +1 -1
- package/dist/shared/components/notifications/composables/useContainer/index.d.ts.map +1 -1
- package/dist/shared/components/notifications/composables/useInstance/index.d.ts.map +1 -1
- package/dist/shared/components/notifications/core/notification.d.ts.map +1 -1
- package/dist/shared/components/popup-handler/components/vc-popup-container/vc-popup-container.vue.d.ts.map +1 -1
- package/dist/shared/components/sign-in/useExternalProvider.d.ts.map +1 -1
- package/dist/shared/composables/index.d.ts +1 -0
- package/dist/shared/composables/index.d.ts.map +1 -1
- package/dist/shared/composables/useExternalWidgets.d.ts.map +1 -1
- package/dist/shared/composables/useMenuExpanded.d.ts.map +1 -1
- package/dist/shared/composables/useTableSelection.d.ts +57 -0
- package/dist/shared/composables/useTableSelection.d.ts.map +1 -0
- package/dist/shared/composables/useTableSort.d.ts.map +1 -1
- package/dist/shared/modules/assets-manager/components/assets-manager/assets-manager.vue.d.ts.map +1 -1
- package/dist/shared/pages/LoginPage/components/login/Login.vue.d.ts.map +1 -1
- package/dist/shared/utilities/colorUtils.d.ts +0 -6
- package/dist/shared/utilities/colorUtils.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/atoms/vc-banner/vc-banner.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts +0 -15
- package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-container/vc-container.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-image/vc-image.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-link/vc-link.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-loading/vc-loading.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts +0 -5
- package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-tooltip/vc-tooltip.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-video/vc-video.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-widget/vc-widget.vue.d.ts.map +1 -1
- package/dist/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue.d.ts.map +1 -1
- package/dist/ui/components/molecules/vc-input/vc-input.vue.d.ts.map +1 -1
- package/dist/ui/components/molecules/vc-pagination/vc-pagination.vue.d.ts.map +1 -1
- package/dist/ui/components/molecules/vc-toast/vc-toast.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-login-form/vc-login-form.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/composables/useTableColumnResize.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/composables/useTableRowReorder.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/composables/useTableSelection.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/composables/useTableState.d.ts.map +1 -1
- package/dist/{vendor-lodash-es-BqkGj3Jl.js → vendor-lodash-es-SgOIjJF8.js} +2 -0
- package/package.json +5 -5
- package/shared/components/app-switcher/composables/useAppSwitcher/index.ts +4 -1
- package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +67 -4
- package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +13 -10
- package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.ts +7 -4
- package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.ts +4 -1
- package/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.ts +4 -1
- package/shared/components/change-password/change-password.vue +1 -1
- package/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.ts +14 -5
- package/shared/components/draggable-dashboard/composables/useLayoutPersistence.ts +5 -2
- package/shared/components/index.ts +2 -0
- package/shared/components/notifications/composables/useContainer/index.ts +8 -6
- package/shared/components/notifications/composables/useInstance/index.ts +4 -1
- package/shared/components/notifications/core/notification.ts +10 -7
- package/shared/components/popup-handler/components/vc-popup-container/vc-popup-container.vue +20 -1
- package/shared/components/sign-in/useExternalProvider.ts +6 -4
- package/shared/composables/index.ts +1 -0
- package/shared/composables/useExternalWidgets.ts +7 -4
- package/shared/composables/useMenuExpanded.ts +15 -1
- package/shared/composables/useTableSelection.ts +151 -0
- package/shared/composables/useTableSort.ts +4 -4
- package/shared/modules/assets-manager/components/assets-manager/assets-manager.vue +6 -3
- package/shared/pages/LoginPage/components/login/Login.vue +4 -1
- package/shared/utilities/colorUtils.ts +5 -12
- package/ui/components/atoms/vc-banner/vc-banner.vue +4 -1
- package/ui/components/atoms/vc-button/vc-button.vue +2 -25
- package/ui/components/atoms/vc-container/vc-container.vue +12 -3
- package/ui/components/atoms/vc-icon/vc-icon.vue +0 -10
- package/ui/components/atoms/vc-icon/vc-lucide-icon.vue +5 -2
- package/ui/components/atoms/vc-image/vc-image.vue +4 -1
- package/ui/components/atoms/vc-link/vc-link.vue +59 -54
- package/ui/components/atoms/vc-loading/vc-loading.vue +4 -0
- package/ui/components/atoms/vc-status/vc-status.vue +0 -5
- package/ui/components/atoms/vc-status-icon/vc-status-icon.vue +4 -4
- package/ui/components/atoms/vc-tooltip/vc-tooltip.vue +8 -1
- package/ui/components/atoms/vc-video/vc-video.vue +4 -2
- package/ui/components/atoms/vc-widget/vc-widget.vue +4 -1
- package/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue +7 -2
- package/ui/components/molecules/vc-input/vc-input.vue +0 -1
- package/ui/components/molecules/vc-pagination/vc-pagination.vue +6 -1
- package/ui/components/molecules/vc-rating/vc-rating.vue +1 -1
- package/ui/components/molecules/vc-textarea/vc-textarea.vue +1 -1
- package/ui/components/molecules/vc-toast/vc-toast.vue +11 -1
- package/ui/components/organisms/vc-app/vc-app.vue +22 -3
- package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue +4 -1
- package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/vc-blade-toolbar.vue +14 -14
- package/ui/components/organisms/vc-blade/vc-blade.vue +3 -1
- package/ui/components/organisms/vc-login-form/vc-login-form.vue +3 -1
- package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +34 -2
- package/ui/components/organisms/vc-table/composables/useTableActions.ts +7 -10
- package/ui/components/organisms/vc-table/composables/useTableColumnResize.ts +4 -1
- package/ui/components/organisms/vc-table/composables/useTableRowReorder.ts +5 -2
- package/ui/components/organisms/vc-table/composables/useTableSelection.ts +26 -18
- package/ui/components/organisms/vc-table/composables/useTableState.ts +4 -1
- package/core/services/global-search-service.ts +0 -36
- package/dist/core/services/global-search-service.d.ts +0 -10
- package/dist/core/services/global-search-service.d.ts.map +0 -1
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { computed, ref, ComputedRef } from "vue";
|
|
2
2
|
import * as _ from "lodash-es";
|
|
3
3
|
import { ICommonAsset } from "../../types";
|
|
4
|
+
import { createLogger } from "../../utilities";
|
|
5
|
+
|
|
6
|
+
const logger = createLogger("use-assets");
|
|
7
|
+
|
|
8
|
+
/** Maximum number of concurrent uploads */
|
|
9
|
+
const MAX_CONCURRENT_UPLOADS = 4;
|
|
4
10
|
|
|
5
11
|
export interface IUseAssets {
|
|
6
12
|
upload: (files: FileList, uploadPath: string, startingSortOrder?: number) => Promise<ICommonAsset[]>;
|
|
@@ -9,6 +15,60 @@ export interface IUseAssets {
|
|
|
9
15
|
loading: ComputedRef<boolean>;
|
|
10
16
|
}
|
|
11
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Uploads a single file and returns the asset
|
|
20
|
+
*/
|
|
21
|
+
async function uploadSingleFile(
|
|
22
|
+
file: File,
|
|
23
|
+
uploadPath: string,
|
|
24
|
+
index: number,
|
|
25
|
+
startingSortOrder?: number,
|
|
26
|
+
): Promise<ICommonAsset | null> {
|
|
27
|
+
const formData = new FormData();
|
|
28
|
+
formData.append("file", file);
|
|
29
|
+
|
|
30
|
+
const result = await fetch(`/api/assets?folderUrl=/${uploadPath}`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
body: formData,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const response = await result.json();
|
|
36
|
+
|
|
37
|
+
if (response?.length) {
|
|
38
|
+
const uploadedFile = response[0];
|
|
39
|
+
uploadedFile.createdDate = new Date();
|
|
40
|
+
uploadedFile.sortOrder = startingSortOrder !== undefined && startingSortOrder >= 0 ? startingSortOrder + index + 1 : 0;
|
|
41
|
+
uploadedFile.url = uploadedFile.url ? decodeURI(uploadedFile.url) : "";
|
|
42
|
+
|
|
43
|
+
if ("size" in uploadedFile) {
|
|
44
|
+
uploadedFile.size = file.size;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return uploadedFile;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Processes items in batches with concurrency limit
|
|
55
|
+
*/
|
|
56
|
+
async function processBatched<T, R>(
|
|
57
|
+
items: T[],
|
|
58
|
+
processor: (item: T, index: number) => Promise<R>,
|
|
59
|
+
concurrency: number,
|
|
60
|
+
): Promise<R[]> {
|
|
61
|
+
const results: R[] = [];
|
|
62
|
+
|
|
63
|
+
for (let i = 0; i < items.length; i += concurrency) {
|
|
64
|
+
const batch = items.slice(i, i + concurrency);
|
|
65
|
+
const batchResults = await Promise.all(batch.map((item, batchIndex) => processor(item, i + batchIndex)));
|
|
66
|
+
results.push(...batchResults);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
|
|
12
72
|
export function useAssets(): IUseAssets {
|
|
13
73
|
const loading = ref(false);
|
|
14
74
|
|
|
@@ -16,35 +76,19 @@ export function useAssets(): IUseAssets {
|
|
|
16
76
|
try {
|
|
17
77
|
loading.value = true;
|
|
18
78
|
|
|
19
|
-
const
|
|
20
|
-
for (let i = 0; i < files.length; i++) {
|
|
21
|
-
const formData = new FormData();
|
|
22
|
-
formData.append("file", files[i]);
|
|
23
|
-
|
|
24
|
-
const result = await fetch(`/api/assets?folderUrl=/${uploadPath}`, {
|
|
25
|
-
method: "POST",
|
|
26
|
-
body: formData,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const response = await result.json();
|
|
79
|
+
const fileArray = Array.from(files);
|
|
30
80
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if ("size" in file) {
|
|
38
|
-
file.size = files[i].size;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
uploadedAssets.value.push(file);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
81
|
+
// Upload files in parallel batches
|
|
82
|
+
const uploadResults = await processBatched(
|
|
83
|
+
fileArray,
|
|
84
|
+
(file, index) => uploadSingleFile(file, uploadPath, index, startingSortOrder),
|
|
85
|
+
MAX_CONCURRENT_UPLOADS,
|
|
86
|
+
);
|
|
44
87
|
|
|
45
|
-
return
|
|
88
|
+
// Filter out null results and return successful uploads
|
|
89
|
+
return uploadResults.filter((asset): asset is ICommonAsset => asset !== null);
|
|
46
90
|
} catch (error) {
|
|
47
|
-
|
|
91
|
+
logger.error("Upload failed:", error);
|
|
48
92
|
throw error;
|
|
49
93
|
} finally {
|
|
50
94
|
loading.value = false;
|
|
@@ -63,7 +107,7 @@ export function useAssets(): IUseAssets {
|
|
|
63
107
|
|
|
64
108
|
return updatedAssetArr;
|
|
65
109
|
} catch (error) {
|
|
66
|
-
|
|
110
|
+
logger.error("Remove failed:", error);
|
|
67
111
|
throw error;
|
|
68
112
|
} finally {
|
|
69
113
|
loading.value = false;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { readonly, ref } from "vue";
|
|
3
3
|
import { HasLoading } from "../useLoading";
|
|
4
|
+
import { createLogger } from "../../utilities";
|
|
5
|
+
|
|
6
|
+
const logger = createLogger("use-async");
|
|
4
7
|
|
|
5
8
|
export type AsyncAction<Payload = void, Result = void> = (payload?: Payload, ...rest: any[]) => Promise<Result>;
|
|
6
9
|
|
|
@@ -18,7 +21,7 @@ export function useAsync<Payload = void, Result = void>(
|
|
|
18
21
|
try {
|
|
19
22
|
return await innerAction(payload, ...rest);
|
|
20
23
|
} catch (e) {
|
|
21
|
-
|
|
24
|
+
logger.error("Async action failed:", e);
|
|
22
25
|
throw e;
|
|
23
26
|
} finally {
|
|
24
27
|
loading.value = false;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { App, inject, shallowRef, computed, ComputedRef, readonly as vueReadonly } from "vue";
|
|
2
2
|
import { BladeInstanceConstructor } from "../../../shared/components/blade-navigation/types";
|
|
3
|
+
import { createLogger } from "../../utilities";
|
|
4
|
+
|
|
5
|
+
const logger = createLogger("blade-registry");
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Interface for blade registration data
|
|
@@ -81,16 +84,14 @@ export function createBladeRegistry(app: App): IBladeRegistryInstance {
|
|
|
81
84
|
const newMap = new Map(registeredBladesInternal.value);
|
|
82
85
|
|
|
83
86
|
if (newMap.has(name)) {
|
|
84
|
-
|
|
87
|
+
logger.warn(`Blade '${name}' is already registered. It will be overwritten.`);
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
// Register component globally if not already registered or different
|
|
88
91
|
const existingGlobalComponent = app.component(name);
|
|
89
92
|
if (!existingGlobalComponent || existingGlobalComponent !== registrationData.component) {
|
|
90
93
|
if (existingGlobalComponent && existingGlobalComponent !== registrationData.component) {
|
|
91
|
-
|
|
92
|
-
`BladeRegistry: Global component '${name}' already exists and is different. Overwriting with new blade component.`,
|
|
93
|
-
);
|
|
94
|
+
logger.warn(`Global component '${name}' already exists and is different. Overwriting with new blade component.`);
|
|
94
95
|
}
|
|
95
96
|
app.component(name, registrationData.component);
|
|
96
97
|
}
|
|
@@ -137,7 +138,7 @@ export function createBladeRegistry(app: App): IBladeRegistryInstance {
|
|
|
137
138
|
return globalComponent;
|
|
138
139
|
}
|
|
139
140
|
} catch (error) {
|
|
140
|
-
|
|
141
|
+
logger.warn(`Error accessing global component '${name}':`, error);
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
return undefined;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Breadcrumbs } from "./../../../ui/types/index";
|
|
2
2
|
import { ComputedRef, computed, reactive, toValue } from "vue";
|
|
3
3
|
import * as _ from "lodash-es";
|
|
4
|
+
import { createLogger } from "../../utilities";
|
|
5
|
+
|
|
6
|
+
const logger = createLogger("use-breadcrumbs");
|
|
4
7
|
|
|
5
8
|
interface HistoryRecord {
|
|
6
9
|
records: Breadcrumbs[];
|
|
@@ -45,7 +48,7 @@ export function useBreadcrumbs() {
|
|
|
45
48
|
removeNext(id);
|
|
46
49
|
}
|
|
47
50
|
} catch (e) {
|
|
48
|
-
|
|
51
|
+
logger.error("Breadcrumb click handler failed:", e);
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
},
|
|
@@ -2,6 +2,9 @@ import { onErrorCaptured, getCurrentInstance, ref, Ref, nextTick } from "vue";
|
|
|
2
2
|
import { useAppInsights } from "..";
|
|
3
3
|
import { useUserManagement } from "../useUserManagement";
|
|
4
4
|
import { DisplayableError, parseError } from "../../utilities/error";
|
|
5
|
+
import { createLogger } from "../../utilities";
|
|
6
|
+
|
|
7
|
+
const logger = createLogger("use-error-handler");
|
|
5
8
|
|
|
6
9
|
interface IUseErrorHandler {
|
|
7
10
|
error: Ref<DisplayableError | null>;
|
|
@@ -51,7 +54,7 @@ export function useErrorHandler(capture?: boolean): IUseErrorHandler {
|
|
|
51
54
|
});
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
logger.error("Captured Error:", capturedError.originalError);
|
|
55
58
|
|
|
56
59
|
if (instance) {
|
|
57
60
|
instance.emit("error", capturedError);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
export default function debounce(func: (...args: any[]) => void, delay: number): (...args: unknown[]) => void {
|
|
3
|
-
console.debug(`[@vc-shell/framework#useFunctions:debounce] - Entry point`);
|
|
4
3
|
let timer: number | null = null;
|
|
5
4
|
|
|
6
5
|
return function (...args: unknown[]): void {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const resultsMap = new WeakMap();
|
|
2
2
|
|
|
3
3
|
export default function once(func: (...args: unknown[]) => void): (...args: unknown[]) => unknown {
|
|
4
|
-
console.debug(`[@vc-shell/framework#useFunctions:once] - Entry point`);
|
|
5
4
|
return function (...args: unknown[]): unknown {
|
|
6
5
|
if (!resultsMap.has(func)) {
|
|
7
6
|
const result = func(...args);
|
|
@@ -2,17 +2,17 @@ import { inject, provide } from "vue";
|
|
|
2
2
|
import { GlobalSearchKey } from "../../../injection-keys";
|
|
3
3
|
import { GlobalSearchState, createGlobalSearchService } from "../../services/global-search-service";
|
|
4
4
|
|
|
5
|
-
export function provideGlobalSearch() {
|
|
5
|
+
export function provideGlobalSearch(): GlobalSearchState {
|
|
6
6
|
const state = createGlobalSearchService();
|
|
7
7
|
provide(GlobalSearchKey, state);
|
|
8
8
|
return state;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function useGlobalSearch() {
|
|
11
|
+
export function useGlobalSearch(): GlobalSearchState {
|
|
12
12
|
const state = inject<GlobalSearchState>(GlobalSearchKey);
|
|
13
13
|
|
|
14
14
|
if (!state) {
|
|
15
|
-
throw new Error("useGlobalSearch must be used within a component that has called
|
|
15
|
+
throw new Error("useGlobalSearch must be used within a component that has called provideGlobalSearch");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
return state;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { provide, inject, getCurrentInstance } from "vue";
|
|
2
2
|
import { MenuService, createMenuService, addMenuItem } from "../../services/menu-service";
|
|
3
3
|
import { MenuServiceKey } from "../../../injection-keys";
|
|
4
|
+
import { createLogger, InjectionError } from "../../utilities";
|
|
5
|
+
|
|
6
|
+
const logger = createLogger("use-menu-service");
|
|
4
7
|
|
|
5
8
|
export function provideMenuService(): MenuService {
|
|
6
9
|
const service = createMenuService();
|
|
@@ -11,8 +14,8 @@ export function provideMenuService(): MenuService {
|
|
|
11
14
|
export function useMenuService(): MenuService {
|
|
12
15
|
const service = inject(MenuServiceKey);
|
|
13
16
|
if (!service) {
|
|
14
|
-
|
|
15
|
-
throw new
|
|
17
|
+
logger.error("Menu service not found in current context. Injection chain:", getCurrentInstance());
|
|
18
|
+
throw new InjectionError("MenuService");
|
|
16
19
|
}
|
|
17
20
|
return service;
|
|
18
21
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { PushNotification, PushNotificationClient } from "./../../api/platform";
|
|
2
2
|
import { computed, ComputedRef, ref, onUnmounted } from "vue";
|
|
3
3
|
import * as _ from "lodash-es";
|
|
4
|
+
import { createLogger } from "../../utilities";
|
|
5
|
+
|
|
6
|
+
const logger = createLogger("use-notifications");
|
|
4
7
|
|
|
5
8
|
const notificationsClient = new PushNotificationClient();
|
|
6
9
|
|
|
@@ -64,7 +67,7 @@ export function useNotifications(notifyType?: string | string[]): INotifications
|
|
|
64
67
|
notifications.value = <PushNotification[]>JSON.parse(response).notifyEvents ?? [];
|
|
65
68
|
});
|
|
66
69
|
} catch (e) {
|
|
67
|
-
|
|
70
|
+
logger.error("loadFromHistory failed:", e);
|
|
68
71
|
throw e;
|
|
69
72
|
}
|
|
70
73
|
}
|
|
@@ -121,7 +124,7 @@ export function useNotifications(notifyType?: string | string[]): INotifications
|
|
|
121
124
|
});
|
|
122
125
|
await notificationsClient.markAllAsRead();
|
|
123
126
|
} catch (e) {
|
|
124
|
-
|
|
127
|
+
logger.error("markAllAsRead failed:", e);
|
|
125
128
|
throw e;
|
|
126
129
|
}
|
|
127
130
|
}
|
|
@@ -3,6 +3,9 @@ import { computed, watchEffect, ref, type Ref } from "vue";
|
|
|
3
3
|
import { useI18n } from "vue-i18n";
|
|
4
4
|
import * as _ from "lodash-es";
|
|
5
5
|
import { i18n } from "../../plugins/i18n";
|
|
6
|
+
import { createLogger } from "../../utilities";
|
|
7
|
+
|
|
8
|
+
const logger = createLogger("use-theme");
|
|
6
9
|
|
|
7
10
|
export interface ThemeDefinition {
|
|
8
11
|
key: string;
|
|
@@ -82,7 +85,7 @@ export const useTheme = (): IUseTheme => {
|
|
|
82
85
|
if (themeKeys.value.includes(themeKey)) {
|
|
83
86
|
state.value = themeKey;
|
|
84
87
|
} else {
|
|
85
|
-
|
|
88
|
+
logger.warn(`Attempted to set an unregistered theme: ${themeKey}`);
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -15,6 +15,18 @@ import {
|
|
|
15
15
|
import { RequestPasswordResult } from "./../../types";
|
|
16
16
|
import { createSharedComposable } from "@vueuse/core";
|
|
17
17
|
import { useExternalProvider } from "../../../shared/components/sign-in/useExternalProvider";
|
|
18
|
+
import { createLogger } from "../../utilities";
|
|
19
|
+
|
|
20
|
+
export interface TokenData {
|
|
21
|
+
token: string | null;
|
|
22
|
+
access_token: string | null;
|
|
23
|
+
refresh_token: string | null;
|
|
24
|
+
expires_at: number | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const AUTH_STORAGE_KEY = "vc_auth_data";
|
|
28
|
+
|
|
29
|
+
const logger = createLogger("use-user");
|
|
18
30
|
|
|
19
31
|
// Interface for the full internal API provided by _createInternalUserLogic
|
|
20
32
|
export interface IUserInternalAPI {
|
|
@@ -30,6 +42,7 @@ export interface IUserInternalAPI {
|
|
|
30
42
|
requestPasswordReset: (loginOrEmail: string) => Promise<RequestPasswordResult>;
|
|
31
43
|
changeUserPassword: (oldPassword: string, newPassword: string) => Promise<SecurityResult | undefined>;
|
|
32
44
|
getLoginType: () => Promise<LoginType[]>;
|
|
45
|
+
getAccessToken: () => Promise<string | null>;
|
|
33
46
|
isAuthenticated: ComputedRef<boolean>;
|
|
34
47
|
}
|
|
35
48
|
|
|
@@ -40,12 +53,89 @@ export interface IAppUserAPI {
|
|
|
40
53
|
isAdministrator: ComputedRef<boolean | undefined>;
|
|
41
54
|
loadUser: () => Promise<UserDetail>;
|
|
42
55
|
signOut: () => Promise<void>;
|
|
56
|
+
getAccessToken: () => Promise<string | null>;
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
const user: Ref<UserDetail | undefined> = ref();
|
|
46
60
|
|
|
61
|
+
function readAuthData(): TokenData | null {
|
|
62
|
+
try {
|
|
63
|
+
const stored = localStorage.getItem(AUTH_STORAGE_KEY);
|
|
64
|
+
if (stored) {
|
|
65
|
+
return JSON.parse(stored) as TokenData;
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
logger.error("Failed to read auth data from storage:", e);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function storeAuthData(data: TokenData): void {
|
|
74
|
+
try {
|
|
75
|
+
logger.debug("storeAuthData - Saving:", data);
|
|
76
|
+
localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(data));
|
|
77
|
+
logger.debug("storeAuthData - Saved successfully");
|
|
78
|
+
} catch (e) {
|
|
79
|
+
logger.error("Failed to store auth data:", e);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function clearAuthData(): void {
|
|
84
|
+
try {
|
|
85
|
+
localStorage.removeItem(AUTH_STORAGE_KEY);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
logger.error("Failed to clear auth data:", e);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Direct fetch to /connect/token endpoint
|
|
92
|
+
async function fetchToken(params: Record<string, string>): Promise<TokenData | null> {
|
|
93
|
+
try {
|
|
94
|
+
const body = new URLSearchParams(params).toString();
|
|
95
|
+
|
|
96
|
+
const response = await fetch("/connect/token", {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
100
|
+
},
|
|
101
|
+
body,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
const errorBody = await response.text();
|
|
106
|
+
logger.error("fetchToken - HTTP error:", response.status, response.statusText, errorBody);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const data = await response.json();
|
|
111
|
+
logger.debug("fetchToken - Response:", data);
|
|
112
|
+
|
|
113
|
+
const accessToken = data.access_token;
|
|
114
|
+
const refreshToken = data.refresh_token;
|
|
115
|
+
const expiresIn = data.expires_in;
|
|
116
|
+
|
|
117
|
+
if (data.error || !accessToken) {
|
|
118
|
+
logger.error("fetchToken - Error:", data.error_description || data.error || "No access token");
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const expiresAt = expiresIn ? Date.now() + expiresIn * 1000 : null;
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
token: accessToken,
|
|
126
|
+
access_token: accessToken,
|
|
127
|
+
refresh_token: refreshToken ?? null,
|
|
128
|
+
expires_at: expiresAt,
|
|
129
|
+
};
|
|
130
|
+
} catch (e) {
|
|
131
|
+
logger.error("fetchToken - Exception:", e);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
47
136
|
export function _createInternalUserLogic(): IUserInternalAPI {
|
|
48
137
|
const loading: Ref<boolean> = ref(false);
|
|
138
|
+
const authData: Ref<TokenData | null> = ref(null);
|
|
49
139
|
|
|
50
140
|
const { storage: externalSignInStorage, signOut: externalSignOut } = useExternalProvider();
|
|
51
141
|
|
|
@@ -83,25 +173,40 @@ export function _createInternalUserLogic(): IUserInternalAPI {
|
|
|
83
173
|
username: string,
|
|
84
174
|
password: string,
|
|
85
175
|
): Promise<SignInResult | { succeeded: boolean; error?: any; status?: number }> {
|
|
86
|
-
|
|
176
|
+
logger.debug("signIn - Entry point");
|
|
87
177
|
try {
|
|
88
178
|
loading.value = true;
|
|
179
|
+
|
|
180
|
+
// First do the standard login to set cookies/session
|
|
89
181
|
const result = await securityClient.login(new LoginRequest({ userName: username, password }));
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
182
|
+
logger.debug("signIn - Cookie login completed:", result);
|
|
183
|
+
|
|
184
|
+
// Then get OAuth token for API calls (direct fetch, bypasses API client)
|
|
185
|
+
// Request offline_access scope to get refresh_token for automatic token renewal
|
|
186
|
+
logger.debug("signIn - Requesting token...");
|
|
187
|
+
const tokenData = await fetchToken({
|
|
188
|
+
grant_type: "password",
|
|
189
|
+
username,
|
|
190
|
+
password,
|
|
191
|
+
scope: "offline_access",
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (tokenData) {
|
|
195
|
+
authData.value = tokenData;
|
|
196
|
+
storeAuthData(authData.value);
|
|
197
|
+
logger.debug("signIn - Token saved:", authData.value);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Load current user info
|
|
201
|
+
const userInfo = await securityClient.getCurrentUser();
|
|
202
|
+
if (userInfo) {
|
|
203
|
+
user.value = userInfo;
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
throw { succeeded: false };
|
|
102
208
|
} catch (e: any) {
|
|
103
|
-
|
|
104
|
-
console.log(e);
|
|
209
|
+
logger.error("signIn failed:", e);
|
|
105
210
|
return { succeeded: false, error: e.message, status: e.status };
|
|
106
211
|
} finally {
|
|
107
212
|
loading.value = false;
|
|
@@ -109,10 +214,14 @@ export function _createInternalUserLogic(): IUserInternalAPI {
|
|
|
109
214
|
}
|
|
110
215
|
|
|
111
216
|
async function signOut(): Promise<void> {
|
|
112
|
-
|
|
217
|
+
logger.debug("signOut - Entry point");
|
|
113
218
|
|
|
114
219
|
user.value = undefined;
|
|
115
220
|
|
|
221
|
+
// Clear stored auth data
|
|
222
|
+
clearAuthData();
|
|
223
|
+
authData.value = null;
|
|
224
|
+
|
|
116
225
|
if (externalSignInStorage.value?.providerType) {
|
|
117
226
|
await externalSignOut(externalSignInStorage.value.providerType);
|
|
118
227
|
} else {
|
|
@@ -121,14 +230,15 @@ export function _createInternalUserLogic(): IUserInternalAPI {
|
|
|
121
230
|
}
|
|
122
231
|
|
|
123
232
|
async function loadUser(): Promise<UserDetail> {
|
|
124
|
-
|
|
233
|
+
logger.debug("loadUser - Entry point");
|
|
125
234
|
|
|
126
235
|
try {
|
|
127
236
|
loading.value = true;
|
|
128
237
|
user.value = await securityClient.getCurrentUser();
|
|
129
|
-
|
|
238
|
+
await getAccessToken();
|
|
239
|
+
logger.debug("User details loaded:", user.value);
|
|
130
240
|
} catch (e: any) {
|
|
131
|
-
|
|
241
|
+
logger.error("loadUser failed:", e);
|
|
132
242
|
} finally {
|
|
133
243
|
loading.value = false;
|
|
134
244
|
}
|
|
@@ -174,13 +284,70 @@ export function _createInternalUserLogic(): IUserInternalAPI {
|
|
|
174
284
|
try {
|
|
175
285
|
result = await securityClient.getLoginTypes();
|
|
176
286
|
} catch (e) {
|
|
177
|
-
|
|
287
|
+
logger.error("getLoginType failed:", e);
|
|
178
288
|
throw e;
|
|
179
289
|
}
|
|
180
290
|
|
|
181
291
|
return result;
|
|
182
292
|
}
|
|
183
293
|
|
|
294
|
+
// Buffer time in ms - refresh token this much before actual expiration
|
|
295
|
+
const TOKEN_REFRESH_BUFFER_MS = 60 * 1000; // 60 seconds
|
|
296
|
+
|
|
297
|
+
async function getAccessToken(): Promise<string | null> {
|
|
298
|
+
logger.debug("getAccessToken - Entry point");
|
|
299
|
+
|
|
300
|
+
// Load auth data from storage if not yet loaded
|
|
301
|
+
if (!authData.value) {
|
|
302
|
+
authData.value = readAuthData();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// No auth data available
|
|
306
|
+
if (!authData.value) {
|
|
307
|
+
logger.debug("getAccessToken - No auth data available");
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Check if token is expired or about to expire (with buffer)
|
|
312
|
+
const now = Date.now();
|
|
313
|
+
const expiresAt = authData.value.expires_at;
|
|
314
|
+
const shouldRefresh = expiresAt ? now >= expiresAt - TOKEN_REFRESH_BUFFER_MS : false;
|
|
315
|
+
|
|
316
|
+
logger.debug("getAccessToken - Token status:", {
|
|
317
|
+
hasToken: !!authData.value.access_token,
|
|
318
|
+
expiresAt: expiresAt ? new Date(expiresAt).toISOString() : "not set",
|
|
319
|
+
now: new Date(now).toISOString(),
|
|
320
|
+
shouldRefresh,
|
|
321
|
+
hasRefreshToken: !!authData.value.refresh_token,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
if (shouldRefresh && authData.value.refresh_token) {
|
|
325
|
+
logger.debug("getAccessToken - Token expired or expiring soon, attempting refresh");
|
|
326
|
+
|
|
327
|
+
const tokenData = await fetchToken({
|
|
328
|
+
grant_type: "refresh_token",
|
|
329
|
+
refresh_token: authData.value.refresh_token,
|
|
330
|
+
scope: "offline_access",
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
if (tokenData) {
|
|
334
|
+
// Keep old refresh_token if new one not provided
|
|
335
|
+
tokenData.refresh_token = tokenData.refresh_token ?? authData.value.refresh_token;
|
|
336
|
+
authData.value = tokenData;
|
|
337
|
+
storeAuthData(authData.value);
|
|
338
|
+
logger.debug("getAccessToken - Token refreshed successfully, new expiry:", {
|
|
339
|
+
expiresAt: tokenData.expires_at ? new Date(tokenData.expires_at).toISOString() : "not set",
|
|
340
|
+
});
|
|
341
|
+
} else {
|
|
342
|
+
// Refresh failed - log error but return existing token (it might still work)
|
|
343
|
+
// Don't clear auth data - let the API call fail naturally if token is truly invalid
|
|
344
|
+
logger.warn("getAccessToken - Failed to refresh token, returning existing token");
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return authData.value?.access_token ?? authData.value?.token ?? null;
|
|
349
|
+
}
|
|
350
|
+
|
|
184
351
|
return {
|
|
185
352
|
user: computed(() => user.value),
|
|
186
353
|
loading: computed(() => loading.value),
|
|
@@ -195,6 +362,7 @@ export function _createInternalUserLogic(): IUserInternalAPI {
|
|
|
195
362
|
requestPasswordReset,
|
|
196
363
|
changeUserPassword,
|
|
197
364
|
getLoginType,
|
|
365
|
+
getAccessToken,
|
|
198
366
|
};
|
|
199
367
|
}
|
|
200
368
|
|
|
@@ -207,5 +375,6 @@ export const useUser = createSharedComposable((): IAppUserAPI => {
|
|
|
207
375
|
isAdministrator: internals.isAdministrator,
|
|
208
376
|
loadUser: internals.loadUser,
|
|
209
377
|
signOut: internals.signOut,
|
|
378
|
+
getAccessToken: internals.getAccessToken,
|
|
210
379
|
};
|
|
211
380
|
});
|