From 786afda4c32cbd4a9e0147814a7ca2da29089ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 1 Nov 2016 13:43:05 +0100 Subject: [PATCH] ux(dashboard): edit mode fixes --- public/app/features/dashboard/all.js | 3 +- .../dashboard/dynamic_dashboard_srv.ts | 7 +- public/app/features/dashboard/model.ts | 25 +- .../dashboard/repeat_option/repeat_option.ts | 34 +++ .../app/features/dashboard/row/options.html | 20 +- public/app/features/dashboard/row/options.ts | 20 +- public/app/features/dashboard/row/row.html | 8 +- public/app/features/dashboard/row/row.ts | 267 ------------------ public/app/features/dashboard/row/row_ctrl.ts | 115 ++++---- .../app/features/dashboard/row/row_model.ts | 15 + public/app/features/dashboard/rowCtrl.js | 51 ---- public/app/features/panel/panel_directive.ts | 2 +- public/app/partials/panelgeneral.html | 4 +- public/sass/components/_row.scss | 2 +- 14 files changed, 162 insertions(+), 411 deletions(-) create mode 100644 public/app/features/dashboard/repeat_option/repeat_option.ts delete mode 100644 public/app/features/dashboard/row/row.ts delete mode 100644 public/app/features/dashboard/rowCtrl.js diff --git a/public/app/features/dashboard/all.js b/public/app/features/dashboard/all.js index 8d66c2eb1b2..edcc3c74d8e 100644 --- a/public/app/features/dashboard/all.js +++ b/public/app/features/dashboard/all.js @@ -22,5 +22,6 @@ define([ './export/export_modal', './dash_list_ctrl', './ad_hoc_filters', - './row/row', + './row/row_ctrl', + './repeat_option/repeat_option', ], function () {}); diff --git a/public/app/features/dashboard/dynamic_dashboard_srv.ts b/public/app/features/dashboard/dynamic_dashboard_srv.ts index a7189627820..9f8fe7f7ab2 100644 --- a/public/app/features/dashboard/dynamic_dashboard_srv.ts +++ b/public/app/features/dashboard/dynamic_dashboard_srv.ts @@ -5,6 +5,7 @@ import angular from 'angular'; import _ from 'lodash'; import coreModule from 'app/core/core_module'; +import {DashboardRow} from './row/row_model'; export class DynamicDashboardSrv { iteration: number; @@ -45,7 +46,7 @@ export class DynamicDashboardSrv { } } else if (row.repeatRowId && row.repeatIteration !== this.iteration) { // clean up old left overs - this.dashboard.rows.splice(i, 1); + this.dashboard.removeRow(row, true); i = i - 1; continue; } @@ -80,12 +81,14 @@ export class DynamicDashboardSrv { row = this.dashboard.rows[i]; if (row.repeatRowId === sourceRowId && row.repeatIteration !== this.iteration) { copy = row; + copy.copyPropertiesFromRowSource(sourceRow); break; } } if (!copy) { - copy = angular.copy(sourceRow); + var modelCopy = angular.copy(sourceRow.getSaveModel()); + copy = new DashboardRow(modelCopy); this.dashboard.rows.splice(sourceRowIndex + repeatIndex, 0, copy); // set new panel ids diff --git a/public/app/features/dashboard/model.ts b/public/app/features/dashboard/model.ts index 3a544e9672f..167ce20ea2b 100644 --- a/public/app/features/dashboard/model.ts +++ b/public/app/features/dashboard/model.ts @@ -6,7 +6,7 @@ import moment from 'moment'; import _ from 'lodash'; import $ from 'jquery'; -import {Emitter, contextSrv} from 'app/core/core'; +import {Emitter, contextSrv, appEvents} from 'app/core/core'; import {DashboardRow} from './row/row_model'; export class DashboardModel { @@ -169,6 +169,27 @@ export class DashboardModel { row.addPanel(panel); } + removeRow(row, force?) { + var index = _.indexOf(this.rows, row); + + if (!row.panels.length || force) { + this.rows.splice(index, 1); + row.destroy(); + return; + } + + appEvents.emit('confirm-modal', { + title: 'Delete', + text: 'Are you sure you want to delete this row?', + icon: 'fa-trash', + yesText: 'Delete', + onConfirm: () => { + this.rows.splice(index, 1); + row.destroy(); + } + }); + } + toggleEditMode() { this.editMode = !this.editMode; this.updateSubmenuVisibility(); @@ -234,7 +255,7 @@ export class DashboardModel { destroy() { this.events.removeAllListeners(); for (let row of this.rows) { - row.events.removeAllListeners(); + row.destroy(); } } diff --git a/public/app/features/dashboard/repeat_option/repeat_option.ts b/public/app/features/dashboard/repeat_option/repeat_option.ts new file mode 100644 index 00000000000..380c2861a28 --- /dev/null +++ b/public/app/features/dashboard/repeat_option/repeat_option.ts @@ -0,0 +1,34 @@ +/// + +import {coreModule} from 'app/core/core'; + +var template = ` +
+ - -
+ + +
+ +
+ +
+ +
+ diff --git a/public/app/features/dashboard/row/options.ts b/public/app/features/dashboard/row/options.ts index 5046a0e77ca..6e9faaf8c00 100644 --- a/public/app/features/dashboard/row/options.ts +++ b/public/app/features/dashboard/row/options.ts @@ -3,7 +3,7 @@ import _ from 'lodash'; import config from 'app/core/config'; -import {coreModule, appEvents} from 'app/core/core'; +import {coreModule} from 'app/core/core'; // import VirtualScroll from 'virtual-scroll'; // console.log(VirtualScroll); @@ -20,23 +20,9 @@ export class RowOptionsCtrl { this.row.titleSize = this.row.titleSize || 'h6'; } - deleteRow() { - if (!this.row.panels.length) { - this.dashboard.rows = _.without(this.dashboard.rows, this.row); - return; - } - - appEvents.emit('confirm-modal', { - title: 'Delete', - text: 'Are you sure you want to delete this row?', - icon: 'fa-trash', - yesText: 'Delete', - onConfirm: () => { - this.dashboard.rows = _.without(this.dashboard.rows, this.row); - } - }); + removeRow() { + this.dashboard.removeRow(this.row); } - } export function rowOptionsDirective() { diff --git a/public/app/features/dashboard/row/row.html b/public/app/features/dashboard/row/row.html index bca5f6f0d57..5728f77c950 100644 --- a/public/app/features/dashboard/row/row.html +++ b/public/app/features/dashboard/row/row.html @@ -5,7 +5,7 @@ - {{ctrl.row.title}} + {{ctrl.row.title | interpolateTemplateVars:this}}
@@ -22,10 +22,10 @@ - + - +
@@ -47,7 +47,7 @@ - {{ctrl.row.title}} + {{ctrl.row.title | interpolateTemplateVars:this}} diff --git a/public/app/features/dashboard/row/row.ts b/public/app/features/dashboard/row/row.ts deleted file mode 100644 index ad05865411e..00000000000 --- a/public/app/features/dashboard/row/row.ts +++ /dev/null @@ -1,267 +0,0 @@ -/// - -import _ from 'lodash'; -import $ from 'jquery'; -import angular from 'angular'; - -import config from 'app/core/config'; -import {coreModule} from 'app/core/core'; - -import './options'; -import './add_panel'; - -export class DashRowCtrl { - dashboard: any; - row: any; - dropView: number; - - /** @ngInject */ - constructor(private $scope, private $rootScope, private $timeout, private uiSegmentSrv, private $q) { - this.row.title = this.row.title || 'Row title'; - - if (this.row.isNew) { - this.dropView = 1; - delete this.row.isNew; - } - } - - onDrop(panelId, dropTarget) { - var dragObject; - - // if string it's a panel type - if (_.isString(panelId)) { - // setup new panel - dragObject = { - row: this.row, - panel: { - title: config.new_panel_title, - type: panelId, - id: this.dashboard.getNextPanelId(), - }, - isNew: true, - }; - } else { - dragObject = this.dashboard.getPanelInfoById(panelId); - } - - if (dropTarget) { - dropTarget = this.dashboard.getPanelInfoById(dropTarget.id); - // if draging new panel onto existing panel split it - if (dragObject.isNew) { - dragObject.panel.span = dropTarget.panel.span = dropTarget.panel.span/2; - // insert after - dropTarget.row.panels.splice(dropTarget.index+1, 0, dragObject.panel); - } else if (this.row === dragObject.row) { - // just move element - this.row.movePanel(dropTarget.index, dragObject.index); - } else { - // split drop target space - dragObject.panel.span = dropTarget.panel.span = dropTarget.panel.span/2; - // insert after - dropTarget.row.panels.splice(dropTarget.index+1, 0, dragObject.panel); - // remove from source row - dragObject.row.removePanel(dragObject.panel); - } - // dropInfo.row.panels[dropInfo.index] = info.panel; - // info.row.panels[info.index] = dropTarget; - // var dragSpan = info.panel.span; - // info.panel.span = dropTarget.span; - // dropTarget.span = dragSpan; - } else { - dragObject.panel.span = 12 - this.row.span; - this.row.panels.push(dragObject.panel); - - // if not new remove from source row - if (!dragObject.isNew) { - dragObject.row.removePanel(dragObject.panel); - } - } - - this.row.panelSpanChanged(); - this.$timeout(() => { - this.$rootScope.$broadcast('render'); - }); - } - - setHeight(height) { - this.row.height = height; - this.$scope.$broadcast('render'); - } - - moveRow(direction) { - var rowsList = this.dashboard.rows; - var rowIndex = _.indexOf(rowsList, this.row); - var newIndex = rowIndex; - switch (direction) { - case 'up': { - newIndex = rowIndex - 1; - break; - } - case 'down': { - newIndex = rowIndex + 1; - break; - } - case 'top': { - newIndex = 0; - break; - } - case 'bottom': { - newIndex = rowsList.length - 1; - break; - } - default: { - newIndex = rowIndex; - } - } - if (newIndex >= 0 && newIndex <= (rowsList.length - 1)) { - _.move(rowsList, rowIndex, newIndex); - } - } - - toggleCollapse() { - this.dropView = 0; - this.row.collapse = !this.row.collapse; - } - - showAddPanel() { - this.row.collapse = false; - this.dropView = this.dropView === 1 ? 0 : 1; - } - - showRowOptions() { - this.dropView = this.dropView === 2 ? 0 : 2; - } -} - -export function rowDirective($rootScope) { - return { - restrict: 'E', - templateUrl: 'public/app/features/dashboard/row/row.html', - controller: DashRowCtrl, - bindToController: true, - controllerAs: 'ctrl', - scope: { - dashboard: "=", - row: "=", - }, - link: function(scope, element) { - scope.$watchGroup(['ctrl.row.collapse', 'ctrl.row.height'], function() { - element.find('.panels-wrapper').css({minHeight: scope.ctrl.row.collapse ? '5px' : scope.ctrl.row.height}); - }); - - $rootScope.onAppEvent('panel-fullscreen-enter', function(evt, info) { - var hasPanel = _.find(scope.ctrl.row.panels, {id: info.panelId}); - if (!hasPanel) { - element.hide(); - } - }, scope); - - $rootScope.onAppEvent('panel-fullscreen-exit', function() { - element.show(); - }, scope); - } - }; -} - -coreModule.directive('dashRow', rowDirective); - - -coreModule.directive('panelWidth', function($rootScope) { - return function(scope, element) { - var fullscreen = false; - - function updateWidth() { - if (!fullscreen) { - element[0].style.width = ((scope.panel.span / 1.2) * 10) + '%'; - } - } - - $rootScope.onAppEvent('panel-fullscreen-enter', function(evt, info) { - fullscreen = true; - - if (scope.panel.id !== info.panelId) { - element.hide(); - } else { - element[0].style.width = '100%'; - } - }, scope); - - $rootScope.onAppEvent('panel-fullscreen-exit', function(evt, info) { - fullscreen = false; - - if (scope.panel.id !== info.panelId) { - element.show(); - } - - updateWidth(); - }, scope); - - scope.$watch('panel.span', updateWidth); - - if (fullscreen) { - element.hide(); - } - }; -}); - - -coreModule.directive('panelDropZone', function($timeout) { - return function(scope, element) { - var row = scope.ctrl.row; - var indrag = false; - var textEl = element.find('.panel-drop-zone-text'); - - function showPanel(span, text) { - element.find('.panel-container').css('height', row.height); - element[0].style.width = ((span / 1.2) * 10) + '%'; - textEl.text(text); - element.show(); - } - - function hidePanel() { - element.hide(); - // element.removeClass('panel-drop-zone--empty'); - } - - function updateState() { - if (scope.ctrl.dashboard.editMode) { - if (row.panels.length === 0 && indrag === false) { - return showPanel(12, 'Empty Space'); - } - - var dropZoneSpan = 12 - scope.ctrl.dashboard.rowSpan(scope.ctrl.row); - if (dropZoneSpan > 0) { - if (indrag) { - return showPanel(dropZoneSpan, 'Drop Here'); - } else { - return showPanel(dropZoneSpan, 'Empty Space'); - } - } - } - - if (indrag === true) { - var dropZoneSpan = 12 - scope.ctrl.dashboard.rowSpan(scope.ctrl.row); - if (dropZoneSpan > 1) { - return showPanel(dropZoneSpan, 'Drop Here'); - } - } - - hidePanel(); - } - - row.events.on('span-changed', updateState, scope); - - scope.$watchGroup(['ctrl.dashboard.editMode'], updateState); - - scope.$on("ANGULAR_DRAG_START", function() { - indrag = true; - updateState(); - }); - - scope.$on("ANGULAR_DRAG_END", function() { - indrag = false; - updateState(); - }); - }; -}); - diff --git a/public/app/features/dashboard/row/row_ctrl.ts b/public/app/features/dashboard/row/row_ctrl.ts index 2f5b1446a17..dad66ceb024 100644 --- a/public/app/features/dashboard/row/row_ctrl.ts +++ b/public/app/features/dashboard/row/row_ctrl.ts @@ -1,11 +1,9 @@ /// import _ from 'lodash'; -import $ from 'jquery'; -import angular from 'angular'; import config from 'app/core/config'; -import {coreModule} from 'app/core/core'; +import {coreModule, appEvents} from 'app/core/core'; import './options'; import './add_panel'; @@ -19,28 +17,63 @@ export class DashRowCtrl { constructor(private $scope, private $rootScope, private $timeout, private uiSegmentSrv, private $q) { this.row.title = this.row.title || 'Row title'; - if (this.dashboard.meta.isNew) { + if (this.row.isNew) { this.dropView = 1; delete this.row.isNew; } } onDrop(panelId, dropTarget) { - var info = this.dashboard.getPanelInfoById(panelId); - if (dropTarget) { - var dropInfo = this.dashboard.getPanelInfoById(dropTarget.id); - dropInfo.row.panels[dropInfo.index] = info.panel; - info.row.panels[info.index] = dropTarget; - var dragSpan = info.panel.span; - info.panel.span = dropTarget.span; - dropTarget.span = dragSpan; + var dragObject; + + // if string it's a panel type + if (_.isString(panelId)) { + // setup new panel + dragObject = { + row: this.row, + panel: { + title: config.new_panel_title, + type: panelId, + id: this.dashboard.getNextPanelId(), + }, + isNew: true, + }; } else { - info.row.panels.splice(info.index, 1); - info.panel.span = 12 - this.dashboard.rowSpan(this.row); - this.row.panels.push(info.panel); + dragObject = this.dashboard.getPanelInfoById(panelId); } - this.$rootScope.$broadcast('render'); + if (dropTarget) { + dropTarget = this.dashboard.getPanelInfoById(dropTarget.id); + // if draging new panel onto existing panel split it + if (dragObject.isNew) { + dragObject.panel.span = dropTarget.panel.span = dropTarget.panel.span/2; + // insert after + dropTarget.row.panels.splice(dropTarget.index+1, 0, dragObject.panel); + } else if (this.row === dragObject.row) { + // just move element + this.row.movePanel(dropTarget.index, dragObject.index); + } else { + // split drop target space + dragObject.panel.span = dropTarget.panel.span = dropTarget.panel.span/2; + // insert after + dropTarget.row.panels.splice(dropTarget.index+1, 0, dragObject.panel); + // remove from source row + dragObject.row.removePanel(dragObject.panel); + } + } else { + dragObject.panel.span = 12 - this.row.span; + this.row.panels.push(dragObject.panel); + + // if not new remove from source row + if (!dragObject.isNew) { + dragObject.row.removePanel(dragObject.panel); + } + } + + this.row.panelSpanChanged(); + this.$timeout(() => { + this.$rootScope.$broadcast('render'); + }); } setHeight(height) { @@ -51,28 +84,8 @@ export class DashRowCtrl { moveRow(direction) { var rowsList = this.dashboard.rows; var rowIndex = _.indexOf(rowsList, this.row); - var newIndex = rowIndex; - switch (direction) { - case 'up': { - newIndex = rowIndex - 1; - break; - } - case 'down': { - newIndex = rowIndex + 1; - break; - } - case 'top': { - newIndex = 0; - break; - } - case 'bottom': { - newIndex = rowsList.length - 1; - break; - } - default: { - newIndex = rowIndex; - } - } + var newIndex = rowIndex + direction; + if (newIndex >= 0 && newIndex <= (rowsList.length - 1)) { _.move(rowsList, rowIndex, newIndex); } @@ -93,7 +106,7 @@ export class DashRowCtrl { } } -export function rowDirective($rootScope) { +coreModule.directive('dashRow', function($rootScope) { return { restrict: 'E', templateUrl: 'public/app/features/dashboard/row/row.html', @@ -121,10 +134,7 @@ export function rowDirective($rootScope) { }, scope); } }; -} - -coreModule.directive('dashRow', rowDirective); - +}); coreModule.directive('panelWidth', function($rootScope) { return function(scope, element) { @@ -180,7 +190,6 @@ coreModule.directive('panelDropZone', function($timeout) { function hidePanel() { element.hide(); - // element.removeClass('panel-drop-zone--empty'); } function updateState() { @@ -190,7 +199,7 @@ coreModule.directive('panelDropZone', function($timeout) { } var dropZoneSpan = 12 - scope.ctrl.dashboard.rowSpan(scope.ctrl.row); - if (dropZoneSpan > 1) { + if (dropZoneSpan > 0) { if (indrag) { return showPanel(dropZoneSpan, 'Drop Here'); } else { @@ -200,26 +209,22 @@ coreModule.directive('panelDropZone', function($timeout) { } if (indrag === true) { - return showPanel(dropZoneSpan, 'Drop Here'); + var dropZoneSpan = 12 - scope.ctrl.dashboard.rowSpan(scope.ctrl.row); + if (dropZoneSpan > 1) { + return showPanel(dropZoneSpan, 'Drop Here'); + } } hidePanel(); } - scope.row.events.on('panel-added', updateState); - scope.row.events.on('span-changed', updateState); + row.events.on('span-changed', updateState, scope); - scope.$watchGroup(['ctrl.row.panels.length', 'ctrl.dashboard.editMode', 'ctrl.row.span'], updateState); + scope.$watchGroup(['ctrl.dashboard.editMode'], updateState); scope.$on("ANGULAR_DRAG_START", function() { indrag = true; updateState(); - // $timeout(function() { - // var dropZoneSpan = 12 - scope.ctrl.dashboard.rowSpan(scope.ctrl.row); - // if (dropZoneSpan > 0) { - // showPanel(dropZoneSpan, 'Panel Drop Zone'); - // } - // }); }); scope.$on("ANGULAR_DRAG_END", function() { diff --git a/public/app/features/dashboard/row/row_model.ts b/public/app/features/dashboard/row/row_model.ts index d32a0c25259..67a0159d9cf 100644 --- a/public/app/features/dashboard/row/row_model.ts +++ b/public/app/features/dashboard/row/row_model.ts @@ -11,6 +11,7 @@ export class DashboardRow { titleSize: any; events: Emitter; span: number; + height: number; defaults = { title: 'Dashboard Row', @@ -19,6 +20,9 @@ export class DashboardRow { titleSize: 'h6', height: 250, isNew: false, + repeat: null, + repeatRowId: null, + repeatIteration: null, }; constructor(private model) { @@ -86,5 +90,16 @@ export class DashboardRow { movePanel(fromIndex, toIndex) { this.panels.splice(toIndex, 0, this.panels.splice(fromIndex, 1)[0]); } + + destroy() { + this.events.removeAllListeners(); + } + + copyPropertiesFromRowSource(source) { + this.height = source.height; + this.title = source.title; + this.showTitle = source.showTitle; + this.titleSize = source.titleSize; + } } diff --git a/public/app/features/dashboard/rowCtrl.js b/public/app/features/dashboard/rowCtrl.js deleted file mode 100644 index e5f063d5f63..00000000000 --- a/public/app/features/dashboard/rowCtrl.js +++ /dev/null @@ -1,51 +0,0 @@ -// define([ -// 'angular', -// 'lodash', -// 'app/core/config' -// ], -// function (angular, _, config) { -// 'use strict'; -// -// var module = angular.module('grafana.controllers'); -// -// module.controller('RowCtrl', function($scope, $rootScope, $timeout) { -// -// $scope.moveRow = function(direction) { -// var rowsList = $scope.dashboard.rows; -// var rowIndex = _.indexOf(rowsList, $scope.row); -// var newIndex = rowIndex; -// switch(direction) { -// case 'up': { -// newIndex = rowIndex - 1; -// break; -// } -// case 'down': { -// newIndex = rowIndex + 1; -// break; -// } -// case 'top': { -// newIndex = 0; -// break; -// } -// case 'bottom': { -// newIndex = rowsList.length - 1; -// break; -// } -// default: { -// newIndex = rowIndex; -// } -// } -// if (newIndex >= 0 && newIndex <= (rowsList.length - 1)) { -// _.move(rowsList, rowIndex, newIndex); -// } -// }; -// -// $scope.setHeight = function(height) { -// $scope.row.height = height; -// $scope.$broadcast('render'); -// }; -// -// $scope.init(); -// }); -// -// }); diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index b19ff972368..de9f5c7ea9b 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -139,7 +139,7 @@ module.directive('panelResizer', function($rootScope) { } function moveHandler(e) { - ctrl.row.height = originalHeight + (e.pageY - handleOffset.top); + ctrl.row.height = Math.round(originalHeight + (e.pageY - handleOffset.top)); ctrl.panel.span = originalWidth + (((e.pageX - handleOffset.left) / maxWidth) * 12); ctrl.panel.span = Math.min(Math.max(ctrl.panel.span, 1), 12); diff --git a/public/app/partials/panelgeneral.html b/public/app/partials/panelgeneral.html index fd7fa19d082..99e56cc27de 100644 --- a/public/app/partials/panelgeneral.html +++ b/public/app/partials/panelgeneral.html @@ -18,9 +18,7 @@
Repeat Panel - +
Min span diff --git a/public/sass/components/_row.scss b/public/sass/components/_row.scss index be85c9ed6f2..ea4858cc0e4 100644 --- a/public/sass/components/_row.scss +++ b/public/sass/components/_row.scss @@ -104,7 +104,7 @@ a.dash-row-header-actions--tight { position: relative; } .dash-row { - margin-bottom: $spacer*2; + margin-bottom: $spacer; } .dash-row-header-title { border-left: 1px solid $dark-4;