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 UI] Add overview tab with the first section to asset details view #160924

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8db7d8e
Add metadata summary
jennypavlova Jun 27, 2023
e574b9e
Add overview tab
jennypavlova Jun 27, 2023
efa3ad7
KPI tiles changes
jennypavlova Jun 29, 2023
9d9146f
Add show all button in overview metadata section
jennypavlova Jun 29, 2023
a18a5f7
Set overview to be the default tab
jennypavlova Jun 29, 2023
96257f8
Change show all button position and icon
jennypavlova Jun 29, 2023
5b13157
Add 'infra' to translations
jennypavlova Jun 30, 2023
1b88fd0
Update existing flyout test
jennypavlova Jun 30, 2023
f25fd0c
Merge branch 'main' into 160376-infra-ui-add-overview-tab-with-the-fi…
jennypavlova Jun 30, 2023
6ecad31
Update type and add overview tab test
jennypavlova Jun 30, 2023
db79644
Small fixes
jennypavlova Jun 30, 2023
1600220
Add storybook and pass dataview and daterange as overrides
jennypavlova Jun 30, 2023
c38d4cb
Cleanup imports
jennypavlova Jul 3, 2023
2f4538f
Merge branch 'main' into 160376-infra-ui-add-overview-tab-with-the-fi…
jennypavlova Jul 3, 2023
afefdbc
Small CR changes
jennypavlova Jul 4, 2023
8c91109
Merge branch 'main' into 160376-infra-ui-add-overview-tab-with-the-fi…
jennypavlova Jul 4, 2023
ee3c1c2
Extract tile dependencies in common folder
jennypavlova Jul 4, 2023
2ce0f8f
Use React.memo in KPIGrid
jennypavlova Jul 4, 2023
1c34e52
Import fixes
jennypavlova Jul 4, 2023
4a12e3e
Add onTabsStateChange to useTabSwitcher
jennypavlova Jul 4, 2023
f686a28
Merge branch 'main' of github.com:elastic/kibana into 160376-infra-ui…
jennypavlova Jul 5, 2023
5e93f2e
Merge branch 'main' into 160376-infra-ui-add-overview-tab-with-the-fi…
jennypavlova Jul 5, 2023
d21dd63
CR changes
jennypavlova Jul 6, 2023
7735c1c
Show charts if metadata fetch fails
jennypavlova Jul 6, 2023
5d7eb2c
Merge branch 'main' of github.com:elastic/kibana into 160376-infra-ui…
jennypavlova Jul 6, 2023
e772b91
Move kpi grid config and tooltip translation to common folder
jennypavlova Jul 7, 2023
2f367b2
Merge branch 'main' into 160376-infra-ui-add-overview-tab-with-the-fi…
jennypavlova Jul 7, 2023
d24988e
Use correct translations and type in shared kpi config
jennypavlova Jul 7, 2023
0c0b9d5
Merge branch 'main' into 160376-infra-ui-add-overview-tab-with-the-fi…
jennypavlova Jul 7, 2023
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
Expand Up @@ -42,3 +42,5 @@ export const visualizationTypes = {
lineChart: LineChart,
metricChart: MetricChart,
};

export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics';
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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 { HostsLensMetricChartFormulas } from '../types';
import { TOOLTIP } from './translations';

export interface KPIChartProps {
title: string;
subtitle?: string;
trendLine?: boolean;
backgroundColor: string;
type: HostsLensMetricChartFormulas;
decimals?: number;
toolTip: string;
}

export const KPI_CHARTS: Array<Omit<KPIChartProps, 'loading' | 'subtitle' | 'style'>> = [
{
type: 'cpuUsage',
trendLine: true,
backgroundColor: '#F1D86F',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.cpuUsage.title', {
defaultMessage: 'CPU Usage',
}),
toolTip: TOOLTIP.cpuUsage,
},
{
type: 'normalizedLoad1m',
trendLine: true,
backgroundColor: '#79AAD9',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title', {
defaultMessage: 'Normalized Load',
}),
toolTip: TOOLTIP.rx,
},
{
type: 'memoryUsage',
trendLine: true,
backgroundColor: '#A987D1',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.memoryUsage.title', {
defaultMessage: 'Memory Usage',
}),
toolTip: i18n.translate('xpack.infra.hostsViewPage.metricTrend.memoryUsage.tooltip', {
defaultMessage: 'Main memory usage excluding page cache.',
}),
},
{
type: 'diskSpaceUsage',
trendLine: true,
backgroundColor: '#F5A35C',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.diskSpaceUsage.title', {
defaultMessage: 'Disk Space Usage',
}),
toolTip: TOOLTIP.tx,
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { Action } from '@kbn/ui-actions-plugin/public';
import { ViewMode } from '@kbn/embeddable-plugin/public';
import { BrushTriggerEvent } from '@kbn/charts-plugin/public';
import { Filter, Query, TimeRange } from '@kbn/es-query';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import { useIntersectedOnce } from '../../../../../hooks/use_intersection_once';
import { LensAttributes } from '../../../../../common/visualizations';
import { useIntersectedOnce } from '../../../hooks/use_intersection_once';
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
import { ChartLoader } from './chart_loader';
import type { LensAttributes } from '../types';

