diff --git a/apps/web/src/api-clients/api-client-manager.ts b/apps/web/src/api-clients/api-client-manager.ts new file mode 100644 index 0000000000..b480adeaa2 --- /dev/null +++ b/apps/web/src/api-clients/api-client-manager.ts @@ -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(); diff --git a/apps/web/src/common/composables/contents-accessibility/index.ts b/apps/web/src/common/composables/contents-accessibility/index.ts new file mode 100644 index 0000000000..4ddb74a9ae --- /dev/null +++ b/apps/web/src/common/composables/contents-accessibility/index.ts @@ -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; +} + +export const useContentsAccessibility = (menuId: MenuId): UseContentsAccessibilityReturnType => { + const menuStore = useMenuStore(); + const menuState = menuStore.state; + + const state = reactive({ + visibleContents: computed(() => menuState.menuList.findIndex((menu) => menu.id === menuId) !== -1), + }); + + return { + visibleContents: toRef(state, 'visibleContents'), + }; +}; diff --git a/apps/web/src/common/modules/custom-table/custom-field-modal/CustomFieldModalForDynamicLayout.vue b/apps/web/src/common/modules/custom-table/custom-field-modal/CustomFieldModalForDynamicLayout.vue index f4266fe0c0..31adf2a591 100644 --- a/apps/web/src/common/modules/custom-table/custom-field-modal/CustomFieldModalForDynamicLayout.vue +++ b/apps/web/src/common/modules/custom-table/custom-field-modal/CustomFieldModalForDynamicLayout.vue @@ -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'); diff --git a/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue b/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue index ddf03e1609..f4593f0749 100644 --- a/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue +++ b/apps/web/src/common/modules/navigations/gnb/GNBNavigationRail.vue @@ -60,7 +60,7 @@ const storeState = reactive({ costDataSource: computed(() => 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, diff --git a/apps/web/src/common/modules/navigations/stores/gnb-store.ts b/apps/web/src/common/modules/navigations/stores/gnb-store.ts index a3e319cedf..4277a98f3e 100644 --- a/apps/web/src/common/modules/navigations/stores/gnb-store.ts +++ b/apps/web/src/common/modules/navigations/stores/gnb-store.ts @@ -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; @@ -44,6 +45,7 @@ export const useGnbStore = defineStore('gnb', () => { }); const state = reactive({ + visibleAlertIcon: false, breadcrumbs: [], selectedItem: {} as Breadcrumb, id: '', @@ -66,6 +68,9 @@ export const useGnbStore = defineStore('gnb', () => { }); const mutations = { + setVisibleAlertIcon: (val?: boolean) => { + state.visibleAlertIcon = val; + }, setBreadcrumbs: (breadcrumbs: Breadcrumb[]) => { state.breadcrumbs = breadcrumbs; }, diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts index 1a9fe88780..6dd2444f28 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts @@ -8,6 +8,7 @@ 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(); @@ -15,7 +16,7 @@ export const topBarSearchReferenceRouter = (type: Exclude, 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: diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue index 82aa5be4e5..e95fc2df05 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue @@ -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'; @@ -33,10 +32,13 @@ 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>(() => ({ adminToggle: (state.isAdminMode ? i18n.t('COMMON.GNB.TOOLTIP.EXIT_ADMIN_MODE') : i18n.t('COMMON.GNB.TOOLTIP.ENABLE_ADMIN_MODE')) as string, })), @@ -44,7 +46,6 @@ const state = reactive({ const extraMenu = domainStore.getters.domainExtraMenu; return extraMenu?.title; }), - isAlertManagerVersionV2: computed(() => (config.get('ADVANCED_SERVICE')?.alert_manager_v2 ?? []).includes(domainStore.state.domainId)), }); const hideMenu = () => { @@ -72,7 +73,7 @@ const updateOpenedMenu = (menu: string, visible: boolean) => { :visible="props.openedMenu === 'favorite'" @update:visible="updateOpenedMenu('favorite', $event)" /> - diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue index dd2add734c..629eca906f 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue @@ -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'; @@ -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(); @@ -56,6 +57,8 @@ const userStore = useUserStore(); const emit = defineEmits<{(e: 'scroll'): void;}>(); +const { visibleContents } = useContentsAccessibility(MENU_ID.ASSET_INVENTORY); + /* Query */ const { dataTableList, @@ -455,31 +458,33 @@ watch(() => state.showPopover, (val) => { -

- {{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.INVENTORY') }} -

- -
- -
- +

+ {{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.INVENTORY') }} +

+ +
+ +
+ +
+

+ {{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.ASSET') }} +

-

- {{ i18n.t('DASHBOARDS.WIDGET.OVERLAY.STEP_1.ASSET') }} -

-
- + +