mirror of
https://github.com/grafana/grafana.git
synced 2025-02-15 10:03:33 -06:00
* VizPanel: Make it more real * Updates * Progress on query runner and max data points from width * Updated * Update * Tests * Fixed issue with migration * Moving VizPanel * Fixed migration issue due to pluginVersion not being set * Update public/app/features/scenes/querying/SceneQueryRunner.test.ts Co-authored-by: Ivan Ortega Alba <ivanortegaalba@gmail.com> * Some minor review fixes * Added expect Co-authored-by: Ivan Ortega Alba <ivanortegaalba@gmail.com>
161 lines
4.4 KiB
TypeScript
161 lines
4.4 KiB
TypeScript
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<P extends object = any, F extends object = any>(props: PanelRendererProps<P, F>) {
|
|
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<string | undefined>();
|
|
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 <div>Failed to load plugin: {error}</div>;
|
|
}
|
|
|
|
if (!plugin || !plugin.hasPluginId(pluginId)) {
|
|
return <div>Loading plugin panel...</div>;
|
|
}
|
|
|
|
if (!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 (
|
|
<ErrorBoundaryAlert dependencies={[plugin, data]}>
|
|
<PluginContextProvider meta={plugin.meta}>
|
|
<PanelComponent
|
|
id={1}
|
|
data={dataWithOverrides}
|
|
title={title}
|
|
timeRange={dataWithOverrides.timeRange}
|
|
timeZone={timeZone}
|
|
options={optionsWithDefaults!.options}
|
|
fieldConfig={fieldConfig}
|
|
transparent={false}
|
|
width={width}
|
|
height={height}
|
|
renderCounter={0}
|
|
replaceVariables={(str: string) => str}
|
|
onOptionsChange={onOptionsChange}
|
|
onFieldConfigChange={onFieldConfigChange}
|
|
onChangeTimeRange={onChangeTimeRange}
|
|
eventBus={appEvents}
|
|
/>
|
|
</PluginContextProvider>
|
|
</ErrorBoundaryAlert>
|
|
);
|
|
}
|
|
|
|
function useOptionDefaults<P extends object = any, F extends object = any>(
|
|
plugin: PanelPlugin | undefined,
|
|
options: P,
|
|
fieldConfig: FieldConfigSource<F>
|
|
): 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]);
|
|
}
|