2021-09-15 10:35:12 -05:00
|
|
|
import React, { useState, useMemo, useEffect, useRef } from 'react';
|
2021-03-18 15:40:27 -05:00
|
|
|
import { applyFieldOverrides, FieldConfigSource, getTimeZone, PanelData, PanelPlugin } from '@grafana/data';
|
|
|
|
import { PanelRendererProps } from '@grafana/runtime';
|
|
|
|
import { appEvents } from 'app/core/core';
|
|
|
|
import { useAsync } from 'react-use';
|
|
|
|
import { getPanelOptionsWithDefaults, OptionDefaults } from '../dashboard/state/getPanelOptionsWithDefaults';
|
|
|
|
import { importPanelPlugin } from '../plugins/plugin_loader';
|
2021-04-29 05:44:06 -05:00
|
|
|
import { useTheme2 } from '@grafana/ui';
|
2021-09-15 10:35:12 -05:00
|
|
|
const defaultFieldConfig = { defaults: {}, overrides: [] };
|
2021-03-18 15:40:27 -05:00
|
|
|
export function PanelRenderer<P extends object = any, F extends object = any>(props: PanelRendererProps<P, F>) {
|
|
|
|
const {
|
|
|
|
pluginId,
|
|
|
|
data,
|
|
|
|
timeZone = getTimeZone(),
|
|
|
|
options = {},
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
title,
|
2021-05-07 10:09:06 -05:00
|
|
|
onOptionsChange = () => {},
|
2021-03-18 15:40:27 -05:00
|
|
|
onChangeTimeRange = () => {},
|
2021-09-15 10:35:12 -05:00
|
|
|
fieldConfig: externalFieldConfig = defaultFieldConfig,
|
2021-03-18 15:40:27 -05:00
|
|
|
} = props;
|
|
|
|
|
2021-09-15 10:35:12 -05:00
|
|
|
const [localFieldConfig, setFieldConfig] = useState(externalFieldConfig);
|
2021-03-18 15:40:27 -05:00
|
|
|
const { value: plugin, error, loading } = useAsync(() => importPanelPlugin(pluginId), [pluginId]);
|
2021-09-15 10:35:12 -05:00
|
|
|
const optionsWithDefaults = useOptionDefaults(plugin, options, localFieldConfig);
|
2021-05-07 10:09:06 -05:00
|
|
|
const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults, data, timeZone);
|
2021-03-18 15:40:27 -05:00
|
|
|
|
2021-09-15 10:35:12 -05:00
|
|
|
useEffect(() => {
|
|
|
|
setFieldConfig((lfc) => ({ ...lfc, ...externalFieldConfig }));
|
|
|
|
}, [externalFieldConfig]);
|
|
|
|
|
2021-03-18 15:40:27 -05:00
|
|
|
if (error) {
|
|
|
|
return <div>Failed to load plugin: {error.message}</div>;
|
|
|
|
}
|
|
|
|
|
2021-05-18 09:16:26 -05:00
|
|
|
if (pluginIsLoading(loading, plugin, pluginId)) {
|
2021-03-18 15:40:27 -05:00
|
|
|
return <div>Loading plugin panel...</div>;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!plugin || !plugin.panel) {
|
|
|
|
return <div>Seems like the plugin you are trying to load does not have a panel component.</div>;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dataWithOverrides) {
|
|
|
|
return <div>No panel data</div>;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PanelComponent = plugin.panel;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<PanelComponent
|
|
|
|
id={1}
|
|
|
|
data={dataWithOverrides}
|
|
|
|
title={title}
|
|
|
|
timeRange={dataWithOverrides.timeRange}
|
|
|
|
timeZone={timeZone}
|
2021-05-07 10:09:06 -05:00
|
|
|
options={optionsWithDefaults!.options}
|
2021-09-15 10:35:12 -05:00
|
|
|
fieldConfig={localFieldConfig}
|
2021-03-18 15:40:27 -05:00
|
|
|
transparent={false}
|
|
|
|
width={width}
|
|
|
|
height={height}
|
|
|
|
renderCounter={0}
|
|
|
|
replaceVariables={(str: string) => str}
|
|
|
|
onOptionsChange={onOptionsChange}
|
|
|
|
onFieldConfigChange={setFieldConfig}
|
|
|
|
onChangeTimeRange={onChangeTimeRange}
|
|
|
|
eventBus={appEvents}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-18 09:16:26 -05:00
|
|
|
function useOptionDefaults<P extends object = any, F extends object = any>(
|
2021-03-18 15:40:27 -05:00
|
|
|
plugin: PanelPlugin | undefined,
|
|
|
|
options: P,
|
|
|
|
fieldConfig: FieldConfigSource<F>
|
2021-05-18 09:16:26 -05:00
|
|
|
): OptionDefaults | undefined {
|
2021-03-18 15:40:27 -05:00
|
|
|
return useMemo(() => {
|
|
|
|
if (!plugin) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return getPanelOptionsWithDefaults({
|
|
|
|
plugin,
|
|
|
|
currentOptions: options,
|
|
|
|
currentFieldConfig: fieldConfig,
|
|
|
|
isAfterPluginChange: false,
|
|
|
|
});
|
|
|
|
}, [plugin, fieldConfig, options]);
|
2021-05-18 09:16:26 -05:00
|
|
|
}
|
2021-03-18 15:40:27 -05:00
|
|
|
|
2021-05-18 09:16:26 -05:00
|
|
|
function useFieldOverrides(
|
2021-03-18 15:40:27 -05:00
|
|
|
plugin: PanelPlugin | undefined,
|
|
|
|
defaultOptions: OptionDefaults | undefined,
|
|
|
|
data: PanelData | undefined,
|
|
|
|
timeZone: string
|
2021-05-18 09:16:26 -05:00
|
|
|
): PanelData | undefined {
|
2021-03-18 15:40:27 -05:00
|
|
|
const fieldConfig = defaultOptions?.fieldConfig;
|
|
|
|
const series = data?.series;
|
|
|
|
const fieldConfigRegistry = plugin?.fieldConfigRegistry;
|
2021-04-29 05:44:06 -05:00
|
|
|
const theme = useTheme2();
|
2021-09-15 10:35:12 -05:00
|
|
|
const structureRev = useRef(0);
|
2021-03-18 15:40:27 -05:00
|
|
|
|
|
|
|
return useMemo(() => {
|
|
|
|
if (!fieldConfigRegistry || !fieldConfig || !data) {
|
|
|
|
return;
|
|
|
|
}
|
2021-09-15 10:35:12 -05:00
|
|
|
structureRev.current = structureRev.current + 1;
|
2021-03-18 15:40:27 -05:00
|
|
|
|
|
|
|
return {
|
|
|
|
...data,
|
|
|
|
series: applyFieldOverrides({
|
|
|
|
data: series,
|
|
|
|
fieldConfig,
|
|
|
|
fieldConfigRegistry,
|
|
|
|
replaceVariables: (str: string) => str,
|
2021-04-29 05:44:06 -05:00
|
|
|
theme,
|
2021-03-18 15:40:27 -05:00
|
|
|
timeZone,
|
|
|
|
}),
|
2021-09-15 10:35:12 -05:00
|
|
|
structureRev: structureRev.current,
|
2021-03-18 15:40:27 -05:00
|
|
|
};
|
2021-04-29 05:44:06 -05:00
|
|
|
}, [fieldConfigRegistry, fieldConfig, data, series, timeZone, theme]);
|
2021-05-18 09:16:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
function pluginIsLoading(loading: boolean, plugin: PanelPlugin<any, any> | undefined, pluginId: string) {
|
|
|
|
return loading || plugin?.meta.id !== pluginId;
|
|
|
|
}
|