浏览代码

grid: minor progress

Torkel Ödegaard 8 年之前
父节点
当前提交
207773e07e

+ 11 - 0
public/app/features/dashboard/PanelModel.ts

@@ -0,0 +1,11 @@
+
+export interface PanelModel {
+  id: number;
+  x: number;
+  y: number;
+  width: number;
+  height: number;
+  type: string;
+  title: string;
+}
+

+ 132 - 130
public/app/features/dashboard/dashboard_ctrl.ts

@@ -1,146 +1,148 @@
 import config from 'app/core/config';
-import angular from 'angular';
 
 import coreModule from 'app/core/core_module';
+import {PanelContainer} from './dashgrid/PanelContainer';
+import {DashboardModel} from './model';
+import {PanelModel} from './PanelModel';
 
-export class DashboardCtrl {
+export class DashboardCtrl implements PanelContainer {
+  dashboard: DashboardModel;
+  dashboardViewState: any;
+  loadedFallbackDashboard: boolean;
 
   /** @ngInject */
   constructor(
     private $scope,
-    $rootScope,
-    keybindingSrv,
-    timeSrv,
-    variableSrv,
-    alertingSrv,
-    dashboardSrv,
-    unsavedChangesSrv,
-    dynamicDashboardSrv,
-    dashboardViewStateSrv,
-    panelLoader,
-    contextSrv,
-    alertSrv,
-    $timeout) {
-
-      $scope.editor = { index: 0 };
-
-      var resizeEventTimeout;
-
-      $scope.setupDashboard = function(data) {
-        try {
-          $scope.setupDashboardInternal(data);
-        } catch (err) {
-          $scope.onInitFailed(err, 'Dashboard init failed', true);
-        }
-      };
-
-      $scope.setupDashboardInternal = function(data) {
-        var dashboard = dashboardSrv.create(data.dashboard, data.meta);
-        dashboardSrv.setCurrent(dashboard);
-
-        // init services
-        timeSrv.init(dashboard);
-        alertingSrv.init(dashboard, data.alerts);
-
-        // template values service needs to initialize completely before
-        // the rest of the dashboard can load
-        variableSrv.init(dashboard)
-        // template values failes are non fatal
-        .catch($scope.onInitFailed.bind(this, 'Templating init failed', false))
-        // continue
-        .finally(function() {
-          dynamicDashboardSrv.init(dashboard);
-          dynamicDashboardSrv.process();
-
-          unsavedChangesSrv.init(dashboard, $scope);
-
-          $scope.dashboard = dashboard;
-          $scope.dashboardMeta = dashboard.meta;
-          $scope.dashboardViewState = dashboardViewStateSrv.create($scope);
-
-          keybindingSrv.setupDashboardBindings($scope, dashboard);
-
-          $scope.dashboard.updateSubmenuVisibility();
-          $scope.setWindowTitleAndTheme();
-
-          $scope.appEvent("dashboard-initialized", $scope.dashboard);
-        })
-        .catch($scope.onInitFailed.bind(this, 'Dashboard init failed', true));
-      };
-
-      $scope.onInitFailed = function(msg, fatal, err) {
-        console.log(msg, err);
-
-        if (err.data && err.data.message) {
-          err.message = err.data.message;
-        } else if (!err.message) {
-          err = {message: err.toString()};
-        }
-
-        $scope.appEvent("alert-error", [msg, err.message]);
-
-        // protect against  recursive fallbacks
-        if (fatal && !$scope.loadedFallbackDashboard) {
-          $scope.loadedFallbackDashboard = true;
-          $scope.setupDashboard({dashboard: {title: 'Dashboard Init failed'}});
-        }
-      };
-
-      $scope.templateVariableUpdated = function() {
-        dynamicDashboardSrv.process();
-      };
-
-      $scope.setWindowTitleAndTheme = function() {
-        window.document.title = config.window_title_prefix + $scope.dashboard.title;
-      };
-
-      $scope.broadcastRefresh = function() {
-        $rootScope.$broadcast('refresh');
-      };
-
-      $scope.addRowDefault = function() {
-        $scope.dashboard.addEmptyRow();
-      };
-
-      $scope.showJsonEditor = function(evt, options) {
-        var editScope = $rootScope.$new();
-        editScope.object = options.object;
-        editScope.updateHandler = options.updateHandler;
-        $scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope });
-      };
-
-      $scope.registerWindowResizeEvent = function() {
-        angular.element(window).bind('resize', function() {
-          $timeout.cancel(resizeEventTimeout);
-          resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200);
-        });
-
-        $scope.$on('$destroy', function() {
-          angular.element(window).unbind('resize');
-          $scope.dashboard.destroy();
-        });
-      };
-
-      $scope.timezoneChanged = function() {
-        $rootScope.$broadcast("refresh");
-      };
-
-      $scope.onFolderChange = function(folder) {
-        $scope.dashboard.folderId = folder.id;
-        $scope.dashboard.meta.folderId = folder.id;
-        $scope.dashboard.meta.folderTitle= folder.title;
-      };
-
-      $scope.getPanelLoader = function() {
-        return panelLoader;
-      };
+    private $rootScope,
+    private keybindingSrv,
+    private timeSrv,
+    private variableSrv,
+    private alertingSrv,
+    private dashboardSrv,
+    private unsavedChangesSrv,
+    private dynamicDashboardSrv,
+    private dashboardViewStateSrv,
+    private panelLoader) {
+      // temp hack due to way dashboards are loaded
+      // can't use controllerAs on route yet
+      $scope.ctrl = this;
+
+      // funcs called from React component bindings and needs this binding
+      this.getPanelContainer = this.getPanelContainer.bind(this);
+    }
+
+    setupDashboard(data) {
+      try {
+        this.setupDashboardInternal(data);
+      } catch (err) {
+        this.onInitFailed(err, 'Dashboard init failed', true);
+      }
+    }
+
+    setupDashboardInternal(data) {
+      const dashboard = this.dashboardSrv.create(data.dashboard, data.meta);
+      this.dashboardSrv.setCurrent(dashboard);
+
+      // init services
+      this.timeSrv.init(dashboard);
+      this.alertingSrv.init(dashboard, data.alerts);
+
+      // template values service needs to initialize completely before
+      // the rest of the dashboard can load
+      this.variableSrv.init(dashboard)
+      // template values failes are non fatal
+      .catch(this.onInitFailed.bind(this, 'Templating init failed', false))
+      // continue
+      .finally(() => {
+        this.dashboard = dashboard;
+
+        this.dynamicDashboardSrv.init(dashboard);
+        this.dynamicDashboardSrv.process();
+
+        this.unsavedChangesSrv.init(dashboard, this.$scope);
+
+        // TODO refactor ViewStateSrv
+        this.$scope.dashboard = dashboard;
+        this.dashboardViewState = this.dashboardViewStateSrv.create(this.$scope);
+
+        this.keybindingSrv.setupDashboardBindings(this.$scope, dashboard);
+
+        this.dashboard.updateSubmenuVisibility();
+        this.setWindowTitleAndTheme();
+
+        this.$scope.appEvent("dashboard-initialized", dashboard);
+      })
+      .catch(this.onInitFailed.bind(this, 'Dashboard init failed', true));
+    }
+
+    onInitFailed(msg, fatal, err) {
+      console.log(msg, err);
+
+      if (err.data && err.data.message) {
+        err.message = err.data.message;
+      } else if (!err.message) {
+        err = {message: err.toString()};
+      }
+
+      this.$scope.appEvent("alert-error", [msg, err.message]);
+
+      // protect against  recursive fallbacks
+      if (fatal && !this.loadedFallbackDashboard) {
+        this.loadedFallbackDashboard = true;
+        this.setupDashboard({dashboard: {title: 'Dashboard Init failed'}});
+      }
+    }
+
+    templateVariableUpdated() {
+      this.dynamicDashboardSrv.process();
+    }
+
+    setWindowTitleAndTheme() {
+      window.document.title = config.window_title_prefix + this.dashboard.title;
+    }
+
+    showJsonEditor(evt, options) {
+      var editScope = this.$rootScope.$new();
+      editScope.object = options.object;
+      editScope.updateHandler = options.updateHandler;
+      this.$scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope });
+    }
+
+    getDashboard() {
+      return this.dashboard;
+    }
+
+    getPanelLoader() {
+      return this.panelLoader;
+    }
+
+    getPanels() {
+      return this.dashboard.panels;
+    }
+
+    panelPossitionUpdated(panel: PanelModel) {
+      console.log('panel pos updated', panel);
+    }
+
+    timezoneChanged() {
+      this.$rootScope.$broadcast("refresh");
+    }
+
+    onFolderChange(folder) {
+      this.dashboard.folderId = folder.id;
+      this.dashboard.meta.folderId = folder.id;
+      this.dashboard.meta.folderTitle= folder.title;
+    }
+
+    getPanelContainer() {
+      console.log('DashboardCtrl:getPanelContainer()');
+      return this;
     }
 
     init(dashboard) {
       this.$scope.onAppEvent('show-json-editor', this.$scope.showJsonEditor);
       this.$scope.onAppEvent('template-variable-value-updated', this.$scope.templateVariableUpdated);
-      this.$scope.setupDashboard(dashboard);
-      this.$scope.registerWindowResizeEvent();
+      this.setupDashboard(dashboard);
     }
 }
 

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

