grafana/public/app/features/panel/PanelRenderer.tsx
Marcus Andersson 2aa1a051f0
Alerting: visualizing data when creating/editing alerting rule. (#34191)
* VizWrapper to handle some state

* alertingqueryrunner first edition

* added so we always set name and uid when changing datasource.

* wip.

* wip

* added support for canceling requests.

* util for getting time ranges for expression queries

* remove logs, store data in state

* merge from run branch

* incremental commit

* viz working

* added structure for marble testing.

* paddings and move viz picker

* less height for viz, less width on rows

* change so the expression buttons doesnt submit form.

* fixed run button.

* replaced mocks with implementation that will set default query + expression.

* merge with run queries

* fixed so we set a datasource name for the default expression rule.

* improving expression guard.

* lots of styling fixes for viz

* adding placeholder for relative time range.

* fixed story.

* added basic structure to handle open/close of time range picker.

* removed section from TimeOptions since it isn't used any where.

* adding mapper and tests

* move relativetimepicker to its own dir

* added some simple tests.

* changed test.

* use relativetimerangeinput

* redo state management

* refactored the tests.

* replace timerange with relativetimerange

* wip

* wip

* did some refactoring.

* refactored time option formatting.

* added proper formatting and display of time range.

* add relative time description, slight refactor of height

* fixed incorrect import.

* added validator and changed formatting.

* removed unused dep.

* reverted back to internal function.

* fixed display of relative time range picker.

* fixed failing tests.

* fixed parsing issue.

* fixed position of time range picker.

* some more refactorings.

* fixed validation of really big values.

* added another test.

* restored the step2 check.

* fixed merge issue.

* Update packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>

* reverted change.

* fixed merge conflict.

* fixed todo.

* sort some paddings

* replace theme with theme2

Co-authored-by: Peter Holmberg <peter.hlmbrg@gmail.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
2021-05-18 16:16:26 +02:00

121 lines
3.5 KiB
TypeScript

import React, { useState, useMemo } from 'react';
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';
import { useTheme2 } from '@grafana/ui';
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 = () => {},
fieldConfig: config = { defaults: {}, overrides: [] },
} = props;
const [fieldConfig, setFieldConfig] = useState<FieldConfigSource>(config);
const { value: plugin, error, loading } = useAsync(() => importPanelPlugin(pluginId), [pluginId]);
const optionsWithDefaults = useOptionDefaults(plugin, options, fieldConfig);
const dataWithOverrides = useFieldOverrides(plugin, optionsWithDefaults, data, timeZone);
if (error) {
return <div>Failed to load plugin: {error.message}</div>;
}
if (pluginIsLoading(loading, plugin, pluginId)) {
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}
options={optionsWithDefaults!.options}
fieldConfig={fieldConfig}
transparent={false}
width={width}
height={height}
renderCounter={0}
replaceVariables={(str: string) => str}
onOptionsChange={onOptionsChange}
onFieldConfigChange={setFieldConfig}
onChangeTimeRange={onChangeTimeRange}
eventBus={appEvents}
/>
);
}
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]);
}
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();
return useMemo(() => {
if (!fieldConfigRegistry || !fieldConfig || !data) {
return;
}
return {
...data,
series: applyFieldOverrides({
data: series,
fieldConfig,
fieldConfigRegistry,
replaceVariables: (str: string) => str,
theme,
timeZone,
}),
};
}, [fieldConfigRegistry, fieldConfig, data, series, timeZone, theme]);
}
function pluginIsLoading(loading: boolean, plugin: PanelPlugin<any, any> | undefined, pluginId: string) {
return loading || plugin?.meta.id !== pluginId;
}