diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.test.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.test.ts index 2f4136d425963..7313d21dd3ffb 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.test.ts @@ -12,8 +12,14 @@ import { getSeriesAndDomain, getSidebarItems, } from './data_formatting'; -import { MimeType, FriendlyFlyoutLabels, FriendlyTimingLabels, Timings, Metadata } from './types'; -import { WaterfallDataEntry } from './types'; +import { + MimeType, + FriendlyFlyoutLabels, + FriendlyTimingLabels, + Timings, + Metadata, + WaterfallTooltipItem, +} from './types'; import type { DateFormatter } from '../../../../../../hooks/use_date_format'; import { mockMoment } from '../../../../utils/formatting/test_helpers'; import { NetworkEvent } from '../../../../../../../common/runtime_types'; @@ -247,11 +253,6 @@ describe('getSeriesAndDomain', () => { "colour": "#b0c9e0", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#b0c9e0", - "value": "Queued / Blocked: 0.9ms", - }, }, "x": 0, "y": 0.8540000017092098, @@ -262,11 +263,6 @@ describe('getSeriesAndDomain', () => { "colour": "#aad9cc", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#aad9cc", - "value": "DNS: 4ms", - }, }, "x": 0, "y": 4.413999999087537, @@ -277,11 +273,6 @@ describe('getSeriesAndDomain', () => { "colour": "#c8b8dc", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#c8b8dc", - "value": "Connecting: 26ms", - }, }, "x": 0, "y": 30.135000000882428, @@ -292,11 +283,6 @@ describe('getSeriesAndDomain', () => { "colour": "#e5c7d7", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#e5c7d7", - "value": "TLS: 55ms", - }, }, "x": 0, "y": 85.52200000121957, @@ -307,11 +293,6 @@ describe('getSeriesAndDomain', () => { "colour": "#f3b3a6", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#f3b3a6", - "value": "Sending request: 0.4ms", - }, }, "x": 0, "y": 85.88200000303914, @@ -322,11 +303,6 @@ describe('getSeriesAndDomain', () => { "colour": "#e7664c", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#e7664c", - "value": "Waiting (TTFB): 35ms", - }, }, "x": 0, "y": 120.4600000019127, @@ -337,11 +313,6 @@ describe('getSeriesAndDomain', () => { "colour": "#9170b8", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#9170b8", - "value": "Content downloading (CSS): 0.6ms", - }, }, "x": 0, "y": 121.01200000324752, @@ -352,11 +323,6 @@ describe('getSeriesAndDomain', () => { "colour": "#b0c9e0", "id": 1, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#b0c9e0", - "value": "Queued / Blocked: 85ms", - }, }, "x": 1, "y": 84.90799999795854, @@ -367,11 +333,6 @@ describe('getSeriesAndDomain', () => { "colour": "#f3b3a6", "id": 1, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#f3b3a6", - "value": "Sending request: 0.2ms", - }, }, "x": 1, "y": 85.14699999883305, @@ -382,11 +343,6 @@ describe('getSeriesAndDomain', () => { "colour": "#e7664c", "id": 1, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#e7664c", - "value": "Waiting (TTFB): 53ms", - }, }, "x": 1, "y": 137.70799999925657, @@ -397,11 +353,6 @@ describe('getSeriesAndDomain', () => { "colour": "#da8b45", "id": 1, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#da8b45", - "value": "Content downloading (JS): 3ms", - }, }, "x": 1, "y": 140.7760000010603, @@ -420,11 +371,6 @@ describe('getSeriesAndDomain', () => { "colour": "#b0c9e0", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#b0c9e0", - "value": "Queued / Blocked: 0.9ms", - }, }, "x": 0, "y": 0.8540000017092098, @@ -435,11 +381,6 @@ describe('getSeriesAndDomain', () => { "colour": "#aad9cc", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#aad9cc", - "value": "DNS: 4ms", - }, }, "x": 0, "y": 4.413999999087537, @@ -450,11 +391,6 @@ describe('getSeriesAndDomain', () => { "colour": "#c8b8dc", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#c8b8dc", - "value": "Connecting: 26ms", - }, }, "x": 0, "y": 30.135000000882428, @@ -465,11 +401,6 @@ describe('getSeriesAndDomain', () => { "colour": "#e5c7d7", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#e5c7d7", - "value": "TLS: 55ms", - }, }, "x": 0, "y": 85.52200000121957, @@ -480,11 +411,6 @@ describe('getSeriesAndDomain', () => { "colour": "#f3b3a6", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#f3b3a6", - "value": "Sending request: 0.4ms", - }, }, "x": 0, "y": 85.88200000303914, @@ -495,11 +421,6 @@ describe('getSeriesAndDomain', () => { "colour": "#e7664c", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#e7664c", - "value": "Waiting (TTFB): 35ms", - }, }, "x": 0, "y": 120.4600000019127, @@ -510,11 +431,6 @@ describe('getSeriesAndDomain', () => { "colour": "#9170b8", "id": 0, "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#9170b8", - "value": "Content downloading (CSS): 0.6ms", - }, }, "x": 0, "y": 121.01200000324752, @@ -524,11 +440,6 @@ describe('getSeriesAndDomain', () => { "config": Object { "colour": "#da8b45", "isHighlighted": true, - "showTooltip": true, - "tooltipProps": Object { - "colour": "#da8b45", - "value": "Content downloading (JS): 3ms", - }, }, "x": 1, "y": 3.714999998046551, @@ -546,8 +457,6 @@ describe('getSeriesAndDomain', () => { "config": Object { "colour": "", "isHighlighted": true, - "showTooltip": false, - "tooltipProps": undefined, }, "x": 0, "y": 0, @@ -614,8 +523,10 @@ describe('getSeriesAndDomain', () => { "value": undefined, }, ], + "networkItemTooltipProps": Array [], "requestHeaders": undefined, "responseHeaders": undefined, + "showTooltip": false, "url": "file:///Users/dominiqueclarke/dev/synthetics/examples/todos/app/app.js", "x": 0, }, @@ -625,8 +536,6 @@ describe('getSeriesAndDomain', () => { "config": Object { "colour": "", "isHighlighted": true, - "showTooltip": false, - "tooltipProps": undefined, }, "x": 0, "y": 0, @@ -660,23 +569,21 @@ describe('getSeriesAndDomain', () => { }); it('handles formatting when mime type is not mapped to a specific mime type bucket', () => { - const { series } = getSeriesAndDomain( + const { metadata } = getSeriesAndDomain( networkItemsWithUnknownMimeType, false, mockDateFormatter ); /* verify that raw mime type appears in the tooltip config and that * the colour is mapped to mime type other */ - const contentDownloadingConfigItem = series.find((item: WaterfallDataEntry) => { - const { tooltipProps } = item.config; - if (tooltipProps && typeof tooltipProps.value === 'string') { + const contentDownloadingConfigItem = metadata[0].networkItemTooltipProps.find( + (item: WaterfallTooltipItem) => { return ( - tooltipProps.value.includes('application/x-unknown') && - tooltipProps.colour === colourPalette[MimeType.Other] + item.value.includes('application/x-unknown') && + item.colour === colourPalette[MimeType.Other] ); } - return false; - }); + ); expect(contentDownloadingConfigItem).toBeDefined(); }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.ts index 8ad55e56ee40a..31fac41865d6a 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/data_formatting.ts @@ -20,7 +20,8 @@ import { Metadata, MimeType, MimeTypesMap, - SidebarItem, + WaterfallNetworkItem, + WaterfallTooltipItem, TIMING_ORDER, Timings, } from './types'; @@ -167,10 +168,11 @@ export const getSeriesAndDomain = ( const queryMatcher = getQueryMatcher(query); const filterMatcher = getFilterMatcher(activeFilters); items.forEach((item, index) => { + let showTooltip = true; const mimeTypeColour = getColourForMimeType(item.mimeType); const offsetValue = getValueForOffset(item); let currentOffset = offsetValue - zeroOffset; - metadata.push(formatMetadata({ item, index, requestStart: currentOffset, dateFormatter })); + const requestStart = currentOffset; const isHighlighted = isHighlightedItem(item, queryMatcher, filterMatcher); if (isHighlighted) { totalHighlightedRequests++; @@ -190,14 +192,26 @@ export const getSeriesAndDomain = ( } let timingValueFound = false; + const networkItemTooltipProps = []; TIMING_ORDER.forEach((timing) => { const value = getValue(item.timings, timing); - if (value && value >= 0) { + const colour = timing === Timings.Receive ? mimeTypeColour : colourPalette[timing]; + + if (value !== null && value !== undefined && value >= 0) { timingValueFound = true; - const colour = timing === Timings.Receive ? mimeTypeColour : colourPalette[timing]; const y = currentOffset + value; + const tooltipProps = { + value: getFriendlyTooltipValue({ + value: y - currentOffset, + timing, + mimeType: item.mimeType, + }), + colour, + }; + networkItemTooltipProps.push(tooltipProps); + series.push({ x: index, y0: currentOffset, @@ -206,15 +220,6 @@ export const getSeriesAndDomain = ( id: index, colour, isHighlighted, - showTooltip: true, - tooltipProps: { - value: getFriendlyTooltipValue({ - value: y - currentOffset, - timing, - mimeType: item.mimeType, - }), - colour, - }, }, }); currentOffset = y; @@ -225,8 +230,19 @@ export const getSeriesAndDomain = ( * if total time is not available use 0, set showTooltip to false, * and omit tooltip props */ if (!timingValueFound) { + showTooltip = false; const total = item.timings.total; const hasTotal = total !== -1; + if (hasTotal) { + networkItemTooltipProps.push({ + value: getFriendlyTooltipValue({ + value: total, + timing: Timings.Receive, + mimeType: item.mimeType, + }), + colour: mimeTypeColour, + }); + } series.push({ x: index, y0: hasTotal ? currentOffset : 0, @@ -234,20 +250,20 @@ export const getSeriesAndDomain = ( config: { isHighlighted, colour: hasTotal ? mimeTypeColour : '', - showTooltip: hasTotal, - tooltipProps: hasTotal - ? { - value: getFriendlyTooltipValue({ - value: total, - timing: Timings.Receive, - mimeType: item.mimeType, - }), - colour: mimeTypeColour, - } - : undefined, }, }); } + + metadata.push( + formatMetadata({ + item, + index, + showTooltip, + requestStart, + dateFormatter, + networkItemTooltipProps, + }) + ); }); const yValues = series.map((serie) => serie.y); @@ -282,11 +298,15 @@ const formatMetadata = ({ index, requestStart, dateFormatter, + showTooltip, + networkItemTooltipProps, }: { item: NetworkEvent; index: number; requestStart: number; dateFormatter: DateFormatter; + showTooltip: boolean; + networkItemTooltipProps: WaterfallTooltipItem[]; }) => { const { certificates, @@ -304,6 +324,8 @@ const formatMetadata = ({ return { x: index, url, + networkItemTooltipProps, + showTooltip, requestHeaders: formatHeaders(requestHeaders), responseHeaders: formatHeaders(responseHeaders), certificates: certificates @@ -383,7 +405,7 @@ export const getSidebarItems = ( onlyHighlighted: boolean, query: string, activeFilters: string[] -): SidebarItem[] => { +): WaterfallNetworkItem[] => { const queryMatcher = getQueryMatcher(query); const filterMatcher = getFilterMatcher(activeFilters); const sideBarItems = items.map((item, index) => { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/types.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/types.ts index 78076be872dbb..4496009aaa796 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/common/network_data/types.ts @@ -256,7 +256,7 @@ export const MimeTypesMap: Record = { 'application/json': MimeType.XHR, }; -export type SidebarItem = Pick & { +export type WaterfallNetworkItem = Pick & { isHighlighted: boolean; index: number; offsetIndex: number; @@ -310,27 +310,29 @@ interface PlotProperties { y0: number; } -export interface WaterfallDataSeriesConfigProperties { - tooltipProps?: Record; - showTooltip: boolean; -} - export interface WaterfallMetadataItem { name: string; value?: string; } +export interface WaterfallTooltipItem { + colour: string; + value: string; +} + export interface WaterfallMetadataEntry { x: number; url: string; requestHeaders?: WaterfallMetadataItem[]; responseHeaders?: WaterfallMetadataItem[]; certificates?: WaterfallMetadataItem[]; + networkItemTooltipProps: WaterfallTooltipItem[]; + showTooltip: boolean; details: WaterfallMetadataItem[]; } export type WaterfallDataEntry = PlotProperties & { - config: WaterfallDataSeriesConfigProperties & Record; + config: Record; }; export type WaterfallMetadata = WaterfallMetadataEntry[]; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/README.md b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/README.md index cf8d3b5345eaa..61e5de6249c4f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/README.md +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/README.md @@ -6,7 +6,7 @@ The waterfall chart component aims to be agnostic in it's approach, so that a va ## Requirements for usage -The waterfall chart component asssumes that the consumer is making use of `KibanaReactContext`, and as such things like `useKibana` can be called. +The waterfall chart component asssumes that the consumer is making use of `KibanaReactContext`, and as such things like `useKibana` can be called. Consumers are also expected to be using the `` so that the waterfall chart can apply styled-component styles based on the EUI theme. @@ -24,13 +24,13 @@ This section aims to cover some things that are non-standard. By default the formatting of tooltip values is very basic, but for a waterfall chart there needs to be a great deal of flexibility to represent whatever breakdown you're trying to show. -As such a custom tooltip component is used. This custom component would usually only have access to some basic props that pertain to the values of the hovered bar. The waterfall chart component extends this by making us of a waterfall chart context. +As such a custom tooltip component is used. This custom component would usually only have access to some basic props that pertain to the values of the hovered bar. The waterfall chart component extends this by making us of a waterfall chart context. -The custom tooltip component can use the context to access the full set of chart data, find the relevant items (those with the same `x` value) and call a custom `renderTooltipItem` for each item, `renderTooltipItem` will be passed `item.config.tooltipProps`. Every consumer can choose what they use for their `tooltipProps`. +The custom tooltip component can use the context to access the full set of chart data, find the relevant items (those with the same `x` value) and call a custom `renderTooltipItem` for each item, `renderTooltipItem` will be passed `item.config.tooltipProps`. Every consumer can choose what they use for their `tooltipProps`. Some consumers might need colours, some might need iconography and so on. The waterfall chart doesn't make assumptions, and will render out the React content returned by `renderTooltipItem`. -IMPORTANT: `renderTooltipItem` is provided via context and not as a direct prop due to the fact the custom tooltip component would usually only have access to the props provided directly to it from Elastic Charts. +IMPORTANT: `renderTooltipItem` is provided via context and not as a direct prop due to the fact the custom tooltip component would usually only have access to the props provided directly to it from Elastic Charts. ### Colours @@ -90,7 +90,7 @@ A legend is optional. Pulling all of this together, things look like this (for a specific solution): ``` -const renderSidebarItem: RenderItem = (item, index) => { +const renderSidebarItem: RenderItem = (item, index) => { return ; }; @@ -119,5 +119,3 @@ const renderLegendItem: RenderItem = (item) => { ``` A solution could easily forego a sidebar and legend for a more minimalistic view, e.g. maybe a mini waterfall within a table column. - - diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/context/waterfall_context.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/context/waterfall_context.tsx index 39b8479560cbb..1ccc95f562d5a 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/context/waterfall_context.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/context/waterfall_context.tsx @@ -20,7 +20,7 @@ import { WaterfallMetadata, } from '../../../common/network_data/types'; import { OnSidebarClick, OnElementClick, OnProjectionClick } from '../waterfall_flyout/use_flyout'; -import { SidebarItem } from '../../../common/network_data/types'; +import { WaterfallNetworkItem } from '../../../common/network_data/types'; export type MarkerItems = Array<{ id: @@ -43,7 +43,7 @@ export interface IWaterfallContext { onSidebarClick?: OnSidebarClick; showOnlyHighlightedNetworkRequests: boolean; showCustomMarks: boolean; - sidebarItems?: SidebarItem[]; + sidebarItems?: WaterfallNetworkItem[]; metadata: WaterfallMetadata; renderTooltipItem: ( item: WaterfallDataEntry['config']['tooltipProps'], diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.test.tsx index e6b29cfb9faa7..035eaba33cb90 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.test.tsx @@ -26,14 +26,12 @@ describe('getChunks', () => { }); describe('Component', () => { - const url = 'http://www.elastic.co'; it('renders truncated text and aria label', () => { const { getByText, getByLabelText } = render( @@ -47,13 +45,7 @@ describe('Component', () => { it('renders screen reader only text', () => { const { getByTestId } = render( - + ); const { getByText } = within(getByTestId('middleTruncatedTextSROnly')); @@ -63,17 +55,11 @@ describe('Component', () => { it('renders external link', () => { const { getByText } = render( - + ); const link = getByText('Open resource in new tab').closest('a'); - expect(link).toHaveAttribute('href', url); + expect(link).toHaveAttribute('href', longString); expect(link).toHaveAttribute('target', '_blank'); }); @@ -82,9 +68,8 @@ describe('Component', () => { const { getByTestId } = render( diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.tsx index 7f95069c56f08..701790799dfba 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/middle_truncated_text.tsx @@ -26,7 +26,6 @@ interface Props { index: number; highestIndex: number; ariaLabel: string; - text: string; onClick?: (event: React.MouseEvent) => void; setButtonRef?: (ref: HTMLButtonElement | HTMLAnchorElement | null) => void; url: string; @@ -102,14 +101,13 @@ export const getChunks = (text: string = '') => { export const MiddleTruncatedText = ({ index, ariaLabel, - text: fullText, onClick, setButtonRef, url, highestIndex, }: Props) => { - const secureHttps = fullText.startsWith('https://'); - const text = fullText.replace(/https:\/\/www.|http:\/\/www.|http:\/\/|https:\/\//, ''); + const secureHttps = url.startsWith('https://'); + const text = url.replace(/https:\/\/www.|http:\/\/www.|http:\/\/|https:\/\//, ''); const chunks = useMemo(() => { return getChunks(text); @@ -118,15 +116,17 @@ export const MiddleTruncatedText = ({ return ( - {fullText} + {url} + } data-test-subj="middleTruncatedTextToolTip" - delay="long" position="top" > <> diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx index 2d44735857f40..3f0a80082aec6 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx @@ -39,27 +39,29 @@ const getChartHeight = (data: WaterfallData): number => { }; const CustomTooltip: CustomChartTooltip = (tooltipInfo) => { - const { data, sidebarItems } = useWaterfallContext(); + const { sidebarItems, metadata } = 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 ? ( + if (!sidebarItem) { + return null; + } + const metadataEntry = metadata?.[sidebarItem.index]; + const showTooltip = + metadataEntry?.showTooltip && metadataEntry?.networkItemTooltipProps.length > 1; + return showTooltip ? ( {sidebarItem && ( )} ) : null; - }, [data, sidebarItems, tooltipInfo.header?.value]); + }, [sidebarItems, tooltipInfo.header?.value, metadata]); }; interface Props { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_chart_wrapper.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_chart_wrapper.tsx index 4f155d56db833..ec43aa4508f15 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_chart_wrapper.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_chart_wrapper.tsx @@ -11,7 +11,7 @@ import { EuiHealth } from '@elastic/eui'; import { JourneyStep, NetworkEvent } from '../../../../../../../common/runtime_types'; import { useDateFormat } from '../../../../../../hooks/use_date_format'; import { getSeriesAndDomain, getSidebarItems } from '../../common/network_data/data_formatting'; -import { SidebarItem, LegendItem } from '../../common/network_data/types'; +import { WaterfallNetworkItem, LegendItem } from '../../common/network_data/types'; import { RenderItem, WaterfallDataEntry } from '../../common/network_data/types'; import { useFlyout } from './waterfall_flyout/use_flyout'; import { WaterfallFlyout } from './waterfall_flyout/waterfall_flyout'; @@ -92,7 +92,7 @@ export const WaterfallChartWrapper: React.FC = ({ const highestSideBarIndex = Math.max(...series.map((sr: WaterfallDataEntry) => sr.x)); - const renderSidebarItem: RenderItem = useCallback( + const renderSidebarItem: RenderItem = useCallback( (item) => { return ( { value: 'text/html', }, ], + showTooltip: false, + networkItemTooltipProps: [], }, ]; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.test.tsx index 6e91c47922170..e2d3e8e990066 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.test.tsx @@ -29,6 +29,8 @@ describe('WaterfallFlyout', () => { value: 'text/html', }, ], + showTooltip: false, + networkItemTooltipProps: [], }; const defaultProps = { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.tsx index cb3babffd16b4..7b7c5c9b5a73e 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/waterfall_flyout.tsx @@ -93,13 +93,7 @@ export const WaterfallFlyout = ({

- +

diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.test.tsx index 786978e3647a7..8f7516abe9083 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import 'jest-canvas-mock'; import { fireEvent } from '@testing-library/react'; -import { SidebarItem } from '../../common/network_data/types'; +import { WaterfallNetworkItem } from '../../common/network_data/types'; import { WaterfallSidebarItem } from './waterfall_sidebar_item'; import { SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL } from './translations'; import { getChunks } from './middle_truncated_text'; @@ -19,7 +19,7 @@ describe('waterfall filter', () => { const url = 'http://www.elastic.co/observability/uptime'; const index = 0; const offsetIndex = index + 1; - const item: SidebarItem = { + const item: WaterfallNetworkItem = { url, isHighlighted: true, index, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.tsx index a5d26e33a9b5a..f553c8a81337c 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_sidebar_item.tsx @@ -7,14 +7,14 @@ import React, { RefObject, useMemo, useCallback, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; -import { SidebarItem } from '../../common/network_data/types'; +import { WaterfallNetworkItem } from '../../common/network_data/types'; import { MiddleTruncatedText } from './middle_truncated_text'; import { SideBarItemHighlighter } from './styles'; import { SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL } from './translations'; import { OnSidebarClick } from './waterfall_flyout/use_flyout'; interface SidebarItemProps { - item: SidebarItem; + item: WaterfallNetworkItem; renderFilterScreenReaderText?: boolean; onClick?: OnSidebarClick; highestIndex: number; @@ -44,13 +44,11 @@ export const WaterfallSidebarItem = React.memo(function WaterfallSidebarItem({ return is400 || is500 || isSpecific300; }; - const text = item.url; - const ariaLabel = `${ isHighlighted && renderFilterScreenReaderText ? `${SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL} ` : '' - }${text}`; + }${url}`; return ( ({ }, }, ], + metadata: { + 0: { + networkItemTooltipProps: [ + { + colour: '#000000', + value: 'test-val', + }, + ], + showTooltip: true, + }, + 1: { + networkItemTooltipProps: [ + { + colour: '#010000', + value: 'test-val-missing', + }, + ], + showTooltip: true, + }, + }, renderTooltipItem: (props: any) => (
{props.colour}
@@ -64,7 +84,11 @@ jest.mock('./context/waterfall_context', () => ({ describe('WaterfallTooltipContent', () => { it('renders tooltip', () => { const { getByText, queryByText } = render( - + ); expect(getByText('#000000')).toBeInTheDocument(); expect(getByText('test-val')).toBeInTheDocument(); @@ -75,7 +99,11 @@ describe('WaterfallTooltipContent', () => { it(`doesn't render metric if tooltip props missing`, () => { const { getAllByLabelText, getByText } = render( - + ); const metricElements = getAllByLabelText('tooltip item'); expect(metricElements).toHaveLength(1); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.tsx index b4e4ff040d6c6..e783cf0858867 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.tsx @@ -13,6 +13,7 @@ import { useWaterfallContext } from './context/waterfall_context'; interface Props { text: string; url: string; + index: number; } const StyledText = euiStyled(EuiText)` @@ -23,22 +24,24 @@ const StyledHorizontalRule = euiStyled(EuiHorizontalRule)` background-color: ${(props) => props.theme.eui.euiColorDarkShade}; `; -export const WaterfallTooltipContent: React.FC = ({ text, url }) => { - const { data, renderTooltipItem, sidebarItems } = useWaterfallContext(); +export const WaterfallTooltipContent: React.FC = ({ text, url, index }) => { + const { renderTooltipItem, metadata } = useWaterfallContext(); + // the passed index is base 1, so we need to subtract 1 to get the correct index + const metadataEntry = metadata?.[index - 1]; + const tooltipItems = metadataEntry?.networkItemTooltipProps; + const showTooltip = metadataEntry?.showTooltip; + + if (!tooltipItems || !showTooltip) { + return null; + } - 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)} + {tooltipItems.map((item, idx) => ( + {renderTooltipItem(item)} ))}