Browse Source

ux(dashboard): lots of tweaks and polish to row menu, added remove X to add panel and row option views, #6442

Torkel Ödegaard 9 years ago
parent
commit
2fa7100c3b

+ 1 - 0
package.json

@@ -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",

+ 30 - 10
public/app/core/services/keybindingSrv.ts

@@ -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);

+ 8 - 6
public/app/core/services/util_srv.ts

@@ -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
     });

+ 5 - 2
public/app/features/dashboard/row/add_panel.html

@@ -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>

+ 22 - 23
public/app/features/dashboard/row/options.html

@@ -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>
-

+ 50 - 45
public/app/features/dashboard/row/row.html

@@ -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 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 class="clearfix"></div>
 </div>
 

+ 1 - 0
public/app/features/dashboard/row/row_ctrl.ts

@@ -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});
       });
 

+ 6 - 1
public/app/features/dashboard/row/row_model.ts

@@ -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;
+  }
 }
 

+ 4 - 0
public/sass/_old_responsive.scss

@@ -32,6 +32,10 @@
   .page-container {
     padding: ($spacer * 1) ($spacer * 2);
   }
+
+  .dash-row-menu-container {
+    display: none;
+  }
 }
 
 @include media-breakpoint-down(xs) {

+ 21 - 11
public/sass/components/_row.scss

@@ -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,19 +54,21 @@
   position: relative;
 }
 
-.dash-row-options {
+.dash-row-dropview {
+  position: relative;
   background:  $panel-bg;
   border: 1px solid $dash-row-border-color;
   margin: 0 $panel-margin $panel-margin*2 $panel-margin;
   padding: $panel-margin*2;
+  display: flex;
 }
 
-.dash-row-add-panel {
-  background:  $panel-bg;
-  border: 1px solid $dash-row-border-color;
-  margin: 0 $panel-margin $panel-margin*2 $panel-margin;
-  padding: $panel-margin*2;
-  display: flex;
+.dash-row-dropview-close {
+  position: absolute;
+  right: -15px;
+  top: -12px;
+  width: 20px;
+  height: 20px;
 }
 
 .add-panel-panels-scroll {
@@ -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;

+ 1 - 1
public/sass/components/_sidemenu.scss

@@ -179,7 +179,7 @@
   top: 38%;
   right: 6px;
   font-size: 14px;
-  color: $text-color-weak;
+  color: $text-color-faint;
 }
 
 .sidemenu-org-avatar,

+ 3 - 0
public/sass/pages/_dashboard.scss

@@ -35,6 +35,9 @@
   .dash-row-menu {
     display: none;
   }
+  .panel-drop-zone {
+    visibility: hidden;
+  }
 }
 
 div.flot-text {

+ 63 - 39
tasks/options/watch.js

@@ -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);
 
-  return {
-    copy_to_gen: {
-      files: ['<%= srcDir %>/**/*'],
-      tasks: [],
-      options: {
-        spawn: false
-      }
-    },
-  };
+          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');
+      });
+    });
+  });
 };