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

started on some big refactoring of how the app starts and how dashboard object is loaded, created. This should make it easier to add other dashboard storage backends and other views

Torkel Ödegaard 11 лет назад
Родитель
Сommit
79404e754e

+ 6 - 16
src/app/app.js

@@ -6,15 +6,16 @@ define([
   'jquery',
   'underscore',
   'require',
+  'config',
   'elasticjs',
   'bootstrap',
   'angular-sanitize',
   'angular-strap',
   'angular-dragdrop',
   'extend-jquery',
-  'bindonce'
+  'bindonce',
 ],
-function (angular, $, _, appLevelRequire) {
+function (angular, $, _, appLevelRequire, config) {
 
   "use strict";
 
@@ -67,19 +68,7 @@ function (angular, $, _, appLevelRequire) {
 
   app.config(function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
 
-    $routeProvider
-      .when('/dashboard', {
-        templateUrl: 'app/partials/dashboard.html',
-      })
-      .when('/dashboard/:kbnType/:kbnId', {
-        templateUrl: 'app/partials/dashboard.html',
-      })
-      .when('/dashboard/:kbnType/:kbnId/:params', {
-        templateUrl: 'app/partials/dashboard.html'
-      })
-      .otherwise({
-        redirectTo: 'dashboard'
-      });
+    $routeProvider.otherwise({ redirectTo: config.default_route });
 
     // this is how the internet told me to dynamically add modules :/
     register_fns.controller = $controllerProvider.register;
@@ -98,7 +87,7 @@ function (angular, $, _, appLevelRequire) {
     'pasvaz.bindonce'
   ];
 
-  var module_types = ['controllers', 'directives', 'factories', 'services', 'services.dashboard', 'filters'];
+  var module_types = ['controllers', 'directives', 'factories', 'services', 'filters', 'routes'];
 
   _.each(module_types, function (type) {
     var module_name = 'kibana.'+type;
@@ -120,6 +109,7 @@ function (angular, $, _, appLevelRequire) {
     'directives/all',
     'filters/all',
     'components/partials',
+    'routes/dashboard-loader',
   ], function () {
 
     // bootstrap the app

+ 1 - 11
src/app/controllers/dash.js

@@ -31,11 +31,9 @@ function (angular, $, config, _) {
   var module = angular.module('kibana.controllers');
 
   module.controller('DashCtrl', function(
-    $scope, $rootScope, $timeout, ejsResource, dashboard, filterSrv, dashboardKeybindings,
+    $scope, $rootScope, $timeout, ejsResource, filterSrv, dashboardKeybindings,
     alertSrv, panelMove, keyboardManager, grafanaVersion) {
 
-    $scope.requiredElasticSearchVersion = ">=0.90.3";
-
     $scope.editor = {
       index: 0
     };
@@ -54,16 +52,8 @@ function (angular, $, config, _) {
 
       // Make stuff, including underscore.js available to views
       $scope._ = _;
-      $scope.dashboard = dashboard;
       $scope.dashAlerts = alertSrv;
 
-      $scope.filter = filterSrv;
-      $scope.filter.init(dashboard.current);
-
-      $rootScope.$on("dashboard-loaded", function(event, dashboard) {
-        $scope.filter.init(dashboard);
-      });
-
       // Clear existing alerts
       alertSrv.clearAll();
 

+ 9 - 6
src/app/controllers/dashLoader.js

@@ -8,8 +8,7 @@ function (angular, _, moment) {
 
   var module = angular.module('kibana.controllers');
 
-  module.controller('dashLoader', function($scope, $rootScope, $http, dashboard, alertSrv, $location, playlistSrv) {
-    $scope.loader = dashboard.current.loader;
+  module.controller('dashLoader', function($scope, $rootScope, $http, alertSrv, $location, playlistSrv) {
 
     $scope.init = function() {
       $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
@@ -23,6 +22,10 @@ function (angular, _, moment) {
       $rootScope.$on('zoom-out', function() {
         $scope.zoom(2);
       });
+
+      $rootScope.$on('dashboard-loaded', function(event, dashboard) {
+        $scope.loader = dashboard.loader;
+      });
     };
 
     $scope.exitFullscreen = function() {
@@ -30,11 +33,11 @@ function (angular, _, moment) {
     };
 
     $scope.showDropdown = function(type) {
-      if(_.isUndefined(dashboard.current.loader)) {
+      if(_.isUndefined($scope.loader)) {
         return true;
       }
 
-      var _l = dashboard.current.loader;
+      var _l = $scope.loader;
       if(type === 'load') {
         return (_l.load_elasticsearch || _l.load_gist || _l.load_local);
       }
@@ -129,7 +132,7 @@ function (angular, _, moment) {
     // function $scope.zoom
     // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
     $scope.zoom = function(factor) {
-      var _range = this.filter.timeRange();
+      var _range = $scope.filter.timeRange();
       var _timespan = (_range.to.valueOf() - _range.from.valueOf());
       var _center = _range.to.valueOf() - _timespan/2;
 
@@ -143,7 +146,7 @@ function (angular, _, moment) {
         _to = Date.now();
       }
 
-      this.filter.setTime({
+      $scope.filter.setTime({
         from:moment.utc(_from).toDate(),
         to:moment.utc(_to).toDate(),
       });

+ 12 - 4
src/app/directives/bodyClass.js

@@ -15,8 +15,12 @@ function (angular, app, _) {
           var lastPulldownVal;
           var lastHideControlsVal;
 
-          $scope.$watch('dashboard.current.pulldowns', function() {
-            var panel = _.find($scope.dashboard.current.pulldowns, function(pulldown) { return pulldown.enable; });
+          $scope.$watch('dashboard.pulldowns', function() {
+            if (!$scope.dashboard) {
+              return;
+            }
+
+            var panel = _.find($scope.dashboard.pulldowns, function(pulldown) { return pulldown.enable; });
             var panelEnabled = panel ? panel.enable : false;
             if (lastPulldownVal !== panelEnabled) {
               elem.toggleClass('submenu-controls-visible', panelEnabled);
@@ -24,8 +28,12 @@ function (angular, app, _) {
             }
           }, true);
 
-          $scope.$watch('dashboard.current.hideControls', function() {
-            var hideControls = $scope.dashboard.current.hideControls || $scope.playlist_active;
+          $scope.$watch('dashboard.hideControls', function() {
+            if (!$scope.dashboard) {
+              return;
+            }
+
+            var hideControls = $scope.dashboard.hideControls || $scope.playlist_active;
 
             if (lastHideControlsVal !== hideControls) {
               elem.toggleClass('hide-controls', hideControls);

+ 4 - 3
src/app/directives/grafanaGraph.js

@@ -10,13 +10,14 @@ function (angular, $, kbn, moment, _) {
 
   var module = angular.module('kibana.directives');
 
-  module.directive('grafanaGraph', function($rootScope, dashboard) {
+  module.directive('grafanaGraph', function($rootScope) {
     return {
       restrict: 'A',
       template: '<div> </div>',
       link: function(scope, elem) {
         var data, plot, annotations;
         var hiddenData = {};
+        var dashboard = scope.dashboard;
 
         scope.$on('refresh',function() {
           if (scope.otherPanelInFullscreenMode()) { return; }
@@ -172,7 +173,7 @@ function (angular, $, kbn, moment, _) {
           var max = _.isUndefined(scope.range.to) ? null : scope.range.to.getTime();
 
           options.xaxis = {
-            timezone: dashboard.current.timezone,
+            timezone: dashboard.timezone,
             show: scope.panel['x-axis'],
             mode: "time",
             min: min,
@@ -329,7 +330,7 @@ function (angular, $, kbn, moment, _) {
 
             value = kbn.getFormatFunction(format, 2)(value);
 
-            timestamp = dashboard.current.timezone === 'browser' ?
+            timestamp = dashboard.timezone === 'browser' ?
               moment(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss') :
               moment.utc(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss');
             $tooltip

+ 3 - 2
src/app/panels/graph/module.js

@@ -259,10 +259,11 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
         targets: $scope.panel.targets,
         format: $scope.panel.renderer === 'png' ? 'png' : 'json',
         maxDataPoints: $scope.resolution,
-        datasource: $scope.panel.datasource
+        datasource: $scope.panel.datasource,
+        timezone: $scope.dashboard.timezone
       };
 
-      $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.filter, $scope.rangeUnparsed);
+      $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.filter, $scope.rangeUnparsed, $scope.dashboard);
 
       return $scope.datasource.query($scope.filter, graphiteQuery)
         .then($scope.dataHandler)

+ 13 - 3
src/app/partials/dashboard.html

@@ -1,5 +1,15 @@
+<div class="navbar navbar-static-top">
+  <div class="navbar-inner">
+    <div class="container-fluid">
+      <span class="brand"><img src="img/small.png" bs-tooltip="'Grafana'" data-placement="bottom"> {{dashboard.title}}</span>
+      <ul class="nav pull-right" ng-controller='dashLoader' ng-init="init()" ng-include="'app/partials/dashLoader.html'">
+      </ul>
+    </div>
+  </div>
+</div>
+
 <div class="submenu-controls">
-  <div class="submenu-panel" ng-controller="SubmenuCtrl" ng-repeat="pulldown in dashboard.current.pulldowns | filter:{ enable: true }">
+  <div class="submenu-panel" ng-controller="SubmenuCtrl" ng-repeat="pulldown in dashboard.pulldowns | filter:{ enable: true }">
     <div class="submenu-panel-title">
       <span class="small"><strong>{{pulldown.type}}:</strong></span>
     </div>
@@ -15,7 +25,7 @@
   <div>
     <div class="grafana-container container">
       <!-- Rows -->
-      <div class="kibana-row" ng-controller="RowCtrl" ng-repeat="(row_name, row) in dashboard.current.rows" ng-style="row_style(row)">
+      <div class="kibana-row" ng-controller="RowCtrl" ng-repeat="(row_name, row) in dashboard.rows" ng-style="row_style(row)">
         <div class="row-control">
           <div class="grafana-row" style="padding:0px;margin:0px;position:relative;">
             <div class="row-close" ng-show="row.collapse" data-placement="bottom" >
@@ -97,7 +107,7 @@
         </div>
       </div>
 
-      <div ng-show='dashboard.current.editable && dashboard.current.panel_hints' class="row-fluid add-row-panel-hint">
+      <div ng-show='dashboard.editable && dashboard.current.panel_hints' class="row-fluid add-row-panel-hint">
         <div class="span12" style="text-align:right;">
           <span style="margin-right: 10px;" ng-click="add_row_default()" class="pointer btn btn-info btn-mini">
             <span><i class="icon-plus-sign"></i> ADD A ROW</span>

+ 70 - 0
src/app/routes/dashboard-loader.js

@@ -0,0 +1,70 @@
+define([
+  'angular',
+  'jquery',
+  'config',
+  'underscore'
+],
+function (angular, $, config, _) {
+  "use strict";
+
+  var module = angular.module('kibana.routes');
+
+  module.config(function($routeProvider) {
+    $routeProvider
+      .when('/dashboard/file/:jsonFile', {
+        templateUrl: 'app/partials/dashboard.html',
+        controller : 'DashFromFileProvider',
+      });
+  });
+
+  module.controller('DashFromFileProvider', function($scope, $rootScope, $http, $routeParams, alertSrv, dashboard, filterSrv) {
+
+    $scope.init = function() {
+      console.log('DashFromFileProvider->init()')
+
+      file_load($routeParams.jsonFile)
+        .then(function(data) {
+          $scope.dashboard = dashboard.create(data);
+          $scope.filter = filterSrv;
+          $scope.filter.init($scope.dashboard);
+
+          $rootScope.$emit("dashboard-loaded", $scope.dashboard);
+        });
+    };
+
+    var renderTemplate = function(json,params) {
+      var _r;
+      _.templateSettings = {interpolate : /\{\{(.+?)\}\}/g};
+      var template = _.template(json);
+      var rendered = template({ARGS:params});
+      try {
+        _r = angular.fromJson(rendered);
+      } catch(e) {
+        _r = false;
+      }
+      return _r;
+    };
+
+    var file_load = function(file) {
+      return $http({
+        url: "app/dashboards/"+file.replace(/\.(?!json)/,"/")+'?' + new Date().getTime(),
+        method: "GET",
+        transformResponse: function(response) {
+          return renderTemplate(response,$routeParams);
+        }
+      }).then(function(result) {
+        if(!result) {
+          return false;
+        }
+        return result.data;
+      },function() {
+        alertSrv.set('Error',"Could not load <i>dashboards/"+file+"</i>. Please make sure it exists" ,'error');
+        return false;
+      });
+    };
+
+    $scope.init();
+
+  });
+
+});

+ 3 - 10
src/app/services/annotationsSrv.js

@@ -7,20 +7,12 @@ define([
 
   var module = angular.module('kibana.services');
 
-  module.service('annotationsSrv', function(dashboard, datasourceSrv, $q, alertSrv, $rootScope) {
+  module.service('annotationsSrv', function(datasourceSrv, $q, alertSrv, $rootScope) {
     var promiseCached;
-    var annotationPanel;
     var list = [];
 
     this.init = function() {
       $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() {
@@ -28,7 +20,8 @@ define([
       list = [];
     };
 
-    this.getAnnotations = function(filterSrv, rangeUnparsed) {
+    this.getAnnotations = function(filterSrv, rangeUnparsed, dashboard) {
+      var annotationPanel = _.findWhere(dashboard.pulldowns, { type: 'annotations' });
       if (!annotationPanel.enable) {
         return $q.when(null);
       }

+ 76 - 25
src/app/services/dashboard.js

@@ -8,33 +8,28 @@ define([
   'modernizr',
   'filesaver'
 ],
-function (angular, $, kbn, _, config, moment, Modernizr) {
+function (angular, $, kbn, _) {
   'use strict';
 
   var module = angular.module('kibana.services');
 
-  module.service('dashboard', function(
-    $routeParams, $http, $rootScope, $injector, $location, $timeout,
-    ejsResource, timer, alertSrv, $q
-  ) {
-    // A hash of defaults to use when loading a dashboard
-
-    var _dash = {
-      title: "",
-      tags: [],
-      style: "dark",
-      timezone: 'browser',
-      editable: true,
-      failover: false,
-      panel_hints: true,
-      rows: [],
-      pulldowns: [{ type: 'templating' },  { type: 'annotations' }],
-      nav: [{ type: 'timepicker' }],
-      services: {},
-      loader: {
+  module.service('dashboard', function(timer, $rootScope) {
+
+    function DashboardModel (data) {
+      this.title = data.title;
+      this.tags = data.tags || [];
+      this.style = data.style || "dark";
+      this.timezone = data.browser || 'browser';
+      this.editable = data.editble || true;
+      this.rows = data.rows || [];
+      this.pulldowns = data.pulldowns || [];
+      this.nav = data.nav || [];
+      this.services = data.services || {};
+      this.loader = data.loader;
+
+      _.defaults(this.loader, {
         save_gist: false,
         save_elasticsearch: true,
-        save_local: true,
         save_default: true,
         save_temp: true,
         save_temp_ttl_enable: true,
@@ -42,10 +37,64 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
         load_gist: false,
         load_elasticsearch: true,
         load_elasticsearch_size: 20,
-        load_local: false,
         hide: false
-      },
-      refresh: false
+      });
+
+      if (this.nav.length === 0) {
+        this.nav.push({ type: 'timepicker' });
+      }
+
+      if (!_.findWhere(this.pulldowns, {type: 'filtering'})) {
+        this.pulldowns.push({ type: 'filtering', enable: false });
+      }
+
+      if (!_.findWhere(this.pulldowns, {type: 'annotations'})) {
+        this.pulldowns.push({ type: 'annotations', enable: false });
+      }
+
+      _.each(this.rows, function(row) {
+        _.each(row.panels, function(panel) {
+          if (panel.type === 'graphite') {
+            panel.type = 'graph';
+          }
+        });
+      });
+    }
+
+    var p = DashboardModel.prototype;
+
+    p.refresh = function() {
+      $rootScope.$broadcast('refresh');
+    };
+
+    p.set_interval = function(interval) {
+      this.refresh = interval;
+
+      if (interval) {
+        var _i = kbn.interval_to_ms(interval);
+        timer.cancel(this.refresh_timer);
+        var dashboard_reference = this;
+
+        this.refresh_timer = timer.register($timeout(function() {
+          dashboard_reference.set_interval(interval);
+          dashboard_reference.full_refresh();
+        },_i));
+        this.full_refresh();
+      } else {
+        timer.cancel(this.refresh_timer);
+      }
+    };
+
+    return {
+      create: function(dashboard) {
+        return new DashboardModel(dashboard);
+      }
+    };
+
+    /*// A hash of defaults to use when loading a dashboard
+
+    var _dash = {
+
     };
 
     // An elasticJS client to use
@@ -326,6 +375,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
       })
       .then(function(result) {
         /*jshint -W054 */
+/*
         var script_func = new Function('ARGS','kbn','_','moment','window','document','$','jQuery', result.data);
         var script_result = script_func($routeParams,kbn,_,moment, window, document, $, $);
 
@@ -459,6 +509,7 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
         timer.cancel(self.refresh_timer);
       }
     };
-  });
+  */
 
+  });
 });

+ 1 - 1
src/app/services/dashboard/dashboardKeyBindings.js

@@ -6,7 +6,7 @@ define([
 function(angular, $) {
   "use strict";
 
-  var module = angular.module('kibana.services.dashboard');
+  var module = angular.module('kibana.services');
 
   module.service('dashboardKeybindings', function($rootScope, keyboardManager, dashboard) {
     this.shortcuts = function() {

+ 4 - 6
src/app/services/filterSrv.js

@@ -8,7 +8,7 @@ define([
 
   var module = angular.module('kibana.services');
 
-  module.factory('filterSrv', function(dashboard, $rootScope, $timeout, $routeParams) {
+  module.factory('filterSrv', function($rootScope, $timeout, $routeParams) {
     // defaults
     var _d = {
       templateParameters: [],
@@ -53,16 +53,14 @@ define([
         // disable refresh if we have an absolute time
         if (time.to !== 'now') {
           this.old_refresh = this.dashboard.refresh;
-          dashboard.set_interval(false);
+          this.dashboard.set_interval(false);
         }
         else if (this.old_refresh && this.old_refresh !== this.dashboard.refresh) {
-          dashboard.set_interval(this.old_refresh);
+          this.dashboard.set_interval(this.old_refresh);
           this.old_refresh = null;
         }
 
-        $timeout(function() {
-          dashboard.refresh();
-        },0);
+        $timeout(this.dashboard.refresh, 0);
       },
 
       timeRange: function(parse) {

+ 5 - 5
src/app/services/graphite/graphiteDatasource.js

@@ -11,7 +11,7 @@ function (angular, _, $, config, kbn, moment) {
 
   var module = angular.module('kibana.services');
 
-  module.factory('GraphiteDatasource', function(dashboard, $q, $http) {
+  module.factory('GraphiteDatasource', function($q, $http) {
 
     function GraphiteDatasource(datasource) {
       this.type = 'graphite';
@@ -25,8 +25,8 @@ function (angular, _, $, config, kbn, moment) {
     GraphiteDatasource.prototype.query = function(filterSrv, options) {
       try {
         var graphOptions = {
-          from: this.translateTime(options.range.from, 'round-down'),
-          until: this.translateTime(options.range.to, 'round-up'),
+          from: this.translateTime(options.range.from, options.timezone, 'round-down'),
+          until: this.translateTime(options.range.to, options.timezone, 'round-up'),
           targets: options.targets,
           format: options.format,
           maxDataPoints: options.maxDataPoints,
@@ -72,7 +72,7 @@ function (angular, _, $, config, kbn, moment) {
       }
     };
 
-    GraphiteDatasource.prototype.translateTime = function(date, rounding) {
+    GraphiteDatasource.prototype.translateTime = function(date, timezone, rounding) {
       if (_.isString(date)) {
         if (date === 'now') {
           return 'now';
@@ -104,7 +104,7 @@ function (angular, _, $, config, kbn, moment) {
         }
       }
 
-      if (dashboard.current.timezone === 'browser') {
+      if (timezone === 'browser') {
         date = date.local();
       }
 

+ 1 - 10
src/index.html

@@ -20,7 +20,7 @@
 
   <body ng-cloak body-class>
 
-    <link rel="stylesheet" href="css/bootstrap.light.min.css" ng-if="dashboard.current.style === 'light'">
+    <link rel="stylesheet" href="css/bootstrap.light.min.css" ng-if="dashboard.style === 'light'">
     <link rel="stylesheet" href="css/bootstrap-responsive.min.css">
     <link rel="stylesheet" href="css/font-awesome.min.css">
 
@@ -28,15 +28,6 @@
       <button type="button" class="close" ng-click="dashAlerts.clear(alert)" style="padding-right:50px">&times;</button>
       <strong>{{alert.title}}</strong> <span ng-bind-html='alert.text'></span> <div style="padding-right:10px" class='pull-right small'> {{$index + 1}} alert(s) </div>
     </div>
-    <div class="navbar navbar-static-top">
-      <div class="navbar-inner">
-        <div class="container-fluid">
-          <span class="brand"><img src="img/small.png" bs-tooltip="'Grafana'" data-placement="bottom"> {{dashboard.current.title}}</span>
-          <ul class="nav pull-right" ng-controller='dashLoader' ng-init="init()" ng-include="'app/partials/dashLoader.html'">
-          </ul>
-        </div>
-      </div>
-    </div>
 
     <div ng-view ng-class="{'dashboard-fullscreen': fullscreen}"></div>