mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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
This commit is contained in:
parent
19509d1e7a
commit
95e7ead89b
@ -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) {
|
||||
|
@ -1,8 +1,7 @@
|
||||
///<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'
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user