Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { ComputedRef } from 'vue';
import { useMutation } from '@tanstack/vue-query';

import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list';
import { RESOURCE_GROUP } from '@/api-clients/_common/schema/constant';
import type { DashboardCreateParams, DashboardModel } from '@/api-clients/dashboard/_types/dashboard-type';
import type { WidgetModel } from '@/api-clients/dashboard/_types/widget-type';
import { usePrivateDashboardApi } from '@/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api';
Expand All @@ -16,7 +15,6 @@ import { usePublicWidgetApi } from '@/api-clients/dashboard/public-widget/compos
import { useAllReferenceStore } from '@/store/reference/all-reference-store';
import { useUserStore } from '@/store/user/user-store';

import { useDashboardRouteContext } from '@/services/dashboard-shared/core/composables/use-dashboard-route-context';
import { getSharedDashboardLayouts } from '@/services/dashboard-shared/core/helpers/dashboard-share-helper';


Expand All @@ -35,9 +33,6 @@ export const useDashboardCloneAction = (options: UseDashboardCloneActionOptions)
const { publicWidgetAPI } = usePublicWidgetApi();
const allReferenceStore = useAllReferenceStore();
const userStore = useUserStore();
const {
entryPoint,
} = useDashboardRouteContext();

const {
dashboardId, isPrivate, onSuccess, onError, onSettled,
Expand Down Expand Up @@ -78,23 +73,14 @@ export const useDashboardCloneAction = (options: UseDashboardCloneActionOptions)
const _sharedLayouts = await getSharedDashboardLayouts(dashboard.layouts, widgetList.results || [], allReferenceStore.getters.costDataSource);

const _sharedDashboard: DashboardCreateParams = {
name: params.name,
...params,
layouts: _sharedLayouts,
options: dashboard.options || {},
labels: dashboard.labels || [],
tags: { created_by: userStore.state.userId },
vars: dashboard.vars,
vars_schema: dashboard.vars_schema,
};
if (entryPoint.value === 'ADMIN') {
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.DOMAIN;
} else if (entryPoint.value === 'WORKSPACE') {
if (!isPrivate?.value) {
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.WORKSPACE;
}
} else if (entryPoint.value === 'PROJECT') {
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.PROJECT;
}


if (isPrivate?.value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ export const useDashboardDeleteAction = (options: UseDashboardDeleteActionOption
onSuccess: async (data, variables) => {
const _dashboardId = variables.dashboard_id;
const _isPrivate = _dashboardId.startsWith('private');
const dashboardListQueryKey = _isPrivate ? privateDashboardGetQueryKey(_dashboardId) : publicDashboardGetQueryKey(_dashboardId);
queryClient.invalidateQueries({ queryKey: dashboardListQueryKey });
const dashboardGetQueryKey = _isPrivate ? privateDashboardGetQueryKey(_dashboardId) : publicDashboardGetQueryKey(_dashboardId);
queryClient.invalidateQueries({ queryKey: dashboardGetQueryKey });
if (onSuccess) await onSuccess(data, variables);
},
onError: (error, variables) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { ComputedRef } from 'vue';
import { computed } from 'vue';

import {
useMutation, useQueryClient,
} from '@tanstack/vue-query';

import type { DashboardDeleteParams, DashboardListParams } from '@/api-clients/dashboard/_types/dashboard-type';
import type { FolderDeleteParams } from '@/api-clients/dashboard/_types/folder-type';
import { usePrivateDashboardApi } from '@/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api';
import { usePrivateFolderApi } from '@/api-clients/dashboard/private-folder/composables/use-private-folder-api';
import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
import { usePublicFolderApi } from '@/api-clients/dashboard/public-folder/composables/use-public-folder-api';
import { useServiceQueryKey } from '@/query/query-key/use-service-query-key';

interface UseDashboardFolderDeleteActionOptions {
folderId: ComputedRef<string|undefined>;
onSuccess?: (data: unknown, variables: FolderDeleteParams) => void|Promise<void>;
onError?: (error: Error, variables: FolderDeleteParams) => void|Promise<void>;
onSettled?: (data: unknown|undefined, error: Error|null, variables: FolderDeleteParams) => void|Promise<void>;
}

export const useDashboardFolderDeleteAction = (options: UseDashboardFolderDeleteActionOptions) => {
const { publicFolderAPI } = usePublicFolderApi();
const { privateFolderAPI } = usePrivateFolderApi();
const { publicDashboardAPI } = usePublicDashboardApi();
const { privateDashboardAPI } = usePrivateDashboardApi();
const queryClient = useQueryClient();
const { withSuffix: publicFolderGetQueryKey } = useServiceQueryKey('dashboard', 'public-folder', 'get');
const { withSuffix: privateFolderGetQueryKey } = useServiceQueryKey('dashboard', 'private-folder', 'get');
const { withSuffix: publicDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'public-dashboard', 'get');
const { withSuffix: privateDashboardGetQueryKey } = useServiceQueryKey('dashboard', 'private-dashboard', 'get');

const {
folderId, onSuccess, onError, onSettled,
} = options;

const isPrivate = computed(() => folderId.value?.startsWith('private'));

const listDashboardFn = (params: DashboardListParams) => {
if (!folderId.value) throw new Error('Folder ID is not provided');
const fetcher = isPrivate.value ? privateDashboardAPI.list : publicDashboardAPI.list;
return fetcher(params);
};
const deleteDashboardFn = (params: DashboardDeleteParams) => {
if (!params.dashboard_id) throw new Error('Dashboard ID is not provided');
const fetcher = isPrivate.value ? privateDashboardAPI.delete : publicDashboardAPI.delete;
return fetcher(params);
};

const deleteDashboardListByFolderId = async (_folderId: string) => {
const _dashboardList = await listDashboardFn({
folder_id: _folderId,
});
const _dashboardIds = _dashboardList.results?.map((d) => d.dashboard_id);
if (!_dashboardIds) return;
const _dashboardDeletePromises = _dashboardIds.map(async (id) => {
const _isPrivate = id.startsWith('private');
await deleteDashboardFn({ dashboard_id: id });
queryClient.invalidateQueries({ queryKey: _isPrivate ? privateDashboardGetQueryKey(id) : publicDashboardGetQueryKey(id) });
});
await Promise.all(_dashboardDeletePromises);
};

const deleteFolderFn = (params: FolderDeleteParams) => {
if (!folderId.value) throw new Error('Folder ID is not provided');
const fetcher = isPrivate.value ? privateFolderAPI.delete : publicFolderAPI.delete;
return fetcher(params);
};

return useMutation({
mutationFn: deleteFolderFn,
onSuccess: async (data, variables) => {
const _folderId = variables.folder_id;
const _isPrivate = _folderId.startsWith('private');
const folderListQueryKey = _isPrivate ? privateFolderGetQueryKey(_folderId) : publicFolderGetQueryKey(_folderId);
queryClient.invalidateQueries({ queryKey: folderListQueryKey });

await deleteDashboardListByFolderId(_folderId);

if (onSuccess) await onSuccess(data, variables);
},
onError: (error, variables) => {
if (onError) onError(error, variables);
},
onSettled: (data, error, variables) => {
if (onSettled) onSettled(data, error, variables);
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { PROJECT_ROUTE_V2 } from '@/services/project/v2/routes/route-constant';
interface Props {
dashboardId: string;
dashboardItems?: Array<DashboardModel>;
folderItems?: Array<DashboardFolderModel>;
folderItems: Array<DashboardFolderModel>;
}

const props = withDefaults(defineProps<Props>(), {
Expand Down Expand Up @@ -194,6 +194,7 @@ onUnmounted(() => {
<template>
<div class="dashboard-detail-body">
<dashboard-detail-header :dashboard-id="props.dashboardId"
:folder-items="props.folderItems"
@select-toolset="handleSelectToolset"
/>
<p-divider v-if="entryPoint !== 'PROJECT'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import {
} from '@cloudforet/mirinae';
import { getClonedName } from '@cloudforet/utils';

import { RESOURCE_GROUP } from '@/api-clients/_common/schema/constant';
import type { DashboardCreateParams, DashboardModel, DashboardType } from '@/api-clients/dashboard/_types/dashboard-type';
import type { PublicDashboardCreateParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/create';
import { ROLE_TYPE } from '@/api-clients/identity/role/constant';
import { i18n } from '@/translations';

import { useAppContextStore } from '@/store/app-context/app-context-store';
import { useAllReferenceStore } from '@/store/reference/all-reference-store';
import type { CostDataSourceReferenceMap } from '@/store/reference/cost-data-source-reference-store';
import { useUserStore } from '@/store/user/user-store';

import { showErrorMessage } from '@/lib/helper/notice-alert-helper';
Expand Down Expand Up @@ -51,7 +51,6 @@ const queryClient = useQueryClient();

const router = useRouter();
const appContextStore = useAppContextStore();
const allReferenceStore = useAllReferenceStore();
const userStore = useUserStore();
const {
forms: {
Expand All @@ -77,7 +76,6 @@ const storeState = reactive({
isAdminMode: computed(() => appContextStore.getters.isAdminMode),
isWorkspaceOwner: computed<boolean>(() => userStore.state.currentRoleInfo?.roleType === ROLE_TYPE.WORKSPACE_OWNER),
isWorkspaceMember: computed<boolean>(() => userStore.state.currentRoleInfo?.roleType === ROLE_TYPE.WORKSPACE_MEMBER),
costDataSource: computed<CostDataSourceReferenceMap>(() => allReferenceStore.getters.costDataSource),
});
const state = reactive({
proxyVisible: useProxyValue('visible', props, emit),
Expand Down Expand Up @@ -121,6 +119,15 @@ const handleConfirm = async () => {
} else if (storeState.isAdminMode) {
state.isPrivate = false;
}

if (!state.isPrivate) {
if (storeState.isAdminMode) {
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.DOMAIN;
} else {
(_sharedDashboard as PublicDashboardCreateParameters).resource_group = RESOURCE_GROUP.WORKSPACE;
}
}

mutate(_sharedDashboard as DashboardCreateParams);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useDashboardGetQuery } from '@/services/dashboard-shared/dashboard-deta

interface Props {
dashboardId: string;
folderItems?: Array<FolderModel>;
folderItems: Array<FolderModel>;
}
const props = withDefaults(defineProps<Props>(), {
folderItems: () => [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,64 +8,58 @@ import type { FolderModel } from '@/api-clients/dashboard/_types/folder-type';
import type { DashboardTreeDataType, DashboardDataTableItem } from '@/services/dashboards/types/dashboard-folder-type';


export const getDashboardTreeData = (folderList: FolderModel[], dashboardList: DashboardModel[], newIdList?: string[]): TreeNode<DashboardTreeDataType>[] => {
const nodes: Record<string, TreeNode<DashboardTreeDataType>> = {};
folderList.forEach((d) => {
nodes[d.folder_id] = {
id: d.folder_id,
export const getDashboardTreeData = (
folderList: FolderModel[],
dashboardList: DashboardModel[],
newIdList?: string[],
): TreeNode<DashboardTreeDataType>[] => {
const folderNodeMap: Record<string, TreeNode<DashboardTreeDataType>> = {};
const rootNodes: TreeNode<DashboardTreeDataType>[] = [];

folderList.forEach((folder) => {
const folderNode: TreeNode<DashboardTreeDataType> = {
id: folder.folder_id,
depth: 0,
data: {
name: d.name,
id: folder.folder_id,
name: folder.name,
type: 'FOLDER',
id: d.folder_id,
createdBy: d.tags?.created_by,
isNew: newIdList?.includes(d.folder_id),
...d,
createdBy: folder.tags?.created_by,
isNew: newIdList?.includes(folder.folder_id),
...folder,
},
children: [],
};
folderNodeMap[folder.folder_id] = folderNode;
rootNodes.push(folderNode);
});
dashboardList.forEach((d) => {
nodes[d.dashboard_id] = {
id: d.dashboard_id,

dashboardList.forEach((dashboard) => {
const dashboardNode: TreeNode<DashboardTreeDataType> = {
id: dashboard.dashboard_id,
depth: 0,
data: {
name: d.name,
id: d.dashboard_id,
id: dashboard.dashboard_id,
name: dashboard.name,
type: 'DASHBOARD',
createdBy: d.tags?.created_by,
isNew: newIdList?.includes(d.dashboard_id),
...d,
createdBy: dashboard.tags?.created_by,
isNew: newIdList?.includes(dashboard.dashboard_id),
...dashboard,
},
};
});

const rootNodes: TreeNode<DashboardTreeDataType>[] = [];
const setDepth = (node, depth) => {
node.depth = depth;
if (!node.children) return;
node.children.forEach((child) => {
setDepth(child, depth + 1);
});
};
Object.values(nodes).forEach((node) => {
const folderId = node.data?.folderId;
if (!folderId) {
rootNodes.push(node);
setDepth(node, 0);
const folderNode = dashboard.folder_id ? folderNodeMap[dashboard.folder_id] : undefined;

if (folderNode) {
dashboardNode.depth = 1;
folderNode.children.push(dashboardNode);
} else {
const parentNode = nodes[folderId];
if (parentNode) {
parentNode.children = parentNode.children || [];
parentNode.children.push(node);
setDepth(node, parentNode.depth + 1);
}
rootNodes.push(dashboardNode);
}
});

return rootNodes;
};

export const getSelectedDataTableItems = (folderItems: FolderModel[], dashboardItems: DashboardModel[], selectedIdMap: Record<string, boolean>): DashboardDataTableItem[] => {
const _results: DashboardDataTableItem[] = [];
const _selectedIdList: string[] = Object.keys(selectedIdMap).filter((key) => selectedIdMap[key]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { DashboardModel, DashboardFolderModel } from '@/api-clients/dashboa
import DashboardDetailBody from '@/services/dashboard-shared/dashboard-detail/DashboardDetailBody.vue';
import { useProjectDashboardFolderQuery } from '@/services/project/v2/composables/queries/use-project-dashboard-folder-query';
import { useProjectDashboardQuery } from '@/services/project/v2/composables/queries/use-project-dashboard-query';
import { useProjectPageModalStore } from '@/services/project/v2/stores/project-page-modal-store';

interface Props {
projectId?: string;
Expand All @@ -19,7 +20,7 @@ interface Props {
}
const props = defineProps<Props>();


const projectPageModalStore = useProjectPageModalStore();
/* Query */
const {
dashboardList,
Expand All @@ -40,13 +41,20 @@ const {
const dashboardItems = computed<Array<DashboardModel>>(() => [...dashboardSharedList.value, ...dashboardList.value]);
const dashboardFolderItems = computed<Array<DashboardFolderModel>>(() => [...dashboardFolderSharedList.value, ...dashboardFolderList.value]);

const handleSelectToolset = (toolsetId: string|undefined) => {
if (toolsetId === 'edit') projectPageModalStore.openDashboardNameEditModal(props.dashboardId);
if (toolsetId === 'move') projectPageModalStore.openDashboardChangeFolderModal(props.dashboardId);
if (toolsetId === 'delete') projectPageModalStore.openDashboardDeleteModal(props.dashboardId);
if (toolsetId === 'clone') projectPageModalStore.openDashboardCloneModal(props.dashboardId);
};
</script>

<template>
<div class="project-dashboard">
<dashboard-detail-body :dashboard-id="props.dashboardId"
:dashboard-items="dashboardItems"
:folder-items="dashboardFolderItems"
@select-toolset="handleSelectToolset"
/>
</div>
</template>
Expand Down
Loading
Loading