From b68987dcde14580276cc4e41e62d92814a301928 Mon Sep 17 00:00:00 2001 From: anryko Date: Fri, 9 Oct 2015 17:05:46 +0200 Subject: [PATCH 01/51] Fixed configuration example for Github OAuth team_ids. --- docs/sources/installation/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 31d029b1101..e68edcbca0c 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -266,7 +266,7 @@ automatically signed up. ### team_ids Require an active team membership for at least one of the given teams on -GitHub. If the authenticated user isn't a member of at least one the +GitHub. If the authenticated user isn't a member of at least one of the teams they will not be able to register or authenticate with your Grafana instance. For example: @@ -274,7 +274,7 @@ Grafana instance. For example: enabled = true client_id = YOUR_GITHUB_APP_CLIENT_ID client_secret = YOUR_GITHUB_APP_CLIENT_SECRET - scopes = user:email + scopes = user:email,read:org team_ids = 150,300 auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token From c831369974f0cbbacd72678184a7fa73589d7a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 10 Oct 2015 11:46:00 -0400 Subject: [PATCH 02/51] fix(influxdb): influxdb data source did not use right http abstraction for metric queries, fixes #2919 --- docker/blocks/prometheus/prometheus.yml | 4 ---- pkg/plugins/plugins.go | 1 - public/app/plugins/datasource/influxdb/datasource.js | 4 ++-- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docker/blocks/prometheus/prometheus.yml b/docker/blocks/prometheus/prometheus.yml index 1d524b1b320..b0fc2a919cd 100644 --- a/docker/blocks/prometheus/prometheus.yml +++ b/docker/blocks/prometheus/prometheus.yml @@ -4,10 +4,6 @@ global: evaluation_interval: 10s # By default, scrape targets every 15 seconds. # scrape_timeout is set to the global default (10s). - # Attach these extra labels to all timeseries collected by this Prometheus instance. - labels: - monitor: 'codelab-monitor' - # Load and evaluate rules in this file every 'evaluation_interval' seconds. rule_files: # - "first.rules" diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 2f7e5264e53..665cf6a36ca 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -91,7 +91,6 @@ func (scanner *PluginScanner) loadPluginJson(path string) error { if !exists { return errors.New("Did not find type property in plugin.json") } - DataSources[datasourceType.(string)] = pluginJson } diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js index d6a5ccc37ad..fabe2278708 100644 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ b/public/app/plugins/datasource/influxdb/datasource.js @@ -12,7 +12,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQueryBuilder) { var module = angular.module('grafana.services'); - module.factory('InfluxDatasource', function($q, $http, templateSrv) { + module.factory('InfluxDatasource', function($q, backendSrv, templateSrv) { function InfluxDatasource(datasource) { this.type = 'influxdb'; @@ -161,7 +161,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQueryBuilder) { options.headers.Authorization = self.basicAuth; } - return $http(options).then(function(result) { + return backendSrv.datasourceRequest(options).then(function(result) { return result.data; }, function(err) { if (err.status !== 0 || err.status >= 300) { From c0da52aac8b47501535ab5740305a73510d5d2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 10 Oct 2015 14:38:22 -0400 Subject: [PATCH 03/51] fix(share): fixed share panel image url, did not generate correct url when domain name contained word dashboards, fixes #2916 --- public/app/features/dashboard/shareModalCtrl.js | 2 +- public/test/specs/helpers.js | 3 ++- public/test/specs/shareModalCtrl-specs.js | 12 ++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/shareModalCtrl.js b/public/app/features/dashboard/shareModalCtrl.js index 5afee9d39cd..9c0d14ee601 100644 --- a/public/app/features/dashboard/shareModalCtrl.js +++ b/public/app/features/dashboard/shareModalCtrl.js @@ -75,7 +75,7 @@ function (angular, _, require, config) { $scope.iframeHtml = ''; - $scope.imageUrl = soloUrl.replace('/dashboard', '/render/dashboard'); + $scope.imageUrl = soloUrl.replace('/dashboard-solo/', '/render/dashboard-solo/'); $scope.imageUrl += '&width=1000'; $scope.imageUrl += '&height=500'; }; diff --git a/public/test/specs/helpers.js b/public/test/specs/helpers.js index 011c0cc70d6..9fa5aeee209 100644 --- a/public/test/specs/helpers.js +++ b/public/test/specs/helpers.js @@ -38,9 +38,10 @@ define([ }; this.createControllerPhase = function(controllerName) { - return inject(function($controller, $rootScope, $q, $location) { + return inject(function($controller, $rootScope, $q, $location, $browser) { self.scope = $rootScope.$new(); self.$location = $location; + self.$browser = $browser; self.scope.contextSrv = {}; self.scope.panel = {}; self.scope.row = { panels:[] }; diff --git a/public/test/specs/shareModalCtrl-specs.js b/public/test/specs/shareModalCtrl-specs.js index 6aea645d557..f3ff4aeb719 100644 --- a/public/test/specs/shareModalCtrl-specs.js +++ b/public/test/specs/shareModalCtrl-specs.js @@ -7,6 +7,7 @@ define([ describe('ShareModalCtrl', function() { var ctx = new helpers.ControllerTestContext(); + var browser; function setTime(range) { ctx.timeSrv.timeRange = sinon.stub().returns(range); @@ -31,6 +32,17 @@ define([ expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=1000&to=2000&panelId=22&fullscreen'); }); + it('should generate render url', function() { + ctx.$location.$$absUrl = 'http://dashboards.grafana.com/dashboard/db/my-dash'; + + ctx.scope.panel = { id: 22 }; + + ctx.scope.init(); + var base = 'http://dashboards.grafana.com/render/dashboard-solo/db/my-dash'; + var params = '?from=1000&to=2000&panelId=22&fullscreen&width=1000&height=500'; + expect(ctx.scope.imageUrl).to.be(base + params); + }); + it('should remove panel id when no panel in scope', function() { ctx.$location.path('/test'); ctx.scope.options.forCurrent = true; From d09bff903948eecc21f48355fed93fac838b218c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 10 Oct 2015 15:11:58 -0400 Subject: [PATCH 04/51] fixed failing jshint --- public/test/specs/shareModalCtrl-specs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/test/specs/shareModalCtrl-specs.js b/public/test/specs/shareModalCtrl-specs.js index f3ff4aeb719..995d663779a 100644 --- a/public/test/specs/shareModalCtrl-specs.js +++ b/public/test/specs/shareModalCtrl-specs.js @@ -7,7 +7,6 @@ define([ describe('ShareModalCtrl', function() { var ctx = new helpers.ControllerTestContext(); - var browser; function setTime(range) { ctx.timeSrv.timeRange = sinon.stub().returns(range); From e873574e8c5ed95f39b0627991b57bf49eb29cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 10 Oct 2015 17:55:15 -0400 Subject: [PATCH 05/51] fix(logging): fixed so that router_logging = true actually logs all http requests, fixes #2902 --- pkg/middleware/logger.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/middleware/logger.go b/pkg/middleware/logger.go index 5b1132e111e..eb5c7b8dde4 100644 --- a/pkg/middleware/logger.go +++ b/pkg/middleware/logger.go @@ -22,6 +22,7 @@ import ( "github.com/Unknwon/macaron" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/setting" ) func Logger() macaron.Handler { @@ -36,7 +37,9 @@ func Logger() macaron.Handler { switch rw.Status() { case 200, 304: content = fmt.Sprintf("%s", content) - return + if !setting.RouterLogging { + return + } case 404: content = fmt.Sprintf("%s", content) case 500: From 267417d6a8d27fe908375c63693310b6340bc022 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Wed, 14 Oct 2015 14:00:25 -0400 Subject: [PATCH 06/51] docs(): Fix changelog link in whats-new-in-v2-1 The quotes turn the value into a title attribute rather than href attribute, thus on http://docs.grafana.org/guides/whats-new-in-v2-1/ this link was rendered as CHANGELOG.md which when clicked goes back to itself (not to GitHub). --- docs/sources/guides/whats-new-in-v2-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/guides/whats-new-in-v2-1.md b/docs/sources/guides/whats-new-in-v2-1.md index 6a6ebba98de..27285d08857 100644 --- a/docs/sources/guides/whats-new-in-v2-1.md +++ b/docs/sources/guides/whats-new-in-v2-1.md @@ -126,5 +126,5 @@ string values. ### Changelog For a detailed list and link to github issues for everything included in the 2.1 release please -view the [CHANGELOG.md]("https://github.com/grafana/grafana/blob/master/CHANGELOG.md") file. +view the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file. From e3e21a251f67ad1b506aefa72ac9282c034cab71 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 12:41:20 -0700 Subject: [PATCH 07/51] Group helper functions in kbn.js. --- public/app/components/kbn.js | 56 +++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 5b9516bc82f..a49c6a3bb4c 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -8,6 +8,8 @@ function($, _) { var kbn = {}; kbn.valueFormats = {}; + ///// HELPER FUNCTIONS ///// + kbn.round_interval = function(interval) { switch (true) { // 0.5s @@ -170,6 +172,33 @@ function($, _) { ].join(';') + '">'; }; + kbn.slugifyForUrl = function(str) { + return str + .toLowerCase() + .replace(/[^\w ]+/g,'') + .replace(/ +/g,'-'); + }; + + kbn.exportSeriesListToCsv = function(seriesList) { + var text = 'Series;Time;Value\n'; + _.each(seriesList, function(series) { + _.each(series.datapoints, function(dp) { + text += series.alias + ';' + new Date(dp[1]).toISOString() + ';' + dp[0] + '\n'; + }); + }); + var blob = new Blob([text], { type: "text/csv;charset=utf-8" }); + window.saveAs(blob, 'grafana_data_export.csv'); + }; + + kbn.stringToJsRegex = function(str) { + if (str[0] !== '/') { + return new RegExp(str); + } + + var match = str.match(new RegExp('^/(.*?)/(g?i?m?y?)$')); + return new RegExp(match[1], match[2]); + }; + kbn.valueFormats.percent = function(size, decimals) { return kbn.toFixed(size, decimals) + '%'; }; @@ -354,32 +383,7 @@ function($, _) { } }; - kbn.slugifyForUrl = function(str) { - return str - .toLowerCase() - .replace(/[^\w ]+/g,'') - .replace(/ +/g,'-'); - }; - - kbn.exportSeriesListToCsv = function(seriesList) { - var text = 'Series;Time;Value\n'; - _.each(seriesList, function(series) { - _.each(series.datapoints, function(dp) { - text += series.alias + ';' + new Date(dp[1]).toISOString() + ';' + dp[0] + '\n'; - }); - }); - var blob = new Blob([text], { type: "text/csv;charset=utf-8" }); - window.saveAs(blob, 'grafana_data_export.csv'); - }; - - kbn.stringToJsRegex = function(str) { - if (str[0] !== '/') { - return new RegExp(str); - } - - var match = str.match(new RegExp('^/(.*?)/(g?i?m?y?)$')); - return new RegExp(match[1], match[2]); - }; + ///// FORMAT MENU ///// kbn.getUnitFormats = function() { return [ From 43c2ca2d7dbd9ffb8dc1474a0bf0a38bd2add065 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 12:51:59 -0700 Subject: [PATCH 08/51] Group value formats by type. --- public/app/components/kbn.js | 53 ++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index a49c6a3bb4c..be1f37dfacd 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -199,10 +199,6 @@ function($, _) { return new RegExp(match[1], match[2]); }; - kbn.valueFormats.percent = function(size, decimals) { - return kbn.toFixed(size, decimals) + '%'; - }; - kbn.formatFuncCreator = function(factor, extArray) { return function(size, decimals, scaledDecimals) { if (size === null) { @@ -253,36 +249,57 @@ function($, _) { return formatted; }; - kbn.valueFormats.bits = kbn.formatFuncCreator(1024, [' b', ' Kib', ' Mib', ' Gib', ' Tib', ' Pib', ' Eib', ' Zib', ' Yib']); - kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); + ///// VALUE FORMATS ///// + + // Dimensionless Units + kbn.valueFormats.none = kbn.toFixed; + kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); + kbn.valueFormats.ppm = function(value, decimals) { return kbn.toFixed(value, decimals) + ' ppm'; }; + + kbn.valueFormats.percent = function(size, decimals) { + return kbn.toFixed(size, decimals) + '%'; + }; + + // Data + kbn.valueFormats.bits = kbn.formatFuncCreator(1024, [' b', ' Kib', ' Mib', ' Gib', ' Tib', ' Pib', ' Eib', ' Zib', ' Yib']); + kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); kbn.valueFormats.kbytes = kbn.formatFuncCreator(1024, [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); kbn.valueFormats.mbytes = kbn.formatFuncCreator(1024, [' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); kbn.valueFormats.gbytes = kbn.formatFuncCreator(1024, [' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); - kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']); + + // Data Rate kbn.valueFormats.pps = kbn.formatFuncCreator(1000, [' pps', ' Kpps', ' Mpps', ' Gpps', ' Tpps', ' Ppps', ' Epps', ' Zpps', ' Ypps']); + kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']); kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']); - kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); - kbn.valueFormats.joule = kbn.formatFuncCreator(1000, [' J', ' kJ', ' MJ', ' GJ', ' TJ', ' PJ', ' EJ', ' ZJ', ' YJ']); - kbn.valueFormats.amp = kbn.formatFuncCreator(1000, [' A', ' kA', ' MA', ' GA', ' TA', ' PA', ' EA', ' ZA', ' YA']); - kbn.valueFormats.volt = kbn.formatFuncCreator(1000, [' V', ' kV', ' MV', ' GV', ' TV', ' PV', ' EV', ' ZV', ' YV']); - kbn.valueFormats.hertz = kbn.formatFuncCreator(1000, [' Hz', ' kHz', ' MHz', ' GHz', ' THz', ' PHz', ' EHz', ' ZHz', ' YHz']); - kbn.valueFormats.watt = kbn.formatFuncCreator(1000, [' W', ' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']); - kbn.valueFormats.kwatt = kbn.formatFuncCreator(1000, [' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']); - kbn.valueFormats.watth = kbn.formatFuncCreator(1000, [' Wh', ' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']); + + // Energy + kbn.valueFormats.watt = kbn.formatFuncCreator(1000, [' W', ' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']); + kbn.valueFormats.kwatt = kbn.formatFuncCreator(1000, [' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']); + kbn.valueFormats.watth = kbn.formatFuncCreator(1000, [' Wh', ' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']); kbn.valueFormats.kwatth = kbn.formatFuncCreator(1000, [' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']); - kbn.valueFormats.ev = kbn.formatFuncCreator(1000, [' eV', ' keV', ' MeV', 'GeV', 'TeV', 'PeV', 'EeV', 'ZeV', 'YeV']); - kbn.valueFormats.none = kbn.toFixed; + kbn.valueFormats.joule = kbn.formatFuncCreator(1000, [' J', ' kJ', ' MJ', ' GJ', ' TJ', ' PJ', ' EJ', ' ZJ', ' YJ']); + kbn.valueFormats.ev = kbn.formatFuncCreator(1000, [' eV', ' keV', ' MeV', 'GeV', 'TeV', 'PeV', 'EeV', 'ZeV', 'YeV']); + kbn.valueFormats.amp = kbn.formatFuncCreator(1000, [' A', ' kA', ' MA', ' GA', ' TA', ' PA', ' EA', ' ZA', ' YA']); + kbn.valueFormats.volt = kbn.formatFuncCreator(1000, [' V', ' kV', ' MV', ' GV', ' TV', ' PV', ' EV', ' ZV', ' YV']); + + // Temperature kbn.valueFormats.celsius = function(value, decimals) { return kbn.toFixed(value, decimals) + ' °C'; }; kbn.valueFormats.farenheit = function(value, decimals) { return kbn.toFixed(value, decimals) + ' °F'; }; kbn.valueFormats.humidity = function(value, decimals) { return kbn.toFixed(value, decimals) + ' %H'; }; + + // Pressure kbn.valueFormats.pressurembar = function(value, decimals) { return kbn.toFixed(value, decimals) + ' mbar'; }; kbn.valueFormats.pressurehpa = function(value, decimals) { return kbn.toFixed(value, decimals) + ' hPa'; }; - kbn.valueFormats.ppm = function(value, decimals) { return kbn.toFixed(value, decimals) + ' ppm'; }; + + // Velocity kbn.valueFormats.velocityms = function(value, decimals) { return kbn.toFixed(value, decimals) + ' m/s'; }; kbn.valueFormats.velocitykmh = function(value, decimals) { return kbn.toFixed(value, decimals) + ' km/h'; }; kbn.valueFormats.velocitymph = function(value, decimals) { return kbn.toFixed(value, decimals) + ' mph'; }; kbn.valueFormats.velocityknot = function(value, decimals) { return kbn.toFixed(value, decimals) + ' kn'; }; + // Time + kbn.valueFormats.hertz = kbn.formatFuncCreator(1000, [' Hz', ' kHz', ' MHz', ' GHz', ' THz', ' PHz', ' EHz', ' ZHz', ' YHz']); + kbn.roundValue = function (num, decimals) { if (num === null) { return null; } var n = Math.pow(10, decimals); From 0bc85d27f8b4cf91e79f76cf2be4814f322921fe Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 12:56:31 -0700 Subject: [PATCH 09/51] Group rounding and fixed number functions. --- public/app/components/kbn.js | 79 +++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index be1f37dfacd..0fe0320feb8 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -199,30 +199,6 @@ function($, _) { return new RegExp(match[1], match[2]); }; - kbn.formatFuncCreator = function(factor, extArray) { - return function(size, decimals, scaledDecimals) { - if (size === null) { - return ""; - } - - var steps = 0; - var limit = extArray.length; - - while (Math.abs(size) >= factor) { - steps++; - size /= factor; - - if (steps >= limit) { return "NA"; } - } - - if (steps > 0 && scaledDecimals !== null) { - decimals = scaledDecimals + (3 * steps); - } - - return kbn.toFixed(size, decimals) + extArray[steps]; - }; - }; - kbn.toFixed = function(value, decimals) { if (value === null) { return ""; @@ -249,6 +225,46 @@ function($, _) { return formatted; }; + kbn.toFixedScaled = function(value, decimals, scaledDecimals, additionalDecimals, ext) { + if (scaledDecimals === null) { + return kbn.toFixed(value, decimals) + ext; + } else { + return kbn.toFixed(value, scaledDecimals + additionalDecimals) + ext; + } + }; + + kbn.roundValue = function (num, decimals) { + if (num === null) { return null; } + var n = Math.pow(10, decimals); + return Math.round((n * num).toFixed(decimals)) / n; + }; + + ///// FORMAT FUNCTION CONSTRUCTORS ///// + + kbn.formatFuncCreator = function(factor, extArray) { + return function(size, decimals, scaledDecimals) { + if (size === null) { + return ""; + } + + var steps = 0; + var limit = extArray.length; + + while (Math.abs(size) >= factor) { + steps++; + size /= factor; + + if (steps >= limit) { return "NA"; } + } + + if (steps > 0 && scaledDecimals !== null) { + decimals = scaledDecimals + (3 * steps); + } + + return kbn.toFixed(size, decimals) + extArray[steps]; + }; + }; + ///// VALUE FORMATS ///// // Dimensionless Units @@ -257,6 +273,7 @@ function($, _) { kbn.valueFormats.ppm = function(value, decimals) { return kbn.toFixed(value, decimals) + ' ppm'; }; kbn.valueFormats.percent = function(size, decimals) { + if (size == null) { return ""; } return kbn.toFixed(size, decimals) + '%'; }; @@ -300,20 +317,6 @@ function($, _) { // Time kbn.valueFormats.hertz = kbn.formatFuncCreator(1000, [' Hz', ' kHz', ' MHz', ' GHz', ' THz', ' PHz', ' EHz', ' ZHz', ' YHz']); - kbn.roundValue = function (num, decimals) { - if (num === null) { return null; } - var n = Math.pow(10, decimals); - return Math.round((n * num).toFixed(decimals)) / n; - }; - - kbn.toFixedScaled = function(value, decimals, scaledDecimals, additionalDecimals, ext) { - if (scaledDecimals === null) { - return kbn.toFixed(value, decimals) + ext; - } else { - return kbn.toFixed(value, scaledDecimals + additionalDecimals) + ext; - } - }; - kbn.valueFormats.ms = function(size, decimals, scaledDecimals) { if (size === null) { return ""; } From 7d24c5fda24abccd712a6df8002b62955d2f83a4 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 13:07:34 -0700 Subject: [PATCH 10/51] Add fixedUnit format builder. --- public/app/components/kbn.js | 41 +++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 0fe0320feb8..18821c17754 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -241,6 +241,17 @@ function($, _) { ///// FORMAT FUNCTION CONSTRUCTORS ///// + kbn.formatBuilders = {}; + + // Formatter which always appends a fixed unit string to the value. No + // scaling of the value is performed. + kbn.formatBuilders.fixedUnit = function(unit, separator) { + return function(size, decimals) { + if (size === null) { return ""; } + return kbn.toFixed(size, decimals) + (separator || ' ') + unit; + }; + }; + kbn.formatFuncCreator = function(factor, extArray) { return function(size, decimals, scaledDecimals) { if (size === null) { @@ -268,14 +279,10 @@ function($, _) { ///// VALUE FORMATS ///// // Dimensionless Units - kbn.valueFormats.none = kbn.toFixed; - kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); - kbn.valueFormats.ppm = function(value, decimals) { return kbn.toFixed(value, decimals) + ' ppm'; }; - - kbn.valueFormats.percent = function(size, decimals) { - if (size == null) { return ""; } - return kbn.toFixed(size, decimals) + '%'; - }; + kbn.valueFormats.none = kbn.toFixed; + kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); + kbn.valueFormats.ppm = kbn.formatBuilders.fixedUnit('ppm'); + kbn.valueFormats.percent = kbn.formatBuilders.fixedUnit('%', ''); // Data kbn.valueFormats.bits = kbn.formatFuncCreator(1024, [' b', ' Kib', ' Mib', ' Gib', ' Tib', ' Pib', ' Eib', ' Zib', ' Yib']); @@ -300,19 +307,19 @@ function($, _) { kbn.valueFormats.volt = kbn.formatFuncCreator(1000, [' V', ' kV', ' MV', ' GV', ' TV', ' PV', ' EV', ' ZV', ' YV']); // Temperature - kbn.valueFormats.celsius = function(value, decimals) { return kbn.toFixed(value, decimals) + ' °C'; }; - kbn.valueFormats.farenheit = function(value, decimals) { return kbn.toFixed(value, decimals) + ' °F'; }; - kbn.valueFormats.humidity = function(value, decimals) { return kbn.toFixed(value, decimals) + ' %H'; }; + kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C'); + kbn.valueFormats.farenheit = kbn.formatBuilders.fixedUnit('°F'); + kbn.valueFormats.humidity = kbn.formatBuilders.fixedUnit('%H'); // Pressure - kbn.valueFormats.pressurembar = function(value, decimals) { return kbn.toFixed(value, decimals) + ' mbar'; }; - kbn.valueFormats.pressurehpa = function(value, decimals) { return kbn.toFixed(value, decimals) + ' hPa'; }; + kbn.valueFormats.pressurembar = kbn.formatBuilders.fixedUnit('mbar'); + kbn.valueFormats.pressurehpa = kbn.formatBuilders.fixedUnit('hPa'); // Velocity - kbn.valueFormats.velocityms = function(value, decimals) { return kbn.toFixed(value, decimals) + ' m/s'; }; - kbn.valueFormats.velocitykmh = function(value, decimals) { return kbn.toFixed(value, decimals) + ' km/h'; }; - kbn.valueFormats.velocitymph = function(value, decimals) { return kbn.toFixed(value, decimals) + ' mph'; }; - kbn.valueFormats.velocityknot = function(value, decimals) { return kbn.toFixed(value, decimals) + ' kn'; }; + kbn.valueFormats.velocityms = kbn.formatBuilders.fixedUnit('m/s'); + kbn.valueFormats.velocitykmh = kbn.formatBuilders.fixedUnit('km/h'); + kbn.valueFormats.velocitymph = kbn.formatBuilders.fixedUnit('mph'); + kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn'); // Time kbn.valueFormats.hertz = kbn.formatFuncCreator(1000, [' Hz', ' kHz', ' MHz', ' GHz', ' THz', ' PHz', ' EHz', ' ZHz', ' YHz']); From 51a589f5a6e58cd4b004cf35590024361f68f373 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 13:18:02 -0700 Subject: [PATCH 11/51] Change formatFuncCreator to scaledUnits builder. Abstract out both decimal and binary SI prefixes into builders using scaledUnits. --- public/app/components/kbn.js | 60 ++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 18821c17754..8f338a5a177 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -252,7 +252,10 @@ function($, _) { }; }; - kbn.formatFuncCreator = function(factor, extArray) { + // Formatter which scales the unit string geometrically according to the given + // numeric factor. Repeatedly scales the value down by the factor until it is + // less than the factor in magnitude, or the end of the array is reached. + kbn.formatBuilders.scaledUnits = function(factor, extArray) { return function(size, decimals, scaledDecimals) { if (size === null) { return ""; @@ -276,35 +279,54 @@ function($, _) { }; }; + // Extension of the scaledUnits builder which uses SI decimal prefixes. If an + // offset is given, it adjusts the starting units at the given prefix; a value + // of 0 starts at no scale; -3 drops to nano, +2 starts at mega, etc. + kbn.formatBuilders.decimalSIPrefix = function(unit, offset) { + var prefixes = ['n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; + prefixes = prefixes.slice(3 + (offset || 0)); + var units = prefixes.map(function(p) { return ' ' + p + unit; }); + return kbn.formatBuilders.scaledUnits(1000, units); + }; + + // Extension of the scaledUnits builder which uses SI binary prefixes. If + // offset is given, it starts the units at the given prefix; otherwise, the + // offset defaults to zero and the initial unit is not prefixed. + kbn.formatBuilders.binarySIPrefix = function(unit, offset) { + var prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'].slice(offset); + var units = prefixes.map(function(p) { return ' ' + p + unit; }); + return kbn.formatBuilders.scaledUnits(1024, units); + }; + ///// VALUE FORMATS ///// // Dimensionless Units kbn.valueFormats.none = kbn.toFixed; - kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); + kbn.valueFormats.short = kbn.formatBuilders.scaledUnits(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); kbn.valueFormats.ppm = kbn.formatBuilders.fixedUnit('ppm'); kbn.valueFormats.percent = kbn.formatBuilders.fixedUnit('%', ''); // Data - kbn.valueFormats.bits = kbn.formatFuncCreator(1024, [' b', ' Kib', ' Mib', ' Gib', ' Tib', ' Pib', ' Eib', ' Zib', ' Yib']); - kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); - kbn.valueFormats.kbytes = kbn.formatFuncCreator(1024, [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); - kbn.valueFormats.mbytes = kbn.formatFuncCreator(1024, [' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); - kbn.valueFormats.gbytes = kbn.formatFuncCreator(1024, [' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']); + kbn.valueFormats.bits = kbn.formatBuilders.binarySIPrefix('b'); + kbn.valueFormats.bytes = kbn.formatBuilders.binarySIPrefix('B'); + kbn.valueFormats.kbytes = kbn.formatBuilders.binarySIPrefix('B', 1); + kbn.valueFormats.mbytes = kbn.formatBuilders.binarySIPrefix('B', 2); + kbn.valueFormats.gbytes = kbn.formatBuilders.binarySIPrefix('B', 3); // Data Rate - kbn.valueFormats.pps = kbn.formatFuncCreator(1000, [' pps', ' Kpps', ' Mpps', ' Gpps', ' Tpps', ' Ppps', ' Epps', ' Zpps', ' Ypps']); - kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']); - kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']); + kbn.valueFormats.pps = kbn.formatBuilders.decimalSIPrefix('pps'); + kbn.valueFormats.bps = kbn.formatBuilders.decimalSIPrefix('bps'); + kbn.valueFormats.Bps = kbn.formatBuilders.decimalSIPrefix('Bps'); // Energy - kbn.valueFormats.watt = kbn.formatFuncCreator(1000, [' W', ' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']); - kbn.valueFormats.kwatt = kbn.formatFuncCreator(1000, [' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']); - kbn.valueFormats.watth = kbn.formatFuncCreator(1000, [' Wh', ' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']); - kbn.valueFormats.kwatth = kbn.formatFuncCreator(1000, [' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']); - kbn.valueFormats.joule = kbn.formatFuncCreator(1000, [' J', ' kJ', ' MJ', ' GJ', ' TJ', ' PJ', ' EJ', ' ZJ', ' YJ']); - kbn.valueFormats.ev = kbn.formatFuncCreator(1000, [' eV', ' keV', ' MeV', 'GeV', 'TeV', 'PeV', 'EeV', 'ZeV', 'YeV']); - kbn.valueFormats.amp = kbn.formatFuncCreator(1000, [' A', ' kA', ' MA', ' GA', ' TA', ' PA', ' EA', ' ZA', ' YA']); - kbn.valueFormats.volt = kbn.formatFuncCreator(1000, [' V', ' kV', ' MV', ' GV', ' TV', ' PV', ' EV', ' ZV', ' YV']); + kbn.valueFormats.watt = kbn.formatBuilders.decimalSIPrefix('W'); + kbn.valueFormats.kwatt = kbn.formatBuilders.decimalSIPrefix('W', 1); + kbn.valueFormats.watth = kbn.formatBuilders.decimalSIPrefix('Wh'); + kbn.valueFormats.kwatth = kbn.formatBuilders.decimalSIPrefix('Wh', 1); + kbn.valueFormats.joule = kbn.formatBuilders.decimalSIPrefix('J'); + kbn.valueFormats.ev = kbn.formatBuilders.decimalSIPrefix('eV'); + kbn.valueFormats.amp = kbn.formatBuilders.decimalSIPrefix('A'); + kbn.valueFormats.volt = kbn.formatBuilders.decimalSIPrefix('V'); // Temperature kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C'); @@ -322,7 +344,7 @@ function($, _) { kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn'); // Time - kbn.valueFormats.hertz = kbn.formatFuncCreator(1000, [' Hz', ' kHz', ' MHz', ' GHz', ' THz', ' PHz', ' EHz', ' ZHz', ' YHz']); + kbn.valueFormats.hertz = kbn.formatBuilders.decimalSIPrefix('Hz'); kbn.valueFormats.ms = function(size, decimals, scaledDecimals) { if (size === null) { return ""; } From 70269c81968f4a97f2e8639178af600d3423805b Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 13:34:48 -0700 Subject: [PATCH 12/51] Reformat unit menu definition. --- public/app/components/kbn.js | 62 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 8f338a5a177..4ac6d5712d9 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -439,28 +439,28 @@ function($, _) { { text: 'none', submenu: [ - {text: 'none' , value: 'none'}, - {text: 'short', value: 'short'}, - {text: 'percent', value: 'percent'}, - {text: 'ppm', value: 'ppm'}, - {text: 'dB', value: 'dB'}, + {text: 'none' , value: 'none' }, + {text: 'short', value: 'short' }, + {text: 'scaled percentage (0-100)', value: 'percent' }, + {text: 'ppm', value: 'ppm' }, + {text: 'decibel', value: 'dB' }, ] }, { text: 'duration', submenu: [ - {text: 'nanoseconds (ns)' , value: 'ns'}, - {text: 'microseconds (µs)', value: 'µs'}, - {text: 'milliseconds (ms)', value: 'ms'}, - {text: 'seconds (s)', value: 's'}, - {text: 'Hertz (1/s)', value: 'hertz'}, + {text: 'Hertz (1/s)', value: 'hertz'}, + {text: 'nanoseconds (ns)' , value: 'ns' }, + {text: 'microseconds (µs)', value: 'µs' }, + {text: 'milliseconds (ms)', value: 'ms' }, + {text: 'seconds (s)', value: 's' }, ] }, { text: 'data', submenu: [ - {text: 'bits', value: 'bits'}, - {text: 'bytes', value: 'bytes'}, + {text: 'bits', value: 'bits' }, + {text: 'bytes', value: 'bytes' }, {text: 'kilobytes', value: 'kbytes'}, {text: 'megabytes', value: 'mbytes'}, {text: 'gigabytes', value: 'gbytes'}, @@ -470,40 +470,40 @@ function($, _) { text: 'data rate', submenu: [ {text: 'packets/sec', value: 'pps'}, - {text: 'bits/sec', value: 'bps'}, - {text: 'bytes/sec', value: 'Bps'}, + {text: 'bits/sec', value: 'bps'}, + {text: 'bytes/sec', value: 'Bps'}, ] }, { text: 'energy', submenu: [ - {text: 'watt (W)', value: 'watt'}, - {text: 'kilowatt (kW)', value: 'kwatt'}, - {text: 'watt-hour (Wh)', value: 'watth'}, - {text: 'kilowatt-hour (kWh)', value: 'kwatth'}, - {text: 'joule (J)', value: 'joule'}, - {text: 'electron volt (eV)', value: 'ev'}, - {text: 'Ampere (A)', value: 'amp'}, - {text: 'Volt (V)', value: 'volt'}, + {text: 'watt (W)', value: 'watt' }, + {text: 'kilowatt (kW)', value: 'kwatt' }, + {text: 'watt-hour (Wh)', value: 'watth' }, + {text: 'kilowatt-hour (kWh)', value: 'kwatth'}, + {text: 'joule (J)', value: 'joule' }, + {text: 'electron volt (eV)', value: 'ev' }, + {text: 'Ampere (A)', value: 'amp' }, + {text: 'Volt (V)', value: 'volt' }, ] }, { text: 'weather', submenu: [ - {text: 'Celcius (°C)', value: 'celsius' }, - {text: 'Farenheit (°F)', value: 'farenheit'}, - {text: 'Humidity (%H)', value: 'humidity' }, - {text: 'Pressure (mbar)', value: 'pressurembar' }, - {text: 'Pressure (hPa)', value: 'pressurehpa' }, + {text: 'Celcius (°C)', value: 'celsius' }, + {text: 'Farenheit (°F)', value: 'farenheit' }, + {text: 'Humidity (%H)', value: 'humidity' }, + {text: 'Pressure (mbar)', value: 'pressurembar'}, + {text: 'Pressure (hPa)', value: 'pressurehpa' }, ] }, { text: 'velocity', submenu: [ - {text: 'm/s', value: 'velocityms' }, - {text: 'km/h', value: 'velocitykmh' }, - {text: 'mph', value: 'velocitymph' }, - {text: 'knot (kn)', value: 'velocityknot' }, + {text: 'm/s', value: 'velocityms' }, + {text: 'km/h', value: 'velocitykmh' }, + {text: 'mph', value: 'velocitymph' }, + {text: 'knot (kn)', value: 'velocityknot'}, ] }, ]; From dc5c3a393963ea4c949ebb7162ed78a693e351db Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 13:39:27 -0700 Subject: [PATCH 13/51] Implement decibel and percentunit units. Add tests to exercise new units as well. --- public/app/components/kbn.js | 23 +++++++++++++++++------ public/test/specs/kbn-format-specs.js | 8 ++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 4ac6d5712d9..208d3840fa1 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -245,10 +245,10 @@ function($, _) { // Formatter which always appends a fixed unit string to the value. No // scaling of the value is performed. - kbn.formatBuilders.fixedUnit = function(unit, separator) { + kbn.formatBuilders.fixedUnit = function(unit) { return function(size, decimals) { if (size === null) { return ""; } - return kbn.toFixed(size, decimals) + (separator || ' ') + unit; + return kbn.toFixed(size, decimals) + ' ' + unit; }; }; @@ -301,10 +301,20 @@ function($, _) { ///// VALUE FORMATS ///// // Dimensionless Units - kbn.valueFormats.none = kbn.toFixed; - kbn.valueFormats.short = kbn.formatBuilders.scaledUnits(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); - kbn.valueFormats.ppm = kbn.formatBuilders.fixedUnit('ppm'); - kbn.valueFormats.percent = kbn.formatBuilders.fixedUnit('%', ''); + kbn.valueFormats.none = kbn.toFixed; + kbn.valueFormats.short = kbn.formatBuilders.scaledUnits(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']); + kbn.valueFormats.dB = kbn.formatBuilders.fixedUnit('dB'); + kbn.valueFormats.ppm = kbn.formatBuilders.fixedUnit('ppm'); + + kbn.valueFormats.percent = function(size, decimals) { + if (size === null) { return ""; } + return kbn.toFixed(size, decimals) + '%'; + }; + + kbn.valueFormats.percentunit = function(size, decimals) { + if (size === null) { return ""; } + return kbn.toFixed(100*size, decimals) + '%'; + }; // Data kbn.valueFormats.bits = kbn.formatBuilders.binarySIPrefix('b'); @@ -442,6 +452,7 @@ function($, _) { {text: 'none' , value: 'none' }, {text: 'short', value: 'short' }, {text: 'scaled percentage (0-100)', value: 'percent' }, + {text: 'unit percentage (0.0-1.0)', value: 'percentunit'}, {text: 'ppm', value: 'ppm' }, {text: 'decibel', value: 'dB' }, ] diff --git a/public/test/specs/kbn-format-specs.js b/public/test/specs/kbn-format-specs.js index 366ab575491..d7f97187716 100644 --- a/public/test/specs/kbn-format-specs.js +++ b/public/test/specs/kbn-format-specs.js @@ -26,6 +26,14 @@ define([ describeValueFormat('none', 2.75e-10, 0, 10, '3e-10'); describeValueFormat('none', 0, 0, 2, '0'); + describeValueFormat('dB', 10, 1000, 2, '10.00 dB'); + + describeValueFormat('percent', 0, 0, 0, '0%'); + describeValueFormat('percent', 53, 0, 1, '53.0%'); + describeValueFormat('percentunit', 0.0, 0, 0, '0%'); + describeValueFormat('percentunit', 0.278, 0, 1, '27.8%'); + describeValueFormat('percentunit', 1.0, 0, 0, '100%'); + describeValueFormat('bytes', -1.57e+308, -1.57e+308, 2, 'NA'); describeValueFormat('ns', 25, 1, 0, '25 ns'); From 3c7a483f5c582cbb822ab89ec4125730ec83ab7a Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 14:13:21 -0700 Subject: [PATCH 14/51] Add length and volume units. --- public/app/components/kbn.js | 43 ++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 208d3840fa1..6adc4fac17a 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -347,12 +347,20 @@ function($, _) { kbn.valueFormats.pressurembar = kbn.formatBuilders.fixedUnit('mbar'); kbn.valueFormats.pressurehpa = kbn.formatBuilders.fixedUnit('hPa'); + // Length + kbn.valueFormats.lengthm = kbn.formatBuilders.decimalSIPrefix('m'); + kbn.valueFormats.lengthkm = kbn.formatBuilders.decimalSIPrefix('m', 1); + // Velocity kbn.valueFormats.velocityms = kbn.formatBuilders.fixedUnit('m/s'); kbn.valueFormats.velocitykmh = kbn.formatBuilders.fixedUnit('km/h'); kbn.valueFormats.velocitymph = kbn.formatBuilders.fixedUnit('mph'); kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn'); + // Volume + kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L'); + kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1); + // Time kbn.valueFormats.hertz = kbn.formatBuilders.decimalSIPrefix('Hz'); @@ -485,6 +493,32 @@ function($, _) { {text: 'bytes/sec', value: 'Bps'}, ] }, + { + text: 'length', + submenu: [ + {text: 'millimetre (mm)', value: 'lengthmm'}, + {text: 'meter (m)', value: 'lengthm' }, + {text: 'kilometer (km)', value: 'lengthm' }, + {text: 'inches', value: 'lengthin'}, + {text: 'feet', value: 'lengthft'}, + ] + }, + { + text: 'velocity', + submenu: [ + {text: 'm/s', value: 'velocityms' }, + {text: 'km/h', value: 'velocitykmh' }, + {text: 'mph', value: 'velocitymph' }, + {text: 'knot (kn)', value: 'velocityknot'}, + ] + }, + { + text: 'volume', + submenu: [ + {text: 'millilitre', value: 'mlitre'}, + {text: 'litre', value: 'litre' }, + ] + }, { text: 'energy', submenu: [ @@ -508,15 +542,6 @@ function($, _) { {text: 'Pressure (hPa)', value: 'pressurehpa' }, ] }, - { - text: 'velocity', - submenu: [ - {text: 'm/s', value: 'velocityms' }, - {text: 'km/h', value: 'velocitykmh' }, - {text: 'mph', value: 'velocitymph' }, - {text: 'knot (kn)', value: 'velocityknot'}, - ] - }, ]; }; From d94b6635af06f12a3185d7261c6595b361230da1 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 14:50:43 -0700 Subject: [PATCH 15/51] Add temperature and pressure units, split submenus. --- public/app/components/kbn.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 6adc4fac17a..aa3aad19fd9 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -341,11 +341,14 @@ function($, _) { // Temperature kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C'); kbn.valueFormats.farenheit = kbn.formatBuilders.fixedUnit('°F'); + kbn.valueFormats.kelvin = kbn.formatBuilders.fixedUnit('K'); kbn.valueFormats.humidity = kbn.formatBuilders.fixedUnit('%H'); // Pressure kbn.valueFormats.pressurembar = kbn.formatBuilders.fixedUnit('mbar'); kbn.valueFormats.pressurehpa = kbn.formatBuilders.fixedUnit('hPa'); + kbn.valueFormats.pressurehg = kbn.formatBuilders.fixedUnit('"Hg'); + kbn.valueFormats.pressurepsi = kbn.formatBuilders.scaledUnits(1000, [' psi', ' ksi', ' Mpsi']); // Length kbn.valueFormats.lengthm = kbn.formatBuilders.decimalSIPrefix('m'); @@ -461,12 +464,13 @@ function($, _) { {text: 'short', value: 'short' }, {text: 'scaled percentage (0-100)', value: 'percent' }, {text: 'unit percentage (0.0-1.0)', value: 'percentunit'}, + {text: 'Humidity (%H)', value: 'humidity' }, {text: 'ppm', value: 'ppm' }, {text: 'decibel', value: 'dB' }, ] }, { - text: 'duration', + text: 'time', submenu: [ {text: 'Hertz (1/s)', value: 'hertz'}, {text: 'nanoseconds (ns)' , value: 'ns' }, @@ -533,13 +537,20 @@ function($, _) { ] }, { - text: 'weather', + text: 'temperature', submenu: [ {text: 'Celcius (°C)', value: 'celsius' }, {text: 'Farenheit (°F)', value: 'farenheit' }, - {text: 'Humidity (%H)', value: 'humidity' }, - {text: 'Pressure (mbar)', value: 'pressurembar'}, - {text: 'Pressure (hPa)', value: 'pressurehpa' }, + {text: 'Kelvin (K)', value: 'kelvin' }, + ] + }, + { + text: 'pressure', + submenu: [ + {text: 'Millibars', value: 'pressurembar'}, + {text: 'Hectopascals', value: 'pressurehpa' }, + {text: 'Inches of mercury', value: 'pressurehq' }, + {text: 'PSI', value: 'pressurepsi' }, ] }, ]; From 85887ad1cf8063d08fec83fc17d7f7d2612946aa Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 14:51:33 -0700 Subject: [PATCH 16/51] Add mile, fix menu values. --- public/app/components/kbn.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index aa3aad19fd9..9c9b337f1b3 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -352,7 +352,9 @@ function($, _) { // Length kbn.valueFormats.lengthm = kbn.formatBuilders.decimalSIPrefix('m'); + kbn.valueFormats.lengthmm = kbn.formatBuilders.decimalSIPrefix('m', -1); kbn.valueFormats.lengthkm = kbn.formatBuilders.decimalSIPrefix('m', 1); + kbn.valueFormats.lengthmi = kbn.formatBuilders.fixedUnit('mi'); // Velocity kbn.valueFormats.velocityms = kbn.formatBuilders.fixedUnit('m/s'); @@ -502,9 +504,8 @@ function($, _) { submenu: [ {text: 'millimetre (mm)', value: 'lengthmm'}, {text: 'meter (m)', value: 'lengthm' }, - {text: 'kilometer (km)', value: 'lengthm' }, - {text: 'inches', value: 'lengthin'}, - {text: 'feet', value: 'lengthft'}, + {text: 'kilometer (km)', value: 'lengthkm'}, + {text: 'mile (mi)', value: 'lengthmi'}, ] }, { @@ -549,7 +550,7 @@ function($, _) { submenu: [ {text: 'Millibars', value: 'pressurembar'}, {text: 'Hectopascals', value: 'pressurehpa' }, - {text: 'Inches of mercury', value: 'pressurehq' }, + {text: 'Inches of mercury', value: 'pressurehg' }, {text: 'PSI', value: 'pressurepsi' }, ] }, From 524f5d45ec1b1e76ded0ae79ba1df5958cfa2bb0 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 14:51:42 -0700 Subject: [PATCH 17/51] Add test for unit menu structure. --- public/test/specs/kbn-format-specs.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/public/test/specs/kbn-format-specs.js b/public/test/specs/kbn-format-specs.js index d7f97187716..feae3c261aa 100644 --- a/public/test/specs/kbn-format-specs.js +++ b/public/test/specs/kbn-format-specs.js @@ -4,6 +4,25 @@ define([ ], function(kbn, dateMath) { 'use strict'; + describe('unit format menu', function() { + var menu = kbn.getUnitFormats(); + menu.map(function(submenu) { + describe('submenu ' + submenu.text, function() { + it('should have a title', function() { expect(submenu.text).to.be.a('string'); }); + it('should have a submenu', function() { expect(submenu.submenu).to.be.an('array'); }); + submenu.submenu.map(function(entry) { + describe('entry ' + entry.text, function() { + it('should have a title', function() { expect(entry.text).to.be.a('string'); }); + it('should have a format', function() { expect(entry.value).to.be.a('string'); }); + it('should have a valid format', function() { + expect(kbn.valueFormats[entry.value]).to.be.a('function'); + }); + }); + }); + }); + }); + }); + function describeValueFormat(desc, value, tickSize, tickDecimals, result) { describe('value format: ' + desc, function() { From 0b3e33e2265fb686080c3b2f18ee2ddb11f3d77f Mon Sep 17 00:00:00 2001 From: Greg Look Date: Wed, 14 Oct 2015 15:40:04 -0700 Subject: [PATCH 18/51] Shorten percent unit labels. --- public/app/components/kbn.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index 9c9b337f1b3..e0aa81dc485 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -462,13 +462,13 @@ function($, _) { { text: 'none', submenu: [ - {text: 'none' , value: 'none' }, - {text: 'short', value: 'short' }, - {text: 'scaled percentage (0-100)', value: 'percent' }, - {text: 'unit percentage (0.0-1.0)', value: 'percentunit'}, - {text: 'Humidity (%H)', value: 'humidity' }, - {text: 'ppm', value: 'ppm' }, - {text: 'decibel', value: 'dB' }, + {text: 'none' , value: 'none' }, + {text: 'short', value: 'short' }, + {text: 'percent (0-100)', value: 'percent' }, + {text: 'percent (0.0-1.0)', value: 'percentunit'}, + {text: 'Humidity (%H)', value: 'humidity' }, + {text: 'ppm', value: 'ppm' }, + {text: 'decibel', value: 'dB' }, ] }, { From 882a988143711e551f42177fc11489dcf082db98 Mon Sep 17 00:00:00 2001 From: Greg Look Date: Thu, 15 Oct 2015 12:48:48 -0700 Subject: [PATCH 19/51] Add currency units from #1910. --- public/app/components/kbn.js | 23 +++++++++++++++++++++++ public/test/specs/kbn-format-specs.js | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/public/app/components/kbn.js b/public/app/components/kbn.js index e0aa81dc485..ad2d4c3c422 100644 --- a/public/app/components/kbn.js +++ b/public/app/components/kbn.js @@ -298,6 +298,18 @@ function($, _) { return kbn.formatBuilders.scaledUnits(1024, units); }; + // Currency formatter for prefixing a symbol onto a number. Supports scaling + // up to the trillions. + kbn.formatBuilders.currency = function(symbol) { + var units = ['', 'K', 'M', 'B', 'T']; + var scaler = kbn.formatBuilders.scaledUnits(1000, units); + return function(size, decimals, scaledDecimals) { + if (size === null) { return ""; } + var scaled = scaler(size, decimals, scaledDecimals); + return symbol + scaled; + }; + }; + ///// VALUE FORMATS ///// // Dimensionless Units @@ -316,6 +328,10 @@ function($, _) { return kbn.toFixed(100*size, decimals) + '%'; }; + // Currencies + kbn.valueFormats.currencyUSD = kbn.formatBuilders.currency('$'); + kbn.valueFormats.currencyGBP = kbn.formatBuilders.currency('£'); + // Data kbn.valueFormats.bits = kbn.formatBuilders.binarySIPrefix('b'); kbn.valueFormats.bytes = kbn.formatBuilders.binarySIPrefix('B'); @@ -471,6 +487,13 @@ function($, _) { {text: 'decibel', value: 'dB' }, ] }, + { + text: 'currency', + submenu: [ + {text: 'Dollars ($)', value: 'currencyUSD'}, + {text: 'Pounds (£)', value: 'currencyGBP'}, + ] + }, { text: 'time', submenu: [ diff --git a/public/test/specs/kbn-format-specs.js b/public/test/specs/kbn-format-specs.js index feae3c261aa..f84544fff4f 100644 --- a/public/test/specs/kbn-format-specs.js +++ b/public/test/specs/kbn-format-specs.js @@ -53,6 +53,10 @@ define([ describeValueFormat('percentunit', 0.278, 0, 1, '27.8%'); describeValueFormat('percentunit', 1.0, 0, 0, '100%'); + describeValueFormat('currencyUSD', 7.42, 10000, 2, '$7.42'); + describeValueFormat('currencyUSD', 1532.82, 1000, 1, '$1.53K'); + describeValueFormat('currencyUSD', 18520408.7, 10000000, 0, '$19M'); + describeValueFormat('bytes', -1.57e+308, -1.57e+308, 2, 'NA'); describeValueFormat('ns', 25, 1, 0, '25 ns'); From bd77fd92bbddd157bf491069e96aced8e8f862c4 Mon Sep 17 00:00:00 2001 From: "Scott M. Likens" Date: Thu, 15 Oct 2015 19:45:40 -0700 Subject: [PATCH 20/51] I'm not sure what a dashboard is ... --- docs/sources/reference/graph.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/reference/graph.md b/docs/sources/reference/graph.md index 9de23332a99..e8867d3d527 100644 --- a/docs/sources/reference/graph.md +++ b/docs/sources/reference/graph.md @@ -30,7 +30,7 @@ The drilldown section allows adding dynamic links to the panel that can link to or URLs Each link has a title, a type and params. A link can be either a ``dashboard`` or ``absolute`` links. -If it is a dashboard links, the `dashboard` value must be the name of a dashbaord. If it's an +If it is a dashboard links, the `dashboard` value must be the name of a dashboard. If it's an `absolute` link, the URL is the URL to link. ``params`` allows adding additional URL params to the links. The format is the ``name=value`` with From e507afc3d51a42af7e0c42de9fc0f981bd99ef51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Oct 2015 10:10:39 -0400 Subject: [PATCH 21/51] fix(panel): fix for firefox and placing cursor in text inputs when in panel fullscreen edit mode, fixes #2957 --- public/app/partials/dashboard.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/partials/dashboard.html b/public/app/partials/dashboard.html index 156da97e50a..78d54e1b5eb 100644 --- a/public/app/partials/dashboard.html +++ b/public/app/partials/dashboard.html @@ -79,7 +79,7 @@
-
From c320e9d58327f17c583287f365865e6d802aee0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Oct 2015 11:07:15 -0400 Subject: [PATCH 22/51] fix(annotations): fixed graphite annotations, broken by recent time handling changes, fixes #2947 --- public/app/plugins/datasource/graphite/datasource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/graphite/datasource.js b/public/app/plugins/datasource/graphite/datasource.js index 553a11c2350..f9e747fb984 100644 --- a/public/app/plugins/datasource/graphite/datasource.js +++ b/public/app/plugins/datasource/graphite/datasource.js @@ -75,7 +75,7 @@ function (angular, _, $, config, dateMath) { if (annotation.target) { var target = templateSrv.replace(annotation.target); var graphiteQuery = { - range: rangeUnparsed, + rangeRaw: rangeUnparsed, targets: [{ target: target }], format: 'json', maxDataPoints: 100 From c95a991cb30c272e288d16f56a447418869a71a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Oct 2015 11:58:44 -0400 Subject: [PATCH 23/51] fix(panel/common): fix for query letters when importing old dashboards, fixes #2943 --- public/app/features/dashboard/dashboardSrv.js | 19 +++++++++++++++---- public/test/specs/dashboardSrv-specs.js | 9 ++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/public/app/features/dashboard/dashboardSrv.js b/public/app/features/dashboard/dashboardSrv.js index 170cce52fbf..66372dea026 100644 --- a/public/app/features/dashboard/dashboardSrv.js +++ b/public/app/features/dashboard/dashboardSrv.js @@ -328,9 +328,20 @@ function (angular, $, kbn, _, moment) { } } - if (oldVersion < 7 && old.nav && old.nav.length) { - this.timepicker = old.nav[0]; - delete this.nav; + if (oldVersion < 7) { + if (old.nav && old.nav.length) { + this.timepicker = old.nav[0]; + delete this.nav; + } + + // ensure query refIds + panelUpgrades.push(function(panel) { + _.each(panel.targets, function(target) { + if (!target.refId) { + target.refId = this.getNextQueryLetter(panel); + } + }, this); + }); } if (panelUpgrades.length === 0) { @@ -341,7 +352,7 @@ function (angular, $, kbn, _, moment) { var row = this.rows[i]; for (j = 0; j < row.panels.length; j++) { for (k = 0; k < panelUpgrades.length; k++) { - panelUpgrades[k](row.panels[j]); + panelUpgrades[k].call(this, row.panels[j]); } } } diff --git a/public/test/specs/dashboardSrv-specs.js b/public/test/specs/dashboardSrv-specs.js index 112dc7b9aad..276e28b32c8 100644 --- a/public/test/specs/dashboardSrv-specs.js +++ b/public/test/specs/dashboardSrv-specs.js @@ -152,7 +152,10 @@ define([ rows: [ { panels: [ - {type: 'graphite', legend: true, aliasYAxis: { test: 2 }, grid: { min: 1, max: 10 }} + { + type: 'graphite', legend: true, aliasYAxis: { test: 2 }, grid: { min: 1, max: 10 }, + targets: [{refId: 'A'}, {}], + } ] } ] @@ -178,6 +181,10 @@ define([ expect(graph.type).to.be('graph'); }); + it('queries without refId should get it', function() { + expect(graph.targets[1].refId).to.be('B'); + }); + it('update legend setting', function() { expect(graph.legend.show).to.be(true); }); From dbc1a9cf82c94caa06f0762e120163e4a8ea000d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Oct 2015 12:07:35 -0400 Subject: [PATCH 24/51] fix(influxdb_0.8.x): fixed issue with new timepicker ranges like The day so far, fixes #2936 --- public/app/plugins/datasource/influxdb_08/datasource.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/influxdb_08/datasource.js b/public/app/plugins/datasource/influxdb_08/datasource.js index 5dabc93efa0..0bfa3f84527 100644 --- a/public/app/plugins/datasource/influxdb_08/datasource.js +++ b/public/app/plugins/datasource/influxdb_08/datasource.js @@ -266,11 +266,11 @@ function (angular, _, dateMath, InfluxSeries, InfluxQueryBuilder) { } function getInfluxTime(date, roundUp) { - if (_.isString(date) && date.indexOf('/') === -1) { + if (_.isString(date)) { if (date === 'now') { return 'now()'; } - if (date.indexOf('now-') >= 0) { + if (date.indexOf('now-') >= 0 && date.indexOf('/') === -1) { return date.replace('now', 'now()'); } date = dateMath.parse(date, roundUp); From b70b730cb96bd1d7f81e6bf67db3663c094843b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Oct 2015 12:26:30 -0400 Subject: [PATCH 25/51] fix(build): minor fix for build script to make latest copy for rpm when version is pre release version --- build.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build.go b/build.go index ca6f52ecd89..39c55c799ad 100644 --- a/build.go +++ b/build.go @@ -73,7 +73,7 @@ func main() { case "package": //verifyGitRepoIsClean() - grunt("release") + // grunt("release") createLinuxPackages() case "latest": @@ -89,8 +89,13 @@ func main() { } func makeLatestDistCopies() { + rpmIteration := "-1" + if linuxPackageIteration != "" { + rpmIteration = "-" + linuxPackageIteration + } + runError("cp", "dist/grafana_"+version+"_amd64.deb", "dist/grafana_latest_amd64.deb") - runError("cp", "dist/grafana-"+strings.Replace(version, "-", "_", 5)+"-1.x86_64.rpm", "dist/grafana-latest-1.x86_64.rpm") + runError("cp", "dist/grafana-"+linuxPackageVersion+rpmIteration+".x86_64.rpm", "dist/grafana-latest-1.x86_64.rpm") runError("cp", "dist/grafana-"+version+".linux-x64.tar.gz", "dist/grafana-latest.linux-x64.tar.gz") } From 43ca50ebbec938c1b29c27d3d7e75029240bf576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 16 Oct 2015 13:03:20 -0400 Subject: [PATCH 26/51] fix(build): anonther minor build script fix --- build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.go b/build.go index 39c55c799ad..7804d00890e 100644 --- a/build.go +++ b/build.go @@ -73,7 +73,7 @@ func main() { case "package": //verifyGitRepoIsClean() - // grunt("release") + grunt("release") createLinuxPackages() case "latest": From 867ac5df67c3a9baffb46e50b0be7d2a31df5bf7 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 19 Oct 2015 13:07:18 -0400 Subject: [PATCH 27/51] fix appending query strings in linkSrv When linkSrv appends parameters to a URL's query string, it would blindly add a ? to the URL even if the URL already contained a ? or the string to add was empty. This change fixes that behavior and some other edge cases. Includes a unit test to verify expected behavior. --- public/app/features/panellinks/linkSrv.js | 22 ++++++++-- public/test/specs/linkSrv-specs.js | 50 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 public/test/specs/linkSrv-specs.js diff --git a/public/app/features/panellinks/linkSrv.js b/public/app/features/panellinks/linkSrv.js index 413d3d9303b..2e1f3e16436 100644 --- a/public/app/features/panellinks/linkSrv.js +++ b/public/app/features/panellinks/linkSrv.js @@ -48,8 +48,22 @@ function (angular, kbn, _) { return url; } - url += (url.indexOf('?') !== -1 ? '&' : '?'); - return url + paramsArray.join('&'); + return this.appendToQueryString(url, paramsArray.join('&')); + }; + + this.appendToQueryString = function(url, stringToAppend) { + if (!_.isUndefined(stringToAppend) && stringToAppend !== null && stringToAppend !== '') { + var pos = url.indexOf('?'); + if (pos !== -1) { + if (url.length - pos > 1) { + url += '&'; + } + } else { + url += '?'; + } + url += stringToAppend; + } + return url; }; this.getAnchorInfo = function(link) { @@ -65,7 +79,6 @@ function (angular, kbn, _) { info.target = link.targetBlank ? '_blank' : '_self'; info.href = templateSrv.replace(link.url || '', scopedVars); info.title = templateSrv.replace(link.title || '', scopedVars); - info.href += '?'; } else if (link.dashUri) { info.href = 'dashboard/' + link.dashUri + '?'; @@ -91,8 +104,9 @@ function (angular, kbn, _) { } info.href = this.addParamsToUrl(info.href, params); + if (link.params) { - info.href += "&" + templateSrv.replace(link.params, scopedVars); + info.href = this.appendToQueryString(info.href, templateSrv.replace(link.params, scopedVars)); } return info; diff --git a/public/test/specs/linkSrv-specs.js b/public/test/specs/linkSrv-specs.js new file mode 100644 index 00000000000..8a978b650ff --- /dev/null +++ b/public/test/specs/linkSrv-specs.js @@ -0,0 +1,50 @@ +define([ + 'lodash', + 'app/features/panellinks/linkSrv' +], function(_) { + 'use strict'; + + describe('linkSrv', function() { + var _linkSrv; + + beforeEach(module('grafana.services')); + + beforeEach(inject(function(linkSrv) { + _linkSrv = linkSrv; + })); + + describe('when appending query strings', function() { + + it('add ? to URL if not present', function() { + var url = _linkSrv.appendToQueryString('http://example.com', 'foo=bar'); + expect(url).to.be('http://example.com?foo=bar'); + }); + + it('do not add & to URL if ? is present but query string is empty', function() { + var url = _linkSrv.appendToQueryString('http://example.com?', 'foo=bar'); + expect(url).to.be('http://example.com?foo=bar'); + }); + + it('add & to URL if query string is present', function() { + var url = _linkSrv.appendToQueryString('http://example.com?foo=bar', 'hello=world'); + expect(url).to.be('http://example.com?foo=bar&hello=world'); + }); + + it('do not change the URL if there is nothing to append', function() { + _.each(['', undefined, null], function(toAppend) { + var url1 = _linkSrv.appendToQueryString('http://example.com', toAppend); + expect(url1).to.be('http://example.com'); + + var url2 = _linkSrv.appendToQueryString('http://example.com?', toAppend); + expect(url2).to.be('http://example.com?'); + + var url3 = _linkSrv.appendToQueryString('http://example.com?foo=bar', toAppend); + expect(url3).to.be('http://example.com?foo=bar'); + }); + }); + + }); + + }); + +}); From 6fecb4bf3e28226b5de462d10062be24bcf2d33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 20 Oct 2015 10:02:56 -0400 Subject: [PATCH 28/51] fix(http route): fixed dashboard-solo route to not return 404, fixes #2979 --- pkg/api/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/api/api.go b/pkg/api/api.go index 27eb3c749db..013b2ebe076 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -40,7 +40,9 @@ func Register(r *macaron.Macaron) { r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index) r.Get("/admin/orgs", reqGrafanaAdmin, Index) r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index) + r.Get("/dashboard/*", reqSignedIn, Index) + r.Get("/dashboard-solo/*", reqSignedIn, Index) // sign up r.Get("/signup", Index) From f3ecdc5af4e1eb3545ae717fa1ab1a67720839b3 Mon Sep 17 00:00:00 2001 From: Jari Sukanen Date: Wed, 21 Oct 2015 14:31:06 +0300 Subject: [PATCH 29/51] influxdb: fix influxdb annotation query --- public/app/plugins/datasource/influxdb/datasource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js index fabe2278708..b8ee9b15d49 100644 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ b/public/app/plugins/datasource/influxdb/datasource.js @@ -78,7 +78,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQueryBuilder) { }; InfluxDatasource.prototype.annotationQuery = function(annotation, rangeUnparsed) { - var timeFilter = getTimeFilter({ range: rangeUnparsed }); + var timeFilter = getTimeFilter({ rangeRaw: rangeUnparsed }); var query = annotation.query.replace('$timeFilter', timeFilter); query = templateSrv.replace(query); From fc0705e87c5a2bb2aa77fe1234d87b2243cfad7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 21 Oct 2015 10:59:02 -0400 Subject: [PATCH 30/51] fix(elasticsearch): fix for daily pattern when getting index for today, is now using utc, fixes #2913 --- public/app/plugins/datasource/elasticsearch/index_pattern.js | 2 +- .../datasource/elasticsearch/specs/index_pattern_specs.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/elasticsearch/index_pattern.js b/public/app/plugins/datasource/elasticsearch/index_pattern.js index 29ddc9e5741..d565e22c0b6 100644 --- a/public/app/plugins/datasource/elasticsearch/index_pattern.js +++ b/public/app/plugins/datasource/elasticsearch/index_pattern.js @@ -20,7 +20,7 @@ function (_, moment) { IndexPattern.prototype.getIndexForToday = function() { if (this.interval) { - return moment().format(this.pattern); + return moment.utc().format(this.pattern); } else { return this.pattern; } diff --git a/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts index 8f662bb075f..ccebef59a12 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts @@ -8,7 +8,7 @@ declare var IndexPattern: any; describe('IndexPattern', function() { - describe('when getting index for today', function() { + describe.only('when getting index for today', function() { it('should return correct index name', function() { var pattern = new IndexPattern('[asd-]YYYY.MM.DD', 'Daily'); var expected = 'asd-' + moment().format('YYYY.MM.DD'); From 58497ed59641acdfbb2fea39e7b22e6378c3aa45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 21 Oct 2015 11:22:53 -0400 Subject: [PATCH 31/51] feat(panel): performance improvement for loading panels, closes #2994 --- public/app/app.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/public/app/app.js b/public/app/app.js index 4f30df34d89..1e7acf2e56f 100644 --- a/public/app/app.js +++ b/public/app/app.js @@ -100,12 +100,7 @@ function (angular, $, _, appLevelRequire) { var $scope = this; $scope.requireContext(deps, function () { var deps = _.toArray(arguments); - // Check that this is a valid scope. - if($scope.$id) { - $scope.$apply(function () { - fn.apply($scope, deps); - }); - } + fn.apply($scope, deps); }); }; }]); From a5e3d7a94b759fa7e5d381fb5b7b19bcf5088b0b Mon Sep 17 00:00:00 2001 From: ubhatnagar Date: Wed, 21 Oct 2015 20:58:04 -0700 Subject: [PATCH 32/51] Fixed datasources docs typos --- docs/sources/datasources/graphite.md | 4 ++-- docs/sources/datasources/influxdb.md | 2 +- docs/sources/datasources/kairosdb.md | 4 ++-- docs/sources/datasources/prometheus.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/sources/datasources/graphite.md b/docs/sources/datasources/graphite.md index dc545af5007..9640d21a81d 100644 --- a/docs/sources/datasources/graphite.md +++ b/docs/sources/datasources/graphite.md @@ -29,7 +29,7 @@ Url | The http protocol, ip and port of you graphite-web or graphite-api install Access | Proxy = access via Grafana backend, Direct = access directory from browser. -Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the Data Source to the brower. +Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the Data Source to the browser. Direct access is still supported because in some cases it may be useful to access a Data Source directly depending on the use case and topology of Grafana, the user, and the Data Source. @@ -78,4 +78,4 @@ You can also create nested variables that use other variables in their definitio ## Query Reference -You can reference queries by the row “letter” that they’re on (similar to Microsoft Excel). If you add a second query to graph, you can reference the first query simply by typing in #A. This provides an easy and convenient way to build compounded queries. \ No newline at end of file +You can reference queries by the row “letter” that they’re on (similar to Microsoft Excel). If you add a second query to graph, you can reference the first query simply by typing in #A. This provides an easy and convenient way to build compounded queries. diff --git a/docs/sources/datasources/influxdb.md b/docs/sources/datasources/influxdb.md index b48b2b0097a..35a6c914e65 100644 --- a/docs/sources/datasources/influxdb.md +++ b/docs/sources/datasources/influxdb.md @@ -33,7 +33,7 @@ Database | Name of your influxdb database User | Name of your database user Password | Database user's password - > Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the Data Source to the brower. + > Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the Data Source to the browser. > Direct access is still supported because in some cases it may be useful to access a Data Source directly depending on the use case and topology of Grafana, the user, and the Data Source. diff --git a/docs/sources/datasources/kairosdb.md b/docs/sources/datasources/kairosdb.md index 7619c8e8b1f..fc9b5682515 100644 --- a/docs/sources/datasources/kairosdb.md +++ b/docs/sources/datasources/kairosdb.md @@ -32,7 +32,7 @@ Open a graph in edit mode by click the title. ![](/img/v2/kairos_query_editor.png) -For details on KairosDB metric queries checkout the offical. +For details on KairosDB metric queries checkout the official. - [Query Metrics - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/QueryMetrics.html). ## Templated queries @@ -49,4 +49,4 @@ For details of `metric names`, `tag names`, and `tag values`, please refer to th - [List Metric Names - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/ListMetricNames.html) - [List Tag Names - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/ListTagNames.html) - [List Tag Values - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/ListTagValues.html) -- [Query Metrics - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/QueryMetrics.html). \ No newline at end of file +- [Query Metrics - KairosDB 0.9.4 documentation](http://kairosdb.github.io/kairosdocs/restapi/QueryMetrics.html). diff --git a/docs/sources/datasources/prometheus.md b/docs/sources/datasources/prometheus.md index e975a5cf8a4..61f6c0d66e8 100644 --- a/docs/sources/datasources/prometheus.md +++ b/docs/sources/datasources/prometheus.md @@ -28,7 +28,7 @@ Basic Auth | Enable basic authentication to the Prometheus datasource. User | Name of your Prometheus user Password | Database user's password - > Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the Data Source to the brower. + > Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the Data Source to the browser. > Direct access is still supported because in some cases it may be useful to access a Data Source directly depending on the use case and topology of Grafana, the user, and the Data Source. From aaf4b1a3994e9ba6a06c17d92e8ea70ef15543ae Mon Sep 17 00:00:00 2001 From: ubhatnagar Date: Wed, 21 Oct 2015 21:13:39 -0700 Subject: [PATCH 33/51] Fixed typos in guides. --- docs/sources/guides/gettingstarted.md | 2 +- docs/sources/guides/screencasts.md | 2 +- docs/sources/guides/whats-new-in-v2-1.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/guides/gettingstarted.md b/docs/sources/guides/gettingstarted.md index 93d67048ad6..6f9ef76232d 100644 --- a/docs/sources/guides/gettingstarted.md +++ b/docs/sources/guides/gettingstarted.md @@ -29,7 +29,7 @@ The image above shows you the top header for a Dashboard. 6. Settings: Manage Dashboard settings and features such as Templating and Annotations. ## Dashboards, Panels, Rows, the building blocks of Grafana... -Dashboards are at the core of what Grafana is all about. Dashboards are composed of individual Panels arranged on a number of Rows. Grafana ships with a variety of Panels. Gafana makes it easy to construct the right queries, and customize the display properities so that you can create the perfect Dashboard for your need. Each Panel can interact with data from any configured Grafana Data Source (currently InfluxDB, Graphite, OpenTSDB, and KairosDB). The [Core Concepts](/guides/basic_concepts) guide explores these key ideas in detail. +Dashboards are at the core of what Grafana is all about. Dashboards are composed of individual Panels arranged on a number of Rows. Grafana ships with a variety of Panels. Grafana makes it easy to construct the right queries, and customize the display properties so that you can create the perfect Dashboard for your need. Each Panel can interact with data from any configured Grafana Data Source (currently InfluxDB, Graphite, OpenTSDB, and KairosDB). The [Core Concepts](/guides/basic_concepts) guide explores these key ideas in detail. ## Adding & Editing Graphs and Panels diff --git a/docs/sources/guides/screencasts.md b/docs/sources/guides/screencasts.md index edf3d7b8122..500ca9f9b6a 100644 --- a/docs/sources/guides/screencasts.md +++ b/docs/sources/guides/screencasts.md @@ -32,7 +32,7 @@ no_toc: true

