From 65cef057df0450ceb54278f89cfef0155c59a961 Mon Sep 17 00:00:00 2001 From: Dominique Belcher Date: Mon, 16 Sep 2024 16:27:49 -0400 Subject: [PATCH 1/3] synthetics - waterfall chart - handle cached resources --- .../common/network_data/data_formatting.ts | 66 ++++++++++++------- .../common/network_data/types.ts | 16 +++-- .../step_waterfall_chart/waterfall/README.md | 12 ++-- .../waterfall/context/waterfall_context.tsx | 4 +- .../waterfall/middle_truncated_text.tsx | 13 ++-- .../waterfall/waterfall_chart_wrapper.tsx | 4 +- .../waterfall_flyout/waterfall_flyout.tsx | 8 +-- .../waterfall/waterfall_sidebar_item.test.tsx | 4 +- .../waterfall/waterfall_tooltip_content.tsx | 22 ++++--- 9 files changed, 83 insertions(+), 66 deletions(-) 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..ce38926d0ba0b 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 @@ -167,10 +167,10 @@ 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 isHighlighted = isHighlightedItem(item, queryMatcher, filterMatcher); if (isHighlighted) { totalHighlightedRequests++; @@ -190,14 +190,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 +218,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 +228,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 +248,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: currentOffset, + dateFormatter, + networkItemTooltipProps, + }) + ); }); const yValues = series.map((serie) => serie.y); @@ -282,11 +296,15 @@ const formatMetadata = ({ index, requestStart, dateFormatter, + showTooltip, + networkItemTooltipProps, }: { item: NetworkEvent; index: number; requestStart: number; dateFormatter: DateFormatter; + showTooltip: boolean; + networkItemTooltipProps?: Array>; }) => { const { certificates, @@ -304,6 +322,8 @@ const formatMetadata = ({ return { x: index, url, + networkItemTooltipProps, + showTooltip, requestHeaders: formatHeaders(requestHeaders), responseHeaders: formatHeaders(responseHeaders), certificates: certificates 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.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..53b04a99807b0 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 @@ -102,14 +102,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 +117,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_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 (

- +

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_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..8313358fe09e9 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: string; } const StyledText = euiStyled(EuiText)` @@ -23,22 +24,23 @@ 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 { data, renderTooltipItem, sidebarItems, metadata } = useWaterfallContext(); + 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)} ))}
From 5dbeebfe05d5814c080a8b3aa8e4c6e7f7b0220f Mon Sep 17 00:00:00 2001 From: Dominique Belcher Date: Mon, 16 Sep 2024 17:13:44 -0400 Subject: [PATCH 2/3] adjust tests --- .../network_data/data_formatting.test.ts | 125 +++--------------- .../common/network_data/data_formatting.ts | 3 +- .../waterfall/middle_truncated_text.test.tsx | 25 +--- .../waterfall_tooltip_content.test.tsx | 32 ++++- .../waterfall/waterfall_tooltip_content.tsx | 3 +- 5 files changed, 55 insertions(+), 133 deletions(-) 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..5df1b945542b2 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 { series, 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 ce38926d0ba0b..973dd5da72d42 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 @@ -171,6 +171,7 @@ export const getSeriesAndDomain = ( const mimeTypeColour = getColourForMimeType(item.mimeType); const offsetValue = getValueForOffset(item); let currentOffset = offsetValue - zeroOffset; + const requestStart = currentOffset; const isHighlighted = isHighlightedItem(item, queryMatcher, filterMatcher); if (isHighlighted) { totalHighlightedRequests++; @@ -257,7 +258,7 @@ export const getSeriesAndDomain = ( item, index, showTooltip, - requestStart: currentOffset, + requestStart, dateFormatter, networkItemTooltipProps, }) 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/waterfall_tooltip_content.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.test.tsx index 9cd85c0b32281..64c0787a1258a 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_tooltip_content.test.tsx @@ -42,6 +42,26 @@ jest.mock('./context/waterfall_context', () => ({ }, }, ], + 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 8313358fe09e9..2966c03d2e145 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 @@ -25,7 +25,8 @@ const StyledHorizontalRule = euiStyled(EuiHorizontalRule)` `; export const WaterfallTooltipContent: React.FC = ({ text, url, index }) => { - const { data, renderTooltipItem, sidebarItems, metadata } = useWaterfallContext(); + const { renderTooltipItem, sidebarItems, 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; From 4e88a5454594036f2e11c5fda96a8b26ba6fb8e4 Mon Sep 17 00:00:00 2001 From: Dominique Belcher Date: Wed, 18 Sep 2024 12:29:41 -0400 Subject: [PATCH 3/3] adjust types --- .../network_data/data_formatting.test.ts | 2 +- .../common/network_data/data_formatting.ts | 7 ++++--- .../waterfall/middle_truncated_text.tsx | 1 - .../waterfall/waterfall_bar_chart.tsx | 20 ++++++++++--------- .../waterfall_flyout/use_flyout.test.tsx | 2 ++ .../waterfall_flyout.test.tsx | 2 ++ .../waterfall/waterfall_sidebar_item.tsx | 10 +++------- .../waterfall/waterfall_tooltip_content.tsx | 4 ++-- 8 files changed, 25 insertions(+), 23 deletions(-) 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 5df1b945542b2..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 @@ -569,7 +569,7 @@ describe('getSeriesAndDomain', () => { }); it('handles formatting when mime type is not mapped to a specific mime type bucket', () => { - const { series, metadata } = getSeriesAndDomain( + const { metadata } = getSeriesAndDomain( networkItemsWithUnknownMimeType, false, mockDateFormatter 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 973dd5da72d42..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'; @@ -305,7 +306,7 @@ const formatMetadata = ({ requestStart: number; dateFormatter: DateFormatter; showTooltip: boolean; - networkItemTooltipProps?: Array>; + networkItemTooltipProps: WaterfallTooltipItem[]; }) => { const { certificates, @@ -404,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/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 53b04a99807b0..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; 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_flyout/use_flyout.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/use_flyout.test.tsx index 584d17e873629..0476f46e11f2a 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/use_flyout.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_flyout/use_flyout.test.tsx @@ -25,6 +25,8 @@ describe('useFlyoutHook', () => { 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_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 ( = ({ text, url, index }) => { - const { renderTooltipItem, sidebarItems, metadata } = useWaterfallContext(); + 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;