Commit e0c9ddbf by Torkel Ödegaard

Worked on variable initilization and sync to from url, #772

parent bbc5dae1
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
- [Issue #262](https://github.com/grafana/grafana/issues/262). Templating: Ability to use template variables for function parameters via custom variable type, can be used as parameter for movingAverage or scaleToSeconds for example - [Issue #262](https://github.com/grafana/grafana/issues/262). Templating: Ability to use template variables for function parameters via custom variable type, can be used as parameter for movingAverage or scaleToSeconds for example
- [Issue #312](https://github.com/grafana/grafana/issues/312). Templating: Can now use template variables in panel titles - [Issue #312](https://github.com/grafana/grafana/issues/312). Templating: Can now use template variables in panel titles
- [Issue #613](https://github.com/grafana/grafana/issues/613). Templating: Full support for InfluxDB, filter by part of series names, extract series substrings, nested queries, multipe where clauses! - [Issue #613](https://github.com/grafana/grafana/issues/613). Templating: Full support for InfluxDB, filter by part of series names, extract series substrings, nested queries, multipe where clauses!
- Template variables can be initialized from url, with var-my_varname=value, breaking change, before it was just my_varname.
- Templating and url state sync has some issues that are not solved for this release, see [Issue #772](https://github.com/grafana/grafana/issues/772) for more details.
**InfluxDB Breaking changes** **InfluxDB Breaking changes**
- To better support templating, fill(0) and group by time low limit some changes has been made to the editor and query model schema - To better support templating, fill(0) and group by time low limit some changes has been made to the editor and query model schema
......
...@@ -51,7 +51,7 @@ function (angular, $, config, _) { ...@@ -51,7 +51,7 @@ function (angular, $, config, _) {
// init services // init services
timeSrv.init($scope.dashboard); timeSrv.init($scope.dashboard);
templateValuesSrv.init($scope.dashboard); templateValuesSrv.init($scope.dashboard, $scope.dashboardViewState);
panelMoveSrv.init($scope.dashboard, $scope); panelMoveSrv.init($scope.dashboard, $scope);
$scope.checkFeatureToggles(); $scope.checkFeatureToggles();
......
...@@ -94,7 +94,7 @@ function (angular, app, _, $) { ...@@ -94,7 +94,7 @@ function (angular, app, _, $) {
}; };
$input.attr('data-provide', 'typeahead'); $input.attr('data-provide', 'typeahead');
$input.typeahead({ source: $scope.source, minLength: 0, items: 100, updater: $scope.updater }); $input.typeahead({ source: $scope.source, minLength: 0, items: 10000, updater: $scope.updater });
var typeahead = $input.data('typeahead'); var typeahead = $input.data('typeahead');
typeahead.lookup = function () { typeahead.lookup = function () {
......
...@@ -14,9 +14,12 @@ function (angular, _, $) { ...@@ -14,9 +14,12 @@ function (angular, _, $) {
// like fullscreen panel & edit // like fullscreen panel & edit
function DashboardViewState($scope) { function DashboardViewState($scope) {
var self = this; var self = this;
self.state = {};
self.panelScopes = [];
self.$scope = $scope;
$scope.exitFullscreen = function() { $scope.exitFullscreen = function() {
if (self.fullscreen) { if (self.state.fullscreen) {
self.update({ fullscreen: false }); self.update({ fullscreen: false });
} }
}; };
...@@ -28,42 +31,48 @@ function (angular, _, $) { ...@@ -28,42 +31,48 @@ function (angular, _, $) {
} }
}); });
this.panelScopes = [];
this.$scope = $scope;
this.update(this.getQueryStringState(), true); this.update(this.getQueryStringState(), true);
} }
DashboardViewState.prototype.needsSync = function(urlState) { DashboardViewState.prototype.needsSync = function(urlState) {
if (urlState.fullscreen !== this.fullscreen) { return true; } return _.isEqual(this.state, urlState) === false;
if (urlState.edit !== this.edit) { return true; }
if (urlState.panelId !== this.panelId) { return true; }
return false;
}; };
DashboardViewState.prototype.getQueryStringState = function() { DashboardViewState.prototype.getQueryStringState = function() {
var queryParams = $location.search(); var queryParams = $location.search();
return { var urlState = {
panelId: parseInt(queryParams.panelId) || null, panelId: parseInt(queryParams.panelId) || null,
fullscreen: queryParams.fullscreen ? true : false, fullscreen: queryParams.fullscreen ? true : false,
edit: queryParams.edit ? true : false edit: queryParams.edit ? true : false,
}; };
_.each(queryParams, function(value, key) {
if (key.indexOf('var-') !== 0) { return; }
urlState[key] = value;
});
return urlState;
};
DashboardViewState.prototype.serializeToUrl = function() {
var urlState = _.clone(this.state);
urlState.fullscreen = this.state.fullscreen ? true : null,
urlState.edit = this.state.edit ? true : null;
return urlState;
}; };
DashboardViewState.prototype.update = function(state, skipUrlSync) { DashboardViewState.prototype.update = function(state, skipUrlSync) {
_.extend(this, state); _.extend(this.state, state);
this.fullscreen = this.state.fullscreen;
if (!this.fullscreen) { if (!this.state.fullscreen) {
this.panelId = null; this.state.panelId = null;
this.edit = false; this.state.edit = false;
} }
if (!skipUrlSync) { if (!skipUrlSync) {
$location.search({ $location.search(this.serializeToUrl());
fullscreen: this.fullscreen ? true : null,
panelId: this.panelId,
edit: this.edit ? true : null
});
} }
this.syncState(); this.syncState();
...@@ -76,7 +85,7 @@ function (angular, _, $) { ...@@ -76,7 +85,7 @@ function (angular, _, $) {
if (this.fullscreenPanel) { if (this.fullscreenPanel) {
this.leaveFullscreen(false); this.leaveFullscreen(false);
} }
var panelScope = this.getPanelScope(this.panelId); var panelScope = this.getPanelScope(this.state.panelId);
this.enterFullscreen(panelScope); this.enterFullscreen(panelScope);
return; return;
} }
...@@ -118,8 +127,8 @@ function (angular, _, $) { ...@@ -118,8 +127,8 @@ function (angular, _, $) {
var fullscreenHeight = Math.floor(docHeight * 0.7); var fullscreenHeight = Math.floor(docHeight * 0.7);
this.oldTimeRange = panelScope.range; this.oldTimeRange = panelScope.range;
panelScope.height = this.edit ? editHeight : fullscreenHeight; panelScope.height = this.state.edit ? editHeight : fullscreenHeight;
panelScope.editMode = this.edit; panelScope.editMode = this.state.edit;
this.fullscreenPanel = panelScope; this.fullscreenPanel = panelScope;
$(window).scrollTop(0); $(window).scrollTop(0);
...@@ -135,7 +144,7 @@ function (angular, _, $) { ...@@ -135,7 +144,7 @@ function (angular, _, $) {
var self = this; var self = this;
self.panelScopes.push(panelScope); self.panelScopes.push(panelScope);
if (self.panelId === panelScope.panel.id) { if (self.state.panelId === panelScope.panel.id) {
self.enterFullscreen(panelScope); self.enterFullscreen(panelScope);
} }
......
...@@ -7,7 +7,7 @@ function (angular, _) { ...@@ -7,7 +7,7 @@ function (angular, _) {
var module = angular.module('grafana.services'); var module = angular.module('grafana.services');
module.service('templateSrv', function($q, $routeParams) { module.service('templateSrv', function() {
var self = this; var self = this;
this._regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g; this._regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
...@@ -19,17 +19,10 @@ function (angular, _) { ...@@ -19,17 +19,10 @@ function (angular, _) {
this.updateTemplateData(true); this.updateTemplateData(true);
}; };
this.updateTemplateData = function(initial) { this.updateTemplateData = function() {
var data = {}; var data = {};
_.each(this.variables, function(variable) { _.each(this.variables, function(variable) {
if (initial) {
var urlValue = $routeParams[ variable.name ];
if (urlValue) {
variable.current = { text: urlValue, value: urlValue };
}
}
if (!variable.current || !variable.current.value) { if (!variable.current || !variable.current.value) {
return; return;
} }
...@@ -50,6 +43,10 @@ function (angular, _) { ...@@ -50,6 +43,10 @@ function (angular, _) {
return match && (self._templateData[match[1] || match[2]] !== void 0); return match && (self._templateData[match[1] || match[2]] !== void 0);
}; };
this.containsVariable = function(str, variableName) {
return str.indexOf('$' + variableName) !== -1 || str.indexOf('[[' + variableName + ']]') !== -1;
};
this.highlightVariablesAsHtml = function(str) { this.highlightVariablesAsHtml = function(str) {
if (!str || !_.isString(str)) { return str; } if (!str || !_.isString(str)) { return str; }
......
...@@ -18,17 +18,24 @@ function (angular, _, kbn) { ...@@ -18,17 +18,24 @@ function (angular, _, kbn) {
} }
}); });
this.init = function(dashboard) { this.init = function(dashboard, viewstate) {
this.variables = dashboard.templating.list; this.variables = dashboard.templating.list;
this.viewstate = viewstate;
templateSrv.init(this.variables); templateSrv.init(this.variables);
for (var i = 0; i < this.variables.length; i++) { for (var i = 0; i < this.variables.length; i++) {
var param = this.variables[i]; var variable = this.variables[i];
if (param.refresh) { var urlValue = viewstate.state['var-' + variable.name];
this.updateOptions(param); if (urlValue !== void 0) {
var option = _.findWhere(variable.options, { text: urlValue });
option = option || { text: urlValue, value: urlValue };
this.setVariableValue(variable, option, true);
} }
else if (param.type === 'interval') { else if (variable.refresh) {
this.updateAutoInterval(param); this.updateOptions(variable);
}
else if (variable.type === 'interval') {
this.updateAutoInterval(variable);
} }
} }
}; };
...@@ -63,7 +70,7 @@ function (angular, _, kbn) { ...@@ -63,7 +70,7 @@ function (angular, _, kbn) {
if (otherVariable === updatedVariable) { if (otherVariable === updatedVariable) {
return; return;
} }
if (otherVariable.query.indexOf('[[' + updatedVariable.name + ']]') !== -1) { if (templateSrv.containsVariable(otherVariable.query, updatedVariable.name)) {
return self.updateOptions(otherVariable); return self.updateOptions(otherVariable);
} }
}); });
...@@ -92,7 +99,6 @@ function (angular, _, kbn) { ...@@ -92,7 +99,6 @@ function (angular, _, kbn) {
var datasource = datasourceSrv.get(variable.datasource); var datasource = datasourceSrv.get(variable.datasource);
return datasource.metricFindQuery(variable.query) return datasource.metricFindQuery(variable.query)
.then(function (results) { .then(function (results) {
variable.options = self.metricNamesToVariableValues(variable, results); variable.options = self.metricNamesToVariableValues(variable, results);
if (variable.includeAll) { if (variable.includeAll) {
...@@ -102,7 +108,7 @@ function (angular, _, kbn) { ...@@ -102,7 +108,7 @@ function (angular, _, kbn) {
// if parameter has current value // if parameter has current value
// if it exists in options array keep value // if it exists in options array keep value
if (variable.current) { if (variable.current) {
var currentExists = _.findWhere(variable.options, { value: variable.current.value }); var currentExists = _.findWhere(variable.options, { text: variable.current.text });
if (currentExists) { if (currentExists) {
return self.setVariableValue(variable, variable.current, true); return self.setVariableValue(variable, variable.current, true);
} }
......
...@@ -516,6 +516,11 @@ div.flot-text { ...@@ -516,6 +516,11 @@ div.flot-text {
} }
} }
// typeahead max height
.typeahead {
max-height: 300px;
overflow-y: auto;
}
// Labels & Badges // Labels & Badges
.label-tag { .label-tag {
......
...@@ -20,6 +20,7 @@ define([ ...@@ -20,6 +20,7 @@ define([
viewState.update(updateState); viewState.update(updateState);
expect(location.search()).to.eql(updateState); expect(location.search()).to.eql(updateState);
expect(viewState.fullscreen).to.be(true); expect(viewState.fullscreen).to.be(true);
expect(viewState.state.fullscreen).to.be(true);
}); });
}); });
...@@ -29,6 +30,7 @@ define([ ...@@ -29,6 +30,7 @@ define([
viewState.update({fullscreen: false}); viewState.update({fullscreen: false});
expect(location.search()).to.eql({}); expect(location.search()).to.eql({});
expect(viewState.fullscreen).to.be(false); expect(viewState.fullscreen).to.be(false);
expect(viewState.state.fullscreen).to.be(false);
}); });
}); });
......
...@@ -62,6 +62,24 @@ define([ ...@@ -62,6 +62,24 @@ define([
}); });
describe('when checking if a string contains a variable', function() {
beforeEach(function() {
_templateSrv.init([{ name: 'test', current: { value: 'muuuu' } }]);
_templateSrv.updateTemplateData();
});
it('should find it with $var syntax', function() {
var contains = _templateSrv.containsVariable('this.$test.filters', 'test');
expect(contains).to.be(true);
});
it('should find it with [[var]] syntax', function() {
var contains = _templateSrv.containsVariable('this.[[test]].filters', 'test');
expect(contains).to.be(true);
});
});
describe('updateTemplateData with simple value', function() { describe('updateTemplateData with simple value', function() {
beforeEach(function() { beforeEach(function() {
_templateSrv.init([{ name: 'test', current: { value: 'muuuu' } }]); _templateSrv.init([{ name: 'test', current: { value: 'muuuu' } }]);
......
...@@ -27,20 +27,6 @@ define([ ...@@ -27,20 +27,6 @@ define([
}); });
}); });
describe.only('should init values', function() {
var variables = [
{ name: 'test', current: { value: 'hej' }}
];
var dashboard = { templating: { list: variables } };
beforeEach(function() {
ctx.service.init(dashboard);
});
it('should update options array', function() {
});
});
function describeUpdateVariable(desc, fn) { function describeUpdateVariable(desc, fn) {
describe(desc, function() { describe(desc, function() {
var scenario = {}; var scenario = {};
...@@ -139,12 +125,12 @@ define([ ...@@ -139,12 +125,12 @@ define([
describeUpdateVariable('and existing value still exists in options', function(scenario) { describeUpdateVariable('and existing value still exists in options', function(scenario) {
scenario.setup(function() { scenario.setup(function() {
scenario.variable = { type: 'query', query: 'apps.*', name: 'test' }; scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
scenario.variable.current = { value: 'backend2'}; scenario.variable.current = { text: 'backend2'};
scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}]; scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
}); });
it('should keep variable value', function() { it('should keep variable value', function() {
expect(scenario.variable.current.value).to.be('backend2'); expect(scenario.variable.current.text).to.be('backend2');
}); });
}); });
...@@ -196,18 +182,6 @@ define([ ...@@ -196,18 +182,6 @@ define([
}); });
}); });
describeUpdateVariable('and existing value still exists in options', function(scenario) {
scenario.setup(function() {
scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
scenario.variable.current = { value: 'backend2'};
scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
});
it('should keep variable value', function() {
expect(scenario.variable.current.value).to.be('backend2');
});
});
describeUpdateVariable('with include All glob syntax', function(scenario) { describeUpdateVariable('with include All glob syntax', function(scenario) {
scenario.setup(function() { scenario.setup(function() {
scenario.variable = { type: 'query', query: 'apps.*', name: 'test', includeAll: true, allFormat: 'glob' }; scenario.variable = { type: 'query', query: 'apps.*', name: 'test', includeAll: true, allFormat: 'glob' };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment