Просмотр исходного кода

More work on annotations (#44, #8) It is working for annotations from graphite metrics, basic annotation editor and everything is working. Needs some final touches and support for more datasources

Torkel Ödegaard 12 лет назад
Родитель
Сommit
700d60058f

+ 0 - 2
src/app/controllers/submenuCtrl.js

@@ -10,8 +10,6 @@ function (angular, app, _) {
 
   module.controller('SubmenuCtrl', function($scope) {
       var _d = {
-        collapse: false,
-        notice: false,
         enable: true
       };
 

+ 9 - 10
src/app/directives/configModal.js

@@ -2,7 +2,7 @@ define([
   'angular',
   'underscore'
 ],
-function (angular,_) {
+function (angular, _) {
   'use strict';
 
   angular
@@ -10,30 +10,29 @@ function (angular,_) {
     .directive('configModal', function($modal,$q) {
       return {
         restrict: 'A',
-        link: function(scope, elem) {
+        link: function(scope, elem, attrs) {
+          var
+            model = attrs.kbnModel,
+            partial = attrs.configModal;
+
 
           // create a new modal. Can't reuse one modal unforunately as the directive will not
           // re-render on show.
           elem.bind('click',function(){
-            if (scope.openConfigureModal) {
-              scope.openConfigureModal();
-              scope.$apply();
-              return;
-            }
 
             // Create a temp scope so we can discard changes to it if needed
             var tmpScope = scope.$new();
-            tmpScope.panel = angular.copy(scope.panel);
+            tmpScope[model] = angular.copy(scope[model]);
 
             tmpScope.editSave = function(panel) {
               // Correctly set the top level properties of the panel object
               _.each(panel,function(v,k) {
-                scope.panel[k] = panel[k];
+                scope[model][k] = panel[k];
               });
             };
 
             var panelModal = $modal({
-              template: './app/partials/paneleditor.html',
+              template: partial,
               persist: true,
               show: false,
               scope: tmpScope,

+ 2 - 1
src/app/directives/kibanaPanel.js

@@ -44,7 +44,8 @@ function (angular, $) {
               '</span>' +
             '</span>'+
 
-            '<span ng-if="!panelMeta.menuItems" config-modal class="panel-text panel-title pointer" ng-show="panel.title">' +
+            '<span ng-if="!panelMeta.menuItems" config-modal="./app/partials/paneleditor.html" ' +
+                  ' kbn-model="panel" class="panel-text panel-title pointer" >' +
               '{{panel.title}}' +
             '</span>'+
 

+ 60 - 0
src/app/panels/annotations/editor.html

@@ -0,0 +1,60 @@
+<div bindonce class="modal-body">
+  <div class="pull-right editor-title">Annotations</div>
+
+  <div class="editor-row">
+    <table class="table table-striped annotation-editor-table">
+      <thead>
+        <th width="1%">Type</th>
+        <th width="90%">Name</th>
+        <th width="1%"></th>
+        <th width="1%"></th>
+        <th width="1%"></th>
+        <th width="1%"></th>
+      </thead>
+      <tr ng-repeat="annotation in panel.annotations">
+        <td>{{annotation.type}}</td>
+        <td>{{annotation.name}}</td>
+        <td><i ng-click="_.move(panel.annotations,$index,$index-1)" ng-hide="$first" class="pointer icon-arrow-up"></i></td>
+        <td><i ng-click="_.move(panel.annotations,$index,$index+1)" ng-hide="$last" class="pointer icon-arrow-down"></i></td>
+        <td><i ng-click="panel.annotations = _.without(panel.annotations, annotation)" class="pointer icon-remove"></i></td>
+        <td><a ng-click="edit(annotation)"><i class="icon-pencil" /></a></td>
+      </tr>
+    </table>
+  </div>
+
+  <div class="editor-row">
+    <h4 ng-show="currentIsNew">Add Annotation</h4>
+    <h4 ng-show="!currentIsNew">Edit Annotation</h4>
+
+    <div class="editor-option">
+      <label class="small">Name</label>
+      <input type="text" class="input-medium" ng-model='currentAnnnotation.name' placeholder="name"></input>
+    </div>
+    <div class="editor-option">
+      <label class="small">Type</label>
+      <select ng-model="currentAnnnotation.type" ng-options="f for f in ['graphite metric']"></select>
+    </div>
+  </div>
+
+  <div class="editor-row" ng-if="currentAnnnotation.type === 'graphite metric'">
+    <div class="editor-option">
+      <label class="small">Graphite target expression</label>
+      <input type="text" class="span10" ng-model='currentAnnnotation.target' placeholder=""></input>
+    </div>
+  </div>
+
+  <div class="editor-row" ng-if="currentAnnnotation.type === 'graphite events'">
+    <div class="editor-option">
+      <label class="small">Graphite event tags</label>
+      <input type="text" ng-model='currentAnnnotation.tags' placeholder=""></input>
+    </div>
+  </div>
+
+</div>
+
+<div class="modal-footer">
+  <!-- close_edit() is provided here to allow for a scope to perform action on dismiss -->
+  <button ng-show="currentIsNew" type="button" class="btn btn-success" ng-click="add()">Add annotation</button>
+  <button ng-show="!currentIsNew" type="button" class="btn btn-success" ng-click="update()">Update</button>
+  <button type="button" class="btn btn-danger" ng-click="editSave(panel);close_edit();dismiss()">Close</button>
+</div>

+ 6 - 7
src/app/panels/annotations/module.html

@@ -1,13 +1,12 @@
 <div ng-controller='AnnotationsCtrl' ng-init="init()">
 
- <!--  <div class="submenu-toggle" ng-class="{'annotation-disabled': panel.hideAll }">
-    <a ng-click="hideAll();" class="small">Hide All</a>
-    <i class="icon-ok"></i>
-  </div>
- -->
-  <div class="submenu-toggle" ng-repeat="annotation in annotationList" ng-class="{'annotation-disabled': !annotation.enabled }">
+  <div class="submenu-toggle" ng-repeat="annotation in panel.annotations" ng-class="{'annotation-disabled': !annotation.enable }">
+    <i class="annotation-color-icon icon-minus"></i>
     <a ng-click="hide(annotation)" class="small">{{annotation.name}}</a>
-    <i class="icon-ok"></i>
+  </div>
+
+  <div class="submenu-control-edit">
+    <i class="icon-cog pointer" bs-modal="'app/panels/annotations/editor.html'" bs-tooltip="'Edit annotations'" ></i>
   </div>
 
 </div>

+ 30 - 10
src/app/panels/annotations/module.js

@@ -14,7 +14,7 @@ function (angular, app, _) {
   var module = angular.module('kibana.panels.annotations', []);
   app.useModule(module);
 
-  module.controller('AnnotationsCtrl', function($scope, dashboard, annotationsSrv, $rootScope) {
+  module.controller('AnnotationsCtrl', function($scope, dashboard, $rootScope) {
 
     $scope.panelMeta = {
       status  : "Stable",
@@ -23,26 +23,46 @@ function (angular, app, _) {
 
     // Set and populate defaults
     var _d = {
+      annotations: []
+    };
+
+    var annotationDefaults = {
+      name: '',
+      type: 'graphite metric'
     };
 
     _.defaults($scope.panel,_d);
 
     $scope.init = function() {
-      $scope.annotationList = annotationsSrv.annotationList;
+      $scope.currentAnnnotation = angular.copy(annotationDefaults);
+      $scope.currentIsNew = true;
     };
 
-    $scope.hideAll = function () {
-      $scope.panel.hideAll = !$scope.panel.hideAll;
+    $scope.getAnnotationInfo = function(annotation) {
+      return annotation.target;
+    };
 
-      _.each($scope.annotationList, function(annotation) {
-        annotation.enabled = !$scope.panel.hideAll;
-      });
+    $scope.edit = function(annotation) {
+      $scope.currentAnnnotation = annotation;
+      $scope.currentIsNew = false;
     };
 
-    $scope.hide = function (annotation) {
-      annotation.enabled = !annotation.enabled;
-      $scope.panel.hideAll = !annotation.enabled;
+    $scope.getInfo = function(annotation) {
+      return annotation.target;
+    };
 
+    $scope.update = function() {
+      $scope.currentAnnnotation = angular.copy(annotationDefaults);
+      $scope.currentIsNew = true;
+    };
+
+    $scope.add = function() {
+      $scope.panel.annotations.push($scope.currentAnnnotation);
+      $scope.currentAnnnotation = angular.copy(annotationDefaults);
+    };
+
+    $scope.hide = function (annotation) {
+      annotation.enable = !annotation.enable;
       $rootScope.$broadcast('refresh');
     };
 

+ 2 - 5
src/app/partials/dasheditor.html

@@ -43,7 +43,7 @@
   </div>
 
   <div ng-if="editor.index == 1">
-    <div class="row-fluid">
+    <div class="editor-row">
       <div class="span8">
         <h4>Rows</h4>
         <table class="table table-striped">
@@ -69,9 +69,6 @@
         <input type="text" class="input-mini" ng-model='row.height'></input>
       </div>
     </div>
-    <div class="row-fluid">
-
-    </div>
   </div>
 
   <div ng-if="editor.index == 2" ng-controller="dashLoader">
@@ -124,7 +121,7 @@
   <div ng-if="editor.index == 2">
     <div class="editor-row">
       <div class="section">
-        <h5>Pulldowns</h5>
+        <h5>Feature toggles</h5>
         <div class="editor-option" ng-repeat="pulldown in dashboard.current.pulldowns">
           <label class="small" style="text-transform:capitalize;">{{pulldown.type}}</label><input type="checkbox" ng-model="pulldown.enable" ng-checked="pulldown.enable">
         </div>

+ 29 - 18
src/app/services/annotationsSrv.js

@@ -7,27 +7,35 @@ define([
 
   var module = angular.module('kibana.services');
 
-  module.service('annotationsSrv', function(dashboard, datasourceSrv, $q, alertSrv) {
+  module.service('annotationsSrv', function(dashboard, datasourceSrv, $q, alertSrv, $rootScope) {
+    var promiseCached;
+    var annotationPanel;
 
     this.init = function() {
-      this.annotationList = [
-       /* {
-          type: 'graphite-target',
-          enabled: false,
-          target: 'metrics_data.mysite.dolph.counters.payment.cart_klarna_payment_completed.count',
-          name: 'deploys',
-        },
-        {
-          type: 'graphite-target',
-          enabled: true,
-          target: 'metrics_data.mysite.dolph.counters.payment.cart_paypal_payment_completed.count',
-          name: 'restarts',
-        }*/
-      ];
+      $rootScope.$on('refresh', this.clearCache);
+      $rootScope.$on('dashboard-loaded', this.dashboardLoaded);
+
+      this.dashboardLoaded();
+    };
+
+    this.dashboardLoaded = function () {
+      annotationPanel = _.findWhere(dashboard.current.pulldowns, { type: 'annotations' });
+    };
+
+    this.clearCache = function() {
+      promiseCached = null;
     };
 
     this.getAnnotations = function(rangeUnparsed) {
-      var graphiteAnnotations = _.where(this.annotationList, { type: 'graphite-target', enabled: true });
+      if (!annotationPanel.enable) {
+        return $q.when(null);
+      }
+
+      if (promiseCached) {
+        return promiseCached;
+      }
+
+      var graphiteAnnotations = _.where(annotationPanel.annotations, { type: 'graphite metric', enable: true });
       var graphiteTargets = _.map(graphiteAnnotations, function(annotation) {
         return { target: annotation.target };
       });
@@ -43,7 +51,7 @@ define([
         maxDataPoints: 100
       };
 
-      return datasourceSrv.default.query(graphiteQuery)
+      promiseCached = datasourceSrv.default.query(graphiteQuery)
         .then(function(results) {
           return _.reduce(results.data, function(list, target) {
             _.each(target.datapoints, function (values) {
@@ -51,12 +59,13 @@ define([
                 return;
               }
 
+
               list.push({
                 min: values[1] * 1000,
                 max: values[1] * 1000,
                 eventType: "annotation",
                 title: null,
-                description: "<small><i class='icon-tag icon-flip-vertical'></i>test</small><br>"+
+                description: "<small>" + target.target + "</small><br>"+
                   moment(values[1] * 1000).format('YYYY-MM-DD HH:mm:ss'),
                 score: 1
               });
@@ -68,6 +77,8 @@ define([
         .then(null, function() {
           alertSrv.set('Annotations','Could not fetch annotations','error');
         });
+
+      return promiseCached;
     };
 
     // Now init

+ 5 - 3
src/app/services/dashboard.js

@@ -28,7 +28,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
       failover: false,
       panel_hints: true,
       rows: [],
-      pulldowns: [ { type: 'filtering' },  /*{ type: 'annotations' }*/ ],
+      pulldowns: [ { type: 'filtering' },  { type: 'annotations' } ],
       nav: [ { type: 'timepicker' } ],
       services: {},
       loader: {
@@ -131,13 +131,13 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
         });
       }
 
-      /*var annotations = _.findWhere(dashboard.pulldowns, {type: 'annotations'});
+      var annotations = _.findWhere(dashboard.pulldowns, {type: 'annotations'});
       if (!annotations) {
         dashboard.pulldowns.push({
           type: 'annotations',
           enable: false
         });
-      }*/
+      }
 
       return dashboard;
     };
@@ -177,6 +177,8 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
       // Take out any that we're not allowed to add from the gui.
       self.availablePanels = _.difference(self.availablePanels,config.hidden_panels);
 
+      $rootScope.$emit('dashboard-loaded');
+
       return true;
     };
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/css/bootstrap.dark.min.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/css/bootstrap.light.min.css


+ 1 - 1
src/css/less/grafana.less

@@ -142,7 +142,7 @@
   padding: 0 4px;
   i {
     position: relative;
-    top: 3px;
+    top: 2px;
   }
 }
 

+ 4 - 53
src/css/less/overrides.less

@@ -565,57 +565,8 @@ div.flot-text {
   color: @white;
 }
 
-// Filter submenu
-.filtering-container {
-  float: left;
-}
-
-.filtering-container label {
-  float: left;
-}
-
-.filtering-container input[type=checkbox] {
-  margin: 0;
-}
-
-.filter-panel-filter {
-  display:inline-block;
-  vertical-align: top;
-  padding: 4px 10px 3px 10px;
-  border-right: 1px solid @submenuBorder;
-}
-
-.filter-panel-filter:first-child {
-  padding-left: 0;
-}
-
-.filter-panel-filter ul {
-  margin-bottom: 0px;
-}
-
-.filter-deselected {
-  opacity: 0.5;
-}
-
-.filter-action {
-  float:right;
-  padding-right: 2px;
-  margin-bottom: 0px !important;
-  margin-left: 0px;
-  margin-top: 4px;
-}
-
-.add-filter-action {
-  padding: 3px 10px 0px 5px;
-  position: relative;
-  top: 4px;
-}
-
-.filter-mandate {
-  text-decoration: underline;
-  cursor: pointer;
-}
-
-.filter-apply {
-  float:right;
+.annotation-editor-table {
+  td {
+    white-space: nowrap;
+  }
 }

+ 72 - 1
src/css/less/submenu.less

@@ -12,11 +12,15 @@
 }
 
 .submenu-panel {
-  padding: 0 10px 0 17px;
+  padding: 0 4px 0 8px;
   border-right: 1px solid @submenuBorder;
   float: left;
 }
 
+.submenu-panel:first-child {
+  padding-left: 17px;
+}
+
 .submenu-panel-title {
   float: left;
   text-transform: uppercase;
@@ -30,12 +34,79 @@
 .submenu-toggle {
   padding: 4px 0 3px 8px;
   float: left;
+  .annotation-color-icon {
+    position: relative;
+    top: 2px;
+  }
 }
 
 .submenu-toggle:first-child {
   padding-left: 0;
 }
 
+.submenu-control-edit {
+  padding: 4px 4px 3px 8px;
+  float: right;
+  border-left: 1px solid @submenuBorder;
+  margin-left: 8px;
+}
+
 .annotation-disabled, .annotation-disabled a {
   color: darken(@textColor, 25%);
+}
+
+
+// Filter submenu
+.filtering-container {
+  float: left;
+}
+
+.filtering-container label {
+  float: left;
+}
+
+.filtering-container input[type=checkbox] {
+  margin: 0;
+}
+
+.filter-panel-filter {
+  display:inline-block;
+  vertical-align: top;
+  padding: 4px 10px 3px 10px;
+  border-right: 1px solid @submenuBorder;
+}
+
+.filter-panel-filter:first-child {
+  padding-left: 0;
+}
+
+.filter-panel-filter ul {
+  margin-bottom: 0px;
+}
+
+.filter-deselected {
+  opacity: 0.5;
+}
+
+.filtering-container .filter-action {
+  float:right;
+  padding-right: 2px;
+  margin-bottom: 0px !important;
+  margin-left: 0px;
+  margin-top: 4px;
+}
+
+.add-filter-action {
+  padding: 3px 5px 0px 5px;
+  position: relative;
+  top: 4px;
+}
+
+.filter-mandate {
+  text-decoration: underline;
+  cursor: pointer;
+}
+
+.filter-apply {
+  float:right;
 }

Некоторые файлы не были показаны из-за большого количества измененных файлов