Episode 4 - Installation & Configuration on Ubuntu / Debian

- Learn how to easily install the dependencies and packages to get Grafana 2.0 up and running on Ubuntu or Debian in just a few mintues. + Learn how to easily install the dependencies and packages to get Grafana 2.0 up and running on Ubuntu or Debian in just a few minutes.
diff --git a/docs/sources/guides/whats-new-in-v2-1.md b/docs/sources/guides/whats-new-in-v2-1.md index 27285d08857..10519cb0422 100644 --- a/docs/sources/guides/whats-new-in-v2-1.md +++ b/docs/sources/guides/whats-new-in-v2-1.md @@ -112,7 +112,7 @@ for example make all series that contain the word **CPU** `red` and assigned to ![Define series color using regex rule](/img/v2/regex_color_override.png "Define series color using regex rule") -New series style override, negative-y transform and stack groups. Negative y tranform is +New series style override, negative-y transform and stack groups. Negative y transform is very useful if you want to plot a series on the negative y scale without affecting the legend values like min or max or the values shown in the hover tooltip. From 1e2e4ba3ad3ee2105add631c9254e428b9653864 Mon Sep 17 00:00:00 2001 From: ubhatnagar Date: Wed, 21 Oct 2015 22:09:07 -0700 Subject: [PATCH 34/51] Fixed other docs typos --- docs/sources/installation/docker.md | 2 +- docs/sources/installation/ldap.md | 6 +++--- docs/sources/project/building_from_source.md | 2 +- docs/sources/reference/admin.md | 2 +- docs/sources/reference/dashlist.md | 2 +- docs/sources/reference/graph.md | 2 +- docs/sources/reference/keyboard_shortcuts.md | 4 ++-- docs/sources/reference/search.md | 12 ++++++------ docs/sources/reference/sharing.md | 2 +- docs/sources/reference/singlestat.md | 6 +++--- docs/sources/reference/templating.md | 4 ++-- docs/sources/tutorials/hubot_howto.md | 6 +++--- 12 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/sources/installation/docker.md b/docs/sources/installation/docker.md index 53366bed44a..18dcf964450 100644 --- a/docs/sources/installation/docker.md +++ b/docs/sources/installation/docker.md @@ -9,7 +9,7 @@ page_keywords: grafana, installation, docker, container, guide > **2.0.2 -> 2.1.0 Upgrade NOTICE!** > The data and log paths were not correct in the previous image. The grafana database was placed by default in /usr/share/grafana/data instead of the correct path /var/lib/grafana. This means it was not in a dir that was marked as a volume. So if you remove the container it will remove the grafana database. So before updating make sure you copy the /usr/share/grafana/data path from inside the container to the host. -## Install from offical docker image +## Install from official docker image Grafana has an official Docker container. diff --git a/docs/sources/installation/ldap.md b/docs/sources/installation/ldap.md index f0325a953fe..45552a8e2b0 100644 --- a/docs/sources/installation/ldap.md +++ b/docs/sources/installation/ldap.md @@ -1,6 +1,6 @@ --- page_title: LDAP Integration -page_description: LDAP Integrtaion guide for Grafana. +page_description: LDAP Integration guide for Grafana. page_keywords: grafana, ldap, configuration, documentation, integration --- @@ -85,12 +85,12 @@ bind_dn = "cn=%s,o=users,dc=grafana,dc=org" ``` In this case you skip providing a `bind_password` and instead provide a `bind_dn` value with a `%s` somewhere. This will be replaced with the username entered in on the Grafana login page. -The search filter and search bases settings are still needed to perform the LDAP search to retreive the other LDAP information (like LDAP groups and email). +The search filter and search bases settings are still needed to perform the LDAP search to retrieve the other LDAP information (like LDAP groups and email). ## LDAP to Grafana Org Role Sync ## Group Mappings -In `[[servers.group_mappings]]` you can map an LDAP group to a Grafana organization and role. These will be synced every time the user logs in, with LDAP being the authoratative source. +In `[[servers.group_mappings]]` you can map an LDAP group to a Grafana organization and role. These will be synced every time the user logs in, with LDAP being the authoritative source. So, if you change a user's role in the Grafana Org. Users page, this change will be reset the next time the user logs in. If you change the LDAP groups of a user, the change will take effect the next time the user logs in. ### Priority between Multiple Mappings diff --git a/docs/sources/project/building_from_source.md b/docs/sources/project/building_from_source.md index 45ab26249c8..71e94b088fb 100644 --- a/docs/sources/project/building_from_source.md +++ b/docs/sources/project/building_from_source.md @@ -25,7 +25,7 @@ go get github.com/grafana/grafana ``` cd $GOPATH/src/github.com/grafana/grafana go run build.go setup # (only needed once to install godep) -$GOPATH/bin/godep restore # (will pull down all golang lib dependecies in your current GOPATH) +$GOPATH/bin/godep restore # (will pull down all golang lib dependencies in your current GOPATH) go run build.go build # (or 'go build .') ``` diff --git a/docs/sources/reference/admin.md b/docs/sources/reference/admin.md index 854147b4240..c5d5073020d 100644 --- a/docs/sources/reference/admin.md +++ b/docs/sources/reference/admin.md @@ -24,7 +24,7 @@ modify Organization details and options. As a Grafana Administrator, you have complete access to any Organization or User in that instance of Grafana. -When performing actions as a Grafana admin, the sidebar will change it's apperance as below to indicate you are performing global server administration. +When performing actions as a Grafana admin, the sidebar will change it's appearance as below to indicate you are performing global server administration. From the Grafana Server Admin page, you can access the System Info page which summarizes all of the backend configuration settings of the Grafana server. diff --git a/docs/sources/reference/dashlist.md b/docs/sources/reference/dashlist.md index 1f0794dabfc..ea098541da2 100644 --- a/docs/sources/reference/dashlist.md +++ b/docs/sources/reference/dashlist.md @@ -8,7 +8,7 @@ page_keywords: grafana, dashlist, panel, documentation ## Overview -The dashboard list panel allows you to display dynamic links to other dashboards. The list can be configured to use starred dashbaords, a search query and/or dashboard tags. +The dashboard list panel allows you to display dynamic links to other dashboards. The list can be configured to use starred dashboards, a search query and/or dashboard tags. diff --git a/docs/sources/reference/graph.md b/docs/sources/reference/graph.md index e8867d3d527..9c2ab63fbaa 100644 --- a/docs/sources/reference/graph.md +++ b/docs/sources/reference/graph.md @@ -127,7 +127,7 @@ If you have stack enabled you can select what the mouse hover feature should sho ### Rendering - ``Flot`` - Render the graphs in the browser using Flot (default) -- ``Graphite PNG`` - Render the graph on the server using graphites render API. +- ``Graphite PNG`` - Render the graph on the server using graphite's render API. ### Tooltip diff --git a/docs/sources/reference/keyboard_shortcuts.md b/docs/sources/reference/keyboard_shortcuts.md index b6e199e4e70..627bfc5c3dd 100644 --- a/docs/sources/reference/keyboard_shortcuts.md +++ b/docs/sources/reference/keyboard_shortcuts.md @@ -1,5 +1,5 @@ -page_title: Kayboard Shortcuts -page_description: Kayboard Shortcuts for Grafana +page_title: Keyboard Shortcuts +page_description: Keyboard Shortcuts for Grafana page_keywords: grafana, export, import, documentation --- diff --git a/docs/sources/reference/search.md b/docs/sources/reference/search.md index 3c4555b843e..e2d6647229c 100644 --- a/docs/sources/reference/search.md +++ b/docs/sources/reference/search.md @@ -11,7 +11,7 @@ Dashboards can be searched by the dashboard name, filtered by one (or many) tags 1. `Dashboard Picker`: The Dashboard Picker is your primary navigation tool to move between dashboards. It is present on all dashboards, and open the Dashboard Search. The dashboard picker also doubles as the title of the current dashboard. -2. `Search Bar`: The search bar allows you to enter any string and search both database and file based dashbaords in real-time. +2. `Search Bar`: The search bar allows you to enter any string and search both database and file based dashboards in real-time. 3. `Starred`: The starred link allows you to filter the list to display only starred dashboards. 4. `Tags`: The tags filter allows you to filter the list by dashboard tags. @@ -25,14 +25,14 @@ To search and load dashboards click the open folder icon in the header or use th Dashboard search is: - Real-time -- *Not* case senstitive +- *Not* case sensitive - Functional across stored *and* file based dashboards. ## Filter by Tag(s) -Tags are a great way to organize your dashboards, especially as the number of dashbaords grow. Tags can be added and managed in the dashboard `Settings`. +Tags are a great way to organize your dashboards, especially as the number of dashboards grow. Tags can be added and managed in the dashboard `Settings`. -To filter the dashboard list by tag, click on any tag appearing in the right column. The list may be further filtered by cliking on additional tags: +To filter the dashboard list by tag, click on any tag appearing in the right column. The list may be further filtered by clicking on additional tags: @@ -40,7 +40,7 @@ Alternately, to see a list of all available tags, click the tags link in the sea -When using only a keybaord: `tab` to focus on the *tags* link, `▼` down arrow key to find a tag and select with the `Enter` key. +When using only a keyboard: `tab` to focus on the *tags* link, `▼` down arrow key to find a tag and select with the `Enter` key. **Note**: When multiple tags are selected, Grafana will show dashboards that include **all**. @@ -51,4 +51,4 @@ Starring is a great way to organize and find commonly used dashboards. To show o -When using only a keybaord: `tab` to focus on the *stars* link, `▼` down arrow key to find a tag and select with the `Enter` key. \ No newline at end of file +When using only a keyboard: `tab` to focus on the *stars* link, `▼` down arrow key to find a tag and select with the `Enter` key. \ No newline at end of file diff --git a/docs/sources/reference/sharing.md b/docs/sources/reference/sharing.md index e3a6ce3f2f5..c20f4e5f67c 100644 --- a/docs/sources/reference/sharing.md +++ b/docs/sources/reference/sharing.md @@ -5,7 +5,7 @@ page_keywords: grafana, sharing, guide, documentation --- # Sharing features -Grafana provides a number of ways to share a dashboard or a specfic panel to other users within your +Grafana provides a number of ways to share a dashboard or a specific panel to other users within your organization. It also provides ways to publish interactive snapshots that can be accessed by external partners. ## Share dashboard diff --git a/docs/sources/reference/singlestat.md b/docs/sources/reference/singlestat.md index 7a7c38da289..a6a6a06c806 100644 --- a/docs/sources/reference/singlestat.md +++ b/docs/sources/reference/singlestat.md @@ -21,7 +21,7 @@ The singlestat panel has a normal query editor to allow you define your exact me 3. `Values`: The Value fields let you set the function (min, max, average, current, total) that your entire query is reduced into a single value with. You can also set the font size of theand font-size (as a %) of the metric query that the Panel is configured with. This reduces the entire query into a single summary value that is displayed. 4. `Postfixes`: The Postfix fields let you define a custom label and font-size (as a %) to appear *after* the value 5. `Units`: Units are appended to the the Singlestat within the panel, and will respect the color and threshold settings for the value. -6. `Decimals`: The Decimal field allows you to override the automatic decimal precision, and set it explicitely. +6. `Decimals`: The Decimal field allows you to override the automatic decimal precision, and set it explicitly. ### Coloring @@ -29,9 +29,9 @@ The coloring options of the Singlestat Panel config allow you to dynamically cha -1. `Background`: This checkbox applies the configured thresholds and colors to the entirity of the Singlestat Panel background. +1. `Background`: This checkbox applies the configured thresholds and colors to the entirety of the Singlestat Panel background. 2. `Value`: This checkbox applies the configured thresholds and colors to the summary stat. -3. `Thresholds`: Change the background and value colors dyanmically within the panel, depending on the Singlestat value. The threshold field accepts **3 comma-separated** values, corresponding to the three colors directly to the right. +3. `Thresholds`: Change the background and value colors dynamically within the panel, depending on the Singlestat value. The threshold field accepts **3 comma-separated** values, corresponding to the three colors directly to the right. 4. `Colors`: Select a color and opacity 5. `Invert order`: This link toggles the threshold color order.
For example: Green, Orange, Red () will become Red, Orange, Green (). diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index 239cb33c378..e605af845ea 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -63,7 +63,7 @@ Once configured, Multi-Select Tagging provides a convenient way to group and you ### Interval -Use the `Interval` type to create Template variables aroundr time ranges (eg. `1m`,`1h`, `1d`). There is also a special `auto` option that will change depending on the current time range, you can specify how many times the current time range should be divided to calculate the current `auto` range. +Use the `Interval` type to create Template variables around time ranges (eg. `1m`,`1h`, `1d`). There is also a special `auto` option that will change depending on the current time range, you can specify how many times the current time range should be divided to calculate the current `auto` range. ![](/img/v2/templated_variable_parameter.png) @@ -75,7 +75,7 @@ Use the `Custom` type to manually create Template variables around explicit valu Template Variables can be very useful to dynamically change what you're visualizing on a given panel. Sometimes, you might want to create entire new Panels (or Rows) based on what Template Variables have been selected. This is now possible in Grafana 2.1. -Once you've got your Template variables (of any type) configured the way you'd like, check out the Repeating Panels and Repeating Row documentatione +Once you've got your Template variables (of any type) configured the way you'd like, check out the Repeating Panels and Repeating Row documentation ## Screencast - Templated Graphite Queries diff --git a/docs/sources/tutorials/hubot_howto.md b/docs/sources/tutorials/hubot_howto.md index b2f53d0bece..85ebb3e7c85 100644 --- a/docs/sources/tutorials/hubot_howto.md +++ b/docs/sources/tutorials/hubot_howto.md @@ -64,13 +64,13 @@ The `hubot-grafana` plugin requires a number of environment variables to be set The hubot plugin will take advantage of the Grafana server side rendering feature that can render any panel on the server using phantomjs. Grafana ships with a phantomjs binary (linux only). -To verify that this freature works try the `Direct link to rendered image` link in the panel share dialog. +To verify that this feature works try the `Direct link to rendered image` link in the panel share dialog. If you do not get an image when opening this link verify that the required font packages are installed for phantomjs to work. ### Grafana API Key You need to set the environment variable `HUBOT_GRAFANA_API_KEY` to a Grafana API Key. -You can add these from the API Keys page wich you find in the Organization dropdown. +You can add these from the API Keys page which you find in the Organization dropdown. ### Amazon S3 The `S3` options are optional but for the images to work properly in services like Slack and Hipchat they need @@ -118,7 +118,7 @@ Now you can add an alias like this: ## Summary -Grafana is going to ship with integrated Slack and Hiptchat features some day but you do +Grafana is going to ship with integrated Slack and Hipchat features some day but you do not have to wait for that. Grafana 2 shipped with a very clever server side rendering feature that can render any panel to a png using phantomjs. The hubot plugin for Grafana is something you can install and use today! From eb8c2d9053ec55bc18a0192e1f1f20a7307b7621 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Thu, 22 Oct 2015 13:10:10 +0200 Subject: [PATCH 35/51] Ability to set a low limit for Elasticsearch date histogram interval closes #2901 --- .../elasticsearch/partials/query.options.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/public/app/plugins/datasource/elasticsearch/partials/query.options.html b/public/app/plugins/datasource/elasticsearch/partials/query.options.html index ab345d0eb59..eb6c6ff55fb 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/query.options.html +++ b/public/app/plugins/datasource/elasticsearch/partials/query.options.html @@ -1,4 +1,22 @@
+
+
    +
  • + +
  • +
  • + Group by time interval +
  • +
  • + +
  • +
  • + +
  • +
