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

[Uptime] Show URL and metrics on sidebar and waterfall item tooltips #99985

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d5ec9ae
Add URL to metrics tooltip.
justinkambic May 12, 2021
16fb63a
Add screenreader label for URL container.
justinkambic May 12, 2021
70fc308
Add metrics to URL sidebar tooltip.
justinkambic May 13, 2021
4f62270
Rename vars.
justinkambic May 13, 2021
dcaf5d3
Delete unnecessary code.
justinkambic May 13, 2021
a800f48
Undo rename.
justinkambic May 13, 2021
b46472d
Extract component to dedicated file, add tests.
justinkambic May 14, 2021
912885f
Fix error in test.
justinkambic May 14, 2021
9687a62
Add offset index to heading of waterfall chart tooltip.
justinkambic May 14, 2021
ff60b65
Format the waterfall tool tip header.
justinkambic May 20, 2021
fbdfad1
Add horizontal rule and bold text for waterfall tooltip.
justinkambic May 20, 2021
feb23fc
Merge branch 'master' into feature/87272-show-url-on-waterfall-tooltip
justinkambic May 25, 2021
a18fd10
Extract inline helper function to module-level for reuse.
justinkambic May 25, 2021
bfa7810
Reuse waterfall tooltip style.
justinkambic May 25, 2021
5cee2f1
Style reusable tooltip content.
justinkambic May 25, 2021
58d4b88
Adapt existing chart tooltip to use tooltip content component for bet…
justinkambic May 25, 2021
15907b4
Delete test code.
justinkambic May 25, 2021
efe3d59
Style EUI tooltip arrow.
justinkambic May 25, 2021
47afec8
Merge branch 'master' into feature/87272-show-url-on-waterfall-tooltip
justinkambic May 28, 2021
d90fe06
Revert whitespace change.
justinkambic May 28, 2021
5ada88d
Merge branch 'master' into feature/87272-show-url-on-waterfall-tooltip
justinkambic Jun 1, 2021
9ea10af
Delete obsolete test.
justinkambic Jun 1, 2021
0f8846f
Implement and use common tooltip heading formatter function.
justinkambic Jun 1, 2021
3f3c92d
Add tests for new formatter function.
justinkambic Jun 1, 2021
552a0d5
Fix a typo.
justinkambic Jun 1, 2021
85dc425
Add a comment explaining a style hack.
justinkambic Jun 1, 2021
63e30d0
Add optional chaining to avoid breaking a test.
justinkambic Jun 2, 2021
a142306
Revert previous change, use RTL wrapper, rename describe block.
justinkambic Jun 2, 2021
72c9c95
Merge branch 'master' into feature/87272-show-url-on-waterfall-tooltip
justinkambic Jun 2, 2021
06065fa
Merge branch 'master' into feature/87272-show-url-on-waterfall-tooltip
kibanamachine Jun 3, 2021
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 @@ -7,6 +7,7 @@
import moment from 'moment';
import {
colourPalette,
formatTooltipHeading,
getConnectingTime,
getSeriesAndDomain,
getSidebarItems,
Expand Down Expand Up @@ -729,3 +730,13 @@ describe('getSidebarItems', () => {
expect(actual[0].offsetIndex).toBe(1);
});
});

