import React, { useState, useMemo, useEffect, useRef } from 'react'; import { usePrevious } from 'react-use'; import { applyFieldOverrides, FieldConfigSource, getTimeZone, PanelData, PanelPlugin, compareArrayValues, compareDataFrameStructures, PluginContextProvider, } from '@grafana/data'; import { PanelRendererProps } from '@grafana/runtime'; import { ErrorBoundaryAlert, useTheme2 } from '@grafana/ui'; import { appEvents } from 'app/core/core'; import { getPanelOptionsWithDefaults, OptionDefaults } from '../../dashboard/state/getPanelOptionsWithDefaults'; import { importPanelPlugin, syncGetPanelPlugin } from '../../plugins/importPanelPlugin'; const defaultFieldConfig = { defaults: {}, overrides: [] }; export function PanelRenderer

(props: PanelRendererProps) { const { pluginId, data, timeZone = getTimeZone(), options = {}, width, height, title, onOptionsChange = () => {}, onChangeTimeRange = () => {}, onFieldConfigChange = () => {}, fieldConfig = defaultFieldConfig, } = props; const [plugin, setPlugin] = useState(syncGetPanelPlugin(pluginId)); const [error, setError] = useState(); const optionsWithDefaults = useOptionDefaults(plugin, options, fieldConfig); const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults?.fieldConfig, data, timeZone); useEffect(() => { // If we already have a plugin and it's correct one do nothing if (plugin && plugin.hasPluginId(pluginId)) { return; } // Async load the plugin importPanelPlugin(pluginId) .then((result) => setPlugin(result)) .catch((err: Error) => { setError(err.message); }); }, [pluginId, plugin]); if (error) { return

Failed to load plugin: {error}
; } if (!plugin || !plugin.hasPluginId(pluginId)) { return
Loading plugin panel...
; } if (!plugin.panel) { return
Seems like the plugin you are trying to load does not have a panel component.
; } if (!dataWithOverrides) { return
No panel data
; } const PanelComponent = plugin.panel; return ( str} onOptionsChange={onOptionsChange} onFieldConfigChange={onFieldConfigChange} onChangeTimeRange={onChangeTimeRange} eventBus={appEvents} /> ); } function useOptionDefaults

( plugin: PanelPlugin | undefined, options: P, fieldConfig: FieldConfigSource ): OptionDefaults | undefined { return useMemo(() => { if (!plugin) { return; } return getPanelOptionsWithDefaults({ plugin, currentOptions: options, currentFieldConfig: fieldConfig, isAfterPluginChange: false, }); }, [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) => str, theme, timeZone, }), }; }, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme]); }