diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilClassBase.ts index 9f98cbfc075..52ae6c65e63 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilClassBase.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilClassBase.ts @@ -12,9 +12,14 @@ */ import { ObjectFieldTemplatePropertyType } from '@rjsf/utils'; -import { get, toLower } from 'lodash'; +import { get, isEmpty, toLower } from 'lodash'; import { ServiceTypes } from 'Models'; +import GlossaryIcon from '../assets/svg/book.svg'; +import DataProductIcon from '../assets/svg/ic-data-product.svg'; +import DatabaseIcon from '../assets/svg/ic-database.svg'; +import DatabaseSchemaIcon from '../assets/svg/ic-schema.svg'; import MetricIcon from '../assets/svg/metric.svg'; +import TagIcon from '../assets/svg/tag-grey.svg'; import AgentsStatusWidget from '../components/ServiceInsights/AgentsStatusWidget/AgentsStatusWidget'; import PlatformInsightsWidget from '../components/ServiceInsights/PlatformInsightsWidget/PlatformInsightsWidget'; import TotalDataAssetsWidget from '../components/ServiceInsights/TotalDataAssetsWidget/TotalDataAssetsWidget'; @@ -685,9 +690,24 @@ class ServiceUtilClassBase { const type = get(searchSource, 'serviceType', ''); const entityType = get(searchSource, 'entityType', ''); - // metric entity does not have service so we need to handle it separately - if (entityType === EntityType.METRIC) { - return MetricIcon; + // Handle entities that don't have serviceType by using entity-specific icons + if (isEmpty(type)) { + switch (entityType) { + case EntityType.TAG: + return TagIcon; + case EntityType.GLOSSARY_TERM: + return GlossaryIcon; + case EntityType.DATABASE: + return DatabaseIcon; + case EntityType.DATABASE_SCHEMA: + return DatabaseSchemaIcon; + case EntityType.METRIC: + return MetricIcon; + case EntityType.DATA_PRODUCT: + return DataProductIcon; + default: + return this.getServiceLogo(''); + } } return this.getServiceLogo(type); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilsClassBase.test.ts b/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilsClassBase.test.ts index 64a7b35bbd6..12aa0eac5d3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilsClassBase.test.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/ServiceUtilsClassBase.test.ts @@ -10,11 +10,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { EntityType } from '../enums/entity.enum'; import { ExplorePageTabs } from '../enums/Explore.enum'; import serviceUtilClassBase, { ServiceUtilClassBase, } from './ServiceUtilClassBase'; +// Mock dependencies to avoid compilation errors +jest.mock('./CommonUtils', () => ({ + getEntityName: jest.fn(), + getServiceLogo: jest.fn(), +})); + +jest.mock( + '../components/ServiceInsights/AgentsStatusWidget/AgentsStatusWidget', + () => 'AgentsStatusWidget' +); +jest.mock( + '../components/ServiceInsights/PlatformInsightsWidget/PlatformInsightsWidget', + () => 'PlatformInsightsWidget' +); +jest.mock( + '../components/ServiceInsights/TotalDataAssetsWidget/TotalDataAssetsWidget', + () => 'TotalDataAssetsWidget' +); +jest.mock( + '../components/Settings/Services/Ingestion/MetadataAgentsWidget/MetadataAgentsWidget', + () => 'MetadataAgentsWidget' +); + +jest.mock('./APIServiceUtils', () => ({ getAPIConfig: jest.fn() })); +jest.mock('./DashboardServiceUtils', () => ({ getDashboardConfig: jest.fn() })); +jest.mock('./DatabaseServiceUtils', () => ({ getDatabaseConfig: jest.fn() })); +jest.mock('./MessagingServiceUtils', () => ({ getMessagingConfig: jest.fn() })); +jest.mock('./MetadataServiceUtils', () => ({ getMetadataConfig: jest.fn() })); +jest.mock('./MlmodelServiceUtils', () => ({ getMlmodelConfig: jest.fn() })); +jest.mock('./PipelineServiceUtils', () => ({ getPipelineConfig: jest.fn() })); +jest.mock('./SearchServiceUtils', () => ({ + getSearchServiceConfig: jest.fn(), +})); +jest.mock('./SecurityServiceUtils', () => ({ getSecurityConfig: jest.fn() })); +jest.mock('./ServiceUtils', () => ({ getTestConnectionName: jest.fn() })); +jest.mock('./StorageServiceUtils', () => ({ getStorageConfig: jest.fn() })); +jest.mock('./StringsUtils', () => ({ customServiceComparator: jest.fn() })); + describe('ServiceUtilClassBase', () => { it('should create an instance of ServiceUtilClassBase', () => { expect(serviceUtilClassBase).toBeInstanceOf(ServiceUtilClassBase); @@ -107,4 +146,150 @@ describe('ServiceUtilClassBase', () => { expect(result).toEqual(ExplorePageTabs.SEARCH_INDEX); }); + + // getServiceTypeLogo tests + describe('getServiceTypeLogo', () => { + it('should return TagIcon for TAG entity when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: EntityType.TAG, + fullyQualifiedName: 'test.tag', + name: 'test', + tag_id: 'tag123', + tag_name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toEqual({ ReactComponent: 'svg-mock' }); + }); + + it('should return GlossaryIcon for GLOSSARY_TERM entity when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: EntityType.GLOSSARY_TERM, + fullyQualifiedName: 'test.glossary', + name: 'test', + glossary_id: 'glossary123', + glossary_name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toEqual({ ReactComponent: 'svg-mock' }); + }); + + it('should return DatabaseIcon for DATABASE entity when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: EntityType.DATABASE, + fullyQualifiedName: 'test.database', + name: 'test', + database_id: 'db123', + database_name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toEqual({ ReactComponent: 'svg-mock' }); + }); + + it('should return DatabaseSchemaIcon for DATABASE_SCHEMA entity when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: EntityType.DATABASE_SCHEMA, + fullyQualifiedName: 'test.schema', + name: 'test', + database_schema_id: 'schema123', + database_schema_name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toEqual({ ReactComponent: 'svg-mock' }); + }); + + it('should return MetricIcon for METRIC entity when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: EntityType.METRIC, + fullyQualifiedName: 'test.metric', + name: 'test', + metric_id: 'metric123', + metric_name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toEqual({ ReactComponent: 'svg-mock' }); + }); + + it('should return DataProductIcon for DATA_PRODUCT entity when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: EntityType.DATA_PRODUCT, + fullyQualifiedName: 'test.dataproduct', + name: 'test', + data_product_id: 'dp123', + data_product_name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toEqual({ ReactComponent: 'svg-mock' }); + }); + + it('should call getServiceLogo when serviceType is present', () => { + const searchSource = { + serviceType: 'BigQuery', + entityType: EntityType.TABLE, + fullyQualifiedName: 'test.table', + name: 'test', + table_id: 'table123', + table_name: 'test', + }; + + const getServiceLogoSpy = jest.spyOn( + serviceUtilClassBase, + 'getServiceLogo' + ); + + serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(getServiceLogoSpy).toHaveBeenCalledWith('BigQuery'); + + getServiceLogoSpy.mockRestore(); + }); + + it('should call getServiceLogo for unknown entity types when serviceType is empty', () => { + const searchSource = { + serviceType: '', + entityType: 'UNKNOWN_ENTITY' as EntityType, + fullyQualifiedName: 'test.unknown', + name: 'test', + }; + + const getServiceLogoSpy = jest.spyOn( + serviceUtilClassBase, + 'getServiceLogo' + ); + + serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(getServiceLogoSpy).toHaveBeenCalledWith(''); + + getServiceLogoSpy.mockRestore(); + }); + + it('should handle missing serviceType and entityType properties', () => { + const searchSource = { + fullyQualifiedName: 'test.entity', + name: 'test', + }; + + const result = serviceUtilClassBase.getServiceTypeLogo(searchSource); + + expect(result).toBeDefined(); + }); + }); });