describe('formatTooltipHeading', () => {
it('puts index and URL text together', () => {
expect(formatTooltipHeading(1, 'http://www.elastic.co/')).toEqual('1. http://www.elastic.co/');
});

it('returns only the text if `index` is NaN', () => {
expect(formatTooltipHeading(NaN, 'http://www.elastic.co/')).toEqual('http://www.elastic.co/');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,6 @@ const MIME_TYPE_PALETTE = buildMimeTypePalette();
type ColourPalette = TimingColourPalette & MimeTypeColourPalette;

export const colourPalette: ColourPalette = { ...TIMING_PALETTE, ...MIME_TYPE_PALETTE };

export const formatTooltipHeading = (index: number, fullText: string): string =>
isNaN(index) ? fullText : `${index}. ${fullText}`;
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiButtonEmpty,
EuiScreenReaderOnly,
EuiToolTip,
EuiButtonEmpty,
EuiLink,
EuiText,
EuiIcon,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { WaterfallTooltipContent } from './waterfall_tooltip_content';
import { WaterfallTooltipResponsiveMaxWidth } from './styles';
import { FIXED_AXIS_HEIGHT } from './constants';
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
import { formatTooltipHeading } from '../../step_detail/waterfall/data_formatting';

interface Props {
index: number;
Expand Down Expand Up @@ -116,7 +118,9 @@ export const MiddleTruncatedText = ({
</EuiScreenReaderOnly>
<WaterfallTooltipResponsiveMaxWidth
as={EuiToolTip}
content={`${index}. ${fullText}`}
content={
<WaterfallTooltipContent {...{ text: formatTooltipHeading(index, fullText), url }} />
}
data-test-subj="middleTruncatedTextToolTip"
delay="long"
position="top"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ export const WaterfallChartTooltip = euiStyled(WaterfallTooltipResponsiveMaxWidt
border-radius: ${(props) => props.theme.eui.euiBorderRadius};
color: ${(props) => props.theme.eui.euiColorLightestShade};
padding: ${(props) => props.theme.eui.paddingSizes.s};
.euiToolTip__arrow {
background-color: ${(props) => props.theme.eui.euiColorDarkestShade};
}
`;

export const NetworkRequestsTotalStyle = euiStyled(EuiText)`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
TickFormatter,
TooltipInfo,
} from '@elastic/charts';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { BAR_HEIGHT } from './constants';
import { useChartTheme } from '../../../../../hooks/use_chart_theme';
import { WaterfallChartChartContainer, WaterfallChartTooltip } from './styles';
import { useWaterfallContext, WaterfallData } from '..';
import { WaterfallTooltipContent } from './waterfall_tooltip_content';
import { formatTooltipHeading } from '../../step_detail/waterfall/data_formatting';

const getChartHeight = (data: WaterfallData): number => {
// We get the last item x(number of bars) and adds 1 to cater for 0 index
Expand All @@ -32,23 +33,25 @@ const getChartHeight = (data: WaterfallData): number => {
};

const Tooltip = (tooltipInfo: TooltipInfo) => {
const { data, renderTooltipItem } = useWaterfallContext();
const relevantItems = data.filter((item) => {
return (
item.x === tooltipInfo.header?.value && item.config.showTooltip && item.config.tooltipProps
);
});
return relevantItems.length ? (
<WaterfallChartTooltip>
<EuiFlexGroup direction="column" gutterSize="none">
{relevantItems.map((item, index) => {
return (
<EuiFlexItem key={index}>{renderTooltipItem(item.config.tooltipProps)}</EuiFlexItem>
);
})}
</EuiFlexGroup>
</WaterfallChartTooltip>
) : null;
const { data, sidebarItems } = useWaterfallContext();
return useMemo(() => {
const sidebarItem = sidebarItems?.find((item) => item.index === tooltipInfo.header?.value);
const relevantItems = data.filter((item) => {
return (
item.x === tooltipInfo.header?.value && item.config.showTooltip && item.config.tooltipProps
);
});
return relevantItems.length ? (
<WaterfallChartTooltip>
{sidebarItem && (
<WaterfallTooltipContent
text={formatTooltipHeading(sidebarItem.index + 1, sidebarItem.url)}
url={sidebarItem.url}
/>
)}
</WaterfallChartTooltip>
) : null;
}, [data, sidebarItems, tooltipInfo.header?.value]);
};

interface Props {
Expand Down Expand Up @@ -82,7 +85,12 @@ export const WaterfallBarChart = ({
<Settings
showLegend={false}
rotation={90}
tooltip={{ customTooltip: Tooltip }}
tooltip={{
// this is done to prevent the waterfall tooltip from rendering behind Kibana's
// stacked header when the user highlights an item at the top of the chart
boundary: document.getElementById('app-fixed-viewport') ?? undefined,
customTooltip: Tooltip,
}}
theme={theme}
onProjectionClick={handleProjectionClick}
onElementClick={handleElementClick}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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 { render } from '../../../../../lib/helper/rtl_helpers';
import { WaterfallTooltipContent } from './waterfall_tooltip_content';

jest.mock('../context/waterfall_chart', () => ({
useWaterfallContext: jest.fn().mockReturnValue({
data: [
{
x: 0,
config: {
url: 'https://www.elastic.co',
tooltipProps: {
colour: '#000000',
value: 'test-val',
},
showTooltip: true,
},
},
{
x: 0,
config: {
url: 'https://www.elastic.co/with/missing/tooltip.props',
showTooltip: true,
},
},
{
x: 1,
config: {
url: 'https://www.elastic.co/someresource.path',
tooltipProps: {
colour: '#010000',
value: 'test-val-missing',
},
showTooltip: true,
},
},
],
renderTooltipItem: (props: any) => (
<div aria-label="tooltip item">
<div>{props.colour}</div>
<div>{props.value}</div>
</div>
),
sidebarItems: [
{
isHighlighted: true,
index: 0,
offsetIndex: 1,
url: 'https://www.elastic.co',
status: 200,
method: 'GET',
},
],
}),
}));

describe('WaterfallTooltipContent', () => {
it('renders tooltip', () => {
const { getByText, queryByText } = render(
<WaterfallTooltipContent text="1. https://www.elastic.co" url="https://www.elastic.co" />
);
expect(getByText('#000000')).toBeInTheDocument();
expect(getByText('test-val')).toBeInTheDocument();
expect(getByText('1. https://www.elastic.co')).toBeInTheDocument();
expect(queryByText('#010000')).toBeNull();
expect(queryByText('test-val-missing')).toBeNull();
});

it(`doesn't render metric if tooltip props missing`, () => {
const { getAllByLabelText, getByText } = render(
<WaterfallTooltipContent text="1. https://www.elastic.co" url="https://www.elastic.co" />
);
const metricElements = getAllByLabelText('tooltip item');
expect(metricElements).toHaveLength(1);
expect(getByText('test-val')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiText } from '@elastic/eui';
import { useWaterfallContext } from '../context/waterfall_chart';
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';

interface Props {
text: string;
url: string;
}

const StyledText = euiStyled(EuiText)`
font-weight: bold;
`;

const StyledHorizontalRule = euiStyled(EuiHorizontalRule)`
background-color: ${(props) => props.theme.eui.euiColorDarkShade};
`;

export const WaterfallTooltipContent: React.FC<Props> = ({ text, url }) => {
const { data, renderTooltipItem, sidebarItems } = useWaterfallContext();

const tooltipMetrics = data.filter(
(datum) =>
datum.x === sidebarItems?.find((sidebarItem) => sidebarItem.url === url)?.index &&
datum.config.tooltipProps &&
datum.config.showTooltip
);
return (
<>
<StyledText>{text}</StyledText>
<StyledHorizontalRule margin="none" />
<EuiFlexGroup direction="column" gutterSize="none">
{tooltipMetrics.map((item, idx) => (
<EuiFlexItem key={idx}>{renderTooltipItem(item.config.tooltipProps)}</EuiFlexItem>
))}
</EuiFlexGroup>
</>
);
};