import React, { useState, useMemo, useEffect, useRef } from 'react';
import { useAsync } from 'react-use';
import { applyFieldOverrides, FieldConfigSource, getTimeZone, PanelData, PanelPlugin } 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 } from '../../plugins/importPanelPlugin';
const defaultFieldConfig = { defaults: {}, overrides: [] };
export function PanelRenderer
(props: PanelRendererProps
) {
const {
pluginId,
data,
timeZone = getTimeZone(),
options = {},
width,
height,
title,
onOptionsChange = () => {},
onChangeTimeRange = () => {},
fieldConfig: externalFieldConfig = defaultFieldConfig,
} = props;
const [localFieldConfig, setFieldConfig] = useState(externalFieldConfig);
const { value: plugin, error, loading } = useAsync(() => importPanelPlugin(pluginId), [pluginId]);
const optionsWithDefaults = useOptionDefaults(plugin, options, localFieldConfig);
const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults, data, timeZone);
useEffect(() => {
setFieldConfig((lfc) => ({ ...lfc, ...externalFieldConfig }));
}, [externalFieldConfig]);
if (error) {
return
Failed to load plugin: {error.message}
;
}
if (pluginIsLoading(loading, plugin, pluginId)) {
return Loading plugin panel...
;
}
if (!plugin || !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={setFieldConfig}
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]);
}
function useFieldOverrides(
plugin: PanelPlugin | undefined,
defaultOptions: OptionDefaults | undefined,
data: PanelData | undefined,
timeZone: string
): PanelData | undefined {
const fieldConfig = defaultOptions?.fieldConfig;
const series = data?.series;
const fieldConfigRegistry = plugin?.fieldConfigRegistry;
const theme = useTheme2();
const structureRev = useRef(0);
return useMemo(() => {
if (!fieldConfigRegistry || !fieldConfig || !data) {
return;
}
structureRev.current = structureRev.current + 1;
return {
...data,
series: applyFieldOverrides({
data: series,
fieldConfig,
fieldConfigRegistry,
replaceVariables: (str: string) => str,
theme,
timeZone,
}),
structureRev: structureRev.current,
};
}, [fieldConfigRegistry, fieldConfig, data, series, timeZone, theme]);
}
function pluginIsLoading(loading: boolean, plugin: PanelPlugin | undefined, pluginId: string) {
return loading || plugin?.meta.id !== pluginId;
}