diff --git a/packages/grafana-data/src/dataframe/frameComparisons.test.ts b/packages/grafana-data/src/dataframe/frameComparisons.test.ts index a5feae7d51c..98cad7ccfe0 100644 --- a/packages/grafana-data/src/dataframe/frameComparisons.test.ts +++ b/packages/grafana-data/src/dataframe/frameComparisons.test.ts @@ -183,7 +183,7 @@ describe('test comparisons', () => { expect(compareDataFrameStructures(a, b)).toBeFalsy(); }); - it('does not compare deeply', () => { + it('does deep comparison', () => { const a = { ...frameB, fields: [ @@ -218,7 +218,7 @@ describe('test comparisons', () => { ], }; - expect(compareDataFrameStructures(a, b)).toBeFalsy(); + expect(compareDataFrameStructures(a, b)).toBeTruthy(); }); }); }); diff --git a/packages/grafana-data/src/dataframe/frameComparisons.ts b/packages/grafana-data/src/dataframe/frameComparisons.ts index c4c6cb4dae9..d5f1ef99390 100644 --- a/packages/grafana-data/src/dataframe/frameComparisons.ts +++ b/packages/grafana-data/src/dataframe/frameComparisons.ts @@ -1,3 +1,5 @@ +import { isEqual } from 'lodash'; + import { DataFrame } from '../types/dataFrame'; /** @@ -8,10 +10,6 @@ import { DataFrame } from '../types/dataFrame'; * ``` * compareArrayValues(a, b, framesHaveSameStructure); * ``` - * NOTE: this does a shallow check on the FieldConfig properties, when using the query - * editor, this should be sufficient, however if applications are mutating properties - * deep in the FieldConfig this will not recognize a change - * * @beta */ export function compareDataFrameStructures(a: DataFrame, b: DataFrame, skipConfig?: boolean): boolean { @@ -63,11 +61,9 @@ export function compareDataFrameStructures(a: DataFrame, b: DataFrame, skipConfi if (key === 'interval') { continue; } - if (key === 'custom') { - if (!shallowCompare(cfgA[key], cfgB[key])) { - return false; - } - } else if (cfgA[key] !== cfgB[key]) { + + // Deep comparison on all object properties + if (!isEqual(cfgA[key], cfgB[key])) { return false; } } diff --git a/public/app/features/panel/components/PanelRenderer.tsx b/public/app/features/panel/components/PanelRenderer.tsx index 2c0a9a55aee..741beb9d905 100644 --- a/public/app/features/panel/components/PanelRenderer.tsx +++ b/public/app/features/panel/components/PanelRenderer.tsx @@ -1,6 +1,15 @@ import React, { useState, useMemo, useEffect, useRef } from 'react'; +import { usePrevious } from 'react-use'; -import { applyFieldOverrides, FieldConfigSource, getTimeZone, PanelData, PanelPlugin } from '@grafana/data'; +import { + applyFieldOverrides, + FieldConfigSource, + getTimeZone, + PanelData, + PanelPlugin, + compareArrayValues, + compareDataFrameStructures, +} from '@grafana/data'; import { PanelRendererProps } from '@grafana/runtime'; import { ErrorBoundaryAlert, useTheme2 } from '@grafana/ui'; import { appEvents } from 'app/core/core'; @@ -112,18 +121,29 @@ function useFieldOverrides( timeZone: string ): PanelData | undefined { const fieldConfig = defaultOptions?.fieldConfig; - const series = data?.series; const fieldConfigRegistry = plugin?.fieldConfigRegistry; const theme = useTheme2(); const structureRev = useRef(0); + const prevSeries = usePrevious(data?.series); return useMemo(() => { if (!fieldConfigRegistry || !fieldConfig || !data) { return; } - structureRev.current = structureRev.current + 1; + + const series = data?.series; + + if ( + data.structureRev == null && + series && + prevSeries && + !compareArrayValues(series, prevSeries, compareDataFrameStructures) + ) { + structureRev.current++; + } return { + structureRev: structureRev.current, ...data, series: applyFieldOverrides({ data: series, @@ -133,7 +153,6 @@ function useFieldOverrides( theme, timeZone, }), - structureRev: structureRev.current, }; - }, [fieldConfigRegistry, fieldConfig, data, series, timeZone, theme]); + }, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme]); }