Przeglądaj źródła

SharePanelModal: working on share feature, #864

Torkel Ödegaard 11 lat temu
rodzic
commit
2c85205259

+ 21 - 0
.jsfmtrc

@@ -0,0 +1,21 @@
+{
+  "preset" : "default",
+
+  "lineBreak" : {
+    "before" : {
+      "VariableDeclarationWithoutInit" : 0,
+    },
+
+    "after": {
+      "AssignmentOperator": -1,
+      "ArgumentListArrayExpression": ">=1"
+    }
+  },
+
+  "whiteSpace" : {
+    "before" : {
+    },
+    "after" : {
+    }
+  }
+}

+ 46 - 13
src/app/controllers/sharePanelCtrl.js

@@ -11,31 +11,64 @@ function (angular, _) {
 
     $scope.init = function() {
       $scope.editor = { index: 0 };
+      $scope.forCurrent = true;
+      $scope.toPanel = true;
+
+      $scope.buildUrl();
+    };
+
+    $scope.buildUrl = function() {
+      var baseUrl = $location.absUrl();
+      var queryStart = baseUrl.indexOf('?');
+
+      if (queryStart !== -1) {
+        baseUrl = baseUrl.substring(0, queryStart);
+      }
 
-      var currentUrl = $location.absUrl();
       var panelId = $scope.panel.id;
       var range = timeSrv.timeRange(false);
-      var from = range.from;
-      var to = range.to;
-      if (_.isDate(from)) {
-        from = from.getTime();
+      var params = $location.search();
+
+      if (_.isString(range.to) && range.to.indexOf('now')) {
+        range = timeSrv.timeRange();
+      }
+
+      params.from = range.from;
+      params.to = range.to;
+
+      if (_.isDate(params.from)) { params.from = params.from.getTime(); }
+      if (_.isDate(params.to)) { params.to = params.to.getTime(); }
+
+      if (!$scope.forCurrent) {
+        delete params.from;
+        delete params.to;
       }
-      if (_.isDate(to)) {
-        to = to.getTime();
+
+      if ($scope.toPanel) {
+        params.panelId = panelId;
+        params.fullscreen = true;
+      } else {
+        delete params.panelId;
+        delete params.fullscreen;
       }
 
-      $scope.shareUrl = currentUrl + "?panelId=" + panelId + "&fullscreen";
-      $scope.shareUrl += "&from=" + from;
-      $scope.shareUrl += "&to=" + to;
+      var paramsArray = [];
+      _.each(params, function(value, key) {
+        var str = key;
+        if (value !== true) {
+          str += '=' + encodeURIComponent(value);
+        }
+        paramsArray.push(str);
+      });
 
-      $scope.forCurrent = true;
-      $scope.toPanel = true;
+      $scope.shareUrl = baseUrl + "?" + paramsArray.join('&') ;
 
       $timeout(function() {
         var input = $element.find('[data-share-panel-url]');
         input.focus();
         input.select();
-      });
+      }, 10);
+
     };
 
     $scope.init();

+ 0 - 1
src/app/partials/dasheditor.html

@@ -39,7 +39,6 @@
 						</bootstrap-tagsinput>
 						<tip>Press enter to a add tag</tip>
 					</div>
-
 				</div>
 			</div>
 		</div>

+ 4 - 3
src/app/partials/share-panel.html

@@ -15,13 +15,14 @@
 	</div>
 
 	<div class="modal-body">
+
 		<div class="editor-row">
-			<editor-opt-bool name="currentTime" text="Current time range" model="forCurrent"></editor-opt-bool>
-			<editor-opt-bool name="toPanel" text="To this panel only" model="toPanel"></editor-opt-bool>
+			<editor-opt-bool name="currentTime" text="Current time range" model="forCurrent" change="buildUrl()"></editor-opt-bool>
+			<editor-opt-bool name="toPanel" text="To this panel only" model="toPanel" change="buildUrl()"></editor-opt-bool>
 		</div>
 
 		<div class="editor-row" style="margin-top: 20px;">
-			<input type="text" data-share-panel-url ng-model="shareUrl" class="input input-fluid"></input>
+			<input type="text" data-share-panel-url class="input input-fluid" ng-model='shareUrl'></input>
 		</div>
 	</div>
 

+ 97 - 95
src/config.sample.js

@@ -2,108 +2,110 @@
 // config.js is where you will find the core Grafana configuration. This file contains parameter that
 // must be set before Grafana is run for the first time.
 
-define(['settings'],
-function (Settings) {
+define(['settings'], function(Settings) {
   "use strict";
 
   return new Settings({
 
-    /* Data sources
-    * ========================================================
-    * Datasources are used to fetch metrics, annotations, and serve as dashboard storage
-    *  - You can have multiple of the same type.
-    *  - grafanaDB: true    marks it for use for dashboard storage
-    *  - default: true      marks the datasource as the default metric source (if you have multiple)
-    *  - basic authentication: use url syntax http://username:password@domain:port
-    */
-
-    // InfluxDB example setup (the InfluxDB databases specified need to exist)
-    /*
-    datasources: {
-      influxdb: {
-        type: 'influxdb',
-        url: "http://my_influxdb_server:8086/db/database_name",
-        username: 'admin',
-        password: 'admin',
+      /* Data sources
+      * ========================================================
+      * Datasources are used to fetch metrics, annotations, and serve as dashboard storage
+      *  - You can have multiple of the same type.
+      *  - grafanaDB: true    marks it for use for dashboard storage
+      *  - default: true      marks the datasource as the default metric source (if you have multiple)
+      *  - basic authentication: use url syntax http://username:password@domain:port
+      */
+
+      // InfluxDB example setup (the InfluxDB databases specified need to exist)
+      /*
+      datasources: {
+        influxdb: {
+          type: 'influxdb',
+          url: "http://my_influxdb_server:8086/db/database_name",
+          username: 'admin',
+          password: 'admin',
+        },
+        grafana: {
+          type: 'influxdb',
+          url: "http://my_influxdb_server:8086/db/grafana",
+          username: 'admin',
+          password: 'admin',
+          grafanaDB: true
+        },
       },
-      grafana: {
-        type: 'influxdb',
-        url: "http://my_influxdb_server:8086/db/grafana",
-        username: 'admin',
-        password: 'admin',
-        grafanaDB: true
+      */
+
+      // Graphite & Elasticsearch example setup
+      /*
+      datasources: {
+        graphite: {
+          type: 'graphite',
+          url: "http://my.graphite.server.com:8080",
+        },
+        elasticsearch: {
+          type: 'elasticsearch',
+          url: "http://my.elastic.server.com:9200",
+          index: 'grafana-dash',
+          grafanaDB: true,
+        }
       },
-    },
-    */
-
-    // Graphite & Elasticsearch example setup
-    /*
-    datasources: {
-      graphite: {
-        type: 'graphite',
-        url: "http://my.graphite.server.com:8080",
+      */
+
+      // OpenTSDB & Elasticsearch example setup
+      /*
+      datasources: {
+        opentsdb: {
+          type: 'opentsdb',
+          url: "http://opentsdb.server:4242",
+        },
+        elasticsearch: {
+          type: 'elasticsearch',
+          url: "http://my.elastic.server.com:9200",
+          index: 'grafana-dash',
+          grafanaDB: true,
+        }
       },
-      elasticsearch: {
-        type: 'elasticsearch',
-        url: "http://my.elastic.server.com:9200",
-        index: 'grafana-dash',
-        grafanaDB: true,
-      }
-    },
-    */
-
-    // OpenTSDB & Elasticsearch example setup
-    /*
-    datasources: {
-      opentsdb: {
-        type: 'opentsdb',
-        url: "http://opentsdb.server:4242",
+      */
+
+      /* Global configuration options
+      * ========================================================
+      */
+
+      // specify the limit for dashboard search results
+      search: {
+        max_results: 20
       },
-      elasticsearch: {
-        type: 'elasticsearch',
-        url: "http://my.elastic.server.com:9200",
-        index: 'grafana-dash',
-        grafanaDB: true,
+
+      // default home dashboard
+      default_route: '/dashboard/file/default.json',
+
+      // set to false to disable unsaved changes warning
+      unsaved_changes_warning: true,
+
+      // set the default timespan for the playlist feature
+      // Example: "1m", "1h"
+      playlist_timespan: "1m",
+
+      // If you want to specify password before saving, please specify it below
+      // The purpose of this password is not security, but to stop some users from accidentally changing dashboards
+      admin: {
+        password: ''
+      },
+
+      // Change window title prefix from 'Grafana - <dashboard title>'
+      window_title_prefix: 'Grafana - ',
+
+      // Add your own custom panels
+      plugins: {
+        // list of plugin panels
+        panels: [],
+        // requirejs modules in plugins folder that should be loaded
+        // for example custom datasources
+        dependencies: [],
       }
-    },
-    */
-
-    /* Global configuration options
-    * ========================================================
-    */
-
-    // specify the limit for dashboard search results
-    search: {
-      max_results: 20
-    },
-
-    // default home dashboard
-    default_route: '/dashboard/file/default.json',
-
-    // set to false to disable unsaved changes warning
-    unsaved_changes_warning: true,
-
-    // set the default timespan for the playlist feature
-    // Example: "1m", "1h"
-    playlist_timespan: "1m",
-
-    // If you want to specify password before saving, please specify it below
-    // The purpose of this password is not security, but to stop some users from accidentally changing dashboards
-    admin: {
-      password: ''
-    },
-
-    // Change window title prefix from 'Grafana - <dashboard title>'
-    window_title_prefix: 'Grafana - ',
-
-    // Add your own custom panels
-    plugins: {
-      // list of plugin panels
-      panels: [],
-      // requirejs modules in plugins folder that should be loaded
-      // for example custom datasources
-      dependencies: [],
-    }
-
-  });
+
+    });
 });
+
+
+

+ 2 - 0
src/css/less/forms.less

@@ -2,6 +2,8 @@ input[type=text].input-fluid {
   width: 100%;
   box-sizing: border-box;
   padding: 14px;
+  -moz-box-sizing: border-box;
+  height: 100%;
 }
 
 input[type="checkbox"].cr1 {

+ 8 - 2
src/test/specs/helpers.js

@@ -8,6 +8,7 @@ define([
     var self = this;
 
     this.datasource = {};
+    this.$element = {};
     this.annotationsSrv = {};
     this.timeSrv = new TimeSrvStub();
     this.templateSrv = new TemplateSrvStub();
@@ -16,18 +17,23 @@ define([
       get: function() { return self.datasource; }
     };
 
-    this.providePhase = function() {
+    this.providePhase = function(mocks) {
       return module(function($provide) {
         $provide.value('datasourceSrv', self.datasourceSrv);
         $provide.value('annotationsSrv', self.annotationsSrv);
         $provide.value('timeSrv', self.timeSrv);
         $provide.value('templateSrv', self.templateSrv);
+        $provide.value('$element', self.$element);
+        _.each(mocks, function(key, value) {
+          $provide.value(key, value);
+        });
       });
     };
 
     this.createControllerPhase = function(controllerName) {
-      return inject(function($controller, $rootScope, $q) {
+      return inject(function($controller, $rootScope, $q, $location) {
         self.scope = $rootScope.$new();
+        self.$location = $location;
         self.scope.panel = {};
         self.scope.row = { panels:[] };
         self.scope.dashboard = {};

+ 59 - 0
src/test/specs/sharePanelCtrl-specs.js

@@ -0,0 +1,59 @@
+define([
+  './helpers',
+  'controllers/sharePanelCtrl'
+], function(helpers) {
+  'use strict';
+
+  describe('SharePanelCtrl', function() {
+    var ctx = new helpers.ControllerTestContext();
+
+    beforeEach(module('grafana.controllers'));
+
+    beforeEach(ctx.providePhase());
+    beforeEach(ctx.createControllerPhase('SharePanelCtrl'));
+
+    describe('shareUrl with current time range and panel', function() {
+
+      it('should generate share url relative time', function() {
+        ctx.$location.path('/test');
+        ctx.scope.panel = { id: 22 };
+        ctx.timeSrv.time = { from: 'now-1h', to: 'now' };
+
+        ctx.scope.buildUrl();
+        expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now&panelId=22&fullscreen');
+      });
+
+      it('should generate share url absolute time', function() {
+        ctx.$location.path('/test');
+        ctx.scope.panel = { id: 22 };
+        ctx.timeSrv.time = { from: new Date(2012,1,1), to: new Date(2014,3,5) };
+
+        ctx.scope.buildUrl();
+        expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=1328050800000&to=1396648800000&panelId=22&fullscreen');
+      });
+
+      it('should generate share url with time as JSON strings', function() {
+        ctx.$location.path('/test');
+        ctx.scope.panel = { id: 22 };
+        ctx.timeSrv.time = { from: new Date(2012,1,1).toJSON(), to: new Date(2014,3,5).toJSON() };
+
+        ctx.scope.buildUrl();
+        expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=1328050800000&to=1396648800000&panelId=22&fullscreen');
+      });
+
+      it('should remove panel id when toPanel is false', function() {
+        ctx.$location.path('/test');
+        ctx.scope.panel = { id: 22 };
+        ctx.scope.toPanel = false;
+        ctx.timeSrv.time = { from: 'now-1h', to: 'now' };
+
+        ctx.scope.buildUrl();
+        expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now');
+      });
+
+    });
+
+  });
+
+});
+

+ 1 - 0
src/test/test-main.js

@@ -131,6 +131,7 @@ require([
     'specs/grafanaGraph-specs',
     'specs/graph-tooltip-specs',
     'specs/seriesOverridesCtrl-specs',
+    'specs/sharePanelCtrl-specs',
     'specs/timeSrv-specs',
     'specs/templateSrv-specs',
     'specs/templateValuesSrv-specs',