From 6829c239a8c5132a73623a9058e8b20c4eecf561 Mon Sep 17 00:00:00 2001 From: "NaYeong,Kim" Date: Fri, 28 Mar 2025 09:35:19 +0900 Subject: [PATCH 1/2] Merge pull request #5723 from skdud4659/feature/public-config (#5724) feat: modify to allow override of setting data by domain --- apps/web/public/config/default.json | 31 +++++++++- .../web/src/api-clients/api-client-manager.ts | 21 ++----- .../config/public-config/schema/constant.ts | 1 + .../src/lib/site-initializer/api-client.ts | 2 - apps/web/src/lib/site-initializer/index.ts | 6 +- .../src/lib/site-initializer/merge-config.ts | 28 +++++++++ apps/web/src/services/configurator.ts | 8 +-- .../composables/useAdvancedMenuDisplay.ts | 59 +++++++++++++++++++ apps/web/src/store/display/display-store.ts | 4 ++ 9 files changed, 136 insertions(+), 24 deletions(-) create mode 100644 apps/web/src/lib/site-initializer/merge-config.ts create mode 100644 apps/web/src/store/display/composables/useAdvancedMenuDisplay.ts diff --git a/apps/web/public/config/default.json b/apps/web/public/config/default.json index 9275642928..077eb24cc0 100644 --- a/apps/web/public/config/default.json +++ b/apps/web/public/config/default.json @@ -20,5 +20,34 @@ ], "CONTACT_LINK": "", "SMTP_ENABLED": false, - "ADVANCED_SERVICE": {} + "SERVICES": { + "DASHBOARDS": { + "ENABLED": true, + "VERSION": "V1" + }, + "PROJECT": { + "ENABLED": true, + "VERSION": "V1" + }, + "SERVICE_ACCOUNT": { + "ENABLED": true, + "VERSION": "V1" + }, + "ASSET_INVENTORY": { + "ENABLED": true, + "VERSION": "V1" + }, + "COST_ANALYSIS": { + "ENABLED": true, + "VERSION": "V1" + }, + "OPS_FLOW": { + "ENABLED": true, + "VERSION": "V1" + }, + "ALERT_MANAGER": { + "ENABLED": true, + "VERSION": "V1" + } + } } diff --git a/apps/web/src/api-clients/api-client-manager.ts b/apps/web/src/api-clients/api-client-manager.ts index b480adeaa2..d6caaf0605 100644 --- a/apps/web/src/api-clients/api-client-manager.ts +++ b/apps/web/src/api-clients/api-client-manager.ts @@ -1,33 +1,22 @@ 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'; +import type { GlobalServiceConfig } from '@/lib/config/global-config/type'; -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 config: GlobalServiceConfig = {} as GlobalServiceConfig; private apiClientsSchema: ApiClientsSchemaType = {} as ApiClientsSchemaType; - async initialize() { - await config.init(); - this.config = config.get('SERVICES') || {}; - this.apiClientsSchema = JSON.parse(JSON.stringify(ApiClientEndpoint)); + async initialize(mergedConfig) { + this.config = mergedConfig; + this.apiClientsSchema = JSON.parse(JSON.stringify(ApiClientEndpoint)); this.defineDynamicServices(); } diff --git a/apps/web/src/api-clients/config/public-config/schema/constant.ts b/apps/web/src/api-clients/config/public-config/schema/constant.ts index afebe61496..b82fd54d13 100644 --- a/apps/web/src/api-clients/config/public-config/schema/constant.ts +++ b/apps/web/src/api-clients/config/public-config/schema/constant.ts @@ -1,6 +1,7 @@ export const PUBLIC_CONFIG_NAMES = { TASK_LANDING: 'console:task-management:landing', TASK_TEMPLATE: 'console:task-management:template', + OVERRIDE_SERVICE_SETTING: 'console:override-service-setting', EXTRA_MENU: 'console:ext-menu', // NOTE: Not used yet. Will be used after migration from domain-config to public-config SETTINGS: 'settings', // NOTE: Not used yet. Will be used after migration from domain-config to public-config } as const; diff --git a/apps/web/src/lib/site-initializer/api-client.ts b/apps/web/src/lib/site-initializer/api-client.ts index 21252ebd58..8f6f503339 100644 --- a/apps/web/src/lib/site-initializer/api-client.ts +++ b/apps/web/src/lib/site-initializer/api-client.ts @@ -2,7 +2,6 @@ import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; import TokenAPI from '@cloudforet/core-lib/space-connector/token-api'; import type { DevConfig, MockConfig, AuthConfig } from '@cloudforet/core-lib/space-connector/type'; -import APIClientManager from '@/api-clients/api-client-manager'; import type { TokenGrantParameters } from '@/api-clients/identity/token/schema/api-verbs/grant'; import type { TokenGrantModel } from '@/api-clients/identity/token/schema/model'; @@ -434,7 +433,6 @@ export const initApiClient = async (config) => { getAfterCallApiMap(), serviceConfig, ); - await APIClientManager.initialize(); const existingRefreshToken = SpaceConnector.getRefreshToken(); if (!existingRefreshToken) return; diff --git a/apps/web/src/lib/site-initializer/index.ts b/apps/web/src/lib/site-initializer/index.ts index ee0c021c8b..faf55b2a47 100644 --- a/apps/web/src/lib/site-initializer/index.ts +++ b/apps/web/src/lib/site-initializer/index.ts @@ -2,6 +2,7 @@ import { computed, watch } from 'vue'; import { QueryHelper } from '@cloudforet/core-lib/query'; +import APIClientManager from '@/api-clients/api-client-manager'; import { SpaceRouter } from '@/router'; import { setI18nLocale } from '@/translations'; @@ -25,6 +26,7 @@ import { initDomainSettings } from '@/lib/site-initializer/domain-settings'; import { initEcharts } from '@/lib/site-initializer/echarts'; import { initErrorHandler } from '@/lib/site-initializer/error-handler'; import { initTaskManagementTemplate } from '@/lib/site-initializer/initTaskManagementTemplate'; +import { mergeConfig } from '@/lib/site-initializer/merge-config'; import { initModeSetting } from '@/lib/site-initializer/mode-setting'; import { checkSsoAccessToken } from '@/lib/site-initializer/sso'; import { initUserAndAuth } from '@/lib/site-initializer/user-auth'; @@ -83,10 +85,12 @@ const init = async () => { /* Init SpaceONE Console */ try { await config.init(); - await ServiceConfigurator.initialize(); await initApiClient(config); const domainId = await initDomain(config); const userId = await initUserAndAuth(config); + const mergedConfig = await mergeConfig(config, domainId); + await ServiceConfigurator.initialize(mergedConfig); + await APIClientManager.initialize(mergedConfig); initDomainSettings(); initModeSetting(); await initWorkspace(userId); diff --git a/apps/web/src/lib/site-initializer/merge-config.ts b/apps/web/src/lib/site-initializer/merge-config.ts new file mode 100644 index 0000000000..82e03467e5 --- /dev/null +++ b/apps/web/src/lib/site-initializer/merge-config.ts @@ -0,0 +1,28 @@ +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { PublicConfigGetParameters } from '@/api-clients/config/public-config/schema/api-verbs/get'; +import { PUBLIC_CONFIG_NAMES } from '@/api-clients/config/public-config/schema/constant'; +import type { PublicConfigModel } from '@/api-clients/config/public-config/schema/model'; + +import type { GlobalServiceConfig } from '@/lib/config/global-config/type'; + +export const mergeConfig = async (config, domainId: string): Promise => { + const baseConfig = config.get('SERVICES') || {}; + + const { data: overrideConfigData } = await SpaceConnector.clientV2.config.publicConfig.get({ + name: PUBLIC_CONFIG_NAMES.OVERRIDE_SERVICE_SETTING, + domain_id: domainId, + }); + const overrideConfig = overrideConfigData.SERVICES || {}; + + Object.keys(overrideConfig).forEach((serviceName) => { + if (baseConfig[serviceName]) { + baseConfig[serviceName] = { + ...baseConfig[serviceName], + ...overrideConfig[serviceName], + }; + } + }); + + return baseConfig; +}; diff --git a/apps/web/src/services/configurator.ts b/apps/web/src/services/configurator.ts index dcfc2a8083..433b4d75ef 100644 --- a/apps/web/src/services/configurator.ts +++ b/apps/web/src/services/configurator.ts @@ -4,7 +4,6 @@ import { isEmpty } from 'lodash'; import { useMenuStore } from '@/store/menu/menu-store'; -import config from '@/lib/config'; import { FeatureSchemaManager } from '@/lib/config/global-config/feature-schema-manager'; import type { FeatureSchemaType, GlobalServiceConfig } from '@/lib/config/global-config/type'; import type { Menu } from '@/lib/menu/config'; @@ -24,14 +23,15 @@ import ServiceAccountConfigurator from '@/services/service-account/configurator' import adminWorkspaceHomeRoutes from '@/services/workspace-home/routes/admin/routes'; import workspaceHomeRoute from '@/services/workspace-home/routes/routes'; + class ServiceConfigurator { private config: GlobalServiceConfig = {} as GlobalServiceConfig; private featureSchema: FeatureSchemaType = {} as FeatureSchemaType; - async initialize() { - await config.init(); - this.config = config.get('SERVICES') || {}; + async initialize(mergedConfig) { + this.config = mergedConfig; + const featureSchemaManager = new FeatureSchemaManager(this.config); const featureSchema = await featureSchemaManager.applyGlobalConfig(); diff --git a/apps/web/src/store/display/composables/useAdvancedMenuDisplay.ts b/apps/web/src/store/display/composables/useAdvancedMenuDisplay.ts new file mode 100644 index 0000000000..a1f989a275 --- /dev/null +++ b/apps/web/src/store/display/composables/useAdvancedMenuDisplay.ts @@ -0,0 +1,59 @@ +import type { DisplayMenu } from '@/store/display/type'; + +import type { MenuId } from '@/lib/menu/config'; +import { MENU_ID } from '@/lib/menu/config'; + +import { useContentsAccessibility } from '@/common/composables/contents-accessibility'; + +import { + useTaskManagementTemplateStore, +} from '@/services/ops-flow/task-management-templates/stores/use-task-management-template-store'; + +const ADVANCED_SERVICE_NAMES: MenuId[] = [MENU_ID.OPS_FLOW]; +export const useAdvancedMenuDisplay = () => { + const taskManagementTemplateStore = useTaskManagementTemplateStore(); + + const isMenuDisplayable = (menuId: MenuId): boolean => { + if (!ADVANCED_SERVICE_NAMES.includes(menuId)) return true; + const { visibleContents } = useContentsAccessibility(menuId); + return !!visibleContents; + }; + + const refineOpsflowSubMenu = (menu: DisplayMenu): DisplayMenu[]|undefined => { + const sub = menu.subMenuList; + if (!sub) return undefined; + const refined: DisplayMenu[] = sub.map((s) => { + if (s.id === MENU_ID.OPS_FLOW_LANDING) { + const label = taskManagementTemplateStore.templates.TemplateName; + const hideOnGNB = taskManagementTemplateStore.state.templateId === 'default' || !taskManagementTemplateStore.state.enableLanding; + const hideOnSiteMap = taskManagementTemplateStore.state.templateId === 'default' || !taskManagementTemplateStore.state.enableLanding; + return { + ...s, + label, + hideOnGNB, + hideOnSiteMap, + }; + } + if (s.id === MENU_ID.TASK_BOARD) { + const label = taskManagementTemplateStore.templates.TaskBoard; + return { ...s, label }; + } + return s; + }); + + return refined; + }; + + const refineGNBMenuList = (allGNBMenuList: DisplayMenu[]): DisplayMenu[] => allGNBMenuList.filter((menu) => isMenuDisplayable(menu.id)).map((menu) => { + if (menu.id === MENU_ID.OPS_FLOW) { + return { + ...menu, + subMenuList: refineOpsflowSubMenu(menu), + }; + } + return menu; + }); + return { + refineGNBMenuList, + }; +}; diff --git a/apps/web/src/store/display/display-store.ts b/apps/web/src/store/display/display-store.ts index 6f11277f38..66a2741033 100644 --- a/apps/web/src/store/display/display-store.ts +++ b/apps/web/src/store/display/display-store.ts @@ -23,6 +23,7 @@ import { makeAdminRouteName } from '@/router/helpers/route-helper'; import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; +import { useAdvancedMenuDisplay } from '@/store/display/composables/useAdvancedMenuDisplay'; import { SIDEBAR_TYPE } from '@/store/display/constant'; import type { DisplayMenu, DisplayStoreState, SidebarProps, SidebarType, @@ -107,6 +108,7 @@ export const useDisplayStore = defineStore('display-store', () => { gnbNotificationLastReadTime: '', }); + const advancedMenuDisplay = useAdvancedMenuDisplay(); const getters = reactive({ hasUncheckedNotifications: computed(() => !!(state.uncheckedNotificationCount && state.uncheckedNotificationCount > 0)), isHandbookVisible: computed(() => state.visibleSidebar && (state.sidebarType === SIDEBAR_TYPE.handbook)), @@ -328,6 +330,8 @@ export const useDisplayStore = defineStore('display-store', () => { }); } + // advanced service menu display + _allGnbMenuList = advancedMenuDisplay.refineGNBMenuList(_allGnbMenuList); return _allGnbMenuList; }; From 6a36dd33f7b1a3705f827037996d4d9bed51c8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NaYeong=2CKim=28=EA=B9=80=EB=82=98=EC=98=81=29?= Date: Fri, 28 Mar 2025 09:40:19 +0900 Subject: [PATCH 2/2] chore: changed file name Signed-off-by: NaYeong,Kim --- .../{useAdvancedMenuDisplay.ts => use-advanced-menu-display.ts} | 0 apps/web/src/store/display/display-store.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename apps/web/src/store/display/composables/{useAdvancedMenuDisplay.ts => use-advanced-menu-display.ts} (100%) diff --git a/apps/web/src/store/display/composables/useAdvancedMenuDisplay.ts b/apps/web/src/store/display/composables/use-advanced-menu-display.ts similarity index 100% rename from apps/web/src/store/display/composables/useAdvancedMenuDisplay.ts rename to apps/web/src/store/display/composables/use-advanced-menu-display.ts diff --git a/apps/web/src/store/display/display-store.ts b/apps/web/src/store/display/display-store.ts index 66a2741033..39fc1d29cf 100644 --- a/apps/web/src/store/display/display-store.ts +++ b/apps/web/src/store/display/display-store.ts @@ -23,7 +23,7 @@ import { makeAdminRouteName } from '@/router/helpers/route-helper'; import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; -import { useAdvancedMenuDisplay } from '@/store/display/composables/useAdvancedMenuDisplay'; +import { useAdvancedMenuDisplay } from '@/store/display/composables/use-advanced-menu-display'; import { SIDEBAR_TYPE } from '@/store/display/constant'; import type { DisplayMenu, DisplayStoreState, SidebarProps, SidebarType,