Переглянути джерело

wip: react panel minor progrss

Torkel Ödegaard 7 роки тому
батько
коміт
230606146d

+ 5 - 0
public/app/core/components/grafana_app.ts

@@ -10,6 +10,7 @@ import { createStore } from 'app/stores/store';
 import colors from 'app/core/utils/colors';
 import { BackendSrv } from 'app/core/services/backend_srv';
 import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
+import { AngularLoader, setAngularLoader } from 'app/core/services/angular_loader';
 
 export class GrafanaCtrl {
   /** @ngInject */
@@ -22,8 +23,12 @@ export class GrafanaCtrl {
     contextSrv,
     bridgeSrv,
     backendSrv: BackendSrv,
+    angularLoader: AngularLoader,
     datasourceSrv: DatasourceSrv
   ) {
+    // make angular loader service available to react components
+    setAngularLoader(angularLoader);
+    // create store with env services
     createStore({ backendSrv, datasourceSrv });
 
     $scope.init = function() {

+ 42 - 0
public/app/core/services/angular_loader.ts

@@ -0,0 +1,42 @@
+import angular from 'angular';
+import coreModule from 'app/core/core_module';
+import _ from 'lodash';
+
+export interface AngularComponent {
+  destroy();
+}
+
+export class AngularLoader {
+  /** @ngInject */
+  constructor(private $compile, private $rootScope) {}
+
+  load(elem, scopeProps, template): AngularComponent {
+    var scope = this.$rootScope.$new();
+
+    _.assign(scope, scopeProps);
+
+    const compiledElem = this.$compile(template)(scope);
+    const rootNode = angular.element(elem);
+    rootNode.append(compiledElem);
+
+    return {
+      destroy: () => {
+        scope.$destroy();
+        compiledElem.remove();
+      },
+    };
+  }
+}
+
+coreModule.service('angularLoader', AngularLoader);
+
+let angularLoaderInstance: AngularLoader;
+
+export function setAngularLoader(pl: AngularLoader) {
+  angularLoaderInstance = pl;
+}
+
+// away to access it from react
+export function getAngularLoader(): AngularLoader {
+  return angularLoaderInstance;
+}

+ 0 - 1
public/app/features/dashboard/all.ts

@@ -22,7 +22,6 @@ import './export_data/export_data_modal';
 import './ad_hoc_filters';
 import './repeat_option/repeat_option';
 import './dashgrid/DashboardGridDirective';
-import './dashgrid/PanelLoader';
 import './dashgrid/RowOptions';
 import './folder_picker/folder_picker';
 import './move_to_folder_modal/move_to_folder';

+ 2 - 8
public/app/features/dashboard/dashboard_ctrl.ts

@@ -1,11 +1,10 @@
 import config from 'app/core/config';
 
 import coreModule from 'app/core/core_module';
-import { PanelContainer } from './dashgrid/PanelContainer';
 import { DashboardModel } from './dashboard_model';
 import { PanelModel } from './panel_model';
 
-export class DashboardCtrl implements PanelContainer {
+export class DashboardCtrl {
   dashboard: DashboardModel;
   dashboardViewState: any;
   loadedFallbackDashboard: boolean;
@@ -22,8 +21,7 @@ export class DashboardCtrl implements PanelContainer {
     private dashboardSrv,
     private unsavedChangesSrv,
     private dashboardViewStateSrv,
-    public playlistSrv,
-    private panelLoader
+    public playlistSrv
   ) {
     // temp hack due to way dashboards are loaded
     // can't use controllerAs on route yet
@@ -119,10 +117,6 @@ export class DashboardCtrl implements PanelContainer {
     return this.dashboard;
   }
 
-  getPanelLoader() {
-    return this.panelLoader;
-  }
-
   timezoneChanged() {
     this.$rootScope.$broadcast('refresh');
   }

+ 15 - 19
public/app/features/dashboard/dashgrid/DashboardGrid.tsx

@@ -3,7 +3,6 @@ import ReactGridLayout from 'react-grid-layout';
 import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
 import { DashboardPanel } from './DashboardPanel';
 import { DashboardModel } from '../dashboard_model';
-import { PanelContainer } from './PanelContainer';
 import { PanelModel } from '../panel_model';
 import classNames from 'classnames';
 import sizeMe from 'react-sizeme';
@@ -60,18 +59,15 @@ function GridWrapper({
 const SizedReactLayoutGrid = sizeMe({ monitorWidth: true })(GridWrapper);
 
 export interface DashboardGridProps {
-  getPanelContainer: () => PanelContainer;
+  dashboard: DashboardModel;
 }
 
 export class DashboardGrid extends React.Component<DashboardGridProps, any> {
   gridToPanelMap: any;
-  panelContainer: PanelContainer;
-  dashboard: DashboardModel;
   panelMap: { [id: string]: PanelModel };
 
   constructor(props) {
     super(props);
-    this.panelContainer = this.props.getPanelContainer();
     this.onLayoutChange = this.onLayoutChange.bind(this);
     this.onResize = this.onResize.bind(this);
     this.onResizeStop = this.onResizeStop.bind(this);
@@ -81,20 +77,20 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
     this.state = { animated: false };
 
     // subscribe to dashboard events
-    this.dashboard = this.panelContainer.getDashboard();
-    this.dashboard.on('panel-added', this.triggerForceUpdate.bind(this));
-    this.dashboard.on('panel-removed', this.triggerForceUpdate.bind(this));
-    this.dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this));
-    this.dashboard.on('view-mode-changed', this.onViewModeChanged.bind(this));
-    this.dashboard.on('row-collapsed', this.triggerForceUpdate.bind(this));
-    this.dashboard.on('row-expanded', this.triggerForceUpdate.bind(this));
+    let dashboard = this.props.dashboard;
+    dashboard.on('panel-added', this.triggerForceUpdate.bind(this));
+    dashboard.on('panel-removed', this.triggerForceUpdate.bind(this));
+    dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this));
+    dashboard.on('view-mode-changed', this.onViewModeChanged.bind(this));
+    dashboard.on('row-collapsed', this.triggerForceUpdate.bind(this));
+    dashboard.on('row-expanded', this.triggerForceUpdate.bind(this));
   }
 
   buildLayout() {
     const layout = [];
     this.panelMap = {};
 
-    for (let panel of this.dashboard.panels) {
+    for (let panel of this.props.dashboard.panels) {
       let stringId = panel.id.toString();
       this.panelMap[stringId] = panel;
 
@@ -129,7 +125,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
       this.panelMap[newPos.i].updateGridPos(newPos);
     }
 
-    this.dashboard.sortPanelsByGridPos();
+    this.props.dashboard.sortPanelsByGridPos();
   }
 
   triggerForceUpdate() {
@@ -137,7 +133,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
   }
 
   onWidthChange() {
-    for (const panel of this.dashboard.panels) {
+    for (const panel of this.props.dashboard.panels) {
       panel.resizeDone();
     }
   }
@@ -176,11 +172,11 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
   renderPanels() {
     const panelElements = [];
 
-    for (let panel of this.dashboard.panels) {
+    for (let panel of this.props.dashboard.panels) {
       const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen });
       panelElements.push(
         <div key={panel.id.toString()} className={panelClasses}>
-          <DashboardPanel panel={panel} dashboard={this.dashboard} panelContainer={this.panelContainer} />
+          <DashboardPanel panel={panel} dashboard={this.props.dashboard} />
         </div>
       );
     }
@@ -193,8 +189,8 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
       <SizedReactLayoutGrid
         className={classNames({ layout: true, animated: this.state.animated })}
         layout={this.buildLayout()}
-        isResizable={this.dashboard.meta.canEdit}
-        isDraggable={this.dashboard.meta.canEdit}
+        isResizable={this.props.dashboard.meta.canEdit}
+        isDraggable={this.props.dashboard.meta.canEdit}
         onLayoutChange={this.onLayoutChange}
         onWidthChange={this.onWidthChange}
         onDragStop={this.onDragStop}

+ 1 - 3
public/app/features/dashboard/dashgrid/DashboardGridDirective.ts

@@ -1,6 +1,4 @@
 import { react2AngularDirective } from 'app/core/utils/react2angular';
 import { DashboardGrid } from './DashboardGrid';
 
-react2AngularDirective('dashboardGrid', DashboardGrid, [
-  ['getPanelContainer', { watchDepth: 'reference', wrapApply: false }],
-]);
+react2AngularDirective('dashboardGrid', DashboardGrid, [['dashboard', { watchDepth: 'reference' }]]);

+ 9 - 9
public/app/features/dashboard/dashgrid/DashboardPanel.tsx

@@ -2,9 +2,8 @@ import React from 'react';
 import config from 'app/core/config';
 import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_model';
-import { AttachedPanel } from './PanelLoader';
+import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader';
 import { DashboardRow } from './DashboardRow';
-import { PanelContainer } from './PanelContainer';
 import { AddPanelPanel } from './AddPanelPanel';
 import { importPluginModule } from 'app/features/plugins/plugin_loader';
 import { PanelChrome } from './PanelChrome';
@@ -12,12 +11,11 @@ import { PanelChrome } from './PanelChrome';
 export interface DashboardPanelProps {
   panel: PanelModel;
   dashboard: DashboardModel;
-  panelContainer: PanelContainer;
 }
 
 export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
   element: any;
-  attachedPanel: AttachedPanel;
+  angularPanel: AngularComponent;
   pluginInfo: any;
   pluginExports: any;
   specialPanels = {};
@@ -55,17 +53,19 @@ export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
   componentDidUpdate() {
     // skip loading angular component if we have no element
     // or we have already loaded it
-    if (!this.element || this.attachedPanel) {
+    if (!this.element || this.angularPanel) {
       return;
     }
 
-    const loader = this.props.panelContainer.getPanelLoader();
-    this.attachedPanel = loader.load(this.element, this.props.panel, this.props.dashboard);
+    let loader = getAngularLoader();
+    var template = '<plugin-component type="panel" class="panel-height-helper"></plugin-component>';
+    let scopeProps = { panel: this.props.panel, dashboard: this.props.dashboard };
+    this.angularPanel = loader.load(this.element, scopeProps, template);
   }
 
   componentWillUnmount() {
-    if (this.attachedPanel) {
-      this.attachedPanel.destroy();
+    if (this.angularPanel) {
+      this.angularPanel.destroy();
     }
   }
 

+ 2 - 5
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -32,7 +32,6 @@ export class PanelChrome extends React.Component<PanelChromeProps, any> {
     };
 
     let PanelComponent = this.props.component;
-    console.log('PanelChrome render');
 
     return (
       <div className="panel-height-helper">
@@ -42,9 +41,7 @@ export class PanelChrome extends React.Component<PanelChromeProps, any> {
             {<PanelComponent />}
           </div>
         </div>
-        <div>
-          {this.props.panel.isEditing && <PanelEditor panel={this.props.panel} dashboard={this.props.dashboard} />}
-        </div>
+        {this.props.panel.isEditing && <PanelEditor panel={this.props.panel} dashboard={this.props.dashboard} />}
       </div>
     );
   }
@@ -55,7 +52,7 @@ export class PanelChrome extends React.Component<PanelChromeProps, any> {
 
     if (panel.fullscreen) {
       var docHeight = $(window).height();
-      var editHeight = Math.floor(docHeight * 0.4);
+      var editHeight = Math.floor(docHeight * 0.3);
       var fullscreenHeight = Math.floor(docHeight * 0.8);
       height = panel.isEditing ? editHeight : fullscreenHeight;
     } else {

+ 0 - 7
public/app/features/dashboard/dashgrid/PanelContainer.ts

@@ -1,7 +0,0 @@
-import { DashboardModel } from '../dashboard_model';
-import { PanelLoader } from './PanelLoader';
-
-export interface PanelContainer {
-  getPanelLoader(): PanelLoader;
-  getDashboard(): DashboardModel;
-}

+ 34 - 2
public/app/features/dashboard/dashgrid/PanelEditor.tsx

@@ -1,6 +1,7 @@
 import React from 'react';
 import { PanelModel } from '../panel_model';
 import { DashboardModel } from '../dashboard_model';
+import { getAngularLoader, AngularComponent } from 'app/core/services/angular_loader';
 
 interface PanelEditorProps {
   panel: PanelModel;
@@ -8,9 +9,38 @@ interface PanelEditorProps {
 }
 
 export class PanelEditor extends React.Component<PanelEditorProps, any> {
+  queryElement: any;
+  queryComp: AngularComponent;
+
+  constructor(props) {
+    super(props);
+  }
+
+  componentDidMount() {
+    if (!this.queryElement) {
+      return;
+    }
+
+    let loader = getAngularLoader();
+    var template = '<plugin-component type="query-ctrl" />';
+    let scopeProps = {
+      ctrl: {
+        panel: this.props.panel,
+        dashboard: this.props.dashboard,
+        panelCtrl: {
+          panel: this.props.panel,
+          dashboard: this.props.dashboard,
+        },
+      },
+      target: {},
+    };
+
+    this.queryComp = loader.load(this.queryElement, scopeProps, template);
+  }
+
   render() {
     return (
-      <div className="tabbed-view tabbed-view--panel-edit">
+      <div className="tabbed-view tabbed-view--panel-edit-new">
         <div className="tabbed-view-header">
           <ul className="gf-tabs">
             <li className="gf-tabs-item">
@@ -26,7 +56,9 @@ export class PanelEditor extends React.Component<PanelEditorProps, any> {
           </button>
         </div>
 
-        <div className="tabbed-view-body">testing</div>
+        <div className="tabbed-view-body">
+          <div ref={element => (this.queryElement = element)} className="panel-height-helper" />
+        </div>
       </div>
     );
   }

+ 0 - 31
public/app/features/dashboard/dashgrid/PanelLoader.ts

@@ -1,31 +0,0 @@
-import angular from 'angular';
-import coreModule from 'app/core/core_module';
-
-export interface AttachedPanel {
-  destroy();
-}
-
-export class PanelLoader {
-  /** @ngInject */
-  constructor(private $compile, private $rootScope) {}
-
-  load(elem, panel, dashboard): AttachedPanel {
-    var template = '<plugin-component type="panel" class="panel-height-helper"></plugin-component>';
-    var panelScope = this.$rootScope.$new();
-    panelScope.panel = panel;
-    panelScope.dashboard = dashboard;
-
-    const compiledElem = this.$compile(template)(panelScope);
-    const rootNode = angular.element(elem);
-    rootNode.append(compiledElem);
-
-    return {
-      destroy: () => {
-        panelScope.$destroy();
-        compiledElem.remove();
-      },
-    };
-  }
-}
-
-coreModule.service('panelLoader', PanelLoader);

+ 1 - 0
public/app/features/plugins/plugin_component.ts

@@ -110,6 +110,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
         let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
         return datasourceSrv.get(datasource).then(ds => {
           scope.datasource = ds;
+          console.log('scope', scope);
 
           return importPluginModule(ds.meta.module).then(dsModule => {
             return {

+ 1 - 2
public/app/partials/dashboard.html

@@ -11,8 +11,7 @@
       <dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
       </dashboard-submenu>
 
-      <dashboard-grid get-panel-container="ctrl.getPanelContainer">
-      </dashboard-grid>
+      <dashboard-grid dashboard="ctrl.dashboard"></dashboard-grid>
     </div>
   </div>
 </div>

+ 9 - 0
public/sass/components/_tabbed_view.scss

@@ -10,6 +10,15 @@
       background: none;
     }
   }
+
+  &.tabbed-view--panel-edit-new {
+    padding: 10px 0 0 0;
+
+    .tabbed-view-header {
+      padding: 0px;
+      background: none;
+    }
+  }
 }
 
 .tabbed-view-header {