diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index ef30090aa89..9794ab66cf6 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -49,6 +49,7 @@ "moment-timezone": "0.5.38", "ol": "7.1.0", "papaparse": "5.3.2", + "react-use": "17.4.0", "regenerator-runtime": "0.13.10", "rxjs": "7.5.7", "tinycolor2": "1.4.2", diff --git a/packages/grafana-data/src/field/fieldOverrides.ts b/packages/grafana-data/src/field/fieldOverrides.ts index 441635e69b8..6b2fbf31195 100644 --- a/packages/grafana-data/src/field/fieldOverrides.ts +++ b/packages/grafana-data/src/field/fieldOverrides.ts @@ -1,7 +1,11 @@ import { isNumber, set, unset, get, cloneDeep } from 'lodash'; +import { useMemo, useRef } from 'react'; +import usePrevious from 'react-use/lib/usePrevious'; -import { guessFieldTypeForField } from '../dataframe'; +import { compareArrayValues, compareDataFrameStructures, guessFieldTypeForField } from '../dataframe'; import { getTimeField } from '../dataframe/processDataFrame'; +import { PanelPlugin } from '../panel/PanelPlugin'; +import { GrafanaTheme2 } from '../themes'; import { asHexString } from '../themes/colorManipulator'; import { fieldMatchers, reduceField, ReducerID } from '../transformations'; import { @@ -16,11 +20,13 @@ import { FieldColorModeId, FieldConfig, FieldConfigPropertyItem, + FieldConfigSource, FieldOverrideContext, FieldType, InterpolateFunction, LinkModel, NumericRange, + PanelData, ScopedVars, TimeZone, ValueLinkConfig, @@ -503,3 +509,49 @@ export function applyRawFieldOverrides(data: DataFrame[]): DataFrame[] { return newData; } + +/** + * @internal + */ +export function useFieldOverrides( + plugin: PanelPlugin | undefined, + fieldConfig: FieldConfigSource | undefined, + data: PanelData | undefined, + timeZone: string, + theme: GrafanaTheme2, + replace: InterpolateFunction +): PanelData | undefined { + const fieldConfigRegistry = plugin?.fieldConfigRegistry; + const structureRev = useRef(0); + const prevSeries = usePrevious(data?.series); + + return useMemo(() => { + if (!fieldConfigRegistry || !fieldConfig || !data) { + return; + } + + 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, + fieldConfig, + fieldConfigRegistry, + replaceVariables: replace, + theme, + timeZone, + }), + }; + }, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme, replace]); +} diff --git a/packages/grafana-data/src/field/index.ts b/packages/grafana-data/src/field/index.ts index 9bac21ccd8e..8ae807d42bc 100644 --- a/packages/grafana-data/src/field/index.ts +++ b/packages/grafana-data/src/field/index.ts @@ -12,7 +12,7 @@ export { } from './fieldColor'; export { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry'; export { sortThresholds, getActiveThreshold } from './thresholds'; -export { applyFieldOverrides, validateFieldConfig, applyRawFieldOverrides } from './fieldOverrides'; +export { applyFieldOverrides, validateFieldConfig, applyRawFieldOverrides, useFieldOverrides } from './fieldOverrides'; export { getFieldDisplayValuesProxy } from './getFieldDisplayValuesProxy'; export { getFieldDisplayName, getFrameDisplayName } from './fieldState'; export { getScaleCalculator, getFieldConfigWithMinMax } from './scale'; diff --git a/public/app/features/panel/components/PanelRenderer.tsx b/public/app/features/panel/components/PanelRenderer.tsx index dacaf743639..bb221909c12 100644 --- a/public/app/features/panel/components/PanelRenderer.tsx +++ b/public/app/features/panel/components/PanelRenderer.tsx @@ -1,18 +1,13 @@ -import React, { useState, useMemo, useEffect, useRef } from 'react'; -import { usePrevious } from 'react-use'; +import React, { useState, useMemo, useEffect } from 'react'; import { - applyFieldOverrides, FieldConfigSource, getTimeZone, - PanelData, PanelPlugin, - compareArrayValues, - compareDataFrameStructures, PluginContextProvider, - ScopedVars, getPanelOptionsWithDefaults, OptionDefaults, + useFieldOverrides, } from '@grafana/data'; import { getTemplateSrv, PanelRendererProps } from '@grafana/runtime'; import { ErrorBoundaryAlert, useTheme2 } from '@grafana/ui'; @@ -37,10 +32,12 @@ export function PanelRenderer

(pr fieldConfig = defaultFieldConfig, } = props; + const theme = useTheme2(); + const replace = useMemo(() => getTemplateSrv().replace, []); const [plugin, setPlugin] = useState(syncGetPanelPlugin(pluginId)); const [error, setError] = useState(); const optionsWithDefaults = useOptionDefaults(plugin, options, fieldConfig); - const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults?.fieldConfig, data, timeZone); + const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults?.fieldConfig, data, timeZone, theme, replace); useEffect(() => { // If we already have a plugin and it's correct one do nothing @@ -118,47 +115,3 @@ function useOptionDefaults

( }); }, [plugin, fieldConfig, options]); } - -export function useFieldOverrides( - plugin: PanelPlugin | undefined, - fieldConfig: FieldConfigSource | undefined, - data: PanelData | undefined, - timeZone: string -): PanelData | undefined { - const fieldConfigRegistry = plugin?.fieldConfigRegistry; - const theme = useTheme2(); - const structureRev = useRef(0); - const prevSeries = usePrevious(data?.series); - - return useMemo(() => { - if (!fieldConfigRegistry || !fieldConfig || !data) { - return; - } - - 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, - fieldConfig, - fieldConfigRegistry, - replaceVariables: (str: string, scopedVars?: ScopedVars) => { - return getTemplateSrv().replace(str, scopedVars); - }, - theme, - timeZone, - }), - }; - }, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme]); -} diff --git a/public/app/features/scenes/components/VizPanel/VizPanelRenderer.tsx b/public/app/features/scenes/components/VizPanel/VizPanelRenderer.tsx index 8877c8f0d22..9b418f3926a 100644 --- a/public/app/features/scenes/components/VizPanel/VizPanelRenderer.tsx +++ b/public/app/features/scenes/components/VizPanel/VizPanelRenderer.tsx @@ -1,10 +1,10 @@ -import React, { RefCallback } from 'react'; +import React, { RefCallback, useMemo } from 'react'; import { useMeasure } from 'react-use'; -import { PluginContextProvider } from '@grafana/data'; -import { PanelChrome, ErrorBoundaryAlert } from '@grafana/ui'; +import { PluginContextProvider, useFieldOverrides } from '@grafana/data'; +import { getTemplateSrv } from '@grafana/runtime'; +import { PanelChrome, ErrorBoundaryAlert, useTheme2 } from '@grafana/ui'; import { appEvents } from 'app/core/core'; -import { useFieldOverrides } from 'app/features/panel/components/PanelRenderer'; import { sceneGraph } from '../../core/sceneGraph'; import { SceneComponentProps } from '../../core/types'; @@ -16,6 +16,8 @@ import { VizPanel } from './VizPanel'; export function VizPanelRenderer({ model }: SceneComponentProps) { const { title, options, fieldConfig, pluginId, pluginLoadError, $data, placement } = model.useState(); + const theme = useTheme2(); + const replace = useMemo(() => getTemplateSrv().replace, []); const [ref, { width, height }] = useMeasure(); const plugin = model.getPlugin(); const { data } = sceneGraph.getData(model).useState(); @@ -31,7 +33,7 @@ export function VizPanelRenderer({ model }: SceneComponentProps) { // Not sure we need to subscribe to this state const timeZone = sceneGraph.getTimeRange(model).state.timeZone; - const dataWithOverrides = useFieldOverrides(plugin, fieldConfig, data, timeZone); + const dataWithOverrides = useFieldOverrides(plugin, fieldConfig, data, timeZone, theme, replace); if (pluginLoadError) { return

Failed to load plugin: {pluginLoadError}
; diff --git a/yarn.lock b/yarn.lock index 2a18d45d394..f4e61441540 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4850,6 +4850,7 @@ __metadata: react: 17.0.2 react-dom: 17.0.2 react-test-renderer: 17.0.2 + react-use: 17.4.0 regenerator-runtime: 0.13.10 rimraf: 3.0.2 rollup: 2.79.1