mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 01:23:32 -06:00
poc: handling panel edit mode in react even for angular panels poc
This commit is contained in:
parent
487fd12d66
commit
911646f913
@ -5,6 +5,7 @@ import _ from 'lodash';
|
||||
export interface AngularComponent {
|
||||
destroy();
|
||||
digest();
|
||||
getScope();
|
||||
}
|
||||
|
||||
export class AngularLoader {
|
||||
@ -28,6 +29,9 @@ export class AngularLoader {
|
||||
digest: () => {
|
||||
scope.$digest();
|
||||
},
|
||||
getScope: () => {
|
||||
return scope;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,11 @@ export interface Props {
|
||||
|
||||
export interface State {
|
||||
plugin: PanelPlugin;
|
||||
angularPanel: AngularComponent;
|
||||
}
|
||||
|
||||
export class DashboardPanel extends PureComponent<Props, State> {
|
||||
element: any;
|
||||
angularPanel: AngularComponent;
|
||||
element: HTMLElement;
|
||||
specialPanels = {};
|
||||
|
||||
constructor(props) {
|
||||
@ -35,6 +35,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
|
||||
this.state = {
|
||||
plugin: null,
|
||||
angularPanel: null,
|
||||
};
|
||||
|
||||
this.specialPanels['row'] = this.renderRow.bind(this);
|
||||
@ -96,25 +97,30 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
this.loadPlugin();
|
||||
|
||||
// handle angular plugin loading
|
||||
if (!this.element || this.angularPanel) {
|
||||
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 };
|
||||
this.angularPanel = loader.load(this.element, scopeProps, template);
|
||||
const angularPanel = loader.load(this.element, scopeProps, template);
|
||||
|
||||
this.setState({ angularPanel });
|
||||
}
|
||||
|
||||
cleanUpAngularPanel() {
|
||||
if (this.angularPanel) {
|
||||
this.angularPanel.destroy();
|
||||
this.angularPanel = null;
|
||||
cleanUpAngularPanel(unmounted?: boolean) {
|
||||
if (this.state.angularPanel) {
|
||||
this.state.angularPanel.destroy();
|
||||
|
||||
if (!unmounted) {
|
||||
this.setState({ angularPanel: null });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.cleanUpAngularPanel();
|
||||
this.cleanUpAngularPanel(true);
|
||||
}
|
||||
|
||||
onMouseEnter = () => {
|
||||
@ -129,25 +135,16 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
const { dashboard, panel } = this.props;
|
||||
const { plugin } = this.state;
|
||||
|
||||
const containerClass = this.props.isEditing ? 'panel-editor-container' : 'panel-height-helper';
|
||||
const panelWrapperClass = this.props.isEditing ? 'panel-editor-container__panel' : 'panel-height-helper';
|
||||
// this might look strange with these classes that change when edit, but
|
||||
// I want to try to keep markup (parents) for panel the same in edit mode to avoide unmount / new mount of panel
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
<div className={panelWrapperClass} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||
<PanelChrome component={plugin.exports.Panel} panel={panel} dashboard={dashboard} />
|
||||
</div>
|
||||
{panel.isEditing && (
|
||||
<PanelEditor panel={panel} plugin={plugin} dashboard={dashboard} onTypeChanged={this.onPluginTypeChanged} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return <PanelChrome component={plugin.exports.Panel} panel={panel} dashboard={dashboard} />;
|
||||
}
|
||||
|
||||
renderAngularPanel() {
|
||||
return <div ref={element => (this.element = element)} className="panel-height-helper" />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { panel } = this.props;
|
||||
const { plugin } = this.state;
|
||||
const { panel, dashboard } = this.props;
|
||||
const { plugin, angularPanel } = this.state;
|
||||
|
||||
if (this.isSpecial()) {
|
||||
return this.specialPanels[panel.type]();
|
||||
@ -158,19 +155,27 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if exporting PanelComponent it must be a react panel
|
||||
if (plugin.exports.Panel) {
|
||||
return this.renderReactPanel();
|
||||
}
|
||||
console.log('DashboardPanel.render()');
|
||||
|
||||
const containerClass = this.props.isEditing ? 'panel-editor-container' : 'panel-height-helper';
|
||||
const panelWrapperClass = this.props.isEditing ? 'panel-editor-container__panel' : 'panel-height-helper';
|
||||
|
||||
// legacy angular rendering
|
||||
return (
|
||||
<div
|
||||
ref={element => (this.element = element)}
|
||||
className="panel-height-helper"
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
/>
|
||||
<div className={containerClass}>
|
||||
<div className={panelWrapperClass} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||
{plugin.exports.Panel && this.renderReactPanel()}
|
||||
{plugin.exports.PanelCtrl && this.renderAngularPanel()}
|
||||
</div>
|
||||
{panel.isEditing && (
|
||||
<PanelEditor
|
||||
panel={panel}
|
||||
plugin={plugin}
|
||||
dashboard={dashboard}
|
||||
angularPanel={angularPanel}
|
||||
onTypeChanged={this.onPluginTypeChanged}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { GeneralTab } from './GeneralTab';
|
||||
|
||||
import { store } from 'app/store/store';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { AngularComponent } from 'app/core/services/AngularLoader';
|
||||
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
@ -16,6 +17,7 @@ interface PanelEditorProps {
|
||||
panel: PanelModel;
|
||||
dashboard: DashboardModel;
|
||||
plugin: PanelPlugin;
|
||||
angularPanel?: AngularComponent;
|
||||
onTypeChanged: (newType: PanelPlugin) => void;
|
||||
}
|
||||
|
||||
@ -58,7 +60,7 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { panel, dashboard, onTypeChanged, plugin } = this.props;
|
||||
const { panel, dashboard, onTypeChanged, plugin, angularPanel } = this.props;
|
||||
const { location } = store.getState();
|
||||
const activeTab = location.query.tab || 'queries';
|
||||
|
||||
@ -85,7 +87,13 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
|
||||
{activeTab === 'general' && <GeneralTab panel={panel} />}
|
||||
{activeTab === 'queries' && <QueriesTab panel={panel} dashboard={dashboard} />}
|
||||
{activeTab === 'visualization' && (
|
||||
<VisualizationTab panel={panel} dashboard={dashboard} plugin={plugin} onTypeChanged={onTypeChanged} />
|
||||
<VisualizationTab
|
||||
panel={panel}
|
||||
dashboard={dashboard}
|
||||
plugin={plugin}
|
||||
onTypeChanged={onTypeChanged}
|
||||
angularPanel={angularPanel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,8 +1,14 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Utils & Services
|
||||
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
|
||||
|
||||
// Components
|
||||
import { EditorTabBody } from './EditorTabBody';
|
||||
import { VizTypePicker } from './VizTypePicker';
|
||||
|
||||
// Types
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import { PanelPlugin } from 'app/types/plugins';
|
||||
@ -11,18 +17,26 @@ interface Props {
|
||||
panel: PanelModel;
|
||||
dashboard: DashboardModel;
|
||||
plugin: PanelPlugin;
|
||||
angularPanel?: AngularComponent;
|
||||
onTypeChanged: (newType: PanelPlugin) => void;
|
||||
}
|
||||
|
||||
export class VisualizationTab extends PureComponent<Props> {
|
||||
element: HTMLElement;
|
||||
angularOptions: AngularComponent;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
renderPanelOptions() {
|
||||
const { plugin, panel } = this.props;
|
||||
const { plugin, panel, angularPanel } = this.props;
|
||||
const { PanelOptions } = plugin.exports;
|
||||
|
||||
if (angularPanel) {
|
||||
return <div ref={element => (this.element = element)} />;
|
||||
}
|
||||
|
||||
if (PanelOptions) {
|
||||
return <PanelOptions options={panel.getOptions()} onChange={this.onPanelOptionsChanged} />;
|
||||
} else {
|
||||
@ -30,6 +44,27 @@ export class VisualizationTab extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { angularPanel } = this.props;
|
||||
|
||||
if (angularPanel) {
|
||||
const scope = angularPanel.getScope();
|
||||
const panelCtrl = scope.$$childHead.ctrl;
|
||||
|
||||
const loader = getAngularLoader();
|
||||
const template = '<panel-editor-tab editor-tab="tab" ctrl="ctrl"></panel-editor-tab>';
|
||||
const scopeProps = { ctrl: panelCtrl, tab: panelCtrl.editorTabs[2] };
|
||||
|
||||
this.angularOptions = loader.load(this.element, scopeProps, template);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.angularOptions) {
|
||||
this.angularOptions.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
onPanelOptionsChanged = (options: any) => {
|
||||
this.props.panel.updateOptions(options);
|
||||
this.forceUpdate();
|
||||
|
@ -6,54 +6,22 @@ import baron from 'baron';
|
||||
const module = angular.module('grafana.directives');
|
||||
|
||||
const panelTemplate = `
|
||||
<div ng-class="{'panel-editor-container': ctrl.panel.isEditing, 'panel-height-helper': !ctrl.panel.isEditing}">
|
||||
<div ng-class="{'panel-editor-container__panel': ctrl.panel.isEditing, 'panel-height-helper': !ctrl.panel.isEditing}">
|
||||
<div class="panel-container">
|
||||
<div class="panel-header" ng-class="{'grid-drag-handle': !ctrl.panel.fullscreen}">
|
||||
<span class="panel-info-corner">
|
||||
<i class="fa"></i>
|
||||
<span class="panel-info-corner-inner"></span>
|
||||
</span>
|
||||
<div class="panel-container">
|
||||
<div class="panel-header" ng-class="{'grid-drag-handle': !ctrl.panel.fullscreen}">
|
||||
<span class="panel-info-corner">
|
||||
<i class="fa"></i>
|
||||
<span class="panel-info-corner-inner"></span>
|
||||
</span>
|
||||
|
||||
<span class="panel-loading" ng-show="ctrl.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
</span>
|
||||
<span class="panel-loading" ng-show="ctrl.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
</span>
|
||||
|
||||
<panel-header class="panel-title-container" panel-ctrl="ctrl"></panel-header>
|
||||
</div>
|
||||
|
||||
<div class="panel-content">
|
||||
<ng-transclude class="panel-height-helper"></ng-transclude>
|
||||
</div>
|
||||
<panel-header class="panel-title-container" panel-ctrl="ctrl"></panel-header>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.panel.isEditing" ng-class="{'panel-editor-container__editor': ctrl.panel.isEditing,
|
||||
'panel-height-helper': !ctrl.panel.isEditing}">
|
||||
<div class="tabbed-view tabbed-view--new">
|
||||
<div class="tabbed-view-header">
|
||||
<h3 class="tabbed-view-panel-title">
|
||||
{{ctrl.pluginName}}
|
||||
</h3>
|
||||
|
||||
<ul class="gf-tabs">
|
||||
<li class="gf-tabs-item" ng-repeat="tab in ::ctrl.editorTabs">
|
||||
<a class="gf-tabs-link" ng-click="ctrl.changeTab($index)" ng-class="{active: ctrl.editorTabIndex === $index}">
|
||||
{{::tab.title}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="panel-editor-tabs__close" ng-click="ctrl.exitFullscreen();">
|
||||
<i class="fa fa-reply"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tabbed-view-body">
|
||||
<div ng-repeat="tab in ctrl.editorTabs" ng-if="ctrl.editorTabIndex === $index" class="panel-height-helper">
|
||||
<panel-editor-tab editor-tab="tab" ctrl="ctrl" index="$index"></panel-editor-tab>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<ng-transclude class="panel-height-helper"></ng-transclude>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,7 +9,6 @@ function panelEditorTab(dynamicDirectiveSrv) {
|
||||
scope: {
|
||||
ctrl: '=',
|
||||
editorTab: '=',
|
||||
index: '=',
|
||||
},
|
||||
directive: scope => {
|
||||
const pluginId = scope.ctrl.pluginId;
|
||||
|
Loading…
Reference in New Issue
Block a user