export interface LensWrapperProps {
id: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { i18n } from '@kbn/i18n';

export const TOOLTIP = {
hostCount: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.hostCount', {
defaultMessage: 'Number of hosts returned by your search criteria.',
}),

cpuUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.cpuUsage', {
defaultMessage:
'Percentage of CPU time spent in states other than Idle and IOWait, normalized by the number of CPU cores. This includes both time spent on user space and kernel space.',
}),
diskSpaceUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.diskSpaceUsage', {
defaultMessage: 'Percentage of disk space used.',
}),
diskLatency: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.diskLatency', {
defaultMessage: 'Time spent to service disk requests.',
}),
memoryFree: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryFree', {
defaultMessage: 'Total available memory including page cache.',
}),
memoryTotal: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryTotal', {
defaultMessage: 'Total memory capacity.',
}),
memoryUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryUsage', {
defaultMessage: 'Percentage of main memory usage excluding page cache.',
}),
normalizedLoad1m: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.normalizedLoad1m', {
defaultMessage: '1 minute load average normalized by the number of CPU cores. ',
}),
rx: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.rx', {
defaultMessage:
'Number of bytes which have been received per second on the public interfaces of the hosts.',
}),
tx: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.tx', {
defaultMessage:
'Number of bytes which have been sent per second on the public interfaces of the hosts.',
}),
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { EuiLink, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { HOST_METRICS_DOC_HREF } from '../../constants';
import { HOST_METRICS_DOC_HREF } from '../constants';

export const HostMetricsDocsLink = () => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, { HTMLAttributes } from 'react';
import { EuiText, EuiLink } from '@elastic/eui';
import { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
import { HOST_METRICS_DOC_HREF } from '../../constants';
import { HOST_METRICS_DOC_HREF } from '../constants';

interface Props extends Pick<HTMLAttributes<HTMLDivElement>, 'style'> {
description: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export const DecorateWithKibanaContext: DecoratorFn = (story) => {
},
},
},
lens: {
navigateToPrefilledEditor: () => {},
stateHelperApi: () => new Promise(() => {}),
},
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,22 @@ import React, { useState } from 'react';
import { EuiButton } from '@elastic/eui';
import type { Meta, Story } from '@storybook/react/types-6-0';
import { i18n } from '@kbn/i18n';
import type { DataViewField } from '@kbn/data-views-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
import { AssetDetails } from './asset_details';
import { decorateWithGlobalStorybookThemeProviders } from '../../test_utils/use_global_storybook_theme';
import { FlyoutTabIds, Tab, type AssetDetailsProps } from './types';
import { DecorateWithKibanaContext } from './__stories__/decorator';

const links: AssetDetailsProps['links'] = ['alertRule', 'nodeDetails', 'apmServices', 'uptime'];
const tabs: Tab[] = [
{
id: FlyoutTabIds.OVERVIEW,
name: i18n.translate('xpack.infra.nodeDetails.tabs.overview.title', {
defaultMessage: 'Overview',
}),
'data-test-subj': 'hostsView-flyout-tabs-overview',
},
{
id: FlyoutTabIds.METRICS,
name: i18n.translate('xpack.infra.nodeDetails.tabs.metrics', {
Expand Down Expand Up @@ -98,6 +107,16 @@ const stories: Meta<AssetDetailsProps> = {
memoryFree: 34359738368,
},
overrides: {
overview: {
dataView: {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find a good way to add the types here as I wanted to add this just to mock the data view in order to load the overview tab

id: 'default',
getFieldByName: () => 'hostname' as unknown as DataViewField,
} as unknown as DataView,
dateRange: {
from: '168363046800',
to: '168363046900',
},
},
metadata: {
showActionsColumn: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const AssetDetails = ({
return (
<TabSwitcherProvider
initialActiveTabId={tabs.length > 0 ? activeTabId ?? tabs[0].id : undefined}
onTabsStateChange={onTabsStateChange}
>
<ContentTemplate
header={
Expand All @@ -59,7 +60,6 @@ export const AssetDetails = ({
tabs={tabs}
links={links}
overrides={overrides}
onTabsStateChange={onTabsStateChange}
/>
}
body={
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui';

import { i18n } from '@kbn/i18n';
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import useToggle from 'react-use/lib/useToggle';

interface ExpandableContentProps {
values: string | string[] | undefined;
}
export 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 (
<EuiFlexGroup gutterSize="xs" responsive={false} alignItems="baseline" wrap direction="column">
<div>
{first}
{shouldShowMore && (
<>
{' ... '}
<EuiLink data-test-subj="infraExpandableContentCountMoreLink" onClick={toggle}>
<FormattedMessage
id="xpack.infra.nodeDetails.tabs.metadata.seeMore"
defaultMessage="+{count} more"
values={{
count: others.length,
}}
/>
</EuiLink>
</>
)}
</div>
{isExpanded && others.map((item, index) => <EuiFlexItem key={index}>{item}</EuiFlexItem>)}
{hasOthers && isExpanded && (
<EuiFlexItem>
<EuiLink data-test-subj="infraExpandableContentShowLessLink" onClick={toggle}>
{i18n.translate('xpack.infra.nodeDetails.tabs.metadata.seeLess', {
defaultMessage: 'Show less',
})}
</EuiLink>
</EuiFlexItem>
)}
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import React from 'react';
import { useTabSwitcherContext } from '../hooks/use_tab_switcher';
import { Anomalies, Metadata, Processes, Osquery, Metrics, Logs } from '../tabs';
import { Anomalies, Metadata, Processes, Osquery, Metrics, Logs, Overview } from '../tabs';
import { FlyoutTabIds, type TabState, type AssetDetailsProps } from '../types';

type Props = Pick<
Expand All @@ -19,8 +19,8 @@ export const Content = ({
overrides,
currentTimeRange,
node,
nodeType = 'host',
onTabsStateChange,
nodeType = 'host',
}: Props) => {
const onChange = (state: TabState) => {
if (!onTabsStateChange) {
Expand All @@ -35,6 +35,15 @@ export const Content = ({
<TabPanel activeWhen={FlyoutTabIds.ANOMALIES}>
<Anomalies nodeName={node.name} onClose={overrides?.anomalies?.onClose} />
</TabPanel>
<TabPanel activeWhen={FlyoutTabIds.OVERVIEW}>
<Overview
currentTimeRange={currentTimeRange}
nodeName={node.name}
nodeType={nodeType}
dataView={overrides?.overview?.dataView}
dateRange={overrides?.overview?.dateRange}
/>
</TabPanel>
<TabPanel activeWhen={FlyoutTabIds.LOGS}>
<Logs
nodeName={node.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { useTabSwitcherContext } from '../hooks/use_tab_switcher';

type Props = Pick<
AssetDetailsProps,
'currentTimeRange' | 'overrides' | 'node' | 'nodeType' | 'links' | 'tabs' | 'onTabsStateChange'
'currentTimeRange' | 'overrides' | 'node' | 'nodeType' | 'links' | 'tabs'
> & {
compact: boolean;
};
Expand All @@ -45,16 +45,11 @@ export const Header = ({
compact,
currentTimeRange,
overrides,
onTabsStateChange,
}: Props) => {
const { euiTheme } = useEuiTheme();
const { showTab, activeTabId } = useTabSwitcherContext();

const onTabClick = (tabId: TabIds) => {
if (onTabsStateChange) {
onTabsStateChange({ activeTabId: tabId });
}

showTab(tabId);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
import { useState } from 'react';
import createContainer from 'constate';
import { useLazyRef } from '../../../hooks/use_lazy_ref';
import type { TabIds } from '../types';
import type { TabIds, TabsStateChangeFn } from '../types';

export function useTabSwitcher({ initialActiveTabId }: { initialActiveTabId?: TabIds }) {
interface TabSwitcherParams {
initialActiveTabId?: TabIds;
onTabsStateChange?: TabsStateChangeFn;
}

export function useTabSwitcher({ initialActiveTabId, onTabsStateChange }: TabSwitcherParams) {
const [activeTabId, setActiveTabId] = useState<TabIds | undefined>(initialActiveTabId);

// This set keeps track of which tabs content have been rendered the first time.
Expand All @@ -20,6 +25,10 @@ export function useTabSwitcher({ initialActiveTabId }: { initialActiveTabId?: Ta
const showTab = (tabId: TabIds) => {
renderedTabsSet.current.add(tabId); // On a tab click, mark the tab content as allowed to be rendered
setActiveTabId(tabId);

if (onTabsStateChange) {
onTabsStateChange({ activeTabId: tabId });
}
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export { Processes } from './processes/processes';
export { Osquery } from './osquery/osquery';
export { Metrics } from './metrics/metrics';
export { Logs } from './logs/logs';
export { Overview } from './overview/overview';
Loading