grafana/public/app/features/scenes/components/VizPanel/VizPanel.tsx
Dominik Prokop c3c4a57c79
grafana/data: Move getPanelOptionsWithDefaults from core (#60813)
* grafana/data: Move getPanelOptionsWithDefaults from core

* Add internal comments
2022-12-29 05:48:22 -08:00

134 lines
4.0 KiB
TypeScript

import { DeepPartial } from '@reduxjs/toolkit';
import React from 'react';
import {
AbsoluteTimeRange,
FieldConfigSource,
PanelModel,
PanelPlugin,
toUtc,
getPanelOptionsWithDefaults,
} from '@grafana/data';
import { config } from '@grafana/runtime';
import { Field, Input } from '@grafana/ui';
import { importPanelPlugin, syncGetPanelPlugin } from 'app/features/plugins/importPanelPlugin';
import { SceneObjectBase } from '../../core/SceneObjectBase';
import { sceneGraph } from '../../core/sceneGraph';
import { SceneComponentProps, SceneLayoutChildState } from '../../core/types';
import { VariableDependencyConfig } from '../../variables/VariableDependencyConfig';
import { VizPanelRenderer } from './VizPanelRenderer';
export interface VizPanelState<TOptions = {}, TFieldConfig = {}> extends SceneLayoutChildState {
title: string;
pluginId: string;
options: DeepPartial<TOptions>;
fieldConfig: FieldConfigSource<DeepPartial<TFieldConfig>>;
pluginVersion?: string;
// internal state
pluginLoadError?: string;
}
export class VizPanel<TOptions = {}, TFieldConfig = {}> extends SceneObjectBase<VizPanelState<TOptions, TFieldConfig>> {
public static Component = VizPanelRenderer;
public static Editor = VizPanelEditor;
protected _variableDependency = new VariableDependencyConfig(this, { statePaths: ['options', 'title'] });
// Not part of state as this is not serializable
private _plugin?: PanelPlugin;
public constructor(state: Partial<VizPanelState<TOptions, TFieldConfig>>) {
super({
options: {},
fieldConfig: { defaults: {}, overrides: [] },
title: 'Title',
pluginId: 'timeseries',
...state,
});
}
public activate() {
super.activate();
const plugin = syncGetPanelPlugin(this.state.pluginId);
if (plugin) {
this.pluginLoaded(plugin);
} else {
importPanelPlugin(this.state.pluginId)
.then((result) => this.pluginLoaded(result))
.catch((err: Error) => {
this.setState({ pluginLoadError: err.message });
});
}
}
private pluginLoaded(plugin: PanelPlugin) {
const { options, fieldConfig, title, pluginId, pluginVersion } = this.state;
const panel: PanelModel = { title, options, fieldConfig, id: 1, type: pluginId, pluginVersion: pluginVersion };
const currentVersion = this.getPluginVersion(plugin);
if (plugin.onPanelMigration) {
if (currentVersion !== this.state.pluginVersion) {
// These migration handlers also mutate panel.fieldConfig to migrate fieldConfig
panel.options = plugin.onPanelMigration(panel);
}
}
const withDefaults = getPanelOptionsWithDefaults({
plugin,
currentOptions: panel.options,
currentFieldConfig: panel.fieldConfig,
isAfterPluginChange: false,
});
this._plugin = plugin;
this.setState({
options: withDefaults.options,
fieldConfig: withDefaults.fieldConfig,
pluginVersion: currentVersion,
});
}
private getPluginVersion(plugin: PanelPlugin): string {
return plugin && plugin.meta.info.version ? plugin.meta.info.version : config.buildInfo.version;
}
public getPlugin(): PanelPlugin | undefined {
return this._plugin;
}
public onChangeTimeRange = (timeRange: AbsoluteTimeRange) => {
const sceneTimeRange = sceneGraph.getTimeRange(this);
sceneTimeRange.onTimeRangeChange({
raw: {
from: toUtc(timeRange.from),
to: toUtc(timeRange.to),
},
from: toUtc(timeRange.from),
to: toUtc(timeRange.to),
});
};
public onOptionsChange = (options: TOptions) => {
this.setState({ options });
};
public onFieldConfigChange = (fieldConfig: FieldConfigSource<TFieldConfig>) => {
this.setState({ fieldConfig });
};
}
function VizPanelEditor({ model }: SceneComponentProps<VizPanel>) {
const { title } = model.useState();
return (
<Field label="Title">
<Input defaultValue={title} onBlur={(evt) => model.setState({ title: evt.currentTarget.value })} />
</Field>
);
}