Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Infra][Hosts] Display N/A badge for APM hosts without system metrics #191181

Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
914c31f
[Infra][Hosts] Create add data popover
iblancof Aug 22, 2024
5c2fa45
[Infra][Hosts] Integrate add data popover in hosts table when host ro…
iblancof Aug 22, 2024
cfb0c88
[Infra][Hosts] Move function buildMetricCell to a different location …
iblancof Aug 22, 2024
3636e7a
[Infra][Hosts] Fix hosts table test
iblancof Aug 23, 2024
15d51a1
[Infra][Hosts] Remove duplicated hasSystemMetrics addition by merge
iblancof Aug 23, 2024
58d6f0c
[Hosts][Infra] Change add data popover button size
iblancof Aug 23, 2024
e44500c
[Hosts][Infra] Update translation keys in add data popover to match l…
iblancof Aug 23, 2024
1880dd9
[Hosts][Infra] Use APM_HOST_TROUBLESHOOTING_LINK
iblancof Aug 26, 2024
ca65ece
[Hosts][Infra] Remove constant for badge button in AddDataPopover
iblancof Aug 26, 2024
a827723
[Hosts][Infra] Import HostNodeRow as type
iblancof Aug 26, 2024
ec6c0e0
[Infra][Hosts] Rename AddDataPopover to AddDataTroubleshootingPopover
iblancof Aug 26, 2024
3e6cbd9
[Infra][Hosts] Use useBoolean instead of useState in AddDataTroublesh…
iblancof Aug 26, 2024
af43e42
[Infra][Hosts] Extract translations from AddDataTroubleshootingPopover
iblancof Aug 26, 2024
6fd7e3a
[Infra][Hosts] Allow null values in hosts table
iblancof Aug 26, 2024
adacc4a
Merge branch 'main' into 190516-infra-display-na-badge-for-apm-hosts-…
iblancof Aug 26, 2024
5ba674f
Merge branch 'main' into 190516-infra-display-na-badge-for-apm-hosts-…
iblancof Aug 26, 2024
c2de8d0
Merge branch 'main' into 190516-infra-display-na-badge-for-apm-hosts-…
iblancof Aug 26, 2024
b4e0b5d
Merge branch 'main' into 190516-infra-display-na-badge-for-apm-hosts-…
iblancof Aug 27, 2024
07e4271
[Infra][Hosts] Update formatMetric to handle null and 0 values as bef…
iblancof Aug 27, 2024
5032330
Merge branch 'main' into 190516-infra-display-na-badge-for-apm-hosts-…
iblancof Aug 27, 2024
8eb701d
[Infra][Hosts] Update type for value arg in buildMetricCell
iblancof Aug 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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,
EuiButton,
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiPopover,
EuiPopoverFooter,
EuiPopoverTitle,
EuiText,
} from '@elastic/eui';

import {
ObservabilityOnboardingLocatorParams,
OBSERVABILITY_ONBOARDING_LOCATOR,
} from '@kbn/deeplinks-observability';
import { i18n } from '@kbn/i18n';
import { useBoolean } from '@kbn/react-hooks';

import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import { APM_HOST_TROUBLESHOOTING_LINK } from '../../../../../components/asset_details/constants';

const popoverContent = {
title: i18n.translate('xpack.infra.addDataPopover.wantToSeeMorePopoverTitleLabel', {
defaultMessage: 'Want to see more?',
}),
content: i18n.translate('xpack.infra.addDataPopover.understandHostPerformanceByTextLabel', {
defaultMessage: 'Understand host performance by collecting more metrics.',
}),
button: i18n.translate('xpack.infra.addDataPopover.understandHostPerformanceByTextLabel', {
defaultMessage: 'Add data',
}),
link: i18n.translate('xpack.infra.addDataPopover.troubleshootingLinkLabel', {
defaultMessage: 'Troubleshooting',
}),
};

const badgeContent = i18n.translate('xpack.infra.addDataPopover.naBadgeLabel', {
defaultMessage: 'N/A',
});

