From 3bb2ee9de6652f8013922b85fdfcc9b59181eac4 Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Wed, 8 Sep 2021 15:02:44 +0200 Subject: [PATCH] Plugins: added the possibility to manage field config state outside of the panel renderer. (#38944) --- .../src/components/PanelRenderer.tsx | 3 +- public/app/features/panel/PanelRenderer.tsx | 37 +++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/packages/grafana-runtime/src/components/PanelRenderer.tsx b/packages/grafana-runtime/src/components/PanelRenderer.tsx index 1d178836483..23c140408a4 100644 --- a/packages/grafana-runtime/src/components/PanelRenderer.tsx +++ b/packages/grafana-runtime/src/components/PanelRenderer.tsx @@ -13,10 +13,11 @@ export interface PanelRendererProps

; options?: P; onOptionsChange?: (options: P) => void; onChangeTimeRange?: (timeRange: AbsoluteTimeRange) => void; + fieldConfig?: FieldConfigSource; + onFieldConfigChange?: (config: FieldConfigSource) => void; timeZone?: string; width: number; height: number; diff --git a/public/app/features/panel/PanelRenderer.tsx b/public/app/features/panel/PanelRenderer.tsx index 03d4c978c0a..14288099cbe 100644 --- a/public/app/features/panel/PanelRenderer.tsx +++ b/public/app/features/panel/PanelRenderer.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo } from 'react'; +import React, { useState, useMemo, useRef, useCallback } from 'react'; import { applyFieldOverrides, FieldConfigSource, getTimeZone, PanelData, PanelPlugin } from '@grafana/data'; import { PanelRendererProps } from '@grafana/runtime'; import { appEvents } from 'app/core/core'; @@ -18,10 +18,9 @@ export function PanelRenderer

(pr title, onOptionsChange = () => {}, onChangeTimeRange = () => {}, - fieldConfig: config = { defaults: {}, overrides: [] }, } = props; - const [fieldConfig, setFieldConfig] = useState(config); + const [fieldConfig, setFieldConfig] = useFieldConfigState(props); const { value: plugin, error, loading } = useAsync(() => importPanelPlugin(pluginId), [pluginId]); const optionsWithDefaults = useOptionDefaults(plugin, options, fieldConfig); const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults, data, timeZone); @@ -118,3 +117,35 @@ function useFieldOverrides( function pluginIsLoading(loading: boolean, plugin: PanelPlugin | undefined, pluginId: string) { return loading || plugin?.meta.id !== pluginId; } + +function useFieldConfigState(props: PanelRendererProps): [FieldConfigSource, (config: FieldConfigSource) => void] { + const { + onFieldConfigChange, + fieldConfig = { + defaults: {}, + overrides: [], + }, + } = props; + + // First render will detect if the PanelRenderer will manage the + // field config state internally or externally by the consuming + // component. This will also prevent the way of managing state to + // change during the components life cycle. + const isManagedInternally = useRef(() => !!onFieldConfigChange); + const [internalConfig, setInternalConfig] = useState(fieldConfig); + + const setExternalConfig = useCallback( + (config: FieldConfigSource) => { + if (!onFieldConfigChange) { + return; + } + onFieldConfigChange(config); + }, + [onFieldConfigChange] + ); + + if (isManagedInternally) { + return [internalConfig, setInternalConfig]; + } + return [fieldConfig, setExternalConfig]; +}