diff --git a/.jshintrc b/.jshintrc index bca48639a70..510726ee46b 100644 --- a/.jshintrc +++ b/.jshintrc @@ -4,7 +4,7 @@ "bitwise":false, "curly": true, "eqnull": true, - "globalstrict": true, + "strict": true, "devel": true, "eqeqeq": true, "forin": false, @@ -12,7 +12,7 @@ "supernew": true, "expr": true, "indent": 2, - "latedef": true, + "latedef": false, "newcap": true, "noarg": true, "noempty": true, diff --git a/package.json b/package.json index 0df426954d3..a79280c30ba 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "grunt-contrib-copy": "~0.8.2", "grunt-contrib-cssmin": "~0.14.0", "grunt-contrib-htmlmin": "~0.6.0", - "grunt-contrib-jshint": "~0.11.3", + "grunt-contrib-jshint": "~1.0.0", "grunt-contrib-less": "~0.7.0", "grunt-contrib-uglify": "~0.11.0", "grunt-contrib-watch": "^0.6.1", @@ -39,7 +39,7 @@ "grunt-tslint": "^3.0.2", "grunt-typescript": "^0.8.0", "grunt-usemin": "3.0.0", - "jshint-stylish": "~0.1.5", + "jshint-stylish": "~2.1.0", "karma": "~0.13.15", "karma-chrome-launcher": "~0.2.2", "karma-coverage": "0.5.3", diff --git a/public/app/features/templating/templateSrv.js b/public/app/features/templating/templateSrv.js index 1e1ec72b02f..5ccf8a4ec2d 100644 --- a/public/app/features/templating/templateSrv.js +++ b/public/app/features/templating/templateSrv.js @@ -31,31 +31,37 @@ function (angular, _) { }, this); }; - this.regexEscape = function(value) { + function regexEscape(value) { return value.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&'); - }; + } + + function luceneEscape(value) { + return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1"); + } this.formatValue = function(value, format) { - if (_.isString(value)) { - return value; - } else { - switch(format) { - case "regex": { - var escapedValues = _.map(value, this.regexEscape); - return '(' + escapedValues.join('|') + ')'; + switch(format) { + case "regex": { + var escapedValues = _.map(value, regexEscape); + return '(' + escapedValues.join('|') + ')'; + } + case "lucene": { + if (typeof value === 'string') { + return luceneEscape(value); } - case "lucene": { - var quotedValues = _.map(value, function(val) { - return '\\\"' + val + '\\\"'; - }); - return '(' + quotedValues.join(' OR ') + ')'; - } - case "pipe": { - return value.join('|'); - } - default: { - return '{' + value.join(',') + '}'; + var quotedValues = _.map(value, function(val) { + return '\"' + luceneEscape(val) + '\"'; + }); + return '(' + quotedValues.join(' OR ') + ')'; + } + case "pipe": { + return value.join('|'); + } + default: { + if (typeof value === 'string') { + return value; } + return '{' + value.join(',') + '}'; } } }; @@ -114,7 +120,9 @@ function (angular, _) { return self.formatValue(systemValue); } - return self.formatValue(value, format); + var res = self.formatValue(value, format); + console.log('replace: ' + value, res); + return res; }); }; diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index cc721de32ff..b048c206edb 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -47,15 +47,15 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }; this._get = function(url) { - return this._request('GET', this.indexPattern.getIndexForToday() + url) - .then(function(results) { + return this._request('GET', this.indexPattern.getIndexForToday() + url).then(function(results) { + results.data.$$config = results.config; return results.data; }); }; this._post = function(url, data) { - return this._request('POST', url, data) - .then(function(results) { + return this._request('POST', url, data).then(function(results) { + results.data.$$config = results.config; return results.data; }); }; @@ -170,7 +170,10 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes var queryObj = this.queryBuilder.build(target); var esQuery = angular.toJson(queryObj); - var luceneQuery = angular.toJson(target.query || '*'); + var luceneQuery = target.query || '*'; + luceneQuery = templateSrv.replace(luceneQuery, options.scopedVars, 'lucene'); + luceneQuery = angular.toJson(luceneQuery); + // remove inner quotes luceneQuery = luceneQuery.substr(1, luceneQuery.length - 2); esQuery = esQuery.replace("$lucene_query", luceneQuery); @@ -190,7 +193,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes payload = payload.replace(/\$interval/g, options.interval); payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf()); payload = payload.replace(/\$timeTo/g, options.range.to.valueOf()); - payload = templateSrv.replace(payload, options.scopedVars, 'lucene'); + payload = templateSrv.replace(payload, options.scopedVars); return this._post('_msearch', payload).then(function(res) { return new ElasticResponse(sentTargets, res).getTimeSeries(); diff --git a/public/app/plugins/datasource/elasticsearch/elastic_response.js b/public/app/plugins/datasource/elasticsearch/elastic_response.js index 7ae4c204207..99b5af0d737 100644 --- a/public/app/plugins/datasource/elasticsearch/elastic_response.js +++ b/public/app/plugins/datasource/elasticsearch/elastic_response.js @@ -284,13 +284,29 @@ function (_, queryDef) { } }; + ElasticResponse.prototype.getErrorFromElasticResponse = function(response, err) { + var result = {}; + result.data = JSON.stringify(err, null, 4); + if (err.root_cause && err.root_cause.length > 0 && err.root_cause[0].reason) { + result.message = err.root_cause[0].reason; + } else { + result.message = err.reason || 'Unkown elatic error response'; + } + + if (response.$$config) { + result.config = response.$$config; + } + + return result; + }; + ElasticResponse.prototype.getTimeSeries = function() { var seriesList = []; for (var i = 0; i < this.response.responses.length; i++) { var response = this.response.responses[i]; if (response.error) { - throw { message: response.error }; + throw this.getErrorFromElasticResponse(this.response, response.error); } if (response.hits && response.hits.hits.length > 0) { diff --git a/public/test/.jshintrc b/public/test/.jshintrc index f808d281741..3478f503dda 100644 --- a/public/test/.jshintrc +++ b/public/test/.jshintrc @@ -3,7 +3,7 @@ "bitwise":false, "curly": true, "eqnull": true, - "globalstrict": true, + "strict": true, "devel": true, "eqeqeq": true, "forin": false, @@ -11,7 +11,7 @@ "supernew": true, "expr": true, "indent": 2, - "latedef": true, + "latedef": false, "newcap": true, "noarg": true, "noempty": true, diff --git a/public/test/specs/templateSrv-specs.js b/public/test/specs/templateSrv-specs.js index 0728abc49cf..56b23f89798 100644 --- a/public/test/specs/templateSrv-specs.js +++ b/public/test/specs/templateSrv-specs.js @@ -45,7 +45,7 @@ define([ }); }); - describe.only('replace can pass multi / all format', function() { + describe('replace can pass multi / all format', function() { beforeEach(function() { _templateSrv.init([{name: 'test', current: {value: ['value1', 'value2'] }}]); }); @@ -59,6 +59,19 @@ define([ var target = _templateSrv.replace('this=$test', {}, 'pipe'); expect(target).to.be('this=value1|value2'); }); + + it('should replace $test with piped value', function() { + var target = _templateSrv.replace('this=$test', {}, 'pipe'); + expect(target).to.be('this=value1|value2'); + }); + }); + + describe.only('lucene format', function() { + it('should properly escape $test with lucene escape sequences', function() { + _templateSrv.init([{name: 'test', current: {value: 'value/4' }}]); + var target = _templateSrv.replace('this:$test', {}, 'lucene'); + expect(target).to.be("this:value\\\/4"); + }); }); describe('render variable to string values', function() {