@@ -1,13 +1,12 @@
 import React from 'react';
 import coreModule from 'app/core/core_module';
 import ReactGridLayout from 'react-grid-layout';
-import {DashboardModel} from '../model';
+import {CELL_HEIGHT, CELL_VMARGIN} from '../model';
 import {DashboardPanel} from './DashboardPanel';
-import {PanelLoader} from './PanelLoader';
+import {PanelContainer} from './PanelContainer';
 import sizeMe from 'react-sizeme';
 
 const COLUMN_COUNT = 12;
-const ROW_HEIGHT = 30;
 
 function GridWrapper({size, layout, onLayoutChange, children}) {
   if (size.width === 0) {
@@ -23,9 +22,9 @@ function GridWrapper({size, layout, onLayoutChange, children}) {
       isDraggable={true}
       isResizable={true}
       measureBeforeMount={false}
-      margin={[10, 10]}
+      margin={[CELL_VMARGIN, CELL_VMARGIN]}
       cols={COLUMN_COUNT}
-      rowHeight={ROW_HEIGHT}
+      rowHeight={CELL_HEIGHT}
       draggableHandle=".grid-drag-handle"
       layout={layout}
       onLayoutChange={onLayoutChange}>
@@ -37,21 +36,24 @@ function GridWrapper({size, layout, onLayoutChange, children}) {
 const SizedReactLayoutGrid = sizeMe({monitorWidth: true})(GridWrapper);
 
 export interface DashboardGridProps {
-  dashboard: DashboardModel;
-  getPanelLoader: () => PanelLoader;
+  getPanelContainer: () => PanelContainer;
 }
 
 export class DashboardGrid extends React.Component<DashboardGridProps, any> {
   gridToPanelMap: any;
+  panelContainer: PanelContainer;
 
   constructor(props) {
     super(props);
+    this.panelContainer = this.props.getPanelContainer();
     this.onLayoutChange = this.onLayoutChange.bind(this);
   }
 
   buildLayout() {
     const layout = [];
-    for (let panel of this.props.dashboard.panels) {
+    const panels = this.panelContainer.getPanels();
+
+    for (let panel of panels) {
       layout.push({
         i: panel.id.toString(),
         x: panel.x,
@@ -60,21 +62,28 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
         h: panel.height,
       });
     }
-    console.log(layout);
+
+    console.log('layout', layout);
     return layout;
   }
 
   onLayoutChange() {}
 
   renderPanels() {
+    const panels = this.panelContainer.getPanels();
     const panelElements = [];
-    for (let panel of this.props.dashboard.panels) {
+
+    for (let panel of panels) {
       panelElements.push(
         <div key={panel.id.toString()} className="panel">
-          <DashboardPanel panel={panel} getPanelLoader={this.props.getPanelLoader} dashboard={this.props.dashboard} />
+          <DashboardPanel
+            panel={panel}
+            getPanelContainer={this.props.getPanelContainer}
+          />
         </div>,
       );
     }
+
     return panelElements;
   }
 
@@ -88,8 +97,5 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
 }
 
 coreModule.directive('dashboardGrid', function(reactDirective) {
-  return reactDirective(DashboardGrid, [
-    ['dashboard', {watchDepth: 'reference'}],
-    ['getPanelLoader', {watchDepth: 'reference', wrapApply: false}],
-  ]);
+  return reactDirective(DashboardGrid, [['getPanelContainer', {watchDepth: 'reference', wrapApply: false}]]);
 });

+ 18 - 7
public/app/features/dashboard/dashgrid/DashboardPanel.tsx

@@ -1,14 +1,16 @@
 import React from 'react';
-import {PanelLoader} from './PanelLoader';
+import {PanelModel} from '../PanelModel';
+import {PanelContainer} from './PanelContainer';
+import {AttachedPanel} from './PanelLoader';
 
 export interface DashboardPanelProps {
-  panel: any;
-  dashboard: any;
-  getPanelLoader: () => PanelLoader;
+  panel: PanelModel;
+  getPanelContainer: () => PanelContainer;
 }
 
 export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
-  private element: any;
+  element: any;
+  attachedPanel: AttachedPanel;
 
   constructor(props) {
     super(props);
@@ -16,8 +18,17 @@ export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
   }
 
   componentDidMount() {
-    var loader = this.props.getPanelLoader();
-    loader.load(this.element, this.props.panel, this.props.dashboard);
+    const panelContainer = this.props.getPanelContainer();
+    const dashboard = panelContainer.getDashboard();
+    const loader = panelContainer.getPanelLoader();
+
+    this.attachedPanel = loader.load(this.element, this.props.panel, dashboard);
+  }
+
+  componentWillUnmount() {
+    if (this.attachedPanel) {
+      this.attachedPanel.destroy();
+    }
   }
 
   render() {

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

@@ -0,0 +1,11 @@
+import {PanelModel} from '../PanelModel';
+import {DashboardModel}  from '../model';
+import {PanelLoader} from './PanelLoader';
+
+export interface PanelContainer {
+  getPanels(): PanelModel[];
+  getPanelLoader(): PanelLoader;
+  getDashboard(): DashboardModel;
+  panelPossitionUpdated(panel: PanelModel);
+}
+

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

@@ -23,6 +23,7 @@ export class PanelLoader {
 
     return {
       destroy: () => {
+        console.log('AttachedPanel:Destroy, id' + panel.id);
         panelScope.$destroy();
         compiledElem.remove();
       }

+ 2 - 13
public/app/features/dashboard/model.ts

@@ -1,5 +1,3 @@
-///<reference path="../../headers/common.d.ts" />
-
 import angular from 'angular';
 import moment from 'moment';
 import _ from 'lodash';
@@ -8,18 +6,9 @@ import $ from 'jquery';
 import {DEFAULT_ANNOTATION_COLOR} from 'app/core/utils/colors';
 import {Emitter, contextSrv, appEvents} from 'app/core/core';
 import {DashboardRow} from './row/row_model';
+import {PanelModel} from './PanelModel';
 import sortByKeys from 'app/core/utils/sort_by_keys';
 
-export interface Panel {
-  id: number;
-  x: number;
-  y: number;
-  width: number;
-  height: number;
-  type: string;
-  title: string;
-}
-
 export const CELL_HEIGHT = 30;
 export const CELL_VMARGIN = 15;
 
@@ -50,7 +39,7 @@ export class DashboardModel {
   events: any;
   editMode: boolean;
   folderId: number;
-  panels: Panel[];
+  panels: PanelModel[];
 
   constructor(data, meta?) {
     if (!data) {

+ 5 - 5
public/app/partials/dashboard.html

@@ -1,15 +1,15 @@
-<div dash-class ng-if="dashboard">
-	<dashnav dashboard="dashboard"></dashnav>
+<div dash-class ng-if="ctrl.dashboard">
+	<dashnav dashboard="ctrl.dashboard"></dashnav>
 
 	<div class="scroll-canvas scroll-canvas--dashboard">
 		<div gemini-scrollbar>
 			<div dash-editor-view class="dash-edit-view"></div>
 			<div class="dashboard-container">
 
-				<dashboard-submenu ng-if="dashboard.meta.submenuEnabled" dashboard="dashboard"></dashboard-submenu>
+				<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
+				</dashboard-submenu>
 
-        <!-- <dash&#45;grid dashboard="dashboard"></dash&#45;grid> -->
-				<dashboard-grid dashboard="dashboard" get-panel-loader="getPanelLoader">
+				<dashboard-grid get-panel-container="ctrl.getPanelContainer">
 				</dashboard-grid>
 
 			</div>