Prechádzať zdrojové kódy

Merge branch 'master' into export-dashboard

Conflicts:
	public/app/features/dashboard/submenu/submenu.ts
Torkel Ödegaard 9 rokov pred
rodič
commit
e83d13848e

+ 1 - 0
pkg/api/api.go

@@ -117,6 +117,7 @@ func Register(r *macaron.Macaron) {
 			r.Get("/:id", wrap(GetUserById))
 			r.Get("/:id/orgs", wrap(GetUserOrgList))
 			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
+			r.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg))
 		}, reqGrafanaAdmin)
 
 		// org information available to all users.

+ 7 - 0
pkg/api/dataproxy.go

@@ -55,6 +55,13 @@ func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *ht
 			req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.BasicAuthUser, ds.BasicAuthPassword))
 		}
 
+		dsAuth := req.Header.Get("X-DS-Authorization")
+		if len(dsAuth) > 0 {
+			req.Header.Del("X-DS-Authorization")
+			req.Header.Del("Authorization")
+			req.Header.Add("Authorization", dsAuth)
+		}
+
 		// clear cookie headers
 		req.Header.Del("Cookie")
 		req.Header.Del("Set-Cookie")

+ 18 - 0
pkg/api/user.go

@@ -40,6 +40,24 @@ func UpdateUser(c *middleware.Context, cmd m.UpdateUserCommand) Response {
 	return handleUpdateUser(cmd)
 }
 
