Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions apps/web/src/api-clients/api-client-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { SpaceConnector } from '@cloudforet/core-lib/space-connector';

import config from '@/lib/config';
import type { ApiClientsSchemaType } from '@/lib/config/global-config/api-client-schema';
import { ApiClientEndpoint } from '@/lib/config/global-config/api-client-schema';

interface ServiceConfig {
ENABLED: boolean;
VERSION: string;
}

interface GlobalConfig {
SERVICES: {
[key: string]: ServiceConfig;
};
}

class APIClientManager {
// eslint-disable-next-line no-undef
[key: string]: any;

private config: GlobalConfig['SERVICES'] | null = null;

private apiClientsSchema: ApiClientsSchemaType = {} as ApiClientsSchemaType;

async initialize() {
await config.init();
this.config = config.get('SERVICES') || {};
this.apiClientsSchema = JSON.parse(JSON.stringify(ApiClientEndpoint));

this.defineDynamicServices();
}

private defineDynamicServices() {
if (!this.apiClientsSchema) {
throw new Error('[APIClientManager] APIClientManager is not initialized. Call initialize() first.');
}

Object.keys(this.apiClientsSchema).forEach((serviceName) => {
const propertyName = serviceName.toLowerCase()
.replace(/_([a-z])/g, (_, char) => char.toUpperCase());

Object.defineProperty(this, propertyName, {
get: () => this.createServiceHandler(serviceName),
enumerable: true,
});
});
}

private createServiceHandler(serviceName: string) {
const serviceConfig = this.config?.[serviceName] || null;
if (!serviceConfig || !serviceConfig.ENABLED) {
return null;
}

const apiClientSchemaByService = this.apiClientsSchema[serviceName];
if (!apiClientSchemaByService) {
return null;
}

const version = serviceConfig.VERSION;
const clientEndpoint = apiClientSchemaByService[version];
if (!clientEndpoint) {
return null;
}

const endpoint = SpaceConnector.clientV2[clientEndpoint];

return { endpoint, version };
}
}

export default new APIClientManager();
23 changes: 23 additions & 0 deletions apps/web/src/common/composables/contents-accessibility/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Ref } from 'vue';
import { computed, reactive, toRef } from 'vue';

import { useMenuStore } from '@/store/menu/menu-store';

import type { MenuId } from '@/lib/menu/config';

interface UseContentsAccessibilityReturnType {
visibleContents: Ref<boolean>;
}