+
+
  • From 62c908a905dcacfc94776dca4b99c3b902559731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 10:02:29 -0400 Subject: [PATCH 36/51] fix(build): fixed partials so they are included in optimized js file, fixes #2997 --- tasks/build_task.js | 1 - tasks/options/concat.js | 1 - tasks/options/ngtemplates.js | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tasks/build_task.js b/tasks/build_task.js index 364c3dc797c..7773299a06d 100644 --- a/tasks/build_task.js +++ b/tasks/build_task.js @@ -23,7 +23,6 @@ module.exports = function(grunt) { 'filerev', 'remapFilerev', 'usemin', - 'clean:temp', 'uglify:genDir' ]); diff --git a/tasks/options/concat.js b/tasks/options/concat.js index 96ad9ae1341..c15aa8a2d6e 100644 --- a/tasks/options/concat.js +++ b/tasks/options/concat.js @@ -24,7 +24,6 @@ module.exports = function(config) { ], dest: '<%= genDir %>/css/grafana.light.min.css' }, - js: { src: [ '<%= tempDir %>/vendor/requirejs/require.js', diff --git a/tasks/options/ngtemplates.js b/tasks/options/ngtemplates.js index 2ccdf4ce5ef..10c39a49c39 100644 --- a/tasks/options/ngtemplates.js +++ b/tasks/options/ngtemplates.js @@ -6,7 +6,7 @@ module.exports = function(config) { dest: '<%= genDir %>/app/components/partials.js', options: { bootstrap: function(module, script) { - return "define('components/partials', ['angular'], function(angular) { \n" + + return "define('app/components/partials', ['angular'], function(angular) { \n" + "angular.module('grafana').run(['$templateCache', function($templateCache) { \n" + script + '\n}]);' + From 3228c4f41a584bc67c3556f710b7e4c4e5abd3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 12:27:22 -0400 Subject: [PATCH 37/51] changelog: updated with info about new units PR #2955 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e01e105db6c..bbe75e84210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ it allows you to add queries of differnet data source types & instances to the s - [Issue #2708](https://github.com/grafana/grafana/issues/2708). InfluxDB: You can now set math expression for select clauses. - [Issue #1575](https://github.com/grafana/grafana/issues/1575). Drilldown link: now you can click on the external link icon in the panel header to access drilldown links! - [Issue #1646](https://github.com/grafana/grafana/issues/1646). OpenTSDB: Fetch list of aggregators from OpenTSDB +- [Issue #2955](https://github.com/grafana/grafana/issues/2955). Graph: More axis units (Length, Volume, Temperature, Pressure, etc), thanks @greglook **Fixes** - [Issue #2413](https://github.com/grafana/grafana/issues/2413). InfluxDB 0.9: Fix for handling empty series object in response from influxdb From 87715d6231b2c438bea991a2f1c30ee30dd09b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 12:33:42 -0400 Subject: [PATCH 38/51] fix(solo panel): fixed solo panel view gray bottom for rendered image and embedd iframe scenarios, fixes #3004 --- public/app/features/panel/soloPanelCtrl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/panel/soloPanelCtrl.js b/public/app/features/panel/soloPanelCtrl.js index 55e1c029200..c51f9c61a9d 100644 --- a/public/app/features/panel/soloPanelCtrl.js +++ b/public/app/features/panel/soloPanelCtrl.js @@ -26,7 +26,7 @@ function (angular, $) { $scope.initPanelScope = function() { $scope.row = { - height: ($(window).height() - 10) + 'px', + height: $(window).height() + 'px', }; $scope.test = "Hej"; From ae93f2b936cda93b8141a6ff61adb18037aca4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 16:23:21 -0400 Subject: [PATCH 39/51] fix(elasticsearch): fixed proper json escaping for lucene query, fixes #2981 --- .../datasource/elasticsearch/datasource.js | 5 ++++- .../elasticsearch/specs/datasource_specs.ts | 20 +++++++++++++------ .../specs/index_pattern_specs.ts | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 9d6b8e4c834..374fc9da90d 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -159,7 +159,10 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes if (target.hide) {return;} var esQuery = angular.toJson(this.queryBuilder.build(target)); - esQuery = esQuery.replace("$lucene_query", target.query || '*'); + var luceneQuery = angular.toJson(target.query || '*'); + // remove inner quotes + luceneQuery = luceneQuery.substr(1, luceneQuery.length - 2); + esQuery = esQuery.replace("$lucene_query", luceneQuery); payload += header + '\n' + esQuery + '\n'; sentTargets.push(target); diff --git a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts index aecb16501b7..a5e55abe4dd 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts @@ -42,16 +42,15 @@ describe('ElasticDatasource', function() { }); describe('When issueing metric query with interval pattern', function() { + var requestOptions, parts, header; + beforeEach(function() { ctx.ds = new ctx.service({ url: 'http://es.com', index: '[asd-]YYYY.MM.DD', jsonData: { interval: 'Daily' } }); - }); - it('should translate index pattern to current day', function() { - var requestOptions; ctx.backendSrv.datasourceRequest = function(options) { requestOptions = options; return ctx.$q.when({data: {responses: []}}); @@ -62,13 +61,22 @@ describe('ElasticDatasource', function() { from: moment([2015, 4, 30, 10]), to: moment([2015, 5, 1, 10]) }, - targets: [{ bucketAggs: [], metrics: [] }] + targets: [{ bucketAggs: [], metrics: [], query: 'escape\\:test' }] }); ctx.$rootScope.$apply(); - var parts = requestOptions.data.split('\n'); - var header = angular.fromJson(parts[0]); + + parts = requestOptions.data.split('\n'); + header = angular.fromJson(parts[0]); + }); + + it('should translate index pattern to current day', function() { expect(header.index).to.eql(['asd-2015.05.30', 'asd-2015.05.31', 'asd-2015.06.01']); }); + + it('should json escape lucene query', function() { + var body = angular.fromJson(parts[1]); + expect(body.query.filtered.query.query_string.query).to.be('escape\\:test'); + }); }); }); diff --git a/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts index ccebef59a12..8f662bb075f 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts @@ -8,7 +8,7 @@ declare var IndexPattern: any; describe('IndexPattern', function() { - describe.only('when getting index for today', function() { + describe('when getting index for today', function() { it('should return correct index name', function() { var pattern = new IndexPattern('[asd-]YYYY.MM.DD', 'Daily'); var expected = 'asd-' + moment().format('YYYY.MM.DD'); From 8526230b59a45da968912c09e9fc64837c3136d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 16:53:34 -0400 Subject: [PATCH 40/51] fix(influxdb_08): fixed influxdb 08 query editor issue, fixes #3009 --- .../datasource/influxdb_08/datasource.js | 8 +- .../{funcEditor.js => func_editor.js} | 0 .../{influxSeries.js => influx_series.js} | 0 .../{queryBuilder.js => query_builder.js} | 0 .../{queryCtrl.js => query_ctrl.js} | 3 +- .../influxdb_08/specs/datasource-specs.ts | 97 ++++++++ .../influxdb_08/specs/influx_series_specs.ts | 220 ++++++++++++++++++ .../influxdb_08/specs/query_builder_specs.ts | 78 +++++++ public/test/specs/influxQueryBuilder-specs.js | 78 ------- public/test/specs/influxSeries08-specs.js | 220 ------------------ .../test/specs/influxdb-datasource-specs.js | 101 -------- 11 files changed, 401 insertions(+), 404 deletions(-) rename public/app/plugins/datasource/influxdb_08/{funcEditor.js => func_editor.js} (100%) rename public/app/plugins/datasource/influxdb_08/{influxSeries.js => influx_series.js} (100%) rename public/app/plugins/datasource/influxdb_08/{queryBuilder.js => query_builder.js} (100%) rename public/app/plugins/datasource/influxdb_08/{queryCtrl.js => query_ctrl.js} (99%) create mode 100644 public/app/plugins/datasource/influxdb_08/specs/datasource-specs.ts create mode 100644 public/app/plugins/datasource/influxdb_08/specs/influx_series_specs.ts create mode 100644 public/app/plugins/datasource/influxdb_08/specs/query_builder_specs.ts delete mode 100644 public/test/specs/influxQueryBuilder-specs.js delete mode 100644 public/test/specs/influxSeries08-specs.js delete mode 100644 public/test/specs/influxdb-datasource-specs.js diff --git a/public/app/plugins/datasource/influxdb_08/datasource.js b/public/app/plugins/datasource/influxdb_08/datasource.js index 0bfa3f84527..a5058db3eb6 100644 --- a/public/app/plugins/datasource/influxdb_08/datasource.js +++ b/public/app/plugins/datasource/influxdb_08/datasource.js @@ -2,11 +2,11 @@ define([ 'angular', 'lodash', 'app/core/utils/datemath', - './influxSeries', - './queryBuilder', + './influx_series', + './query_builder', './directives', - './queryCtrl', - './funcEditor', + './query_ctrl', + './func_editor', ], function (angular, _, dateMath, InfluxSeries, InfluxQueryBuilder) { 'use strict'; diff --git a/public/app/plugins/datasource/influxdb_08/funcEditor.js b/public/app/plugins/datasource/influxdb_08/func_editor.js similarity index 100% rename from public/app/plugins/datasource/influxdb_08/funcEditor.js rename to public/app/plugins/datasource/influxdb_08/func_editor.js diff --git a/public/app/plugins/datasource/influxdb_08/influxSeries.js b/public/app/plugins/datasource/influxdb_08/influx_series.js similarity index 100% rename from public/app/plugins/datasource/influxdb_08/influxSeries.js rename to public/app/plugins/datasource/influxdb_08/influx_series.js diff --git a/public/app/plugins/datasource/influxdb_08/queryBuilder.js b/public/app/plugins/datasource/influxdb_08/query_builder.js similarity index 100% rename from public/app/plugins/datasource/influxdb_08/queryBuilder.js rename to public/app/plugins/datasource/influxdb_08/query_builder.js diff --git a/public/app/plugins/datasource/influxdb_08/queryCtrl.js b/public/app/plugins/datasource/influxdb_08/query_ctrl.js similarity index 99% rename from public/app/plugins/datasource/influxdb_08/queryCtrl.js rename to public/app/plugins/datasource/influxdb_08/query_ctrl.js index c6304bc50ae..093e0af84d1 100644 --- a/public/app/plugins/datasource/influxdb_08/queryCtrl.js +++ b/public/app/plugins/datasource/influxdb_08/query_ctrl.js @@ -89,6 +89,7 @@ function (angular) { } }; - }); + $scope.init(); + }); }); diff --git a/public/app/plugins/datasource/influxdb_08/specs/datasource-specs.ts b/public/app/plugins/datasource/influxdb_08/specs/datasource-specs.ts new file mode 100644 index 00000000000..c4ea81759e8 --- /dev/null +++ b/public/app/plugins/datasource/influxdb_08/specs/datasource-specs.ts @@ -0,0 +1,97 @@ +/// +/// +/// +/// + +import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; + +declare var helpers: any; + +describe('InfluxDatasource', function() { + var ctx = new helpers.ServiceTestContext(); + + beforeEach(angularMocks.module('grafana.services')); + beforeEach(ctx.providePhase(['templateSrv'])); + beforeEach(ctx.createService('InfluxDatasource_08')); + beforeEach(function() { + ctx.ds = new ctx.service({ url: '', user: 'test', password: 'mupp' }); + }); + + describe('When querying influxdb with one target using query editor target spec', function() { + var results; + var urlExpected = "/series?p=mupp&q=select+mean(value)+from+%22test%22+where+time+%3E+now()-1h+group+by+time(1s)+order+asc"; + var query = { + rangeRaw: { from: 'now-1h', to: 'now' }, + targets: [{ series: 'test', column: 'value', function: 'mean' }], + interval: '1s' + }; + + var response = [{ + columns: ["time", "sequence_nr", "value"], + name: 'test', + points: [[10, 1, 1]], + }]; + + beforeEach(function() { + ctx.$httpBackend.expect('GET', urlExpected).respond(response); + ctx.ds.query(query).then(function(data) { results = data; }); + ctx.$httpBackend.flush(); + }); + + it('should generate the correct query', function() { + ctx.$httpBackend.verifyNoOutstandingExpectation(); + }); + + it('should return series list', function() { + expect(results.data.length).to.be(1); + expect(results.data[0].target).to.be('test.value'); + }); + + }); + + describe('When querying influxdb with one raw query', function() { + var results; + var urlExpected = "/series?p=mupp&q=select+value+from+series+where+time+%3E+now()-1h"; + var query = { + rangeRaw: { from: 'now-1h', to: 'now' }, + targets: [{ query: "select value from series where $timeFilter", rawQuery: true }] + }; + + var response = []; + + beforeEach(function() { + ctx.$httpBackend.expect('GET', urlExpected).respond(response); + ctx.ds.query(query).then(function(data) { results = data; }); + ctx.$httpBackend.flush(); + }); + + it('should generate the correct query', function() { + ctx.$httpBackend.verifyNoOutstandingExpectation(); + }); + + }); + + describe('When issuing annotation query', function() { + var results; + var urlExpected = "/series?p=mupp&q=select+title+from+events.backend_01+where+time+%3E+now()-1h"; + + var range = { from: 'now-1h', to: 'now' }; + var annotation = { query: 'select title from events.$server where $timeFilter' }; + var response = []; + + beforeEach(function() { + ctx.templateSrv.replace = function(str) { + return str.replace('$server', 'backend_01'); + }; + ctx.$httpBackend.expect('GET', urlExpected).respond(response); + ctx.ds.annotationQuery(annotation, range).then(function(data) { results = data; }); + ctx.$httpBackend.flush(); + }); + + it('should generate the correct query', function() { + ctx.$httpBackend.verifyNoOutstandingExpectation(); + }); + + }); + +}); diff --git a/public/app/plugins/datasource/influxdb_08/specs/influx_series_specs.ts b/public/app/plugins/datasource/influxdb_08/specs/influx_series_specs.ts new file mode 100644 index 00000000000..f8f2e4ed62f --- /dev/null +++ b/public/app/plugins/datasource/influxdb_08/specs/influx_series_specs.ts @@ -0,0 +1,220 @@ +/// + +import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; + +declare var InfluxSeries: any; + +describe('when generating timeseries from influxdb response', function() { + + describe('given two series', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server1.cpu', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + }, + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server2.cpu', + points: [[1402596000, 15, 1], [1402596001, 16, 2]] + } + ] + }); + + var result = series.getTimeSeries(); + + it('should generate two time series', function() { + expect(result.length).to.be(2); + expect(result[0].target).to.be('prod.server1.cpu.mean'); + expect(result[0].datapoints[0][0]).to.be(10); + expect(result[0].datapoints[0][1]).to.be(1402596000); + expect(result[0].datapoints[1][0]).to.be(12); + expect(result[0].datapoints[1][1]).to.be(1402596001); + + expect(result[1].target).to.be('prod.server2.cpu.mean'); + expect(result[1].datapoints[0][0]).to.be(15); + expect(result[1].datapoints[0][1]).to.be(1402596000); + expect(result[1].datapoints[1][0]).to.be(16); + expect(result[1].datapoints[1][1]).to.be(1402596001); + }); + + }); + + describe('given an alias format', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server1.cpu', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + } + ], + alias: '$s.testing' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('prod.server1.cpu.testing'); + }); + + }); + + describe('given an alias format with segment numbers', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server1.cpu', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + } + ], + alias: '$1.mean' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('server1.mean'); + }); + + }); + + describe('given an alias format and many segments', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'a0.a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + } + ], + alias: '$5.$11.mean' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('a5.a11.mean'); + }); + + }); + + + describe('given an alias format with group by field', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'host'], + name: 'prod.cpu', + points: [[1402596000, 10, 'A']] + } + ], + groupByField: 'host', + alias: '$g.$1' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('A.cpu'); + }); + + }); + + describe('given group by column', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'host'], + name: 'prod.cpu', + points: [ + [1402596000, 10, 'A'], + [1402596001, 11, 'A'], + [1402596000, 5, 'B'], + [1402596001, 6, 'B'], + ] + } + ], + groupByField: 'host' + }); + + var result = series.getTimeSeries(); + + it('should generate two time series', function() { + expect(result.length).to.be(2); + expect(result[0].target).to.be('prod.cpu.A'); + expect(result[0].datapoints[0][0]).to.be(10); + expect(result[0].datapoints[0][1]).to.be(1402596000); + expect(result[0].datapoints[1][0]).to.be(11); + expect(result[0].datapoints[1][1]).to.be(1402596001); + + expect(result[1].target).to.be('prod.cpu.B'); + expect(result[1].datapoints[0][0]).to.be(5); + expect(result[1].datapoints[0][1]).to.be(1402596000); + expect(result[1].datapoints[1][0]).to.be(6); + expect(result[1].datapoints[1][1]).to.be(1402596001); + }); + + }); + +}); + +describe("when creating annotations from influxdb response", function() { + describe('given column mapping for all columns', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'text', 'sequence_number', 'title', 'tags'], + name: 'events1', + points: [[1402596000000, 'some text', 1, 'Hello', 'B'], [1402596001000, 'asd', 2, 'Hello2', 'B']] + } + ], + annotation: { + query: 'select', + titleColumn: 'title', + tagsColumn: 'tags', + textColumn: 'text', + } + }); + + var result = series.getAnnotations(); + + it(' should generate 2 annnotations ', function() { + expect(result.length).to.be(2); + expect(result[0].annotation.query).to.be('select'); + expect(result[0].title).to.be('Hello'); + expect(result[0].time).to.be(1402596000000); + expect(result[0].tags).to.be('B'); + expect(result[0].text).to.be('some text'); + }); + + }); + + describe('given no column mapping', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'text', 'sequence_number'], + name: 'events1', + points: [[1402596000000, 'some text', 1]] + } + ], + annotation: { query: 'select' } + }); + + var result = series.getAnnotations(); + + it('should generate 1 annnotation', function() { + expect(result.length).to.be(1); + expect(result[0].title).to.be('some text'); + expect(result[0].time).to.be(1402596000000); + expect(result[0].tags).to.be(undefined); + expect(result[0].text).to.be(undefined); + }); + + }); + +}); + diff --git a/public/app/plugins/datasource/influxdb_08/specs/query_builder_specs.ts b/public/app/plugins/datasource/influxdb_08/specs/query_builder_specs.ts new file mode 100644 index 00000000000..5876efb962e --- /dev/null +++ b/public/app/plugins/datasource/influxdb_08/specs/query_builder_specs.ts @@ -0,0 +1,78 @@ +/// + +import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; + +declare var InfluxQueryBuilder: any; + +describe('InfluxQueryBuilder', function() { + + describe('series with conditon and group by', function() { + var builder = new InfluxQueryBuilder({ + series: 'google.test', + column: 'value', + function: 'mean', + condition: "code=1", + groupby_field: 'code' + }); + + var query = builder.build(); + + it('should generate correct query', function() { + expect(query).to.be('select code, mean(value) from "google.test" where $timeFilter and code=1 ' + + 'group by time($interval), code order asc'); + }); + + it('should expose groupByFiled', function() { + expect(builder.groupByField).to.be('code'); + }); + + }); + + describe('series with fill and minimum group by time', function() { + var builder = new InfluxQueryBuilder({ + series: 'google.test', + column: 'value', + function: 'mean', + fill: '0', + }); + + var query = builder.build(); + + it('should generate correct query', function() { + expect(query).to.be('select mean(value) from "google.test" where $timeFilter ' + + 'group by time($interval) fill(0) order asc'); + }); + + }); + + describe('merge function detection', function() { + it('should not quote wrap regex merged series', function() { + var builder = new InfluxQueryBuilder({ + series: 'merge(/^google.test/)', + column: 'value', + function: 'mean' + }); + + var query = builder.build(); + + expect(query).to.be('select mean(value) from merge(/^google.test/) where $timeFilter ' + + 'group by time($interval) order asc'); + }); + + it('should quote wrap series names that start with "merge"', function() { + var builder = new InfluxQueryBuilder({ + series: 'merge.google.test', + column: 'value', + function: 'mean' + }); + + var query = builder.build(); + + expect(query).to.be('select mean(value) from "merge.google.test" where $timeFilter ' + + 'group by time($interval) order asc'); + }); + + }); + +}); + diff --git a/public/test/specs/influxQueryBuilder-specs.js b/public/test/specs/influxQueryBuilder-specs.js deleted file mode 100644 index 5dcb7a9facd..00000000000 --- a/public/test/specs/influxQueryBuilder-specs.js +++ /dev/null @@ -1,78 +0,0 @@ -define([ - 'app/plugins/datasource/influxdb_08/queryBuilder' -], function(InfluxQueryBuilder) { - 'use strict'; - - describe('InfluxQueryBuilder', function() { - - describe('series with conditon and group by', function() { - var builder = new InfluxQueryBuilder({ - series: 'google.test', - column: 'value', - function: 'mean', - condition: "code=1", - groupby_field: 'code' - }); - - var query = builder.build(); - - it('should generate correct query', function() { - expect(query).to.be('select code, mean(value) from "google.test" where $timeFilter and code=1 ' + - 'group by time($interval), code order asc'); - }); - - it('should expose groupByFiled', function() { - expect(builder.groupByField).to.be('code'); - }); - - }); - - describe('series with fill and minimum group by time', function() { - var builder = new InfluxQueryBuilder({ - series: 'google.test', - column: 'value', - function: 'mean', - fill: '0', - }); - - var query = builder.build(); - - it('should generate correct query', function() { - expect(query).to.be('select mean(value) from "google.test" where $timeFilter ' + - 'group by time($interval) fill(0) order asc'); - }); - - }); - - describe('merge function detection', function() { - it('should not quote wrap regex merged series', function() { - var builder = new InfluxQueryBuilder({ - series: 'merge(/^google.test/)', - column: 'value', - function: 'mean' - }); - - var query = builder.build(); - - expect(query).to.be('select mean(value) from merge(/^google.test/) where $timeFilter ' + - 'group by time($interval) order asc'); - }); - - it('should quote wrap series names that start with "merge"', function() { - var builder = new InfluxQueryBuilder({ - series: 'merge.google.test', - column: 'value', - function: 'mean' - }); - - var query = builder.build(); - - expect(query).to.be('select mean(value) from "merge.google.test" where $timeFilter ' + - 'group by time($interval) order asc'); - }); - - }); - - }); - -}); diff --git a/public/test/specs/influxSeries08-specs.js b/public/test/specs/influxSeries08-specs.js deleted file mode 100644 index 7b99a3035a9..00000000000 --- a/public/test/specs/influxSeries08-specs.js +++ /dev/null @@ -1,220 +0,0 @@ -define([ - 'app/plugins/datasource/influxdb_08/influxSeries' -], function(InfluxSeries) { - 'use strict'; - - describe('when generating timeseries from influxdb response', function() { - - describe('given two series', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server1.cpu', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - }, - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server2.cpu', - points: [[1402596000, 15, 1], [1402596001, 16, 2]] - } - ] - }); - - var result = series.getTimeSeries(); - - it('should generate two time series', function() { - expect(result.length).to.be(2); - expect(result[0].target).to.be('prod.server1.cpu.mean'); - expect(result[0].datapoints[0][0]).to.be(10); - expect(result[0].datapoints[0][1]).to.be(1402596000); - expect(result[0].datapoints[1][0]).to.be(12); - expect(result[0].datapoints[1][1]).to.be(1402596001); - - expect(result[1].target).to.be('prod.server2.cpu.mean'); - expect(result[1].datapoints[0][0]).to.be(15); - expect(result[1].datapoints[0][1]).to.be(1402596000); - expect(result[1].datapoints[1][0]).to.be(16); - expect(result[1].datapoints[1][1]).to.be(1402596001); - }); - - }); - - describe('given an alias format', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server1.cpu', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - } - ], - alias: '$s.testing' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('prod.server1.cpu.testing'); - }); - - }); - - describe('given an alias format with segment numbers', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server1.cpu', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - } - ], - alias: '$1.mean' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('server1.mean'); - }); - - }); - - describe('given an alias format and many segments', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'a0.a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - } - ], - alias: '$5.$11.mean' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('a5.a11.mean'); - }); - - }); - - - describe('given an alias format with group by field', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'host'], - name: 'prod.cpu', - points: [[1402596000, 10, 'A']] - } - ], - groupByField: 'host', - alias: '$g.$1' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('A.cpu'); - }); - - }); - - describe('given group by column', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'host'], - name: 'prod.cpu', - points: [ - [1402596000, 10, 'A'], - [1402596001, 11, 'A'], - [1402596000, 5, 'B'], - [1402596001, 6, 'B'], - ] - } - ], - groupByField: 'host' - }); - - var result = series.getTimeSeries(); - - it('should generate two time series', function() { - expect(result.length).to.be(2); - expect(result[0].target).to.be('prod.cpu.A'); - expect(result[0].datapoints[0][0]).to.be(10); - expect(result[0].datapoints[0][1]).to.be(1402596000); - expect(result[0].datapoints[1][0]).to.be(11); - expect(result[0].datapoints[1][1]).to.be(1402596001); - - expect(result[1].target).to.be('prod.cpu.B'); - expect(result[1].datapoints[0][0]).to.be(5); - expect(result[1].datapoints[0][1]).to.be(1402596000); - expect(result[1].datapoints[1][0]).to.be(6); - expect(result[1].datapoints[1][1]).to.be(1402596001); - }); - - }); - - }); - - describe("when creating annotations from influxdb response", function() { - describe('given column mapping for all columns', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'text', 'sequence_number', 'title', 'tags'], - name: 'events1', - points: [[1402596000000, 'some text', 1, 'Hello', 'B'], [1402596001000, 'asd', 2, 'Hello2', 'B']] - } - ], - annotation: { - query: 'select', - titleColumn: 'title', - tagsColumn: 'tags', - textColumn: 'text', - } - }); - - var result = series.getAnnotations(); - - it(' should generate 2 annnotations ', function() { - expect(result.length).to.be(2); - expect(result[0].annotation.query).to.be('select'); - expect(result[0].title).to.be('Hello'); - expect(result[0].time).to.be(1402596000000); - expect(result[0].tags).to.be('B'); - expect(result[0].text).to.be('some text'); - }); - - }); - - describe('given no column mapping', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'text', 'sequence_number'], - name: 'events1', - points: [[1402596000000, 'some text', 1]] - } - ], - annotation: { query: 'select' } - }); - - var result = series.getAnnotations(); - - it('should generate 1 annnotation', function() { - expect(result.length).to.be(1); - expect(result[0].title).to.be('some text'); - expect(result[0].time).to.be(1402596000000); - expect(result[0].tags).to.be(undefined); - expect(result[0].text).to.be(undefined); - }); - - }); - - }); - -}); diff --git a/public/test/specs/influxdb-datasource-specs.js b/public/test/specs/influxdb-datasource-specs.js deleted file mode 100644 index 175215663e0..00000000000 --- a/public/test/specs/influxdb-datasource-specs.js +++ /dev/null @@ -1,101 +0,0 @@ -define([ - './helpers', - 'app/plugins/datasource/influxdb_08/datasource', - 'app/services/backendSrv', - 'app/services/alertSrv' -], function(helpers) { - 'use strict'; - - describe('InfluxDatasource', function() { - var ctx = new helpers.ServiceTestContext(); - - beforeEach(module('grafana.services')); - beforeEach(ctx.providePhase(['templateSrv'])); - beforeEach(ctx.createService('InfluxDatasource_08')); - beforeEach(function() { - ctx.ds = new ctx.service({ url: '', user: 'test', password: 'mupp' }); - }); - - describe('When querying influxdb with one target using query editor target spec', function() { - var results; - var urlExpected = "/series?p=mupp&q=select+mean(value)+from+%22test%22"+ - "+where+time+%3E+now()-1h+group+by+time(1s)+order+asc"; - var query = { - rangeRaw: { from: 'now-1h', to: 'now' }, - targets: [{ series: 'test', column: 'value', function: 'mean' }], - interval: '1s' - }; - - var response = [{ - columns: ["time", "sequence_nr", "value"], - name: 'test', - points: [[10, 1, 1]], - }]; - - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query).then(function(data) { results = data; }); - ctx.$httpBackend.flush(); - }); - - it('should generate the correct query', function() { - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - - it('should return series list', function() { - expect(results.data.length).to.be(1); - expect(results.data[0].target).to.be('test.value'); - }); - - }); - - describe('When querying influxdb with one raw query', function() { - var results; - var urlExpected = "/series?p=mupp&q=select+value+from+series"+ - "+where+time+%3E+now()-1h"; - var query = { - rangeRaw: { from: 'now-1h', to: 'now' }, - targets: [{ query: "select value from series where $timeFilter", rawQuery: true }] - }; - - var response = []; - - beforeEach(function() { - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.query(query).then(function(data) { results = data; }); - ctx.$httpBackend.flush(); - }); - - it('should generate the correct query', function() { - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - - }); - - describe('When issuing annotation query', function() { - var results; - var urlExpected = "/series?p=mupp&q=select+title+from+events.backend_01"+ - "+where+time+%3E+now()-1h"; - - var range = { from: 'now-1h', to: 'now' }; - var annotation = { query: 'select title from events.$server where $timeFilter' }; - var response = []; - - beforeEach(function() { - ctx.templateSrv.replace = function(str) { - return str.replace('$server', 'backend_01'); - }; - ctx.$httpBackend.expect('GET', urlExpected).respond(response); - ctx.ds.annotationQuery(annotation, range).then(function(data) { results = data; }); - ctx.$httpBackend.flush(); - }); - - it('should generate the correct query', function() { - ctx.$httpBackend.verifyNoOutstandingExpectation(); - }); - - }); - - }); -}); - From 5b01e9ec971b2744c4e1e152076ae4f096e0302c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 16:58:31 -0400 Subject: [PATCH 41/51] fix(elasticsearch): minor fix to elasticsearch unit tests so that they work in any timezone, fixes #3010 --- .../plugins/datasource/elasticsearch/specs/datasource_specs.ts | 2 +- .../datasource/elasticsearch/specs/index_pattern_specs.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts index a5e55abe4dd..584f915a86d 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts @@ -36,7 +36,7 @@ describe('ElasticDatasource', function() { ctx.ds.testDatasource(); ctx.$rootScope.$apply(); - var today = moment().format("YYYY.MM.DD"); + var today = moment.utc().format("YYYY.MM.DD"); expect(requestOptions.url).to.be("http://es.com/asd-" + today + '/_stats'); }); }); diff --git a/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts index 8f662bb075f..1a19b550f4e 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/index_pattern_specs.ts @@ -11,7 +11,7 @@ describe('IndexPattern', function() { describe('when getting index for today', function() { it('should return correct index name', function() { var pattern = new IndexPattern('[asd-]YYYY.MM.DD', 'Daily'); - var expected = 'asd-' + moment().format('YYYY.MM.DD'); + var expected = 'asd-' + moment.utc().format('YYYY.MM.DD'); expect(pattern.getIndexForToday()).to.be(expected); }); From 2d23251da95f15f1a40436b590e795600d515ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 22 Oct 2015 18:24:43 -0400 Subject: [PATCH 42/51] spelling: fixed selling in influxdb annotation partial, fixes #3012 --- .../datasource/influxdb/partials/annotations.editor.html | 2 +- .../datasource/influxdb_08/partials/annotations.editor.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/partials/annotations.editor.html b/public/app/plugins/datasource/influxdb/partials/annotations.editor.html index fe867d68f36..cec47e7a7e4 100644 --- a/public/app/plugins/datasource/influxdb/partials/annotations.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/annotations.editor.html @@ -9,7 +9,7 @@
    -
    Column mappings If your influxdb query returns more than one column you need to specify the column names bellow. An annotation event is composed of a title, tags, and an additional text field.
    +
    Column mappings If your influxdb query returns more than one column you need to specify the column names below. An annotation event is composed of a title, tags, and an additional text field.
    diff --git a/public/app/plugins/datasource/influxdb_08/partials/annotations.editor.html b/public/app/plugins/datasource/influxdb_08/partials/annotations.editor.html index fe867d68f36..cec47e7a7e4 100644 --- a/public/app/plugins/datasource/influxdb_08/partials/annotations.editor.html +++ b/public/app/plugins/datasource/influxdb_08/partials/annotations.editor.html @@ -9,7 +9,7 @@
    -
    Column mappings If your influxdb query returns more than one column you need to specify the column names bellow. An annotation event is composed of a title, tags, and an additional text field.
    +
    Column mappings If your influxdb query returns more than one column you need to specify the column names below. An annotation event is composed of a title, tags, and an additional text field.
    From 184307816f7071a83fea36c7197d848869965a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20Fr=C3=B6hlich?= Date: Fri, 23 Oct 2015 11:32:51 +0200 Subject: [PATCH 43/51] "No limit" was not effective for ES terms aggregation This may belong to #2827 --- public/app/plugins/datasource/elasticsearch/query_builder.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.js b/public/app/plugins/datasource/elasticsearch/query_builder.js index ac61fe13a1e..43d8f96bc03 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.js +++ b/public/app/plugins/datasource/elasticsearch/query_builder.js @@ -22,8 +22,7 @@ function (angular) { return queryNode; } - size = parseInt(aggDef.settings.size, 10); - if (size > 0) { queryNode.terms.size = size; } + queryNode.terms.size = parseInt(aggDef.settings.size, 10); if (aggDef.settings.orderBy !== void 0) { queryNode.terms.order = {}; queryNode.terms.order[aggDef.settings.orderBy] = aggDef.settings.order; From 6b9b08da3056555097a9ae32cd91328a4b32c57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20Fr=C3=B6hlich?= Date: Fri, 23 Oct 2015 12:00:20 +0200 Subject: [PATCH 44/51] Remove declaration of unused variable size --- public/app/plugins/datasource/elasticsearch/query_builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.js b/public/app/plugins/datasource/elasticsearch/query_builder.js index 43d8f96bc03..d0fbb6a603a 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.js +++ b/public/app/plugins/datasource/elasticsearch/query_builder.js @@ -15,7 +15,7 @@ function (angular) { }; ElasticQueryBuilder.prototype.buildTermsAgg = function(aggDef, queryNode, target) { - var metricRef, metric, size, y; + var metricRef, metric, y; queryNode.terms = { "field": aggDef.field }; if (!aggDef.settings) { From 4ec6691ea9ed6e073217e04237bcb917a6835cde Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 23 Oct 2015 15:12:52 +0200 Subject: [PATCH 45/51] Fix LimitNOFILE in Debian systemd unit --- packaging/deb/systemd/grafana-server.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/deb/systemd/grafana-server.service b/packaging/deb/systemd/grafana-server.service index 16b975f23ea..dd5d2097149 100644 --- a/packaging/deb/systemd/grafana-server.service +++ b/packaging/deb/systemd/grafana-server.service @@ -14,7 +14,7 @@ ExecStart=/usr/sbin/grafana-server \ --config=${CONF_FILE} \ --pidfile=${PID_FILE} \ cfg:default.paths.logs=${LOG_DIR} \ - cfg:default.paths.data=${DATA_DIR} \ + cfg:default.paths.data=${DATA_DIR} LimitNOFILE=10000 TimeoutStopSec=20 UMask=0027 From e7834b885a4d7f2b686d42de45ce84ca730663ca Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Fri, 23 Oct 2015 15:13:41 +0200 Subject: [PATCH 46/51] Fix LimitNOFILE in RPM systemd unit --- packaging/rpm/systemd/grafana-server.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpm/systemd/grafana-server.service b/packaging/rpm/systemd/grafana-server.service index 855dce53d08..fb2ec24d123 100644 --- a/packaging/rpm/systemd/grafana-server.service +++ b/packaging/rpm/systemd/grafana-server.service @@ -14,7 +14,7 @@ ExecStart=/usr/sbin/grafana-server \ --config=${CONF_FILE} \ --pidfile=${PID_FILE} \ cfg:default.paths.logs=${LOG_DIR} \ - cfg:default.paths.data=${DATA_DIR} \ + cfg:default.paths.data=${DATA_DIR} LimitNOFILE=10000 TimeoutStopSec=20 From 7205cf8ce113f072e9f4b2776cd2877d467e0763 Mon Sep 17 00:00:00 2001 From: ubhatnagar Date: Fri, 23 Oct 2015 07:29:15 -0700 Subject: [PATCH 47/51] Fixed 3014 --- docs/sources/reference/singlestat.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/reference/singlestat.md b/docs/sources/reference/singlestat.md index a6a6a06c806..6f7c9fbd965 100644 --- a/docs/sources/reference/singlestat.md +++ b/docs/sources/reference/singlestat.md @@ -17,8 +17,8 @@ The singlestat panel has a normal query editor to allow you define your exact me 1. `Big Value`: Big Value refers to how we display the main stat for the Singlestat Panel. This is always a single value that is displayed in the Panel in between two strings, `Prefix` and `Suffix`. The single number is calculated by choosing a function (min,max,average,current,total) of your metric query. This functions reduces your query into a single numeric value. -2. `Font Size`: You can use this section -3. `Values`: The Value fields let you set the function (min, max, average, current, total) that your entire query is reduced into a single value with. You can also set the font size of theand font-size (as a %) of the metric query that the Panel is configured with. This reduces the entire query into a single summary value that is displayed. +2. `Font Size`: You can use this section to select the font size of the different texts in the Singlestat Panel, i.e. prefix, value and postfix. +3. `Values`: The Value fields let you set the function (min, max, average, current, total) that your entire query is reduced into a single value with. You can also set the font size of the Value field and font-size (as a %) of the metric query that the Panel is configured with. This reduces the entire query into a single summary value that is displayed. 4. `Postfixes`: The Postfix fields let you define a custom label and font-size (as a %) to appear *after* the value 5. `Units`: Units are appended to the the Singlestat within the panel, and will respect the color and threshold settings for the value. 6. `Decimals`: The Decimal field allows you to override the automatic decimal precision, and set it explicitly. From 6c76e9728e5f1dc58c949345cbbf81eacb5ba497 Mon Sep 17 00:00:00 2001 From: ubhatnagar Date: Fri, 23 Oct 2015 22:53:30 -0700 Subject: [PATCH 48/51] Added OpenSuse installation command --- docs/sources/installation/rpm.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index c112c4c9fea..e8e61ea6d06 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -23,6 +23,10 @@ Or install manually using `rpm`. $ sudo yum install initscripts fontconfig $ sudo rpm -Uvh grafana-2.1.3-1.x86_64.rpm +On OpenSuse you need to run the following command to install the `rpm`. + + $ sudo rpm -i --nodeps grafana-2.1.3-1.x86_64.rpm + ## Install via YUM Repository Add the following to a new file at `/etc/yum.repos.d/grafana.repo` From 45cdbe0a188b8ff0db1cd1cba328192cd97080d3 Mon Sep 17 00:00:00 2001 From: ubhatnagar Date: Fri, 23 Oct 2015 23:03:58 -0700 Subject: [PATCH 49/51] Rearranged installation docs for OpenSuse --- docs/sources/installation/rpm.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index e8e61ea6d06..9d6782f9c70 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -1,6 +1,6 @@ --- page_title: Installing on RPM-based Linux -page_description: Grafana Installation guide for Centos, Fedora, Redhat. +page_description: Grafana Installation guide for Centos, Fedora, OpenSuse, Redhat. page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide --- @@ -10,7 +10,7 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide Description | Download ------------ | ------------- -.RPM for Fedora / RHEL / CentOS Linux | [grafana-2.1.3-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.1.3-1.x86_64.rpm) +.RPM for Fedora / RHEL / CentOS / OpenSuse Linux | [grafana-2.1.3-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.1.3-1.x86_64.rpm) ## Install from package file @@ -20,10 +20,12 @@ You can install Grafana using Yum directly. Or install manually using `rpm`. +On Fedora / RHEL / CentOS run the following commands to install the `rpm`: + $ sudo yum install initscripts fontconfig $ sudo rpm -Uvh grafana-2.1.3-1.x86_64.rpm -On OpenSuse you need to run the following command to install the `rpm`. +On OpenSuse run the following command to install the `rpm`. $ sudo rpm -i --nodeps grafana-2.1.3-1.x86_64.rpm From 54be4c5e2ca1c78c3ae22453d727f1a35d46a2b6 Mon Sep 17 00:00:00 2001 From: Utkarsh Bhatnagar Date: Fri, 23 Oct 2015 23:21:00 -0700 Subject: [PATCH 50/51] Made installation doc consistent --- docs/sources/installation/rpm.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index 9d6782f9c70..67057384af0 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -10,7 +10,7 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide Description | Download ------------ | ------------- -.RPM for Fedora / RHEL / CentOS / OpenSuse Linux | [grafana-2.1.3-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.1.3-1.x86_64.rpm) +.RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-2.1.3-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.1.3-1.x86_64.rpm) ## Install from package file @@ -20,12 +20,12 @@ You can install Grafana using Yum directly. Or install manually using `rpm`. -On Fedora / RHEL / CentOS run the following commands to install the `rpm`: +#### On CentOS / Fedora / Redhat: $ sudo yum install initscripts fontconfig $ sudo rpm -Uvh grafana-2.1.3-1.x86_64.rpm -On OpenSuse run the following command to install the `rpm`. +#### On OpenSuse: $ sudo rpm -i --nodeps grafana-2.1.3-1.x86_64.rpm From 21f3f859b9a4cddae56bd3bee562bb2164831315 Mon Sep 17 00:00:00 2001 From: mlbarrow Date: Sat, 24 Oct 2015 20:58:19 -0700 Subject: [PATCH 51/51] Update influxdb.md Typo fix --- docs/sources/datasources/influxdb.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/datasources/influxdb.md b/docs/sources/datasources/influxdb.md index 35a6c914e65..8595548a1cb 100644 --- a/docs/sources/datasources/influxdb.md +++ b/docs/sources/datasources/influxdb.md @@ -28,7 +28,7 @@ Name | Description Name | The data source name, important that this is the same as in Grafana v1.x if you plan to import old dashboards. Default | Default data source means that it will be pre-selected for new panels. Url | The http protocol, ip and port of you influxdb api (influxdb api port is by default 8086) -Access | Proxy = access via Grafana backend, Direct = access directory from browser. +Access | Proxy = access via Grafana backend, Direct = access directly from browser. Database | Name of your influxdb database User | Name of your database user Password | Database user's password