2018-11-07 13:36:35 +01:00
|
|
|
import React, { PureComponent } from 'react';
|
2018-01-02 14:52:30 +01:00
|
|
|
import config from 'app/core/config';
|
2018-11-20 16:00:19 +01:00
|
|
|
import classNames from 'classnames';
|
2019-03-22 13:45:09 -07:00
|
|
|
import get from 'lodash/get';
|
2018-11-06 18:14:29 +01:00
|
|
|
|
2018-10-14 12:41:09 +02:00
|
|
|
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
|
2018-07-09 18:17:51 +02:00
|
|
|
import { importPluginModule } from 'app/features/plugins/plugin_loader';
|
2018-11-06 18:14:29 +01:00
|
|
|
|
2019-01-24 09:23:48 +01:00
|
|
|
import { AddPanelWidget } from '../components/AddPanelWidget';
|
2018-11-13 07:54:02 +01:00
|
|
|
import { getPanelPluginNotFound } from './PanelPluginNotFound';
|
2019-01-31 08:37:15 +01:00
|
|
|
import { DashboardRow } from '../components/DashboardRow';
|
2018-06-19 14:51:57 +02:00
|
|
|
import { PanelChrome } from './PanelChrome';
|
2019-01-14 15:17:48 +01:00
|
|
|
import { PanelEditor } from '../panel_editor/PanelEditor';
|
2017-10-09 17:52:25 +02:00
|
|
|
|
2019-01-31 08:56:17 +01:00
|
|
|
import { PanelModel, DashboardModel } from '../state';
|
2018-11-13 07:54:02 +01:00
|
|
|
import { PanelPlugin } from 'app/types';
|
2018-12-18 17:20:09 +01:00
|
|
|
import { PanelResizer } from './PanelResizer';
|
2019-03-13 13:11:49 -07:00
|
|
|
import { PanelTypeChangedHook } from '@grafana/ui';
|
2018-11-06 18:14:29 +01:00
|
|
|
|
2018-07-05 13:10:39 -07:00
|
|
|
export interface Props {
|
2017-10-10 09:34:14 +02:00
|
|
|
panel: PanelModel;
|
2018-01-03 13:33:54 +01:00
|
|
|
dashboard: DashboardModel;
|
2018-11-07 16:03:33 +01:00
|
|
|
isEditing: boolean;
|
|
|
|
|
isFullscreen: boolean;
|
2017-10-09 17:52:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-05 13:10:39 -07:00
|
|
|
export interface State {
|
2018-11-06 18:14:29 +01:00
|
|
|
plugin: PanelPlugin;
|
2018-11-15 09:46:21 +01:00
|
|
|
angularPanel: AngularComponent;
|
2018-07-05 13:10:39 -07:00
|
|
|
}
|
|
|
|
|
|
2018-10-31 13:41:50 +01:00
|
|
|
export class DashboardPanel extends PureComponent<Props, State> {
|
2018-11-15 09:46:21 +01:00
|
|
|
element: HTMLElement;
|
2018-01-02 14:52:30 +01:00
|
|
|
specialPanels = {};
|
2017-10-09 17:52:25 +02:00
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
2018-07-09 13:24:15 -07:00
|
|
|
|
|
|
|
|
this.state = {
|
2018-11-06 18:14:29 +01:00
|
|
|
plugin: null,
|
2018-11-15 09:46:21 +01:00
|
|
|
angularPanel: null,
|
2018-07-09 13:24:15 -07:00
|
|
|
};
|
2018-01-02 14:52:30 +01:00
|
|
|
|
|
|
|
|
this.specialPanels['row'] = this.renderRow.bind(this);
|
|
|
|
|
this.specialPanels['add-panel'] = this.renderAddPanel.bind(this);
|
2017-10-09 17:52:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-12-13 11:35:07 +01:00
|
|
|
isSpecial(pluginId: string) {
|
|
|
|
|
return this.specialPanels[pluginId];
|
2018-01-02 14:52:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renderRow() {
|
2018-01-03 13:33:54 +01:00
|
|
|
return <DashboardRow panel={this.props.panel} dashboard={this.props.dashboard} />;
|
2018-01-02 14:52:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renderAddPanel() {
|
2019-01-24 09:23:48 +01:00
|
|
|
return <AddPanelWidget panel={this.props.panel} dashboard={this.props.dashboard} />;
|
2018-01-02 14:52:30 +01:00
|
|
|
}
|
|
|
|
|
|
2018-07-09 13:24:15 -07:00
|
|
|
onPluginTypeChanged = (plugin: PanelPlugin) => {
|
2018-12-13 11:35:07 +01:00
|
|
|
this.loadPlugin(plugin.id);
|
2018-08-25 12:22:50 -07:00
|
|
|
};
|
|
|
|
|
|
2018-12-13 11:35:07 +01:00
|
|
|
async loadPlugin(pluginId: string) {
|
|
|
|
|
if (this.isSpecial(pluginId)) {
|
2018-07-09 18:17:51 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-06 18:14:29 +01:00
|
|
|
const { panel } = this.props;
|
|
|
|
|
|
2018-07-09 18:17:51 +02:00
|
|
|
// handle plugin loading & changing of plugin type
|
2018-12-13 11:35:07 +01:00
|
|
|
if (!this.state.plugin || this.state.plugin.id !== pluginId) {
|
2019-02-11 11:47:12 +01:00
|
|
|
let plugin = config.panels[pluginId] || getPanelPluginNotFound(pluginId);
|
2018-12-13 11:35:07 +01:00
|
|
|
|
|
|
|
|
// remember if this is from an angular panel
|
|
|
|
|
const fromAngularPanel = this.state.angularPanel != null;
|
|
|
|
|
|
|
|
|
|
// unmount angular panel
|
|
|
|
|
this.cleanUpAngularPanel();
|
2018-07-09 18:17:51 +02:00
|
|
|
|
2019-02-17 07:03:42 +01:00
|
|
|
if (!plugin.exports) {
|
2019-02-11 11:47:12 +01:00
|
|
|
try {
|
|
|
|
|
plugin.exports = await importPluginModule(plugin.module);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
plugin = getPanelPluginNotFound(pluginId);
|
|
|
|
|
}
|
2019-02-17 07:03:42 +01:00
|
|
|
}
|
2019-02-11 11:47:12 +01:00
|
|
|
|
2019-02-17 07:03:42 +01:00
|
|
|
if (panel.type !== pluginId) {
|
2019-02-21 13:43:36 +01:00
|
|
|
if (fromAngularPanel) {
|
|
|
|
|
// for angular panels only we need to remove all events and let angular panels do some cleanup
|
|
|
|
|
panel.destroy();
|
|
|
|
|
|
|
|
|
|
this.props.panel.changeType(pluginId);
|
|
|
|
|
} else {
|
2019-03-13 13:11:49 -07:00
|
|
|
let hook: PanelTypeChangedHook | null = null;
|
|
|
|
|
if (plugin.exports.reactPanel) {
|
2019-03-22 13:12:35 -07:00
|
|
|
hook = plugin.exports.reactPanel.onPanelTypeChanged;
|
2019-03-13 13:11:49 -07:00
|
|
|
}
|
|
|
|
|
panel.changeType(pluginId, hook);
|
2019-02-21 13:43:36 +01:00
|
|
|
}
|
2019-03-22 10:22:25 -07:00
|
|
|
} else if (plugin.exports && plugin.exports.reactPanel && panel.options) {
|
2019-03-22 13:45:09 -07:00
|
|
|
const pluginVersion = get(plugin, 'info.version') || config.buildInfo.version;
|
2019-03-22 13:12:35 -07:00
|
|
|
const hook = plugin.exports.reactPanel.onPanelMigration;
|
2019-03-22 13:45:09 -07:00
|
|
|
if (hook && panel.pluginVersion !== pluginVersion) {
|
|
|
|
|
panel.options = hook(panel.options, panel.pluginVersion);
|
|
|
|
|
panel.pluginVersion = pluginVersion;
|
2019-03-22 00:14:50 -07:00
|
|
|
}
|
2018-12-13 11:35:07 +01:00
|
|
|
}
|
2019-02-17 07:03:42 +01:00
|
|
|
this.setState({ plugin, angularPanel: null });
|
2019-03-12 16:35:22 -07:00
|
|
|
}
|
2018-07-09 18:17:51 +02:00
|
|
|
}
|
2019-03-12 16:35:22 -07:00
|
|
|
|
2018-07-09 18:17:51 +02:00
|
|
|
componentDidMount() {
|
2018-12-13 11:35:07 +01:00
|
|
|
this.loadPlugin(this.props.panel.type);
|
2018-07-09 18:17:51 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-12 16:35:22 -07:00
|
|
|
componentDidUpdate() {
|
2018-11-15 09:46:21 +01:00
|
|
|
if (!this.element || this.state.angularPanel) {
|
2018-06-19 14:51:57 +02:00
|
|
|
return;
|
2017-10-16 09:55:55 +02:00
|
|
|
}
|
2017-10-13 17:01:38 +02:00
|
|
|
|
2018-09-10 15:42:36 +02:00
|
|
|
const loader = getAngularLoader();
|
|
|
|
|
const template = '<plugin-component type="panel" class="panel-height-helper"></plugin-component>';
|
|
|
|
|
const scopeProps = { panel: this.props.panel, dashboard: this.props.dashboard };
|
2018-11-15 09:46:21 +01:00
|
|
|
const angularPanel = loader.load(this.element, scopeProps, template);
|
|
|
|
|
|
|
|
|
|
this.setState({ angularPanel });
|
2017-10-09 17:52:25 +02:00
|
|
|
}
|
2018-06-19 08:42:41 +02:00
|
|
|
|
2018-12-14 10:47:18 +01:00
|
|
|
cleanUpAngularPanel() {
|
2018-11-15 09:46:21 +01:00
|
|
|
if (this.state.angularPanel) {
|
|
|
|
|
this.state.angularPanel.destroy();
|
2018-12-14 10:47:18 +01:00
|
|
|
this.element = null;
|
2018-06-19 08:42:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-01-03 13:03:26 +01:00
|
|
|
|
2018-08-25 12:22:50 -07:00
|
|
|
componentWillUnmount() {
|
2018-12-14 10:47:18 +01:00
|
|
|
this.cleanUpAngularPanel();
|
2018-08-25 12:22:50 -07:00
|
|
|
}
|
|
|
|
|
|
2018-11-14 13:31:40 +01:00
|
|
|
onMouseEnter = () => {
|
|
|
|
|
this.props.dashboard.setPanelFocus(this.props.panel.id);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onMouseLeave = () => {
|
|
|
|
|
this.props.dashboard.setPanelFocus(0);
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-09 18:17:51 +02:00
|
|
|
renderReactPanel() {
|
2019-02-17 08:11:57 +01:00
|
|
|
const { dashboard, panel, isFullscreen } = this.props;
|
2018-11-06 18:14:29 +01:00
|
|
|
const { plugin } = this.state;
|
|
|
|
|
|
2019-02-17 08:11:57 +01:00
|
|
|
return <PanelChrome plugin={plugin} panel={panel} dashboard={dashboard} isFullscreen={isFullscreen} />;
|
2018-11-15 09:46:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renderAngularPanel() {
|
|
|
|
|
return <div ref={element => (this.element = element)} className="panel-height-helper" />;
|
2018-07-09 18:17:51 +02:00
|
|
|
}
|
2018-07-05 13:10:39 -07:00
|
|
|
|
2018-07-09 18:17:51 +02:00
|
|
|
render() {
|
2018-11-20 16:00:19 +01:00
|
|
|
const { panel, dashboard, isFullscreen, isEditing } = this.props;
|
2018-11-15 09:46:21 +01:00
|
|
|
const { plugin, angularPanel } = this.state;
|
2018-11-06 18:14:29 +01:00
|
|
|
|
2018-12-13 11:35:07 +01:00
|
|
|
if (this.isSpecial(panel.type)) {
|
2018-11-06 18:14:29 +01:00
|
|
|
return this.specialPanels[panel.type]();
|
2018-06-19 14:51:57 +02:00
|
|
|
}
|
2018-06-19 08:42:41 +02:00
|
|
|
|
2018-11-06 18:14:29 +01:00
|
|
|
// if we have not loaded plugin exports yet, wait
|
|
|
|
|
if (!plugin || !plugin.exports) {
|
2018-06-19 14:51:57 +02:00
|
|
|
return null;
|
|
|
|
|
}
|
2018-06-19 08:42:41 +02:00
|
|
|
|
2018-11-20 16:00:19 +01:00
|
|
|
const containerClass = classNames({ 'panel-editor-container': isEditing, 'panel-height-helper': !isEditing });
|
|
|
|
|
const panelWrapperClass = classNames({
|
|
|
|
|
'panel-wrapper': true,
|
|
|
|
|
'panel-wrapper--edit': isEditing,
|
|
|
|
|
'panel-wrapper--view': isFullscreen && !isEditing,
|
|
|
|
|
});
|
2018-06-19 14:51:57 +02:00
|
|
|
|
2018-11-14 13:31:40 +01:00
|
|
|
return (
|
2018-11-15 09:46:21 +01:00
|
|
|
<div className={containerClass}>
|
2018-12-18 17:20:09 +01:00
|
|
|
<PanelResizer
|
2019-01-02 10:54:57 +01:00
|
|
|
isEditing={isEditing}
|
2018-12-18 17:20:09 +01:00
|
|
|
panel={panel}
|
2019-01-02 10:54:57 +01:00
|
|
|
render={styles => (
|
2018-12-18 17:20:09 +01:00
|
|
|
<div
|
|
|
|
|
className={panelWrapperClass}
|
|
|
|
|
onMouseEnter={this.onMouseEnter}
|
|
|
|
|
onMouseLeave={this.onMouseLeave}
|
2019-01-02 10:54:57 +01:00
|
|
|
style={styles}
|
2018-12-18 17:20:09 +01:00
|
|
|
>
|
2019-02-18 11:41:14 +01:00
|
|
|
{plugin.exports.reactPanel && this.renderReactPanel()}
|
2018-12-18 17:20:09 +01:00
|
|
|
{plugin.exports.PanelCtrl && this.renderAngularPanel()}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2018-11-15 09:46:21 +01:00
|
|
|
{panel.isEditing && (
|
|
|
|
|
<PanelEditor
|
|
|
|
|
panel={panel}
|
|
|
|
|
plugin={plugin}
|
|
|
|
|
dashboard={dashboard}
|
|
|
|
|
angularPanel={angularPanel}
|
|
|
|
|
onTypeChanged={this.onPluginTypeChanged}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2018-11-14 13:31:40 +01:00
|
|
|
);
|
2018-06-19 08:42:41 +02:00
|
|
|
}
|
|
|
|
|
}
|