From 207773e07e78094eb3bb43161bf428dd1335de1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 10 Oct 2017 09:34:14 +0200 Subject: [PATCH] grid: minor progress --- public/app/features/dashboard/PanelModel.ts | 11 + .../app/features/dashboard/dashboard_ctrl.ts | 212 +++++++++--------- .../dashboard/dashgrid/DashboardGrid.tsx | 36 +-- .../dashboard/dashgrid/DashboardPanel.tsx | 25 ++- .../dashboard/dashgrid/PanelContainer.ts | 11 + .../dashboard/dashgrid/PanelLoader.ts | 1 + public/app/features/dashboard/model.ts | 15 +- public/app/partials/dashboard.html | 10 +- 8 files changed, 176 insertions(+), 145 deletions(-) create mode 100644 public/app/features/dashboard/PanelModel.ts create mode 100644 public/app/features/dashboard/dashgrid/PanelContainer.ts diff --git a/public/app/features/dashboard/PanelModel.ts b/public/app/features/dashboard/PanelModel.ts new file mode 100644 index 00000000000..90355562ec2 --- /dev/null +++ b/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; +} + diff --git a/public/app/features/dashboard/dashboard_ctrl.ts b/public/app/features/dashboard/dashboard_ctrl.ts index 728bd4a8432..eeb5e7e243b 100644 --- a/public/app/features/dashboard/dashboard_ctrl.ts +++ b/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) { + 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; - $scope.editor = { index: 0 }; + // funcs called from React component bindings and needs this binding + this.getPanelContainer = this.getPanelContainer.bind(this); + } - var resizeEventTimeout; + setupDashboard(data) { + try { + this.setupDashboardInternal(data); + } catch (err) { + this.onInitFailed(err, 'Dashboard init failed', true); + } + } - $scope.setupDashboard = function(data) { - try { - $scope.setupDashboardInternal(data); - } catch (err) { - $scope.onInitFailed(err, 'Dashboard init failed', true); - } - }; + setupDashboardInternal(data) { + const dashboard = this.dashboardSrv.create(data.dashboard, data.meta); + this.dashboardSrv.setCurrent(dashboard); - $scope.setupDashboardInternal = function(data) { - var dashboard = dashboardSrv.create(data.dashboard, data.meta); - dashboardSrv.setCurrent(dashboard); + // init services + this.timeSrv.init(dashboard); + this.alertingSrv.init(dashboard, data.alerts); - // 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 + this.variableSrv.init(dashboard) + // template values failes are non fatal + .catch(this.onInitFailed.bind(this, 'Templating init failed', false)) + // continue + .finally(() => { + this.dashboard = dashboard; - // 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(); + this.dynamicDashboardSrv.init(dashboard); + this.dynamicDashboardSrv.process(); - unsavedChangesSrv.init(dashboard, $scope); + this.unsavedChangesSrv.init(dashboard, this.$scope); - $scope.dashboard = dashboard; - $scope.dashboardMeta = dashboard.meta; - $scope.dashboardViewState = dashboardViewStateSrv.create($scope); + // TODO refactor ViewStateSrv + this.$scope.dashboard = dashboard; + this.dashboardViewState = this.dashboardViewStateSrv.create(this.$scope); - keybindingSrv.setupDashboardBindings($scope, dashboard); + this.keybindingSrv.setupDashboardBindings(this.$scope, dashboard); - $scope.dashboard.updateSubmenuVisibility(); - $scope.setWindowTitleAndTheme(); + this.dashboard.updateSubmenuVisibility(); + this.setWindowTitleAndTheme(); - $scope.appEvent("dashboard-initialized", $scope.dashboard); - }) - .catch($scope.onInitFailed.bind(this, 'Dashboard init failed', true)); - }; + this.$scope.appEvent("dashboard-initialized", dashboard); + }) + .catch(this.onInitFailed.bind(this, 'Dashboard init failed', true)); + } - $scope.onInitFailed = function(msg, fatal, err) { - console.log(msg, err); + 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()}; - } + 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]); + this.$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'}}); - } - }; + // protect against recursive fallbacks + if (fatal && !this.loadedFallbackDashboard) { + this.loadedFallbackDashboard = true; + this.setupDashboard({dashboard: {title: 'Dashboard Init failed'}}); + } + } - $scope.templateVariableUpdated = function() { - dynamicDashboardSrv.process(); - }; + templateVariableUpdated() { + this.dynamicDashboardSrv.process(); + } - $scope.setWindowTitleAndTheme = function() { - window.document.title = config.window_title_prefix + $scope.dashboard.title; - }; + setWindowTitleAndTheme() { + window.document.title = config.window_title_prefix + this.dashboard.title; + } - $scope.broadcastRefresh = function() { - $rootScope.$broadcast('refresh'); - }; + 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 }); + } - $scope.addRowDefault = function() { - $scope.dashboard.addEmptyRow(); - }; + getDashboard() { + return this.dashboard; + } - $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 }); - }; + getPanelLoader() { + return this.panelLoader; + } - $scope.registerWindowResizeEvent = function() { - angular.element(window).bind('resize', function() { - $timeout.cancel(resizeEventTimeout); - resizeEventTimeout = $timeout(function() { $scope.$broadcast('render'); }, 200); - }); + getPanels() { + return this.dashboard.panels; + } - $scope.$on('$destroy', function() { - angular.element(window).unbind('resize'); - $scope.dashboard.destroy(); - }); - }; + panelPossitionUpdated(panel: PanelModel) { + console.log('panel pos updated', panel); + } - $scope.timezoneChanged = function() { - $rootScope.$broadcast("refresh"); - }; + timezoneChanged() { + this.$rootScope.$broadcast("refresh"); + } - $scope.onFolderChange = function(folder) { - $scope.dashboard.folderId = folder.id; - $scope.dashboard.meta.folderId = folder.id; - $scope.dashboard.meta.folderTitle= folder.title; - }; + onFolderChange(folder) { + this.dashboard.folderId = folder.id; + this.dashboard.meta.folderId = folder.id; + this.dashboard.meta.folderTitle= folder.title; + } - $scope.getPanelLoader = function() { - return panelLoader; - }; + 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); } } diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index fc972e7abc4..8d1d8a74a80 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/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 { 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 { 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(
- +
, ); } + return panelElements; } @@ -88,8 +97,5 @@ export class DashboardGrid extends React.Component { } coreModule.directive('dashboardGrid', function(reactDirective) { - return reactDirective(DashboardGrid, [ - ['dashboard', {watchDepth: 'reference'}], - ['getPanelLoader', {watchDepth: 'reference', wrapApply: false}], - ]); + return reactDirective(DashboardGrid, [['getPanelContainer', {watchDepth: 'reference', wrapApply: false}]]); }); diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index ad9c1ccb585..5c7f2178c96 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/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 { - private element: any; + element: any; + attachedPanel: AttachedPanel; constructor(props) { super(props); @@ -16,8 +18,17 @@ export class DashboardPanel extends React.Component { } 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() { diff --git a/public/app/features/dashboard/dashgrid/PanelContainer.ts b/public/app/features/dashboard/dashgrid/PanelContainer.ts new file mode 100644 index 00000000000..352e771cb41 --- /dev/null +++ b/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); +} + diff --git a/public/app/features/dashboard/dashgrid/PanelLoader.ts b/public/app/features/dashboard/dashgrid/PanelLoader.ts index 3d0988381e0..2e9302537af 100644 --- a/public/app/features/dashboard/dashgrid/PanelLoader.ts +++ b/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(); } diff --git a/public/app/features/dashboard/model.ts b/public/app/features/dashboard/model.ts index e407a78faa4..946368040af 100644 --- a/public/app/features/dashboard/model.ts +++ b/public/app/features/dashboard/model.ts @@ -1,5 +1,3 @@ -/// - 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) { diff --git a/public/app/partials/dashboard.html b/public/app/partials/dashboard.html index ddbd4c4d326..58fea114aeb 100644 --- a/public/app/partials/dashboard.html +++ b/public/app/partials/dashboard.html @@ -1,15 +1,15 @@ -
- +
+
- + + - - +