From 230a39c093eb128b4a48ac359d98b36fd8ee76f9 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Tue, 1 Aug 2023 14:40:28 -0600 Subject: [PATCH 01/13] measure main visualization data and render times --- .../workspace_panel/workspace_panel.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index f4767124afb81..ae40dcafc0d4f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -192,8 +192,11 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ dataViews, }; + const initialRenderTime = useRef(performance.now()); + const onRender$ = useCallback(() => { if (renderDeps.current) { + // console.log('onRender$', performance.now() - initialRenderTime.current); const datasourceEvents = Object.values(renderDeps.current.datasourceMap).reduce( (acc, datasource) => { if (!renderDeps.current!.datasourceStates[datasource.id]) return []; @@ -232,6 +235,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const onData$ = useCallback( (_data: unknown, adapters?: Partial) => { if (renderDeps.current) { + // console.log('onData$', performance.now() - initialRenderTime.current); const [defaultLayerId] = Object.keys(renderDeps.current.datasourceLayers); const datasource = Object.values(renderDeps.current.datasourceMap)[0]; const datasourceState = Object.values(renderDeps.current.datasourceStates)[0].state; @@ -687,6 +691,12 @@ export const VisualizationWrapper = ({ // Used for reporting const { isRenderComplete, hasDynamicError, setIsRenderComplete, setDynamicError, nodeRef } = useReportingState(errors); + + const onRenderHandler = useCallback(() => { + setIsRenderComplete(true); + onRender$(); + }, [setIsRenderComplete, onRender$]); + const searchContext: ExecutionContextSearch = useMemo( () => ({ query: context.query, @@ -782,10 +792,7 @@ export const VisualizationWrapper = ({ onEvent={onEvent} hasCompatibleActions={hasCompatibleActions} onData$={onData$} - onRender$={() => { - setIsRenderComplete(true); - onRender$(); - }} + onRender$={onRenderHandler} inspectorAdapters={lensInspector.adapters} executionContext={executionContext} renderMode="edit" From 52f5b7f5adedc3e05b9f6a8d88a9cb8267b8b893 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Tue, 1 Aug 2023 14:52:56 -0600 Subject: [PATCH 02/13] improve main visualization metrics --- .../editor_frame/workspace_panel/workspace_panel.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index ae40dcafc0d4f..c56addbd3fb8e 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -193,10 +193,14 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ }; const initialRenderTime = useRef(performance.now()); + const dataReceivedTime = useRef(0); const onRender$ = useCallback(() => { if (renderDeps.current) { - // console.log('onRender$', performance.now() - initialRenderTime.current); + // console.log( + // 'visualization took to render after data received', + // performance.now() - dataReceivedTime.current + // ); const datasourceEvents = Object.values(renderDeps.current.datasourceMap).reduce( (acc, datasource) => { if (!renderDeps.current!.datasourceStates[datasource.id]) return []; @@ -235,7 +239,9 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const onData$ = useCallback( (_data: unknown, adapters?: Partial) => { if (renderDeps.current) { - // console.log('onData$', performance.now() - initialRenderTime.current); + dataReceivedTime.current = performance.now(); + // console.log('data took to arrive', dataReceivedTime.current - initialRenderTime.current); + const [defaultLayerId] = Object.keys(renderDeps.current.datasourceLayers); const datasource = Object.values(renderDeps.current.datasourceMap)[0]; const datasourceState = Object.values(renderDeps.current.datasourceStates)[0].state; From 478bc14e9cb4773e1424ada83a7832491fcb9cc4 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Wed, 2 Aug 2023 10:13:31 -0600 Subject: [PATCH 03/13] measure suggestion loading time --- .../editor_frame/suggestion_panel.scss | 4 + .../editor_frame/suggestion_panel.tsx | 152 +++++++++++------- 2 files changed, 102 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss index 1619eea882b25..f7701f5a8da59 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss @@ -100,3 +100,7 @@ align-items: center; justify-content: center; } + +.lnsSuggestionPanel__loadingState { + height: $lnsSuggestionHeight; +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 36d8b4104e64c..48bcf7907b0c8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -20,6 +20,7 @@ import { EuiButtonEmpty, EuiAccordion, EuiText, + EuiProgress, } from '@elastic/eui'; import { IconType } from '@elastic/eui/src/components/icon/icon'; import { Ast, fromExpression, toExpression } from '@kbn/interpreter'; @@ -30,6 +31,9 @@ import { ReactExpressionRendererProps, ReactExpressionRendererType, } from '@kbn/expressions-plugin/public'; +import fastIsEqual from 'fast-deep-equal'; +import { useWhatChanged } from '@simbathesailor/use-what-changed'; +import { css } from '@emotion/react'; import { DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../utils'; import { Datasource, @@ -64,7 +68,6 @@ import { selectFrameDatasourceAPI, } from '../../state_management'; import { filterAndSortUserMessages } from '../../app_plugin/get_application_user_messages'; - const MAX_SUGGESTIONS_DISPLAYED = 5; const LOCAL_STORAGE_SUGGESTIONS_PANEL = 'LENS_SUGGESTIONS_PANEL_HIDDEN'; @@ -108,11 +111,13 @@ const PreviewRenderer = ({ ExpressionRendererComponent, expression, hasError, + onRender, }: { withLabel: boolean; expression: string | null | undefined; ExpressionRendererComponent: ReactExpressionRendererType; hasError: boolean; + onRender: () => void; }) => { const onErrorMessage = (
@@ -143,6 +148,7 @@ const PreviewRenderer = ({ padding="s" renderMode="preview" expression={expression} + onRender$={onRender} debounce={2000} renderError={() => { return onErrorMessage; @@ -159,6 +165,7 @@ const SuggestionPreview = ({ selected, onSelect, showTitleAsLabel, + onRender, }: { onSelect: () => void; preview: { @@ -170,6 +177,7 @@ const SuggestionPreview = ({ ExpressionRenderer: ReactExpressionRendererType; selected: boolean; showTitleAsLabel?: boolean; + onRender: () => void; }) => { return ( @@ -194,6 +202,7 @@ const SuggestionPreview = ({ expression={preview.expression && toExpression(preview.expression)} withLabel={Boolean(showTitleAsLabel)} hasError={Boolean(preview.error)} + onRender={onRender} /> ) : ( @@ -358,20 +367,31 @@ export function SuggestionPanel({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [existsStagedPreview]); - if (!activeDatasourceId) { - return null; - } + const startTime = useRef(0); + const suggestionsRendered = useRef(0); + const totalSuggestions = suggestions.length + 1; - if (suggestions.length === 0) { - return null; - } + const onSuggestionRender = useCallback(() => { + suggestionsRendered.current++; + if (suggestionsRendered.current === totalSuggestions) { + console.log('suggestions finished rendering', performance.now() - startTime.current); + } + }, [totalSuggestions]); - function rollbackToCurrentVisualization() { + const rollbackToCurrentVisualization = useCallback(() => { if (lastSelectedSuggestion !== -1) { setLastSelectedSuggestion(-1); dispatchLens(rollbackSuggestion()); dispatchLens(applyChanges()); } + }, [dispatchLens, lastSelectedSuggestion]); + + if (!activeDatasourceId) { + return null; + } + + if (suggestions.length === 0) { + return null; } const renderApplyChangesPrompt = () => ( @@ -400,53 +420,73 @@ export function SuggestionPanel({ ); - const renderSuggestionsUI = () => ( - <> - {currentVisualization.activeId && !hideSuggestions && ( - - )} - {!hideSuggestions && - suggestions.map((suggestion, index) => { - return ( - { - if (lastSelectedSuggestion === index) { - rollbackToCurrentVisualization(); - } else { - setLastSelectedSuggestion(index); - switchToSuggestion(dispatchLens, suggestion, { applyImmediately: true }); - } - }} - selected={index === lastSelectedSuggestion} - /> - ); - })} - + const renderSuggestionsLoadingState = () => ( + + + ); + const renderSuggestionsUI = () => { + suggestionsRendered.current = 0; + startTime.current = performance.now(); + return ( + <> + {currentVisualization.activeId && !hideSuggestions && ( + + )} + {!hideSuggestions && + suggestions.map((suggestion, index) => { + return ( + { + if (lastSelectedSuggestion === index) { + rollbackToCurrentVisualization(); + } else { + setLastSelectedSuggestion(index); + switchToSuggestion(dispatchLens, suggestion, { applyImmediately: true }); + } + }} + selected={index === lastSelectedSuggestion} + onRender={onSuggestionRender} + /> + ); + })} + + ); + }; + return (
- {changesApplied ? renderSuggestionsUI() : renderApplyChangesPrompt()} + {changesApplied + ? activeData + ? renderSuggestionsUI() + : renderSuggestionsLoadingState() + : renderApplyChangesPrompt()}
From b7d903e3b0b8a7af77ccd86ba2ebfe17104f456c Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 07:31:30 -0600 Subject: [PATCH 04/13] improve render measurement --- .../expression_xy/public/components/xy_chart.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 0c19cc72d691c..ba7159896b72d 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -309,7 +309,10 @@ export function XYChart({ const onRenderChange = useCallback( (isRendered: boolean = true) => { if (isRendered) { - renderComplete(); + // temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + window.requestAnimationFrame(() => { + renderComplete(); + }); } }, [renderComplete] From d7095c2c35db1e76eb0193c75fb5105ca6735751 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 08:28:06 -0600 Subject: [PATCH 05/13] wait a tick to report render --- .../expression_gauge/public/components/gauge_component.tsx | 5 ++++- .../public/components/heatmap_component.tsx | 5 ++++- .../expression_metric/public/components/metric_vis.tsx | 5 ++++- .../public/components/partition_vis_component.tsx | 7 +++++-- .../public/components/tagcloud_component.tsx | 5 ++++- .../expression_xy/public/components/xy_chart.tsx | 2 +- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx index affbff3ea9b2c..4684a160881b8 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx @@ -246,7 +246,10 @@ export const GaugeComponent: FC = memo( const onRenderChange = useCallback( (isRendered: boolean = true) => { if (isRendered) { - renderComplete(); + // this requestAnimationFrame call is a temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + window.requestAnimationFrame(() => { + renderComplete(); + }); } }, [renderComplete] diff --git a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx index ab70211361e46..95856d1bae485 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/components/heatmap_component.tsx @@ -196,7 +196,10 @@ export const HeatmapComponent: FC = memo( const onRenderChange = useCallback( (isRendered: boolean = true) => { if (isRendered) { - renderComplete(); + // this requestAnimationFrame call is a temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + window.requestAnimationFrame(() => { + renderComplete(); + }); } }, [renderComplete] diff --git a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx index f0aa3c3e1dede..cb352fe883152 100644 --- a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx @@ -134,7 +134,10 @@ export const MetricVis = ({ const onRenderChange = useCallback( (isRendered) => { if (isRendered) { - renderComplete(); + // this requestAnimationFrame call is a temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + window.requestAnimationFrame(() => { + renderComplete(); + }); } }, [renderComplete] diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx index a321aaf181e2d..c151741158ac1 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx @@ -176,8 +176,11 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => { const onRenderChange = useCallback( (isRendered: boolean = true) => { if (isRendered) { - props.renderComplete(); - setChartIsLoaded(true); + // this requestAnimationFrame call is a temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + window.requestAnimationFrame(() => { + props.renderComplete(); + setChartIsLoaded(true); + }); } }, [props] diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx index 7fe65370693d5..adfc3df81f97f 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx @@ -145,7 +145,10 @@ export const TagCloudChart = ({ const onRenderChange = useCallback( (isRendered) => { if (isRendered) { - renderComplete(); + // this requestAnimationFrame call is a temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + window.requestAnimationFrame(() => { + renderComplete(); + }); } }, [renderComplete] diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index ba7159896b72d..e1ad4fa19d1c0 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -309,7 +309,7 @@ export function XYChart({ const onRenderChange = useCallback( (isRendered: boolean = true) => { if (isRendered) { - // temporary fix for https://github.com/elastic/elastic-charts/issues/2124 + // this requestAnimationFrame call is a temporary fix for https://github.com/elastic/elastic-charts/issues/2124 window.requestAnimationFrame(() => { renderComplete(); }); From 77b1065c9d52566e1f22406f43d79dfa64358191 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 09:06:57 -0600 Subject: [PATCH 06/13] update messaging --- .../editor_frame_service/editor_frame/suggestion_panel.tsx | 7 ++++--- .../editor_frame/workspace_panel/workspace_panel.tsx | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 48bcf7907b0c8..c522a829586a8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -31,8 +31,6 @@ import { ReactExpressionRendererProps, ReactExpressionRendererType, } from '@kbn/expressions-plugin/public'; -import fastIsEqual from 'fast-deep-equal'; -import { useWhatChanged } from '@simbathesailor/use-what-changed'; import { css } from '@emotion/react'; import { DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../utils'; import { @@ -374,7 +372,10 @@ export function SuggestionPanel({ const onSuggestionRender = useCallback(() => { suggestionsRendered.current++; if (suggestionsRendered.current === totalSuggestions) { - console.log('suggestions finished rendering', performance.now() - startTime.current); + // console.log( + // 'suggestions took to fetch data and render', + // performance.now() - startTime.current + // ); } }, [totalSuggestions]); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index c56addbd3fb8e..c895d20c7d67b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -192,6 +192,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ dataViews, }; + // NOTE: initialRenderTime is only set once when the component mounts const initialRenderTime = useRef(performance.now()); const dataReceivedTime = useRef(0); @@ -240,6 +241,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ (_data: unknown, adapters?: Partial) => { if (renderDeps.current) { dataReceivedTime.current = performance.now(); + // NOTE: this metric is only valid for an initial editor load of a pre-existing visualization // console.log('data took to arrive', dataReceivedTime.current - initialRenderTime.current); const [defaultLayerId] = Object.keys(renderDeps.current.datasourceLayers); From aeafebe7a84ea111cc775b7ce2aeafdf68e566a5 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 10:04:00 -0600 Subject: [PATCH 07/13] remove suggestion loading improvement --- .../editor_frame/suggestion_panel.scss | 4 -- .../editor_frame/suggestion_panel.tsx | 40 +++++-------------- 2 files changed, 10 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss index f7701f5a8da59..c8e560d86eeb2 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss @@ -99,8 +99,4 @@ flex-direction: column; align-items: center; justify-content: center; -} - -.lnsSuggestionPanel__loadingState { - height: $lnsSuggestionHeight; } \ No newline at end of file diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index c522a829586a8..3310523a6ec6d 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -20,7 +20,6 @@ import { EuiButtonEmpty, EuiAccordion, EuiText, - EuiProgress, } from '@elastic/eui'; import { IconType } from '@elastic/eui/src/components/icon/icon'; import { Ast, fromExpression, toExpression } from '@kbn/interpreter'; @@ -31,7 +30,6 @@ import { ReactExpressionRendererProps, ReactExpressionRendererType, } from '@kbn/expressions-plugin/public'; -import { css } from '@emotion/react'; import { DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../utils'; import { Datasource, @@ -366,18 +364,18 @@ export function SuggestionPanel({ }, [existsStagedPreview]); const startTime = useRef(0); - const suggestionsRendered = useRef(0); + const suggestionsRendered = useRef([]); const totalSuggestions = suggestions.length + 1; - const onSuggestionRender = useCallback(() => { - suggestionsRendered.current++; - if (suggestionsRendered.current === totalSuggestions) { + const onSuggestionRender = useCallback((suggestionIndex: number) => { + suggestionsRendered.current[suggestionIndex] = true; + if (suggestionsRendered.current.every(Boolean)) { // console.log( - // 'suggestions took to fetch data and render', + // 'time to fetch data and perform initial render for all suggestions', // performance.now() - startTime.current // ); } - }, [totalSuggestions]); + }, []); const rollbackToCurrentVisualization = useCallback(() => { if (lastSelectedSuggestion !== -1) { @@ -421,22 +419,8 @@ export function SuggestionPanel({ ); - const renderSuggestionsLoadingState = () => ( - - - - ); - const renderSuggestionsUI = () => { - suggestionsRendered.current = 0; + suggestionsRendered.current = new Array(totalSuggestions).fill(false); startTime.current = performance.now(); return ( <> @@ -457,7 +441,7 @@ export function SuggestionPanel({ onSelect={rollbackToCurrentVisualization} selected={lastSelectedSuggestion === -1} showTitleAsLabel - onRender={onSuggestionRender} + onRender={() => onSuggestionRender(0)} /> )} {!hideSuggestions && @@ -480,7 +464,7 @@ export function SuggestionPanel({ } }} selected={index === lastSelectedSuggestion} - onRender={onSuggestionRender} + onRender={() => onSuggestionRender(index + 1)} /> ); })} @@ -535,11 +519,7 @@ export function SuggestionPanel({ role="list" tabIndex={0} > - {changesApplied - ? activeData - ? renderSuggestionsUI() - : renderSuggestionsLoadingState() - : renderApplyChangesPrompt()} + {changesApplied ? renderSuggestionsUI() : renderApplyChangesPrompt()} From bfb92f4dcbd22aee2263f6bb2dc11783584bdb5c Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 10:29:38 -0600 Subject: [PATCH 08/13] only report the metrics once --- .../editor_frame/suggestion_panel.tsx | 4 ++- .../workspace_panel/workspace_panel.tsx | 33 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 3310523a6ec6d..11f50252b993e 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -364,12 +364,14 @@ export function SuggestionPanel({ }, [existsStagedPreview]); const startTime = useRef(0); + const initialRenderComplete = useRef(false); const suggestionsRendered = useRef([]); const totalSuggestions = suggestions.length + 1; const onSuggestionRender = useCallback((suggestionIndex: number) => { suggestionsRendered.current[suggestionIndex] = true; - if (suggestionsRendered.current.every(Boolean)) { + if (initialRenderComplete.current === false && suggestionsRendered.current.every(Boolean)) { + initialRenderComplete.current = true; // console.log( // 'time to fetch data and perform initial render for all suggestions', // performance.now() - startTime.current diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index c895d20c7d67b..4d1f7d375bbe8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -170,7 +170,10 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ errors: [], }); - const initialRenderComplete = useRef(); + const initialVisualizationRenderComplete = useRef(false); + + // NOTE: This does not reflect the actual visualization render + const initialWorkspaceRenderComplete = useRef(); const renderDeps = useRef<{ datasourceMap: DatasourceMap; @@ -198,10 +201,14 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const onRender$ = useCallback(() => { if (renderDeps.current) { - // console.log( - // 'visualization took to render after data received', - // performance.now() - dataReceivedTime.current - // ); + if (!initialVisualizationRenderComplete.current) { + initialVisualizationRenderComplete.current = true; + // NOTE: this metric is only repored for an initial editor load of a pre-existing visualization + // console.log( + // 'initial visualization took to render after data received', + // performance.now() - dataReceivedTime.current + // ); + } const datasourceEvents = Object.values(renderDeps.current.datasourceMap).reduce( (acc, datasource) => { if (!renderDeps.current!.datasourceStates[datasource.id]) return []; @@ -241,8 +248,13 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ (_data: unknown, adapters?: Partial) => { if (renderDeps.current) { dataReceivedTime.current = performance.now(); - // NOTE: this metric is only valid for an initial editor load of a pre-existing visualization - // console.log('data took to arrive', dataReceivedTime.current - initialRenderTime.current); + if (!initialVisualizationRenderComplete.current) { + // NOTE: this metric is only repored for an initial editor load of a pre-existing visualization + // console.log( + // 'initial data took to arrive', + // dataReceivedTime.current - initialRenderTime.current + // ); + } const [defaultLayerId] = Object.keys(renderDeps.current.datasourceLayers); const datasource = Object.values(renderDeps.current.datasourceMap)[0]; @@ -288,7 +300,8 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ [addUserMessages, dispatchLens, plugins.data.search] ); - const shouldApplyExpression = autoApplyEnabled || !initialRenderComplete.current || triggerApply; + const shouldApplyExpression = + autoApplyEnabled || !initialWorkspaceRenderComplete.current || triggerApply; const activeVisualization = visualization.activeId ? visualizationMap[visualization.activeId] : null; @@ -401,9 +414,9 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ // null signals an empty workspace which should count as an initial render if ( (expressionExists || localState.expressionToRender === null) && - !initialRenderComplete.current + !initialWorkspaceRenderComplete.current ) { - initialRenderComplete.current = true; + initialWorkspaceRenderComplete.current = true; } }, [expressionExists, localState.expressionToRender]); From 7bfd784234b806550482d7b19e17721b6163b49b Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 10:48:05 -0600 Subject: [PATCH 09/13] fix type error --- .../workspace_panel/workspace_panel.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 4d1f7d375bbe8..0293e34f3097f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -138,6 +138,10 @@ export const WorkspacePanel = React.memo(function WorkspacePanel(props: Workspac ); }); +const log = (...messages: Array) => { + // console.log(...messages); +}; + // Exported for testing purposes only. export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ framePublicAPI, @@ -204,10 +208,10 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ if (!initialVisualizationRenderComplete.current) { initialVisualizationRenderComplete.current = true; // NOTE: this metric is only repored for an initial editor load of a pre-existing visualization - // console.log( - // 'initial visualization took to render after data received', - // performance.now() - dataReceivedTime.current - // ); + log( + 'initial visualization took to render after data received', + performance.now() - dataReceivedTime.current + ); } const datasourceEvents = Object.values(renderDeps.current.datasourceMap).reduce( (acc, datasource) => { @@ -250,10 +254,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ dataReceivedTime.current = performance.now(); if (!initialVisualizationRenderComplete.current) { // NOTE: this metric is only repored for an initial editor load of a pre-existing visualization - // console.log( - // 'initial data took to arrive', - // dataReceivedTime.current - initialRenderTime.current - // ); + log('initial data took to arrive', dataReceivedTime.current - initialRenderTime.current); } const [defaultLayerId] = Object.keys(renderDeps.current.datasourceLayers); From 84c0ec8e8896dcf89ab494136b593847bcd6e815 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 11:56:36 -0500 Subject: [PATCH 10/13] Update workspace_panel.tsx --- .../editor_frame/workspace_panel/workspace_panel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 0293e34f3097f..13a6ef2a28b44 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -207,7 +207,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ if (renderDeps.current) { if (!initialVisualizationRenderComplete.current) { initialVisualizationRenderComplete.current = true; - // NOTE: this metric is only repored for an initial editor load of a pre-existing visualization + // NOTE: this metric is only reported for an initial editor load of a pre-existing visualization log( 'initial visualization took to render after data received', performance.now() - dataReceivedTime.current @@ -253,7 +253,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ if (renderDeps.current) { dataReceivedTime.current = performance.now(); if (!initialVisualizationRenderComplete.current) { - // NOTE: this metric is only repored for an initial editor load of a pre-existing visualization + // NOTE: this metric is only reported for an initial editor load of a pre-existing visualization log('initial data took to arrive', dataReceivedTime.current - initialRenderTime.current); } From bff8f62101be978c718be4465f65085a3e0322fa Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 11:14:22 -0600 Subject: [PATCH 11/13] make visualization metric work when vis created from empty workspace --- .../workspace_panel/workspace_panel.tsx | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 13a6ef2a28b44..3f92236c99e5d 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -200,8 +200,8 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ }; // NOTE: initialRenderTime is only set once when the component mounts - const initialRenderTime = useRef(performance.now()); - const dataReceivedTime = useRef(0); + const visualizationRenderStartTime = useRef(NaN); + const dataReceivedTime = useRef(NaN); const onRender$ = useCallback(() => { if (renderDeps.current) { @@ -254,7 +254,10 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ dataReceivedTime.current = performance.now(); if (!initialVisualizationRenderComplete.current) { // NOTE: this metric is only reported for an initial editor load of a pre-existing visualization - log('initial data took to arrive', dataReceivedTime.current - initialRenderTime.current); + log( + 'initial data took to arrive', + dataReceivedTime.current - visualizationRenderStartTime.current + ); } const [defaultLayerId] = Object.keys(renderDeps.current.datasourceLayers); @@ -585,7 +588,6 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ return ( { + visualizationRenderStartTime.current = performance.now(); + }} /> ); }; @@ -682,7 +686,6 @@ function useReportingState(errors: UserMessage[]): { export const VisualizationWrapper = ({ expression, - framePublicAPI, lensInspector, onEvent, hasCompatibleActions, @@ -691,12 +694,11 @@ export const VisualizationWrapper = ({ errors, ExpressionRendererComponent, core, - activeDatasourceId, onRender$, onData$, + onComponentRendered, }: { expression: string | null | undefined; - framePublicAPI: FramePublicAPI; lensInspector: LensInspector; onEvent: (event: ExpressionRendererEvent) => void; hasCompatibleActions: (event: ExpressionRendererEvent) => Promise; @@ -705,10 +707,15 @@ export const VisualizationWrapper = ({ errors: UserMessage[]; ExpressionRendererComponent: ReactExpressionRendererType; core: CoreStart; - activeDatasourceId: string | null; onRender$: () => void; onData$: (data: unknown, adapters?: Partial) => void; + onComponentRendered: () => void; }) => { + useEffect(() => { + onComponentRendered(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const context = useLensSelector(selectExecutionContext); // Used for reporting const { isRenderComplete, hasDynamicError, setIsRenderComplete, setDynamicError, nodeRef } = From f19dd13f16859e4dc98062db9872dc5af8aa0279 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Thu, 3 Aug 2023 15:42:05 -0600 Subject: [PATCH 12/13] fix failing test --- .../public/components/metric_vis.test.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.test.tsx b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.test.tsx index 209608c260eca..6e96c2ab06cdf 100644 --- a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.test.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.test.tsx @@ -971,6 +971,11 @@ describe('MetricVisComponent', function () { }); it('should report render complete', () => { + jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => { + cb(0); + return 0; + }); + const renderCompleteSpy = jest.fn(); const component = shallow( { From 23ee3ad88613b653d16102b7e621df2ed9196959 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Mon, 7 Aug 2023 11:12:09 -0500 Subject: [PATCH 13/13] Update suggestion_panel.scss --- .../editor_frame_service/editor_frame/suggestion_panel.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss index c8e560d86eeb2..1619eea882b25 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss @@ -99,4 +99,4 @@ flex-direction: column; align-items: center; justify-content: center; -} \ No newline at end of file +}