diff --git a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts index f996f088df7ef..a2ebf9bf9853f 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts @@ -11,12 +11,12 @@ import { arrayOfStringsSchema } from './common'; export const entityBaseSchema = z.object({ id: z.string(), type: z.string(), - identityFields: z.union([arrayOfStringsSchema, z.string()]), - displayName: z.string(), + identity_fields: z.union([arrayOfStringsSchema, z.string()]), + display_name: z.string(), metrics: z.optional(z.record(z.string(), z.number())), - definitionVersion: z.string(), - schemaVersion: z.string(), - definitionId: z.string(), + definition_version: z.string(), + schema_version: z.string(), + definition_id: z.string(), }); export interface MetadataRecord { diff --git a/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts b/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts index dbaf1205cdf98..0a13952a6d694 100644 --- a/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts +++ b/x-pack/plugins/entity_manager/public/lib/entity_client.test.ts @@ -14,7 +14,7 @@ const commonEntityFields: EnitityInstance = { id: '1', display_name: 'entity_name', definition_id: 'entity_definition_id', - } as EnitityInstance['entity'], + }, }; describe('EntityClient', () => { diff --git a/x-pack/plugins/observability_solution/inventory/.storybook/get_mock_inventory_context.tsx b/x-pack/plugins/observability_solution/inventory/.storybook/get_mock_inventory_context.tsx index d3d28fe040198..0188ed3143034 100644 --- a/x-pack/plugins/observability_solution/inventory/.storybook/get_mock_inventory_context.tsx +++ b/x-pack/plugins/observability_solution/inventory/.storybook/get_mock_inventory_context.tsx @@ -24,7 +24,14 @@ export function getMockInventoryContext(): InventoryKibanaContext { return { ...coreStart, - entityManager: {} as unknown as EntityManagerPublicPluginStart, + entityManager: { + entityClient: { + asKqlFilter: jest.fn(), + getIdentityFieldsValue() { + return 'entity_id'; + }, + }, + } as unknown as EntityManagerPublicPluginStart, observabilityShared: {} as unknown as ObservabilitySharedPluginStart, inference: {} as unknown as InferencePublicStart, share: { diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index 3e1c2c838360d..705a0d5a5a214 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -7,17 +7,13 @@ import { z } from '@kbn/zod'; import { ENTITY_LATEST, entitiesAliasPattern, entityLatestSchema } from '@kbn/entities-schema'; import { - ENTITY_DEFINITION_ID, ENTITY_DISPLAY_NAME, - ENTITY_ID, - ENTITY_IDENTITY_FIELDS, ENTITY_LAST_SEEN, ENTITY_TYPE, } from '@kbn/observability-shared-plugin/common'; import { decode, encode } from '@kbn/rison'; import { isRight } from 'fp-ts/lib/Either'; import * as t from 'io-ts'; -import { AgentName } from '@kbn/elastic-agent-utils'; export const entityColumnIdsRt = t.union([ t.literal(ENTITY_DISPLAY_NAME), @@ -103,17 +99,6 @@ export const entityTypesRt = new t.Type( (arr) => arr.join() ); -export interface Entity { - [ENTITY_LAST_SEEN]: string; - [ENTITY_ID]: string; - [ENTITY_TYPE]: string; - [ENTITY_DISPLAY_NAME]: string; - [ENTITY_DEFINITION_ID]: string; - [ENTITY_IDENTITY_FIELDS]: string | string[]; - alertsCount?: number; - [key: string]: any; -} - export type EntityGroup = { count: number; } & { @@ -123,24 +108,3 @@ export type EntityGroup = { export type InventoryEntityLatest = z.infer & { alertsCount?: number; }; - -export const isHostEntity = ( - entity: InventoryEntityLatest -): entity is InventoryEntityLatest & { cloud?: { provider: string } } => { - return entity.entity.type === 'host'; -}; - -export const isContainerEntity = ( - entity: InventoryEntityLatest -): entity is InventoryEntityLatest & { cloud?: { provider: string } } => { - return entity.entity.type === 'container'; -}; - -export const isServiceEntity = ( - entity: InventoryEntityLatest -): entity is InventoryEntityLatest & { - agent?: { name: AgentName }; - service: { name: string; environment: string }; -} => { - return entity.entity.type === 'service'; -}; diff --git a/x-pack/plugins/observability_solution/inventory/common/utils/entity_type_guards.ts b/x-pack/plugins/observability_solution/inventory/common/utils/entity_type_guards.ts new file mode 100644 index 0000000000000..8665f22996aa8 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/common/utils/entity_type_guards.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AgentName } from '@kbn/elastic-agent-utils'; +import type { InventoryEntityLatest } from '../entities'; + +interface EntityMap { + host: InventoryEntityLatest & { cloud?: { provider?: string } }; + container: InventoryEntityLatest & { cloud?: { provider?: string } }; + service: InventoryEntityLatest & { + agent?: { name: AgentName }; + service?: { name: string; environment?: string }; + }; +} + +export const isEntityOfType = ( + type: T, + entity: InventoryEntityLatest +): entity is EntityMap[T] => { + return entity.entity.type === type; +}; diff --git a/x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts b/x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts deleted file mode 100644 index 758d185a5753b..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/common/utils/unflatten_entity.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { unflattenObject } from '@kbn/observability-utils/object/unflatten_object'; -import type { Entity, InventoryEntityLatest } from '../entities'; - -export function unflattenEntity(entity: Entity) { - return unflattenObject(entity) as InventoryEntityLatest; -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx index b5244cb29f7fc..8e549315e17df 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx @@ -8,11 +8,18 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { AlertsBadge } from './alerts_badge'; import { useKibana } from '../../hooks/use_kibana'; -import type { Entity } from '../../../common/entities'; +import type { InventoryEntityLatest } from '../../../common/entities'; jest.mock('../../hooks/use_kibana'); const useKibanaMock = useKibana as jest.Mock; +const commonEntityFields: Partial = { + last_seen_timestamp: 'foo', + id: '1', + definition_version: '1', + schema_version: '1', +}; + describe('AlertsBadge', () => { const mockAsKqlFilter = jest.fn(); @@ -40,16 +47,21 @@ describe('AlertsBadge', () => { }); it('render alerts badge for a host entity', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'entity.id': '1', - 'entity.type': 'host', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'host.name', - 'host.name': 'foo', - 'entity.definition_id': 'host', - 'cloud.provider': null, + const entity: InventoryEntityLatest = { + entity: { + ...(commonEntityFields as InventoryEntityLatest['entity']), + type: 'host', + display_name: 'foo', + identity_fields: 'host.name', + definition_id: 'host', + }, alertsCount: 1, + host: { + name: 'foo', + }, + cloud: { + provider: null, + }, }; mockAsKqlFilter.mockReturnValue('host.name: foo'); @@ -60,16 +72,24 @@ describe('AlertsBadge', () => { expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('1'); }); it('render alerts badge for a service entity', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'agent.name': 'node', - 'entity.id': '1', - 'entity.type': 'service', - 'entity.display_name': 'foo', - 'entity.identity_fields': 'service.name', - 'service.name': 'bar', - 'entity.definition_id': 'host', - 'cloud.provider': null, + const entity: InventoryEntityLatest = { + entity: { + ...(commonEntityFields as InventoryEntityLatest['entity']), + type: 'service', + display_name: 'foo', + identity_fields: 'service.name', + definition_id: 'service', + }, + service: { + name: 'bar', + }, + agent: { + name: 'node', + }, + cloud: { + provider: null, + }, + alertsCount: 5, }; mockAsKqlFilter.mockReturnValue('service.name: bar'); @@ -81,17 +101,24 @@ describe('AlertsBadge', () => { expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('5'); }); it('render alerts badge for a service entity with multiple identity fields', () => { - const entity: Entity = { - 'entity.last_seen_timestamp': 'foo', - 'agent.name': 'node', - 'entity.id': '1', - 'entity.type': 'service', - 'entity.display_name': 'foo', - 'entity.identity_fields': ['service.name', 'service.environment'], - 'service.name': 'bar', - 'service.environment': 'prod', - 'entity.definition_id': 'host', - 'cloud.provider': null, + const entity: InventoryEntityLatest = { + entity: { + ...(commonEntityFields as InventoryEntityLatest['entity']), + type: 'service', + display_name: 'foo', + identity_fields: ['service.name', 'service.environment'], + definition_id: 'service', + }, + service: { + name: 'bar', + environment: 'prod', + }, + agent: { + name: 'node', + }, + cloud: { + provider: null, + }, alertsCount: 2, }; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx index 047c2e73d0d3e..255b2fd263c5f 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx @@ -9,7 +9,7 @@ import { EuiButton, EuiDataGridSorting, EuiFlexGroup, EuiFlexItem } from '@elast import { Meta, Story } from '@storybook/react'; import { orderBy } from 'lodash'; import React, { useMemo, useState } from 'react'; -import { ENTITY_LAST_SEEN, ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import { ENTITY_LAST_SEEN } from '@kbn/observability-shared-plugin/common'; import { useArgs } from '@storybook/addons'; import { EntitiesGrid } from '.'; import { entitiesMock } from './mock/entities_mock'; @@ -45,7 +45,7 @@ export const Grid: Story = (args) => { const filteredAndSortedItems = useMemo( () => orderBy( - entityType ? entitiesMock.filter((mock) => mock[ENTITY_TYPE] === entityType) : entitiesMock, + entityType ? entitiesMock.filter((mock) => mock.entity.type === entityType) : entitiesMock, sort.id, sort.direction ), diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx index d5d08ed415a40..5b2c862253672 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/entity_name.test.tsx @@ -9,28 +9,24 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { EntityName } from '.'; import { useDetailViewRedirect } from '../../../hooks/use_detail_view_redirect'; -import { Entity } from '../../../../common/entities'; -import { - ENTITY_DEFINITION_ID, - ENTITY_DISPLAY_NAME, - ENTITY_ID, - ENTITY_IDENTITY_FIELDS, - ENTITY_LAST_SEEN, - ENTITY_TYPE, -} from '@kbn/observability-shared-plugin/common'; +import { InventoryEntityLatest } from '../../../../common/entities'; jest.mock('../../../hooks/use_detail_view_redirect'); const useDetailViewRedirectMock = useDetailViewRedirect as jest.Mock; describe('EntityName', () => { - const mockEntity: Entity = { - [ENTITY_LAST_SEEN]: '2023-10-09T00:00:00Z', - [ENTITY_ID]: '1', - [ENTITY_DISPLAY_NAME]: 'entity_name', - [ENTITY_DEFINITION_ID]: 'entity_definition_id', - [ENTITY_IDENTITY_FIELDS]: ['service.name', 'service.environment'], - [ENTITY_TYPE]: 'service', + const mockEntity: InventoryEntityLatest = { + entity: { + last_seen_timestamp: '2023-10-09T00:00:00Z', + id: '1', + type: 'service', + display_name: 'entity_name', + identity_fields: ['service.name', 'service.environment'], + definition_id: 'entity_definition_id', + definition_version: '1.0.0', + schema_version: '1.0.0', + }, }; beforeEach(() => { diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx index 11c63b62634af..82ba1337bf82a 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entity_name/index.tsx @@ -6,7 +6,8 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; +import { useKibana } from '../../../hooks/use_kibana'; import { InventoryEntityLatest } from '../../../../common/entities'; import { EntityIcon } from '../../entity_icon'; import { useDetailViewRedirect } from '../../../hooks/use_detail_view_redirect'; @@ -27,7 +28,7 @@ export function EntityName({ entity }: EntityNameProps) { const handleLinkClick = useCallback(() => { telemetry.reportEntityViewClicked({ view_type: 'detail', - entity_type: entity['entity.type'], + entity_type: entity.entity.type, }); }, [entity, telemetry]); @@ -38,7 +39,7 @@ export function EntityName({ entity }: EntityNameProps) { - {entity.entity.displayName} + {entity.entity.display_name} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx index 331e19e54fecd..73a918d18155d 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx @@ -107,7 +107,7 @@ export function EntitiesGrid({ values={{ date: ( { let id = 0; @@ -33,38 +25,51 @@ function generateRandomTimestamp() { return randomDate.toISOString(); } -const getEntity = (entityType: string, customFields: Record = {}) => ({ - [ENTITY_LAST_SEEN]: generateRandomTimestamp(), - [ENTITY_TYPE]: entityType, - [ENTITY_DISPLAY_NAME]: faker.person.fullName(), - [ENTITY_ID]: generateId(), - ...customFields, -}); +const indentityFieldsPerType: Record = { + host: ['host.name'], + container: ['container.id'], + service: ['service.name'], +}; -const alertsMock = [ - { - ...getEntity('host'), - alertsCount: 3, - }, - { - ...getEntity('service'), - alertsCount: 3, +const getEntityLatest = ( + entityType: string, + overrides?: Partial +): InventoryEntityLatest => ({ + entity: { + last_seen_timestamp: generateRandomTimestamp(), + type: entityType, + display_name: faker.person.fullName(), + id: generateId(), + definition_id: faker.string.uuid(), + definition_version: '1.0.0', + identity_fields: indentityFieldsPerType[entityType], + schema_version: '1.0.0', + ...(overrides?.entity ? overrides.entity : undefined), }, + ...((overrides ? overrides : {}) as Record), +}); - { - ...getEntity('host'), +const alertsMock: InventoryEntityLatest[] = [ + getEntityLatest('host', { + alertsCount: 1, + }), + getEntityLatest('service', { + alertsCount: 3, + }), + getEntityLatest('host', { alertsCount: 10, - }, - { - ...getEntity('host'), + }), + getEntityLatest('host', { alertsCount: 1, - }, + }), ]; -const hostsMock = Array.from({ length: 20 }, () => getEntity('host', { [CLOUD_PROVIDER]: 'gcp' })); -const containersMock = Array.from({ length: 20 }, () => getEntity('container')); +const hostsMock = Array.from({ length: 20 }, () => + getEntityLatest('host', { cloud: { provider: 'gcp' } }) +); +const containersMock = Array.from({ length: 20 }, () => getEntityLatest('container')); const servicesMock = Array.from({ length: 20 }, () => - getEntity('service', { [AGENT_NAME]: 'java' }) + getEntityLatest('service', { agent: { name: 'java' } }) ); export const entitiesMock = [ @@ -72,4 +77,4 @@ export const entitiesMock = [ ...hostsMock, ...containersMock, ...servicesMock, -] as Entity[]; +] as InventoryEntityLatest[]; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx index 860c6c5ca2e86..8ecb372b2cea3 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx @@ -9,12 +9,8 @@ import React from 'react'; import { type CloudProvider, CloudProviderIcon, AgentIcon } from '@kbn/custom-icons'; import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; import { euiThemeVars } from '@kbn/ui-theme'; -import { - isHostEntity, - type InventoryEntityLatest, - isContainerEntity, - isServiceEntity, -} from '../../../common/entities'; +import type { InventoryEntityLatest } from '../../../common/entities'; +import { isEntityOfType } from '../../../common/utils/entity_type_guards'; interface EntityIconProps { entity: InventoryEntityLatest; @@ -23,7 +19,7 @@ interface EntityIconProps { export function EntityIcon({ entity }: EntityIconProps) { const defaultIconSize = euiThemeVars.euiSizeL; - if (isHostEntity(entity) || isContainerEntity(entity)) { + if (isEntityOfType('host', entity) || isEntityOfType('container', entity)) { const cloudProvider = entity.cloud?.provider; return ( @@ -44,11 +40,11 @@ export function EntityIcon({ entity }: EntityIconProps) { ); } - if (isServiceEntity(entity)) { + if (isEntityOfType('service', entity)) { return ; } - if (entityType.startsWith('kubernetes')) { + if (entity.entity.type.startsWith('kubernetes')) { return ; } diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts index 0cc68bcea5ee7..f74303fc02caa 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts @@ -8,23 +8,20 @@ import { renderHook } from '@testing-library/react-hooks'; import { useDetailViewRedirect } from './use_detail_view_redirect'; import { useKibana } from './use_kibana'; -import { CONTAINER_ID, HOST_NAME, SERVICE_NAME } from '@kbn/observability-shared-plugin/common'; -import { unflattenEntity } from '../../common/utils/unflatten_entity'; +import { ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; import type { InventoryEntityLatest } from '../../common/entities'; jest.mock('./use_kibana'); -jest.mock('../../common/utils/unflatten_entity'); const useKibanaMock = useKibana as jest.Mock; -const unflattenEntityMock = unflattenEntity as jest.Mock; const commonEntityFields: Partial = { - lastSeenTimestamp: '2023-10-09T00:00:00Z', + last_seen_timestamp: '2023-10-09T00:00:00Z', id: '1', - displayName: 'entity_name', - definitionId: 'entity_definition_id', - definitionVersion: '1', - schemaVersion: '1', + display_name: 'entity_name', + definition_id: 'entity_definition_id', + definition_version: '1', + schema_version: '1', }; describe('useDetailViewRedirect', () => { @@ -54,8 +51,6 @@ describe('useDetailViewRedirect', () => { }, }, }); - - unflattenEntityMock.mockImplementation((entity) => entity); }); it('getEntityRedirectUrl should return the correct URL for host entity', () => { @@ -63,7 +58,7 @@ describe('useDetailViewRedirect', () => { entity: { ...(commonEntityFields as InventoryEntityLatest['entity']), type: 'host', - identityFields: ['host.name'], + identity_fields: ['host.name'], }, host: { name: 'host-1', @@ -73,7 +68,7 @@ describe('useDetailViewRedirect', () => { }, }; - mockGetIdentityFieldsValue.mockReturnValue({ [HOST_NAME]: 'host-1' }); + mockGetIdentityFieldsValue.mockReturnValue({ host: { name: 'host-1' } }); mockGetRedirectUrl.mockReturnValue('asset-details-url'); const { result } = renderHook(() => useDetailViewRedirect()); @@ -88,7 +83,7 @@ describe('useDetailViewRedirect', () => { entity: { ...(commonEntityFields as InventoryEntityLatest['entity']), type: 'container', - identityFields: ['container.id'], + identity_fields: ['container.id'], }, container: { id: 'container-1', @@ -98,7 +93,7 @@ describe('useDetailViewRedirect', () => { }, }; - mockGetIdentityFieldsValue.mockReturnValue({ [CONTAINER_ID]: 'container-1' }); + mockGetIdentityFieldsValue.mockReturnValue({ container: { id: 'container-1' } }); mockGetRedirectUrl.mockReturnValue('asset-details-url'); const { result } = renderHook(() => useDetailViewRedirect()); @@ -116,7 +111,7 @@ describe('useDetailViewRedirect', () => { entity: { ...(commonEntityFields as InventoryEntityLatest['entity']), type: 'service', - identityFields: ['service.name'], + identity_fields: ['service.name'], }, agent: { name: 'node', @@ -126,7 +121,7 @@ describe('useDetailViewRedirect', () => { environment: 'prod', }, }; - mockGetIdentityFieldsValue.mockReturnValue({ [SERVICE_NAME]: 'service-1' }); + mockGetIdentityFieldsValue.mockReturnValue({ service: { name: 'service-1' } }); mockGetRedirectUrl.mockReturnValue('service-overview-url'); const { result } = renderHook(() => useDetailViewRedirect()); @@ -155,7 +150,7 @@ describe('useDetailViewRedirect', () => { entity: { ...(commonEntityFields as InventoryEntityLatest['entity']), type: entityType, - identityFields: ['some.field'], + identity_fields: ['some.field'], }, some: { field: 'some-value', diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts index e6ca1a359f81a..a856dcaa9ba99 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts @@ -7,6 +7,7 @@ import { ASSET_DETAILS_LOCATOR_ID, AssetDetailsLocatorParams, + ENTITY_TYPES, SERVICE_OVERVIEW_LOCATOR_ID, ServiceOverviewParams, } from '@kbn/observability-shared-plugin/common'; @@ -15,12 +16,8 @@ import { DashboardLocatorParams } from '@kbn/dashboard-plugin/public'; import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { castArray } from 'lodash'; import { Exception } from 'handlebars'; -import { - isHostEntity, - type InventoryEntityLatest, - isContainerEntity, - isServiceEntity, -} from '../../common/entities'; +import { isEntityOfType } from '../../common/utils/entity_type_guards'; +import { type InventoryEntityLatest } from '../../common/entities'; import { useKibana } from './use_kibana'; const KUBERNETES_DASHBOARDS_IDS: Record = { @@ -47,7 +44,7 @@ export const useDetailViewRedirect = () => { const getSingleIdentityFieldValue = useCallback( (latestEntity: InventoryEntityLatest) => { - const identityFields = castArray(latestEntity.entity.identityFields); + const identityFields = castArray(latestEntity.entity.identity_fields); if (identityFields.length > 1) { throw new Exception( `Multiple identity fields are not supported for ${latestEntity.entity.type}` @@ -64,19 +61,19 @@ export const useDetailViewRedirect = () => { (latestEntity: InventoryEntityLatest) => { const identityValue = getSingleIdentityFieldValue(latestEntity); - if (isHostEntity(latestEntity) || isContainerEntity(latestEntity)) { + if (isEntityOfType('host', latestEntity) || isEntityOfType('container', latestEntity)) { return assetDetailsLocator?.getRedirectUrl({ assetId: identityValue, assetType: latestEntity.entity.type, }); } - if (isServiceEntity(latestEntity)) { + if (isEntityOfType('service', latestEntity)) { return serviceOverviewLocator?.getRedirectUrl({ serviceName: identityValue, // service.environemnt is not part of entity.identityFields // we need to manually get its value - environment: latestEntity.service.environment, + environment: latestEntity.service?.environment, }); } diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts index 40fd25d9ad742..7b59c7064b89e 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identify_fields.test.ts @@ -10,10 +10,10 @@ import { getIdentityFieldsPerEntityType } from './get_identity_fields_per_entity const commonEntityFields: InventoryEntityLatest = { entity: { - lastSeenTimestamp: '2023-10-09T00:00:00Z', + last_seen_timestamp: '2023-10-09T00:00:00Z', id: '1', - displayName: 'entity_name', - definitionId: 'entity_definition_id', + display_name: 'entity_name', + definition_id: 'entity_definition_id', } as InventoryEntityLatest['entity'], alertCount: 3, }; @@ -30,7 +30,7 @@ describe('getIdentityFields', () => { }, entity: { ...commonEntityFields.entity, - identityFields: ['service.name', 'service.environment'], + identity_fields: ['service.name', 'service.environment'], type: 'service', }, service: { @@ -42,7 +42,7 @@ describe('getIdentityFields', () => { ...commonEntityFields, entity: { ...commonEntityFields.entity, - identityFields: ['host.name'], + identity_fields: ['host.name'], type: 'host', }, host: { @@ -57,7 +57,7 @@ describe('getIdentityFields', () => { ...commonEntityFields, entity: { ...commonEntityFields.entity, - identityFields: ['container.id'], + identity_fields: ['container.id'], type: 'container', }, host: { diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identity_fields_per_entity_type.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identity_fields_per_entity_type.ts index b755bc87e530e..c6e5aedf987a5 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identity_fields_per_entity_type.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_identity_fields_per_entity_type.ts @@ -14,7 +14,7 @@ export const getIdentityFieldsPerEntityType = (entities: InventoryEntityLatest[] const identityFieldsPerEntityType = new Map(); entities.forEach((entity) => - identityFieldsPerEntityType.set(entity.entity.type, castArray(entity.entity.identityFields)) + identityFieldsPerEntityType.set(entity.entity.type, castArray(entity.entity.identity_fields)) ); return identityFieldsPerEntityType; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts index 631a544a1ac28..6b22b66ba4c56 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts @@ -61,7 +61,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ logger, plugins, request, - }): Promise<{ entities: Entity[] }> => { + }): Promise<{ entities: InventoryEntityLatest[] }> => { const coreContext = await context.core; const inventoryEsClient = createObservabilityEsClient({ client: coreContext.elasticsearch.client.asCurrentUser,