export const AddDataTroubleshootingPopover = () => {
const [isPopoverOpen, { off: closePopover, toggle: togglePopover }] = useBoolean(false);

const {
services: { share },
} = useKibanaContextForPlugin();
const addDataLinkHref = share.url.locators
.get<ObservabilityOnboardingLocatorParams>(OBSERVABILITY_ONBOARDING_LOCATOR)
?.getRedirectUrl({ category: 'logs' });

const onButtonClick = () => togglePopover();

return (
<EuiPopover
button={
<EuiBadge
color="hollow"
iconType="iInCircle"
iconSide="left"
onClick={onButtonClick}
onClickAriaLabel={popoverContent.title}
iconOnClick={onButtonClick}
iconOnClickAriaLabel={popoverContent.title}
>
{badgeContent}
</EuiBadge>
}
isOpen={isPopoverOpen}
closePopover={closePopover}
>
<EuiPopoverTitle>{popoverContent.title}</EuiPopoverTitle>
<EuiText size="s" style={{ width: 300 }}>
{popoverContent.content}
</EuiText>
<EuiPopoverFooter>
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButton
size="s"
href={addDataLinkHref}
data-test-subj="infraHostsTableWithoutSystemMetricsPopoverAddMoreButton"
>
{popoverContent.button}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">
<EuiLink
href={APM_HOST_TROUBLESHOOTING_LINK}
target="_blank"
data-test-subj="infraHostsTableWithoutSystemMetricsPopoverTroubleshootingLink"
external
>
{popoverContent.link}
</EuiLink>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPopoverFooter>
</EuiPopover>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { useHostsTable } from './use_hosts_table';
import { type HostNodeRow, useHostsTable } from './use_hosts_table';
import { renderHook } from '@testing-library/react-hooks';
import { InfraAssetMetricsItem } from '../../../../../common/http_api';
import * as useUnifiedSearchHooks from './use_unified_search';
Expand Down Expand Up @@ -158,7 +158,7 @@ describe('useHostTable hook', () => {
} as unknown as ReturnType<typeof useKibanaContextForPluginHook.useKibanaContextForPlugin>);
});
it('it should map the nodes returned from the snapshot api to a format matching eui table items', () => {
const expected = [
const expected: Array<Partial<HostNodeRow>> = [
{
name: 'host-0',
os: '-',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { ColumnHeader } from '../components/table/column_header';
import { TABLE_COLUMN_LABEL, TABLE_CONTENT_LABEL } from '../translations';
import { METRICS_TOOLTIP } from '../../../../common/visualizations';
import { buildCombinedAssetFilter } from '../../../../utils/filters/build';
import { AddDataTroubleshootingPopover } from '../components/table/add_data_troubleshooting_popover';

/**
* Columns and items types
Expand Down Expand Up @@ -67,6 +68,18 @@ const formatMetric = (type: InfraAssetMetricType, value: number | undefined | nu
return value || value === 0 ? createInventoryMetricFormatter({ type })(value) : 'N/A';
};

const buildMetricCell = (
value: number,
iblancof marked this conversation as resolved.
Show resolved Hide resolved
formatType: InfraAssetMetricType,
hasSystemMetrics?: boolean
) => {
if (!hasSystemMetrics && value === null) {
return <AddDataTroubleshootingPopover />;
}

return formatMetric(formatType, value);
};

const buildItemsList = (nodes: InfraAssetMetricsItem[]): HostNodeRow[] => {
return nodes.map(({ metrics, metadata, name, alertsCount, hasSystemMetrics }) => {
const metadataKeyValue = metadata.reduce(
Expand All @@ -89,7 +102,7 @@ const buildItemsList = (nodes: InfraAssetMetricsItem[]): HostNodeRow[] => {
...metrics.reduce(
(acc, curr) => ({
...acc,
[curr.name]: curr.value ?? 0,
[curr.name]: curr.value,
}),
{} as HostMetrics
),
Expand All @@ -104,12 +117,15 @@ const isTitleColumn = (cell: HostNodeRow[keyof HostNodeRow]): cell is HostNodeRo
};

const sortValues = (aValue: any, bValue: any, { direction }: Sorting) => {
if (typeof aValue === 'string' && typeof bValue === 'string') {
return direction === 'desc' ? bValue.localeCompare(aValue) : aValue.localeCompare(bValue);
const a = aValue ?? -1;
const b = bValue ?? -1;

if (typeof a === 'string' && typeof b === 'string') {
return direction === 'desc' ? b.localeCompare(a) : a.localeCompare(b);
}

if (isNumber(aValue) && isNumber(bValue)) {
return direction === 'desc' ? bValue - aValue : aValue - bValue;
if (isNumber(a) && isNumber(b)) {
return direction === 'desc' ? b - a : a - b;
}

return 1;
Expand Down Expand Up @@ -358,7 +374,8 @@ export const useHostsTable = () => {
field: 'cpuV2',
sortable: true,
'data-test-subj': 'hostsView-tableRow-cpuUsage',
render: (avg: number) => formatMetric('cpuV2', avg),
render: (avg: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(avg, 'cpuV2', hasSystemMetrics),
iblancof marked this conversation as resolved.
Show resolved Hide resolved
align: 'right',
},
{
Expand All @@ -373,7 +390,8 @@ export const useHostsTable = () => {
field: 'normalizedLoad1m',
sortable: true,
'data-test-subj': 'hostsView-tableRow-normalizedLoad1m',
render: (avg: number) => formatMetric('normalizedLoad1m', avg),
render: (avg: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(avg, 'normalizedLoad1m', hasSystemMetrics),
align: 'right',
},
{
Expand All @@ -388,7 +406,8 @@ export const useHostsTable = () => {
field: 'memory',
sortable: true,
'data-test-subj': 'hostsView-tableRow-memoryUsage',
render: (avg: number) => formatMetric('memory', avg),
render: (avg: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(avg, 'memory', hasSystemMetrics),
align: 'right',
},
{
Expand All @@ -403,7 +422,8 @@ export const useHostsTable = () => {
field: 'memoryFree',
sortable: true,
'data-test-subj': 'hostsView-tableRow-memoryFree',
render: (avg: number) => formatMetric('memoryFree', avg),
render: (avg: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(avg, 'memoryFree', hasSystemMetrics),
align: 'right',
},
{
Expand All @@ -418,7 +438,8 @@ export const useHostsTable = () => {
field: 'diskSpaceUsage',
sortable: true,
'data-test-subj': 'hostsView-tableRow-diskSpaceUsage',
render: (max: number) => formatMetric('diskSpaceUsage', max),
render: (max: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(max, 'diskSpaceUsage', hasSystemMetrics),
align: 'right',
},
{
Expand All @@ -433,7 +454,8 @@ export const useHostsTable = () => {
field: 'rxV2',
sortable: true,
'data-test-subj': 'hostsView-tableRow-rx',
render: (avg: number) => formatMetric('rx', avg),
render: (avg: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(avg, 'rx', hasSystemMetrics),
align: 'right',
},
{
Expand All @@ -448,7 +470,8 @@ export const useHostsTable = () => {
field: 'txV2',
sortable: true,
'data-test-subj': 'hostsView-tableRow-tx',
render: (avg: number) => formatMetric('tx', avg),
render: (avg: number, { hasSystemMetrics }: HostNodeRow) =>
buildMetricCell(avg, 'tx', hasSystemMetrics),
align: 'right',
},
],
Expand Down