diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx index efd3dac36daaa..d87b81aa3f6d0 100644 --- a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/cell_actions_popover.tsx @@ -26,6 +26,11 @@ import { useBoolean } from '@kbn/react-hooks'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { HttpStart } from '@kbn/core/public'; +import type { InfraDashboardLocatorParams } from '@kbn/observability-shared-plugin/common'; +import { INFRA_DASHBOARD_LOCATOR_ID } from '@kbn/observability-shared-plugin/common'; +import { DiscoverServices } from '@kbn/discover-plugin/public'; import { actionFilterForText, actionFilterOutText, @@ -36,7 +41,7 @@ import { filterOutText, openCellActionPopoverAriaText, } from './translations'; -import { truncateAndPreserveHighlightTags } from './utils'; +import { truncateAndPreserveHighlightTags, useGetK8sEntitiesDefinition } from './utils'; interface CellActionsPopoverProps { onFilter?: DocViewFilterFn; @@ -58,13 +63,6 @@ interface CellActionsPopoverProps { }) => ReactElement; } -const infraRoutes = { - overview: { - href: 'metrics/entity/Kubernetes/Overview?dashboardId=kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c', - label: 'Kubernetes Overview', - }, -}; - export function CellActionsPopover({ onFilter, property, @@ -74,24 +72,30 @@ export function CellActionsPopover({ renderPopoverTrigger, }: CellActionsPopoverProps) { const { euiTheme } = useEuiTheme(); + const { + services: { http, share }, + } = useKibana(); const [isPopoverOpen, { toggle: togglePopover, off: closePopover }] = useBoolean(false); - + const locator = + share && share.url.locators.get(INFRA_DASHBOARD_LOCATOR_ID); const makeFilterHandlerByOperator = (operator: '+' | '-') => () => { if (onFilter) { onFilter(property, rawValue, operator); } }; - const popoverTriggerProps = { onClick: togglePopover, onClickAriaLabel: openCellActionPopoverAriaText, 'data-test-subj': `dataTableCellActionsPopover_${property}`, }; - const infraProps = - property in infraRoutes - ? infraRoutes[property as keyof typeof infraRoutes] - : infraRoutes.overview; + const { data: rawEntitiesDefinition } = useGetK8sEntitiesDefinition({ + http: http as HttpStart, + }); + + const entityDefinition = rawEntitiesDefinition?.find((entity) => + entity.attributes.includes(property) + ); return ( ) : null} - - - Go to {infraProps.label} dashboard - - + {entityDefinition?.navigation?.href && ( + + + Go to {entityDefinition?.navigation?.title} dashboard + + + )} {(copy) => ( diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx index e302a468c9d7a..9ee77b985636f 100644 --- a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx @@ -20,9 +20,15 @@ import { TRACE_FIELDS, getLogDocumentOverview, getMessageFieldWithFallbacks, - METRIC_FIELDS, } from '@kbn/discover-utils'; -import { getAvailableResourceFields, getAvailableTraceFields } from '@kbn/discover-utils/src'; +import { + ResourceFields, + getAvailableResourceFields, + getAvailableTraceFields, +} from '@kbn/discover-utils/src'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { HttpStart } from '@kbn/core/public'; +import { EnrichedEntityDefinitionsResponse } from '@kbn/observability-navigation-plugin/common/types'; import { Resource } from './resource'; import { Content } from './content'; import { createResourceFields, formatJsonDocumentForContent, isTraceDocument } from './utils'; @@ -33,6 +39,7 @@ import { resourceLabel, traceLabel, } from '../translations'; +import { useGetK8sEntitiesDefinition } from '../utils'; export interface SummaryColumnFactoryDeps { density: DataGridDensity | undefined; @@ -51,9 +58,11 @@ export type AllSummaryColumnProps = SummaryColumnProps & SummaryColumnFactoryDep const getResourceFields = ({ isTracesDoc, isMetricsDoc, + k8sEntitiesDefinition, }: { isTracesDoc?: boolean; isMetricsDoc?: boolean; + k8sEntitiesDefinition: EnrichedEntityDefinitionsResponse[]; }) => { if (isTracesDoc) { return { @@ -63,9 +72,19 @@ const getResourceFields = ({ } if (isMetricsDoc) { + const k8sFields = k8sEntitiesDefinition?.map((entity) => entity.attributes) || []; + return { - fields: METRIC_FIELDS, - getAvailableFields: getAvailableResourceFields, + fields: k8sFields.flat(), + // move this into a separate util if needed in other places + getAvailableFields: (resourceDoc: ResourceFields) => + k8sFields.reduce((acc, fields) => { + const field = fields.find((fieldName) => resourceDoc[fieldName as keyof ResourceFields]); + if (field) { + acc.push(field); + } + return acc; + }, []), }; } @@ -77,12 +96,18 @@ const getResourceFields = ({ export const SummaryColumn = (props: AllSummaryColumnProps) => { const { isDetails } = props; + const { + services: { http }, + } = useKibana(); + const { data: k8sEntitiesDefinition } = useGetK8sEntitiesDefinition({ + http: http as HttpStart, + }); if (isDetails) { - return ; + return ; } - return ; + return ; }; // eslint-disable-next-line import/no-default-export @@ -95,9 +120,18 @@ const SummaryCell = ({ density: maybeNullishDensity, rowHeight: maybeNullishRowHeight, ...props -}: AllSummaryColumnProps) => { - const { dataView, onFilter, row, share, core, isTracesSummary, isMetricsSummary, fieldFormats } = - props; +}: AllSummaryColumnProps & { k8sEntitiesDefinition: any }) => { + const { + dataView, + onFilter, + row, + share, + core, + isTracesSummary, + isMetricsSummary, + fieldFormats, + k8sEntitiesDefinition, + } = props; const density = maybeNullishDensity ?? DataGridDensity.COMPACT; const isCompressed = density === DataGridDensity.COMPACT; @@ -108,6 +142,7 @@ const SummaryCell = ({ const specificFields = getResourceFields({ isTracesDoc: isTracesSummary && isTraceDocument(row), isMetricsDoc: isMetricsSummary, + k8sEntitiesDefinition, }); const resourceFields = createResourceFields({ @@ -119,7 +154,6 @@ const SummaryCell = ({ ...specificFields, }); - console.log('SummaryCell', resourceFields, 'resourceFields'); const shouldRenderResource = resourceFields.length > 0; return isSingleLine ? ( @@ -149,7 +183,9 @@ const SummaryCell = ({ ); }; -export const SummaryCellPopover = (props: AllSummaryColumnProps) => { +export const SummaryCellPopover = ( + props: AllSummaryColumnProps & { k8sEntitiesDefinition: any } +) => { const { row, dataView, @@ -160,12 +196,14 @@ export const SummaryCellPopover = (props: AllSummaryColumnProps) => { core, isTracesSummary, isMetricsSummary, + k8sEntitiesDefinition, } = props; const isTraceDoc = isTracesSummary && isTraceDocument(row); const specificFields = getResourceFields({ isTracesDoc: isTraceDoc, isMetricsDoc: isMetricsSummary, + k8sEntitiesDefinition, }); const resourceFields = createResourceFields({ row, diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx index b7eb208012209..046b237136df4 100644 --- a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx @@ -90,7 +90,6 @@ const getResourceBadgeComponent = ( core: CoreStart, share?: SharePluginStart ): React.ComponentType => { - console.log('getResourceBadgeComponent', name, 'name'); switch (name) { case EVENT_OUTCOME_FIELD: return EventOutcomeBadge; diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/index.ts b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/index.ts index 20078568b5190..809062b17816b 100644 --- a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/index.ts +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/index.ts @@ -8,3 +8,4 @@ */ export * from './truncate_preserve_highlight_tags'; +export * from './use_get_k8s_entities_definition'; diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/use_get_k8s_entities_definition.tsx b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/use_get_k8s_entities_definition.tsx new file mode 100644 index 0000000000000..fdc0bbdd58e57 --- /dev/null +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/utils/use_get_k8s_entities_definition.tsx @@ -0,0 +1,42 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { useQuery } from '@tanstack/react-query'; +import type { HttpStart } from '@kbn/core-http-browser'; +import { EnrichedEntityDefinitionsResponse } from '@kbn/observability-navigation-plugin/common/types'; +export interface UseGetK8sEntitiesDefinitionProps { + http: HttpStart; +} + +export const useGetK8sEntitiesDefinition = (props: UseGetK8sEntitiesDefinitionProps) => { + const { http } = props; + + const queryFn = async () => { + const result = await http.get( + `/internal/observability/entity_definitions/kubernetes` + ); + + return result; + }; + + const { data, isSuccess, isLoading, isFetching, isInitialLoading, isError, error } = useQuery({ + queryKey: ['useGetK8sEntitiesDefinition'], + queryFn, + refetchOnWindowFocus: false, + }); + + return { + data, + isLoading: isLoading || isFetching, + isInitialLoading, + isSuccess, + isError, + error, + }; +}; diff --git a/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/constants.ts b/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/constants.ts index 9df72f326572b..bdc316e1561d7 100644 --- a/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/constants.ts +++ b/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/constants.ts @@ -89,14 +89,7 @@ export const RESOURCE_FIELDS = [ fieldConstants.ORCHESTRATOR_CLUSTER_ID_FIELD, fieldConstants.CONTAINER_ID_FIELD, fieldConstants.AGENT_NAME_FIELD, - 'kubernetes.container.name', ] as const; -export const METRIC_FIELDS = [ - 'kubernetes.container.name', - 'k8s.container.name', - 'kubernetes.pod.name', - 'k8s.pod.name', -]; export const TRACE_FIELDS = [ fieldConstants.SERVICE_NAME_FIELD, fieldConstants.EVENT_OUTCOME_FIELD, diff --git a/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts b/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts index 8623310db99c4..15750c99dc0fd 100644 --- a/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts +++ b/src/platform/packages/shared/kbn-discover-utils/src/data_types/logs/utils/get_available_resource_fields.ts @@ -36,7 +36,6 @@ const AVAILABLE_RESOURCE_FIELDS: Array> = [ export const getAvailableResourceFields = (resourceDoc: ResourceFields) => AVAILABLE_RESOURCE_FIELDS.reduce((acc, fields) => { - console.log('getAvailableResourceFields', fields, resourceDoc); const field = fields.find((fieldName) => resourceDoc[fieldName]); if (field) { acc.push(field); diff --git a/src/platform/plugins/shared/discover/kibana.jsonc b/src/platform/plugins/shared/discover/kibana.jsonc index 467d6cfbbc8c5..e1a2915f23e20 100644 --- a/src/platform/plugins/shared/discover/kibana.jsonc +++ b/src/platform/plugins/shared/discover/kibana.jsonc @@ -30,7 +30,8 @@ "expressions", "unifiedDocViewer", "unifiedSearch", - "contentManagement" + "contentManagement", + "observabilityShared" ], "optionalPlugins": [ "dataVisualizer", diff --git a/src/platform/plugins/shared/discover/public/application/discover_router.tsx b/src/platform/plugins/shared/discover/public/application/discover_router.tsx index 1d4c6f1d29f72..77413d3fa9fa8 100644 --- a/src/platform/plugins/shared/discover/public/application/discover_router.tsx +++ b/src/platform/plugins/shared/discover/public/application/discover_router.tsx @@ -12,6 +12,7 @@ import { Router, Routes, Route } from '@kbn/shared-ux-router'; import React from 'react'; import { EuiErrorBoundary } from '@elastic/eui'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ContextAppRoute } from './context'; import { SingleDocRoute } from './doc'; import { NotFoundRoute } from './not_found'; @@ -25,12 +26,15 @@ export interface DiscoverRouterProps { customizationContext: DiscoverCustomizationContext; } +const queryClient = new QueryClient(); export const DiscoverRouter = ({ services, ...routeProps }: DiscoverRouterProps) => { return ( - + + + diff --git a/x-pack/platform/plugins/shared/observability_navigation/server/routes/internal/setup/get_navigation_items.ts b/x-pack/platform/plugins/shared/observability_navigation/server/routes/internal/setup/get_navigation_items.ts index d0fa91234800e..4dd122cd81b05 100644 --- a/x-pack/platform/plugins/shared/observability_navigation/server/routes/internal/setup/get_navigation_items.ts +++ b/x-pack/platform/plugins/shared/observability_navigation/server/routes/internal/setup/get_navigation_items.ts @@ -46,14 +46,14 @@ export async function getNavigationItems({ id: 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013', entityId: 'entity.k8s.cronjob', sideNavTitle: 'Cron jobs', - sideNavOrder: 900, + sideNavOrder: 1200, type: 'dashboard', }, { id: 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013', entityId: 'entity.k8s.statefulset', sideNavTitle: 'Stateful sets', - sideNavOrder: 600, + sideNavOrder: 900, type: 'dashboard', }, @@ -61,28 +61,49 @@ export async function getNavigationItems({ id: 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013', entityId: 'entity.k8s.pod', sideNavTitle: 'Pods', + sideNavOrder: 400, + type: 'dashboard', + }, + { + id: 'kubernetes_otel-cluster-overview', + entityId: 'entity.k8s.namespace', + sideNavTitle: 'Namespaces', sideNavOrder: 300, type: 'dashboard', }, + { + id: 'kubernetes_otel-cluster-overview', + entityId: 'entity.k8s.replicaset', + sideNavTitle: 'Replicaset', + sideNavOrder: 700, + type: 'dashboard', + }, + { + id: 'kubernetes_otel-cluster-overview', + entityId: 'entity.k8s.container', + sideNavTitle: 'Containers', + sideNavOrder: 500, + type: 'dashboard', + }, { id: 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013', entityId: 'entity.k8s.deployment', sideNavTitle: 'Deployments', - sideNavOrder: 400, + sideNavOrder: 600, type: 'dashboard', }, { id: 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013', entityId: 'entity.k8s.daemonset', sideNavTitle: 'Daemon sets', - sideNavOrder: 700, + sideNavOrder: 1000, type: 'dashboard', }, { id: 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013', entityId: 'entity.k8s.job', sideNavTitle: 'Jobs', - sideNavOrder: 800, + sideNavOrder: 1100, type: 'dashboard', }, { @@ -195,7 +216,7 @@ function formatId(id: string): string { } function buildHref(id: string, parent?: string): string { - const href = `${parent ? `${parent}/` : ''}${id}`; + const href = `/${parent ? `${parent}/` : ''}${id}`; return href; } diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/metrics/dashboard/components/page_content/page_content.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/metrics/dashboard/components/page_content/page_content.tsx index b486e08652ee9..e220d18e81055 100644 --- a/x-pack/solutions/observability/plugins/infra/public/pages/metrics/dashboard/components/page_content/page_content.tsx +++ b/x-pack/solutions/observability/plugins/infra/public/pages/metrics/dashboard/components/page_content/page_content.tsx @@ -58,8 +58,8 @@ export const PageContent = ({ ) : ( <> - {entityId ? : null} + {entityId ? : null} )}