diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx deleted file mode 100644 index 7614b46014378..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx +++ /dev/null @@ -1,233 +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 { EuiPortal, EuiTabs, EuiTab, EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useMemo, useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; -import { EuiOutsideClickDetector } from '@elastic/eui'; -import { EuiIcon, EuiButtonIcon } from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { useLinkProps } from '@kbn/observability-shared-plugin/public'; -import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; -import { InventoryItemType } from '../../../../../../common/inventory_models/types'; -import { MetricsTab } from './tabs/metrics/metrics'; -import { LogsTab } from './tabs/logs'; -import { ProcessesTab } from './tabs/processes'; -import { PropertiesTab } from './tabs/properties'; -import { AnomaliesTab } from './tabs/anomalies/anomalies'; -import { OsqueryTab } from './tabs/osquery'; -import { OVERLAY_Y_START, OVERLAY_BOTTOM_MARGIN } from './tabs/shared'; -import { useNodeDetailsRedirect } from '../../../../link_to'; -import { findInventoryModel } from '../../../../../../common/inventory_models'; -import { navigateToUptime } from '../../lib/navigate_to_uptime'; -import { InfraClientCoreStart, InfraClientStartDeps } from '../../../../../types'; - -interface Props { - isOpen: boolean; - onClose(): void; - options: InfraWaffleMapOptions; - currentTime: number; - node: InfraWaffleMapNode; - nodeType: InventoryItemType; - openAlertFlyout(): void; -} -export const NodeContextPopover = ({ - isOpen, - node, - nodeType, - currentTime, - options, - onClose, - openAlertFlyout, -}: Props) => { - // eslint-disable-next-line react-hooks/exhaustive-deps - const tabConfigs = [MetricsTab, LogsTab, ProcessesTab, PropertiesTab, AnomaliesTab, OsqueryTab]; - const inventoryModel = findInventoryModel(nodeType); - const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; - const { application, share } = useKibana().services; - const { getNodeDetailUrl } = useNodeDetailsRedirect(); - const uiCapabilities = application?.capabilities; - const canCreateAlerts = useMemo( - () => Boolean(uiCapabilities?.infrastructure?.save), - [uiCapabilities] - ); - - const tabs = useMemo(() => { - return tabConfigs.map((m) => { - const TabContent = m.content; - return { - ...m, - content: ( - - ), - }; - }); - }, [tabConfigs, node, nodeType, currentTime, onClose, options]); - - const [selectedTab, setSelectedTab] = useState(0); - - const nodeDetailMenuItemLinkProps = useLinkProps({ - ...getNodeDetailUrl({ - assetType: nodeType, - assetId: node.id, - search: { - from: nodeDetailFrom, - to: currentTime, - name: node.name, - }, - }), - }); - const apmField = nodeType === 'host' ? 'host.hostname' : inventoryModel.fields.id; - const apmTracesMenuItemLinkProps = useLinkProps({ - app: 'apm', - hash: 'traces', - search: { - kuery: `${apmField}:"${node.id}"`, - }, - }); - - if (!isOpen) { - return null; - } - - return ( - - - - - - - -

{node.name}

-
-
- - - {canCreateAlerts && ( - - - - - - )} - - - - - - - - - - -
- - - {tabs.map((tab, i) => ( - setSelectedTab(i)} - > - {tab.name} - - ))} - - {' '} - - - navigateToUptime(share.url.locators, nodeType, node)}> - {' '} - - - -
- {tabs[selectedTab].content} -
-
-
- ); -}; - -const OverlayHeader = euiStyled.div` - padding-top: ${(props) => props.theme.eui.euiSizeM}; - padding-right: ${(props) => props.theme.eui.euiSizeM}; - padding-left: ${(props) => props.theme.eui.euiSizeM}; - background-color: ${(props) => props.theme.eui.euiPageBackgroundColor}; - box-shadow: inset 0 -1px ${(props) => props.theme.eui.euiBorderColor}; -`; - -const OverlayPanel = euiStyled(EuiPanel).attrs({ paddingSize: 'none' })` - display: flex; - flex-direction: column; - position: absolute; - right: 16px; - top: ${OVERLAY_Y_START}px; - width: 100%; - max-width: 720px; - z-index: 2; - max-height: calc(100vh - ${OVERLAY_Y_START + OVERLAY_BOTTOM_MARGIN}px); - overflow: hidden; - - @media (max-width: 752px) { - border-radius: 0px !important; - left: 0px; - right: 0px; - top: 97px; - bottom: 0; - max-height: calc(100vh - 97px); - max-width: 100%; - } -`; - -const OverlayTitle = euiStyled(EuiFlexItem)` - overflow: hidden; - & h4 { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/anomalies/anomalies.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/anomalies/anomalies.tsx deleted file mode 100644 index 40dad03f73366..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/anomalies/anomalies.tsx +++ /dev/null @@ -1,29 +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 { i18n } from '@kbn/i18n'; -import React from 'react'; -import { AnomaliesTable } from '../../../ml/anomaly_detection/anomalies_table/anomalies_table'; -import { TabContent, TabProps } from '../shared'; - -const TabComponent = (props: TabProps) => { - const { node, onClose } = props; - - return ( - - - - ); -}; - -export const AnomaliesTab = { - id: 'anomalies', - name: i18n.translate('xpack.infra.nodeDetails.tabs.anomalies', { - defaultMessage: 'Anomalies', - }), - content: TabComponent, -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx deleted file mode 100644 index ddbf4ae52788b..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx +++ /dev/null @@ -1,110 +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, { useCallback, useMemo, useState } from 'react'; -import useDebounce from 'react-use/lib/useDebounce'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; -import { EuiFieldSearch } from '@elastic/eui'; -import { EuiFlexGroup } from '@elastic/eui'; -import { EuiFlexItem } from '@elastic/eui'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; -import { LogStream } from '@kbn/logs-shared-plugin/public'; -import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; -import { TabContent, TabProps } from './shared'; -import { useWaffleOptionsContext } from '../../../hooks/use_waffle_options'; -import { findInventoryFields } from '../../../../../../../common/inventory_models'; - -const TabComponent = (props: TabProps) => { - const { services } = useKibanaContextForPlugin(); - const { locators } = services; - const [textQuery, setTextQuery] = useState(''); - const [textQueryDebounced, setTextQueryDebounced] = useState(''); - const endTimestamp = props.currentTime; - const startTimestamp = endTimestamp - 60 * 60 * 1000; // 60 minutes - const { nodeType } = useWaffleOptionsContext(); - const { node } = props; - - useDebounce(() => setTextQueryDebounced(textQuery), textQueryThrottleInterval, [textQuery]); - - const filter = useMemo(() => { - const query = [ - `${findInventoryFields(nodeType).id}: "${node.id}"`, - ...(textQueryDebounced !== '' ? [textQueryDebounced] : []), - ].join(' and '); - - return { - language: 'kuery', - query, - }; - }, [nodeType, node.id, textQueryDebounced]); - - const onQueryChange = useCallback((e: React.ChangeEvent) => { - setTextQuery(e.target.value); - }, []); - - const logsUrl = useMemo(() => { - return locators.nodeLogsLocator.getRedirectUrl({ - nodeType, - nodeId: node.id, - time: startTimestamp, - filter: textQueryDebounced, - }); - }, [locators.nodeLogsLocator, node.id, nodeType, startTimestamp, textQueryDebounced]); - - return ( - - - - - - - - - - - - - - - - ); -}; - -export const LogsTab = { - id: 'logs', - name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', { - defaultMessage: 'Logs', - }), - content: TabComponent, -}; - -const textQueryThrottleInterval = 1000; // milliseconds diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/chart_header.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/chart_header.tsx deleted file mode 100644 index 2c371691f4587..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/chart_header.tsx +++ /dev/null @@ -1,63 +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 { EuiText } from '@elastic/eui'; -import { EuiFlexItem } from '@elastic/eui'; -import React from 'react'; -import { EuiFlexGroup } from '@elastic/eui'; -import { EuiIcon } from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { colorTransformer } from '../../../../../../../../common/color_palette'; -import { MetricsExplorerOptionsMetric } from '../../../../../metrics_explorer/hooks/use_metrics_explorer_options'; - -interface Props { - title: string; - metrics: MetricsExplorerOptionsMetric[]; -} - -export const ChartHeader = ({ title, metrics }: Props) => { - return ( - - - -

{title}

-
-
- - - {metrics.map((chartMetric) => ( - - - - - - - {chartMetric.label} - - - - ))} - - -
- ); -}; - -const HeaderItem = euiStyled(EuiFlexItem).attrs({ grow: 1 })` - overflow: hidden; -`; - -const H4 = euiStyled('h4')` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/chart_section.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/chart_section.tsx deleted file mode 100644 index e078f25d60437..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/chart_section.tsx +++ /dev/null @@ -1,103 +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 { - Axis, - Chart, - ChartSizeArray, - PointerUpdateListener, - Position, - Settings, - TickFormatter, - TooltipProps, - Tooltip, -} from '@elastic/charts'; -import moment from 'moment'; -import React from 'react'; -import { useTimelineChartTheme } from '../../../../../../../utils/use_timeline_chart_theme'; -import { MetricsExplorerSeries } from '../../../../../../../../common/http_api'; -import { MetricExplorerSeriesChart } from '../../../../../metrics_explorer/components/series_chart'; -import { - MetricsExplorerChartType, - MetricsExplorerOptionsMetric, -} from '../../../../../metrics_explorer/hooks/use_metrics_explorer_options'; -import { ChartHeader } from './chart_header'; - -const CHART_SIZE: ChartSizeArray = ['100%', 160]; - -interface Props { - title: string; - style: MetricsExplorerChartType; - chartRef: React.Ref; - series: ChartSectionSeries[]; - tickFormatterForTime: TickFormatter; - tickFormatter: TickFormatter; - onPointerUpdate: PointerUpdateListener; - domain: { max: number; min: number }; - stack?: boolean; -} - -export interface ChartSectionSeries { - metric: MetricsExplorerOptionsMetric; - series: MetricsExplorerSeries; -} - -export const ChartSection = ({ - title, - style, - chartRef, - series, - tickFormatterForTime, - tickFormatter, - onPointerUpdate, - domain, - stack = false, -}: Props) => { - const chartTheme = useTimelineChartTheme(); - const metrics = series.map((chartSeries) => chartSeries.metric); - const tooltipProps: TooltipProps = { - headerFormatter: ({ value }) => moment(value).format('Y-MM-DD HH:mm:ss.SSS'), - }; - - return ( - <> - - - {series.map((chartSeries, index) => ( - - ))} - - - - - - - ); -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/index.tsx deleted file mode 100644 index 6cc79a1c32375..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/index.tsx +++ /dev/null @@ -1,8 +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 * from './metrics'; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/metrics.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/metrics.tsx deleted file mode 100644 index 6e8908bf2362a..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/metrics.tsx +++ /dev/null @@ -1,460 +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, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { Chart, niceTimeFormatter, PointerEvent } from '@elastic/charts'; -import { EuiLoadingChart, EuiSpacer, EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; -import { first, last } from 'lodash'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { TabContent, TabProps } from '../shared'; -import { useSnapshot } from '../../../../hooks/use_snaphot'; -import { useWaffleOptionsContext } from '../../../../hooks/use_waffle_options'; -import { useSourceContext } from '../../../../../../../containers/metrics_source'; -import { findInventoryFields } from '../../../../../../../../common/inventory_models'; -import { convertKueryToElasticSearchQuery } from '../../../../../../../utils/kuery'; -import { SnapshotMetricType } from '../../../../../../../../common/inventory_models/types'; -import { - MetricsExplorerChartType, - MetricsExplorerOptionsMetric, -} from '../../../../../metrics_explorer/hooks/use_metrics_explorer_options'; -import { Color } from '../../../../../../../../common/color_palette'; -import { - MetricsExplorerAggregation, - MetricsExplorerSeries, -} from '../../../../../../../../common/http_api'; -import { createInventoryMetricFormatter } from '../../../../lib/create_inventory_metric_formatter'; -import { calculateDomain } from '../../../../../metrics_explorer/components/helpers/calculate_domain'; -import { ChartSection } from './chart_section'; -import { - SYSTEM_METRIC_NAME, - USER_METRIC_NAME, - INBOUND_METRIC_NAME, - OUTBOUND_METRIC_NAME, - USED_MEMORY_METRIC_NAME, - FREE_MEMORY_METRIC_NAME, - CPU_CHART_TITLE, - LOAD_CHART_TITLE, - MEMORY_CHART_TITLE, - NETWORK_CHART_TITLE, - LOG_RATE_METRIC_NAME, - LOG_RATE_CHART_TITLE, -} from './translations'; -import { TimeDropdown } from './time_dropdown'; -import { getCustomMetricLabel } from '../../../../../../../../common/formatters/get_custom_metric_label'; -import { createFormatterForMetric } from '../../../../../metrics_explorer/components/helpers/create_formatter_for_metric'; - -const ONE_HOUR = 60 * 60 * 1000; - -const TabComponent = (props: TabProps) => { - const cpuChartRef = useRef(null); - const networkChartRef = useRef(null); - const memoryChartRef = useRef(null); - const loadChartRef = useRef(null); - const logRateChartRef = useRef(null); - const customMetricRefs = useRef>({}); - const [time, setTime] = useState(ONE_HOUR); - const chartRefs = useMemo(() => { - const refs = [cpuChartRef, networkChartRef, memoryChartRef, loadChartRef, logRateChartRef]; - return [...refs, customMetricRefs]; - }, [ - cpuChartRef, - networkChartRef, - memoryChartRef, - loadChartRef, - logRateChartRef, - customMetricRefs, - ]); - const { sourceId, createDerivedIndexPattern } = useSourceContext(); - const { nodeType, accountId, region, customMetrics } = useWaffleOptionsContext(); - const { currentTime, node } = props; - const derivedIndexPattern = useMemo( - () => createDerivedIndexPattern(), - [createDerivedIndexPattern] - ); - let filter = `${findInventoryFields(nodeType).id}: "${node.id}"`; - - if (filter) { - filter = convertKueryToElasticSearchQuery(filter, derivedIndexPattern); - } - - const buildCustomMetric = useCallback( - (field: string, id: string, aggregation: string = 'avg') => ({ - type: 'custom' as SnapshotMetricType, - aggregation, - field, - id, - }), - [] - ); - - const updateTime = useCallback( - (e: React.ChangeEvent) => { - setTime(Number(e.currentTarget.value)); - }, - [setTime] - ); - - const timeRange = { - interval: '1m', - to: currentTime, - from: currentTime - time, - ignoreLookback: true, - }; - - const defaultMetrics: Array<{ type: SnapshotMetricType }> = [ - { type: 'rx' }, - { type: 'tx' }, - buildCustomMetric('system.cpu.user.pct', 'user'), - buildCustomMetric('system.cpu.system.pct', 'system'), - buildCustomMetric('system.load.1', 'load1m'), - buildCustomMetric('system.load.5', 'load5m'), - buildCustomMetric('system.load.15', 'load15m'), - buildCustomMetric('system.memory.actual.used.bytes', 'usedMemory'), - buildCustomMetric('system.memory.actual.free', 'freeMemory'), - buildCustomMetric('system.cpu.cores', 'cores', 'max'), - ]; - - const { nodes, reload } = useSnapshot({ - filterQuery: filter, - metrics: [...defaultMetrics, ...customMetrics], - groupBy: [], - nodeType, - sourceId, - currentTime, - accountId, - region, - sendRequestImmediately: false, - timerange: timeRange, - }); - - const { nodes: logRateNodes, reload: reloadLogRate } = useSnapshot({ - filterQuery: filter, - metrics: [{ type: 'logRate' }], - groupBy: [], - nodeType, - sourceId, - currentTime, - accountId, - region, - sendRequestImmediately: false, - timerange: timeRange, - }); - - const getDomain = useCallback( - (timeseries: MetricsExplorerSeries, ms: MetricsExplorerOptionsMetric[]) => { - const dataDomain = timeseries ? calculateDomain(timeseries, ms, false) : null; - return dataDomain - ? { - max: dataDomain.max * 1.1, // add 10% headroom. - min: dataDomain.min, - } - : { max: 0, min: 0 }; - }, - [] - ); - - const dateFormatter = useCallback((timeseries: MetricsExplorerSeries) => { - if (!timeseries) return () => ''; - const firstTimestamp = first(timeseries.rows)?.timestamp; - const lastTimestamp = last(timeseries.rows)?.timestamp; - - if (firstTimestamp == null || lastTimestamp == null) { - return (value: number) => `${value}`; - } - - return niceTimeFormatter([firstTimestamp, lastTimestamp]); - }, []); - - const networkFormatter = useMemo(() => createInventoryMetricFormatter({ type: 'rx' }), []); - const cpuFormatter = useMemo(() => createInventoryMetricFormatter({ type: 'cpu' }), []); - const memoryFormatter = useMemo( - () => createInventoryMetricFormatter({ type: 's3BucketSize' }), - [] - ); - const loadFormatter = useMemo(() => createInventoryMetricFormatter({ type: 'load' }), []); - const logRateFormatter = useMemo(() => createInventoryMetricFormatter({ type: 'logRate' }), []); - - const mergeTimeseries = useCallback((...series: MetricsExplorerSeries[]) => { - const base = series[0]; - const otherSeries = series.slice(1); - base.rows = base.rows.map((b, rowIdx) => { - const newRow = { ...b }; - otherSeries.forEach((o, idx) => { - newRow[`metric_${idx + 1}`] = o.rows[rowIdx].metric_0; - }); - return newRow; - }); - return base; - }, []); - - const buildChartMetricLabels = useCallback( - (labels: string[], aggregation: MetricsExplorerAggregation) => { - const baseMetric = { - color: Color.color0, - aggregation, - label: 'System', - }; - - return labels.map((label, idx) => { - return { ...baseMetric, color: Color[`color${idx}` as Color], label }; - }); - }, - [] - ); - - const pointerUpdate = useCallback( - (event: PointerEvent) => { - chartRefs.forEach((ref) => { - if (ref.current) { - if (ref.current instanceof Chart) { - ref.current.dispatchExternalPointerEvent(event); - } else { - const charts = Object.values(ref.current); - charts.forEach((c) => { - if (c) { - c.dispatchExternalPointerEvent(event); - } - }); - } - } - }); - }, - [chartRefs] - ); - - const getTimeseries = useCallback( - (metricName: string) => { - if (!nodes || !nodes.length) { - return null; - } - return nodes[0].metrics.find((m) => m.name === metricName)!.timeseries!; - }, - [nodes] - ); - - const getLogRateTimeseries = useCallback(() => { - if (!logRateNodes) { - return null; - } - if (logRateNodes.length === 0) { - return { rows: [], columns: [], id: '0' }; - } - return logRateNodes[0].metrics.find((m) => m.name === 'logRate')!.timeseries!; - }, [logRateNodes]); - - const systemMetricsTs = useMemo(() => getTimeseries('system'), [getTimeseries]); - const userMetricsTs = useMemo(() => getTimeseries('user'), [getTimeseries]); - const rxMetricsTs = useMemo(() => getTimeseries('rx'), [getTimeseries]); - const txMetricsTs = useMemo(() => getTimeseries('tx'), [getTimeseries]); - const load1mMetricsTs = useMemo(() => getTimeseries('load1m'), [getTimeseries]); - const load5mMetricsTs = useMemo(() => getTimeseries('load5m'), [getTimeseries]); - const load15mMetricsTs = useMemo(() => getTimeseries('load15m'), [getTimeseries]); - const usedMemoryMetricsTs = useMemo(() => getTimeseries('usedMemory'), [getTimeseries]); - const freeMemoryMetricsTs = useMemo(() => getTimeseries('freeMemory'), [getTimeseries]); - const coresMetricsTs = useMemo(() => getTimeseries('cores'), [getTimeseries]); - const logRateMetricsTs = useMemo(() => getLogRateTimeseries(), [getLogRateTimeseries]); - - useEffect(() => { - reload(); - reloadLogRate(); - }, [time, reload, reloadLogRate]); - - if ( - !systemMetricsTs || - !userMetricsTs || - !rxMetricsTs || - !txMetricsTs || - !load1mMetricsTs || - !load5mMetricsTs || - !load15mMetricsTs || - !usedMemoryMetricsTs || - !freeMemoryMetricsTs || - !logRateMetricsTs - ) { - return ; - } - - const cpuChartMetrics = buildChartMetricLabels([SYSTEM_METRIC_NAME, USER_METRIC_NAME], 'avg'); - const logRateChartMetrics = buildChartMetricLabels([LOG_RATE_METRIC_NAME], 'rate'); - const networkChartMetrics = buildChartMetricLabels( - [INBOUND_METRIC_NAME, OUTBOUND_METRIC_NAME], - 'rate' - ); - const loadChartMetrics = buildChartMetricLabels(['1m', '5m', '15m'], 'avg'); - const memoryChartMetrics = buildChartMetricLabels( - [USED_MEMORY_METRIC_NAME, FREE_MEMORY_METRIC_NAME], - 'rate' - ); - - systemMetricsTs.rows = systemMetricsTs.rows.slice().map((r, idx) => { - const metric = r.metric_0 as number | undefined; - const cores = coresMetricsTs!.rows[idx].metric_0 as number | undefined; - if (metric && cores) { - r.metric_0 = metric / cores; - } - return r; - }); - - userMetricsTs.rows = userMetricsTs.rows.slice().map((r, idx) => { - const metric = r.metric_0 as number | undefined; - const cores = coresMetricsTs!.rows[idx].metric_0 as number | undefined; - if (metric && cores) { - r.metric_0 = metric / cores; - } - return r; - }); - const cpuTimeseries = mergeTimeseries(systemMetricsTs, userMetricsTs); - const logRateTimeseries = mergeTimeseries(logRateMetricsTs); - const networkTimeseries = mergeTimeseries(rxMetricsTs, txMetricsTs); - const loadTimeseries = mergeTimeseries(load1mMetricsTs, load5mMetricsTs, load15mMetricsTs); - const memoryTimeseries = mergeTimeseries(usedMemoryMetricsTs, freeMemoryMetricsTs); - - const formatter = dateFormatter(rxMetricsTs); - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - {customMetrics.map((c) => { - const metricTS = getTimeseries(c.id); - const chartMetrics = buildChartMetricLabels([c.field], c.aggregation); - if (!metricTS) return null; - return ( - - { - customMetricRefs.current[c.id] = r; - }} - series={[{ metric: chartMetrics[0], series: metricTS }]} - tickFormatterForTime={formatter} - tickFormatter={createFormatterForMetric(c)} - onPointerUpdate={pointerUpdate} - domain={getDomain(mergeTimeseries(metricTS), chartMetrics)} - stack={true} - /> - - ); - })} - - - ); -}; - -const ChartGridItem = euiStyled(EuiFlexItem)` - overflow: hidden -`; - -const LoadingPlaceholder = () => { - return ( -
- -
- ); -}; - -export const MetricsTab = { - id: 'metrics', - name: i18n.translate('xpack.infra.nodeDetails.tabs.metrics', { - defaultMessage: 'Metrics', - }), - content: TabComponent, -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/time_dropdown.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/time_dropdown.tsx deleted file mode 100644 index a7e9aef892e04..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/time_dropdown.tsx +++ /dev/null @@ -1,56 +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 { EuiSelect } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -interface Props { - value: number; - onChange(event: React.ChangeEvent): void; -} - -export const TimeDropdown = (props: Props) => ( - -); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/translations.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/translations.tsx deleted file mode 100644 index 940d97918b181..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics/translations.tsx +++ /dev/null @@ -1,66 +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 { i18n } from '@kbn/i18n'; - -export const SYSTEM_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.system', { - defaultMessage: 'System', -}); - -export const USER_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.user', { - defaultMessage: 'User', -}); - -export const INBOUND_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.inbound', { - defaultMessage: 'Inbound', -}); - -export const OUTBOUND_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.outbound', { - defaultMessage: 'Outbound', -}); - -export const USED_MEMORY_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.used', { - defaultMessage: 'Used', -}); - -export const CACHED_MEMORY_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.cached', { - defaultMessage: 'Cached', -}); - -export const FREE_MEMORY_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.free', { - defaultMessage: 'Free', -}); - -export const NETWORK_CHART_TITLE = i18n.translate( - 'xpack.infra.nodeDetails.metrics.charts.networkTitle', - { - defaultMessage: 'Network', - } -); -export const MEMORY_CHART_TITLE = i18n.translate( - 'xpack.infra.nodeDetails.metrics.charts.memoryTitle', - { - defaultMessage: 'Memory', - } -); -export const CPU_CHART_TITLE = i18n.translate('xpack.infra.nodeDetails.metrics.fcharts.cpuTitle', { - defaultMessage: 'CPU', -}); -export const LOAD_CHART_TITLE = i18n.translate('xpack.infra.nodeDetails.metrics.charts.loadTitle', { - defaultMessage: 'Load', -}); - -export const LOG_RATE_METRIC_NAME = i18n.translate('xpack.infra.nodeDetails.metrics.logRate', { - defaultMessage: 'Log Rate', -}); - -export const LOG_RATE_CHART_TITLE = i18n.translate( - 'xpack.infra.nodeDetails.metrics.charts.logRateTitle', - { - defaultMessage: 'Log Rate', - } -); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/osquery/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/osquery/index.tsx deleted file mode 100644 index 26ff945d04025..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/osquery/index.tsx +++ /dev/null @@ -1,66 +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 { EuiSkeletonText } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import { useKibanaContextForPlugin } from '../../../../../../../hooks/use_kibana'; -import { TabContent, TabProps } from '../shared'; -import { useSourceContext } from '../../../../../../../containers/metrics_source'; -import { findInventoryModel } from '../../../../../../../../common/inventory_models'; -import { InventoryItemType } from '../../../../../../../../common/inventory_models/types'; -import { useMetadata } from '../../../../../../../components/asset_details/hooks/use_metadata'; -import { useWaffleTimeContext } from '../../../../hooks/use_waffle_time'; - -const TabComponent = (props: TabProps) => { - const nodeId = props.node.id; - const nodeType = props.nodeType as InventoryItemType; - const inventoryModel = findInventoryModel(nodeType); - const { sourceId } = useSourceContext(); - const { currentTimeRange } = useWaffleTimeContext(); - const { loading, metadata } = useMetadata( - nodeId, - nodeType, - inventoryModel.requiredMetrics, - sourceId, - currentTimeRange - ); - const { - services: { osquery }, - } = useKibanaContextForPlugin(); - - // @ts-expect-error - const OsqueryAction = osquery?.OsqueryAction; - - // avoids component rerender when resizing the popover - const content = useMemo(() => { - // TODO: Add info when Osquery plugin is not available - if (loading || !OsqueryAction) { - return ( - - - - ); - } - - return ( - - - - ); - }, [OsqueryAction, loading, metadata]); - - return content; -}; - -export const OsqueryTab = { - id: 'osquery', - name: i18n.translate('xpack.infra.nodeDetails.tabs.osquery', { - defaultMessage: 'Osquery', - }), - content: TabComponent, -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/index.tsx deleted file mode 100644 index 2d4ef39864a45..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/index.tsx +++ /dev/null @@ -1,171 +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, { useMemo, useState, useCallback } from 'react'; -import { debounce } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { - EuiSearchBar, - EuiSpacer, - EuiEmptyPrompt, - EuiButton, - EuiText, - EuiIconTip, - Query, -} from '@elastic/eui'; -import { getFieldByType } from '../../../../../../../../common/inventory_models'; -import { - useProcessList, - SortBy, - ProcessListContextProvider, -} from '../../../../hooks/use_process_list'; -import { TabContent, TabProps } from '../shared'; -import { STATE_NAMES } from './states'; -import { SummaryTable } from './summary_table'; -import { ProcessesTable } from './processes_table'; -import { parseSearchString } from './parse_search_string'; - -const TabComponent = ({ currentTime, node, nodeType }: TabProps) => { - const [searchBarState, setSearchBarState] = useState(Query.MATCH_ALL); - const [searchFilter, setSearchFilter] = useState(''); - const [sortBy, setSortBy] = useState({ - name: 'cpu', - isAscending: false, - }); - - const hostTerm = useMemo(() => { - const field = getFieldByType(nodeType) ?? nodeType; - return { [field]: node.name }; - }, [node, nodeType]); - - const { - loading, - error, - response, - makeRequest: reload, - } = useProcessList(hostTerm, currentTime, sortBy, parseSearchString(searchFilter)); - - const debouncedSearchOnChange = useMemo( - () => debounce<(queryText: string) => void>((queryText) => setSearchFilter(queryText), 500), - [setSearchFilter] - ); - - const searchBarOnChange = useCallback( - ({ query, queryText }) => { - setSearchBarState(query); - debouncedSearchOnChange(queryText); - }, - [setSearchBarState, debouncedSearchOnChange] - ); - - const clearSearchBar = useCallback(() => { - setSearchBarState(Query.MATCH_ALL); - setSearchFilter(''); - }, [setSearchBarState, setSearchFilter]); - - return ( - - - - - -

- {i18n.translate('xpack.infra.metrics.nodeDetails.processesHeader', { - defaultMessage: 'Top processes', - })}{' '} - -

-
- - ({ - value, - view, - })), - }, - ]} - /> - - {!error ? ( - - ) : ( - - {i18n.translate('xpack.infra.metrics.nodeDetails.processListError', { - defaultMessage: 'Unable to load process data', - })} - - } - actions={ - - {i18n.translate('xpack.infra.metrics.nodeDetails.processListRetry', { - defaultMessage: 'Try again', - })} - - } - /> - )} -
-
- ); -}; - -export const ProcessesTab = { - id: 'processes', - name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.processes', { - defaultMessage: 'Processes', - }), - content: TabComponent, -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/parse_search_string.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/parse_search_string.ts deleted file mode 100644 index 7112dbed917a6..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/parse_search_string.ts +++ /dev/null @@ -1,39 +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 const parseSearchString = (query: string) => { - if (query.trim() === '') { - return [ - { - match_all: {}, - }, - ]; - } - const elements = query - .split(' ') - .map((s) => s.trim()) - .filter(Boolean); - const stateFilter = elements.filter((s) => s.startsWith('state=')); - const cmdlineFilters = elements.filter((s) => !s.startsWith('state=')); - return [ - ...cmdlineFilters.map((clause) => ({ - query_string: { - fields: ['system.process.cmdline'], - query: `*${escapeReservedCharacters(clause)}*`, - minimum_should_match: 1, - }, - })), - ...stateFilter.map((state) => ({ - match: { - 'system.process.state': state.replace('state=', ''), - }, - })), - ]; -}; - -const escapeReservedCharacters = (clause: string) => - clause.replace(/([+\-=!\(\)\{\}\[\]^"~*?:\\/!]|&&|\|\|)/g, '\\$1'); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/process_row.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/process_row.tsx deleted file mode 100644 index 12f6eb066a697..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/process_row.tsx +++ /dev/null @@ -1,247 +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, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - EuiTableRow, - EuiTableRowCell, - EuiButtonEmpty, - EuiCode, - EuiDescriptionList, - EuiDescriptionListTitle, - EuiDescriptionListDescription, - EuiFlexGrid, - EuiFlexGroup, - EuiFlexItem, - EuiButton, - EuiSpacer, -} from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import useToggle from 'react-use/lib/useToggle'; -import { - useObservabilityAIAssistant, - type Message, - MessageRole, - ContextualInsight, -} from '@kbn/observability-ai-assistant-plugin/public'; -import { Process } from './types'; -import { ProcessRowCharts } from './process_row_charts'; - -interface Props { - cells: React.ReactNode[]; - item: Process; - supportAIAssistant?: boolean; -} -export const ContextualInsightProcessRow = ({ command }: { command: string }) => { - const aiAssistant = useObservabilityAIAssistant(); - const explainProcessMessages = useMemo(() => { - if (!command) { - return undefined; - } - const now = new Date().toISOString(); - return [ - { - '@timestamp': now, - message: { - role: MessageRole.System, - content: `You are infra-gpt, a helpful assistant for metrics-based infrastructure observability. Answer as - concisely as possible.`, - }, - }, - { - '@timestamp': now, - message: { - role: MessageRole.User, - content: `I am a software engineer. I am trying to understand what a process running on my - machine does. - Your task is to first describe what the process is and what its general use cases are. If I also provide you - with the arguments to the process you should then explain its arguments and how they influence the behaviour - of the process. If I do not provide any arguments then explain the behaviour of the process when no arguments are - provided. - If you do not recognise the process say "No information available for this process". If I provide an argument - to the process that you do not recognise then say "No information available for this argument" when explaining - that argument. - Here is an example with arguments. - Process: metricbeat -c /etc/metricbeat.yml -d autodiscover,kafka -e -system.hostfs=/hostfs - Explanation: Metricbeat is part of the Elastic Stack. It is a lightweight shipper that you can install on your - servers to periodically collect metrics from the operating system and from services running on the server. - Use cases for Metricbeat generally revolve around infrastructure monitoring. You would typically install - Metricbeat on your servers to collect metrics from your systems and services. These metrics are then - used for performance monitoring, anomaly detection, system status checks, etc. - Here is a breakdown of the arguments used: - * -c /etc/metricbeat.yml: The -c option is used to specify the configuration file for Metricbeat. In - this case, /etc/metricbeat.yml is the configuration file. This file contains configurations for what - metrics to collect and where to send them (e.g., to Elasticsearch or Logstash). - * -d autodiscover,kafka: The -d option is used to enable debug output for selected components. In - this case, debug output is enabled for autodiscover and kafka components. The autodiscover feature - allows Metricbeat to automatically discover services as they get started and stopped in your environment, - and kafka is presumably a monitored service from which Metricbeat collects metrics. - * -e: The -e option is used to log to stderr and disable syslog/file output. This is useful for debugging. - * -system.hostfs=/hostfs: The -system.hostfs option is used to set the mount point of the host’s - filesystem for use in monitoring a host from within a container. In this case, /hostfs is the mount - point. When running Metricbeat inside a container, filesystem metrics would be for the container by - default, but with this option, Metricbeat can get metrics for the host system. - Here is an example without arguments. - Process: metricbeat - Explanation: Metricbeat is part of the Elastic Stack. It is a lightweight shipper that you can install on your - servers to periodically collect metrics from the operating system and from services running on the server. - Use cases for Metricbeat generally revolve around infrastructure monitoring. You would typically install - Metricbeat on your servers to collect metrics from your systems and services. These metrics are then - used for performance monitoring, anomaly detection, system status checks, etc. - Running it without any arguments will start the process with the default configuration file, typically - located at /etc/metricbeat/metricbeat.yml. This file specifies the metrics to be collected and where - to ship them to. - Now explain this process to me. - Process: ${command} - Explanation: - `, - }, - }, - ]; - }, [command]); - return ( - <> - {aiAssistant.isEnabled() && explainProcessMessages ? ( - - - - - - - - ) : null} - - ); -}; - -export const ProcessRow = ({ cells, item, supportAIAssistant = false }: Props) => { - const [isExpanded, toggle] = useToggle(false); - - return ( - <> - - - - - {cells} - - - {isExpanded && ( - - - - - -
- - {i18n.translate( - 'xpack.infra.metrics.nodeDetails.processes.expandedRowLabelCommand', - { - defaultMessage: 'Command', - } - )} - - - {item.command} - -
-
- {item.apmTrace && ( - - - {i18n.translate('xpack.infra.metrics.nodeDetails.processes.viewTraceInAPM', { - defaultMessage: 'View trace in APM', - })} - - - )} -
- - - - {i18n.translate( - 'xpack.infra.metrics.nodeDetails.processes.expandedRowLabelPID', - { - defaultMessage: 'PID', - } - )} - - - {item.pid} - - - - - {i18n.translate( - 'xpack.infra.metrics.nodeDetails.processes.expandedRowLabelUser', - { - defaultMessage: 'User', - } - )} - - - {item.user} - - - - - {supportAIAssistant && } -
-
- )} -
- - ); -}; - -const explainProcessMessageTitle = i18n.translate( - 'xpack.infra.hostFlyout.explainProcessMessageTitle', - { - defaultMessage: "What's this process?", - } -); - -const ExpandedRowDescriptionList = euiStyled(EuiDescriptionList).attrs({ - compressed: true, -})` - width: 100%; -`; - -const CodeListItem = euiStyled(EuiCode).attrs({ - transparentBackground: true, -})` - padding: 0 !important; - & code.euiCodeBlock__code { - white-space: nowrap !important; - vertical-align: middle; - } -`; - -const ExpandedCommandLine = euiStyled(EuiCode).attrs({ - transparentBackground: true, -})` - padding: 0 !important; - margin-bottom: ${(props) => props.theme.eui.euiSizeS}; -`; - -const ExpandedRowCell = euiStyled(EuiTableRowCell).attrs({ - textOnly: false, - colSpan: 6, -})` - padding-top: ${(props) => props.theme.eui.euiSizeM} !important; - padding-bottom: ${(props) => props.theme.eui.euiSizeM} !important; - background-color: ${(props) => props.theme.eui.euiColorLightestShade}; -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/process_row_charts.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/process_row_charts.tsx deleted file mode 100644 index b19a859f196ea..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/process_row_charts.tsx +++ /dev/null @@ -1,160 +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 { Axis, Chart, niceTimeFormatter, Position, Settings, Tooltip } from '@elastic/charts'; -import { - EuiDescriptionListDescription, - EuiDescriptionListTitle, - EuiEmptyPrompt, - EuiFlexItem, - EuiLoadingChart, - EuiText, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { first, last } from 'lodash'; -import moment from 'moment'; -import React, { useMemo } from 'react'; -import { useTimelineChartTheme } from '../../../../../../../utils/use_timeline_chart_theme'; -import { Color } from '../../../../../../../../common/color_palette'; -import { createFormatter } from '../../../../../../../../common/formatters'; -import { MetricsExplorerAggregation } from '../../../../../../../../common/http_api'; -import { calculateDomain } from '../../../../../metrics_explorer/components/helpers/calculate_domain'; -import { MetricExplorerSeriesChart } from '../../../../../metrics_explorer/components/series_chart'; -import { MetricsExplorerChartType } from '../../../../../metrics_explorer/hooks/use_metrics_explorer_options'; -import { useProcessListRowChart } from '../../../../hooks/use_process_list_row_chart'; -import { Process } from './types'; - -interface Props { - command: string; -} - -export const ProcessRowCharts = ({ command }: Props) => { - const { loading, error, response } = useProcessListRowChart(command); - - const isLoading = loading || !response; - - const cpuChart = error ? ( - {failedToLoadChart}} /> - ) : isLoading ? ( - - ) : ( - - ); - const memoryChart = error ? ( - {failedToLoadChart}} /> - ) : isLoading ? ( - - ) : ( - - ); - - return ( - <> - - {cpuMetricLabel} - {cpuChart} - - - {memoryMetricLabel} - {memoryChart} - - - ); -}; - -interface ProcessChartProps { - timeseries: Process['timeseries']['x']; - color: Color; - label: string; -} -const ProcessChart = ({ timeseries, color, label }: ProcessChartProps) => { - const chartTheme = useTimelineChartTheme(); - const chartMetric = { - color, - aggregation: 'avg' as MetricsExplorerAggregation, - label, - }; - - const dateFormatter = useMemo(() => { - if (!timeseries) return () => ''; - const firstTimestamp = first(timeseries.rows)?.timestamp; - const lastTimestamp = last(timeseries.rows)?.timestamp; - - if (firstTimestamp == null || lastTimestamp == null) { - return (value: number) => `${value}`; - } - - return niceTimeFormatter([firstTimestamp, lastTimestamp]); - }, [timeseries]); - - const yAxisFormatter = createFormatter('percent'); - - const dataDomain = calculateDomain(timeseries, [chartMetric], false); - const domain = dataDomain - ? { - max: dataDomain.max * 1.1, // add 10% headroom. - min: dataDomain.min, - } - : { max: 0, min: 0 }; - - return ( - - - - - - moment(value).format('Y-MM-DD HH:mm:ss.SSS')} /> - - - - ); -}; - -const ChartContainer = euiStyled.div` - width: 100%; - height: 140px; -`; - -const cpuMetricLabel = i18n.translate( - 'xpack.infra.metrics.nodeDetails.processes.expandedRowLabelCPU', - { - defaultMessage: 'CPU', - } -); - -const memoryMetricLabel = i18n.translate( - 'xpack.infra.metrics.nodeDetails.processes.expandedRowLabelMemory', - { - defaultMessage: 'Memory', - } -); - -const failedToLoadChart = i18n.translate( - 'xpack.infra.metrics.nodeDetails.processes.failedToLoadChart', - { - defaultMessage: 'Unable to load chart', - } -); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/processes_table.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/processes_table.tsx deleted file mode 100644 index c85cc1577fa7f..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/processes_table.tsx +++ /dev/null @@ -1,311 +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, { useMemo, useState, useCallback } from 'react'; -import { omit } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { - EuiTable, - EuiTableHeader, - EuiTableBody, - EuiTableHeaderCell, - EuiTableRowCell, - EuiLoadingChart, - EuiEmptyPrompt, - EuiText, - EuiLink, - EuiButton, - SortableProperties, - LEFT_ALIGNMENT, - RIGHT_ALIGNMENT, -} from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { ProcessListAPIResponse } from '../../../../../../../../common/http_api'; -import { FORMATTERS } from '../../../../../../../../common/formatters'; -import { SortBy } from '../../../../hooks/use_process_list'; -import { Process } from './types'; -import { ProcessRow } from './process_row'; -import { StateBadge } from './state_badge'; -import { STATE_ORDER } from './states'; - -interface TableProps { - processList: ProcessListAPIResponse['processList']; - currentTime: number; - isLoading: boolean; - sortBy: SortBy; - setSortBy: (s: SortBy) => void; - clearSearchBar: () => void; -} - -function useSortableProperties( - sortablePropertyItems: Array<{ - name: string; - getValue: (obj: T) => any; - isAscending: boolean; - }>, - defaultSortProperty: string, - callback: (s: SortBy) => void -) { - const [sortableProperties] = useState>( - new SortableProperties(sortablePropertyItems, defaultSortProperty) - ); - - return { - updateSortableProperties: useCallback( - (property) => { - sortableProperties.sortOn(property); - callback(omit(sortableProperties.getSortedProperty(), 'getValue')); - }, - [sortableProperties, callback] - ), - }; -} - -export const ProcessesTable = ({ - processList, - currentTime, - isLoading, - sortBy, - setSortBy, - clearSearchBar, -}: TableProps) => { - const { updateSortableProperties } = useSortableProperties( - [ - { - name: 'startTime', - getValue: (item: any) => Date.parse(item.startTime), - isAscending: true, - }, - { - name: 'cpu', - getValue: (item: any) => item.cpu, - isAscending: false, - }, - { - name: 'memory', - getValue: (item: any) => item.memory, - isAscending: false, - }, - ], - 'cpu', - setSortBy - ); - - const currentItems = useMemo( - () => - processList.sort( - (a, b) => STATE_ORDER.indexOf(a.state) - STATE_ORDER.indexOf(b.state) - ) as Process[], - [processList] - ); - - if (isLoading) return ; - - if (currentItems.length === 0) - return ( - - {i18n.translate('xpack.infra.metrics.nodeDetails.noProcesses', { - defaultMessage: 'No processes found', - })} - - } - body={ - - - - - ), - }} - /> - - } - actions={ - - {i18n.translate('xpack.infra.metrics.nodeDetails.noProcessesClearFilters', { - defaultMessage: 'Clear filters', - })} - - } - /> - ); - - return ( - <> - - - - {columns.map((column) => ( - updateSortableProperties(column.field) : undefined} - isSorted={sortBy.name === column.field} - isSortAscending={sortBy.name === column.field && sortBy.isAscending} - > - {column.name} - - ))} - - - - - - - ); -}; - -const LoadingPlaceholder = () => { - return ( -
- -
- ); -}; - -interface TableBodyProps { - items: Process[]; - currentTime: number; -} -const ProcessesTableBody = ({ items, currentTime }: TableBodyProps) => ( - <> - {items.map((item, i) => { - const cells = columns.map((column) => ( - - {column.render ? column.render(item[column.field], currentTime) : item[column.field]} - - )); - return ; - })} - -); - -const StyledTableBody = euiStyled(EuiTableBody)` - & .euiTableCellContent { - padding-top: 0; - padding-bottom: 0; - - } -`; - -const ONE_MINUTE = 60 * 1000; -const ONE_HOUR = ONE_MINUTE * 60; -const RuntimeCell = ({ startTime, currentTime }: { startTime: number; currentTime: number }) => { - const runtimeLength = currentTime - startTime; - let remainingRuntimeMS = runtimeLength; - const runtimeHours = Math.floor(remainingRuntimeMS / ONE_HOUR); - remainingRuntimeMS -= runtimeHours * ONE_HOUR; - const runtimeMinutes = Math.floor(remainingRuntimeMS / ONE_MINUTE); - remainingRuntimeMS -= runtimeMinutes * ONE_MINUTE; - const runtimeSeconds = Math.floor(remainingRuntimeMS / 1000); - remainingRuntimeMS -= runtimeSeconds * 1000; - - const runtimeDisplayHours = runtimeHours ? `${runtimeHours}:` : ''; - const runtimeDisplayMinutes = runtimeMinutes < 10 ? `0${runtimeMinutes}:` : `${runtimeMinutes}:`; - const runtimeDisplaySeconds = runtimeSeconds < 10 ? `0${runtimeSeconds}` : runtimeSeconds; - - return <>{`${runtimeDisplayHours}${runtimeDisplayMinutes}${runtimeDisplaySeconds}`}; -}; - -const columns: Array<{ - field: keyof Process; - name: string; - sortable: boolean; - render?: Function; - width?: string | number; - textOnly?: boolean; - align?: typeof RIGHT_ALIGNMENT | typeof LEFT_ALIGNMENT; -}> = [ - { - field: 'state', - name: i18n.translate('xpack.infra.metrics.nodeDetails.processes.columnLabelState', { - defaultMessage: 'State', - }), - sortable: false, - render: (state: string) => , - width: 84, - textOnly: false, - }, - { - field: 'command', - name: i18n.translate('xpack.infra.metrics.nodeDetails.processes.columnLabelCommand', { - defaultMessage: 'Command', - }), - sortable: false, - width: '40%', - render: (command: string) => {command}, - }, - { - field: 'startTime', - name: i18n.translate('xpack.infra.metrics.nodeDetails.processes.columnLabelTime', { - defaultMessage: 'Time', - }), - align: RIGHT_ALIGNMENT, - sortable: true, - render: (startTime: number, currentTime: number) => ( - - ), - }, - { - field: 'cpu', - name: i18n.translate('xpack.infra.metrics.nodeDetails.processes.columnLabelCPU', { - defaultMessage: 'CPU', - }), - sortable: true, - render: (value: number) => FORMATTERS.percent(value), - }, - { - field: 'memory', - name: i18n.translate('xpack.infra.metrics.nodeDetails.processes.columnLabelMemory', { - defaultMessage: 'Mem.', - }), - sortable: true, - render: (value: number) => FORMATTERS.percent(value), - }, -]; - -const CodeLine = euiStyled.div` - font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; - font-size: ${(props) => props.theme.eui.euiFontSizeS}; - white-space: pre; - overflow: hidden; - text-overflow: ellipsis; -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/state_badge.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/state_badge.tsx deleted file mode 100644 index 47049c7d9c893..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/state_badge.tsx +++ /dev/null @@ -1,29 +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 { EuiBadge } from '@elastic/eui'; -import { STATE_NAMES } from './states'; - -export const StateBadge = ({ state }: { state: string }) => { - switch (state) { - case 'running': - return {STATE_NAMES.running}; - case 'sleeping': - return {STATE_NAMES.sleeping}; - case 'dead': - return {STATE_NAMES.dead}; - case 'stopped': - return {STATE_NAMES.stopped}; - case 'idle': - return {STATE_NAMES.idle}; - case 'zombie': - return {STATE_NAMES.zombie}; - default: - return {STATE_NAMES.unknown}; - } -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/states.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/states.ts deleted file mode 100644 index ea944cd8bb8c0..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/states.ts +++ /dev/null @@ -1,34 +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 { i18n } from '@kbn/i18n'; - -export const STATE_NAMES = { - running: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateRunning', { - defaultMessage: 'Running', - }), - sleeping: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateSleeping', { - defaultMessage: 'Sleeping', - }), - dead: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateDead', { - defaultMessage: 'Dead', - }), - stopped: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateStopped', { - defaultMessage: 'Stopped', - }), - idle: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateIdle', { - defaultMessage: 'Idle', - }), - zombie: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateZombie', { - defaultMessage: 'Zombie', - }), - unknown: i18n.translate('xpack.infra.metrics.nodeDetails.processes.stateUnknown', { - defaultMessage: 'Unknown', - }), -}; - -export const STATE_ORDER = ['running', 'sleeping', 'stopped', 'idle', 'dead', 'zombie', 'unknown']; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/summary_table.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/summary_table.tsx deleted file mode 100644 index 61e5cde421181..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/summary_table.tsx +++ /dev/null @@ -1,93 +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, { useMemo } from 'react'; -import { mapValues } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { - EuiLoadingSpinner, - EuiFlexGroup, - EuiFlexItem, - EuiDescriptionList, - EuiDescriptionListTitle, - EuiDescriptionListDescription, - EuiHorizontalRule, -} from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { ProcessListAPIResponse } from '../../../../../../../../common/http_api'; -import { STATE_NAMES } from './states'; - -interface Props { - processSummary: ProcessListAPIResponse['summary']; - isLoading: boolean; -} - -type SummaryRecord = { - total: number; -} & Record; - -const NOT_AVAILABLE_LABEL = i18n.translate('xpack.infra.notAvailableLabel', { - defaultMessage: 'N/A', -}); - -const processSummaryNotAvailable = { - total: NOT_AVAILABLE_LABEL, - running: NOT_AVAILABLE_LABEL, - sleeping: NOT_AVAILABLE_LABEL, - dead: NOT_AVAILABLE_LABEL, - stopped: NOT_AVAILABLE_LABEL, - idle: NOT_AVAILABLE_LABEL, - zombie: NOT_AVAILABLE_LABEL, - unknown: NOT_AVAILABLE_LABEL, -}; - -export const SummaryTable = ({ processSummary, isLoading }: Props) => { - const summary = !processSummary?.total ? processSummaryNotAvailable : processSummary; - - const processCount = useMemo( - () => - ({ - total: isLoading ? -1 : summary.total, - ...mapValues(STATE_NAMES, () => (isLoading ? -1 : 0)), - ...(isLoading ? {} : summary), - } as SummaryRecord), - [summary, isLoading] - ); - return ( - <> - - {Object.entries(processCount).map(([field, value]) => ( - - - {columnTitles[field as keyof SummaryRecord]} - - {value === -1 ? : value} - - - - ))} - - - - ); -}; - -const columnTitles = { - total: i18n.translate('xpack.infra.metrics.nodeDetails.processes.headingTotalProcesses', { - defaultMessage: 'Total processes', - }), - ...STATE_NAMES, -}; - -const LoadingSpinner = euiStyled(EuiLoadingSpinner).attrs({ size: 'm' })` - margin-top: 2px; - margin-bottom: 3px; -`; - -const ColumnTitle = euiStyled(EuiDescriptionListTitle)` - white-space: nowrap; -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/types.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/types.ts deleted file mode 100644 index 1b38ac3829960..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes/types.ts +++ /dev/null @@ -1,23 +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 { MetricsExplorerSeries } from '../../../../../../../../common/http_api'; -import { STATE_NAMES } from './states'; - -export interface Process { - command: string; - cpu: number; - memory: number; - startTime: number; - state: keyof typeof STATE_NAMES; - pid: number; - user: string; - timeseries: { - [x: string]: MetricsExplorerSeries; - }; - apmTrace?: string; // Placeholder -} diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/build_fields.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/build_fields.ts deleted file mode 100644 index 8b77242055a1f..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/build_fields.ts +++ /dev/null @@ -1,117 +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 { InfraMetadata } from '../../../../../../../../common/http_api'; - -export const getFields = (metadata: InfraMetadata, group: 'cloud' | 'host' | 'agent') => { - switch (group) { - case 'host': - return prune([ - { - name: 'host.architecture', - value: metadata.info?.host?.architecture, - }, - { - name: 'host.hostname', - value: metadata.info?.host?.name, - }, - { - name: 'host.id', - value: metadata.info?.host?.id, - }, - { - name: 'host.ip', - value: metadata.info?.host?.ip, - }, - { - name: 'host.mac', - value: metadata.info?.host?.mac, - }, - { - name: 'host.name', - value: metadata.info?.host?.name, - }, - { - name: 'host.os.build', - value: metadata.info?.host?.os?.build, - }, - { - name: 'host.os.family', - value: metadata.info?.host?.os?.family, - }, - { - name: 'host.os.name', - value: metadata.info?.host?.os?.name, - }, - { - name: 'host.os.kernel', - value: metadata.info?.host?.os?.kernel, - }, - { - name: 'host.os.platform', - value: metadata.info?.host?.os?.platform, - }, - { - name: 'host.os.version', - value: metadata.info?.host?.os?.version, - }, - ]); - case 'cloud': - return prune([ - { - name: 'cloud.account.id', - value: metadata.info?.cloud?.account?.id, - }, - { - name: 'cloud.account.name', - value: metadata.info?.cloud?.account?.name, - }, - { - name: 'cloud.availability_zone', - value: metadata.info?.cloud?.availability_zone, - }, - { - name: 'cloud.instance.id', - value: metadata.info?.cloud?.instance?.id, - }, - { - name: 'cloud.instance.name', - value: metadata.info?.cloud?.instance?.name, - }, - { - name: 'cloud.machine.type', - value: metadata.info?.cloud?.machine?.type, - }, - { - name: 'cloud.provider', - value: metadata.info?.cloud?.provider, - }, - { - name: 'cloud.region', - value: metadata.info?.cloud?.region, - }, - ]); - case 'agent': - return prune([ - { - name: 'agent.id', - value: metadata.info?.agent?.id, - }, - { - name: 'agent.version', - value: metadata.info?.agent?.version, - }, - { - name: 'agent.policy', - value: metadata.info?.agent?.policy, - }, - ]); - } -}; - -const prune = (fields: Array<{ name: string; value: string | string[] | undefined }>) => - fields.filter((f) => !!f.value); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/index.tsx deleted file mode 100644 index bc0ee279b2cbd..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/index.tsx +++ /dev/null @@ -1,134 +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, { useCallback, useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiLoadingChart } from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { TabContent, TabProps } from '../shared'; -import { useSourceContext } from '../../../../../../../containers/metrics_source'; -import { findInventoryModel } from '../../../../../../../../common/inventory_models'; -import { InventoryItemType } from '../../../../../../../../common/inventory_models/types'; -import { useMetadata } from '../../../../../../../components/asset_details/hooks/use_metadata'; -import { getFields } from './build_fields'; -import { useWaffleTimeContext } from '../../../../hooks/use_waffle_time'; -import { Table } from './table'; -import { useWaffleFiltersContext } from '../../../../hooks/use_waffle_filters'; - -const TabComponent = (props: TabProps) => { - const nodeId = props.node.id; - const nodeType = props.nodeType as InventoryItemType; - const inventoryModel = findInventoryModel(nodeType); - const { sourceId } = useSourceContext(); - const { currentTimeRange } = useWaffleTimeContext(); - const { applyFilterQuery } = useWaffleFiltersContext(); - const { loading: metadataLoading, metadata } = useMetadata( - nodeId, - nodeType, - inventoryModel.requiredMetrics, - sourceId, - currentTimeRange - ); - - const hostFields = useMemo(() => { - if (!metadata) return null; - return getFields(metadata, 'host'); - }, [metadata]); - - const cloudFields = useMemo(() => { - if (!metadata) return null; - return getFields(metadata, 'cloud'); - }, [metadata]); - - const agentFields = useMemo(() => { - if (!metadata) return null; - return getFields(metadata, 'agent'); - }, [metadata]); - - const onFilter = useCallback( - (item: { name: string; value: string }) => { - applyFilterQuery({ - kind: 'kuery', - expression: `${item.name}: "${item.value}"`, - }); - }, - [applyFilterQuery] - ); - - if (metadataLoading) { - return ; - } - - return ( - - {hostFields && hostFields.length > 0 && ( - - - - )} - {cloudFields && cloudFields.length > 0 && ( - -
- - )} - {agentFields && agentFields.length > 0 && ( - -
- - )} - - ); -}; - -const TableWrapper = euiStyled.div` - &:not(:last-child) { - margin-bottom: 16px - } -`; - -const LoadingPlaceholder = () => { - return ( -
- -
- ); -}; - -export const PropertiesTab = { - id: 'properties', - name: i18n.translate('xpack.infra.nodeDetails.tabs.metadata.title', { - defaultMessage: 'Metadata', - }), - content: TabComponent, -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/table.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/table.tsx deleted file mode 100644 index 01b047f2e3664..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties/table.tsx +++ /dev/null @@ -1,167 +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 { - EuiText, - EuiToolTip, - EuiButtonIcon, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiBasicTable, - EuiSpacer, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import useToggle from 'react-use/lib/useToggle'; - -interface Row { - name: string; - value: string | string[] | undefined; -} - -interface Props { - rows: Row[]; - title: string; - onClick(item: Row): void; -} - -export const Table = (props: Props) => { - const { rows, title, onClick } = props; - const columns = useMemo( - () => [ - { - field: 'name', - name: '', - width: '35%', - sortable: false, - render: (name: string, item: Row) => ( - - {item.name} - - ), - }, - { - field: 'value', - name: '', - width: '65%', - sortable: false, - render: (_name: string, item: Row) => { - return ( - - - - - onClick(item)} - /> - - - - - - - - ); - }, - }, - ], - [onClick] - ); - - return ( - <> - -

{title}

-
- - - - ); -}; - -class TableWithoutHeader extends EuiBasicTable { - renderTableHead() { - return <>; - } -} - -interface ExpandableContentProps { - values: string | string[] | undefined; -} - -const ExpandableContent = (props: ExpandableContentProps) => { - const { values } = props; - const [isExpanded, toggle] = useToggle(false); - - const list = Array.isArray(values) ? values : [values]; - const [first, ...others] = list; - const hasOthers = others.length > 0; - const shouldShowMore = hasOthers && !isExpanded; - - return ( - -
- {first} - {shouldShowMore && ( - <> - {' ... '} - - - - - )} -
- {isExpanded && others.map((item) => {item})} - {hasOthers && isExpanded && ( - - - {i18n.translate('xpack.infra.nodeDetails.tabs.metadata.seeLess', { - defaultMessage: 'Show less', - })} - - - )} -
- ); -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx deleted file mode 100644 index 2d65ef9c01fc6..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx +++ /dev/null @@ -1,27 +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 { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { InventoryItemType } from '../../../../../../../common/inventory_models/types'; -import { InfraWaffleMapOptions, InfraWaffleMapNode } from '../../../../../../lib/lib'; - -export interface TabProps { - options: InfraWaffleMapOptions; - currentTime: number; - node: InfraWaffleMapNode; - nodeType: InventoryItemType; - onClose(): void; -} - -export const OVERLAY_Y_START = 266; -export const OVERLAY_BOTTOM_MARGIN = 16; -export const TabContent = euiStyled.div` - padding: ${(props) => props.theme.eui.euiSizeM}; - flex: 1; - overflow-y: auto; - overflow-x: hidden; -`;