mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ux(dashboard): lots of tweaks and polish to row menu, added remove X to add panel and row option views, #6442
This commit is contained in:
parent
616e9ce5f6
commit
2fa7100c3b
@ -68,6 +68,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^1.2.0",
|
||||
"gaze": "^1.1.2",
|
||||
"grunt-jscs": "~1.5.x",
|
||||
"grunt-sass-lint": "^0.2.0",
|
||||
"grunt-sync": "^0.4.1",
|
||||
|
@ -66,6 +66,7 @@ export class KeybindingSrv {
|
||||
Mousetrap.bind(keyArg, evt => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
evt.returnValue = false;
|
||||
return this.$rootScope.$apply(fn.bind(this));
|
||||
});
|
||||
}
|
||||
@ -80,31 +81,32 @@ export class KeybindingSrv {
|
||||
// dashboard.toggleEditMode();
|
||||
// });
|
||||
|
||||
this.bind('ctrl+o', () => {
|
||||
this.bind('mod+o', () => {
|
||||
dashboard.sharedCrosshair = !dashboard.sharedCrosshair;
|
||||
scope.broadcastRefresh();
|
||||
});
|
||||
|
||||
this.bind('ctrl+h', () => {
|
||||
this.bind('mod+h', () => {
|
||||
dashboard.hideControls = !dashboard.hideControls;
|
||||
});
|
||||
|
||||
this.bind(['ctrl+s', 'command+s'], () => {
|
||||
this.bind('mod+s', e => {
|
||||
scope.appEvent('save-dashboard');
|
||||
});
|
||||
this.bind('ctrl+z', () => {
|
||||
|
||||
this.bind('t z', () => {
|
||||
scope.appEvent('zoom-out');
|
||||
});
|
||||
|
||||
this.bind('left', () => {
|
||||
this.bind('t left', () => {
|
||||
scope.appEvent('shift-time-backward');
|
||||
});
|
||||
|
||||
this.bind('right', () => {
|
||||
this.bind('t right', () => {
|
||||
scope.appEvent('shift-time-forward');
|
||||
});
|
||||
|
||||
this.bind('ctrl+i', () => {
|
||||
this.bind('mod+i', () => {
|
||||
scope.appEvent('quick-snapshot');
|
||||
});
|
||||
|
||||
@ -133,7 +135,7 @@ export class KeybindingSrv {
|
||||
});
|
||||
|
||||
// delete panel
|
||||
this.bind('r', () => {
|
||||
this.bind('p r', () => {
|
||||
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
|
||||
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
|
||||
panelInfo.row.removePanel(panelInfo.panel);
|
||||
@ -141,8 +143,26 @@ export class KeybindingSrv {
|
||||
}
|
||||
});
|
||||
|
||||
// delete panel
|
||||
this.bind('s', () => {
|
||||
// delete row
|
||||
this.bind('r r', () => {
|
||||
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
|
||||
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
|
||||
dashboard.removeRow(panelInfo.row);
|
||||
dashboard.meta.focusPanelId = 0;
|
||||
}
|
||||
});
|
||||
|
||||
// collapse row
|
||||
this.bind('r c', () => {
|
||||
if (dashboard.meta.focusPanelId) {
|
||||
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
|
||||
panelInfo.row.toggleCollapse();
|
||||
dashboard.meta.focusPanelId = 0;
|
||||
}
|
||||
});
|
||||
|
||||
// share panel
|
||||
this.bind('p s', () => {
|
||||
if (dashboard.meta.focusPanelId) {
|
||||
var shareScope = scope.$new();
|
||||
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
|
||||
|
@ -23,20 +23,22 @@ export class UtilSrv {
|
||||
this.modalScope.dismiss();
|
||||
}
|
||||
|
||||
if (options.model || !options.scope) {
|
||||
options.scope = this.modalScope = this.$rootScope.$new();
|
||||
options.scope.model = options.model;
|
||||
}
|
||||
|
||||
this.modalScope = options.scope;
|
||||
|
||||
if (options.model) {
|
||||
this.modalScope = this.$rootScope.$new();
|
||||
this.modalScope.model = options.model;
|
||||
} else if (!this.modalScope) {
|
||||
this.modalScope = this.$rootScope.$new();
|
||||
}
|
||||
|
||||
var modal = this.$modal({
|
||||
modalClass: options.modalClass,
|
||||
template: options.src,
|
||||
templateHtml: options.templateHtml,
|
||||
persist: false,
|
||||
show: false,
|
||||
scope: options.scope,
|
||||
scope: this.modalScope,
|
||||
keyboard: false,
|
||||
backdrop: options.backdrop
|
||||
});
|
||||
|
@ -1,4 +1,7 @@
|
||||
<div class="dash-row-add-panel">
|
||||
<div class="dash-row-dropview">
|
||||
<a class="dash-row-dropview-close pointer" ng-click="ctrl.rowCtrl.closeDropView();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
|
||||
<div class="gf-form-inline dash-row-add-panel-form">
|
||||
<div class="gf-form">
|
||||
@ -12,7 +15,7 @@
|
||||
ng-repeat="panel in ctrl.panelHits"
|
||||
ng-class="{active: $index === ctrl.activeIndex}"
|
||||
ng-click="ctrl.addPanel(panel)"
|
||||
ui-draggable="ctrl.dashboard.editMode"
|
||||
ui-draggable="true"
|
||||
drag="panel.id"
|
||||
title="{{panel.name}}">
|
||||
<img class="add-panel-item-img" ng-src="{{panel.info.logos.small}}"></img>
|
||||
|
@ -1,35 +1,34 @@
|
||||
<div class="dash-row-options">
|
||||
<div class="gf-form section">
|
||||
<div class="gf-form-inline">
|
||||
<div class="dash-row-dropview">
|
||||
<a class="dash-row-dropview-close pointer" ng-click="ctrl.rowCtrl.closeDropView();">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
|
||||
<div>
|
||||
<div class="section">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-6">Row Title</span>
|
||||
<span class="gf-form-label width-6">Title</span>
|
||||
<input type="text" class="gf-form-input max-width-14" ng-model='ctrl.row.title'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Size</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select class="input-small gf-form-input" ng-model="ctrl.row.titleSize" ng-options="f for f in ctrl.fontSizes"></select>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Size</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select class="input-small gf-form-input" ng-model="ctrl.row.titleSize" ng-options="f for f in ctrl.fontSizes"></select>
|
||||
</div>
|
||||
</div>
|
||||
<gf-form-switch class="gf-form" label="Show" checked="ctrl.row.showTitle">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
<gf-form-switch class="gf-form" label="Show" checked="ctrl.row.showTitle">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="section">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-6">Height</span>
|
||||
<span class="gf-form-label width-7">Height</span>
|
||||
<input type="text" class="gf-form-input max-width-14" ng-model='ctrl.row.height'></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Repeat for</span>
|
||||
<dash-repeat-option model="ctrl.row"></dash-repeat-option>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form section">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label">Repeat Row</span>
|
||||
<dash-repeat-option model="ctrl.row"></dash-repeat-option>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1,36 +1,3 @@
|
||||
<div class="dash-row-menu-container" data-click-hide>
|
||||
<ul class="dash-row-menu" role="menu">
|
||||
<li>
|
||||
<a ng-click="ctrl.onMenuAddPanel()">
|
||||
<i class="fa fa-plus"></i> Add Panel
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-click="ctrl.onMenuRowOptions()">
|
||||
<i class="fa fa-cog"></i> Row Options
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-click="ctrl.onMenuDeleteRow()">
|
||||
<i class="fa fa-arrow-up"></i> Move Up
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-click="ctrl.onMenuDeleteRow()">
|
||||
<i class="fa fa-arrow-down"></i> Move Down
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-click="ctrl.onMenuDeleteRow()">
|
||||
<i class="fa fa-trash"></i> Remove row
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="dash-row-menu-grip">
|
||||
<i class="fa fa-ellipsis-v"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dash-row-header" ng-if="ctrl.row.showTitle || ctrl.row.collapse">
|
||||
<a class="dash-row-header-title" ng-click="ctrl.toggleCollapse()">
|
||||
<span class="dash-row-collapse-toggle pointer">
|
||||
@ -50,19 +17,57 @@
|
||||
</div>
|
||||
|
||||
<div class="panels-wrapper" ng-if="!ctrl.row.collapse">
|
||||
<div ng-repeat="panel in ctrl.row.panels track by panel.id" class="panel" ui-draggable="!ctrl.dashboard.meta.fullscreen" drag="panel.id" ui-on-drop="ctrl.onDrop($data, panel)" drag-handle-class="drag-handle" panel-width>
|
||||
<plugin-component type="panel" class="panel-margin">
|
||||
</plugin-component>
|
||||
</div>
|
||||
<div class="dash-row-menu-container" data-click-hide>
|
||||
<ul class="dash-row-menu" role="menu">
|
||||
<li>
|
||||
<a ng-click="ctrl.toggleCollapse()">
|
||||
<i class="fa fa-minus"></i> Collapse
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="ctrl.dashboard.meta.canEdit">
|
||||
<a ng-click="ctrl.onMenuAddPanel()">
|
||||
<i class="fa fa-plus"></i> Add Panel
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="ctrl.dashboard.meta.canEdit">
|
||||
<a ng-click="ctrl.onMenuRowOptions()">
|
||||
<i class="fa fa-cog"></i> Row Options
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="ctrl.dashboard.meta.canEdit">
|
||||
<a ng-click="ctrl.moveRow(-1)">
|
||||
<i class="fa fa-arrow-up"></i> Move Up
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="ctrl.dashboard.meta.canEdit">
|
||||
<a ng-click="ctrl.moveRow(1)">
|
||||
<i class="fa fa-arrow-down"></i> Move Down
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="ctrl.dashboard.meta.canEdit">
|
||||
<a ng-click="ctrl.onMenuDeleteRow()">
|
||||
<i class="fa fa-trash"></i> Remove
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="dash-row-menu-grip">
|
||||
<i class="fa fa-ellipsis-v"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="ctrl.onDrop($data)" data-drop="true">
|
||||
<div class="panel-margin">
|
||||
<div class="panel-container">
|
||||
<div class="panel-drop-zone-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-repeat="panel in ctrl.row.panels track by panel.id" class="panel" ui-draggable="!ctrl.dashboard.meta.fullscreen" drag="panel.id" ui-on-drop="ctrl.onDrop($data, panel)" drag-handle-class="drag-handle" panel-width>
|
||||
<plugin-component type="panel" class="panel-margin">
|
||||
</plugin-component>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="ctrl.onDrop($data)" data-drop="true">
|
||||
<div class="panel-margin">
|
||||
<div class="panel-container">
|
||||
<div class="panel-drop-zone-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
|
@ -127,6 +127,7 @@ coreModule.directive('dashRow', function($rootScope) {
|
||||
},
|
||||
link: function(scope, element) {
|
||||
scope.$watchGroup(['ctrl.row.collapse', 'ctrl.row.height'], function() {
|
||||
element.toggleClass('dash-row--collapse', scope.ctrl.row.collapse);
|
||||
element.find('.panels-wrapper').css({minHeight: scope.ctrl.row.collapse ? '5px' : scope.ctrl.row.height});
|
||||
});
|
||||
|
||||
|
@ -11,6 +11,7 @@ export class DashboardRow {
|
||||
events: Emitter;
|
||||
span: number;
|
||||
height: number;
|
||||
collapse: boolean;
|
||||
|
||||
defaults = {
|
||||
title: 'Dashboard Row',
|
||||
@ -22,6 +23,7 @@ export class DashboardRow {
|
||||
repeat: null,
|
||||
repeatRowId: null,
|
||||
repeatIteration: null,
|
||||
collapse: false,
|
||||
};
|
||||
|
||||
constructor(private model) {
|
||||
@ -79,7 +81,6 @@ export class DashboardRow {
|
||||
}
|
||||
|
||||
removePanel(panel, ask?) {
|
||||
console.log('remove panel');
|
||||
if (ask !== false) {
|
||||
appEvents.emit('confirm-modal', {
|
||||
title: 'Remove Panel',
|
||||
@ -113,5 +114,9 @@ export class DashboardRow {
|
||||
this.showTitle = source.showTitle;
|
||||
this.titleSize = source.titleSize;
|
||||
}
|
||||
|
||||
toggleCollapse() {
|
||||
this.collapse = !this.collapse;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,10 @@
|
||||
.page-container {
|
||||
padding: ($spacer * 1) ($spacer * 2);
|
||||
}
|
||||
|
||||
.dash-row-menu-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
|
@ -4,6 +4,14 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
&--collapse {
|
||||
.dash-row-header {
|
||||
background: $panel-bg;
|
||||
border: $panel-border;
|
||||
margin-bottom: $panel-margin*2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dash-row-header {
|
||||
@ -46,14 +54,8 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dash-row-options {
|
||||
background: $panel-bg;
|
||||
border: 1px solid $dash-row-border-color;
|
||||
margin: 0 $panel-margin $panel-margin*2 $panel-margin;
|
||||
padding: $panel-margin*2;
|
||||
}
|
||||
|
||||
.dash-row-add-panel {
|
||||
.dash-row-dropview {
|
||||
position: relative;
|
||||
background: $panel-bg;
|
||||
border: 1px solid $dash-row-border-color;
|
||||
margin: 0 $panel-margin $panel-margin*2 $panel-margin;
|
||||
@ -61,6 +63,14 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dash-row-dropview-close {
|
||||
position: absolute;
|
||||
right: -15px;
|
||||
top: -12px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.add-panel-panels-scroll {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
@ -80,7 +90,7 @@
|
||||
.add-panel-item {
|
||||
background: $input-label-bg;
|
||||
border: $panel-border;
|
||||
padding: $spacer;
|
||||
padding: $spacer/3 $spacer;
|
||||
min-width: 9rem;
|
||||
max-width: 9rem;
|
||||
text-align: center;
|
||||
@ -89,7 +99,7 @@
|
||||
|
||||
&.active,
|
||||
&:hover {
|
||||
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 1px rgba(82,168,236,5.8)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,6 +119,8 @@ $dash-row-menu-animation-speed: 0.20s;
|
||||
.dash-row-menu-container {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
width: 138px;
|
||||
height: 100%;
|
||||
transform: translate(-131px, 0);
|
||||
transition: 0.1s ease-out 0.4s;
|
||||
z-index: 100;
|
||||
@ -128,8 +140,6 @@ $dash-row-menu-animation-speed: 0.20s;
|
||||
}
|
||||
|
||||
.dash-row-menu {
|
||||
border-top: $panel-border;
|
||||
border-bottom: $panel-border;
|
||||
list-style: none;
|
||||
flex-grow: 1;
|
||||
box-shadow: $search-shadow;
|
||||
|
@ -179,7 +179,7 @@
|
||||
top: 38%;
|
||||
right: 6px;
|
||||
font-size: 14px;
|
||||
color: $text-color-weak;
|
||||
color: $text-color-faint;
|
||||
}
|
||||
|
||||
.sidemenu-org-avatar,
|
||||
|
@ -35,6 +35,9 @@
|
||||
.dash-row-menu {
|
||||
display: none;
|
||||
}
|
||||
.panel-drop-zone {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
div.flot-text {
|
||||
|
@ -1,53 +1,77 @@
|
||||
module.exports = function(config, grunt) {
|
||||
'use strict';
|
||||
|
||||
grunt.event.on('watch', function(action, filepath) {
|
||||
var newPath;
|
||||
var gaze = require('gaze');
|
||||
var path = require('path');
|
||||
var firstRun = true;
|
||||
var done;
|
||||
var lastTime;
|
||||
|
||||
grunt.log.writeln('File Changed: ' + filepath);
|
||||
grunt.registerTask('watch', function() {
|
||||
|
||||
if (/(\.html)|(\.json)$/.test(filepath)) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
done = this.async();
|
||||
lastTime = new Date().getTime();
|
||||
|
||||
if (firstRun === false) {
|
||||
grunt.log.writeln('Watch resuming');
|
||||
return;
|
||||
}
|
||||
|
||||
if (/(\.js)$/.test(filepath)) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
gaze(config.srcDir + '/**/*', function(err, watcher) {
|
||||
|
||||
grunt.task.run('jshint');
|
||||
grunt.task.run('jscs');
|
||||
}
|
||||
console.log('Gaze watchers setup');
|
||||
|
||||
if (/(\.scss)$/.test(filepath)) {
|
||||
grunt.task.run('clean:css');
|
||||
grunt.task.run('css');
|
||||
}
|
||||
watcher.on('all', function(evtName, filepath) {
|
||||
filepath = path.relative(process.cwd(), filepath);
|
||||
|
||||
if (/(\.ts)$/.test(filepath)) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
// ignore multiple changes at once
|
||||
var now = new Date().getTime();
|
||||
if (now - lastTime < 100) {
|
||||
return;
|
||||
}
|
||||
lastTime = now;
|
||||
|
||||
// copy ts file also used by source maps
|
||||
//changes changed file source to that of the changed file
|
||||
grunt.config('typescript.build.src', filepath);
|
||||
grunt.config('tslint.source.files.src', filepath);
|
||||
var newPath;
|
||||
grunt.log.writeln('File Changed: ', filepath);
|
||||
|
||||
grunt.task.run('typescript:build');
|
||||
grunt.task.run('tslint');
|
||||
}
|
||||
if (/(\.html)|(\.json)$/.test(filepath)) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
}
|
||||
|
||||
if (/(\.js)$/.test(filepath)) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
|
||||
grunt.task.run('jshint');
|
||||
grunt.task.run('jscs');
|
||||
}
|
||||
|
||||
if (/(\.scss)$/.test(filepath)) {
|
||||
grunt.task.run('clean:css');
|
||||
grunt.task.run('css');
|
||||
}
|
||||
|
||||
if (/(\.ts)$/.test(filepath)) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
|
||||
// copy ts file also used by source maps
|
||||
//changes changed file source to that of the changed file
|
||||
grunt.config('typescript.build.src', filepath);
|
||||
grunt.config('tslint.source.files.src', filepath);
|
||||
|
||||
grunt.task.run('typescript:build');
|
||||
grunt.task.run('tslint');
|
||||
}
|
||||
|
||||
done();
|
||||
firstRun = false;
|
||||
grunt.task.run('watch');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
copy_to_gen: {
|
||||
files: ['<%= srcDir %>/**/*'],
|
||||
tasks: [],
|
||||
options: {
|
||||
spawn: false
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user