mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Infra] Add metrics tab to the container views (#186118)
Closes #180799 ## Summary This PR adds the metrics tab to the container views - for now, the charts are the same as in the overview tab: - Docker container 4 metrics - 4 charts  - Kubernetes container 2 metrics - 2 charts <img width="1650" alt="image" src="d626922c
-2972-4858-abe5-9e1271bf2acd"> ### Testing - Select Docker Containers from the inventory "Show" drop-down menu - Click on the metrics tab - the charts should be visible - Select a Docker container and click on "See all" for any metric inside the Metrics section - The metrics tab should be open and the correct metric in the left menu should be selected - Select a Kubernetes container and click on "See all" for any metric inside the Metrics section - The metrics tab should be open and the correct metric in the left menu should be selected684b4b60
-6457-44aa-a1f2-ca0340049684 - Click on open as page link inside the flyout and the same steps should be checked for the page view (both Docker & Kubernetes)2f9e65be
-e22d-4b38-9889-d997de20c081
This commit is contained in:
parent
1150b086c1
commit
4093f4cfbc
10 changed files with 180 additions and 26 deletions
|
@ -111,8 +111,14 @@ export const hostDetailsTabs: Tab[] = [
|
|||
export const hostDetailsFlyoutTabs: Tab[] = [...hostDetailsTabs, linkToApmTab];
|
||||
|
||||
// The profiling tab would be added in next iteration
|
||||
export const containerDetailsTabs: Tab[] = [overviewTab, metadataTab, logsTab];
|
||||
export const containerDetailsFlyoutTabs: Tab[] = [overviewTab, metadataTab, logsTab, linkToApmTab];
|
||||
export const containerDetailsTabs: Tab[] = [overviewTab, metadataTab, metricsTab, logsTab];
|
||||
export const containerDetailsFlyoutTabs: Tab[] = [
|
||||
overviewTab,
|
||||
metadataTab,
|
||||
metricsTab,
|
||||
logsTab,
|
||||
linkToApmTab,
|
||||
];
|
||||
|
||||
export const getAssetDetailsTabs = (type: string): Tab[] => {
|
||||
switch (type) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import React from 'react';
|
|||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { EuiText, EuiLink } from '@elastic/eui';
|
||||
import { EuiText, EuiLink, EuiButtonEmpty } from '@elastic/eui';
|
||||
import { useDockerContainerPageViewMetricsCharts } from '../hooks/use_container_metrics_charts';
|
||||
import { Section } from '../components/section';
|
||||
import { ChartsGrid } from '../charts_grid/charts_grid';
|
||||
|
@ -26,7 +26,7 @@ interface Props extends MetricsChartsFields {
|
|||
const FRAGMENT_BASE = 'key-metrics';
|
||||
|
||||
export const DockerCharts = React.forwardRef<HTMLDivElement, Props>(
|
||||
({ assetId, dataView, dateRange, metric }, ref) => {
|
||||
({ assetId, dataView, dateRange, metric, onShowAll }, ref) => {
|
||||
const { charts } = useDockerContainerPageViewMetricsCharts({
|
||||
metric,
|
||||
metricsDataViewId: dataView?.id,
|
||||
|
@ -67,8 +67,25 @@ export const DockerCharts = React.forwardRef<HTMLDivElement, Props>(
|
|||
/>
|
||||
}
|
||||
data-test-subj={`infraAssetDetailsDockerChartsSection${metric}`}
|
||||
id="dockerContainerCharts"
|
||||
id={metric}
|
||||
ref={ref}
|
||||
extraAction={
|
||||
onShowAll ? (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="infraAssetDetailsHostChartsShowAllButton"
|
||||
onClick={() => onShowAll(metric)}
|
||||
size="xs"
|
||||
flush="both"
|
||||
iconSide="right"
|
||||
iconType="sortRight"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.host.showAllButton"
|
||||
defaultMessage="Show all"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<ChartsGrid columns={2}>
|
||||
{charts.map((chart) => (
|
||||
|
|
|
@ -19,7 +19,7 @@ import { Chart } from './chart';
|
|||
import { useIntegrationCheck } from '../hooks/use_integration_check';
|
||||
import { useK8sContainerPageViewMetricsCharts } from '../hooks/use_container_metrics_charts';
|
||||
import { CONTAINER_METRICS_DOC_HREF } from '../../../common/visualizations/constants';
|
||||
import { ContainerMetricTypes, MetricsChartsFields } from './types';
|
||||
import { KubernetesContainerMetrics, MetricsChartsFields } from './types';
|
||||
|
||||
const FRAGMENT_BASE = 'key-metrics';
|
||||
|
||||
|
@ -79,8 +79,8 @@ export const KubernetesNodeCharts = React.forwardRef<HTMLDivElement, MetricsChar
|
|||
|
||||
export const KubernetesContainerCharts = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
MetricsChartsFields & { metric: ContainerMetricTypes }
|
||||
>(({ assetId, dataView, dateRange, metric }, ref) => {
|
||||
MetricsChartsFields & { metric: KubernetesContainerMetrics }
|
||||
>(({ assetId, dataView, dateRange, metric, onShowAll }, ref) => {
|
||||
const { charts } = useK8sContainerPageViewMetricsCharts({
|
||||
metric,
|
||||
metricsDataViewId: dataView?.id,
|
||||
|
@ -121,9 +121,26 @@ export const KubernetesContainerCharts = React.forwardRef<
|
|||
}
|
||||
/>
|
||||
}
|
||||
data-test-subj="infraAssetDetailsK8ContainerChartsSection"
|
||||
id="k8sContainerCharts"
|
||||
data-test-subj={`infraAssetDetailsK8ContainerChartsSection${metric}`}
|
||||
id={metric}
|
||||
ref={ref}
|
||||
extraAction={
|
||||
onShowAll ? (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="infraAssetDetailsKubernetesChartsShowAllButton"
|
||||
onClick={() => onShowAll(metric)}
|
||||
size="xs"
|
||||
flush="both"
|
||||
iconSide="right"
|
||||
iconType="sortRight"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.kubernetes.showAllButton"
|
||||
defaultMessage="Show all"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<ChartsGrid columns={2}>
|
||||
{charts.map((chart) => (
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { DockerContainerMetrics, KubernetesContainerMetrics } from './charts/types';
|
||||
import { INTEGRATION_NAME, ASSET_DETAILS_ASSET_TYPE } from './types';
|
||||
|
||||
export const ASSET_DETAILS_FLYOUT_COMPONENT_NAME = 'infraAssetDetailsFlyout';
|
||||
|
@ -25,3 +26,6 @@ export const INTEGRATIONS = {
|
|||
[INTEGRATION_NAME.kubernetesContainer]: 'kubernetes.container',
|
||||
[INTEGRATION_NAME.docker]: 'docker',
|
||||
};
|
||||
|
||||
export const DOCKER_METRIC_TYPES: DockerContainerMetrics[] = ['cpu', 'memory', 'network', 'disk'];
|
||||
export const KUBERNETES_METRIC_TYPES: KubernetesContainerMetrics[] = ['cpu', 'memory'];
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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, { useRef } from 'react';
|
||||
import { useDatePickerContext } from '../../hooks/use_date_picker';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
import { useDataViewsContext } from '../../hooks/use_data_views';
|
||||
import { useIntersectingState } from '../../hooks/use_intersecting_state';
|
||||
import { MetricsTemplate } from './metrics_template';
|
||||
import { DockerCharts, KubernetesContainerCharts } from '../../charts';
|
||||
import { DOCKER_METRIC_TYPES, INTEGRATIONS, KUBERNETES_METRIC_TYPES } from '../../constants';
|
||||
import { useIntegrationCheck } from '../../hooks/use_integration_check';
|
||||
|
||||
export const ContainerMetrics = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { dateRange } = useDatePickerContext();
|
||||
const { asset } = useAssetDetailsRenderPropsContext();
|
||||
const { metrics } = useDataViewsContext();
|
||||
|
||||
const state = useIntersectingState(ref, { dateRange });
|
||||
|
||||
const isDockerContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.docker });
|
||||
const isKubernetesContainer = useIntegrationCheck({
|
||||
dependsOn: INTEGRATIONS.kubernetesContainer,
|
||||
});
|
||||
|
||||
if (!isDockerContainer && !isKubernetesContainer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MetricsTemplate ref={ref}>
|
||||
{isDockerContainer &&
|
||||
DOCKER_METRIC_TYPES.map((metric) => (
|
||||
<DockerCharts
|
||||
key={metric}
|
||||
assetId={asset.id}
|
||||
dataView={metrics.dataView}
|
||||
dateRange={state.dateRange}
|
||||
metric={metric}
|
||||
/>
|
||||
))}
|
||||
{!isDockerContainer &&
|
||||
isKubernetesContainer &&
|
||||
KUBERNETES_METRIC_TYPES.map((metric) => (
|
||||
<KubernetesContainerCharts
|
||||
key={metric}
|
||||
assetId={asset.id}
|
||||
dataView={metrics.dataView}
|
||||
dateRange={state.dateRange}
|
||||
metric={metric}
|
||||
/>
|
||||
))}
|
||||
</MetricsTemplate>
|
||||
);
|
||||
};
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { HostMetrics } from './host_metrics';
|
||||
import { ContainerMetrics } from './container_metrics';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
|
||||
export const Metrics = () => {
|
||||
|
@ -14,6 +15,8 @@ export const Metrics = () => {
|
|||
switch (asset.type) {
|
||||
case 'host':
|
||||
return <HostMetrics />;
|
||||
case 'container':
|
||||
return <ContainerMetrics />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,11 @@ import { EuiFlexGroup, EuiFlexGrid } from '@elastic/eui';
|
|||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { DockerCharts } from '../../../charts/docker_charts';
|
||||
import { INTEGRATIONS } from '../../../constants';
|
||||
import { DOCKER_METRIC_TYPES, INTEGRATIONS, KUBERNETES_METRIC_TYPES } from '../../../constants';
|
||||
import { useIntegrationCheck } from '../../../hooks/use_integration_check';
|
||||
import { KubernetesContainerCharts } from '../../../charts/kubernetes_charts';
|
||||
import { useTabSwitcherContext } from '../../../hooks/use_tab_switcher';
|
||||
import { ContentTabIds } from '../../../types';
|
||||
|
||||
interface Props {
|
||||
assetId: string;
|
||||
|
@ -20,11 +22,16 @@ interface Props {
|
|||
}
|
||||
|
||||
export const ContainerMetrics = (props: Props) => {
|
||||
const { showTab } = useTabSwitcherContext();
|
||||
const isDockerContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.docker });
|
||||
const isKubernetesContainer = useIntegrationCheck({
|
||||
dependsOn: INTEGRATIONS.kubernetesContainer,
|
||||
});
|
||||
|
||||
const onClick = (metric: string) => {
|
||||
showTab(ContentTabIds.METRICS, { scrollTo: metric });
|
||||
};
|
||||
|
||||
if (!isDockerContainer && !isKubernetesContainer) {
|
||||
return null;
|
||||
}
|
||||
|
@ -32,20 +39,20 @@ export const ContainerMetrics = (props: Props) => {
|
|||
return (
|
||||
<EuiFlexGroup gutterSize="m" direction="column">
|
||||
<EuiFlexGrid columns={2} gutterSize="s">
|
||||
{isDockerContainer && (
|
||||
<>
|
||||
<DockerCharts {...props} metric="cpu" />
|
||||
<DockerCharts {...props} metric="memory" />
|
||||
<DockerCharts {...props} metric="network" />
|
||||
<DockerCharts {...props} metric="disk" />
|
||||
</>
|
||||
)}
|
||||
{!isDockerContainer && isKubernetesContainer && (
|
||||
<>
|
||||
<KubernetesContainerCharts {...props} metric="cpu" />
|
||||
<KubernetesContainerCharts {...props} metric="memory" />
|
||||
</>
|
||||
)}
|
||||
{isDockerContainer &&
|
||||
DOCKER_METRIC_TYPES.map((metric) => (
|
||||
<DockerCharts key={metric} {...props} metric={metric} onShowAll={onClick} />
|
||||
))}
|
||||
{!isDockerContainer &&
|
||||
isKubernetesContainer &&
|
||||
KUBERNETES_METRIC_TYPES.map((metric) => (
|
||||
<KubernetesContainerCharts
|
||||
key={metric}
|
||||
{...props}
|
||||
metric={metric}
|
||||
onShowAll={onClick}
|
||||
/>
|
||||
))}
|
||||
</EuiFlexGrid>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
|
|
@ -309,7 +309,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
{ metric: 'cpu', chartsCount: 1 },
|
||||
{ metric: 'memory', chartsCount: 1 },
|
||||
].forEach(({ metric, chartsCount }) => {
|
||||
it.skip(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => {
|
||||
it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => {
|
||||
const containers = await pageObjects.assetDetails.getOverviewTabDockerMetricCharts(
|
||||
metric
|
||||
);
|
||||
|
@ -335,6 +335,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Metrics Tab', () => {
|
||||
before(async () => {
|
||||
await pageObjects.assetDetails.clickMetricsTab();
|
||||
});
|
||||
|
||||
it('should show metrics content', async () => {
|
||||
await pageObjects.assetDetails.metricsChartsContentExists();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Logs Tab', () => {
|
||||
before(async () => {
|
||||
await pageObjects.assetDetails.clickLogsTab();
|
||||
|
|
|
@ -724,6 +724,28 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
await searchInput.clearValue();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Metrics Tab', () => {
|
||||
before(async () => {
|
||||
await pageObjects.assetDetails.clickMetricsTab();
|
||||
});
|
||||
|
||||
[
|
||||
{ metric: 'cpu', chartsCount: 1 },
|
||||
{ metric: 'memory', chartsCount: 1 },
|
||||
{ metric: 'disk', chartsCount: 1 },
|
||||
{ metric: 'network', chartsCount: 1 },
|
||||
].forEach(({ metric, chartsCount }) => {
|
||||
it(`should render ${chartsCount} ${metric} chart(s)`, async () => {
|
||||
const charts = await pageObjects.assetDetails.getMetricsTabDockerCharts(metric);
|
||||
expect(charts.length).to.equal(chartsCount);
|
||||
});
|
||||
|
||||
it(`should render a quick access for ${metric} in the side panel`, async () => {
|
||||
await pageObjects.assetDetails.quickAccessItemExists(metric);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -227,6 +227,14 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
|
|||
return section.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricChart"]');
|
||||
},
|
||||
|
||||
async getMetricsTabDockerCharts(metric: string) {
|
||||
const container = await testSubjects.find('infraAssetDetailsMetricsTabContent');
|
||||
const section = await container.findByTestSubject(
|
||||
`infraAssetDetailsDockerChartsSection${metric}`
|
||||
);
|
||||
return section.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricChart"]');
|
||||
},
|
||||
|
||||
async quickAccessItemExists(metric: string) {
|
||||
return testSubjects.click(`infraMetricsQuickAccessItem${metric}`);
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue