Skip to content

Commit e1569f5

Browse files
authored
Merge pull request #5759 from cloudforet-io/feature-project-dashboards
feat(project-dashboard): create project-dashboard page with dashboard-shared
2 parents 289df54 + 1d966e6 commit e1569f5

File tree

70 files changed

+1667
-1174
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1667
-1174
lines changed

Diff for: apps/web/src/api-clients/dashboard/private-dashboard/schema/api-verbs/list.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export interface PrivateDashboardListParameters {
55
query?: Query;
66
dashboard_id?: string;
77
name?: string;
8+
folder_id?: string;
89
}

Diff for: apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/list.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export interface PublicDashboardListParameters {
88
workspace_id?: string;
99
project_id?: string;
1010
project_group_id?: string;
11+
folder_id?: string;
1112
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { ComputedRef } from 'vue';
2+
import { computed } from 'vue';
3+
4+
import {
5+
useMutation, useQueryClient,
6+
} from '@tanstack/vue-query';
7+
8+
import type { DashboardChangeFolderParams, DashboardModel } from '@/api-clients/dashboard/_types/dashboard-type';
9+
import { usePrivateDashboardApi } from '@/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api';
10+
import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
11+
import { useServiceQueryKey } from '@/query/query-key/use-service-query-key';
12+
13+
interface UseDashboardChangeFolderActionOptions {
14+
dashboardId: ComputedRef<string|undefined>;
15+
onSuccess?: (data: DashboardModel, variables: DashboardChangeFolderParams) => void|Promise<void>;
16+
onError?: (error: Error, variables: DashboardChangeFolderParams) => void|Promise<void>;
17+
onSettled?: (data: DashboardModel|undefined, error: Error|null, variables: DashboardChangeFolderParams) => void|Promise<void>;
18+
}
19+
20+
export const useDashboardChangeFolderAction = (options: UseDashboardChangeFolderActionOptions) => {
21+
const { publicDashboardAPI } = usePublicDashboardApi();
22+
const { privateDashboardAPI } = usePrivateDashboardApi();
23+
const queryClient = useQueryClient();
24+
const { withSuffix: publicDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'public-dashboard', 'get');
25+
const { withSuffix: privateDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'private-dashboard', 'get');
26+
27+
const {
28+
dashboardId, onSuccess, onError, onSettled,
29+
} = options;
30+
31+
const isPrivate = computed(() => dashboardId.value?.startsWith('private'));
32+
33+
const changeFolderFn = (params: DashboardChangeFolderParams): Promise<DashboardModel> => {
34+
if (!dashboardId.value) throw new Error('Dashboard ID is not provided');
35+
const fetcher = isPrivate.value ? privateDashboardAPI.changeFolder : publicDashboardAPI.changeFolder;
36+
return fetcher(params);
37+
};
38+
39+
return useMutation({
40+
mutationFn: changeFolderFn,
41+
onSuccess: async (data, variables) => {
42+
const _dashboardId = variables.dashboard_id;
43+
const _isPrivate = _dashboardId.startsWith('private');
44+
const dashboardListQueryKey = _isPrivate ? privateDashboardGetQueryKey(_dashboardId) : publicDashboardGetQueryKey(_dashboardId);
45+
queryClient.invalidateQueries({ queryKey: dashboardListQueryKey });
46+
if (onSuccess) await onSuccess(data, variables);
47+
},
48+
onError: (error, variables) => {
49+
if (onError) onError(error, variables);
50+
},
51+
onSettled: (data, error, variables) => {
52+
if (onSettled) onSettled(data, error, variables);
53+
},
54+
});
55+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import type { ComputedRef } from 'vue';
2+
3+
import { useMutation } from '@tanstack/vue-query';
4+
5+
import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list';
6+
import { RESOURCE_GROUP } from '@/api-clients/_common/schema/constant';
7+
import type { DashboardCreateParams, DashboardModel } from '@/api-clients/dashboard/_types/dashboard-type';
8+
import type { WidgetModel } from '@/api-clients/dashboard/_types/widget-type';
9+
import { usePrivateDashboardApi } from '@/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api';
10+
import type { PrivateDashboardCreateParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/create';
11+
import { usePrivateWidgetApi } from '@/api-clients/dashboard/private-widget/composables/use-private-widget-api';
12+
import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
13+
import type { PublicDashboardCreateParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/create';
14+
import { usePublicWidgetApi } from '@/api-clients/dashboard/public-widget/composables/use-public-widget-api';
15+
16+
import { useAllReferenceStore } from '@/store/reference/all-reference-store';
17+
import { useUserStore } from '@/store/user/user-store';
18+
19+
import { useDashboardRouteContext } from '@/services/dashboard-shared/core/composables/use-dashboard-route-context';
20+
import { getSharedDashboardLayouts } from '@/services/dashboard-shared/core/helpers/dashboard-share-helper';
21+
22+
23+
interface UseDashboardCloneActionOptions {
24+
dashboardId: ComputedRef<string|undefined>;
25+
isPrivate?: ComputedRef<boolean>;
26+
onSuccess?: (data: DashboardModel, variables: DashboardCreateParams) => void|Promise<void>;
27+
onError?: (error: Error, variables: DashboardCreateParams) => void|Promise<void>;
28+
onSettled?: (data: DashboardModel|undefined, error: Error|null, variables: DashboardCreateParams) => void|Promise<void>;
29+
}
30+
31+
export const useDashboardCloneAction = (options: UseDashboardCloneActionOptions) => {
32+
const { publicDashboardAPI } = usePublicDashboardApi();
33+
const { privateDashboardAPI } = usePrivateDashboardApi();
34+
const { privateWidgetAPI } = usePrivateWidgetApi();
35+
const { publicWidgetAPI } = usePublicWidgetApi();
36+
const allReferenceStore = useAllReferenceStore();
37+
const userStore = useUserStore();
38+
const {
39+
entryPoint,
40+
} = useDashboardRouteContext();
41+
42+
const {
43+
dashboardId, isPrivate, onSuccess, onError, onSettled,
44+
} = options;
45+
46+
47+
const getDashboardFn = async (): Promise<DashboardModel> => {
48+
if (!dashboardId.value) throw new Error('Dashboard id not found');
49+
try {
50+
if (dashboardId.value.startsWith('private')) {
51+
return privateDashboardAPI.get({ dashboard_id: dashboardId.value });
52+
}
53+
return publicDashboardAPI.get({ dashboard_id: dashboardId.value });
54+
} catch (error) {
55+
throw new Error('Dashboard not found');
56+
}
57+
};
58+
59+
const listWidgetFn = async (): Promise<ListResponse<WidgetModel>> => {
60+
if (!dashboardId.value) throw new Error('Dashboard id not found');
61+
try {
62+
if (dashboardId.value.startsWith('private')) {
63+
return privateWidgetAPI.list({ dashboard_id: dashboardId.value });
64+
}
65+
return publicWidgetAPI.list({ dashboard_id: dashboardId.value });
66+
} catch (error) {
67+
throw new Error('Widget list not found');
68+
}
69+
};
70+
71+
72+
const cloneDashboardFn = async (params: DashboardCreateParams): Promise<DashboardModel> => {
73+
if (!dashboardId.value) throw new Error('Dashboard id not found');
74+
75+
const dashboard = await getDashboardFn();
76+
const widgetList = await listWidgetFn();
77+
78+
const _sharedLayouts = await getSharedDashboardLayouts(dashboard.layouts, widgetList.results || [], allReferenceStore.getters.costDataSource);
79+
80+
const _sharedDashboard: DashboardCreateParams = {
81+
name: params.name,
82+
layouts: _sharedLayouts,
83+
options: dashboard.options || {},
84+
labels: dashboard.labels || [],
85+
tags: { created_by: userStore.state.userId },
86+
vars: dashboard.vars,
87+
vars_schema: dashboard.vars_schema,
88+
};
89+
if (entryPoint.value === 'ADMIN') {
90+
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.DOMAIN;
91+
} else if (entryPoint.value === 'WORKSPACE') {
92+
if (!isPrivate?.value) {
93+
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.WORKSPACE;
94+
}
95+
} else if (entryPoint.value === 'PROJECT') {
96+
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.PROJECT;
97+
}
98+
99+
100+
if (isPrivate?.value) {
101+
return privateDashboardAPI.create(_sharedDashboard as PrivateDashboardCreateParameters);
102+
}
103+
return publicDashboardAPI.create(_sharedDashboard as PublicDashboardCreateParameters);
104+
};
105+
106+
return useMutation({
107+
mutationFn: cloneDashboardFn,
108+
onSuccess: async (data, variables) => {
109+
if (onSuccess) await onSuccess(data, variables);
110+
},
111+
onError: (error, variables) => {
112+
if (onError) onError(error, variables);
113+
},
114+
onSettled: (data, error, variables) => {
115+
if (onSettled) onSettled(data, error, variables);
116+
},
117+
});
118+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { ComputedRef } from 'vue';
2+
import { computed } from 'vue';
3+
4+
import {
5+
useMutation, useQueryClient,
6+
} from '@tanstack/vue-query';
7+
8+
import type { DashboardDeleteParams } from '@/api-clients/dashboard/_types/dashboard-type';
9+
import { usePrivateDashboardApi } from '@/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api';
10+
import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
11+
import { useServiceQueryKey } from '@/query/query-key/use-service-query-key';
12+
13+
interface UseDashboardDeleteActionOptions {
14+
dashboardId: ComputedRef<string|undefined>;
15+
onSuccess?: (data: unknown, variables: DashboardDeleteParams) => void|Promise<void>;
16+
onError?: (error: Error, variables: DashboardDeleteParams) => void|Promise<void>;
17+
onSettled?: (data: unknown|undefined, error: Error|null, variables: DashboardDeleteParams) => void|Promise<void>;
18+
}
19+
20+
export const useDashboardDeleteAction = (options: UseDashboardDeleteActionOptions) => {
21+
const { publicDashboardAPI } = usePublicDashboardApi();
22+
const { privateDashboardAPI } = usePrivateDashboardApi();
23+
const queryClient = useQueryClient();
24+
const { withSuffix: publicDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'public-dashboard', 'get');
25+
const { withSuffix: privateDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'private-dashboard', 'get');
26+
27+
const {
28+
dashboardId, onSuccess, onError, onSettled,
29+
} = options;
30+
31+
const isPrivate = computed(() => dashboardId.value?.startsWith('private'));
32+
33+
const deleteDashboardFn = (params: DashboardDeleteParams) => {
34+
if (!dashboardId.value) throw new Error('Dashboard ID is not provided');
35+
const fetcher = isPrivate.value ? privateDashboardAPI.delete : publicDashboardAPI.delete;
36+
return fetcher(params);
37+
};
38+
39+
return useMutation({
40+
mutationFn: deleteDashboardFn,
41+
onSuccess: async (data, variables) => {
42+
const _dashboardId = variables.dashboard_id;
43+
const _isPrivate = _dashboardId.startsWith('private');
44+
const dashboardListQueryKey = _isPrivate ? privateDashboardGetQueryKey(_dashboardId) : publicDashboardGetQueryKey(_dashboardId);
45+
queryClient.invalidateQueries({ queryKey: dashboardListQueryKey });
46+
if (onSuccess) await onSuccess(data, variables);
47+
},
48+
onError: (error, variables) => {
49+
if (onError) onError(error, variables);
50+
},
51+
onSettled: (data, error, variables) => {
52+
if (onSettled) onSettled(data, error, variables);
53+
},
54+
});
55+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type { ComputedRef } from 'vue';
2+
3+
import {
4+
useMutation, useQueryClient,
5+
} from '@tanstack/vue-query';
6+
7+
import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
8+
import { usePublicFolderApi } from '@/api-clients/dashboard/public-folder/composables/use-public-folder-api';
9+
import type { PublicFolderShareParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/share';
10+
import type { PublicFolderUnshareParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/unshare';
11+
import type { PublicFolderModel } from '@/api-clients/dashboard/public-folder/schema/model';
12+
import { useServiceQueryKey } from '@/query/query-key/use-service-query-key';
13+
14+
interface UseDashboardFolderShareActionOptions {
15+
folderId: ComputedRef<string|undefined>;
16+
isShared: ComputedRef<boolean>;
17+
onSuccess?: (data: PublicFolderModel, variables: PublicFolderShareParameters|PublicFolderUnshareParameters) => void|Promise<void>;
18+
onError?: (error: Error, variables: PublicFolderShareParameters|PublicFolderUnshareParameters) => void|Promise<void>;
19+
onSettled?: (data: PublicFolderModel|undefined, error: Error|null, variables: PublicFolderShareParameters|PublicFolderUnshareParameters) => void|Promise<void>;
20+
}
21+
22+
export const useDashboardFolderShareAction = (options: UseDashboardFolderShareActionOptions) => {
23+
const { publicFolderAPI } = usePublicFolderApi();
24+
const { publicDashboardAPI } = usePublicDashboardApi();
25+
const queryClient = useQueryClient();
26+
const { withSuffix: publicFolderGetQueryKey } = useServiceQueryKey('dashboard', 'public-folder', 'get');
27+
const { withSuffix: publicDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'public-dashboard', 'get');
28+
const {
29+
folderId, isShared, onSuccess, onError, onSettled,
30+
} = options;
31+
32+
33+
const listPublicDashboard = async () => {
34+
if (!folderId.value) throw new Error('Folder ID is not provided');
35+
try {
36+
const _dashboardList = await publicDashboardAPI.list({
37+
folder_id: folderId.value,
38+
});
39+
return _dashboardList;
40+
} catch (error) {
41+
console.error(error);
42+
return {
43+
results: [],
44+
};
45+
}
46+
};
47+
48+
const shareFolderFn = async (params: PublicFolderShareParameters|PublicFolderUnshareParameters): Promise<PublicFolderModel> => {
49+
if (!folderId.value) throw new Error('Folder ID is not provided');
50+
if (isShared.value) return publicFolderAPI.unshare(params as PublicFolderUnshareParameters);
51+
return publicFolderAPI.share(params as PublicFolderShareParameters);
52+
};
53+
54+
return useMutation({
55+
mutationFn: shareFolderFn,
56+
onSuccess: async (data, variables) => {
57+
const _folderId = variables.folder_id;
58+
queryClient.invalidateQueries({ queryKey: publicFolderGetQueryKey(_folderId) });
59+
if (!isShared.value) {
60+
const _dashboardList = await listPublicDashboard();
61+
const _dashboardIds = _dashboardList.results?.map((dashboard) => dashboard.dashboard_id);
62+
if (_dashboardIds) {
63+
await Promise.all(
64+
_dashboardIds.map((dashboardId) => queryClient.invalidateQueries({ queryKey: publicDashboardGetQueryKey(dashboardId) })),
65+
);
66+
}
67+
}
68+
if (onSuccess) await onSuccess(data, variables);
69+
},
70+
onError: (error, variables) => {
71+
if (onError) onError(error, variables);
72+
},
73+
onSettled: (data, error, variables) => {
74+
if (onSettled) onSettled(data, error, variables);
75+
},
76+
});
77+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { ComputedRef } from 'vue';
2+
3+
import {
4+
useMutation, useQueryClient,
5+
} from '@tanstack/vue-query';
6+
7+
import type { DashboardModel } from '@/api-clients/dashboard/_types/dashboard-type';
8+
import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
9+
import type { PublicDashboardShareParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/share';
10+
import type { PublicDashboardUnshareParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/unshare';
11+
import { useServiceQueryKey } from '@/query/query-key/use-service-query-key';
12+
13+
interface UseDashboardShareActionOptions {
14+
dashboardId: ComputedRef<string|undefined>;
15+
isShared: ComputedRef<boolean>;
16+
onSuccess?: (data: DashboardModel, variables: PublicDashboardShareParameters|PublicDashboardUnshareParameters) => void|Promise<void>;
17+
onError?: (error: Error, variables: PublicDashboardShareParameters|PublicDashboardUnshareParameters) => void|Promise<void>;
18+
onSettled?: (data: DashboardModel|undefined, error: Error|null, variables: PublicDashboardShareParameters|PublicDashboardUnshareParameters) => void|Promise<void>;
19+
}
20+
21+
export const useDashboardShareAction = (options: UseDashboardShareActionOptions) => {
22+
const { publicDashboardAPI } = usePublicDashboardApi();
23+
const queryClient = useQueryClient();
24+
const { withSuffix: publicDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'public-dashboard', 'get');
25+
26+
const {
27+
dashboardId, isShared, onSuccess, onError, onSettled,
28+
} = options;
29+
30+
const shareDashboardFn = (params: PublicDashboardShareParameters|PublicDashboardUnshareParameters): Promise<DashboardModel> => {
31+
if (!dashboardId.value) throw new Error('Dashboard ID is not provided');
32+
if (isShared.value) return publicDashboardAPI.unshare(params as PublicDashboardUnshareParameters);
33+
return publicDashboardAPI.share(params as PublicDashboardShareParameters);
34+
};
35+
36+
return useMutation({
37+
mutationFn: shareDashboardFn,
38+
onSuccess: async (data, variables) => {
39+
const _dashboardId = variables.dashboard_id;
40+
queryClient.invalidateQueries({ queryKey: publicDashboardGetQueryKey(_dashboardId) });
41+
if (onSuccess) await onSuccess(data, variables);
42+
},
43+
onError: (error, variables) => {
44+
if (onError) onError(error, variables);
45+
},
46+
onSettled: (data, error, variables) => {
47+
if (onSettled) onSettled(data, error, variables);
48+
},
49+
});
50+
};

0 commit comments

Comments
 (0)