Commit 95e7ead8 by Torkel Ödegaard

ux(dashboard): varius dashboard ux fixes and keybinding improvements, press 'e'…

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
parent 19509d1e
......@@ -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) {
......
......@@ -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;
......
......@@ -41,6 +41,25 @@
</div>
<div ng-if="!ctrl.dashboard.editMode">
<div class="row-open">
<div class='row-tab dropdown' ng-show="dashboardMeta.canEdit" ng-hide="dashboard.meta.fullscreen">
<span class="row-tab-button dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bars"></i>
</span>
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="drop1">
<li>
<a ng-click="ctrl.onMenuAddPanel()">Add Panel</a>
</li>
<li>
<a ng-click="ctrl.onMenuRowOptions()">Row Options</a>
</li>
<li>
<a ng-click="ctrl.onMenuDeleteRow()">Delete row</a>
</li>
</ul>
</div>
</div>
<div class="dash-row-header" ng-if="ctrl.showtitle">
<a class="dash-row-header-title" ng-click="ctrl.toggleCollapse()">
<span class="dash-row-collapse-toggle pointer">
......
......@@ -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) {
......
///<reference path="../../../headers/common.d.ts" />
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();
}
......
......@@ -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() {
......
......@@ -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();
});
}
};
});
......
......@@ -28,7 +28,7 @@
<div class="confirm-modal-buttons">
<button type="button" class="btn btn-inverse" ng-click="dismiss()">{{noText}}</button>
<button type="button" class="btn btn-danger" ng-click="onConfirm();dismiss();" ng-disabled="!confirmTextValid">{{yesText}}</button>
<button type="button" class="btn btn-danger" ng-click="onConfirm();dismiss();" ng-disabled="!confirmTextValid" give-focus="true">{{yesText}}</button>
<button ng-show="onAltAction" type="button" class="btn btn-success" ng-click="dismiss();onAltAction();">{{altActionText}}</button>
</div>
</div>
......
......@@ -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();
});
}
};
});
......@@ -12,6 +12,10 @@ function ($, _) {
var $tooltip = $('<div id="tooltip" class="graph-tooltip">');
this.destroy = function() {
$tooltip.remove();
};
this.findHoverIndexFromDataPoints = function(posX, series, last) {
var ps = series.datapoints.pointsize;
var initial = last*ps;
......
......@@ -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;
}
}
......@@ -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 {
......
......@@ -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'
},
}
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment