From 941df5cf73f0d13bb7d32469e3ad7dc6c94774bf Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Mon, 16 Sep 2024 10:54:07 +0100 Subject: [PATCH 01/17] cleaning up --- .../entity_type_list/index.stories.tsx | 88 ----------------- .../components/entity_type_list/index.tsx | 96 ------------------- .../inventory_page_template/index.tsx | 63 ++---------- 3 files changed, 8 insertions(+), 239 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.stories.tsx delete mode 100644 x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.tsx diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.stories.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.stories.tsx deleted file mode 100644 index 570622406c9ae..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.stories.tsx +++ /dev/null @@ -1,88 +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 { Meta, StoryObj } from '@storybook/react'; -import React from 'react'; -import { mergePlainObjects } from '@kbn/investigate-plugin/common'; -import { EntityTypeListBase as Component } from '.'; -import { KibanaReactStorybookDecorator } from '../../../.storybook/storybook_decorator'; - -interface Args { - props: Omit, 'onLockAllClick' | 'onUnlockAllClick'>; -} - -type StoryMeta = Meta; -type Story = StoryObj; - -const meta: StoryMeta = { - component: Component, - title: 'app/Molecules/EntityTypeList', - decorators: [KibanaReactStorybookDecorator], -}; - -export default meta; - -const defaultStory: Story = { - args: { - props: { - definitions: [], - loading: true, - }, - }, - render: function Render(args) { - return ( -
- -
- ); - }, -}; - -export const Default: Story = { - ...defaultStory, - args: { - props: mergePlainObjects(defaultStory.args!.props!, { - loading: false, - definitions: [ - { - icon: 'node', - label: 'Services', - type: 'service', - count: 9, - }, - { - icon: 'pipeNoBreaks', - label: 'Datasets', - type: 'dataset', - count: 11, - }, - ], - }), - }, - name: 'default', -}; - -export const Empty: Story = { - ...defaultStory, - args: { - props: mergePlainObjects(defaultStory.args!.props!, { - definitions: [], - loading: false, - }), - }, - name: 'empty', -}; - -export const Loading: Story = { - ...defaultStory, - args: { - props: mergePlainObjects(defaultStory.args!.props!, { - loading: true, - }), - }, - name: 'loading', -}; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.tsx deleted file mode 100644 index 47488f23f3252..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_type_list/index.tsx +++ /dev/null @@ -1,96 +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 React from 'react'; -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; -import { - EuiBadge, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiLoadingSpinner, - EuiText, -} from '@elastic/eui'; -import { useKibana } from '../../hooks/use_kibana'; -import { EntityTypeDefinition } from '../../../common/entities'; -import { useInventoryRouter } from '../../hooks/use_inventory_router'; - -export function EntityTypeListItem({ - href, - icon, - label, - count, -}: { - href: string; - icon: string; - label: string; - count: number; -}) { - return ( - - - - - - - {label} - - - {count} - - - - ); -} - -export function EntityTypeListBase({ - definitions, - loading, - error, -}: { - loading?: boolean; - definitions?: EntityTypeDefinition[]; - error?: Error; -}) { - const router = useInventoryRouter(); - if (loading) { - return ; - } - - return ( - - {definitions?.map((definition) => { - return ( - - ); - })} - - ); -} - -export function EntityTypeList() { - const { - services: { inventoryAPIClient }, - } = useKibana(); - - const { value, loading, error } = useAbortableAsync( - ({ signal }) => { - return inventoryAPIClient.fetch('GET /internal/inventory/entity_types', { - signal, - }); - }, - [inventoryAPIClient] - ); - - return ; -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx index 386df9a51cae5..4dd8eaf3899ee 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx @@ -4,13 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiFlexGroup, EuiPanel, EuiTitle } from '@elastic/eui'; -import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; -import { useTheme } from '@kbn/observability-utils/hooks/use_theme'; import React from 'react'; import { useKibana } from '../../hooks/use_kibana'; -import { EntityTypeList } from '../entity_type_list'; export function InventoryPageTemplate({ children }: { children: React.ReactNode }) { const { @@ -19,60 +15,17 @@ export function InventoryPageTemplate({ children }: { children: React.ReactNode }, } = useKibana(); - const { PageTemplate } = observabilityShared.navigation; - - const theme = useTheme(); + const { PageTemplate: ObservabilityPageTemplate } = observabilityShared.navigation; return ( - - - - - -

- {i18n.translate('xpack.inventory.inventoryPageHeaderLabel', { - defaultMessage: 'Inventory', - })} -

-
- - - -
-
- - - {children} - -
-
+ {children} + ); } From 0b8b97328ea3003fc4cb9d49ee43979da2dd677e Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Mon, 16 Sep 2024 11:17:48 +0100 Subject: [PATCH 02/17] inventory page and grid base --- .../public/components/entities_grid/index.tsx | 16 ++++++++++++++++ .../public/pages/inventory_page/index.tsx | 16 ++++++++++++++++ .../inventory/public/routes/config.tsx | 3 ++- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx 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 new file mode 100644 index 0000000000000..404d7a29aeb2a --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx @@ -0,0 +1,16 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React from 'react'; + +export function EntitiesGrid() { + return ( +
+ {i18n.translate('xpack.inventory.entitiesGrid.div.caueLabel', { defaultMessage: 'Caue' })} +
+ ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx new file mode 100644 index 0000000000000..9389fdaca3ea0 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx @@ -0,0 +1,16 @@ +/* + * 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 React from 'react'; +import { EntitiesGrid } from '../../components/entities_grid'; + +export function InventoryPage() { + return ( +
+ +
+ ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx index 11d9d4836d981..74eeaac220bc2 100644 --- a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx @@ -8,6 +8,7 @@ import * as t from 'io-ts'; import { createRouter, Outlet } from '@kbn/typed-react-router-config'; import React from 'react'; import { InventoryPageTemplate } from '../components/inventory_page_template'; +import { InventoryPage } from '../pages/inventory_page'; /** * The array of route definitions to be used when the application @@ -28,7 +29,7 @@ const inventoryRoutes = { }), }, '/': { - element: <>, + element: , }, }, }, From 05e3991cfc634ffe10ad78e97001b4b1431267b8 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Mon, 16 Sep 2024 14:03:16 +0100 Subject: [PATCH 03/17] server --- .../inventory/common/entities.ts | 30 ++++--- .../public/components/entities_grid/index.tsx | 60 +++++++++++++- .../create_entities_es_client.ts | 80 +++++++++++++++++++ .../routes/entities/get_latest_entities.ts | 27 +++++++ .../inventory/server/routes/entities/route.ts | 33 ++++---- .../inventory/server/utils/with_apm_span.ts | 7 ++ 6 files changed, 203 insertions(+), 34 deletions(-) create mode 100644 x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts create mode 100644 x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts create mode 100644 x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index af0e5c82b978f..d72fa46969b8a 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -5,16 +5,22 @@ * 2.0. */ -export interface EntityTypeDefinition { - type: string; - label: string; - icon: string; - count: number; -} - -export interface EntityDefinition { - type: string; - field: string; - filter?: string; - index: string[]; +export interface LatestEntity { + agent: { + name: string[]; + }; + data_stream: { + type: string[]; + }; + cloud: { + availability_zone: string[]; + }; + entity: { + firstSeenTimestamp: string; + lastSeenTimestamp: string; + type: string; + displayName: string; + id: string; + identityFields: string[]; + }; } 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 404d7a29aeb2a..e689063882c40 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 @@ -4,13 +4,65 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { + EuiDataGrid, + EuiDataGridCellValueElementProps, + EuiDataGridColumn, + EuiLoadingSpinner, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import React, { useState } from 'react'; +import { useKibana } from '../../hooks/use_kibana'; + +const columns: EuiDataGridColumn[] = [ + { + id: 'entityName', + displayAsText: 'Entity name', + }, + { + id: 'entityType', + displayAsText: 'Type', + }, +]; export function EntitiesGrid() { + const { + services: { inventoryAPIClient }, + } = useKibana(); + const [visibleColumns, setVisibleColumns] = useState(columns.map(({ id }) => id)); + const { value = { entities: [] }, loading } = useAbortableAsync( + ({ signal }) => { + return inventoryAPIClient.fetch('GET /internal/inventory/entities', { + signal, + }); + }, + [inventoryAPIClient] + ); + + if (loading) { + return ; + } + + function CellValue({ rowIndex, columnId, setCellProps }: EuiDataGridCellValueElementProps) { + const data = value.entities[rowIndex]; + if (data === undefined) { + return null; + } + + return <>{data.entity.displayName}; + } + return ( -
- {i18n.translate('xpack.inventory.entitiesGrid.div.caueLabel', { defaultMessage: 'Caue' })} -
+ ); } diff --git a/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts b/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts new file mode 100644 index 0000000000000..018e3a4e28a8c --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts @@ -0,0 +1,80 @@ +/* + * 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 { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; +import type { KibanaRequest } from '@kbn/core/server'; +import { ElasticsearchClient } from '@kbn/core/server'; +import { entitiesAliasPattern, ENTITY_LATEST } from '@kbn/entities-schema'; +import { unwrapEsResponse } from '@kbn/observability-plugin/common/utils/unwrap_es_response'; +import { withApmSpan } from '../../utils/with_apm_span'; + +const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ + type: '*', + dataset: ENTITY_LATEST, +}); + +export function cancelEsRequestOnAbort>( + promise: T, + request: KibanaRequest, + controller: AbortController +): T { + const subscription = request.events.aborted$.subscribe(() => { + controller.abort(); + }); + + return promise.finally(() => subscription.unsubscribe()) as T; +} + +export interface EntitiesESClient { + searchLatest( + operationName: string, + searchRequest: TSearchRequest + ): Promise>; +} + +export function createEntitiesESClient({ + request, + esClient, +}: { + request: KibanaRequest; + esClient: ElasticsearchClient; +}) { + function search( + indexName: string, + operationName: string, + searchRequest: TSearchRequest + ): Promise> { + const controller = new AbortController(); + + const promise = withApmSpan(operationName, () => { + return cancelEsRequestOnAbort( + esClient.search( + { ...searchRequest, index: [indexName], ignore_unavailable: true }, + { + signal: controller.signal, + meta: true, + } + ) as unknown as Promise<{ + body: InferSearchResponseOf; + }>, + request, + controller + ); + }); + + return unwrapEsResponse(promise); + } + + return { + searchLatest( + operationName: string, + searchRequest: TSearchRequest + ): Promise> { + return search(ENTITIES_LATEST_ALIAS, operationName, searchRequest); + }, + }; +} diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts new file mode 100644 index 0000000000000..4ddcaaf75c9a4 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -0,0 +1,27 @@ +/* + * 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 { LatestEntity } from '../../../common/entities'; +import { EntitiesESClient } from '../../lib/create_es_client/create_entities_es_client'; + +const MAX_NUMBER_OF_ENTITIES = 500; + +export async function getLatestEntities({ + entitiesESClient, +}: { + entitiesESClient: EntitiesESClient; +}) { + const response = ( + await entitiesESClient.searchLatest('get_latest_entities', { + body: { + size: MAX_NUMBER_OF_ENTITIES, + }, + }) + ).hits.hits.map((hit) => hit._source); + + return response; +} 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 0622ed32ac9dc..093e5ff399ed1 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 @@ -4,31 +4,28 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { i18n } from '@kbn/i18n'; -import type { EntityTypeDefinition } from '../../../common/entities'; import { createInventoryServerRoute } from '../create_inventory_server_route'; +import { createEntitiesESClient } from '../../lib/create_es_client/create_entities_es_client'; +import { getLatestEntities } from './get_latest_entities'; -export const listEntityTypesRoute = createInventoryServerRoute({ - endpoint: 'GET /internal/inventory/entity_types', +export const listLatestEntitiesRoute = createInventoryServerRoute({ + endpoint: 'GET /internal/inventory/entities', options: { tags: ['access:inventory'], }, - handler: async ({ plugins, request }): Promise<{ definitions: EntityTypeDefinition[] }> => { - return { - definitions: [ - { - label: i18n.translate('xpack.inventory.entityTypeLabels.datasets', { - defaultMessage: 'Datasets', - }), - icon: 'pipeNoBreaks', - type: 'dataset', - count: 0, - }, - ], - }; + handler: async ({ plugins, request, context }) => { + const coreContext = await context.core; + const entitiesESClient = createEntitiesESClient({ + esClient: coreContext.elasticsearch.client.asCurrentUser, + request, + }); + + const latestEntities = await getLatestEntities({ entitiesESClient }); + + return { entities: latestEntities }; }, }); export const entitiesRoutes = { - ...listEntityTypesRoute, + ...listLatestEntitiesRoute, }; diff --git a/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts b/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts new file mode 100644 index 0000000000000..f852c8cc102b0 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ +export { withApmSpan } from '@kbn/apm-data-access-plugin/server/utils'; From 1b0f65c456091952d5c8e9cf9825867927ad3ad7 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:14:27 +0000 Subject: [PATCH 04/17] [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' --- .../plugins/observability_solution/inventory/tsconfig.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index 89fdd2e8fdf01..3e1cf4ef7c51c 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -24,7 +24,6 @@ "@kbn/server-route-repository", "@kbn/shared-ux-link-redirect-app", "@kbn/typed-react-router-config", - "@kbn/investigate-plugin", "@kbn/observability-utils", "@kbn/kibana-react-plugin", "@kbn/i18n", @@ -35,5 +34,9 @@ "@kbn/data-views-plugin", "@kbn/server-route-repository-client", "@kbn/react-kibana-context-render", + "@kbn/es-types", + "@kbn/entities-schema", + "@kbn/observability-plugin", + "@kbn/apm-data-access-plugin", ] } From 36e9611f5c64200315ccd018a4c180725bf12190 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Mon, 16 Sep 2024 15:03:11 +0100 Subject: [PATCH 05/17] fixing deps --- .../server/lib/create_es_client/create_entities_es_client.ts | 2 +- x-pack/plugins/observability_solution/inventory/tsconfig.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts b/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts index 018e3a4e28a8c..d73987adeaecc 100644 --- a/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts +++ b/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts @@ -9,7 +9,7 @@ import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import type { KibanaRequest } from '@kbn/core/server'; import { ElasticsearchClient } from '@kbn/core/server'; import { entitiesAliasPattern, ENTITY_LATEST } from '@kbn/entities-schema'; -import { unwrapEsResponse } from '@kbn/observability-plugin/common/utils/unwrap_es_response'; +import { unwrapEsResponse } from '@kbn/observability-shared-plugin/common/utils/unwrap_es_response'; import { withApmSpan } from '../../utils/with_apm_span'; const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index 3e1cf4ef7c51c..093eba5baab85 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -36,7 +36,6 @@ "@kbn/react-kibana-context-render", "@kbn/es-types", "@kbn/entities-schema", - "@kbn/observability-plugin", "@kbn/apm-data-access-plugin", ] } From 218b977e87f5901a01881029d9066ef6227d9c6f Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Tue, 17 Sep 2024 15:00:50 +0100 Subject: [PATCH 06/17] refactoring and adding esql --- .../client/create_observability_es_client.ts | 24 +++++- .../es/utils/esql_result_to_plain_objects.ts | 20 +++++ .../inventory/common/entities.ts | 26 ------ .../public/components/entities_grid/index.tsx | 21 ++++- .../create_entities_es_client.ts | 80 ------------------- .../routes/entities/get_latest_entities.ts | 38 ++++++--- .../inventory/server/routes/entities/route.ts | 13 +-- .../inventory/server/utils/with_apm_span.ts | 7 -- 8 files changed, 96 insertions(+), 133 deletions(-) create mode 100644 x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts delete mode 100644 x-pack/plugins/observability_solution/inventory/common/entities.ts delete mode 100644 x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts delete mode 100644 x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts diff --git a/x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts b/x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts index 2e57653365b0b..0011e0f17c1c0 100644 --- a/x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts +++ b/x-pack/packages/observability/observability_utils/es/client/create_observability_es_client.ts @@ -6,8 +6,9 @@ */ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; -import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; +import type { ESQLSearchResponse, ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { withSpan } from '@kbn/apm-utils'; +import type { EsqlQueryRequest } from '@elastic/elasticsearch/lib/api/types'; type SearchRequest = ESSearchRequest & { index: string | string[]; @@ -24,6 +25,7 @@ export interface ObservabilityElasticsearchClient { operationName: string, parameters: TSearchRequest ): Promise>; + esql(operationName: string, parameters: EsqlQueryRequest): Promise; client: ElasticsearchClient; } @@ -38,6 +40,26 @@ export function createObservabilityEsClient({ }): ObservabilityElasticsearchClient { return { client, + esql(operationName: string, parameters: EsqlQueryRequest) { + logger.trace(() => `Request (${operationName}):\n${JSON.stringify(parameters, null, 2)}`); + return withSpan({ name: operationName, labels: { plugin } }, () => { + return client.esql.query( + { ...parameters }, + { + querystring: { + drop_null_columns: true, + }, + } + ); + }) + .then((response) => { + logger.trace(() => `Response (${operationName}):\n${JSON.stringify(response, null, 2)}`); + return response as unknown as ESQLSearchResponse; + }) + .catch((error) => { + throw error; + }); + }, search( operationName: string, parameters: SearchRequest diff --git a/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts b/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts new file mode 100644 index 0000000000000..ad48bcb311b25 --- /dev/null +++ b/x-pack/packages/observability/observability_utils/es/utils/esql_result_to_plain_objects.ts @@ -0,0 +1,20 @@ +/* + * 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 { ESQLSearchResponse } from '@kbn/es-types'; + +export function esqlResultToPlainObjects>( + result: ESQLSearchResponse +): T[] { + return result.values.map((row) => { + return row.reduce>((acc, value, index) => { + const column = result.columns[index]; + acc[column.name] = value; + return acc; + }, {}); + }) as T[]; +} diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts deleted file mode 100644 index d72fa46969b8a..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ /dev/null @@ -1,26 +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. - */ - -export interface LatestEntity { - agent: { - name: string[]; - }; - data_stream: { - type: string[]; - }; - cloud: { - availability_zone: string[]; - }; - entity: { - firstSeenTimestamp: string; - lastSeenTimestamp: string; - type: string; - displayName: string; - id: string; - identityFields: string[]; - }; -} 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 e689063882c40..93ce19b873007 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 @@ -24,6 +24,14 @@ const columns: EuiDataGridColumn[] = [ id: 'entityType', displayAsText: 'Type', }, + { + id: 'availablityZone', + displayAsText: 'Availability zone', + }, + { + id: 'lastSeen', + displayAsText: 'Last seen', + }, ]; export function EntitiesGrid() { @@ -50,7 +58,18 @@ export function EntitiesGrid() { return null; } - return <>{data.entity.displayName}; + switch (columnId) { + case 'entityName': + return data.entity.displayName; + case 'entityType': + return data.data_stream.type; + case 'availablityZone': + return data.cloud?.availability_zone || 'N/A'; + case 'lastSeen': + return data.entity.lastSeenTimestamp; + default: + return 'N/A'; + } } return ( diff --git a/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts b/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts deleted file mode 100644 index d73987adeaecc..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/server/lib/create_es_client/create_entities_es_client.ts +++ /dev/null @@ -1,80 +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 { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; -import type { KibanaRequest } from '@kbn/core/server'; -import { ElasticsearchClient } from '@kbn/core/server'; -import { entitiesAliasPattern, ENTITY_LATEST } from '@kbn/entities-schema'; -import { unwrapEsResponse } from '@kbn/observability-shared-plugin/common/utils/unwrap_es_response'; -import { withApmSpan } from '../../utils/with_apm_span'; - -const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ - type: '*', - dataset: ENTITY_LATEST, -}); - -export function cancelEsRequestOnAbort>( - promise: T, - request: KibanaRequest, - controller: AbortController -): T { - const subscription = request.events.aborted$.subscribe(() => { - controller.abort(); - }); - - return promise.finally(() => subscription.unsubscribe()) as T; -} - -export interface EntitiesESClient { - searchLatest( - operationName: string, - searchRequest: TSearchRequest - ): Promise>; -} - -export function createEntitiesESClient({ - request, - esClient, -}: { - request: KibanaRequest; - esClient: ElasticsearchClient; -}) { - function search( - indexName: string, - operationName: string, - searchRequest: TSearchRequest - ): Promise> { - const controller = new AbortController(); - - const promise = withApmSpan(operationName, () => { - return cancelEsRequestOnAbort( - esClient.search( - { ...searchRequest, index: [indexName], ignore_unavailable: true }, - { - signal: controller.signal, - meta: true, - } - ) as unknown as Promise<{ - body: InferSearchResponseOf; - }>, - request, - controller - ); - }); - - return unwrapEsResponse(promise); - } - - return { - searchLatest( - operationName: string, - searchRequest: TSearchRequest - ): Promise> { - return search(ENTITIES_LATEST_ALIAS, operationName, searchRequest); - }, - }; -} diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 4ddcaaf75c9a4..3583bf914ed38 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -5,23 +5,37 @@ * 2.0. */ -import { LatestEntity } from '../../../common/entities'; -import { EntitiesESClient } from '../../lib/create_es_client/create_entities_es_client'; +import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import { esqlResultToPlainObjects } from '@kbn/observability-utils/es/utils/esql_result_to_plain_objects'; +import { ENTITY_LATEST, entitiesAliasPattern } from '@kbn/entities-schema'; + +const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ + type: '*', + dataset: ENTITY_LATEST, +}); const MAX_NUMBER_OF_ENTITIES = 500; +interface LatestEntity { + 'entity.lastSeenTimestamp': string; + 'entity.type': string; + 'entity.displayName': string; + 'entity.id': string; +} export async function getLatestEntities({ - entitiesESClient, + inventoryEsClient, }: { - entitiesESClient: EntitiesESClient; + inventoryEsClient: ObservabilityElasticsearchClient; }) { - const response = ( - await entitiesESClient.searchLatest('get_latest_entities', { - body: { - size: MAX_NUMBER_OF_ENTITIES, - }, - }) - ).hits.hits.map((hit) => hit._source); + const latestEntitiesEsqlResponse = await inventoryEsClient.esql('get_latest_entities', { + query: `FROM ${ENTITIES_LATEST_ALIAS} + | WHERE entity.type IN ("service", "host", "container") + | WHERE entity.definitionId IN ("builtin_services_from_ecs_data", "builtin_hosts_from_ecs_data", "builtin_containers_from_ecs_data") + | SORT entity.lastSeenTimestamp DESC + | LIMIT ${MAX_NUMBER_OF_ENTITIES} + | KEEP entity.id, entity.displayName, entity.lastSeenTimestamp, entity.type + `, + }); - return response; + return esqlResultToPlainObjects(latestEntitiesEsqlResponse); } 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 093e5ff399ed1..c5695aaf14718 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 @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; import { createInventoryServerRoute } from '../create_inventory_server_route'; -import { createEntitiesESClient } from '../../lib/create_es_client/create_entities_es_client'; import { getLatestEntities } from './get_latest_entities'; export const listLatestEntitiesRoute = createInventoryServerRoute({ @@ -13,14 +13,15 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ options: { tags: ['access:inventory'], }, - handler: async ({ plugins, request, context }) => { + handler: async ({ context, logger }) => { const coreContext = await context.core; - const entitiesESClient = createEntitiesESClient({ - esClient: coreContext.elasticsearch.client.asCurrentUser, - request, + const inventoryEsClient = createObservabilityEsClient({ + client: coreContext.elasticsearch.client.asCurrentUser, + logger, + plugin: '@kbn/inventory-plugin', }); - const latestEntities = await getLatestEntities({ entitiesESClient }); + const latestEntities = await getLatestEntities({ inventoryEsClient }); return { entities: latestEntities }; }, diff --git a/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts b/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts deleted file mode 100644 index f852c8cc102b0..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts +++ /dev/null @@ -1,7 +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. - */ -export { withApmSpan } from '@kbn/apm-data-access-plugin/server/utils'; From 51ee09c27394169e92ef5db2700d7db001a7c196 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 10:47:43 +0100 Subject: [PATCH 07/17] entities grid --- .../inventory/common/entities.ts | 17 + .../inventory/common/es_fields/entities.ts | 11 + .../entities_grid/entities_grid.stories.tsx | 45 + .../public/components/entities_grid/index.tsx | 171 +- .../entities_grid/mock/entities_mock.ts | 3014 +++++++++++++++++ .../public/pages/inventory_page/index.tsx | 59 +- .../inventory/public/routes/config.tsx | 16 + .../routes/entities/get_latest_entities.ts | 30 +- .../inventory/server/routes/entities/route.ts | 21 +- 9 files changed, 3336 insertions(+), 48 deletions(-) create mode 100644 x-pack/plugins/observability_solution/inventory/common/entities.ts create mode 100644 x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx create mode 100644 x-pack/plugins/observability_solution/inventory/public/components/entities_grid/mock/entities_mock.ts diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts new file mode 100644 index 0000000000000..d8353cf3a97f0 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -0,0 +1,17 @@ +/* + * 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 * as t from 'io-ts'; + +export const entityTypeRt = t.union([ + t.literal('service'), + t.literal('host'), + t.literal('container'), +]); + +export type EntityType = t.TypeOf; + +export const MAX_NUMBER_OF_ENTITIES = 500; diff --git a/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts b/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts new file mode 100644 index 0000000000000..5376bbe9cedcb --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export const ENTITY_LAST_SEEN = 'entity.lastSeenTimestamp'; +export const ENTITY_ID = 'entity.id'; +export const ENTITY_TYPE = 'entity.type'; +export const ENTITY_DISPLAY_NAME = 'entity.displayName'; 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 new file mode 100644 index 0000000000000..3a895c1ac71ed --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx @@ -0,0 +1,45 @@ +/* + * 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 { EuiDataGridSorting } from '@elastic/eui'; +import { Meta, Story } from '@storybook/react'; +import React, { useMemo, useState } from 'react'; +import { orderBy } from 'lodash'; +import { EntitiesGrid } from '.'; +import { ENTITY_LAST_SEEN } from '../../../common/es_fields/entities'; +import { entitiesMock } from './mock/entities_mock'; + +const stories: Meta<{}> = { + title: 'app/inventory/entities_grid', + component: EntitiesGrid, +}; +export default stories; + +export const Example: Story<{}> = () => { + const [pageIndex, setPageIndex] = useState(0); + const [sort, setSort] = useState({ + id: ENTITY_LAST_SEEN, + direction: 'desc', + }); + + const sortedItems = useMemo( + () => orderBy(entitiesMock, sort.id, sort.direction), + [sort.direction, sort.id] + ); + + return ( + + ); +}; 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 93ce19b873007..3d3a3cb3c7d0f 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 @@ -5,73 +5,136 @@ * 2.0. */ import { + EuiBadge, EuiDataGrid, EuiDataGridCellValueElementProps, EuiDataGridColumn, + EuiDataGridSorting, + EuiLink, EuiLoadingSpinner, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; -import React, { useState } from 'react'; -import { useKibana } from '../../hooks/use_kibana'; +import { FormattedDate, FormattedMessage, FormattedTime } from '@kbn/i18n-react'; +import { last } from 'lodash'; +import React, { useCallback, useState } from 'react'; +import { + ENTITY_DISPLAY_NAME, + ENTITY_LAST_SEEN, + ENTITY_TYPE, +} from '../../../common/es_fields/entities'; +import { APIReturnType } from '../../api'; +import { MAX_NUMBER_OF_ENTITIES } from '../../../common/entities'; + +type InventoryEntitiesAPIReturnType = APIReturnType<'GET /internal/inventory/entities'>; + +type EntityColumnIds = typeof ENTITY_DISPLAY_NAME | typeof ENTITY_LAST_SEEN | typeof ENTITY_TYPE; const columns: EuiDataGridColumn[] = [ { - id: 'entityName', + id: ENTITY_DISPLAY_NAME, displayAsText: 'Entity name', + isSortable: true, }, { - id: 'entityType', + id: ENTITY_TYPE, displayAsText: 'Type', + isSortable: true, }, { - id: 'availablityZone', - displayAsText: 'Availability zone', - }, - { - id: 'lastSeen', + id: ENTITY_LAST_SEEN, displayAsText: 'Last seen', + defaultSortDirection: 'desc', + isSortable: true, + schema: 'datetime', }, ]; -export function EntitiesGrid() { - const { - services: { inventoryAPIClient }, - } = useKibana(); +interface Props { + loading: boolean; + entities: InventoryEntitiesAPIReturnType['entities']; + sortDirection: 'asc' | 'desc'; + sortField: string; + pageIndex: number; + onChangeSort: (sorting: EuiDataGridSorting['columns'][0]) => void; + onChangePage: (nextPage: number) => void; +} + +const PAGE_SIZE = 20; + +export function EntitiesGrid({ + entities, + loading, + sortDirection, + sortField, + pageIndex, + onChangePage, + onChangeSort, +}: Props) { const [visibleColumns, setVisibleColumns] = useState(columns.map(({ id }) => id)); - const { value = { entities: [] }, loading } = useAbortableAsync( - ({ signal }) => { - return inventoryAPIClient.fetch('GET /internal/inventory/entities', { - signal, - }); + + const onSort: EuiDataGridSorting['onSort'] = useCallback( + (newSortingColumns) => { + const lastItem = last(newSortingColumns); + if (lastItem) { + onChangeSort(lastItem); + } }, - [inventoryAPIClient] + [onChangeSort] ); if (loading) { return ; } - function CellValue({ rowIndex, columnId, setCellProps }: EuiDataGridCellValueElementProps) { - const data = value.entities[rowIndex]; - if (data === undefined) { + function CellValue({ rowIndex, columnId }: EuiDataGridCellValueElementProps) { + const entity = entities[rowIndex]; + if (entity === undefined) { return null; } - switch (columnId) { - case 'entityName': - return data.entity.displayName; - case 'entityType': - return data.data_stream.type; - case 'availablityZone': - return data.cloud?.availability_zone || 'N/A'; - case 'lastSeen': - return data.entity.lastSeenTimestamp; + const columnEntityTableId = columnId as EntityColumnIds; + switch (columnEntityTableId) { + case ENTITY_TYPE: + return {entity[columnEntityTableId]}; + case ENTITY_LAST_SEEN: + return ( + + ), + time: ( + + ), + }} + /> + ); + case ENTITY_DISPLAY_NAME: + return ( + // TODO: link to the appropriate page based on entity type https://github.com/elastic/kibana/issues/192676 + {entity[columnEntityTableId]} + ); default: - return 'N/A'; + return entity[columnId as EntityColumnIds] || ''; } } + const currentPage = pageIndex + 1; + return ( + + {pageIndex * PAGE_SIZE + 1}-{PAGE_SIZE * currentPage} + + ), + total: MAX_NUMBER_OF_ENTITIES, + boldEntites: ( + + {i18n.translate( + 'xpack.inventory.entitiesGrid.euiDataGrid.headerLeft.entites', + { defaultMessage: 'Entities' } + )} + + ), + }} + /> + + ), + }, + }, + }} + sorting={{ columns: [{ id: sortField, direction: sortDirection }], onSort }} + pagination={{ + pageIndex, + pageSize: PAGE_SIZE, + onChangeItemsPerPage: () => {}, + onChangePage, + pageSizeOptions: [], + }} /> ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/mock/entities_mock.ts b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/mock/entities_mock.ts new file mode 100644 index 0000000000000..16fb73be75534 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/mock/entities_mock.ts @@ -0,0 +1,3014 @@ +/* + * 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 { APIReturnType } from '../../../api'; + +type InventoryEntitiesAPIReturnType = APIReturnType<'GET /internal/inventory/entities'>; + +export const entitiesMock: InventoryEntitiesAPIReturnType['entities'] = [ + { + 'entity.lastSeenTimestamp': '2023-08-20T10:50:06.384Z', + 'entity.type': 'host', + 'entity.displayName': 'Spider-Man', + 'entity.id': '0', + }, + { + 'entity.lastSeenTimestamp': '2024-06-16T21:48:16.259Z', + 'entity.type': 'service', + 'entity.displayName': 'Iron Man', + 'entity.id': '1', + }, + { + 'entity.lastSeenTimestamp': '2024-04-28T03:31:57.528Z', + 'entity.type': 'host', + 'entity.displayName': 'Captain America', + 'entity.id': '2', + }, + { + 'entity.lastSeenTimestamp': '2024-05-14T11:32:04.275Z', + 'entity.type': 'host', + 'entity.displayName': 'Hulk', + 'entity.id': '3', + }, + { + 'entity.lastSeenTimestamp': '2023-12-05T13:33:54.028Z', + 'entity.type': 'container', + 'entity.displayName': 'Thor', + 'entity.id': '4', + }, + { + 'entity.lastSeenTimestamp': '2023-11-27T06:18:52.650Z', + 'entity.type': 'service', + 'entity.displayName': 'Black Widow', + 'entity.id': '5', + }, + { + 'entity.lastSeenTimestamp': '2023-06-23T21:20:41.460Z', + 'entity.type': 'container', + 'entity.displayName': 'Batman', + 'entity.id': '6', + }, + { + 'entity.lastSeenTimestamp': '2023-12-08T03:23:09.317Z', + 'entity.type': 'service', + 'entity.displayName': 'Superman', + 'entity.id': '7', + }, + { + 'entity.lastSeenTimestamp': '2024-08-07T19:06:52.169Z', + 'entity.type': 'service', + 'entity.displayName': 'Wonder Woman', + 'entity.id': '8', + }, + { + 'entity.lastSeenTimestamp': '2024-08-15T01:15:23.589Z', + 'entity.type': 'container', + 'entity.displayName': 'Aquaman', + 'entity.id': '9', + }, + { + 'entity.lastSeenTimestamp': '2024-05-18T09:44:35.799Z', + 'entity.type': 'service', + 'entity.displayName': 'Flash', + 'entity.id': '10', + }, + { + 'entity.lastSeenTimestamp': '2023-12-20T19:12:29.251Z', + 'entity.type': 'container', + 'entity.displayName': 'Cyborg', + 'entity.id': '11', + }, + { + 'entity.lastSeenTimestamp': '2024-04-04T02:52:28.431Z', + 'entity.type': 'container', + 'entity.displayName': 'Wolverine', + 'entity.id': '12', + }, + { + 'entity.lastSeenTimestamp': '2023-07-14T05:13:12.906Z', + 'entity.type': 'host', + 'entity.displayName': 'Deadpool', + 'entity.id': '13', + }, + { + 'entity.lastSeenTimestamp': '2023-07-21T07:30:55.389Z', + 'entity.type': 'service', + 'entity.displayName': 'Green Lantern', + 'entity.id': '14', + }, + { + 'entity.lastSeenTimestamp': '2024-06-16T09:30:32.331Z', + 'entity.type': 'service', + 'entity.displayName': 'Doctor Strange', + 'entity.id': '15', + }, + { + 'entity.lastSeenTimestamp': '2023-08-24T08:05:46.687Z', + 'entity.type': 'container', + 'entity.displayName': 'Ant-Man', + 'entity.id': '16', + }, + { + 'entity.lastSeenTimestamp': '2024-03-23T09:37:36.874Z', + 'entity.type': 'service', + 'entity.displayName': 'Scarlet Witch', + 'entity.id': '17', + }, + { + 'entity.lastSeenTimestamp': '2023-05-12T02:34:46.188Z', + 'entity.type': 'host', + 'entity.displayName': 'Black Panther', + 'entity.id': '18', + }, + { + 'entity.lastSeenTimestamp': '2023-01-05T07:16:17.213Z', + 'entity.type': 'container', + 'entity.displayName': 'Captain Marvel', + 'entity.id': '19', + }, + { + 'entity.lastSeenTimestamp': '2024-05-28T04:08:43.047Z', + 'entity.type': 'host', + 'entity.displayName': 'Hawkeye', + 'entity.id': '20', + }, + { + 'entity.lastSeenTimestamp': '2024-04-23T02:01:01.149Z', + 'entity.type': 'service', + 'entity.displayName': 'Vision', + 'entity.id': '21', + }, + { + 'entity.lastSeenTimestamp': '2023-04-08T10:40:14.658Z', + 'entity.type': 'host', + 'entity.displayName': 'Shazam', + 'entity.id': '22', + }, + { + 'entity.lastSeenTimestamp': '2024-01-11T09:03:11.465Z', + 'entity.type': 'service', + 'entity.displayName': 'Nightwing', + 'entity.id': '23', + }, + { + 'entity.lastSeenTimestamp': '2024-04-27T22:35:18.822Z', + 'entity.type': 'container', + 'entity.displayName': 'Robin', + 'entity.id': '24', + }, + { + 'entity.lastSeenTimestamp': '2023-03-09T22:05:08.071Z', + 'entity.type': 'container', + 'entity.displayName': 'Starfire', + 'entity.id': '25', + }, + { + 'entity.lastSeenTimestamp': '2024-08-09T13:20:31.960Z', + 'entity.type': 'service', + 'entity.displayName': 'Beast Boy', + 'entity.id': '26', + }, + { + 'entity.lastSeenTimestamp': '2024-07-12T01:44:33.204Z', + 'entity.type': 'service', + 'entity.displayName': 'Raven', + 'entity.id': '27', + }, + { + 'entity.lastSeenTimestamp': '2023-01-31T00:08:53.817Z', + 'entity.type': 'service', + 'entity.displayName': 'Daredevil', + 'entity.id': '28', + }, + { + 'entity.lastSeenTimestamp': '2024-03-26T08:37:11.019Z', + 'entity.type': 'container', + 'entity.displayName': 'Luke Cage', + 'entity.id': '29', + }, + { + 'entity.lastSeenTimestamp': '2023-05-17T08:49:09.112Z', + 'entity.type': 'service', + 'entity.displayName': 'Jessica Jones', + 'entity.id': '30', + }, + { + 'entity.lastSeenTimestamp': '2024-06-15T20:05:12.395Z', + 'entity.type': 'service', + 'entity.displayName': 'Punisher', + 'entity.id': '31', + }, + { + 'entity.lastSeenTimestamp': '2024-07-30T06:53:16.477Z', + 'entity.type': 'service', + 'entity.displayName': 'Groot', + 'entity.id': '32', + }, + { + 'entity.lastSeenTimestamp': '2024-06-01T13:22:53.973Z', + 'entity.type': 'host', + 'entity.displayName': 'Rocket Raccoon', + 'entity.id': '33', + }, + { + 'entity.lastSeenTimestamp': '2024-09-12T17:44:12.492Z', + 'entity.type': 'container', + 'entity.displayName': 'Gamora', + 'entity.id': '34', + }, + { + 'entity.lastSeenTimestamp': '2024-03-28T13:44:52.732Z', + 'entity.type': 'service', + 'entity.displayName': 'Drax', + 'entity.id': '35', + }, + { + 'entity.lastSeenTimestamp': '2023-09-19T01:20:23.901Z', + 'entity.type': 'container', + 'entity.displayName': 'Mantis', + 'entity.id': '36', + }, + { + 'entity.lastSeenTimestamp': '2023-01-17T07:04:52.387Z', + 'entity.type': 'service', + 'entity.displayName': 'Winter Soldier', + 'entity.id': '37', + }, + { + 'entity.lastSeenTimestamp': '2023-10-07T15:08:39.776Z', + 'entity.type': 'host', + 'entity.displayName': 'Falcon', + 'entity.id': '38', + }, + { + 'entity.lastSeenTimestamp': '2024-05-01T17:45:43.595Z', + 'entity.type': 'host', + 'entity.displayName': 'Silver Surfer', + 'entity.id': '39', + }, + { + 'entity.lastSeenTimestamp': '2023-01-12T19:33:15.526Z', + 'entity.type': 'host', + 'entity.displayName': 'Moon Knight', + 'entity.id': '40', + }, + { + 'entity.lastSeenTimestamp': '2023-03-28T23:24:20.896Z', + 'entity.type': 'container', + 'entity.displayName': 'She-Hulk', + 'entity.id': '41', + }, + { + 'entity.lastSeenTimestamp': '2023-03-15T09:52:58.134Z', + 'entity.type': 'container', + 'entity.displayName': 'Blade', + 'entity.id': '42', + }, + { + 'entity.lastSeenTimestamp': '2023-04-18T07:38:32.158Z', + 'entity.type': 'container', + 'entity.displayName': 'Ghost Rider', + 'entity.id': '43', + }, + { + 'entity.lastSeenTimestamp': '2024-03-16T16:36:47.704Z', + 'entity.type': 'host', + 'entity.displayName': 'Cyclops', + 'entity.id': '44', + }, + { + 'entity.lastSeenTimestamp': '2023-06-11T13:40:02.951Z', + 'entity.type': 'service', + 'entity.displayName': 'Jean Grey', + 'entity.id': '45', + }, + { + 'entity.lastSeenTimestamp': '2024-09-11T23:54:53.129Z', + 'entity.type': 'container', + 'entity.displayName': 'Storm', + 'entity.id': '46', + }, + { + 'entity.lastSeenTimestamp': '2024-03-31T15:26:58.694Z', + 'entity.type': 'host', + 'entity.displayName': 'Iceman', + 'entity.id': '47', + }, + { + 'entity.lastSeenTimestamp': '2023-01-15T05:36:56.655Z', + 'entity.type': 'host', + 'entity.displayName': 'Colossus', + 'entity.id': '48', + }, + { + 'entity.lastSeenTimestamp': '2024-06-01T22:59:08.883Z', + 'entity.type': 'service', + 'entity.displayName': 'Kitty Pryde', + 'entity.id': '49', + }, + { + 'entity.lastSeenTimestamp': '2024-04-16T21:38:10.398Z', + 'entity.type': 'container', + 'entity.displayName': 'Psylocke', + 'entity.id': '50', + }, + { + 'entity.lastSeenTimestamp': '2023-02-13T07:41:37.539Z', + 'entity.type': 'container', + 'entity.displayName': 'Rogue', + 'entity.id': '51', + }, + { + 'entity.lastSeenTimestamp': '2023-12-11T14:40:29.422Z', + 'entity.type': 'service', + 'entity.displayName': 'Professor X', + 'entity.id': '52', + }, + { + 'entity.lastSeenTimestamp': '2023-03-06T09:50:33.183Z', + 'entity.type': 'host', + 'entity.displayName': 'Magneto', + 'entity.id': '53', + }, + { + 'entity.lastSeenTimestamp': '2024-06-30T14:52:19.840Z', + 'entity.type': 'host', + 'entity.displayName': 'Quicksilver', + 'entity.id': '54', + }, + { + 'entity.lastSeenTimestamp': '2023-08-16T01:03:06.855Z', + 'entity.type': 'container', + 'entity.displayName': 'Scarlet Witch', + 'entity.id': '55', + }, + { + 'entity.lastSeenTimestamp': '2023-12-19T23:23:08.821Z', + 'entity.type': 'host', + 'entity.displayName': 'Black Bolt', + 'entity.id': '56', + }, + { + 'entity.lastSeenTimestamp': '2024-01-04T06:04:23.837Z', + 'entity.type': 'service', + 'entity.displayName': 'Medusa', + 'entity.id': '57', + }, + { + 'entity.lastSeenTimestamp': '2024-01-02T11:03:36.265Z', + 'entity.type': 'container', + 'entity.displayName': 'Crystal', + 'entity.id': '58', + }, + { + 'entity.lastSeenTimestamp': '2023-01-14T04:12:51.710Z', + 'entity.type': 'service', + 'entity.displayName': 'Karnak', + 'entity.id': '59', + }, + { + 'entity.lastSeenTimestamp': '2023-09-16T15:31:25.215Z', + 'entity.type': 'container', + 'entity.displayName': 'Gorgon', + 'entity.id': '60', + }, + { + 'entity.lastSeenTimestamp': '2023-03-19T23:21:32.571Z', + 'entity.type': 'container', + 'entity.displayName': 'Triton', + 'entity.id': '61', + }, + { + 'entity.lastSeenTimestamp': '2024-02-08T21:57:35.600Z', + 'entity.type': 'host', + 'entity.displayName': 'Lockjaw', + 'entity.id': '62', + }, + { + 'entity.lastSeenTimestamp': '2024-02-26T03:18:43.161Z', + 'entity.type': 'container', + 'entity.displayName': 'Namor', + 'entity.id': '63', + }, + { + 'entity.lastSeenTimestamp': '2024-03-13T13:39:54.430Z', + 'entity.type': 'host', + 'entity.displayName': 'Hercules', + 'entity.id': '64', + }, + { + 'entity.lastSeenTimestamp': '2024-06-15T15:57:15.557Z', + 'entity.type': 'host', + 'entity.displayName': 'Valkyrie', + 'entity.id': '65', + }, + { + 'entity.lastSeenTimestamp': '2023-09-14T15:29:09.268Z', + 'entity.type': 'host', + 'entity.displayName': 'Sif', + 'entity.id': '66', + }, + { + 'entity.lastSeenTimestamp': '2023-06-06T11:32:45.998Z', + 'entity.type': 'service', + 'entity.displayName': 'Heimdall', + 'entity.id': '67', + }, + { + 'entity.lastSeenTimestamp': '2023-06-23T20:19:29.918Z', + 'entity.type': 'container', + 'entity.displayName': 'Loki', + 'entity.id': '68', + }, + { + 'entity.lastSeenTimestamp': '2024-02-15T19:08:56.703Z', + 'entity.type': 'service', + 'entity.displayName': 'Odin', + 'entity.id': '69', + }, + { + 'entity.lastSeenTimestamp': '2024-05-05T21:13:36.761Z', + 'entity.type': 'host', + 'entity.displayName': 'Enchantress', + 'entity.id': '70', + }, + { + 'entity.lastSeenTimestamp': '2023-07-29T20:51:41.023Z', + 'entity.type': 'container', + 'entity.displayName': 'Executioner', + 'entity.id': '71', + }, + { + 'entity.lastSeenTimestamp': '2023-08-06T17:17:53.101Z', + 'entity.type': 'container', + 'entity.displayName': 'Balder', + 'entity.id': '72', + }, + { + 'entity.lastSeenTimestamp': '2023-07-03T05:18:36.705Z', + 'entity.type': 'container', + 'entity.displayName': 'Beta Ray Bill', + 'entity.id': '73', + }, + { + 'entity.lastSeenTimestamp': '2023-05-26T14:32:39.569Z', + 'entity.type': 'container', + 'entity.displayName': 'Adam Warlock', + 'entity.id': '74', + }, + { + 'entity.lastSeenTimestamp': '2023-04-22T20:19:48.018Z', + 'entity.type': 'host', + 'entity.displayName': 'Ego the Living Planet', + 'entity.id': '75', + }, + { + 'entity.lastSeenTimestamp': '2024-09-01T05:03:37.465Z', + 'entity.type': 'container', + 'entity.displayName': 'Ronan the Accuser', + 'entity.id': '76', + }, + { + 'entity.lastSeenTimestamp': '2024-03-30T18:51:01.608Z', + 'entity.type': 'service', + 'entity.displayName': 'Nebula', + 'entity.id': '77', + }, + { + 'entity.lastSeenTimestamp': '2023-08-03T00:46:22.909Z', + 'entity.type': 'container', + 'entity.displayName': 'Yondu', + 'entity.id': '78', + }, + { + 'entity.lastSeenTimestamp': '2024-03-22T19:27:42.105Z', + 'entity.type': 'container', + 'entity.displayName': 'Star-Lord', + 'entity.id': '79', + }, + { + 'entity.lastSeenTimestamp': '2023-03-01T12:52:43.009Z', + 'entity.type': 'service', + 'entity.displayName': 'Elektra', + 'entity.id': '80', + }, + { + 'entity.lastSeenTimestamp': '2024-03-01T03:35:49.365Z', + 'entity.type': 'container', + 'entity.displayName': 'Bullseye', + 'entity.id': '81', + }, + { + 'entity.lastSeenTimestamp': '2023-04-23T03:29:05.951Z', + 'entity.type': 'service', + 'entity.displayName': 'Kingpin', + 'entity.id': '82', + }, + { + 'entity.lastSeenTimestamp': '2023-08-19T14:56:49.093Z', + 'entity.type': 'container', + 'entity.displayName': 'Iron Fist', + 'entity.id': '83', + }, + { + 'entity.lastSeenTimestamp': '2023-04-17T09:03:32.311Z', + 'entity.type': 'service', + 'entity.displayName': 'Misty Knight', + 'entity.id': '84', + }, + { + 'entity.lastSeenTimestamp': '2024-06-23T06:42:12.471Z', + 'entity.type': 'service', + 'entity.displayName': 'Colleen Wing', + 'entity.id': '85', + }, + { + 'entity.lastSeenTimestamp': '2023-10-20T10:59:37.573Z', + 'entity.type': 'host', + 'entity.displayName': 'Shang-Chi', + 'entity.id': '86', + }, + { + 'entity.lastSeenTimestamp': '2024-01-18T10:07:55.134Z', + 'entity.type': 'host', + 'entity.displayName': 'Black Cat', + 'entity.id': '87', + }, + { + 'entity.lastSeenTimestamp': '2024-09-04T14:02:31.795Z', + 'entity.type': 'container', + 'entity.displayName': 'Silver Sable', + 'entity.id': '88', + }, + { + 'entity.lastSeenTimestamp': '2023-09-21T16:08:59.195Z', + 'entity.type': 'container', + 'entity.displayName': 'Spider-Woman', + 'entity.id': '89', + }, + { + 'entity.lastSeenTimestamp': '2024-07-12T00:22:45.521Z', + 'entity.type': 'container', + 'entity.displayName': 'Dr. Nick', + 'entity.id': '90', + }, + { + 'entity.lastSeenTimestamp': '2023-06-27T20:43:47.331Z', + 'entity.type': 'container', + 'entity.displayName': 'Miles Morales', + 'entity.id': '91', + }, + { + 'entity.lastSeenTimestamp': '2023-11-15T05:35:28.421Z', + 'entity.type': 'host', + 'entity.displayName': 'Spider-Girl', + 'entity.id': '92', + }, + { + 'entity.lastSeenTimestamp': '2023-07-17T13:28:37.477Z', + 'entity.type': 'container', + 'entity.displayName': 'Nova', + 'entity.id': '93', + }, + { + 'entity.lastSeenTimestamp': '2024-05-13T09:58:21.185Z', + 'entity.type': 'container', + 'entity.displayName': 'Quasar', + 'entity.id': '94', + }, + { + 'entity.lastSeenTimestamp': '2023-09-22T18:29:20.589Z', + 'entity.type': 'container', + 'entity.displayName': 'Mar-Vell', + 'entity.id': '95', + }, + { + 'entity.lastSeenTimestamp': '2024-04-29T21:33:36.318Z', + 'entity.type': 'container', + 'entity.displayName': 'Monica Rambeau', + 'entity.id': '96', + }, + { + 'entity.lastSeenTimestamp': '2024-01-10T17:12:02.785Z', + 'entity.type': 'host', + 'entity.displayName': 'Photon', + 'entity.id': '97', + }, + { + 'entity.lastSeenTimestamp': '2024-08-03T04:59:46.730Z', + 'entity.type': 'container', + 'entity.displayName': 'Blue Marvel', + 'entity.id': '98', + }, + { + 'entity.lastSeenTimestamp': '2023-04-22T05:48:54.665Z', + 'entity.type': 'host', + 'entity.displayName': 'Sentry', + 'entity.id': '99', + }, + { + 'entity.lastSeenTimestamp': '2024-05-08T05:53:56.652Z', + 'entity.type': 'host', + 'entity.displayName': 'Hyperion', + 'entity.id': '100', + }, + { + 'entity.lastSeenTimestamp': '2024-08-21T08:45:38.667Z', + 'entity.type': 'service', + 'entity.displayName': 'Nighthawk', + 'entity.id': '101', + }, + { + 'entity.lastSeenTimestamp': '2024-08-15T14:03:39.798Z', + 'entity.type': 'host', + 'entity.displayName': 'Power Princess', + 'entity.id': '102', + }, + { + 'entity.lastSeenTimestamp': '2024-05-01T13:28:15.225Z', + 'entity.type': 'service', + 'entity.displayName': 'Doctor Spectrum', + 'entity.id': '103', + }, + { + 'entity.lastSeenTimestamp': '2023-01-21T21:03:45.309Z', + 'entity.type': 'container', + 'entity.displayName': 'Speed Demon', + 'entity.id': '104', + }, + { + 'entity.lastSeenTimestamp': '2023-03-29T06:15:14.140Z', + 'entity.type': 'container', + 'entity.displayName': 'Whizzer', + 'entity.id': '105', + }, + { + 'entity.lastSeenTimestamp': '2024-01-25T09:23:14.336Z', + 'entity.type': 'container', + 'entity.displayName': 'Scarlet Spider', + 'entity.id': '106', + }, + { + 'entity.lastSeenTimestamp': '2023-08-07T16:59:31.739Z', + 'entity.type': 'host', + 'entity.displayName': 'Kaine', + 'entity.id': '107', + }, + { + 'entity.lastSeenTimestamp': '2024-03-11T20:29:44.832Z', + 'entity.type': 'host', + 'entity.displayName': 'Ben Reilly', + 'entity.id': '108', + }, + { + 'entity.lastSeenTimestamp': '2023-05-08T00:40:17.226Z', + 'entity.type': 'service', + 'entity.displayName': 'Spider-Man 2099', + 'entity.id': '109', + }, + { + 'entity.lastSeenTimestamp': '2023-01-13T19:15:54.781Z', + 'entity.type': 'service', + 'entity.displayName': 'Spider-Ham', + 'entity.id': '110', + }, + { + 'entity.lastSeenTimestamp': '2024-09-02T15:35:26.309Z', + 'entity.type': 'container', + 'entity.displayName': 'Ultimate Spider-Man', + 'entity.id': '111', + }, + { + 'entity.lastSeenTimestamp': '2023-06-04T16:08:36.902Z', + 'entity.type': 'container', + 'entity.displayName': 'Spider-Man Noir', + 'entity.id': '112', + }, + { + 'entity.lastSeenTimestamp': '2023-02-12T13:28:29.732Z', + 'entity.type': 'service', + 'entity.displayName': 'Superior Spider-Man', + 'entity.id': '113', + }, + { + 'entity.lastSeenTimestamp': '2023-08-16T08:54:36.219Z', + 'entity.type': 'service', + 'entity.displayName': 'Agent Venom', + 'entity.id': '114', + }, + { + 'entity.lastSeenTimestamp': '2023-02-23T12:58:57.715Z', + 'entity.type': 'container', + 'entity.displayName': 'Venom', + 'entity.id': '115', + }, + { + 'entity.lastSeenTimestamp': '2023-06-19T18:17:35.424Z', + 'entity.type': 'container', + 'entity.displayName': 'Carnage', + 'entity.id': '116', + }, + { + 'entity.lastSeenTimestamp': '2024-05-02T11:58:44.239Z', + 'entity.type': 'service', + 'entity.displayName': 'Toxin', + 'entity.id': '117', + }, + { + 'entity.lastSeenTimestamp': '2023-12-27T14:15:59.641Z', + 'entity.type': 'host', + 'entity.displayName': 'Anti-Venom', + 'entity.id': '118', + }, + { + 'entity.lastSeenTimestamp': '2024-01-10T15:23:44.536Z', + 'entity.type': 'container', + 'entity.displayName': 'Morbius', + 'entity.id': '119', + }, + { + 'entity.lastSeenTimestamp': '2023-11-26T01:04:11.090Z', + 'entity.type': 'service', + 'entity.displayName': 'Kraven the Hunter', + 'entity.id': '120', + }, + { + 'entity.lastSeenTimestamp': '2024-02-21T04:11:13.221Z', + 'entity.type': 'container', + 'entity.displayName': 'The Lizard', + 'entity.id': '121', + }, + { + 'entity.lastSeenTimestamp': '2023-12-31T07:29:14.344Z', + 'entity.type': 'service', + 'entity.displayName': 'Sandman', + 'entity.id': '122', + }, + { + 'entity.lastSeenTimestamp': '2024-06-02T11:20:40.793Z', + 'entity.type': 'host', + 'entity.displayName': 'Rhino', + 'entity.id': '123', + }, + { + 'entity.lastSeenTimestamp': '2023-04-02T14:31:44.296Z', + 'entity.type': 'host', + 'entity.displayName': 'Shocker', + 'entity.id': '124', + }, + { + 'entity.lastSeenTimestamp': '2024-06-10T12:26:05.411Z', + 'entity.type': 'container', + 'entity.displayName': 'Vulture', + 'entity.id': '125', + }, + { + 'entity.lastSeenTimestamp': '2023-06-27T16:17:19.611Z', + 'entity.type': 'container', + 'entity.displayName': 'Mysterio', + 'entity.id': '126', + }, + { + 'entity.lastSeenTimestamp': '2023-08-29T04:54:25.898Z', + 'entity.type': 'service', + 'entity.displayName': 'Scorpion', + 'entity.id': '127', + }, + { + 'entity.lastSeenTimestamp': '2023-01-17T21:39:41.265Z', + 'entity.type': 'host', + 'entity.displayName': 'Chameleon', + 'entity.id': '128', + }, + { + 'entity.lastSeenTimestamp': '2023-06-07T03:03:11.032Z', + 'entity.type': 'host', + 'entity.displayName': 'Green Goblin', + 'entity.id': '129', + }, + { + 'entity.lastSeenTimestamp': '2023-05-19T19:18:21.005Z', + 'entity.type': 'service', + 'entity.displayName': 'Hobgoblin', + 'entity.id': '130', + }, + { + 'entity.lastSeenTimestamp': '2023-08-03T20:45:51.404Z', + 'entity.type': 'host', + 'entity.displayName': 'Demogoblin', + 'entity.id': '131', + }, + { + 'entity.lastSeenTimestamp': '2024-01-11T06:14:51.570Z', + 'entity.type': 'service', + 'entity.displayName': 'Red Goblin', + 'entity.id': '132', + }, + { + 'entity.lastSeenTimestamp': '2024-03-27T11:07:02.657Z', + 'entity.type': 'host', + 'entity.displayName': 'Doctor Octopus', + 'entity.id': '133', + }, + { + 'entity.lastSeenTimestamp': '2023-08-17T08:42:02.024Z', + 'entity.type': 'container', + 'entity.displayName': 'Electro', + 'entity.id': '134', + }, + { + 'entity.lastSeenTimestamp': '2023-07-02T16:02:17.438Z', + 'entity.type': 'container', + 'entity.displayName': 'Kingpin', + 'entity.id': '135', + }, + { + 'entity.lastSeenTimestamp': '2024-05-17T22:14:53.375Z', + 'entity.type': 'host', + 'entity.displayName': 'Tombstone', + 'entity.id': '136', + }, + { + 'entity.lastSeenTimestamp': '2023-05-30T09:26:45.647Z', + 'entity.type': 'service', + 'entity.displayName': 'Hammerhead', + 'entity.id': '137', + }, + { + 'entity.lastSeenTimestamp': '2024-09-08T03:21:22.494Z', + 'entity.type': 'host', + 'entity.displayName': 'Silvermane', + 'entity.id': '138', + }, + { + 'entity.lastSeenTimestamp': '2023-06-26T06:23:45.305Z', + 'entity.type': 'host', + 'entity.displayName': 'Hydro-Man', + 'entity.id': '139', + }, + { + 'entity.lastSeenTimestamp': '2024-08-15T13:29:01.603Z', + 'entity.type': 'host', + 'entity.displayName': 'Molten Man', + 'entity.id': '140', + }, + { + 'entity.lastSeenTimestamp': '2023-06-21T04:25:12.371Z', + 'entity.type': 'container', + 'entity.displayName': 'Morlun', + 'entity.id': '141', + }, + { + 'entity.lastSeenTimestamp': '2023-11-01T02:59:06.998Z', + 'entity.type': 'host', + 'entity.displayName': 'The Jackal', + 'entity.id': '142', + }, + { + 'entity.lastSeenTimestamp': '2023-06-25T15:27:39.801Z', + 'entity.type': 'service', + 'entity.displayName': 'Alistair Smythe', + 'entity.id': '143', + }, + { + 'entity.lastSeenTimestamp': '2023-12-07T19:13:02.711Z', + 'entity.type': 'service', + 'entity.displayName': 'The Beetle', + 'entity.id': '144', + }, + { + 'entity.lastSeenTimestamp': '2024-04-13T14:16:24.875Z', + 'entity.type': 'host', + 'entity.displayName': 'The Prowler', + 'entity.id': '145', + }, + { + 'entity.lastSeenTimestamp': '2023-11-02T20:25:05.117Z', + 'entity.type': 'host', + 'entity.displayName': 'Tarantula', + 'entity.id': '146', + }, + { + 'entity.lastSeenTimestamp': '2023-04-12T19:09:48.881Z', + 'entity.type': 'service', + 'entity.displayName': 'Black Tarantula', + 'entity.id': '147', + }, + { + 'entity.lastSeenTimestamp': '2024-01-25T01:37:16.115Z', + 'entity.type': 'host', + 'entity.displayName': 'White Tiger', + 'entity.id': '148', + }, + { + 'entity.lastSeenTimestamp': '2023-12-20T12:27:21.819Z', + 'entity.type': 'service', + 'entity.displayName': 'Nightcrawler', + 'entity.id': '149', + }, + { + 'entity.lastSeenTimestamp': '2024-06-11T05:30:01.226Z', + 'entity.type': 'container', + 'entity.displayName': 'Bishop', + 'entity.id': '150', + }, + { + 'entity.lastSeenTimestamp': '2023-09-24T00:18:40.137Z', + 'entity.type': 'service', + 'entity.displayName': 'Cable', + 'entity.id': '151', + }, + { + 'entity.lastSeenTimestamp': '2024-04-24T03:28:16.162Z', + 'entity.type': 'host', + 'entity.displayName': 'Domino', + 'entity.id': '152', + }, + { + 'entity.lastSeenTimestamp': '2023-04-08T07:23:33.921Z', + 'entity.type': 'host', + 'entity.displayName': 'Warpath', + 'entity.id': '153', + }, + { + 'entity.lastSeenTimestamp': '2023-04-12T23:26:45.533Z', + 'entity.type': 'service', + 'entity.displayName': 'Sunspot', + 'entity.id': '154', + }, + { + 'entity.lastSeenTimestamp': '2024-05-18T14:28:01.751Z', + 'entity.type': 'container', + 'entity.displayName': 'Cannonball', + 'entity.id': '155', + }, + { + 'entity.lastSeenTimestamp': '2023-03-14T17:08:06.243Z', + 'entity.type': 'container', + 'entity.displayName': 'Wolfsbane', + 'entity.id': '156', + }, + { + 'entity.lastSeenTimestamp': '2024-02-25T23:18:49.867Z', + 'entity.type': 'service', + 'entity.displayName': 'Magik', + 'entity.id': '157', + }, + { + 'entity.lastSeenTimestamp': '2024-07-14T14:31:58.080Z', + 'entity.type': 'container', + 'entity.displayName': 'Colossus', + 'entity.id': '158', + }, + { + 'entity.lastSeenTimestamp': '2023-05-09T22:32:41.723Z', + 'entity.type': 'container', + 'entity.displayName': 'Omega Red', + 'entity.id': '159', + }, + { + 'entity.lastSeenTimestamp': '2023-05-21T10:33:50.732Z', + 'entity.type': 'host', + 'entity.displayName': 'Juggernaut', + 'entity.id': '160', + }, + { + 'entity.lastSeenTimestamp': '2024-05-01T07:27:51.647Z', + 'entity.type': 'host', + 'entity.displayName': 'Sebastian Shaw', + 'entity.id': '161', + }, + { + 'entity.lastSeenTimestamp': '2024-01-25T09:47:54.565Z', + 'entity.type': 'service', + 'entity.displayName': 'Emma Frost', + 'entity.id': '162', + }, + { + 'entity.lastSeenTimestamp': '2023-10-25T15:51:18.513Z', + 'entity.type': 'host', + 'entity.displayName': 'Mystique', + 'entity.id': '163', + }, + { + 'entity.lastSeenTimestamp': '2023-03-27T07:26:04.804Z', + 'entity.type': 'service', + 'entity.displayName': 'Sabretooth', + 'entity.id': '164', + }, + { + 'entity.lastSeenTimestamp': '2024-07-22T15:29:51.446Z', + 'entity.type': 'host', + 'entity.displayName': 'Pyro', + 'entity.id': '165', + }, + { + 'entity.lastSeenTimestamp': '2024-06-26T09:09:57.169Z', + 'entity.type': 'host', + 'entity.displayName': 'Avalanche', + 'entity.id': '166', + }, + { + 'entity.lastSeenTimestamp': '2023-10-27T05:14:15.279Z', + 'entity.type': 'container', + 'entity.displayName': 'Destiny', + 'entity.id': '167', + }, + { + 'entity.lastSeenTimestamp': '2023-03-08T00:40:52.990Z', + 'entity.type': 'service', + 'entity.displayName': 'Forge', + 'entity.id': '168', + }, + { + 'entity.lastSeenTimestamp': '2023-11-05T16:40:30.510Z', + 'entity.type': 'host', + 'entity.displayName': 'Polaris', + 'entity.id': '169', + }, + { + 'entity.lastSeenTimestamp': '2024-08-12T05:04:27.632Z', + 'entity.type': 'service', + 'entity.displayName': 'Havok', + 'entity.id': '170', + }, + { + 'entity.lastSeenTimestamp': '2023-01-29T18:30:34.000Z', + 'entity.type': 'service', + 'entity.displayName': 'Multiple Man', + 'entity.id': '171', + }, + { + 'entity.lastSeenTimestamp': '2023-12-18T13:11:26.940Z', + 'entity.type': 'service', + 'entity.displayName': 'Strong Guy', + 'entity.id': '172', + }, + { + 'entity.lastSeenTimestamp': '2024-01-07T16:44:23.323Z', + 'entity.type': 'container', + 'entity.displayName': 'Feral', + 'entity.id': '173', + }, + { + 'entity.lastSeenTimestamp': '2023-03-19T22:38:34.493Z', + 'entity.type': 'container', + 'entity.displayName': 'Boom Boom', + 'entity.id': '174', + }, + { + 'entity.lastSeenTimestamp': '2023-05-31T07:23:57.500Z', + 'entity.type': 'container', + 'entity.displayName': 'Warlock', + 'entity.id': '175', + }, + { + 'entity.lastSeenTimestamp': '2024-07-11T01:57:10.851Z', + 'entity.type': 'host', + 'entity.displayName': 'Magus', + 'entity.id': '176', + }, + { + 'entity.lastSeenTimestamp': '2024-05-22T12:50:09.849Z', + 'entity.type': 'container', + 'entity.displayName': 'Blink', + 'entity.id': '177', + }, + { + 'entity.lastSeenTimestamp': '2023-10-20T11:56:09.004Z', + 'entity.type': 'service', + 'entity.displayName': 'Nocturne', + 'entity.id': '178', + }, + { + 'entity.lastSeenTimestamp': '2023-02-08T06:47:37.958Z', + 'entity.type': 'host', + 'entity.displayName': 'Morph', + 'entity.id': '179', + }, + { + 'entity.lastSeenTimestamp': '2023-09-16T01:14:58.701Z', + 'entity.type': 'host', + 'entity.displayName': 'Sunfire', + 'entity.id': '180', + }, + { + 'entity.lastSeenTimestamp': '2023-12-05T19:56:38.483Z', + 'entity.type': 'service', + 'entity.displayName': 'Thunderbird', + 'entity.id': '181', + }, + { + 'entity.lastSeenTimestamp': '2024-01-21T04:49:41.995Z', + 'entity.type': 'host', + 'entity.displayName': 'Banshee', + 'entity.id': '182', + }, + { + 'entity.lastSeenTimestamp': '2023-10-19T02:58:03.939Z', + 'entity.type': 'container', + 'entity.displayName': 'Syrin', + 'entity.id': '183', + }, + { + 'entity.lastSeenTimestamp': '2023-05-21T14:13:08.847Z', + 'entity.type': 'host', + 'entity.displayName': 'Moira MacTaggert', + 'entity.id': '184', + }, + { + 'entity.lastSeenTimestamp': '2024-02-09T05:57:59.984Z', + 'entity.type': 'container', + 'entity.displayName': 'Angel', + 'entity.id': '185', + }, + { + 'entity.lastSeenTimestamp': '2024-05-05T04:42:36.419Z', + 'entity.type': 'service', + 'entity.displayName': 'Archangel', + 'entity.id': '186', + }, + { + 'entity.lastSeenTimestamp': '2024-02-10T11:42:58.833Z', + 'entity.type': 'service', + 'entity.displayName': 'Iceman', + 'entity.id': '187', + }, + { + 'entity.lastSeenTimestamp': '2024-07-25T19:55:46.838Z', + 'entity.type': 'host', + 'entity.displayName': 'Beast', + 'entity.id': '188', + }, + { + 'entity.lastSeenTimestamp': '2024-09-11T05:07:10.339Z', + 'entity.type': 'host', + 'entity.displayName': 'Nightcrawler', + 'entity.id': '189', + }, + { + 'entity.lastSeenTimestamp': '2023-10-19T15:59:49.360Z', + 'entity.type': 'service', + 'entity.displayName': 'Phoenix', + 'entity.id': '190', + }, + { + 'entity.lastSeenTimestamp': '2024-09-07T17:32:26.019Z', + 'entity.type': 'host', + 'entity.displayName': 'X-Man', + 'entity.id': '191', + }, + { + 'entity.lastSeenTimestamp': '2023-07-13T12:49:11.603Z', + 'entity.type': 'container', + 'entity.displayName': 'Cable', + 'entity.id': '192', + }, + { + 'entity.lastSeenTimestamp': '2024-05-19T21:32:30.970Z', + 'entity.type': 'service', + 'entity.displayName': 'Deadpool', + 'entity.id': '193', + }, + { + 'entity.lastSeenTimestamp': '2023-12-12T00:33:27.870Z', + 'entity.type': 'host', + 'entity.displayName': 'Domino', + 'entity.id': '194', + }, + { + 'entity.lastSeenTimestamp': '2023-08-26T18:34:55.709Z', + 'entity.type': 'host', + 'entity.displayName': 'Shatterstar', + 'entity.id': '195', + }, + { + 'entity.lastSeenTimestamp': '2024-08-05T13:02:27.932Z', + 'entity.type': 'service', + 'entity.displayName': 'Warpath', + 'entity.id': '196', + }, + { + 'entity.lastSeenTimestamp': '2023-08-08T08:09:37.053Z', + 'entity.type': 'service', + 'entity.displayName': 'Rictor', + 'entity.id': '197', + }, + { + 'entity.lastSeenTimestamp': '2024-07-18T17:17:22.628Z', + 'entity.type': 'service', + 'entity.displayName': 'Boom Boom', + 'entity.id': '198', + }, + { + 'entity.lastSeenTimestamp': '2023-06-19T20:45:15.240Z', + 'entity.type': 'host', + 'entity.displayName': 'Magik', + 'entity.id': '199', + }, + { + 'entity.lastSeenTimestamp': '2023-07-29T15:18:44.936Z', + 'entity.type': 'container', + 'entity.displayName': 'Cannonball', + 'entity.id': '200', + }, + { + 'entity.lastSeenTimestamp': '2023-02-08T01:26:18.603Z', + 'entity.type': 'host', + 'entity.displayName': 'Sunspot', + 'entity.id': '201', + }, + { + 'entity.lastSeenTimestamp': '2023-02-22T16:06:39.387Z', + 'entity.type': 'service', + 'entity.displayName': 'Banshee', + 'entity.id': '202', + }, + { + 'entity.lastSeenTimestamp': '2023-04-27T03:32:37.015Z', + 'entity.type': 'host', + 'entity.displayName': 'Thunderbird', + 'entity.id': '203', + }, + { + 'entity.lastSeenTimestamp': '2023-09-08T13:07:04.895Z', + 'entity.type': 'service', + 'entity.displayName': 'X-23', + 'entity.id': '204', + }, + { + 'entity.lastSeenTimestamp': '2024-02-08T06:28:33.208Z', + 'entity.type': 'container', + 'entity.displayName': 'Daken', + 'entity.id': '205', + }, + { + 'entity.lastSeenTimestamp': '2024-01-19T19:28:19.416Z', + 'entity.type': 'host', + 'entity.displayName': 'Laura Kinney', + 'entity.id': '206', + }, + { + 'entity.lastSeenTimestamp': '2024-01-29T07:33:26.920Z', + 'entity.type': 'service', + 'entity.displayName': 'Jubilee', + 'entity.id': '207', + }, + { + 'entity.lastSeenTimestamp': '2023-02-20T10:19:34.322Z', + 'entity.type': 'host', + 'entity.displayName': 'Stepford Cuckoos', + 'entity.id': '208', + }, + { + 'entity.lastSeenTimestamp': '2024-06-03T03:31:08.704Z', + 'entity.type': 'service', + 'entity.displayName': 'Fantomex', + 'entity.id': '209', + }, + { + 'entity.lastSeenTimestamp': '2023-10-30T18:18:12.254Z', + 'entity.type': 'container', + 'entity.displayName': 'Marrow', + 'entity.id': '210', + }, + { + 'entity.lastSeenTimestamp': '2024-03-19T23:47:02.611Z', + 'entity.type': 'service', + 'entity.displayName': 'Pixie', + 'entity.id': '211', + }, + { + 'entity.lastSeenTimestamp': '2023-08-08T06:03:05.326Z', + 'entity.type': 'host', + 'entity.displayName': 'Armor', + 'entity.id': '212', + }, + { + 'entity.lastSeenTimestamp': '2023-04-05T11:25:37.426Z', + 'entity.type': 'service', + 'entity.displayName': 'Gentle', + 'entity.id': '213', + }, + { + 'entity.lastSeenTimestamp': '2023-01-10T22:18:30.812Z', + 'entity.type': 'container', + 'entity.displayName': 'Anole', + 'entity.id': '214', + }, + { + 'entity.lastSeenTimestamp': '2024-07-17T06:09:51.763Z', + 'entity.type': 'host', + 'entity.displayName': 'Rockslide', + 'entity.id': '215', + }, + { + 'entity.lastSeenTimestamp': '2024-02-02T00:44:56.270Z', + 'entity.type': 'host', + 'entity.displayName': 'Dust', + 'entity.id': '216', + }, + { + 'entity.lastSeenTimestamp': '2023-03-09T19:37:54.235Z', + 'entity.type': 'host', + 'entity.displayName': 'Mercury', + 'entity.id': '217', + }, + { + 'entity.lastSeenTimestamp': '2024-06-14T09:51:29.579Z', + 'entity.type': 'service', + 'entity.displayName': 'Surge', + 'entity.id': '218', + }, + { + 'entity.lastSeenTimestamp': '2024-03-12T17:28:48.254Z', + 'entity.type': 'host', + 'entity.displayName': 'Hellion', + 'entity.id': '219', + }, + { + 'entity.lastSeenTimestamp': '2023-04-09T07:19:02.429Z', + 'entity.type': 'service', + 'entity.displayName': 'Elixir', + 'entity.id': '220', + }, + { + 'entity.lastSeenTimestamp': '2024-05-10T08:28:21.025Z', + 'entity.type': 'host', + 'entity.displayName': 'X-23', + 'entity.id': '221', + }, + { + 'entity.lastSeenTimestamp': '2023-05-01T16:23:41.343Z', + 'entity.type': 'host', + 'entity.displayName': 'Prodigy', + 'entity.id': '222', + }, + { + 'entity.lastSeenTimestamp': '2023-02-03T07:17:47.909Z', + 'entity.type': 'container', + 'entity.displayName': 'Blindfold', + 'entity.id': '223', + }, + { + 'entity.lastSeenTimestamp': '2023-06-15T00:56:00.094Z', + 'entity.type': 'service', + 'entity.displayName': 'Ink', + 'entity.id': '224', + }, + { + 'entity.lastSeenTimestamp': '2024-04-28T22:32:11.149Z', + 'entity.type': 'container', + 'entity.displayName': 'Goldballs', + 'entity.id': '225', + }, + { + 'entity.lastSeenTimestamp': '2023-10-14T04:34:56.973Z', + 'entity.type': 'service', + 'entity.displayName': 'Magneto', + 'entity.id': '226', + }, + { + 'entity.lastSeenTimestamp': '2024-08-20T08:01:12.156Z', + 'entity.type': 'host', + 'entity.displayName': 'Juggernaut', + 'entity.id': '227', + }, + { + 'entity.lastSeenTimestamp': '2023-12-31T15:27:41.198Z', + 'entity.type': 'host', + 'entity.displayName': 'Mystique', + 'entity.id': '228', + }, + { + 'entity.lastSeenTimestamp': '2024-03-06T04:31:14.001Z', + 'entity.type': 'service', + 'entity.displayName': 'Sabretooth', + 'entity.id': '229', + }, + { + 'entity.lastSeenTimestamp': '2024-03-26T05:07:12.552Z', + 'entity.type': 'host', + 'entity.displayName': 'Toad', + 'entity.id': '230', + }, + { + 'entity.lastSeenTimestamp': '2024-05-20T17:34:56.098Z', + 'entity.type': 'service', + 'entity.displayName': 'Pyro', + 'entity.id': '231', + }, + { + 'entity.lastSeenTimestamp': '2023-04-12T16:53:27.530Z', + 'entity.type': 'host', + 'entity.displayName': 'Avalanche', + 'entity.id': '232', + }, + { + 'entity.lastSeenTimestamp': '2023-02-21T16:26:36.731Z', + 'entity.type': 'container', + 'entity.displayName': 'Blob', + 'entity.id': '233', + }, + { + 'entity.lastSeenTimestamp': '2023-03-23T03:52:18.017Z', + 'entity.type': 'host', + 'entity.displayName': 'Sauron', + 'entity.id': '234', + }, + { + 'entity.lastSeenTimestamp': '2024-04-10T21:31:37.929Z', + 'entity.type': 'container', + 'entity.displayName': 'Omega Red', + 'entity.id': '235', + }, + { + 'entity.lastSeenTimestamp': '2024-02-28T14:35:09.897Z', + 'entity.type': 'service', + 'entity.displayName': 'Mr. Sinister', + 'entity.id': '236', + }, + { + 'entity.lastSeenTimestamp': '2024-01-24T09:05:06.205Z', + 'entity.type': 'host', + 'entity.displayName': 'Apocalypse', + 'entity.id': '237', + }, + { + 'entity.lastSeenTimestamp': '2024-02-05T23:30:26.586Z', + 'entity.type': 'service', + 'entity.displayName': 'Genesis', + 'entity.id': '238', + }, + { + 'entity.lastSeenTimestamp': '2023-04-18T11:46:41.466Z', + 'entity.type': 'service', + 'entity.displayName': 'Archangel', + 'entity.id': '239', + }, + { + 'entity.lastSeenTimestamp': '2023-02-28T02:10:52.053Z', + 'entity.type': 'host', + 'entity.displayName': 'Holocaust', + 'entity.id': '240', + }, + { + 'entity.lastSeenTimestamp': '2024-04-03T12:19:13.947Z', + 'entity.type': 'host', + 'entity.displayName': 'Onslaught', + 'entity.id': '241', + }, + { + 'entity.lastSeenTimestamp': '2023-01-20T01:37:07.489Z', + 'entity.type': 'host', + 'entity.displayName': 'Exodus', + 'entity.id': '242', + }, + { + 'entity.lastSeenTimestamp': '2023-10-09T07:32:39.074Z', + 'entity.type': 'container', + 'entity.displayName': 'Gambit', + 'entity.id': '243', + }, + { + 'entity.lastSeenTimestamp': '2024-07-21T15:09:00.494Z', + 'entity.type': 'host', + 'entity.displayName': 'Rogue', + 'entity.id': '244', + }, + { + 'entity.lastSeenTimestamp': '2024-08-03T14:58:05.875Z', + 'entity.type': 'service', + 'entity.displayName': 'Magneto', + 'entity.id': '245', + }, + { + 'entity.lastSeenTimestamp': '2024-02-08T04:32:33.334Z', + 'entity.type': 'container', + 'entity.displayName': 'Longshot', + 'entity.id': '246', + }, + { + 'entity.lastSeenTimestamp': '2023-03-18T10:37:49.383Z', + 'entity.type': 'service', + 'entity.displayName': 'Dazzler', + 'entity.id': '247', + }, + { + 'entity.lastSeenTimestamp': '2024-07-11T17:35:31.669Z', + 'entity.type': 'service', + 'entity.displayName': 'Forge', + 'entity.id': '248', + }, + { + 'entity.lastSeenTimestamp': '2024-08-23T15:01:17.593Z', + 'entity.type': 'host', + 'entity.displayName': 'Mojo', + 'entity.id': '249', + }, + { + 'entity.lastSeenTimestamp': '2023-06-27T15:34:23.105Z', + 'entity.type': 'service', + 'entity.displayName': 'Spiral', + 'entity.id': '250', + }, + { + 'entity.lastSeenTimestamp': '2024-03-19T08:06:40.658Z', + 'entity.type': 'container', + 'entity.displayName': 'Warlock', + 'entity.id': '251', + }, + { + 'entity.lastSeenTimestamp': '2023-08-19T12:10:02.477Z', + 'entity.type': 'container', + 'entity.displayName': 'Magus', + 'entity.id': '252', + }, + { + 'entity.lastSeenTimestamp': '2024-05-30T12:20:06.653Z', + 'entity.type': 'service', + 'entity.displayName': 'Douglock', + 'entity.id': '253', + }, + { + 'entity.lastSeenTimestamp': '2023-05-31T17:48:07.719Z', + 'entity.type': 'service', + 'entity.displayName': 'Shatterstar', + 'entity.id': '254', + }, + { + 'entity.lastSeenTimestamp': '2023-12-10T05:35:40.666Z', + 'entity.type': 'service', + 'entity.displayName': 'Rictor', + 'entity.id': '255', + }, + { + 'entity.lastSeenTimestamp': '2024-02-02T22:18:47.168Z', + 'entity.type': 'host', + 'entity.displayName': 'Domino', + 'entity.id': '256', + }, + { + 'entity.lastSeenTimestamp': '2024-01-07T22:07:45.968Z', + 'entity.type': 'container', + 'entity.displayName': 'Cable', + 'entity.id': '257', + }, + { + 'entity.lastSeenTimestamp': '2023-01-15T11:22:54.155Z', + 'entity.type': 'host', + 'entity.displayName': 'Hope Summers', + 'entity.id': '258', + }, + { + 'entity.lastSeenTimestamp': '2023-03-26T13:56:10.553Z', + 'entity.type': 'service', + 'entity.displayName': 'Deadpool', + 'entity.id': '259', + }, + { + 'entity.lastSeenTimestamp': '2023-08-15T19:17:34.583Z', + 'entity.type': 'service', + 'entity.displayName': 'X-23', + 'entity.id': '260', + }, + { + 'entity.lastSeenTimestamp': '2024-06-26T09:02:40.512Z', + 'entity.type': 'host', + 'entity.displayName': 'Daken', + 'entity.id': '261', + }, + { + 'entity.lastSeenTimestamp': '2024-07-07T09:01:04.091Z', + 'entity.type': 'host', + 'entity.displayName': 'Wolverine', + 'entity.id': '262', + }, + { + 'entity.lastSeenTimestamp': '2023-10-15T22:25:29.643Z', + 'entity.type': 'service', + 'entity.displayName': 'Old Man Logan', + 'entity.id': '263', + }, + { + 'entity.lastSeenTimestamp': '2024-07-07T04:51:19.761Z', + 'entity.type': 'container', + 'entity.displayName': 'The Maker', + 'entity.id': '264', + }, + { + 'entity.lastSeenTimestamp': '2024-03-13T14:00:51.289Z', + 'entity.type': 'container', + 'entity.displayName': 'Ultimate Thor', + 'entity.id': '265', + }, + { + 'entity.lastSeenTimestamp': '2023-07-23T10:13:07.651Z', + 'entity.type': 'service', + 'entity.displayName': 'Ultimate Iron Man', + 'entity.id': '266', + }, + { + 'entity.lastSeenTimestamp': '2023-08-20T07:09:20.148Z', + 'entity.type': 'container', + 'entity.displayName': 'Ultimate Hulk', + 'entity.id': '267', + }, + { + 'entity.lastSeenTimestamp': '2024-09-08T10:53:13.256Z', + 'entity.type': 'service', + 'entity.displayName': 'Ultimate Captain America', + 'entity.id': '268', + }, + { + 'entity.lastSeenTimestamp': '2024-09-15T03:57:28.175Z', + 'entity.type': 'container', + 'entity.displayName': + 'Sed dignissim libero a diam sagittis, in convallis leo pellentesque. Cras ut sapien sed lacus scelerisque vehicula. Pellentesque at purus pulvinar, mollis justo hendrerit, pharetra purus. Morbi dapibus, augue et volutpat ultricies, neque quam sollicitudin mauris, vitae luctus ex libero id erat. Suspendisse risus lectus, scelerisque vel odio sed.', + 'entity.id': '269', + }, + { + 'entity.lastSeenTimestamp': '2023-10-22T13:49:53.092Z', + 'entity.type': 'host', + 'entity.displayName': 'Silk', + 'entity.id': '270', + }, + { + 'entity.lastSeenTimestamp': '2023-01-13T00:36:25.773Z', + 'entity.type': 'host', + 'entity.displayName': 'Scarlet Spider', + 'entity.id': '271', + }, + { + 'entity.lastSeenTimestamp': '2023-12-10T19:31:42.994Z', + 'entity.type': 'service', + 'entity.displayName': 'Ben Reilly', + 'entity.id': '272', + }, + { + 'entity.lastSeenTimestamp': '2023-01-17T09:49:30.447Z', + 'entity.type': 'service', + 'entity.displayName': 'Miles Morales', + 'entity.id': '273', + }, + { + 'entity.lastSeenTimestamp': '2023-01-02T18:45:44.012Z', + 'entity.type': 'container', + 'entity.displayName': 'Spider-Ham', + 'entity.id': '274', + }, + { + 'entity.lastSeenTimestamp': '2023-06-28T22:50:08.414Z', + 'entity.type': 'container', + 'entity.displayName': 'Agent Venom', + 'entity.id': '275', + }, + { + 'entity.lastSeenTimestamp': '2023-03-30T17:01:35.995Z', + 'entity.type': 'service', + 'entity.displayName': 'Anti-Venom', + 'entity.id': '276', + }, + { + 'entity.lastSeenTimestamp': '2023-06-11T05:23:11.367Z', + 'entity.type': 'host', + 'entity.displayName': 'Toxin', + 'entity.id': '277', + }, + { + 'entity.lastSeenTimestamp': '2023-07-22T15:27:17.077Z', + 'entity.type': 'service', + 'entity.displayName': 'Morbius', + 'entity.id': '278', + }, + { + 'entity.lastSeenTimestamp': '2024-01-26T11:19:34.147Z', + 'entity.type': 'host', + 'entity.displayName': 'Kraven the Hunter', + 'entity.id': '279', + }, + { + 'entity.lastSeenTimestamp': '2024-06-18T09:03:01.111Z', + 'entity.type': 'container', + 'entity.displayName': 'Doctor Octopus', + 'entity.id': '280', + }, + { + 'entity.lastSeenTimestamp': '2024-07-27T14:08:12.583Z', + 'entity.type': 'container', + 'entity.displayName': 'Green Goblin', + 'entity.id': '281', + }, + { + 'entity.lastSeenTimestamp': '2023-01-12T01:38:45.243Z', + 'entity.type': 'host', + 'entity.displayName': 'Electro', + 'entity.id': '282', + }, + { + 'entity.lastSeenTimestamp': '2024-04-19T05:33:59.289Z', + 'entity.type': 'container', + 'entity.displayName': 'Rhino', + 'entity.id': '283', + }, + { + 'entity.lastSeenTimestamp': '2023-04-13T22:06:02.389Z', + 'entity.type': 'service', + 'entity.displayName': 'Shocker', + 'entity.id': '284', + }, + { + 'entity.lastSeenTimestamp': '2023-01-26T15:36:08.782Z', + 'entity.type': 'host', + 'entity.displayName': 'Vulture', + 'entity.id': '285', + }, + { + 'entity.lastSeenTimestamp': '2023-11-11T19:54:14.523Z', + 'entity.type': 'container', + 'entity.displayName': 'Sandman', + 'entity.id': '286', + }, + { + 'entity.lastSeenTimestamp': '2023-12-06T06:20:06.995Z', + 'entity.type': 'host', + 'entity.displayName': 'Mysterio', + 'entity.id': '287', + }, + { + 'entity.lastSeenTimestamp': '2023-07-23T04:30:35.686Z', + 'entity.type': 'service', + 'entity.displayName': 'Black Cat', + 'entity.id': '288', + }, + { + 'entity.lastSeenTimestamp': '2023-01-18T03:09:26.047Z', + 'entity.type': 'host', + 'entity.displayName': 'Silver Sable', + 'entity.id': '289', + }, + { + 'entity.lastSeenTimestamp': '2024-06-08T12:42:08.485Z', + 'entity.type': 'service', + 'entity.displayName': 'Chameleon', + 'entity.id': '290', + }, + { + 'entity.lastSeenTimestamp': '2023-08-18T03:34:28.230Z', + 'entity.type': 'container', + 'entity.displayName': 'Hammerhead', + 'entity.id': '291', + }, + { + 'entity.lastSeenTimestamp': '2024-04-13T01:42:03.890Z', + 'entity.type': 'container', + 'entity.displayName': 'Tombstone', + 'entity.id': '292', + }, + { + 'entity.lastSeenTimestamp': '2023-11-21T17:39:56.066Z', + 'entity.type': 'container', + 'entity.displayName': 'Alistair Smythe', + 'entity.id': '293', + }, + { + 'entity.lastSeenTimestamp': '2024-02-29T04:45:41.113Z', + 'entity.type': 'host', + 'entity.displayName': 'The Beetle', + 'entity.id': '294', + }, + { + 'entity.lastSeenTimestamp': '2024-08-12T07:40:35.827Z', + 'entity.type': 'host', + 'entity.displayName': 'The Prowler', + 'entity.id': '295', + }, + { + 'entity.lastSeenTimestamp': '2023-11-27T23:09:49.629Z', + 'entity.type': 'service', + 'entity.displayName': 'Scorpion', + 'entity.id': '296', + }, + { + 'entity.lastSeenTimestamp': '2024-08-29T21:24:37.304Z', + 'entity.type': 'container', + 'entity.displayName': 'Jackal', + 'entity.id': '297', + }, + { + 'entity.lastSeenTimestamp': '2023-03-25T03:08:42.970Z', + 'entity.type': 'container', + 'entity.displayName': 'Morlun', + 'entity.id': '298', + }, + { + 'entity.lastSeenTimestamp': '2023-12-12T01:01:52.801Z', + 'entity.type': 'container', + 'entity.displayName': 'Lizard', + 'entity.id': '299', + }, + { + 'entity.lastSeenTimestamp': '2024-02-22T02:29:11.333Z', + 'entity.type': 'service', + 'entity.displayName': 'Kingpin', + 'entity.id': '300', + }, + { + 'entity.lastSeenTimestamp': '2024-09-03T19:31:38.700Z', + 'entity.type': 'host', + 'entity.displayName': 'Carnage', + 'entity.id': '301', + }, + { + 'entity.lastSeenTimestamp': '2023-04-09T17:55:20.565Z', + 'entity.type': 'container', + 'entity.displayName': 'Norman Osborn', + 'entity.id': '302', + }, + { + 'entity.lastSeenTimestamp': '2023-11-15T11:23:39.657Z', + 'entity.type': 'container', + 'entity.displayName': 'Harry Osborn', + 'entity.id': '303', + }, + { + 'entity.lastSeenTimestamp': '2024-08-16T08:14:11.415Z', + 'entity.type': 'service', + 'entity.displayName': 'Hobgoblin', + 'entity.id': '304', + }, + { + 'entity.lastSeenTimestamp': '2023-04-09T06:48:50.111Z', + 'entity.type': 'container', + 'entity.displayName': 'Phil Urich', + 'entity.id': '305', + }, + { + 'entity.lastSeenTimestamp': '2023-10-07T15:00:25.174Z', + 'entity.type': 'host', + 'entity.displayName': 'Demogoblin', + 'entity.id': '306', + }, + { + 'entity.lastSeenTimestamp': '2024-05-04T22:13:00.266Z', + 'entity.type': 'container', + 'entity.displayName': 'Red Goblin', + 'entity.id': '307', + }, + { + 'entity.lastSeenTimestamp': '2024-04-04T23:46:04.650Z', + 'entity.type': 'container', + 'entity.displayName': 'Doctor Octopus', + 'entity.id': '308', + }, + { + 'entity.lastSeenTimestamp': '2023-03-09T03:17:41.028Z', + 'entity.type': 'container', + 'entity.displayName': 'Otto Octavius', + 'entity.id': '309', + }, + { + 'entity.lastSeenTimestamp': '2023-02-15T01:52:08.165Z', + 'entity.type': 'service', + 'entity.displayName': 'Spider-Slayer', + 'entity.id': '310', + }, + { + 'entity.lastSeenTimestamp': '2024-05-18T16:03:17.334Z', + 'entity.type': 'container', + 'entity.displayName': 'The Spot', + 'entity.id': '311', + }, + { + 'entity.lastSeenTimestamp': '2023-10-24T01:14:40.519Z', + 'entity.type': 'host', + 'entity.displayName': 'White Tiger', + 'entity.id': '312', + }, + { + 'entity.lastSeenTimestamp': '2023-11-25T03:29:54.122Z', + 'entity.type': 'container', + 'entity.displayName': 'Kang', + 'entity.id': '313', + }, + { + 'entity.lastSeenTimestamp': '2023-03-10T14:39:44.761Z', + 'entity.type': 'container', + 'entity.displayName': 'Baron Zemo', + 'entity.id': '314', + }, + { + 'entity.lastSeenTimestamp': '2023-05-02T09:25:50.743Z', + 'entity.type': 'host', + 'entity.displayName': 'Red Skull', + 'entity.id': '315', + }, + { + 'entity.lastSeenTimestamp': '2023-04-09T14:57:15.653Z', + 'entity.type': 'container', + 'entity.displayName': 'MODOK', + 'entity.id': '316', + }, + { + 'entity.lastSeenTimestamp': '2023-12-02T10:21:33.045Z', + 'entity.type': 'service', + 'entity.displayName': 'Taskmaster', + 'entity.id': '317', + }, + { + 'entity.lastSeenTimestamp': '2023-09-26T12:18:47.857Z', + 'entity.type': 'service', + 'entity.displayName': 'Ultron', + 'entity.id': '318', + }, + { + 'entity.lastSeenTimestamp': '2023-06-29T22:13:32.744Z', + 'entity.type': 'container', + 'entity.displayName': 'Crossbones', + 'entity.id': '319', + }, + { + 'entity.lastSeenTimestamp': '2023-04-29T16:04:40.552Z', + 'entity.type': 'service', + 'entity.displayName': 'Madame Hydra', + 'entity.id': '320', + }, + { + 'entity.lastSeenTimestamp': '2023-07-26T05:34:55.857Z', + 'entity.type': 'host', + 'entity.displayName': 'The Leader', + 'entity.id': '321', + }, + { + 'entity.lastSeenTimestamp': '2023-05-23T13:21:34.771Z', + 'entity.type': 'service', + 'entity.displayName': 'Abomination', + 'entity.id': '322', + }, + { + 'entity.lastSeenTimestamp': '2024-05-06T22:15:26.389Z', + 'entity.type': 'container', + 'entity.displayName': 'The Mandarin', + 'entity.id': '323', + }, + { + 'entity.lastSeenTimestamp': '2024-01-08T09:12:59.615Z', + 'entity.type': 'service', + 'entity.displayName': 'Fin Fang Foom', + 'entity.id': '324', + }, + { + 'entity.lastSeenTimestamp': '2023-07-07T15:39:12.867Z', + 'entity.type': 'container', + 'entity.displayName': 'Killmonger', + 'entity.id': '325', + }, + { + 'entity.lastSeenTimestamp': '2023-12-04T02:42:55.907Z', + 'entity.type': 'container', + 'entity.displayName': 'Ulysses Klaue', + 'entity.id': '326', + }, + { + 'entity.lastSeenTimestamp': '2024-01-01T10:14:42.258Z', + 'entity.type': 'container', + 'entity.displayName': 'The Collector', + 'entity.id': '327', + }, + { + 'entity.lastSeenTimestamp': '2024-07-21T02:20:14.626Z', + 'entity.type': 'container', + 'entity.displayName': 'The Grandmaster', + 'entity.id': '328', + }, + { + 'entity.lastSeenTimestamp': '2024-04-19T01:54:14.317Z', + 'entity.type': 'service', + 'entity.displayName': 'Thanos', + 'entity.id': '329', + }, + { + 'entity.lastSeenTimestamp': '2023-12-15T04:43:05.141Z', + 'entity.type': 'host', + 'entity.displayName': 'Darkseid', + 'entity.id': '330', + }, + { + 'entity.lastSeenTimestamp': '2023-06-20T14:32:29.968Z', + 'entity.type': 'service', + 'entity.displayName': 'Lex Luthor', + 'entity.id': '331', + }, + { + 'entity.lastSeenTimestamp': '2023-11-02T15:33:40.790Z', + 'entity.type': 'container', + 'entity.displayName': 'Bane', + 'entity.id': '332', + }, + { + 'entity.lastSeenTimestamp': '2024-06-09T08:34:20.039Z', + 'entity.type': 'host', + 'entity.displayName': 'Brainiac', + 'entity.id': '333', + }, + { + 'entity.lastSeenTimestamp': '2024-08-30T14:00:25.077Z', + 'entity.type': 'container', + 'entity.displayName': 'Doomsday', + 'entity.id': '334', + }, + { + 'entity.lastSeenTimestamp': '2024-02-26T18:03:06.283Z', + 'entity.type': 'service', + 'entity.displayName': 'General Zod', + 'entity.id': '335', + }, + { + 'entity.lastSeenTimestamp': '2023-10-30T05:16:19.508Z', + 'entity.type': 'host', + 'entity.displayName': "Ra's al Ghul", + 'entity.id': '336', + }, + { + 'entity.lastSeenTimestamp': '2023-04-05T20:09:22.332Z', + 'entity.type': 'host', + 'entity.displayName': 'Scarecrow', + 'entity.id': '337', + }, + { + 'entity.lastSeenTimestamp': '2023-06-09T06:46:09.887Z', + 'entity.type': 'service', + 'entity.displayName': 'The Joker', + 'entity.id': '338', + }, + { + 'entity.lastSeenTimestamp': '2023-04-26T15:02:13.202Z', + 'entity.type': 'host', + 'entity.displayName': 'Harley Quinn', + 'entity.id': '339', + }, + { + 'entity.lastSeenTimestamp': '2024-04-09T05:21:09.975Z', + 'entity.type': 'service', + 'entity.displayName': 'Poison Ivy', + 'entity.id': '340', + }, + { + 'entity.lastSeenTimestamp': '2023-06-05T04:53:00.171Z', + 'entity.type': 'service', + 'entity.displayName': 'The Riddler', + 'entity.id': '341', + }, + { + 'entity.lastSeenTimestamp': '2024-03-07T01:23:08.698Z', + 'entity.type': 'host', + 'entity.displayName': 'Penguin', + 'entity.id': '342', + }, + { + 'entity.lastSeenTimestamp': '2024-05-17T13:08:12.434Z', + 'entity.type': 'container', + 'entity.displayName': 'Two-Face', + 'entity.id': '343', + }, + { + 'entity.lastSeenTimestamp': '2024-03-13T16:39:26.987Z', + 'entity.type': 'service', + 'entity.displayName': 'Mr. Freeze', + 'entity.id': '344', + }, + { + 'entity.lastSeenTimestamp': '2024-01-01T06:31:32.470Z', + 'entity.type': 'host', + 'entity.displayName': 'Clayface', + 'entity.id': '345', + }, + { + 'entity.lastSeenTimestamp': '2024-06-24T16:27:01.156Z', + 'entity.type': 'service', + 'entity.displayName': 'Hush', + 'entity.id': '346', + }, + { + 'entity.lastSeenTimestamp': '2023-10-19T14:35:47.544Z', + 'entity.type': 'host', + 'entity.displayName': 'Black Mask', + 'entity.id': '347', + }, + { + 'entity.lastSeenTimestamp': '2023-10-24T13:57:07.539Z', + 'entity.type': 'host', + 'entity.displayName': 'Killer Croc', + 'entity.id': '348', + }, + { + 'entity.lastSeenTimestamp': '2023-02-19T09:40:44.538Z', + 'entity.type': 'service', + 'entity.displayName': 'Deathstroke', + 'entity.id': '349', + }, + { + 'entity.lastSeenTimestamp': '2023-03-25T19:22:45.889Z', + 'entity.type': 'service', + 'entity.displayName': 'Deadshot', + 'entity.id': '350', + }, + { + 'entity.lastSeenTimestamp': '2024-06-08T03:10:02.475Z', + 'entity.type': 'container', + 'entity.displayName': 'Amanda Waller', + 'entity.id': '351', + }, + { + 'entity.lastSeenTimestamp': '2023-01-04T03:49:07.210Z', + 'entity.type': 'host', + 'entity.displayName': 'Captain Boomerang', + 'entity.id': '352', + }, + { + 'entity.lastSeenTimestamp': '2023-04-10T20:53:14.367Z', + 'entity.type': 'host', + 'entity.displayName': 'Katana', + 'entity.id': '353', + }, + { + 'entity.lastSeenTimestamp': '2024-04-25T09:42:55.170Z', + 'entity.type': 'host', + 'entity.displayName': 'El Diablo', + 'entity.id': '354', + }, + { + 'entity.lastSeenTimestamp': '2024-05-10T00:44:03.472Z', + 'entity.type': 'host', + 'entity.displayName': 'Enchantress', + 'entity.id': '355', + }, + { + 'entity.lastSeenTimestamp': '2024-02-16T03:47:56.021Z', + 'entity.type': 'service', + 'entity.displayName': 'Rick Flag', + 'entity.id': '356', + }, + { + 'entity.lastSeenTimestamp': '2023-09-30T16:45:27.670Z', + 'entity.type': 'host', + 'entity.displayName': 'King Shark', + 'entity.id': '357', + }, + { + 'entity.lastSeenTimestamp': '2023-10-14T03:04:21.380Z', + 'entity.type': 'host', + 'entity.displayName': 'Peacemaker', + 'entity.id': '358', + }, + { + 'entity.lastSeenTimestamp': '2023-06-27T20:42:18.732Z', + 'entity.type': 'host', + 'entity.displayName': 'Bloodsport', + 'entity.id': '359', + }, + { + 'entity.lastSeenTimestamp': '2024-05-25T22:56:14.675Z', + 'entity.type': 'container', + 'entity.displayName': 'Weasel', + 'entity.id': '360', + }, + { + 'entity.lastSeenTimestamp': '2024-05-15T05:34:39.704Z', + 'entity.type': 'container', + 'entity.displayName': 'Javelin', + 'entity.id': '361', + }, + { + 'entity.lastSeenTimestamp': '2024-07-18T13:40:24.040Z', + 'entity.type': 'container', + 'entity.displayName': 'Ratcatcher', + 'entity.id': '362', + }, + { + 'entity.lastSeenTimestamp': '2023-08-31T03:02:00.545Z', + 'entity.type': 'container', + 'entity.displayName': 'T.D.K.', + 'entity.id': '363', + }, + { + 'entity.lastSeenTimestamp': '2024-08-27T11:13:19.374Z', + 'entity.type': 'container', + 'entity.displayName': 'Doctor Fate', + 'entity.id': '364', + }, + { + 'entity.lastSeenTimestamp': '2023-08-29T06:47:41.545Z', + 'entity.type': 'container', + 'entity.displayName': 'Hawkman', + 'entity.id': '365', + }, + { + 'entity.lastSeenTimestamp': '2024-04-30T00:01:35.041Z', + 'entity.type': 'service', + 'entity.displayName': 'Hawkgirl', + 'entity.id': '366', + }, + { + 'entity.lastSeenTimestamp': '2024-01-24T01:02:59.317Z', + 'entity.type': 'container', + 'entity.displayName': 'Black Adam', + 'entity.id': '367', + }, + { + 'entity.lastSeenTimestamp': '2023-11-08T14:30:16.054Z', + 'entity.type': 'service', + 'entity.displayName': 'Atom Smasher', + 'entity.id': '368', + }, + { + 'entity.lastSeenTimestamp': '2024-08-02T05:40:07.271Z', + 'entity.type': 'host', + 'entity.displayName': 'Cyclone', + 'entity.id': '369', + }, + { + 'entity.lastSeenTimestamp': '2024-03-24T19:11:13.807Z', + 'entity.type': 'host', + 'entity.displayName': 'Stargirl', + 'entity.id': '370', + }, + { + 'entity.lastSeenTimestamp': '2024-01-25T19:31:31.536Z', + 'entity.type': 'host', + 'entity.displayName': 'Hourman', + 'entity.id': '371', + }, + { + 'entity.lastSeenTimestamp': '2024-05-20T22:09:46.339Z', + 'entity.type': 'service', + 'entity.displayName': 'Wildcat', + 'entity.id': '372', + }, + { + 'entity.lastSeenTimestamp': '2023-07-31T01:51:08.575Z', + 'entity.type': 'host', + 'entity.displayName': 'Green Arrow', + 'entity.id': '373', + }, + { + 'entity.lastSeenTimestamp': '2024-03-23T22:01:53.447Z', + 'entity.type': 'container', + 'entity.displayName': 'Speedy', + 'entity.id': '374', + }, + { + 'entity.lastSeenTimestamp': '2024-02-11T22:26:31.584Z', + 'entity.type': 'service', + 'entity.displayName': 'Arsenal', + 'entity.id': '375', + }, + { + 'entity.lastSeenTimestamp': '2024-04-06T12:30:22.601Z', + 'entity.type': 'service', + 'entity.displayName': 'Red Hood', + 'entity.id': '376', + }, + { + 'entity.lastSeenTimestamp': '2023-09-13T07:02:26.095Z', + 'entity.type': 'service', + 'entity.displayName': 'Batgirl', + 'entity.id': '377', + }, + { + 'entity.lastSeenTimestamp': '2024-07-07T22:22:48.331Z', + 'entity.type': 'container', + 'entity.displayName': 'Oracle', + 'entity.id': '378', + }, + { + 'entity.lastSeenTimestamp': '2024-08-09T21:51:59.774Z', + 'entity.type': 'host', + 'entity.displayName': 'Huntress', + 'entity.id': '379', + }, + { + 'entity.lastSeenTimestamp': '2024-02-04T21:15:45.848Z', + 'entity.type': 'service', + 'entity.displayName': 'Cassandra Cain', + 'entity.id': '380', + }, + { + 'entity.lastSeenTimestamp': '2023-07-23T14:22:33.033Z', + 'entity.type': 'host', + 'entity.displayName': 'Azrael', + 'entity.id': '381', + }, + { + 'entity.lastSeenTimestamp': '2024-09-04T05:28:23.197Z', + 'entity.type': 'container', + 'entity.displayName': 'Batwoman', + 'entity.id': '382', + }, + { + 'entity.lastSeenTimestamp': '2023-06-27T08:09:37.626Z', + 'entity.type': 'container', + 'entity.displayName': 'Stephanie Brown', + 'entity.id': '383', + }, + { + 'entity.lastSeenTimestamp': '2023-12-20T08:14:23.553Z', + 'entity.type': 'host', + 'entity.displayName': 'The Question', + 'entity.id': '384', + }, + { + 'entity.lastSeenTimestamp': '2024-03-17T00:19:48.826Z', + 'entity.type': 'container', + 'entity.displayName': 'Blue Beetle', + 'entity.id': '385', + }, + { + 'entity.lastSeenTimestamp': '2024-02-17T20:55:20.634Z', + 'entity.type': 'container', + 'entity.displayName': 'Booster Gold', + 'entity.id': '386', + }, + { + 'entity.lastSeenTimestamp': '2023-02-14T10:24:49.445Z', + 'entity.type': 'host', + 'entity.displayName': 'Plastic Man', + 'entity.id': '387', + }, + { + 'entity.lastSeenTimestamp': '2024-05-10T06:49:45.226Z', + 'entity.type': 'container', + 'entity.displayName': 'Metamorpho', + 'entity.id': '388', + }, + { + 'entity.lastSeenTimestamp': '2023-08-28T11:04:03.884Z', + 'entity.type': 'host', + 'entity.displayName': 'The Spectre', + 'entity.id': '389', + }, + { + 'entity.lastSeenTimestamp': '2023-06-03T09:16:22.294Z', + 'entity.type': 'service', + 'entity.displayName': 'Etrigan', + 'entity.id': '390', + }, + { + 'entity.lastSeenTimestamp': '2023-05-27T15:43:31.368Z', + 'entity.type': 'host', + 'entity.displayName': 'Swamp Thing', + 'entity.id': '391', + }, + { + 'entity.lastSeenTimestamp': '2024-01-23T00:27:36.339Z', + 'entity.type': 'service', + 'entity.displayName': 'Constantine', + 'entity.id': '392', + }, + { + 'entity.lastSeenTimestamp': '2023-12-19T09:00:36.251Z', + 'entity.type': 'host', + 'entity.displayName': 'Zatanna', + 'entity.id': '393', + }, + { + 'entity.lastSeenTimestamp': '2024-02-11T09:31:14.413Z', + 'entity.type': 'host', + 'entity.displayName': 'Doctor Fate', + 'entity.id': '394', + }, + { + 'entity.lastSeenTimestamp': '2024-08-15T14:04:15.345Z', + 'entity.type': 'service', + 'entity.displayName': 'Martian Manhunter', + 'entity.id': '395', + }, + { + 'entity.lastSeenTimestamp': '2024-03-23T06:41:28.527Z', + 'entity.type': 'container', + 'entity.displayName': 'Firestorm', + 'entity.id': '396', + }, + { + 'entity.lastSeenTimestamp': '2023-03-29T19:22:53.314Z', + 'entity.type': 'service', + 'entity.displayName': 'Captain Atom', + 'entity.id': '397', + }, + { + 'entity.lastSeenTimestamp': '2024-05-03T02:22:19.643Z', + 'entity.type': 'service', + 'entity.displayName': 'The Atom', + 'entity.id': '398', + }, + { + 'entity.lastSeenTimestamp': '2024-05-12T05:55:36.153Z', + 'entity.type': 'service', + 'entity.displayName': 'Vixen', + 'entity.id': '399', + }, + { + 'entity.lastSeenTimestamp': '2023-03-01T07:39:44.249Z', + 'entity.type': 'service', + 'entity.displayName': 'Animal Man', + 'entity.id': '400', + }, + { + 'entity.lastSeenTimestamp': '2023-05-20T14:24:33.191Z', + 'entity.type': 'host', + 'entity.displayName': 'Hawk', + 'entity.id': '401', + }, + { + 'entity.lastSeenTimestamp': '2023-06-24T16:44:21.444Z', + 'entity.type': 'host', + 'entity.displayName': 'Dove', + 'entity.id': '402', + }, + { + 'entity.lastSeenTimestamp': '2024-04-05T00:50:29.260Z', + 'entity.type': 'host', + 'entity.displayName': 'Steel', + 'entity.id': '403', + }, + { + 'entity.lastSeenTimestamp': '2024-05-01T07:44:47.694Z', + 'entity.type': 'host', + 'entity.displayName': 'Guardian', + 'entity.id': '404', + }, + { + 'entity.lastSeenTimestamp': '2024-08-10T20:46:37.204Z', + 'entity.type': 'container', + 'entity.displayName': 'The Phantom Stranger', + 'entity.id': '405', + }, + { + 'entity.lastSeenTimestamp': '2024-04-06T11:04:12.556Z', + 'entity.type': 'service', + 'entity.displayName': 'Lobo', + 'entity.id': '406', + }, + { + 'entity.lastSeenTimestamp': '2023-11-24T01:39:36.878Z', + 'entity.type': 'host', + 'entity.displayName': 'Red Tornado', + 'entity.id': '407', + }, + { + 'entity.lastSeenTimestamp': '2024-08-05T14:00:37.985Z', + 'entity.type': 'service', + 'entity.displayName': 'Miss Martian', + 'entity.id': '408', + }, + { + 'entity.lastSeenTimestamp': '2024-01-23T18:57:18.692Z', + 'entity.type': 'container', + 'entity.displayName': 'Bizarro', + 'entity.id': '409', + }, + { + 'entity.lastSeenTimestamp': '2023-01-29T08:35:22.194Z', + 'entity.type': 'service', + 'entity.displayName': 'Black Lightning', + 'entity.id': '410', + }, + { + 'entity.lastSeenTimestamp': '2024-04-03T21:32:10.035Z', + 'entity.type': 'container', + 'entity.displayName': 'Katana', + 'entity.id': '411', + }, + { + 'entity.lastSeenTimestamp': '2024-02-05T09:18:03.386Z', + 'entity.type': 'service', + 'entity.displayName': 'Mr. Terrific', + 'entity.id': '412', + }, + { + 'entity.lastSeenTimestamp': '2024-05-09T01:04:11.713Z', + 'entity.type': 'host', + 'entity.displayName': 'Plastic Man', + 'entity.id': '413', + }, + { + 'entity.lastSeenTimestamp': '2023-03-25T15:26:53.790Z', + 'entity.type': 'host', + 'entity.displayName': 'Shazam', + 'entity.id': '414', + }, + { + 'entity.lastSeenTimestamp': '2023-07-11T11:07:31.377Z', + 'entity.type': 'service', + 'entity.displayName': 'Spawn', + 'entity.id': '415', + }, + { + 'entity.lastSeenTimestamp': '2023-09-08T10:01:26.864Z', + 'entity.type': 'host', + 'entity.displayName': 'Invincible', + 'entity.id': '416', + }, + { + 'entity.lastSeenTimestamp': '2024-07-14T15:51:35.763Z', + 'entity.type': 'container', + 'entity.displayName': 'Atom Eve', + 'entity.id': '417', + }, + { + 'entity.lastSeenTimestamp': '2024-06-26T21:44:30.555Z', + 'entity.type': 'container', + 'entity.displayName': 'Rex Splode', + 'entity.id': '418', + }, + { + 'entity.lastSeenTimestamp': '2023-07-05T04:20:35.073Z', + 'entity.type': 'container', + 'entity.displayName': 'Allen the Alien', + 'entity.id': '419', + }, + { + 'entity.lastSeenTimestamp': '2024-05-31T19:57:53.543Z', + 'entity.type': 'service', + 'entity.displayName': 'Omni-Man', + 'entity.id': '420', + }, + { + 'entity.lastSeenTimestamp': '2023-02-19T17:22:07.379Z', + 'entity.type': 'service', + 'entity.displayName': 'The Tick', + 'entity.id': '421', + }, + { + 'entity.lastSeenTimestamp': '2023-12-17T22:51:04.060Z', + 'entity.type': 'host', + 'entity.displayName': 'Arthur', + 'entity.id': '422', + }, + { + 'entity.lastSeenTimestamp': '2024-03-09T23:54:47.229Z', + 'entity.type': 'service', + 'entity.displayName': 'Big Daddy', + 'entity.id': '423', + }, + { + 'entity.lastSeenTimestamp': '2024-07-14T11:52:37.828Z', + 'entity.type': 'service', + 'entity.displayName': 'Hit-Girl', + 'entity.id': '424', + }, + { + 'entity.lastSeenTimestamp': '2023-02-08T21:15:09.242Z', + 'entity.type': 'container', + 'entity.displayName': 'Kick-Ass', + 'entity.id': '425', + }, + { + 'entity.lastSeenTimestamp': '2024-03-01T17:58:53.274Z', + 'entity.type': 'host', + 'entity.displayName': 'Hellboy', + 'entity.id': '426', + }, + { + 'entity.lastSeenTimestamp': '2023-11-04T20:37:28.218Z', + 'entity.type': 'host', + 'entity.displayName': 'Abe Sapien', + 'entity.id': '427', + }, + { + 'entity.lastSeenTimestamp': '2024-05-16T15:38:01.584Z', + 'entity.type': 'service', + 'entity.displayName': 'Liz Sherman', + 'entity.id': '428', + }, + { + 'entity.lastSeenTimestamp': '2023-03-28T13:40:51.501Z', + 'entity.type': 'container', + 'entity.displayName': 'The Mask', + 'entity.id': '429', + }, + { + 'entity.lastSeenTimestamp': '2023-07-22T10:39:48.045Z', + 'entity.type': 'service', + 'entity.displayName': 'Judge Dredd', + 'entity.id': '430', + }, + { + 'entity.lastSeenTimestamp': '2023-11-10T02:21:09.389Z', + 'entity.type': 'service', + 'entity.displayName': 'Tank Girl', + 'entity.id': '431', + }, + { + 'entity.lastSeenTimestamp': '2024-04-21T16:23:33.730Z', + 'entity.type': 'container', + 'entity.displayName': 'Shadowman', + 'entity.id': '432', + }, + { + 'entity.lastSeenTimestamp': '2023-08-17T19:31:07.282Z', + 'entity.type': 'container', + 'entity.displayName': 'Bloodshot', + 'entity.id': '433', + }, + { + 'entity.lastSeenTimestamp': '2023-04-23T10:05:19.825Z', + 'entity.type': 'service', + 'entity.displayName': 'X-O Manowar', + 'entity.id': '434', + }, + { + 'entity.lastSeenTimestamp': '2024-04-30T21:58:46.410Z', + 'entity.type': 'host', + 'entity.displayName': 'Harbinger', + 'entity.id': '435', + }, + { + 'entity.lastSeenTimestamp': '2023-07-14T05:26:30.493Z', + 'entity.type': 'service', + 'entity.displayName': 'Ninjak', + 'entity.id': '436', + }, + { + 'entity.lastSeenTimestamp': '2024-01-30T09:21:55.939Z', + 'entity.type': 'host', + 'entity.displayName': 'Faith', + 'entity.id': '437', + }, + { + 'entity.lastSeenTimestamp': '2024-02-17T20:36:23.898Z', + 'entity.type': 'host', + 'entity.displayName': 'Archer', + 'entity.id': '438', + }, + { + 'entity.lastSeenTimestamp': '2023-04-04T15:08:08.423Z', + 'entity.type': 'container', + 'entity.displayName': 'Armstrong', + 'entity.id': '439', + }, + { + 'entity.lastSeenTimestamp': '2024-07-29T11:54:01.693Z', + 'entity.type': 'host', + 'entity.displayName': 'Eternal Warrior', + 'entity.id': '440', + }, + { + 'entity.lastSeenTimestamp': '2023-11-02T09:56:15.646Z', + 'entity.type': 'host', + 'entity.displayName': 'Quantum', + 'entity.id': '441', + }, + { + 'entity.lastSeenTimestamp': '2023-04-06T02:07:23.857Z', + 'entity.type': 'container', + 'entity.displayName': 'Woody', + 'entity.id': '442', + }, + { + 'entity.lastSeenTimestamp': '2023-05-20T10:33:26.328Z', + 'entity.type': 'host', + 'entity.displayName': 'The Darkness', + 'entity.id': '443', + }, + { + 'entity.lastSeenTimestamp': '2023-12-03T23:59:21.627Z', + 'entity.type': 'container', + 'entity.displayName': 'Witchblade', + 'entity.id': '444', + }, + { + 'entity.lastSeenTimestamp': '2023-05-31T10:56:01.829Z', + 'entity.type': 'container', + 'entity.displayName': 'Ripclaw', + 'entity.id': '445', + }, + { + 'entity.lastSeenTimestamp': '2024-07-28T11:56:20.407Z', + 'entity.type': 'host', + 'entity.displayName': 'Warblade', + 'entity.id': '446', + }, + { + 'entity.lastSeenTimestamp': '2023-05-03T18:24:08.227Z', + 'entity.type': 'host', + 'entity.displayName': 'Savage Dragon', + 'entity.id': '447', + }, + { + 'entity.lastSeenTimestamp': '2024-07-15T09:05:19.621Z', + 'entity.type': 'host', + 'entity.displayName': 'Spawn', + 'entity.id': '448', + }, + { + 'entity.lastSeenTimestamp': '2024-04-16T13:06:48.941Z', + 'entity.type': 'host', + 'entity.displayName': 'Witchblade', + 'entity.id': '449', + }, + { + 'entity.lastSeenTimestamp': '2024-04-22T12:52:06.912Z', + 'entity.type': 'container', + 'entity.displayName': 'Invincible', + 'entity.id': '450', + }, + { + 'entity.lastSeenTimestamp': '2023-02-23T23:57:49.389Z', + 'entity.type': 'host', + 'entity.displayName': 'The Maxx', + 'entity.id': '451', + }, + { + 'entity.lastSeenTimestamp': '2024-04-17T01:12:16.359Z', + 'entity.type': 'service', + 'entity.displayName': 'Lady Death', + 'entity.id': '452', + }, + { + 'entity.lastSeenTimestamp': '2024-05-07T14:14:02.286Z', + 'entity.type': 'container', + 'entity.displayName': 'The Shadow', + 'entity.id': '453', + }, + { + 'entity.lastSeenTimestamp': '2024-03-31T23:20:56.580Z', + 'entity.type': 'host', + 'entity.displayName': 'Doc Savage', + 'entity.id': '454', + }, + { + 'entity.lastSeenTimestamp': '2023-05-18T01:28:20.743Z', + 'entity.type': 'container', + 'entity.displayName': 'Zorro', + 'entity.id': '455', + }, + { + 'entity.lastSeenTimestamp': '2023-01-12T01:19:03.220Z', + 'entity.type': 'service', + 'entity.displayName': 'The Phantom', + 'entity.id': '456', + }, + { + 'entity.lastSeenTimestamp': '2023-10-10T20:35:47.302Z', + 'entity.type': 'container', + 'entity.displayName': 'Green Hornet', + 'entity.id': '457', + }, + { + 'entity.lastSeenTimestamp': '2023-05-09T19:35:59.568Z', + 'entity.type': 'service', + 'entity.displayName': 'Kato', + 'entity.id': '458', + }, + { + 'entity.lastSeenTimestamp': '2023-07-02T19:40:18.206Z', + 'entity.type': 'host', + 'entity.displayName': 'Red Sonja', + 'entity.id': '459', + }, + { + 'entity.lastSeenTimestamp': '2024-01-08T20:03:24.184Z', + 'entity.type': 'container', + 'entity.displayName': 'Conan the Barbarian', + 'entity.id': '460', + }, + { + 'entity.lastSeenTimestamp': '2024-03-13T05:26:16.730Z', + 'entity.type': 'service', + 'entity.displayName': 'Homer Simpson', + 'entity.id': '461', + }, + { + 'entity.lastSeenTimestamp': '2024-06-28T02:49:37.987Z', + 'entity.type': 'host', + 'entity.displayName': 'Marge Simpson', + 'entity.id': '462', + }, + { + 'entity.lastSeenTimestamp': '2024-06-17T21:16:08.180Z', + 'entity.type': 'host', + 'entity.displayName': 'Bart Simpson', + 'entity.id': '463', + }, + { + 'entity.lastSeenTimestamp': '2023-03-27T21:34:38.051Z', + 'entity.type': 'host', + 'entity.displayName': 'Lisa Simpson', + 'entity.id': '464', + }, + { + 'entity.lastSeenTimestamp': '2023-02-04T21:08:36.340Z', + 'entity.type': 'service', + 'entity.displayName': 'Maggie Simpson', + 'entity.id': '465', + }, + { + 'entity.lastSeenTimestamp': '2024-05-22T20:05:45.805Z', + 'entity.type': 'service', + 'entity.displayName': 'Abe Simpson', + 'entity.id': '466', + }, + { + 'entity.lastSeenTimestamp': '2023-04-02T23:57:33.378Z', + 'entity.type': 'container', + 'entity.displayName': 'Ned Flanders', + 'entity.id': '467', + }, + { + 'entity.lastSeenTimestamp': '2023-03-05T12:25:19.985Z', + 'entity.type': 'container', + 'entity.displayName': 'Maude Flanders', + 'entity.id': '468', + }, + { + 'entity.lastSeenTimestamp': '2024-05-31T22:44:52.035Z', + 'entity.type': 'container', + 'entity.displayName': 'Rod Flanders', + 'entity.id': '469', + }, + { + 'entity.lastSeenTimestamp': '2024-03-06T22:07:45.916Z', + 'entity.type': 'container', + 'entity.displayName': 'Todd Flanders', + 'entity.id': '470', + }, + { + 'entity.lastSeenTimestamp': '2023-09-29T20:39:30.536Z', + 'entity.type': 'service', + 'entity.displayName': 'Milhouse Van Houten', + 'entity.id': '471', + }, + { + 'entity.lastSeenTimestamp': '2023-07-13T22:08:03.669Z', + 'entity.type': 'host', + 'entity.displayName': 'Nelson Muntz', + 'entity.id': '472', + }, + { + 'entity.lastSeenTimestamp': '2024-01-11T11:44:27.608Z', + 'entity.type': 'service', + 'entity.displayName': 'Ralph Wiggum', + 'entity.id': '473', + }, + { + 'entity.lastSeenTimestamp': '2023-10-07T03:48:20.334Z', + 'entity.type': 'container', + 'entity.displayName': 'Chief Wiggum', + 'entity.id': '474', + }, + { + 'entity.lastSeenTimestamp': '2023-12-26T00:46:10.602Z', + 'entity.type': 'host', + 'entity.displayName': 'Clancy Wiggum', + 'entity.id': '475', + }, + { + 'entity.lastSeenTimestamp': '2023-03-24T03:32:51.643Z', + 'entity.type': 'host', + 'entity.displayName': 'Krusty the Clown', + 'entity.id': '476', + }, + { + 'entity.lastSeenTimestamp': '2023-01-19T18:15:10.942Z', + 'entity.type': 'container', + 'entity.displayName': 'Sideshow Bob', + 'entity.id': '477', + }, + { + 'entity.lastSeenTimestamp': '2023-02-05T23:13:30.639Z', + 'entity.type': 'service', + 'entity.displayName': 'Sideshow Mel', + 'entity.id': '478', + }, + { + 'entity.lastSeenTimestamp': '2024-03-06T07:02:19.760Z', + 'entity.type': 'host', + 'entity.displayName': 'Moe Szyslak', + 'entity.id': '479', + }, + { + 'entity.lastSeenTimestamp': '2024-08-26T17:28:47.162Z', + 'entity.type': 'service', + 'entity.displayName': 'Barney Gumble', + 'entity.id': '480', + }, + { + 'entity.lastSeenTimestamp': '2024-05-12T12:10:32.668Z', + 'entity.type': 'service', + 'entity.displayName': 'Lenny Leonard', + 'entity.id': '481', + }, + { + 'entity.lastSeenTimestamp': '2023-07-25T05:19:12.244Z', + 'entity.type': 'service', + 'entity.displayName': 'Carl Carlson', + 'entity.id': '482', + }, + { + 'entity.lastSeenTimestamp': '2023-09-14T19:23:00.311Z', + 'entity.type': 'container', + 'entity.displayName': 'Waylon Smithers', + 'entity.id': '483', + }, + { + 'entity.lastSeenTimestamp': '2023-07-06T12:21:13.655Z', + 'entity.type': 'service', + 'entity.displayName': 'Mr. Burns', + 'entity.id': '484', + }, + { + 'entity.lastSeenTimestamp': '2023-01-23T07:14:22.901Z', + 'entity.type': 'service', + 'entity.displayName': 'Principal Skinner', + 'entity.id': '485', + }, + { + 'entity.lastSeenTimestamp': '2024-05-07T18:03:19.312Z', + 'entity.type': 'service', + 'entity.displayName': 'Edna Krabappel', + 'entity.id': '486', + }, + { + 'entity.lastSeenTimestamp': '2023-02-14T07:33:02.981Z', + 'entity.type': 'service', + 'entity.displayName': 'Superintendent Chalmers', + 'entity.id': '487', + }, + { + 'entity.lastSeenTimestamp': '2024-01-21T22:32:55.738Z', + 'entity.type': 'container', + 'entity.displayName': 'Groundskeeper Willie', + 'entity.id': '488', + }, + { + 'entity.lastSeenTimestamp': '2024-03-31T13:42:07.765Z', + 'entity.type': 'service', + 'entity.displayName': 'Otto Mann', + 'entity.id': '489', + }, + { + 'entity.lastSeenTimestamp': '2023-08-23T18:26:32.084Z', + 'entity.type': 'container', + 'entity.displayName': 'Apu Nahasapeemapetilon', + 'entity.id': '490', + }, + { + 'entity.lastSeenTimestamp': '2024-02-14T04:17:17.737Z', + 'entity.type': 'container', + 'entity.displayName': 'Manjula Nahasapeemapetilon', + 'entity.id': '491', + }, + { + 'entity.lastSeenTimestamp': '2024-07-06T03:25:46.939Z', + 'entity.type': 'service', + 'entity.displayName': 'Kearney Zzyzwicz', + 'entity.id': '492', + }, + { + 'entity.lastSeenTimestamp': '2023-09-04T06:08:42.239Z', + 'entity.type': 'service', + 'entity.displayName': 'Jimbo Jones', + 'entity.id': '493', + }, + { + 'entity.lastSeenTimestamp': '2023-06-12T23:45:21.630Z', + 'entity.type': 'host', + 'entity.displayName': 'Dolph Starbeam', + 'entity.id': '494', + }, + { + 'entity.lastSeenTimestamp': '2023-11-18T18:43:41.585Z', + 'entity.type': 'container', + 'entity.displayName': 'Martin Prince', + 'entity.id': '495', + }, + { + 'entity.lastSeenTimestamp': '2024-07-29T01:12:36.480Z', + 'entity.type': 'container', + 'entity.displayName': 'Mrs. Prince', + 'entity.id': '496', + }, + { + 'entity.lastSeenTimestamp': '2023-09-25T18:32:05.791Z', + 'entity.type': 'container', + 'entity.displayName': 'Comic Book Guy', + 'entity.id': '497', + }, + { + 'entity.lastSeenTimestamp': '2023-04-05T12:49:08.814Z', + 'entity.type': 'host', + 'entity.displayName': 'Professor Frink', + 'entity.id': '498', + }, + { + 'entity.lastSeenTimestamp': '2023-04-07T20:07:02.744Z', + 'entity.type': 'host', + 'entity.displayName': 'Troy McClure', + 'entity.id': '499', + }, +]; diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx index 9389fdaca3ea0..0903e8d1d01d4 100644 --- a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx @@ -5,12 +5,65 @@ * 2.0. */ import React from 'react'; +import { useAbortableAsync } from '@kbn/observability-utils/hooks/use_abortable_async'; +import { EuiDataGridSorting } from '@elastic/eui'; import { EntitiesGrid } from '../../components/entities_grid'; +import { useKibana } from '../../hooks/use_kibana'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; export function InventoryPage() { + const { + services: { inventoryAPIClient }, + } = useKibana(); + const { query } = useInventoryParams('/'); + const { sortDirection, sortField, pageIndex } = query; + const inventoryRoute = useInventoryRouter(); + + const { value = { entities: [] }, loading } = useAbortableAsync( + ({ signal }) => { + return inventoryAPIClient.fetch('GET /internal/inventory/entities', { + params: { + query: { + sortDirection, + sortField, + // TODO: update this to read data from the entity type search filter https://github.com/elastic/kibana/issues/192329 + entityTypes: JSON.stringify(['service', 'host', 'container']), + }, + }, + signal, + }); + }, + [inventoryAPIClient, sortDirection, sortField] + ); + + function handlePageChange(nextPage: number) { + inventoryRoute.push('/', { + path: {}, + query: { ...query, pageIndex: nextPage }, + }); + } + + function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + sortField: sorting.id, + sortDirection: sorting.direction, + }, + }); + } + return ( -
- -
+ ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx index 74eeaac220bc2..f0141a938e0bc 100644 --- a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx @@ -7,8 +7,10 @@ import * as t from 'io-ts'; import { createRouter, Outlet } from '@kbn/typed-react-router-config'; import React from 'react'; +import { toNumberRt } from '@kbn/io-ts-utils'; import { InventoryPageTemplate } from '../components/inventory_page_template'; import { InventoryPage } from '../pages/inventory_page'; +import { ENTITY_LAST_SEEN } from '../../common/es_fields/entities'; /** * The array of route definitions to be used when the application @@ -21,6 +23,20 @@ const inventoryRoutes = { ), + params: t.type({ + query: t.type({ + sortField: t.string, + sortDirection: t.union([t.literal('asc'), t.literal('desc')]), + pageIndex: toNumberRt, + }), + }), + defaults: { + query: { + sortField: ENTITY_LAST_SEEN, + sortDirection: 'desc', + pageIndex: '0', + }, + }, children: { '/{type}': { element: <>, diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 3583bf914ed38..42964060ca147 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -5,35 +5,47 @@ * 2.0. */ +import { ENTITY_LATEST, entitiesAliasPattern } from '@kbn/entities-schema'; import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; import { esqlResultToPlainObjects } from '@kbn/observability-utils/es/utils/esql_result_to_plain_objects'; -import { ENTITY_LATEST, entitiesAliasPattern } from '@kbn/entities-schema'; +import { MAX_NUMBER_OF_ENTITIES, type EntityType } from '../../../common/entities'; +import { + ENTITY_DISPLAY_NAME, + ENTITY_ID, + ENTITY_LAST_SEEN, + ENTITY_TYPE, +} from '../../../common/es_fields/entities'; const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ type: '*', dataset: ENTITY_LATEST, }); -const MAX_NUMBER_OF_ENTITIES = 500; interface LatestEntity { - 'entity.lastSeenTimestamp': string; - 'entity.type': string; - 'entity.displayName': string; - 'entity.id': string; + [ENTITY_LAST_SEEN]: string; + [ENTITY_TYPE]: string; + [ENTITY_DISPLAY_NAME]: string; + [ENTITY_ID]: string; } export async function getLatestEntities({ inventoryEsClient, + sortDirection, + sortField, + entityTypes, }: { inventoryEsClient: ObservabilityElasticsearchClient; + sortDirection: 'asc' | 'desc'; + sortField: string; + entityTypes: EntityType[]; }) { const latestEntitiesEsqlResponse = await inventoryEsClient.esql('get_latest_entities', { query: `FROM ${ENTITIES_LATEST_ALIAS} - | WHERE entity.type IN ("service", "host", "container") + | WHERE entity.type IN (${entityTypes.map((entityType) => `"${entityType}"`).join()}) | WHERE entity.definitionId IN ("builtin_services_from_ecs_data", "builtin_hosts_from_ecs_data", "builtin_containers_from_ecs_data") - | SORT entity.lastSeenTimestamp DESC + | SORT ${sortField} ${sortDirection} | LIMIT ${MAX_NUMBER_OF_ENTITIES} - | KEEP entity.id, entity.displayName, entity.lastSeenTimestamp, entity.type + | KEEP ${ENTITY_LAST_SEEN}, ${ENTITY_TYPE}, ${ENTITY_DISPLAY_NAME}, ${ENTITY_ID} `, }); 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 c5695aaf14718..1bc3acf890f99 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 @@ -4,16 +4,26 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { jsonRt } from '@kbn/io-ts-utils'; import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; +import * as t from 'io-ts'; +import { entityTypeRt } from '../../../common/entities'; import { createInventoryServerRoute } from '../create_inventory_server_route'; import { getLatestEntities } from './get_latest_entities'; export const listLatestEntitiesRoute = createInventoryServerRoute({ endpoint: 'GET /internal/inventory/entities', + params: t.type({ + query: t.type({ + sortField: t.string, + sortDirection: t.union([t.literal('asc'), t.literal('desc')]), + entityTypes: jsonRt.pipe(t.array(entityTypeRt)), + }), + }), options: { tags: ['access:inventory'], }, - handler: async ({ context, logger }) => { + handler: async ({ params, context, logger }) => { const coreContext = await context.core; const inventoryEsClient = createObservabilityEsClient({ client: coreContext.elasticsearch.client.asCurrentUser, @@ -21,7 +31,14 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ plugin: '@kbn/inventory-plugin', }); - const latestEntities = await getLatestEntities({ inventoryEsClient }); + const { sortDirection, sortField, entityTypes } = params.query; + + const latestEntities = await getLatestEntities({ + inventoryEsClient, + sortDirection, + sortField, + entityTypes, + }); return { entities: latestEntities }; }, From 1a7e3d9c82c8a2a5102c027ead40237b56fc74d2 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 10:53:48 +0100 Subject: [PATCH 08/17] removing apm --- .../inventory/server/utils/with_apm_span.ts | 7 ------- .../plugins/observability_solution/inventory/tsconfig.json | 5 ----- 2 files changed, 12 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts diff --git a/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts b/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts deleted file mode 100644 index b9e79df6cb0d7..0000000000000 --- a/x-pack/plugins/observability_solution/inventory/server/utils/with_apm_span.ts +++ /dev/null @@ -1,7 +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. - */ -// export { withApmSpan } from '@kbn/apm-data-access-plugin/server/utils'; diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index bfdf1ed23eacf..c0fc7c2692fde 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -35,11 +35,6 @@ "@kbn/server-route-repository-client", "@kbn/react-kibana-context-render", "@kbn/es-types", -<<<<<<< HEAD - "@kbn/entities-schema", - "@kbn/apm-data-access-plugin", -======= "@kbn/entities-schema" ->>>>>>> 59a0ca244219c701e0c2e80877ff0b6406227c13 ] } From 7448e2ee66f7ffa3fc118def6713fb63a4570b8b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:11:00 +0000 Subject: [PATCH 09/17] [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' --- x-pack/plugins/observability_solution/inventory/tsconfig.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index c0fc7c2692fde..e5e530ce1233f 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -35,6 +35,8 @@ "@kbn/server-route-repository-client", "@kbn/react-kibana-context-render", "@kbn/es-types", - "@kbn/entities-schema" + "@kbn/entities-schema", + "@kbn/i18n-react", + "@kbn/io-ts-utils" ] } From d99030bc23d714599abcba9b2dca1a3a99c15ccb Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 13:04:32 +0100 Subject: [PATCH 10/17] fixing ci --- .../inventory/server/routes/entities/get_latest_entities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 42964060ca147..3884d8941f9fe 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -21,7 +21,7 @@ const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ dataset: ENTITY_LATEST, }); -interface LatestEntity { +export interface LatestEntity { [ENTITY_LAST_SEEN]: string; [ENTITY_TYPE]: string; [ENTITY_DISPLAY_NAME]: string; From 0def3e085440cc9e5a1250fd4ba3a5d589727de0 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 13:18:59 +0100 Subject: [PATCH 11/17] PR comments --- .../inventory/common/es_fields/entities.ts | 1 + .../public/components/entities_grid/index.tsx | 4 +++- .../server/routes/entities/get_latest_entities.ts | 15 +++++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts b/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts index 5376bbe9cedcb..9b619dddbb2df 100644 --- a/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/es_fields/entities.ts @@ -9,3 +9,4 @@ export const ENTITY_LAST_SEEN = 'entity.lastSeenTimestamp'; export const ENTITY_ID = 'entity.id'; export const ENTITY_TYPE = 'entity.type'; export const ENTITY_DISPLAY_NAME = 'entity.displayName'; +export const ENTITY_DEFINITION_ID = 'entity.definitionId'; 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 3d3a3cb3c7d0f..88fd59bea3dca 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 @@ -126,7 +126,9 @@ export function EntitiesGrid({ case ENTITY_DISPLAY_NAME: return ( // TODO: link to the appropriate page based on entity type https://github.com/elastic/kibana/issues/192676 - {entity[columnEntityTableId]} + + {entity[columnEntityTableId]} + ); default: return entity[columnId as EntityColumnIds] || ''; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 3884d8941f9fe..87f8b63dc23ad 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -10,6 +10,7 @@ import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils/ import { esqlResultToPlainObjects } from '@kbn/observability-utils/es/utils/esql_result_to_plain_objects'; import { MAX_NUMBER_OF_ENTITIES, type EntityType } from '../../../common/entities'; import { + ENTITY_DEFINITION_ID, ENTITY_DISPLAY_NAME, ENTITY_ID, ENTITY_LAST_SEEN, @@ -21,6 +22,10 @@ const ENTITIES_LATEST_ALIAS = entitiesAliasPattern({ dataset: ENTITY_LATEST, }); +const BUILTIN_SERVICES_FROM_ECS_DATA = 'builtin_services_from_ecs_data'; +const BUILTIN_HOSTS_FROM_ECS_DATA = 'builtin_hosts_from_ecs_data'; +const BUILTIN_CONTAINERS_FROM_ECS_DATA = 'builtin_containers_from_ecs_data'; + export interface LatestEntity { [ENTITY_LAST_SEEN]: string; [ENTITY_TYPE]: string; @@ -41,8 +46,14 @@ export async function getLatestEntities({ }) { const latestEntitiesEsqlResponse = await inventoryEsClient.esql('get_latest_entities', { query: `FROM ${ENTITIES_LATEST_ALIAS} - | WHERE entity.type IN (${entityTypes.map((entityType) => `"${entityType}"`).join()}) - | WHERE entity.definitionId IN ("builtin_services_from_ecs_data", "builtin_hosts_from_ecs_data", "builtin_containers_from_ecs_data") + | WHERE ${ENTITY_TYPE} IN (${entityTypes.map((entityType) => `"${entityType}"`).join()}) + | WHERE ${ENTITY_DEFINITION_ID} IN (${[ + BUILTIN_SERVICES_FROM_ECS_DATA, + BUILTIN_HOSTS_FROM_ECS_DATA, + BUILTIN_CONTAINERS_FROM_ECS_DATA, + ] + .map((buildin) => `"${buildin}"`) + .join()}) | SORT ${sortField} ${sortDirection} | LIMIT ${MAX_NUMBER_OF_ENTITIES} | KEEP ${ENTITY_LAST_SEEN}, ${ENTITY_TYPE}, ${ENTITY_DISPLAY_NAME}, ${ENTITY_ID} From df5b7db3c8c0fce813512c69714aca8631bba83b Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 13:21:47 +0100 Subject: [PATCH 12/17] adding i18n --- .../public/components/entities_grid/index.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) 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 88fd59bea3dca..0cf51af7503b1 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 @@ -24,7 +24,6 @@ import { ENTITY_TYPE, } from '../../../common/es_fields/entities'; import { APIReturnType } from '../../api'; -import { MAX_NUMBER_OF_ENTITIES } from '../../../common/entities'; type InventoryEntitiesAPIReturnType = APIReturnType<'GET /internal/inventory/entities'>; @@ -33,17 +32,23 @@ type EntityColumnIds = typeof ENTITY_DISPLAY_NAME | typeof ENTITY_LAST_SEEN | ty const columns: EuiDataGridColumn[] = [ { id: ENTITY_DISPLAY_NAME, - displayAsText: 'Entity name', + displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.entityNameLabel', { + defaultMessage: 'Entity name', + }), isSortable: true, }, { id: ENTITY_TYPE, - displayAsText: 'Type', + displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.typeLabel', { + defaultMessage: 'type', + }), isSortable: true, }, { id: ENTITY_LAST_SEEN, - displayAsText: 'Last seen', + displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.lastSeenLabel', { + defaultMessage: 'Last seen', + }), defaultSortDirection: 'desc', isSortable: true, schema: 'datetime', @@ -163,7 +168,7 @@ export function EntitiesGrid({ {pageIndex * PAGE_SIZE + 1}-{PAGE_SIZE * currentPage} ), - total: MAX_NUMBER_OF_ENTITIES, + total: entities.length, boldEntites: ( {i18n.translate( From ce7946da1cdea2a59303295465badd7079848fee Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 13:37:53 +0100 Subject: [PATCH 13/17] pr comments --- .../entities_grid/entities_grid.stories.tsx | 20 ++++ .../public/components/entities_grid/index.tsx | 104 +++++++++--------- .../public/pages/inventory_page/index.tsx | 2 - .../routes/entities/get_latest_entities.ts | 7 +- .../inventory/server/routes/entities/route.ts | 14 ++- 5 files changed, 88 insertions(+), 59 deletions(-) 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 3a895c1ac71ed..b0e6c2fcc5ee4 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 @@ -43,3 +43,23 @@ export const Example: Story<{}> = () => { /> ); }; + +export const EmptyGridExample: Story<{}> = () => { + const [pageIndex, setPageIndex] = useState(0); + const [sort, setSort] = useState({ + id: ENTITY_LAST_SEEN, + direction: 'desc', + }); + + return ( + + ); +}; 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 0cf51af7503b1..d0524f57dd1cd 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 @@ -40,7 +40,7 @@ const columns: EuiDataGridColumn[] = [ { id: ENTITY_TYPE, displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.typeLabel', { - defaultMessage: 'type', + defaultMessage: 'Type', }), isSortable: true, }, @@ -88,56 +88,59 @@ export function EntitiesGrid({ [onChangeSort] ); - if (loading) { - return ; - } + const CellValue = useCallback( + ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => { + const entity = entities[rowIndex]; + if (entity === undefined) { + return null; + } - function CellValue({ rowIndex, columnId }: EuiDataGridCellValueElementProps) { - const entity = entities[rowIndex]; - if (entity === undefined) { - return null; - } + const columnEntityTableId = columnId as EntityColumnIds; + switch (columnEntityTableId) { + case ENTITY_TYPE: + return {entity[columnEntityTableId]}; + case ENTITY_LAST_SEEN: + return ( + + ), + time: ( + + ), + }} + /> + ); + case ENTITY_DISPLAY_NAME: + return ( + // TODO: link to the appropriate page based on entity type https://github.com/elastic/kibana/issues/192676 + + {entity[columnEntityTableId]} + + ); + default: + return entity[columnId as EntityColumnIds] || ''; + } + }, + [entities] + ); - const columnEntityTableId = columnId as EntityColumnIds; - switch (columnEntityTableId) { - case ENTITY_TYPE: - return {entity[columnEntityTableId]}; - case ENTITY_LAST_SEEN: - return ( - - ), - time: ( - - ), - }} - /> - ); - case ENTITY_DISPLAY_NAME: - return ( - // TODO: link to the appropriate page based on entity type https://github.com/elastic/kibana/issues/192676 - - {entity[columnEntityTableId]} - - ); - default: - return entity[columnId as EntityColumnIds] || ''; - } + if (loading) { + return ; } const currentPage = pageIndex + 1; @@ -165,7 +168,8 @@ export function EntitiesGrid({ values={{ currentItems: ( - {pageIndex * PAGE_SIZE + 1}-{PAGE_SIZE * currentPage} + {Math.min(entities.length, pageIndex * PAGE_SIZE + 1)}- + {Math.min(entities.length, PAGE_SIZE * currentPage)} ), total: entities.length, diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx index 0903e8d1d01d4..e77b46b26dc79 100644 --- a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx @@ -27,8 +27,6 @@ export function InventoryPage() { query: { sortDirection, sortField, - // TODO: update this to read data from the entity type search filter https://github.com/elastic/kibana/issues/192329 - entityTypes: JSON.stringify(['service', 'host', 'container']), }, }, signal, diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index 87f8b63dc23ad..e286f0e2fac75 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -33,6 +33,8 @@ export interface LatestEntity { [ENTITY_ID]: string; } +const DEFAULT_ENTITY_TYPES = ['service', 'host', 'container']; + export async function getLatestEntities({ inventoryEsClient, sortDirection, @@ -42,11 +44,12 @@ export async function getLatestEntities({ inventoryEsClient: ObservabilityElasticsearchClient; sortDirection: 'asc' | 'desc'; sortField: string; - entityTypes: EntityType[]; + entityTypes?: EntityType[]; }) { + const entityTypesFilter = entityTypes?.length ? entityTypes : DEFAULT_ENTITY_TYPES; const latestEntitiesEsqlResponse = await inventoryEsClient.esql('get_latest_entities', { query: `FROM ${ENTITIES_LATEST_ALIAS} - | WHERE ${ENTITY_TYPE} IN (${entityTypes.map((entityType) => `"${entityType}"`).join()}) + | WHERE ${ENTITY_TYPE} IN (${entityTypesFilter.map((entityType) => `"${entityType}"`).join()}) | WHERE ${ENTITY_DEFINITION_ID} IN (${[ BUILTIN_SERVICES_FROM_ECS_DATA, BUILTIN_HOSTS_FROM_ECS_DATA, 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 1bc3acf890f99..64d12bb8044b7 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 @@ -14,11 +14,15 @@ import { getLatestEntities } from './get_latest_entities'; export const listLatestEntitiesRoute = createInventoryServerRoute({ endpoint: 'GET /internal/inventory/entities', params: t.type({ - query: t.type({ - sortField: t.string, - sortDirection: t.union([t.literal('asc'), t.literal('desc')]), - entityTypes: jsonRt.pipe(t.array(entityTypeRt)), - }), + query: t.intersection([ + t.type({ + sortField: t.string, + sortDirection: t.union([t.literal('asc'), t.literal('desc')]), + }), + t.partial({ + entityTypes: jsonRt.pipe(t.array(entityTypeRt)), + }), + ]), }), options: { tags: ['access:inventory'], From 6ab74f1f43d7bfa6d459f705cdf6b04e6f4d1f2d Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 13:48:42 +0100 Subject: [PATCH 14/17] adding tootilp to grid --- .../public/components/entities_grid/index.tsx | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) 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 d0524f57dd1cd..f6e04151a6a65 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 @@ -6,6 +6,7 @@ */ import { EuiBadge, + EuiButtonIcon, EuiDataGrid, EuiDataGridCellValueElementProps, EuiDataGridColumn, @@ -13,6 +14,7 @@ import { EuiLink, EuiLoadingSpinner, EuiText, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedDate, FormattedMessage, FormattedTime } from '@kbn/i18n-react'; @@ -29,26 +31,55 @@ type InventoryEntitiesAPIReturnType = APIReturnType<'GET /internal/inventory/ent type EntityColumnIds = typeof ENTITY_DISPLAY_NAME | typeof ENTITY_LAST_SEEN | typeof ENTITY_TYPE; +const CustomHeaderCell = ({ title, tooltipContent }: { title: string; tooltipContent: string }) => ( + <> + {title} + + + + +); + const columns: EuiDataGridColumn[] = [ { id: ENTITY_DISPLAY_NAME, - displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.entityNameLabel', { - defaultMessage: 'Entity name', - }), + display: ( + + ), isSortable: true, }, { id: ENTITY_TYPE, - displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.typeLabel', { - defaultMessage: 'Type', - }), + display: ( + + ), isSortable: true, }, { id: ENTITY_LAST_SEEN, - displayAsText: i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.lastSeenLabel', { - defaultMessage: 'Last seen', - }), + display: ( + + ), defaultSortDirection: 'desc', isSortable: true, schema: 'datetime', From b2b47c5cd3625dc74a37252a777a6ceabe489be9 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 13:54:20 +0100 Subject: [PATCH 15/17] tooltip impro --- .../public/components/entities_grid/index.tsx | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) 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 f6e04151a6a65..cf94153dbfe51 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 @@ -45,14 +45,27 @@ const CustomHeaderCell = ({ title, tooltipContent }: { title: string; tooltipCon ); +const entityNameLabel = i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.entityNameLabel', { + defaultMessage: 'Entity name', +}); +const entityTypeLabel = i18n.translate('xpack.inventory.entitiesGrid.euiDataGrid.typeLabel', { + defaultMessage: 'Type', +}); +const entityLastSeenLabel = i18n.translate( + 'xpack.inventory.entitiesGrid.euiDataGrid.lastSeenLabel', + { + defaultMessage: 'Last seen', + } +); + const columns: EuiDataGridColumn[] = [ { id: ENTITY_DISPLAY_NAME, + // keep it for accessibility purposes + displayAsText: entityNameLabel, display: ( ), @@ -60,23 +73,20 @@ const columns: EuiDataGridColumn[] = [ }, { id: ENTITY_TYPE, + // keep it for accessibility purposes + displayAsText: entityTypeLabel, display: ( - + ), isSortable: true, }, { id: ENTITY_LAST_SEEN, + // keep it for accessibility purposes + displayAsText: entityLastSeenLabel, display: ( ), From 6a29a5efe392138d9da44411b6277ffc9e82b0e1 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 14:05:40 +0100 Subject: [PATCH 16/17] pr comments --- .../inventory/public/components/entities_grid/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 cf94153dbfe51..2003f990ccf29 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 @@ -129,7 +129,7 @@ export function EntitiesGrid({ [onChangeSort] ); - const CellValue = useCallback( + const renderCellValue = useCallback( ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => { const entity = entities[rowIndex]; if (entity === undefined) { @@ -195,7 +195,7 @@ export function EntitiesGrid({ columns={columns} columnVisibility={{ visibleColumns, setVisibleColumns }} rowCount={entities.length} - renderCellValue={CellValue} + renderCellValue={renderCellValue} toolbarVisibility={{ showColumnSelector: false, showSortSelector: false, From 30cfb1477341fbd5ee711169a37d37ec91b3d0ca Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 18 Sep 2024 14:23:30 +0100 Subject: [PATCH 17/17] pr comments --- .../inventory/public/components/entities_grid/index.tsx | 1 + .../inventory/server/routes/entities/route.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) 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 2003f990ccf29..c9b91f165fedd 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 @@ -196,6 +196,7 @@ export function EntitiesGrid({ columnVisibility={{ visibleColumns, setVisibleColumns }} rowCount={entities.length} renderCellValue={renderCellValue} + gridStyle={{ border: 'horizontal', header: 'shade' }} toolbarVisibility={{ showColumnSelector: false, showSortSelector: false, 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 64d12bb8044b7..e77dccb8b8cdb 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 @@ -7,6 +7,7 @@ import { jsonRt } from '@kbn/io-ts-utils'; import { createObservabilityEsClient } from '@kbn/observability-utils/es/client/create_observability_es_client'; import * as t from 'io-ts'; +import { INVENTORY_APP_ID } from '@kbn/deeplinks-observability/constants'; import { entityTypeRt } from '../../../common/entities'; import { createInventoryServerRoute } from '../create_inventory_server_route'; import { getLatestEntities } from './get_latest_entities'; @@ -32,7 +33,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ const inventoryEsClient = createObservabilityEsClient({ client: coreContext.elasticsearch.client.asCurrentUser, logger, - plugin: '@kbn/inventory-plugin', + plugin: `@kbn/${INVENTORY_APP_ID}-plugin`, }); const { sortDirection, sortField, entityTypes } = params.query;