From 0bfaee70174a79fc14e30d17f0021ca9815ad4c7 Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 12 Jan 2026 12:38:30 -0500 Subject: [PATCH] OCPBUGS-72585: Do not resolve disabled catalog type extensions --- .../catalog/hooks/useCatalogExtensions.ts | 85 ++++++++++++------- .../catalog/utils/catalog-utils.tsx | 82 +++++++++++------- .../__tests__/isSubCatalogTypeEnabled.spec.ts | 24 +++--- 3 files changed, 121 insertions(+), 70 deletions(-) diff --git a/frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts b/frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts index fd708c34411..5f1f3f32e36 100644 --- a/frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts +++ b/frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts @@ -15,6 +15,7 @@ import { isCatalogCategoriesProvider, CatalogCategoriesProvider, } from '@console/dynamic-plugin-sdk/src/extensions'; +import { useGetAllDisabledSubCatalogs } from '../utils'; const useCatalogExtensions = ( catalogId: string, @@ -27,11 +28,27 @@ const useCatalogExtensions = ( ResolvedExtension[], boolean, ] => { + const [disabledCatalogs] = useGetAllDisabledSubCatalogs(); + + const isEnabledType = useCallback( + (e: { properties: { type?: string } }) => { + // If no type is specified, we consider it not disabled + if (!e.properties.type) { + return true; + } + + return !disabledCatalogs.includes(e.properties.type); + }, + [disabledCatalogs], + ); + const [itemTypeExtensions, itemTypesResolved] = useResolvedExtensions( useCallback( (e): e is CatalogItemType => - isCatalogItemType(e) && (!catalogType || e.properties.type === catalogType), - [catalogType], + isCatalogItemType(e) && + isEnabledType(e) && + (!catalogType || e.properties.type === catalogType), + [catalogType, isEnabledType], ), ); @@ -40,8 +57,10 @@ const useCatalogExtensions = ( >( useCallback( (e): e is CatalogItemTypeMetadata => - isCatalogItemTypeMetadata(e) && (!catalogType || e.properties.type === catalogType), - [catalogType], + isCatalogItemTypeMetadata(e) && + isEnabledType(e) && + (!catalogType || e.properties.type === catalogType), + [catalogType, isEnabledType], ), ); @@ -49,9 +68,10 @@ const useCatalogExtensions = ( useCallback( (e): e is CatalogItemProvider => isCatalogItemProvider(e) && + isEnabledType(e) && _.castArray(e.properties.catalogId).includes(catalogId) && (!catalogType || e.properties.type === catalogType), - [catalogId, catalogType], + [catalogId, catalogType, isEnabledType], ), ); @@ -59,9 +79,10 @@ const useCatalogExtensions = ( useCallback( (e): e is CatalogItemFilter => isCatalogItemFilter(e) && + isEnabledType(e) && _.castArray(e.properties.catalogId).includes(catalogId) && (!catalogType || e.properties.type === catalogType), - [catalogId, catalogType], + [catalogId, catalogType, isEnabledType], ), ); @@ -71,11 +92,12 @@ const useCatalogExtensions = ( useCallback( (e): e is CatalogCategoriesProvider => isCatalogCategoriesProvider(e) && + isEnabledType(e) && (!e.properties.catalogId || e.properties.catalogId === catalogId || !e.properties.type || e.properties.type === catalogType), - [catalogId, catalogType], + [catalogId, catalogType, isEnabledType], ), ); @@ -85,9 +107,10 @@ const useCatalogExtensions = ( useCallback( (e): e is CatalogItemMetadataProvider => isCatalogItemMetadataProvider(e) && + isEnabledType(e) && _.castArray(e.properties.catalogId).includes(catalogId) && (!catalogType || e.properties.type === catalogType), - [catalogId, catalogType], + [catalogId, catalogType, isEnabledType], ), ); @@ -96,28 +119,30 @@ const useCatalogExtensions = ( (catalogType ? itemTypeExtensions.filter((e) => e.properties.type === catalogType) : itemTypeExtensions - ).map((e) => { - const metadataExts = typeMetadataExtensions.filter( - (em) => e.properties.type === em.properties.type, - ); - if (metadataExts.length > 0) { - return Object.assign({}, e, { - properties: { - ...e.properties, - filters: [ - ...(e.properties.filters ?? []), - ..._.flatten(metadataExts.map((em) => em.properties.filters).filter((x) => x)), - ], - groupings: [ - ...(e.properties.groupings ?? []), - ..._.flatten(metadataExts.map((em) => em.properties.groupings).filter((x) => x)), - ], - }, - }); - } - return e; - }), - [catalogType, itemTypeExtensions, typeMetadataExtensions], + ) + .filter(isEnabledType) + .map((e) => { + const metadataExts = typeMetadataExtensions.filter( + (em) => e.properties.type === em.properties.type, + ); + if (metadataExts.length > 0) { + return Object.assign({}, e, { + properties: { + ...e.properties, + filters: [ + ...(e.properties.filters ?? []), + ..._.flatten(metadataExts.map((em) => em.properties.filters).filter((x) => x)), + ], + groupings: [ + ...(e.properties.groupings ?? []), + ..._.flatten(metadataExts.map((em) => em.properties.groupings).filter((x) => x)), + ], + }, + }); + } + return e; + }), + [catalogType, itemTypeExtensions, typeMetadataExtensions, isEnabledType], ); catalogProviderExtensions.sort((a, b) => { diff --git a/frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx b/frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx index d82b9aa23d2..cdc4664199a 100644 --- a/frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx +++ b/frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx @@ -1,9 +1,6 @@ +import { useMemo } from 'react'; import * as _ from 'lodash'; -import { - useResolvedExtensions, - CatalogItemType, - isCatalogItemType, -} from '@console/dynamic-plugin-sdk'; +import { CatalogItemType, isCatalogItemType } from '@console/dynamic-plugin-sdk'; import { CatalogItem, CatalogItemDetails, @@ -12,6 +9,7 @@ import { import { normalizeIconClass } from '@console/internal/components/catalog/catalog-item-icon'; import { history } from '@console/internal/components/utils/router'; import catalogImg from '@console/internal/imgs/logos/catalog-icon.svg'; +import { useExtensions } from '@console/plugin-sdk/src/api/useExtensions'; import { CatalogSortOrder, CatalogType, CatalogTypeCounts } from './types'; enum CatalogVisibilityState { @@ -19,6 +17,29 @@ enum CatalogVisibilityState { Disabled = 'Disabled', } +type SoftwareCatalogTypesConfig = { + state: CatalogVisibilityState; + enabled?: string[]; + disabled?: string[]; +}; + +/** + * Reads and parses the developerCatalogTypes config from SERVER_FLAGS. + * Has to be dynamic for unit tests to run + */ +const getSoftwareCatalogTypes = (): SoftwareCatalogTypesConfig | undefined => { + if (!window.SERVER_FLAGS.developerCatalogTypes) { + return undefined; + } + try { + return JSON.parse(window.SERVER_FLAGS.developerCatalogTypes) as SoftwareCatalogTypesConfig; + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to parse developerCatalogTypes:', e); + return undefined; + } +}; + // Enhanced scoring constants for operator relevance calculation const SCORE = { // Title/Name matches (highest priority) @@ -362,8 +383,8 @@ export const applyCatalogItemMetadata = ( }); export const isCatalogTypeEnabled = (catalogType: string): boolean => { - if (window.SERVER_FLAGS.developerCatalogTypes) { - const softwareCatalogTypes = JSON.parse(window.SERVER_FLAGS.developerCatalogTypes); + const softwareCatalogTypes = getSoftwareCatalogTypes(); + if (softwareCatalogTypes) { if ( softwareCatalogTypes?.state === CatalogVisibilityState.Enabled && softwareCatalogTypes?.enabled?.length > 0 @@ -381,35 +402,36 @@ export const isCatalogTypeEnabled = (catalogType: string): boolean => { }; export const useGetAllDisabledSubCatalogs = () => { - const [catalogExtensionsArray] = useResolvedExtensions(isCatalogItemType); - const catalogTypeExtensions = catalogExtensionsArray.map((type) => { - return type.properties.type; - }); - let disabledSubCatalogs = []; - if (window.SERVER_FLAGS.developerCatalogTypes) { - const softwareCatalogTypes = JSON.parse(window.SERVER_FLAGS.developerCatalogTypes); - if ( - softwareCatalogTypes?.state === CatalogVisibilityState.Enabled && - softwareCatalogTypes?.enabled?.length > 0 - ) { - disabledSubCatalogs = catalogTypeExtensions.filter( - (val) => !softwareCatalogTypes?.enabled.includes(val), - ); - return [disabledSubCatalogs]; - } - if (softwareCatalogTypes?.state === CatalogVisibilityState.Disabled) { - if (softwareCatalogTypes?.disabled?.length > 0) { - return [softwareCatalogTypes?.disabled, catalogTypeExtensions]; + const catalogExtensionsArray = useExtensions(isCatalogItemType); + const softwareCatalogTypes = useMemo(() => getSoftwareCatalogTypes(), []); + + return useMemo(() => { + const catalogTypeExtensions = catalogExtensionsArray.map((type) => type.properties.type); + + if (softwareCatalogTypes) { + if ( + softwareCatalogTypes?.state === CatalogVisibilityState.Enabled && + softwareCatalogTypes?.enabled?.length > 0 + ) { + const disabledSubCatalogs = catalogTypeExtensions.filter( + (val) => !softwareCatalogTypes?.enabled.includes(val), + ); + return [disabledSubCatalogs]; + } + if (softwareCatalogTypes?.state === CatalogVisibilityState.Disabled) { + if (softwareCatalogTypes?.disabled?.length > 0) { + return [softwareCatalogTypes?.disabled]; + } + return [catalogTypeExtensions]; } - return [catalogTypeExtensions]; } - } - return [disabledSubCatalogs]; + return [[]]; + }, [catalogExtensionsArray, softwareCatalogTypes]); }; export const useIsSoftwareCatalogEnabled = (): boolean => { const [disabledSubCatalogs] = useGetAllDisabledSubCatalogs(); - const [catalogExtensionsArray] = useResolvedExtensions(isCatalogItemType); + const catalogExtensionsArray = useExtensions(isCatalogItemType); const catalogTypeExtensions = catalogExtensionsArray.map((type) => { return type.properties.type; }); diff --git a/frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts b/frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts index e6e9ddc2876..9dc53e3382a 100644 --- a/frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts +++ b/frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts @@ -1,5 +1,5 @@ -import { useResolvedExtensions } from '@console/dynamic-plugin-sdk'; import { HELM_CHART_CATALOG_TYPE_ID } from '@console/helm-plugin/src/const'; +import { useExtensions } from '@console/plugin-sdk/src/api/useExtensions'; import { useGetAllDisabledSubCatalogs, isCatalogTypeEnabled, @@ -8,12 +8,12 @@ import { import { testHook } from '@console/shared/src/test-utils/hooks-utils'; import { mockExtensions } from './catalogTypeExtensions.data'; -jest.mock('@console/dynamic-plugin-sdk/src/api/useResolvedExtensions', () => ({ - useResolvedExtensions: jest.fn(), +jest.mock('@console/plugin-sdk/src/api/useExtensions', () => ({ + useExtensions: jest.fn(), })); -const useResolvedExtensionsMock = useResolvedExtensions as jest.Mock; -useResolvedExtensionsMock.mockReturnValue([mockExtensions, true]); +const useExtensionsMock = useExtensions as jest.Mock; +useExtensionsMock.mockReturnValue(mockExtensions); beforeEach(() => { delete window.SERVER_FLAGS.developerCatalogTypes; @@ -106,13 +106,17 @@ describe('useIsSoftwareCatalogEnabled - check if software catalog is enabled or }); it('should show software catalog as enabled when enabled attribute is not added', () => { window.SERVER_FLAGS.developerCatalogTypes = '{"state" : "Enabled" }'; - const isEnabled = useIsSoftwareCatalogEnabled(); - expect(isEnabled).toBe(true); + testHook(() => { + const isEnabled = useIsSoftwareCatalogEnabled(); + expect(isEnabled).toBe(true); + }); }); - it('should show software catalog as enabled when enabled attribute is not added', () => { + it('should show software catalog as disabled when disabled attribute is not added', () => { window.SERVER_FLAGS.developerCatalogTypes = '{"state" : "Disabled" }'; - const isEnabled = useIsSoftwareCatalogEnabled(); - expect(isEnabled).toBe(false); + testHook(() => { + const isEnabled = useIsSoftwareCatalogEnabled(); + expect(isEnabled).toBe(false); + }); }); });