From 8f83090d74d0254a870ce3540999a7e40ecfea91 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 4 Jun 2021 08:48:35 -0400 Subject: [PATCH] [Uptime] Show URL and metrics on sidebar and waterfall item tooltips (#99985) * Add URL to metrics tooltip. * Add screenreader label for URL container. * Add metrics to URL sidebar tooltip. * Rename vars. * Delete unnecessary code. * Undo rename. * Extract component to dedicated file, add tests. * Fix error in test. * Add offset index to heading of waterfall chart tooltip. * Format the waterfall tool tip header. * Add horizontal rule and bold text for waterfall tooltip. * Extract inline helper function to module-level for reuse. * Reuse waterfall tooltip style. * Style reusable tooltip content. * Adapt existing chart tooltip to use tooltip content component for better consistency. * Delete test code. * Style EUI tooltip arrow. * Revert whitespace change. * Delete obsolete test. * Implement and use common tooltip heading formatter function. * Add tests for new formatter function. * Fix a typo. * Add a comment explaining a style hack. * Add optional chaining to avoid breaking a test. * Revert previous change, use RTL wrapper, rename describe block. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../waterfall/data_formatting.test.ts | 11 +++ .../step_detail/waterfall/data_formatting.ts | 3 + .../components/middle_truncated_text.tsx | 8 +- .../synthetics/waterfall/components/styles.ts | 3 + .../components/waterfall_bar_chart.tsx | 46 +++++----- .../waterfall_tooltip_content.test.tsx | 84 +++++++++++++++++++ .../components/waterfall_tooltip_content.tsx | 46 ++++++++++ 7 files changed, 180 insertions(+), 21 deletions(-) create mode 100644 x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_tooltip_content.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_tooltip_content.tsx diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts index ebb6eb6bdc989c..229933c2f06429 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts @@ -7,6 +7,7 @@ import moment from 'moment'; import { colourPalette, + formatTooltipHeading, getConnectingTime, getSeriesAndDomain, getSidebarItems, @@ -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/'); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts index f497bf1ea7b354..0f0ce01d250998 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts @@ -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}`; diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx index a661d60400f97d..956f4b19c66263 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx @@ -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; @@ -116,7 +118,9 @@ export const MiddleTruncatedText = ({ + } data-test-subj="middleTruncatedTextToolTip" delay="long" position="top" diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts index 8e3033037766a2..f8de61f9d86903 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts @@ -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)` diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_bar_chart.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_bar_chart.tsx index 19a828aa097b6f..8723dd744132ae 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_bar_chart.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_bar_chart.tsx @@ -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 @@ -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 ? ( - - - {relevantItems.map((item, index) => { - return ( - {renderTooltipItem(item.config.tooltipProps)} - ); - })} - - - ) : 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 ? ( + + {sidebarItem && ( + + )} + + ) : null; + }, [data, sidebarItems, tooltipInfo.header?.value]); }; interface Props { @@ -82,7 +85,12 @@ export const WaterfallBarChart = ({ ({ + 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) => ( +
+
{props.colour}
+
{props.value}
+
+ ), + 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( + + ); + 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( + + ); + const metricElements = getAllByLabelText('tooltip item'); + expect(metricElements).toHaveLength(1); + expect(getByText('test-val')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_tooltip_content.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_tooltip_content.tsx new file mode 100644 index 00000000000000..21b3bf72d22178 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/waterfall_tooltip_content.tsx @@ -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 = ({ 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 ( + <> + {text} + + + {tooltipMetrics.map((item, idx) => ( + {renderTooltipItem(item.config.tooltipProps)} + ))} + + + ); +};