export const useContentsAccessibility = (menuId: MenuId): UseContentsAccessibilityReturnType => {
const menuStore = useMenuStore();
const menuState = menuStore.state;

const state = reactive({
visibleContents: computed<boolean>(() => menuState.menuList.findIndex((menu) => menu.id === menuId) !== -1),
});

return {
visibleContents: toRef(state, 'visibleContents'),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import { useProxyValue } from '@/common/composables/proxy-state';
import { TAGS_OPTIONS, TAGS_PREFIX } from '@/common/modules/custom-table/custom-field-modal/config';
import ColumnItemForDynamicLayout from '@/common/modules/custom-table/custom-field-modal/modules/ColumnItemForDynamicLayout.vue';

import { convertAgentModeOptions } from '@/services/asset-inventory/helpers/agent-mode-helper';
import { getServiceAccountTableSchema, updateCustomTableSchema } from '@/services/asset-inventory/helpers/dynamic-ui-schema-generator';
import { convertAgentModeOptions } from '@/services/service-account/helpers/agent-mode-helper';
import { getServiceAccountTableSchema, updateCustomTableSchema } from '@/services/service-account/helpers/dynamic-ui-schema-generator';
import type {
GetSchemaParams,
ResourceType,
} from '@/services/asset-inventory/helpers/dynamic-ui-schema-generator/type';
} from '@/services/service-account/helpers/dynamic-ui-schema-generator/type';

const SelectCloudServiceTagColumns = () => import('@/common/modules/custom-table/custom-field-modal/modules/SelectCloudServiceTagColumns.vue');
const SelectTagColumns = () => import('@/common/modules/custom-table/custom-field-modal/modules/SelectTagColumns.vue');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const storeState = reactive({
costDataSource: computed<CostDataSourceReferenceMap>(() => allReferenceGetters.costDataSource),
});

const noParentsMenuList:MenuId[] = [MENU_ID.DASHBOARDS, MENU_ID.WORKSPACE_HOME, MENU_ID.PROJECT];
const noParentsMenuList:MenuId[] = [MENU_ID.WORKSPACE_HOME, MENU_ID.DASHBOARDS, MENU_ID.PROJECT, MENU_ID.SERVICE_ACCOUNT];

const state = reactive({
isInit: false as boolean|undefined,
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/common/modules/navigations/stores/gnb-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { FavoriteOptions } from '@/common/modules/favorites/favorite-button
import type { Breadcrumb } from '@/common/modules/page-layouts/type';

interface GnbStoreState {
visibleAlertIcon?: boolean;
breadcrumbs: Breadcrumb[];
selectedItem: Breadcrumb;
id?: string;
Expand All @@ -44,6 +45,7 @@ export const useGnbStore = defineStore('gnb', () => {
});

const state = reactive<GnbStoreState>({
visibleAlertIcon: false,
breadcrumbs: [],
selectedItem: {} as Breadcrumb,
id: '',
Expand All @@ -66,6 +68,9 @@ export const useGnbStore = defineStore('gnb', () => {
});

const mutations = {
setVisibleAlertIcon: (val?: boolean) => {
state.visibleAlertIcon = val;
},
setBreadcrumbs: (breadcrumbs: Breadcrumb[]) => {
state.breadcrumbs = breadcrumbs;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import type { SearchTab } from '@/common/modules/navigations/top-bar/modules/top
import { ASSET_INVENTORY_ROUTE } from '@/services/asset-inventory/routes/route-constant';
import { DASHBOARDS_ROUTE } from '@/services/dashboards/routes/route-constant';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
import { SERVICE_ACCOUNT_ROUTE } from '@/services/service-account/routes/route-constant';

const queryHelper = new QueryHelper();

export const topBarSearchReferenceRouter = (type: Exclude<SearchTab, 'service'>, resourceId: string, workspaceId: string, options?: any):RawLocation => {
switch (type) {
case SEARCH_TAB.SERVICE_ACCOUNT:
return {
name: ASSET_INVENTORY_ROUTE.SERVICE_ACCOUNT.DETAIL._NAME,
name: SERVICE_ACCOUNT_ROUTE.DETAIL._NAME,
params: { serviceAccountId: resourceId, workspaceId },
};
case SEARCH_TAB.PROJECT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { useAppContextStore } from '@/store/app-context/app-context-store';
import { useDomainStore } from '@/store/domain/domain-store';
import { useUserStore } from '@/store/user/user-store';

import config from '@/lib/config';

import { useGnbStore } from '@/common/modules/navigations/stores/gnb-store';
import TopBarAdminToggleButton from '@/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue';
import TopBarFavorite
from '@/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-favorite/TopBarFavorite.vue';
Expand All @@ -33,18 +32,20 @@ const emit = defineEmits<{(event: 'hide-menu'): void;
const appContextStore = useAppContextStore();
const domainStore = useDomainStore();
const userStore = useUserStore();
const gnbStore = useGnbStore();

const state = reactive({
isDomainAdmin: computed(() => userStore.getters.isDomainAdmin),
isAdminMode: computed(() => appContextStore.getters.isAdminMode),
isGrantLoading: computed(() => appContextStore.getters.globalGrantLoading),
visibleAlertIcon: computed(() => gnbStore.state.visibleAlertIcon),
tooltipTexts: computed<Record<string, string>>(() => ({
adminToggle: (state.isAdminMode ? i18n.t('COMMON.GNB.TOOLTIP.EXIT_ADMIN_MODE') : i18n.t('COMMON.GNB.TOOLTIP.ENABLE_ADMIN_MODE')) as string,
})),
integrationMenu: computed<string>(() => {
const extraMenu = domainStore.getters.domainExtraMenu;
return extraMenu?.title;
}),
isAlertManagerVersionV2: computed<boolean>(() => (config.get('ADVANCED_SERVICE')?.alert_manager_v2 ?? []).includes(domainStore.state.domainId)),
});

const hideMenu = () => {
Expand Down Expand Up @@ -72,7 +73,7 @@ const updateOpenedMenu = (menu: string, visible: boolean) => {
:visible="props.openedMenu === 'favorite'"
@update:visible="updateOpenedMenu('favorite', $event)"
/>
<top-bar-notifications v-if="!state.isAlertManagerVersionV2 && !state.isAdminMode && !state.isGrantLoading"
<top-bar-notifications v-if="state.visibleAlertIcon && !state.isAdminMode && !state.isGrantLoading"
:visible="props.openedMenu === 'notifications'"
@update:visible="updateOpenedMenu('notifications', $event)"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import type { NamespaceReferenceMap } from '@/store/reference/namespace-referenc
import { useUserStore } from '@/store/user/user-store';

import { showErrorMessage } from '@/lib/helper/notice-alert-helper';
import { MENU_ID } from '@/lib/menu/config';
import getRandomId from '@/lib/random-id-generator';
import type { ListResponse } from '@/lib/variable-models/_base/types';

import { useContentsAccessibility } from '@/common/composables/contents-accessibility';
import ErrorHandler from '@/common/composables/error/errorHandler';
import WidgetFormAssetSecurityDataSourcePopper
from '@/common/modules/widgets/_components/WidgetFormAssetSecurityDataSourcePopper.vue';
Expand All @@ -46,7 +48,6 @@ import type {
import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query';
import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store';


const widgetGenerateStore = useWidgetGenerateStore();
const widgetGenerateState = widgetGenerateStore.state;
const allReferenceStore = useAllReferenceStore();
Expand All @@ -56,6 +57,8 @@ const userStore = useUserStore();

const emit = defineEmits<{(e: 'scroll'): void;}>();

const { visibleContents } = useContentsAccessibility(MENU_ID.ASSET_INVENTORY);

/* Query */
const {
dataTableList,
Expand Down Expand Up @@ -455,31 +458,33 @@ watch(() => state.showPopover, (val) => {
</div>
</p-select-card>

<p class="data-source-domain-title mt-2">
{{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.INVENTORY') }}
</p>
<p-select-card :class="{'custom-select-card': true, 'selected': state.selectedDataSourceDomain === DATA_SOURCE_DOMAIN.ASSET }"
:value="DATA_SOURCE_DOMAIN.ASSET"
@click="handleClickDataSourceDomain(DATA_SOURCE_DOMAIN.ASSET)"
>
<div class="domain-contents">
<p-i v-if="state.selectedDataSourceDomain === DATA_SOURCE_DOMAIN.ASSET"
class="selected-marker"
name="ic_checkbox-circle-selected"
width="1.25rem"
height="1.25rem"
/>
<div class="icon-wrapper">
<p-i name="ic_data-domain-asset"
<template v-if="visibleContents">
<p class="data-source-domain-title mt-2">
{{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.INVENTORY') }}
</p>
<p-select-card :class="{'custom-select-card': true, 'selected': state.selectedDataSourceDomain === DATA_SOURCE_DOMAIN.ASSET }"
:value="DATA_SOURCE_DOMAIN.ASSET"
@click="handleClickDataSourceDomain(DATA_SOURCE_DOMAIN.ASSET)"
>
<div class="domain-contents">
<p-i v-if="state.selectedDataSourceDomain === DATA_SOURCE_DOMAIN.ASSET"
class="selected-marker"
name="ic_checkbox-circle-selected"
width="1.25rem"
height="1.25rem"
/>
<div class="icon-wrapper">
<p-i name="ic_data-domain-asset"
width="1.25rem"
height="1.25rem"
/>
</div>
<p class="name">
{{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.ASSET') }}
</p>
</div>
<p class="name">
{{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.ASSET') }}
</p>
</div>
</p-select-card>
</p-select-card>
</template>
</div>
<template v-if="state.selectedDataSourceDomain">
<widget-form-cost-data-source-popper
Expand Down
10 changes: 5 additions & 5 deletions apps/web/src/lib/access-control/page-access-helper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { RoleType } from '@/api-clients/identity/role/type';

import { useMenuStore } from '@/store/menu/menu-store';

import type {
PageAccessMap,
} from '@/lib/access-control/config';
Expand All @@ -11,9 +13,7 @@ import {
WORKSPACE_OWNER_DEFAULT_PERMISSIONS,
WORKSPACE_USER_MINIMAL_PERMISSIONS,
} from '@/lib/access-control/config';
import config from '@/lib/config';
import type { Menu, MenuId } from '@/lib/menu/config';
import { MENU_LIST, MENU_LIST_FOR_ALERT_MANAGER_V2 } from '@/lib/menu/menu-architecture';

import type { LSBItem, LSBMenu } from '@/common/modules/navigations/lsb/type';

Expand All @@ -38,10 +38,10 @@ export const flattenMenu = (menuList: Menu[]): Menu[] => menuList.flatMap((menu)
...(menu.subMenuList ? flattenMenu(menu.subMenuList) : []),
]);

export const getPageAccessMapFromRawData = (pageAccessPermissions?: string[], domainId?: string): PageAccessMap => {
export const getPageAccessMapFromRawData = (pageAccessPermissions?: string[]): PageAccessMap => {
const menuStore = useMenuStore();
const result: PageAccessMap = {};
const isAlertManagerVersionV2 = (config.get('ADVANCED_SERVICE')?.alert_manager_v2 ?? []).includes(domainId);
const menuListByVersion = (isAlertManagerVersionV2 ? MENU_LIST_FOR_ALERT_MANAGER_V2 : MENU_LIST);
const menuListByVersion = menuStore.state.menuList;
const flattenedMenuList = flattenMenu(menuListByVersion);
const setPermissions = (id: string, read = true, write = true, access = true) => {
result[id] = { read, write, access };
Expand Down
44 changes: 11 additions & 33 deletions apps/web/src/lib/access-control/redirect-route-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,25 @@ import type { Location } from 'vue-router/types/router';

import { ERROR_ROUTE } from '@/router/constant';

import type { FlattenedMenuMap } from '@/store/menu/menu-store';
import { useMenuStore } from '@/store/menu/menu-store';

import type { PageAccessMap } from '@/lib/access-control/config';
import config from '@/lib/config';
import type { Menu, MenuId } from '@/lib/menu/config';
import { MENU_LIST, MENU_LIST_FOR_ALERT_MANAGER_V2 } from '@/lib/menu/menu-architecture';
import type { MenuId } from '@/lib/menu/config';
import { MENU_INFO_MAP } from '@/lib/menu/menu-info';

type FlattenedMenuMap = Partial<Record<MenuId, MenuId[]>>;
const FLATTENED_MENU_MAP = {};
const getSubMenuIdsToMap = (menu: Menu, flattenedMenuMap: FlattenedMenuMap = {}): FlattenedMenuMap => {
let results: MenuId[] = [];
const subMenuList = menu.subMenuList;
if (subMenuList) {
subMenuList.forEach((subMenu) => {
results = subMenuList.map((d) => d.id);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getSubMenuIdsToMap(subMenu, flattenedMenuMap);
});
}
flattenedMenuMap[menu.id] = results;
return flattenedMenuMap;
};

const makeFlattenedMenuMap = (domainId:string) => {
const isAlertManagerVersionV2 = (config.get('ADVANCED_SERVICE')?.alert_manager_v2 ?? []).includes(domainId);
const menuListByVersion = (isAlertManagerVersionV2 ? MENU_LIST_FOR_ALERT_MANAGER_V2 : MENU_LIST);
menuListByVersion.forEach((menu) => {
getSubMenuIdsToMap(menu, FLATTENED_MENU_MAP);
});
};

const getSubMenuListByMenuId = (menuId: MenuId): MenuId[] => {
if (FLATTENED_MENU_MAP[menuId]) return FLATTENED_MENU_MAP[menuId];
const getSubMenuListByMenuId = (menuId: MenuId, flattenedMenu: FlattenedMenuMap): MenuId[] => {
if (flattenedMenu[menuId]) return flattenedMenu[menuId] || [];
return [];
};

export const getRedirectRouteByPagePermission = (route: Route, pagePermissionsMap: PageAccessMap, domainId:string): Location => {
const isFlattenedMenuMapEmpty = Object.keys(FLATTENED_MENU_MAP).length === 0;
if (isFlattenedMenuMapEmpty) makeFlattenedMenuMap(domainId);
export const getRedirectRouteByPagePermission = (route: Route, pagePermissionsMap: PageAccessMap): Location => {
const menuId = route.meta?.menuId;
if (!menuId) return { name: ERROR_ROUTE._NAME, params: { statusCode: '404' } };
const subMenuIdList = getSubMenuListByMenuId(menuId);

const menuStore = useMenuStore();
const generateFlattenedMenuMap = menuStore.getters.generateFlattenedMenuMap;
const subMenuIdList = getSubMenuListByMenuId(menuId, generateFlattenedMenuMap);
let redirectMenuId: MenuId|undefined;
subMenuIdList.some((subMenuId) => {
if (pagePermissionsMap[subMenuId]) {
Expand Down
Loading
Loading