From 95e7ead89bd3589422670fe789bbfeeebeff99ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 2 Nov 2016 15:16:48 +0100 Subject: [PATCH] ux(dashboard): varius dashboard ux fixes and keybinding improvements, press 'e' while hovering over panel will open dashboard in edit mode, pressing 'd' will remove panel, #6442 --- public/app/core/services/keybindingSrv.ts | 16 +++++++ public/app/features/dashboard/model.ts | 10 +++++ public/app/features/dashboard/row/row.html | 19 +++++++++ public/app/features/dashboard/row/row_ctrl.ts | 18 +++++++- .../app/features/dashboard/row/row_model.ts | 20 +++++++-- public/app/features/panel/panel_ctrl.ts | 10 +---- public/app/features/panel/panel_directive.ts | 17 ++++++++ public/app/partials/confirm_modal.html | 2 +- public/app/plugins/panel/graph/graph.ts | 12 +++++- .../app/plugins/panel/graph/graph_tooltip.js | 4 ++ public/sass/components/_row.scss | 42 +++++++++++++++++++ public/sass/pages/_dashboard.scss | 6 ++- public/test/test-main.js | 5 +++ 13 files changed, 162 insertions(+), 19 deletions(-) diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index 073fa240bf8..787e93d0043 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -97,6 +97,22 @@ export class KeybindingSrv { scope.appEvent('quick-snapshot'); }); + this.bind('e', () => { + if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { + this.$rootScope.appEvent('panel-change-view', { + fullscreen: true, edit: true, panelId: dashboard.meta.focusPanelId + }); + } + }); + + this.bind('d', () => { + if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { + var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); + panelInfo.row.removePanel(panelInfo.panel); + dashboard.meta.focusPanelId = 0; + } + }); + this.bind('esc', () => { var popups = $('.popover.in'); if (popups.length > 0) { diff --git a/public/app/features/dashboard/model.ts b/public/app/features/dashboard/model.ts index 4f44746a867..99c2eef7660 100644 --- a/public/app/features/dashboard/model.ts +++ b/public/app/features/dashboard/model.ts @@ -185,10 +185,20 @@ export class DashboardModel { } toggleEditMode() { + if (!this.meta.canEdit) { + console.log('Not allowed to edit dashboard'); + return; + } + this.editMode = !this.editMode; this.updateSubmenuVisibility(); } + setPanelFocus(id) { + console.log('setting focus panel id', id); + this.meta.focusPanelId = id; + } + updateSubmenuVisibility() { if (this.editMode) { this.meta.submenuEnabled = true; diff --git a/public/app/features/dashboard/row/row.html b/public/app/features/dashboard/row/row.html index b311a3b07ba..6323c3288f6 100644 --- a/public/app/features/dashboard/row/row.html +++ b/public/app/features/dashboard/row/row.html @@ -41,6 +41,25 @@
+
+ +
+
diff --git a/public/app/features/dashboard/row/row_ctrl.ts b/public/app/features/dashboard/row/row_ctrl.ts index f805f8773a6..7756140505d 100644 --- a/public/app/features/dashboard/row/row_ctrl.ts +++ b/public/app/features/dashboard/row/row_ctrl.ts @@ -58,7 +58,7 @@ export class DashRowCtrl { // insert after dropTarget.row.panels.splice(dropTarget.index+1, 0, dragObject.panel); // remove from source row - dragObject.row.removePanel(dragObject.panel); + dragObject.row.removePanel(dragObject.panel, false); } } else { dragObject.panel.span = 12 - this.row.span; @@ -66,7 +66,7 @@ export class DashRowCtrl { // if not new remove from source row if (!dragObject.isNew) { - dragObject.row.removePanel(dragObject.panel); + dragObject.row.removePanel(dragObject.panel, false); } } @@ -104,6 +104,20 @@ export class DashRowCtrl { showRowOptions() { this.dropView = this.dropView === 2 ? 0 : 2; } + + onMenuAddPanel() { + this.dashboard.toggleEditMode(); + this.dropView = 1; + } + + onMenuRowOptions() { + this.dashboard.toggleEditMode(); + this.dropView = 2; + } + + onMenuDeleteRow() { + this.dashboard.removeRow(this.row); + } } coreModule.directive('dashRow', function($rootScope) { diff --git a/public/app/features/dashboard/row/row_model.ts b/public/app/features/dashboard/row/row_model.ts index 67a0159d9cf..a1079f608e6 100644 --- a/public/app/features/dashboard/row/row_model.ts +++ b/public/app/features/dashboard/row/row_model.ts @@ -1,8 +1,7 @@ /// import _ from 'lodash'; -import {Emitter, contextSrv} from 'app/core/core'; -import {assignModelProperties} from 'app/core/core'; +import {Emitter, contextSrv, appEvents, assignModelProperties} from 'app/core/core'; export class DashboardRow { panels: any; @@ -79,10 +78,23 @@ export class DashboardRow { this.panelSpanChanged(); } - removePanel(panel) { + removePanel(panel, ask?) { + console.log('remove panel'); + if (ask !== false) { + appEvents.emit('confirm-modal', { + title: 'Remove Panel', + text: 'Are you sure you want to remove this panel?', + icon: 'fa-trash', + yesText: 'Remove', + onConfirm: () => { + this.removePanel(panel, false); + } + }); + return; + } + var index = _.indexOf(this.panels, panel); this.panels.splice(index, 1); - this.events.emit('panel-removed', panel); this.panelSpanChanged(); } diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index a0cd5354364..a80ffb669dc 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -201,15 +201,7 @@ export class PanelCtrl { } removePanel() { - this.publishAppEvent('confirm-modal', { - title: 'Remove Panel', - text: 'Are you sure you want to remove this panel?', - icon: 'fa-trash', - yesText: 'Remove', - onConfirm: () => { - this.row.removePanel(this.panel); - } - }); + this.row.removePanel(this.panel); } editPanelJson() { diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 5bcdad3cba1..0fd07d3b63d 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -74,6 +74,16 @@ module.directive('grafanaPanel', function($rootScope) { var hasAlertRule; var lastHeight = 0; + function mouseEnter() { + panelContainer.toggleClass('panel-hover-highlight', true); + ctrl.dashboard.setPanelFocus(ctrl.panel.id); + } + + function mouseLeave() { + panelContainer.toggleClass('panel-hover-highlight', false); + ctrl.dashboard.setPanelFocus(0); + } + // set initial height if (!ctrl.containerHeight) { ctrl.calculatePanelHeight(); @@ -122,6 +132,13 @@ module.directive('grafanaPanel', function($rootScope) { lastFullscreen = ctrl.fullscreen; } }, scope); + + panelContainer.on('mouseenter', mouseEnter); + panelContainer.on('mouseleave', mouseLeave); + + scope.$on('$destroy', function() { + panelContainer.off(); + }); } }; }); diff --git a/public/app/partials/confirm_modal.html b/public/app/partials/confirm_modal.html index e0b6884618b..0ff9a8aa6f1 100644 --- a/public/app/partials/confirm_modal.html +++ b/public/app/partials/confirm_modal.html @@ -28,7 +28,7 @@
- +
diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index 320a5aa0720..92e5ce177e1 100755 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -59,7 +59,9 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { }, scope); rootScope.onAppEvent('clearCrosshair', function() { - plot.clearCrosshair(); + if (plot) { + plot.clearCrosshair(); + } }, scope); // Receive render events @@ -535,7 +537,7 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { return "%H:%M"; } - new GraphTooltip(elem, dashboard, scope, function() { + var tooltip = new GraphTooltip(elem, dashboard, scope, function() { return sortedSeries; }); @@ -547,6 +549,12 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { }); }); }); + + scope.$on('$destroy', function() { + tooltip.destroy(); + elem.off(); + elem.remove(); + }); } }; }); diff --git a/public/app/plugins/panel/graph/graph_tooltip.js b/public/app/plugins/panel/graph/graph_tooltip.js index 5ae03ccf813..704eb9097ec 100644 --- a/public/app/plugins/panel/graph/graph_tooltip.js +++ b/public/app/plugins/panel/graph/graph_tooltip.js @@ -12,6 +12,10 @@ function ($, _) { var $tooltip = $('
'); + this.destroy = function() { + $tooltip.remove(); + }; + this.findHoverIndexFromDataPoints = function(posX, series, last) { var ps = series.datapoints.pointsize; var initial = last*ps; diff --git a/public/sass/components/_row.scss b/public/sass/components/_row.scss index 9c4af6cdb97..30d648bbefc 100644 --- a/public/sass/components/_row.scss +++ b/public/sass/components/_row.scss @@ -215,3 +215,45 @@ a.dash-row-header-actions--tight { width: 2rem; } + +// Legacy mode +.row-tab { + .dropdown-menu-right { + top: 0; + left: 33px; + } +} + +.row-tab-button { + padding: 0px; + cursor: pointer; + vertical-align: middle; + width: 30px; + height: 30px; + text-align: center; + display: inline-block; + line-height: 30px; + background: $btn-success-bg; + color: rgba(255,255,255,.90); +} + +.row-button { + width: 24px; + float: left; + cursor: pointer; + line-height: 31px; + background-color: $blue-dark; +} + +.row-open { + margin-top: 1px; + left: -22px; + position: absolute; + z-index: 100; + transition: .10s left; + transition-delay: .05s; + + &:hover { + left: 0px; + } +} diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index d02a3101ce6..024567e0c39 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -152,7 +152,11 @@ div.flot-text { } .panel-highlight { - box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 5px rgba(82,168,236,10.8) + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 5px rgba(82,168,236,10.8) +} + +.panel-hover-highlight { + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 1px rgba(82,168,236,10.8) } .on-drag-hover { diff --git a/public/test/test-main.js b/public/test/test-main.js index 0774b004eab..4e77a7eae54 100644 --- a/public/test/test-main.js +++ b/public/test/test-main.js @@ -10,6 +10,7 @@ baseURL: '/base/', defaultJSExtensions: true, paths: { + 'mousetrap': 'vendor/npm/mousetrap/mousetrap.js', 'eventemitter3': 'vendor/npm/eventemitter3/index.js', 'tether': 'vendor/npm/tether/dist/js/tether.js', 'tether-drop': 'vendor/npm/tether-drop/dist/js/drop.js', @@ -65,6 +66,10 @@ format: 'cjs', exports: 'EventEmitter' }, + 'vendor/npm/mousetrap/mousetrap.js': { + format: 'global', + exports: 'Mousetrap' + }, } });