Files
grafana/public/app/features/dashboard/dashgrid/DashboardPanel.tsx

221 lines
5.5 KiB
TypeScript
Raw Normal View History

// Libraries
import React, { PureComponent } from 'react';
import classNames from 'classnames';
2018-11-06 18:14:29 +01:00
// Utils & Services
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
import { importPanelPlugin } from 'app/features/plugins/plugin_loader';
2018-11-06 18:14:29 +01:00
// Components
import { AddPanelWidget } from '../components/AddPanelWidget';
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';
import { PanelEditor } from '../panel_editor/PanelEditor';
import { PanelResizer } from './PanelResizer';
// Types
import { PanelModel, DashboardModel } from '../state';
import { PanelPluginMeta, PanelPlugin } from '@grafana/data';
import { AutoSizer } from 'react-virtualized';
2018-11-06 18:14:29 +01:00
export interface Props {
2017-10-10 09:34:14 +02:00
panel: PanelModel;
dashboard: DashboardModel;
isEditing: boolean;
isFullscreen: boolean;
isInView: boolean;
}
export interface State {
plugin: PanelPlugin;
angularPanel: AngularComponent;
isLazy: boolean;
}
export class DashboardPanel extends PureComponent<Props, State> {
element: HTMLElement;
specialPanels: { [key: string]: Function } = {};
constructor(props: Props) {
super(props);
this.state = {
2018-11-06 18:14:29 +01:00
plugin: null,
angularPanel: null,
isLazy: !props.isInView,
};
2018-01-02 14:52:30 +01:00
this.specialPanels['row'] = this.renderRow.bind(this);
this.specialPanels['add-panel'] = this.renderAddPanel.bind(this);
}
isSpecial(pluginId: string) {
return this.specialPanels[pluginId];
2018-01-02 14:52:30 +01:00
}
renderRow() {
return <DashboardRow panel={this.props.panel} dashboard={this.props.dashboard} />;
2018-01-02 14:52:30 +01:00
}
renderAddPanel() {
return <AddPanelWidget panel={this.props.panel} dashboard={this.props.dashboard} />;
2018-01-02 14:52:30 +01:00
}
onPluginTypeChange = (plugin: PanelPluginMeta) => {
this.loadPlugin(plugin.id);
};
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
if (!this.state.plugin || this.state.plugin.meta.id !== pluginId) {
const plugin = await importPanelPlugin(pluginId);
// unmount angular panel
this.cleanUpAngularPanel();
2018-07-09 18:17:51 +02:00
if (panel.type !== pluginId) {
panel.changePlugin(plugin);
} else {
panel.pluginLoaded(plugin);
}
this.setState({ plugin, angularPanel: null });
}
2018-07-09 18:17:51 +02:00
}
2018-07-09 18:17:51 +02:00
componentDidMount() {
this.loadPlugin(this.props.panel.type);
2018-07-09 18:17:51 +02:00
}
componentDidUpdate(prevProps: Props, prevState: State) {
if (this.state.isLazy && this.props.isInView) {
this.setState({ isLazy: false });
}
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
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 };
const angularPanel = loader.load(this.element, scopeProps, template);
this.setState({ angularPanel });
}
2018-12-14 10:47:18 +01:00
cleanUpAngularPanel() {
if (this.state.angularPanel) {
this.state.angularPanel.destroy();
2018-12-14 10:47:18 +01:00
this.element = null;
}
}
componentWillUnmount() {
2018-12-14 10:47:18 +01:00
this.cleanUpAngularPanel();
}
2018-11-14 13:31:40 +01:00
onMouseEnter = () => {
this.props.dashboard.setPanelFocus(this.props.panel.id);
};
onMouseLeave = () => {
this.props.dashboard.setPanelFocus(0);
};
renderPanel() {
const { dashboard, panel, isFullscreen, isInView } = this.props;
2018-11-06 18:14:29 +01:00
const { plugin } = this.state;
if (plugin.angularPanelCtrl) {
return <div ref={element => (this.element = element)} className="panel-height-helper" />;
}
return (
<AutoSizer>
{({ width, height }) => {
if (width === 0) {
return null;
}
return (
<PanelChrome
plugin={plugin}
panel={panel}
dashboard={dashboard}
isFullscreen={isFullscreen}
isInView={isInView}
width={width}
height={height}
/>
);
}}
</AutoSizer>
);
}
2018-07-09 18:17:51 +02:00
render() {
const { panel, dashboard, isFullscreen, isEditing } = this.props;
const { plugin, angularPanel, isLazy } = this.state;
2018-11-06 18:14:29 +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-11-06 18:14:29 +01:00
// if we have not loaded plugin exports yet, wait
if (!plugin) {
2018-06-19 14:51:57 +02:00
return null;
}
// If we are lazy state don't render anything
if (isLazy) {
return null;
}
const editorContainerClasses = 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 (
<div className={editorContainerClasses}>
<PanelResizer
isEditing={isEditing}
panel={panel}
render={styles => (
<div
className={panelWrapperClass}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
style={styles}
>
{this.renderPanel()}
</div>
)}
/>
{panel.isEditing && (
<PanelEditor
panel={panel}
plugin={plugin}
dashboard={dashboard}
angularPanel={angularPanel}
onPluginTypeChange={this.onPluginTypeChange}
/>
)}
</div>
2018-11-14 13:31:40 +01:00
);
}
}