diff --git a/apps/web/src/common/composables/current-menu-id/index.ts b/apps/web/src/common/composables/current-menu-id/index.ts new file mode 100644 index 0000000000..e26eacdb13 --- /dev/null +++ b/apps/web/src/common/composables/current-menu-id/index.ts @@ -0,0 +1,28 @@ +import type { Ref } from 'vue'; +import { computed, reactive, toRef } from 'vue'; +import { useRoute } from 'vue-router/composables'; + +import { clone } from 'lodash'; + +import { MENU_ID } from '@/lib/menu/config'; + + +interface UseCurrentMenuIdReturnType { + currentMenuId: Ref; +} + +export const useCurrentMenuId = (): UseCurrentMenuIdReturnType => { + const route = useRoute(); + + const state = reactive({ + currentMenuId: computed(() => { + const reversedMatched = clone(route.matched).reverse(); + const closestRoute = reversedMatched.find((d) => d.meta?.menuId !== undefined); + return closestRoute?.meta?.menuId || MENU_ID.WORKSPACE_HOME; + }), + }); + + return { + currentMenuId: toRef(state, 'currentMenuId'), + }; +}; diff --git a/apps/web/src/common/composables/page-editable-status/index.ts b/apps/web/src/common/composables/page-editable-status/index.ts new file mode 100644 index 0000000000..a77d60f18c --- /dev/null +++ b/apps/web/src/common/composables/page-editable-status/index.ts @@ -0,0 +1,31 @@ +import type { Ref } from 'vue'; +import { computed, reactive, toRef } from 'vue'; + +import { useUserStore } from '@/store/user/user-store'; + +import type { PageAccessMap } from '@/lib/access-control/config'; + +import { useCurrentMenuId } from '@/common/composables/current-menu-id'; + +interface UsePageEditableStatusReturnType { + hasReadWriteAccess: Ref; +} + +export const usePageEditableStatus = (): UsePageEditableStatusReturnType => { + const userStore = useUserStore(); + const userGetters = userStore.getters; + + const { currentMenuId } = useCurrentMenuId(); + + const storeState = reactive({ + pageAccessPermissionMap: computed(() => userGetters.pageAccessPermissionMap), + }); + + const state = reactive({ + hasReadWriteAccess: computed(() => storeState.pageAccessPermissionMap[currentMenuId.value]?.write), + }); + + return { + hasReadWriteAccess: toRef(state, 'hasReadWriteAccess'), + }; +}; diff --git a/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue b/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue index d2104c5241..39f5b9bb7c 100644 --- a/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue +++ b/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue @@ -5,7 +5,7 @@ import { } from 'vue'; import { useRoute, useRouter } from 'vue-router/composables'; -import { clone, isEmpty } from 'lodash'; +import { isEmpty } from 'lodash'; import { PI, screens, PButton, PTextButton, PTooltip, @@ -24,6 +24,7 @@ import { MENU_ID } from '@/lib/menu/config'; import BetaMark from '@/common/components/marks/BetaMark.vue'; import NewMark from '@/common/components/marks/NewMark.vue'; import UpdateMark from '@/common/components/marks/UpdateMark.vue'; +import { useCurrentMenuId } from '@/common/composables/current-menu-id'; import { useProperRouteLocation } from '@/common/composables/proper-route-location'; import { useGnbStore } from '@/common/modules/navigations/stores/gnb-store'; @@ -48,6 +49,8 @@ const route = useRoute(); const router = useRouter(); const { width } = useWindowSize(); +const { currentMenuId } = useCurrentMenuId(); + const storeState = reactive({ isHideNavRail: computed(() => gnbGetters.isHideNavRail), isMinimizeNavRail: computed(() => gnbGetters.isMinimizeNavRail), @@ -88,14 +91,11 @@ const state = reactive({ }); return result; }), - selectedMenuId: computed(() => { - const reversedMatched = clone(route.matched).reverse(); - const closestRoute = reversedMatched.find((d) => d.meta?.menuId !== undefined); - const targetMenuId: string = closestRoute?.name || closestRoute?.meta?.menuId || MENU_ID.WORKSPACE_HOME; + selectedMenuId: computed(() => { if (route.name === COST_EXPLORER_ROUTE.LANDING._NAME) { return ''; } - return targetMenuId; + return currentMenuId.value; }), }); diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-header/TopBarWorkspaces.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-header/TopBarWorkspaces.vue index 3d8d6cc4e6..1e3ded313f 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-header/TopBarWorkspaces.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-header/TopBarWorkspaces.vue @@ -5,7 +5,7 @@ import { import type { Location } from 'vue-router'; import { useRouter } from 'vue-router/composables'; -import { clone, sortBy } from 'lodash'; +import { sortBy } from 'lodash'; import { PSelectDropdown, PTooltip, PI, PButton, PTextHighlighting, PEmpty, @@ -21,10 +21,9 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp import type { ReferenceData } from '@/lib/helper/config-data-helper'; import { convertWorkspaceConfigToReferenceData } from '@/lib/helper/config-data-helper'; -import type { MenuId } from '@/lib/menu/config'; -import { MENU_ID } from '@/lib/menu/config'; import { MENU_INFO_MAP } from '@/lib/menu/menu-info'; +import { useCurrentMenuId } from '@/common/composables/current-menu-id'; import FavoriteButton from '@/common/modules/favorites/favorite-button/FavoriteButton.vue'; import { useFavoriteStore } from '@/common/modules/favorites/favorite-button/store/favorite-store'; import type { FavoriteItem } from '@/common/modules/favorites/favorite-button/type'; @@ -54,6 +53,8 @@ const favoriteStore = useFavoriteStore(); const favoriteGetters = favoriteStore.getters; const recentStore = useRecentStore(); +const { currentMenuId } = useCurrentMenuId(); + const router = useRouter(); const selectDropdownRef = ref(null); @@ -80,11 +81,8 @@ const selectWorkspace = (name: string): void => { if (!workspaceId || workspaceId === storeState.currentWorkspaceId) return; appContextStore.setGlobalGrantLoading(true); - const reversedMatched = clone(router.currentRoute.matched).reverse(); - const closestRoute = reversedMatched.find((d) => d.meta?.menuId !== undefined); - const targetMenuId: MenuId = closestRoute?.meta?.menuId || MENU_ID.WORKSPACE_HOME; userWorkspaceStore.setCurrentWorkspace(workspaceId); - router.push({ name: MENU_INFO_MAP[targetMenuId].routeName, params: { workspaceId } }).catch(() => {}); + router.push({ name: MENU_INFO_MAP[currentMenuId.value].routeName, params: { workspaceId } }).catch(() => {}); }; const formatMenuItems = (menuItems: WorkspaceModel[] = []): MenuItem[] => { const result = menuItems.length > 0 ? [ diff --git a/apps/web/src/lib/access-control/config.ts b/apps/web/src/lib/access-control/config.ts index 5d9a7b537a..7b71c8c132 100644 --- a/apps/web/src/lib/access-control/config.ts +++ b/apps/web/src/lib/access-control/config.ts @@ -31,7 +31,6 @@ export const WORKSPACE_OWNER_DEFAULT_PERMISSIONS: MenuId[] = [ MENU_ID.SERVICE_ACCOUNT, MENU_ID.COST_EXPLORER, MENU_ID.COST_ANALYSIS, - // MENU_ID.ANOMALY_DETECTION, MENU_ID.BUDGET, MENU_ID.COST_REPORT, MENU_ID.ALERT_MANAGER_DASHBOARD, @@ -59,7 +58,6 @@ export const WORKSPACE_MEMBER_DEFAULT_PERMISSIONS: MenuId[] = [ MENU_ID.SERVICE_ACCOUNT, MENU_ID.COST_EXPLORER, MENU_ID.COST_ANALYSIS, - // MENU_ID.ANOMALY_DETECTION, MENU_ID.BUDGET, MENU_ID.ALERT_MANAGER_DASHBOARD, MENU_ID.ALERT_MANAGER, diff --git a/apps/web/src/lib/helper/config-data-helper.ts b/apps/web/src/lib/helper/config-data-helper.ts index 03b4bbe998..5011ba3617 100644 --- a/apps/web/src/lib/helper/config-data-helper.ts +++ b/apps/web/src/lib/helper/config-data-helper.ts @@ -28,28 +28,6 @@ export interface ReferenceData extends Omit { export const convertMenuConfigToReferenceData = (config: ConfigData[]|null, menuList: DisplayMenu[]): ReferenceData[] => { const convertMenuList = cloneDeep(menuList); - // const costIdx = convertMenuList.findIndex((i) => i.id === MENU_ID.COST_EXPLORER); - - // NOTE: will be applied after the cost explorer menu is updated - // if (convertMenuList[costIdx].subMenuList?.length === 4) { - // convertMenuList[costIdx].subMenuList?.push( - // { - // id: MENU_ID.ANOMALY_DETECTION_CONFIGURATION, - // to: { name: COST_EXPLORER_ROUTE.ANOMALY_DETECTION.CONFIGURATION._NAME }, - // label: i18n.t('BILLING.COST_MANAGEMENT.ANOMALY_DETECTION.CONFIG.TITLE'), - // }, - // { - // id: MENU_ID.ANOMALY_DETECTION_POLICY, - // to: { name: COST_EXPLORER_ROUTE.ANOMALY_DETECTION.POLICY._NAME }, - // label: i18n.t('BILLING.COST_MANAGEMENT.ANOMALY_DETECTION.POLICY.TITLE'), - // }, - // { - // id: MENU_ID.ANOMALY_DETECTION_HISTORY, - // to: { name: COST_EXPLORER_ROUTE.ANOMALY_DETECTION.HISTORY._NAME }, - // label: i18n.t('BILLING.COST_MANAGEMENT.ANOMALY_DETECTION.HISTORY.TITLE'), - // }, - // ); - // } const allMenuList = getAllSuggestionMenuList(convertMenuList); const results: ReferenceData[] = []; diff --git a/apps/web/src/lib/menu/config.ts b/apps/web/src/lib/menu/config.ts index 4b9c3d3d16..5ce525a705 100644 --- a/apps/web/src/lib/menu/config.ts +++ b/apps/web/src/lib/menu/config.ts @@ -14,7 +14,6 @@ export const MENU_ID = Object.freeze({ COST_EXPLORER: 'cost_explorer', COST_ANALYSIS: 'cost_analysis', COST_ADVANCED_SETTINGS: 'cost_advanced_settings', - ANOMALY_DETECTION: 'anomaly_detection', BUDGET: 'budget', COST_REPORT: 'cost_report', DATA_SOURCES: 'data_sources', diff --git a/apps/web/src/lib/menu/menu-architecture.ts b/apps/web/src/lib/menu/menu-architecture.ts index bb502c0c66..733d69a2c0 100644 --- a/apps/web/src/lib/menu/menu-architecture.ts +++ b/apps/web/src/lib/menu/menu-architecture.ts @@ -28,7 +28,6 @@ export const MENU_LIST: Menu[] = [ needPermissionByRole: true, subMenuList: [ { id: MENU_ID.COST_ANALYSIS, needPermissionByRole: true }, - { id: MENU_ID.ANOMALY_DETECTION, needPermissionByRole: true }, { id: MENU_ID.BUDGET, needPermissionByRole: true }, { id: MENU_ID.COST_REPORT, needPermissionByRole: true }, ], diff --git a/apps/web/src/lib/menu/menu-info.ts b/apps/web/src/lib/menu/menu-info.ts index 62bebb1b52..fd9ed64bde 100644 --- a/apps/web/src/lib/menu/menu-info.ts +++ b/apps/web/src/lib/menu/menu-info.ts @@ -86,13 +86,6 @@ export const MENU_INFO_MAP: Record = Object.freeze({ translationId: 'MENU.COST_EXPLORER_COST_ANALYSIS', icon: 'ic_service_cost-analysis', }, - [MENU_ID.ANOMALY_DETECTION]: { - menuId: MENU_ID.ANOMALY_DETECTION, - routeName: COST_EXPLORER_ROUTE.ANOMALY_DETECTION._NAME, - translationId: 'MENU.COST_EXPLORER_ANOMALY_DETECTION', - highlightTag: 'new', - icon: 'ic_anomaly_detection', - }, [MENU_ID.BUDGET]: { menuId: MENU_ID.BUDGET, routeName: COST_EXPLORER_ROUTE.BUDGET._NAME, diff --git a/apps/web/src/services/advanced/AdvancedLSB.vue b/apps/web/src/services/advanced/AdvancedLSB.vue index 4842eec352..59c388ee0e 100644 --- a/apps/web/src/services/advanced/AdvancedLSB.vue +++ b/apps/web/src/services/advanced/AdvancedLSB.vue @@ -1,28 +1,17 @@ diff --git a/apps/web/src/services/advanced/components/BookmarkDetailContainer.vue b/apps/web/src/services/advanced/components/BookmarkDetailContainer.vue index dbec189d9e..7894e19788 100644 --- a/apps/web/src/services/advanced/components/BookmarkDetailContainer.vue +++ b/apps/web/src/services/advanced/components/BookmarkDetailContainer.vue @@ -6,7 +6,7 @@ import { import type { TranslateResult } from 'vue-i18n'; import { useRoute, useRouter } from 'vue-router/composables'; -import { at, clone } from 'lodash'; +import { at } from 'lodash'; import { PHeading, PButton, PContextMenu, PI, PIconButton, PStatus, PHeadingLayout, @@ -18,15 +18,10 @@ import { i18n } from '@/translations'; import { makeAdminRouteName } from '@/router/helpers/route-helper'; -import { useUserStore } from '@/store/user/user-store'; - -import type { PageAccessMap } from '@/lib/access-control/config'; -import type { MenuId } from '@/lib/menu/config'; -import { MENU_ID } from '@/lib/menu/config'; - import { BOOKMARK_MODAL_TYPE } from '@/common/components/bookmark/constant/constant'; import { useBookmarkStore } from '@/common/components/bookmark/store/bookmark-store'; import type { BookmarkModalType, BookmarkItem } from '@/common/components/bookmark/type/type'; +import { usePageEditableStatus } from '@/common/composables/page-editable-status'; import WorkspaceLogoIcon from '@/common/modules/navigations/top-bar/modules/top-bar-header/WorkspaceLogoIcon.vue'; import { gray } from '@/styles/colors'; @@ -35,17 +30,16 @@ import { getWorkspaceInfo, workspaceStateFormatter } from '@/services/advanced/c import { WORKSPACE_STATE } from '@/services/advanced/constants/workspace-constant'; import { ADVANCED_ROUTE } from '@/services/advanced/routes/route-constant'; import { useBookmarkPageStore } from '@/services/advanced/store/bookmark-page-store'; -import { COST_EXPLORER_ROUTE } from '@/services/cost-explorer/routes/route-constant'; import { WORKSPACE_HOME_ROUTE } from '@/services/workspace-home/routes/route-constant'; - -const userStore = useUserStore(); const bookmarkStore = useBookmarkStore(); const bookmarkState = bookmarkStore.state; const bookmarkPageStore = useBookmarkPageStore(); const bookmarkPageState = bookmarkPageStore.state; const bookmarkPageGetters = bookmarkPageStore.getters; +const { hasReadWriteAccess } = usePageEditableStatus(); + const route = useRoute(); const router = useRouter(); @@ -56,7 +50,6 @@ const storeState = reactive({ selectedIndices: computed(() => bookmarkPageState.selectedIndices), bookmarkFolderList: computed(() => bookmarkPageState.bookmarkFolderList), bookmarkList: computed(() => bookmarkPageGetters.bookmarkList), - pageAccessPermissionMap: computed(() => userStore.getters.pageAccessPermissionMap), }); const state = reactive({ visibleMenu: false, @@ -83,16 +76,6 @@ const state = reactive({ return state.workspaceInfo?.name || ''; }), workspaceInfo: computed(() => getWorkspaceInfo(state.group, storeState.workspaceList)), - selectedMenuId: computed(() => { - const reversedMatched = clone(route.matched).reverse(); - const closestRoute = reversedMatched.find((d) => d.meta?.menuId !== undefined); - const targetMenuId: MenuId = closestRoute?.meta?.menuId || MENU_ID.WORKSPACE_HOME; - if (route.name === COST_EXPLORER_ROUTE.LANDING._NAME) { - return ''; - } - return targetMenuId; - }), - hasReadWriteAccess: computed(() => storeState.pageAccessPermissionMap[state.selectedMenuId]?.write), }); const hideMenu = () => { @@ -204,7 +187,7 @@ onUnmounted(() => { v-bind="workspaceStateFormatter( WORKSPACE_STATE.DORMANT)" class="capitalize state" /> - - -
(() => allReferenceStore.getters.plugin), timezone: computed(() => userStore.state.timezone ?? 'UTC'), - pageAccessPermissionMap: computed(() => userStore.getters.pageAccessPermissionMap), }); const keyItemSets: KeyItemSet[] = [{ @@ -127,16 +119,6 @@ const historyLinkQueryHelper = new QueryHelper(); const state = reactive({ loading: computed(() => collectorPageState.loading.collectorList), - selectedMenuId: computed(() => { - const reversedMatched = clone(route.matched).reverse(); - const closestRoute = reversedMatched.find((d) => d.meta?.menuId !== undefined); - const targetMenuId: MenuId = closestRoute?.meta?.menuId || MENU_ID.WORKSPACE_HOME; - if (route.name === COST_EXPLORER_ROUTE.LANDING._NAME) { - return ''; - } - return targetMenuId; - }), - hasReadWriteAccess: computed(() => storeState.pageAccessPermissionMap[state.selectedMenuId]?.write), searchTags: computed(() => { const tags = searchQueryHelper.setFilters(collectorPageState.searchFilters).queryTags; return tags.reduce((r: QueryItem[], d: any): QueryItem[] => { @@ -284,7 +266,7 @@ onMounted(async () => { @refresh="fetchCollectorList" @export="handleExportExcel" > -