+//POST /api/users/:id/using/:orgId
+func UpdateUserActiveOrg(c *middleware.Context) Response {
+	userId := c.ParamsInt64(":id")
+	orgId := c.ParamsInt64(":orgId")
+
+	if !validateUsingOrg(userId, orgId) {
+		return ApiError(401, "Not a valid organization", nil)
+	}
+
+	cmd := m.SetUsingOrgCommand{UserId: userId, OrgId: orgId}
+
+	if err := bus.Dispatch(&cmd); err != nil {
+		return ApiError(500, "Failed change active organization", err)
+	}
+
+	return ApiSuccess("Active organization changed")
+}
+
 func handleUpdateUser(cmd m.UpdateUserCommand) Response {
 	if len(cmd.Login) == 0 {
 		cmd.Login = cmd.Email

+ 5 - 0
public/app/core/services/backend_srv.js

@@ -96,6 +96,11 @@ function (angular, _, coreModule, config) {
       var requestIsLocal = options.url.indexOf('/') === 0;
       var firstAttempt = options.retry === 0;
 
+      if (requestIsLocal && options.headers && options.headers.Authorization) {
+        options.headers['X-DS-Authorization'] = options.headers.Authorization;
+        delete options.headers.Authorization;
+      }
+
       return $http(options).then(null, function(err) {
         // handle unauthorized for backend requests
         if (requestIsLocal && firstAttempt  && err.status === 401) {

+ 0 - 17
public/app/features/dashboard/submenu/submenu.ts

@@ -26,25 +26,8 @@ export class SubmenuCtrl {
     return this.templateValuesSrv.getValuesForTag(variable, tagKey);
   }
 
-  updateUrlParamsWithCurrentVariables() {
-    // update url
-    var params = this.$location.search();
-    // remove variable params
-    _.each(params, function(value, key) {
-      if (key.indexOf('var-') === 0) {
-        delete params[key];
-      }
-    });
-
-    // add new values
-    this.templateSrv.fillVariableValuesForUrl(params);
-    // update url
-    this.$location.search(params);
-  }
-
   variableUpdated(variable) {
     this.templateValuesSrv.variableUpdated(variable).then(() => {
-      this.updateUrlParamsWithCurrentVariables();
       this.$rootScope.$emit('template-variable-value-updated');
       this.$rootScope.$broadcast('refresh');
     });

+ 1 - 8
public/app/features/dashboard/timeSrv.js

@@ -10,7 +10,7 @@ define([
 
   var module = angular.module('grafana.services');
 
-  module.service('timeSrv', function($rootScope, $timeout, $routeParams, timer, $location) {
+  module.service('timeSrv', function($rootScope, $timeout, $routeParams, timer) {
     var self = this;
 
     this.init = function(dashboard) {
@@ -108,13 +108,6 @@ define([
         this.old_refresh = null;
       }
 
-      // update url params
-      var urlParams = $location.search();
-      var urlRange = this.timeRangeForUrl();
-      urlParams.from = urlRange.from;
-      urlParams.to = urlRange.to;
-      $location.search(urlParams);
-
       $rootScope.appEvent('time-range-changed', this.time);
       $timeout(this.refreshDashboard, 0);
     };

+ 35 - 7
public/app/features/dashboard/viewStateSrv.js

@@ -8,7 +8,7 @@ function (angular, _, $) {
 
   var module = angular.module('grafana.services');
 
-  module.factory('dashboardViewStateSrv', function($location, $timeout) {
+  module.factory('dashboardViewStateSrv', function($location, $timeout, templateSrv, contextSrv, timeSrv) {
 
     // represents the transient view state
     // like fullscreen panel & edit
@@ -25,6 +25,19 @@ function (angular, _, $) {
         }
       };
 
+      // update url on time range change
+      $scope.onAppEvent('time-range-changed', function() {
+        var urlParams = $location.search();
+        var urlRange = timeSrv.timeRangeForUrl();
+        urlParams.from = urlRange.from;
+        urlParams.to = urlRange.to;
+        $location.search(urlParams);
+      });
+
+      $scope.onAppEvent('template-variable-value-updated', function() {
+        self.updateUrlParamsWithCurrentVariables();
+      });
+
       $scope.onAppEvent('$routeUpdate', function() {
         var urlState = self.getQueryStringState();
         if (self.needsSync(urlState)) {
@@ -40,10 +53,26 @@ function (angular, _, $) {
         self.registerPanel(payload.scope);
       });
 
-      this.update(this.getQueryStringState(), true);
+      this.update(this.getQueryStringState());
       this.expandRowForPanel();
     }
 
+    DashboardViewState.prototype.updateUrlParamsWithCurrentVariables = function() {
+      // update url
+      var params = $location.search();
+      // remove variable params
+      _.each(params, function(value, key) {
+        if (key.indexOf('var-') === 0) {
+          delete params[key];
+        }
+      });
+
+      // add new values
+      templateSrv.fillVariableValuesForUrl(params);
+      // update url
+      $location.search(params);
+    };
+
     DashboardViewState.prototype.expandRowForPanel = function() {
       if (!this.state.panelId) { return; }
 
@@ -63,6 +92,7 @@ function (angular, _, $) {
       state.fullscreen = state.fullscreen ? true : null;
       state.edit =  (state.edit === "true" || state.edit === true) || null;
       state.editview = state.editview || null;
+      state.org = contextSrv.user.orgId;
       return state;
     };
 
@@ -70,10 +100,11 @@ function (angular, _, $) {
       var urlState = _.clone(this.state);
       urlState.fullscreen = this.state.fullscreen ? true : null;
       urlState.edit = this.state.edit ? true : null;
+      urlState.org = contextSrv.user.orgId;
       return urlState;
     };
 
-    DashboardViewState.prototype.update = function(state, skipUrlSync) {
+    DashboardViewState.prototype.update = function(state) {
       _.extend(this.state, state);
       this.dashboard.meta.fullscreen = this.state.fullscreen;
 
@@ -83,10 +114,7 @@ function (angular, _, $) {
         this.state.edit = null;
       }
 
-      if (!skipUrlSync) {
-        $location.search(this.serializeToUrl());
-      }
-
+      $location.search(this.serializeToUrl());
       this.syncState();
     };
 

+ 4 - 8
public/app/features/panel/partials/soloPanel.html

@@ -1,9 +1,5 @@
-<div class="main">
-	<div class="row-fluid">
-		<div class="span12">
-			<div class="panel nospace" ng-if="panel" style="width: 100%">
-				<plugin-component type="panel">
-				</plugin-component>
-			</div>
-		</div>
+<div class="panel nospace" ng-if="panel" style="width: 100%">
+	<plugin-component type="panel">
+	</plugin-component>
 </div>
+<div class="clearfix"></div>

+ 4 - 0
public/app/features/panel/solo_panel_ctrl.js

@@ -17,6 +17,10 @@ function (angular, $) {
       var params = $location.search();
       panelId = parseInt(params.panelId);
 
+      // add fullscreen param;
+      params.fullscreen = true;
+      $location.search(params);
+
       dashboardLoaderSrv.loadDashboard($routeParams.type, $routeParams.slug).then(function(result) {
         $scope.initDashboard(result, $scope);
       });

+ 16 - 12
public/app/features/templating/templateValuesSrv.js

@@ -105,8 +105,6 @@ function (angular, _, kbn) {
           return op.text === urlValue || op.value === urlValue;
         });
 
-        option = option || { text: urlValue, value: urlValue };
-
         self.updateAutoInterval(variable);
         return self.setVariableValue(variable, option, true);
       });
@@ -127,8 +125,8 @@ function (angular, _, kbn) {
     this.setVariableValue = function(variable, option, initPhase) {
       variable.current = angular.copy(option);
 
-      if (_.isArray(variable.current.value)) {
-        variable.current.text = variable.current.value.join(' + ');
+      if (_.isArray(variable.current.text)) {
+        variable.current.text = variable.current.text.join(' + ');
       }
 
       self.selectOptionsForCurrentValue(variable);
@@ -226,6 +224,7 @@ function (angular, _, kbn) {
 
     this.selectOptionsForCurrentValue = function(variable) {
       var i, y, value, option;
+      var selected = [];
 
       for (i = 0; i < variable.options.length; i++) {
         option = variable.options[i];
@@ -235,12 +234,16 @@ function (angular, _, kbn) {
             value = variable.current.value[y];
             if (option.value === value) {
               option.selected = true;
+              selected.push(option);
             }
           }
         } else if (option.value === variable.current.value) {
           option.selected = true;
+          selected.push(option);
         }
       }
+
+      return selected;
     };
 
     this.validateVariableSelectionState = function(variable) {
@@ -250,17 +253,18 @@ function (angular, _, kbn) {
       }
 
       if (_.isArray(variable.current.value)) {
-        self.selectOptionsForCurrentValue(variable);
-        // updated selected value
-        var selected = {
-          value: _.map(_.filter(variable.options, {selected: true}), function(op) {
-            return op.value;
-          })
-        };
+        var selected = self.selectOptionsForCurrentValue(variable);
+
         // if none pick first
-        if (selected.value.length === 0) {
+        if (selected.length === 0) {
           selected = variable.options[0];
+        } else {
+          selected = {
+            value: _.map(selected, function(val) {return val.value;}),
+            text: _.map(selected, function(val) {return val.text;}).join(' + '),
+          };
         }
+
         return self.setVariableValue(variable, selected, false);
       } else {
         var currentOption = _.findWhere(variable.options, {text: variable.current.text});

+ 15 - 3
public/test/specs/dashboardViewStateSrv-specs.js

@@ -5,8 +5,20 @@ define([
 
   describe('when updating view state', function() {
     var viewState, location;
+    var timeSrv = {};
+    var templateSrv = {};
+    var contextSrv = {
+      user: {
+        orgId: 19
+      }
+    };
 
     beforeEach(module('grafana.services'));
+    beforeEach(module(function($provide) {
+      $provide.value('timeSrv', timeSrv);
+      $provide.value('templateSrv', templateSrv);
+      $provide.value('contextSrv', contextSrv);
+    }));
 
     beforeEach(inject(function(dashboardViewStateSrv, $location, $rootScope) {
       $rootScope.onAppEvent = function() {};
@@ -17,9 +29,9 @@ define([
 
     describe('to fullscreen true and edit true', function() {
       it('should update querystring and view state', function() {
-        var updateState = { fullscreen: true, edit: true, panelId: 1 };
+        var updateState = {fullscreen: true, edit: true, panelId: 1};
         viewState.update(updateState);
-        expect(location.search()).to.eql(updateState);
+        expect(location.search()).to.eql({fullscreen: true, edit: true, panelId: 1, org: 19});
         expect(viewState.dashboard.meta.fullscreen).to.be(true);
         expect(viewState.state.fullscreen).to.be(true);
       });
@@ -29,7 +41,7 @@ define([
       it('should remove params from query string', function() {
         viewState.update({fullscreen: true, panelId: 1, edit: true});
         viewState.update({fullscreen: false});
-        expect(location.search()).to.eql({});
+        expect(location.search()).to.eql({org: 19});
         expect(viewState.dashboard.meta.fullscreen).to.be(false);
         expect(viewState.state.fullscreen).to.be(null);
       });

+ 21 - 0
public/test/specs/templateValuesSrv-specs.js

@@ -166,6 +166,27 @@ define([
       });
     });
 
+    describeUpdateVariable('query variable with multi select and $__all selected', function(scenario) {
+      scenario.setup(function() {
+        scenario.variable = {
+          type: 'query',
+          query: '',
+          name: 'test',
+          includeAll: true,
+          current: {
+            value: ['$__all'],
+            text: 'All'
+          }
+        };
+        scenario.queryResult = [{text: 'val5'}, {text: 'val6'}];
+      });
+
+      it('should keep current All value', function() {
+        expect(scenario.variable.current.value).to.eql(['$__all']);
+        expect(scenario.variable.current.text).to.eql('All');
+      });
+    });
+
     describeUpdateVariable('query variable with numeric results', function(scenario) {
       scenario.setup(function() {
         scenario.variable = { type: 'query', query: '', name: 'test', current: {} };

+ 3 - 1
vendor/phantomjs/render.js

@@ -39,7 +39,8 @@
       var canvas = page.evaluate(function() {
         if (!window.angular) { return false; }
         var body = window.angular.element(document.body);
-        if (!body.scope) { return false; }
+        if (!body.injector) { return false; }
+        if (!body.injector()) { return false; }
 
         var rootScope = body.injector().get('$rootScope');
         if (!rootScope) {return false;}
@@ -59,6 +60,7 @@
           width:  bb.width,
           height: bb.height
         };
+
         page.render(params.png);
         phantom.exit();
       }