mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 02:23:31 -06:00
* wrap content in autosizer * replace lib * removing react-virtualized, correct type in editor.ts * remove caret * remove dep from grafana/ui and remove story util
221 lines
5.5 KiB
TypeScript
221 lines
5.5 KiB
TypeScript
// Libraries
|
|
import React, { PureComponent } from 'react';
|
|
import classNames from 'classnames';
|
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
|
|
|
// Utils & Services
|
|
import { getAngularLoader, AngularComponent } from '@grafana/runtime';
|
|
import { importPanelPlugin } from 'app/features/plugins/plugin_loader';
|
|
|
|
// Components
|
|
import { AddPanelWidget } from '../components/AddPanelWidget';
|
|
import { DashboardRow } from '../components/DashboardRow';
|
|
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';
|
|
|
|
export interface Props {
|
|
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 = {
|
|
plugin: null,
|
|
angularPanel: null,
|
|
isLazy: !props.isInView,
|
|
};
|
|
|
|
this.specialPanels['row'] = this.renderRow.bind(this);
|
|
this.specialPanels['add-panel'] = this.renderAddPanel.bind(this);
|
|
}
|
|
|
|
isSpecial(pluginId: string) {
|
|
return this.specialPanels[pluginId];
|
|
}
|
|
|
|
renderRow() {
|
|
return <DashboardRow panel={this.props.panel} dashboard={this.props.dashboard} />;
|
|
}
|
|
|
|
renderAddPanel() {
|
|
return <AddPanelWidget panel={this.props.panel} dashboard={this.props.dashboard} />;
|
|
}
|
|
|
|
onPluginTypeChange = (plugin: PanelPluginMeta) => {
|
|
this.loadPlugin(plugin.id);
|
|
};
|
|
|
|
async loadPlugin(pluginId: string) {
|
|
if (this.isSpecial(pluginId)) {
|
|
return;
|
|
}
|
|
|
|
const { panel } = this.props;
|
|
|
|
// 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();
|
|
|
|
if (panel.type !== pluginId) {
|
|
panel.changePlugin(plugin);
|
|
} else {
|
|
panel.pluginLoaded(plugin);
|
|
}
|
|
|
|
this.setState({ plugin, angularPanel: null });
|
|
}
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.loadPlugin(this.props.panel.type);
|
|
}
|
|
|
|
componentDidUpdate(prevProps: Props, prevState: State) {
|
|
if (this.state.isLazy && this.props.isInView) {
|
|
this.setState({ isLazy: false });
|
|
}
|
|
|
|
if (!this.element || this.state.angularPanel) {
|
|
return;
|
|
}
|
|
|
|
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 });
|
|
}
|
|
|
|
cleanUpAngularPanel() {
|
|
if (this.state.angularPanel) {
|
|
this.state.angularPanel.destroy();
|
|
this.element = null;
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.cleanUpAngularPanel();
|
|
}
|
|
|
|
onMouseEnter = () => {
|
|
this.props.dashboard.setPanelFocus(this.props.panel.id);
|
|
};
|
|
|
|
onMouseLeave = () => {
|
|
this.props.dashboard.setPanelFocus(0);
|
|
};
|
|
|
|
renderPanel() {
|
|
const { dashboard, panel, isFullscreen, isInView } = this.props;
|
|
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>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const { panel, dashboard, isFullscreen, isEditing } = this.props;
|
|
const { plugin, angularPanel, isLazy } = this.state;
|
|
|
|
if (this.isSpecial(panel.type)) {
|
|
return this.specialPanels[panel.type]();
|
|
}
|
|
|
|
// if we have not loaded plugin exports yet, wait
|
|
if (!plugin) {
|
|
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,
|
|
});
|
|
|
|
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>
|
|
);
|
|
}
|
|
}
|