From 2dd49e6e5022663545dbd5e591b3f7816e267d86 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 25 Oct 2017 15:29:13 +0200 Subject: [PATCH 01/56] converted linkSrv.js to linkSrv.ts --- public/app/features/panellinks/linkSrv.js | 118 ---------------------- public/app/features/panellinks/linkSrv.ts | 114 +++++++++++++++++++++ 2 files changed, 114 insertions(+), 118 deletions(-) delete mode 100644 public/app/features/panellinks/linkSrv.js create mode 100644 public/app/features/panellinks/linkSrv.ts diff --git a/public/app/features/panellinks/linkSrv.js b/public/app/features/panellinks/linkSrv.js deleted file mode 100644 index 89d89487c51..00000000000 --- a/public/app/features/panellinks/linkSrv.js +++ /dev/null @@ -1,118 +0,0 @@ -define([ - 'angular', - 'lodash', - 'app/core/utils/kbn', -], -function (angular, _, kbn) { - 'use strict'; - - kbn = kbn.default; - - angular - .module('grafana.services') - .service('linkSrv', function(templateSrv, timeSrv) { - - this.getLinkUrl = function(link) { - var url = templateSrv.replace(link.url || ''); - var params = {}; - - if (link.keepTime) { - var range = timeSrv.timeRangeForUrl(); - params['from'] = range.from; - params['to'] = range.to; - } - - if (link.includeVars) { - templateSrv.fillVariableValuesForUrl(params); - } - - return this.addParamsToUrl(url, params); - }; - - this.addParamsToUrl = function(url, params) { - var paramsArray = []; - _.each(params, function(value, key) { - if (value === null) { return; } - if (value === true) { - paramsArray.push(key); - } - else if (_.isArray(value)) { - _.each(value, function(instance) { - paramsArray.push(key + '=' + encodeURIComponent(instance)); - }); - } - else { - paramsArray.push(key + '=' + encodeURIComponent(value)); - } - }); - - if (paramsArray.length === 0) { - return url; - } - - 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) { - var info = {}; - info.href = this.getLinkUrl(link); - info.title = templateSrv.replace(link.title || ''); - return info; - }; - - this.getPanelLinkAnchorInfo = function(link, scopedVars) { - var info = {}; - if (link.type === 'absolute') { - info.target = link.targetBlank ? '_blank' : '_self'; - info.href = templateSrv.replace(link.url || '', scopedVars); - info.title = templateSrv.replace(link.title || '', scopedVars); - } - else if (link.dashUri) { - info.href = 'dashboard/' + link.dashUri + '?'; - info.title = templateSrv.replace(link.title || '', scopedVars); - info.target = link.targetBlank ? '_blank' : ''; - } - else { - info.title = templateSrv.replace(link.title || '', scopedVars); - var slug = kbn.slugifyForUrl(link.dashboard || ''); - info.href = 'dashboard/db/' + slug + '?'; - } - - var params = {}; - - if (link.keepTime) { - var range = timeSrv.timeRangeForUrl(); - params['from'] = range.from; - params['to'] = range.to; - } - - if (link.includeVars) { - templateSrv.fillVariableValuesForUrl(params, scopedVars); - } - - info.href = this.addParamsToUrl(info.href, params); - - if (link.params) { - info.href = this.appendToQueryString(info.href, templateSrv.replace(link.params, scopedVars)); - } - - return info; - }; - - }); -}); diff --git a/public/app/features/panellinks/linkSrv.ts b/public/app/features/panellinks/linkSrv.ts new file mode 100644 index 00000000000..5847d0b7b46 --- /dev/null +++ b/public/app/features/panellinks/linkSrv.ts @@ -0,0 +1,114 @@ +import angular from 'angular'; +import _ from 'lodash'; +import kbn from 'app/core/utils/kbn'; + + +export class LinkSrv { + + /** @ngInject */ + constructor(private templateSrv, private timeSrv) { + } + + getLinkUrl(link) { + var url = this.templateSrv.replace(link.url || ''); + var params = {}; + + if (link.keepTime) { + var range = this.timeSrv.timeRangeForUrl(); + params['from'] = range.from; + params['to'] = range.to; + } + + if (link.includeVars) { + this.templateSrv.fillVariableValuesForUrl(params); + } + + return this.addParamsToUrl(url, params); + } + + addParamsToUrl(url, params) { + var paramsArray = []; + + _.each(params, function(value, key) { + if (value === null) { return; } + if (value === true) { + paramsArray.push(key); + } else if (_.isArray(value)) { + _.each(value, function(instance) { + paramsArray.push(key + '=' + encodeURIComponent(instance)); + }); + } else { + paramsArray.push(key + '=' + encodeURIComponent(value)); + } + }); + + if (paramsArray.length === 0) { + return url; + } + + return this.appendToQueryString(url, paramsArray.join('&')); + } + + appendToQueryString(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; + } + + getAnchorInfo(link) { + var info = {}; + (info).href = this.getLinkUrl(link); + (info).title = this.templateSrv.replace(link.title || ''); + return info; + } + + getPanelLinkAnchorInfo(link, scopedVars) { + var info = {}; + if (link.type === 'absolute') { + (info).target = link.targetBlank ? '_blank' : '_self'; + (info).href = this.templateSrv.replace(link.url || '', scopedVars); + (info).title = this.templateSrv.replace(link.title || '', scopedVars); + } else if (link.dashUri) { + (info).href = 'dashboard/' + link.dashUri + '?'; + (info).title = this.templateSrv.replace(link.title || '', scopedVars); + (info).target = link.targetBlank ? '_blank' : ''; + } else { + (info).title = this.templateSrv.replace(link.title || '', scopedVars); + var slug = kbn.slugifyForUrl(link.dashboard || ''); + (info).href = 'dashboard/db/' + slug + '?'; + } + + var params = {}; + + if (link.keepTime) { + var range = this.timeSrv.timeRangeForUrl(); + params['from'] = range.from; + params['to'] = range.to; + } + + if (link.includeVars) { + this.templateSrv.fillVariableValuesForUrl(params, scopedVars); + } + + (info).href = this.addParamsToUrl((info).href, params); + + if (link.params) { + (info).href = this.appendToQueryString((info).href, this.templateSrv.replace(link.params, scopedVars)); + } + + return info; + } + +} + +angular.module('grafana.services').service('linkSrv', LinkSrv); From 2f4744ca7127ba923cc8e5565f6b78cea2a0daa7 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 26 Oct 2017 13:25:47 +0200 Subject: [PATCH 02/56] declared any to info in declaration --- public/app/features/panellinks/linkSrv.ts | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/public/app/features/panellinks/linkSrv.ts b/public/app/features/panellinks/linkSrv.ts index 5847d0b7b46..b167fb813ac 100644 --- a/public/app/features/panellinks/linkSrv.ts +++ b/public/app/features/panellinks/linkSrv.ts @@ -66,26 +66,26 @@ export class LinkSrv { } getAnchorInfo(link) { - var info = {}; - (info).href = this.getLinkUrl(link); - (info).title = this.templateSrv.replace(link.title || ''); + var info: any = {}; + info.href = this.getLinkUrl(link); + info.title = this.templateSrv.replace(link.title || ''); return info; } getPanelLinkAnchorInfo(link, scopedVars) { - var info = {}; + var info: any = {}; if (link.type === 'absolute') { - (info).target = link.targetBlank ? '_blank' : '_self'; - (info).href = this.templateSrv.replace(link.url || '', scopedVars); - (info).title = this.templateSrv.replace(link.title || '', scopedVars); + info.target = link.targetBlank ? '_blank' : '_self'; + info.href = this.templateSrv.replace(link.url || '', scopedVars); + info.title = this.templateSrv.replace(link.title || '', scopedVars); } else if (link.dashUri) { - (info).href = 'dashboard/' + link.dashUri + '?'; - (info).title = this.templateSrv.replace(link.title || '', scopedVars); - (info).target = link.targetBlank ? '_blank' : ''; + info.href = 'dashboard/' + link.dashUri + '?'; + info.title = this.templateSrv.replace(link.title || '', scopedVars); + info.target = link.targetBlank ? '_blank' : ''; } else { - (info).title = this.templateSrv.replace(link.title || '', scopedVars); + info.title = this.templateSrv.replace(link.title || '', scopedVars); var slug = kbn.slugifyForUrl(link.dashboard || ''); - (info).href = 'dashboard/db/' + slug + '?'; + info.href = 'dashboard/db/' + slug + '?'; } var params = {}; @@ -100,10 +100,10 @@ export class LinkSrv { this.templateSrv.fillVariableValuesForUrl(params, scopedVars); } - (info).href = this.addParamsToUrl((info).href, params); + info.href = this.addParamsToUrl(info.href, params); if (link.params) { - (info).href = this.appendToQueryString((info).href, this.templateSrv.replace(link.params, scopedVars)); + info.href = this.appendToQueryString(info.href, this.templateSrv.replace(link.params, scopedVars)); } return info; From a228bb2308f32b74a68e27cab13ae122594f5299 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 26 Oct 2017 13:34:41 +0200 Subject: [PATCH 03/56] renamed file --- public/app/features/panellinks/{linkSrv.ts => link_srv.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename public/app/features/panellinks/{linkSrv.ts => link_srv.ts} (100%) diff --git a/public/app/features/panellinks/linkSrv.ts b/public/app/features/panellinks/link_srv.ts similarity index 100% rename from public/app/features/panellinks/linkSrv.ts rename to public/app/features/panellinks/link_srv.ts From e654f80e4b92032bf4e8532f55a19392b7c2226d Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 26 Oct 2017 14:25:43 +0200 Subject: [PATCH 04/56] fixed link issues --- public/app/features/panellinks/link_srv.ts | 1 - public/app/features/panellinks/module.js | 2 +- public/app/plugins/panel/singlestat/module.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/public/app/features/panellinks/link_srv.ts b/public/app/features/panellinks/link_srv.ts index b167fb813ac..873e0233e41 100644 --- a/public/app/features/panellinks/link_srv.ts +++ b/public/app/features/panellinks/link_srv.ts @@ -2,7 +2,6 @@ import angular from 'angular'; import _ from 'lodash'; import kbn from 'app/core/utils/kbn'; - export class LinkSrv { /** @ngInject */ diff --git a/public/app/features/panellinks/module.js b/public/app/features/panellinks/module.js index 351b38f27c4..a36317dc2b3 100644 --- a/public/app/features/panellinks/module.js +++ b/public/app/features/panellinks/module.js @@ -1,7 +1,7 @@ define([ 'angular', 'lodash', - './linkSrv', + './link_srv', ], function (angular, _) { 'use strict'; diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 5879b2d720a..134a703a0fb 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -2,7 +2,7 @@ import _ from 'lodash'; import $ from 'jquery'; import 'vendor/flot/jquery.flot'; import 'vendor/flot/jquery.flot.gauge'; -import 'app/features/panellinks/linkSrv'; +import 'app/features/panellinks/link_srv'; import kbn from 'app/core/utils/kbn'; import config from 'app/core/config'; From f097bce565ad5adb689c048fb31baadfd8535715 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Thu, 26 Oct 2017 14:47:07 +0200 Subject: [PATCH 05/56] more link fixes --- public/app/features/dashboard/specs/share_modal_ctrl_specs.ts | 2 +- public/app/features/panellinks/specs/link_srv_specs.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/specs/share_modal_ctrl_specs.ts b/public/app/features/dashboard/specs/share_modal_ctrl_specs.ts index 7a04f5f7579..c39342a6f40 100644 --- a/public/app/features/dashboard/specs/share_modal_ctrl_specs.ts +++ b/public/app/features/dashboard/specs/share_modal_ctrl_specs.ts @@ -2,7 +2,7 @@ import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/co import helpers from 'test/specs/helpers'; import '../shareModalCtrl'; import config from 'app/core/config'; -import 'app/features/panellinks/linkSrv'; +import 'app/features/panellinks/link_srv'; describe('ShareModalCtrl', function() { var ctx = new helpers.ControllerTestContext(); diff --git a/public/app/features/panellinks/specs/link_srv_specs.ts b/public/app/features/panellinks/specs/link_srv_specs.ts index 77bb0a36c1f..397e97ca758 100644 --- a/public/app/features/panellinks/specs/link_srv_specs.ts +++ b/public/app/features/panellinks/specs/link_srv_specs.ts @@ -1,5 +1,5 @@ import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common'; -import 'app/features/panellinks/linkSrv'; +import 'app/features/panellinks/link_srv'; import _ from 'lodash'; describe('linkSrv', function() { From 6aa0f350122c0e21a32dee2adf733ae20399e969 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 26 Oct 2017 17:39:54 +0200 Subject: [PATCH 06/56] docs: fix link --- docs/sources/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 9226c842abc..7a431e29692 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -46,8 +46,8 @@ those options. - [Graphite]({{< relref "features/datasources/graphite.md" >}}) - [Elasticsearch]({{< relref "features/datasources/elasticsearch.md" >}}) - [InfluxDB]({{< relref "features/datasources/influxdb.md" >}}) -- [Prometheus]({{< relref "features/datasources/influxdb.md" >}}) -- [OpenTSDB]({{< relref "features/datasources/prometheus.md" >}}) +- [Prometheus]({{< relref "features/datasources/prometheus.md" >}}) +- [OpenTSDB]({{< relref "features/datasources/opentsdb.md" >}}) - [MySQL]({{< relref "features/datasources/mysql.md" >}}) - [Postgres]({{< relref "features/datasources/postgres.md" >}}) - [Cloudwatch]({{< relref "features/datasources/cloudwatch.md" >}}) From 34da0711abf93fa54376a21452660d2a9f4545df Mon Sep 17 00:00:00 2001 From: Sven Klemm <31455525+svenklemm@users.noreply.github.com> Date: Fri, 27 Oct 2017 11:26:25 +0200 Subject: [PATCH 07/56] add __timeGroup macro for mysql (#9596) * add __timeGroup macro for mysql * put example __timeGroup query in frontend help * do __timeGroup interval parsing in go similar to mysql * ignore whitespace around interval --- pkg/tsdb/mysql/macros.go | 13 ++++++++++++- pkg/tsdb/mysql/macros_test.go | 8 ++++++++ pkg/tsdb/postgres/macros.go | 9 +++++++-- pkg/tsdb/postgres/macros_test.go | 2 +- .../datasource/mysql/partials/query.editor.html | 10 +++++++++- .../datasource/postgres/partials/query.editor.html | 12 +++++------- 6 files changed, 42 insertions(+), 12 deletions(-) diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index 36c38804a01..108b81fc5f3 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -3,6 +3,8 @@ package mysql import ( "fmt" "regexp" + "strings" + "time" "github.com/grafana/grafana/pkg/tsdb" ) @@ -25,7 +27,7 @@ func (m *MySqlMacroEngine) Interpolate(timeRange *tsdb.TimeRange, sql string) (s var macroError error sql = replaceAllStringSubmatchFunc(rExp, sql, func(groups []string) string { - res, err := m.evaluateMacro(groups[1], groups[2:]) + res, err := m.evaluateMacro(groups[1], strings.Split(groups[2], ",")) if err != nil && macroError == nil { macroError = err return "macro_error()" @@ -73,6 +75,15 @@ func (m *MySqlMacroEngine) evaluateMacro(name string, args []string) (string, er return fmt.Sprintf("FROM_UNIXTIME(%d)", uint64(m.TimeRange.GetFromAsMsEpoch()/1000)), nil case "__timeTo": return fmt.Sprintf("FROM_UNIXTIME(%d)", uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil + case "__timeGroup": + if len(args) != 2 { + return "", fmt.Errorf("macro %v needs time column and interval", name) + } + interval, err := time.ParseDuration(strings.Trim(args[1], `'" `)) + if err != nil { + return "", fmt.Errorf("error parsing interval %v", args[1]) + } + return fmt.Sprintf("cast(cast(UNIX_TIMESTAMP(%s)/(%.0f) as signed)*%.0f as signed)", args[0], interval.Seconds(), interval.Seconds()), nil case "__unixEpochFilter": if len(args) == 0 { return "", fmt.Errorf("missing time column argument for macro %v", name) diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index c92020d0aae..988612fb287 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -40,6 +40,14 @@ func TestMacroEngine(t *testing.T) { So(sql, ShouldEqual, "select FROM_UNIXTIME(18446744066914186738)") }) + Convey("interpolate __timeGroup function", func() { + + sql, err := engine.Interpolate(timeRange, "GROUP BY $__timeGroup(time_column,'5m')") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "GROUP BY cast(cast(UNIX_TIMESTAMP(time_column)/(300) as signed)*300 as signed)") + }) + Convey("interpolate __timeTo function", func() { sql, err := engine.Interpolate(timeRange, "select $__timeTo(time_column)") So(err, ShouldBeNil) diff --git a/pkg/tsdb/postgres/macros.go b/pkg/tsdb/postgres/macros.go index 21400b03dfd..95932ab1c83 100644 --- a/pkg/tsdb/postgres/macros.go +++ b/pkg/tsdb/postgres/macros.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" "strings" + "time" "github.com/grafana/grafana/pkg/tsdb" ) @@ -80,10 +81,14 @@ func (m *PostgresMacroEngine) evaluateMacro(name string, args []string) (string, case "__timeTo": return fmt.Sprintf("to_timestamp(%d)", uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil case "__timeGroup": - if len(args) < 2 { + if len(args) != 2 { return "", fmt.Errorf("macro %v needs time column and interval", name) } - return fmt.Sprintf("(extract(epoch from \"%s\")/extract(epoch from %s::interval))::int*extract(epoch from %s::interval)", args[0], args[1], args[1]), nil + interval, err := time.ParseDuration(strings.Trim(args[1], `' `)) + if err != nil { + return "", fmt.Errorf("error parsing interval %v", args[1]) + } + return fmt.Sprintf("(extract(epoch from \"%s\")/%v)::bigint*%v", args[0], interval.Seconds(), interval.Seconds()), nil case "__unixEpochFilter": if len(args) == 0 { return "", fmt.Errorf("missing time column argument for macro %v", name) diff --git a/pkg/tsdb/postgres/macros_test.go b/pkg/tsdb/postgres/macros_test.go index ba991e6f2d5..ff268805259 100644 --- a/pkg/tsdb/postgres/macros_test.go +++ b/pkg/tsdb/postgres/macros_test.go @@ -45,7 +45,7 @@ func TestMacroEngine(t *testing.T) { sql, err := engine.Interpolate(timeRange, "GROUP BY $__timeGroup(time_column,'5m')") So(err, ShouldBeNil) - So(sql, ShouldEqual, "GROUP BY (extract(epoch from \"time_column\")/extract(epoch from '5m'::interval))::int*extract(epoch from '5m'::interval)") + So(sql, ShouldEqual, "GROUP BY (extract(epoch from \"time_column\")/300)::bigint*300") }) Convey("interpolate __timeTo function", func() { diff --git a/public/app/plugins/datasource/mysql/partials/query.editor.html b/public/app/plugins/datasource/mysql/partials/query.editor.html index a7e993afd7f..22d64c9190f 100644 --- a/public/app/plugins/datasource/mysql/partials/query.editor.html +++ b/public/app/plugins/datasource/mysql/partials/query.editor.html @@ -49,7 +49,15 @@ Macros: - $__time(column) -> UNIX_TIMESTAMP(column) as time_sec - $__timeFilter(column) -> UNIX_TIMESTAMP(time_date_time) ≥ 1492750877 AND UNIX_TIMESTAMP(time_date_time) ≤ 1492750877 - $__unixEpochFilter(column) -> time_unix_epoch > 1492750877 AND time_unix_epoch < 1492750877 -- $__timeGroup(column,'5m') -> (extract(epoch from "dateColumn")/extract(epoch from '5m'::interval))::int +- $__timeGroup(column,'5m') -> cast(cast(UNIX_TIMESTAMP(column)/(300) as signed)*300 as signed) + +Example of group by and order by with $__timeGroup: +SELECT + $__timeGroup(timestamp_col, '1h') AS time, + sum(value_double) as value +FROM yourtable +GROUP BY 1 +ORDER BY 1 Or build your own conditionals using these macros which just return the values: - $__timeFrom() -> FROM_UNIXTIME(1492750877) diff --git a/public/app/plugins/datasource/postgres/partials/query.editor.html b/public/app/plugins/datasource/postgres/partials/query.editor.html index 1939fc47ecb..f1c7b376353 100644 --- a/public/app/plugins/datasource/postgres/partials/query.editor.html +++ b/public/app/plugins/datasource/postgres/partials/query.editor.html @@ -50,17 +50,15 @@ Macros: - $__timeEpoch -> extract(epoch from column) as "time" - $__timeFilter(column) -> column ≥ to_timestamp(1492750877) AND column ≤ to_timestamp(1492750877) - $__unixEpochFilter(column) -> column > 1492750877 AND column < 1492750877 - -To group by time use $__timeGroup: --> (extract(epoch from column)/extract(epoch from column::interval))::int +- $__timeGroup(column,'5m') -> (extract(epoch from "dateColumn")/extract(epoch from '5m'::interval))::int Example of group by and order by with $__timeGroup: SELECT - min(date_time_col) AS time_sec, - sum(value_double) as value + $__timeGroup(date_time_col, '1h') AS time, + sum(value) as value FROM yourtable -group by $__timeGroup(date_time_col, '1h') -order by $__timeGroup(date_time_col, '1h') ASC +GROUP BY time +ORDER BY time Or build your own conditionals using these macros which just return the values: - $__timeFrom() -> to_timestamp(1492750877) From 71d9126bb67cb8471f3801fe8d5591889414129b Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 27 Oct 2017 11:28:04 +0200 Subject: [PATCH 08/56] changelog: note for #9596 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0833f60e37..28c48486a7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ ## New Features * **Data Source Proxy**: Add support for whitelisting specified cookies that will be passed through to the data source when proxying data source requests [#5457](https://github.com/grafana/grafana/issues/5457), thanks [@robingustafsson](https://github.com/robingustafsson) +* **Postgres/MySQL**: add __timeGroup macro for mysql [#9596](https://github.com/grafana/grafana/pull/9596), thanks [@svenklemm](https://github.com/svenklemm) + ## Tech From 728471eef41f7ac9d17b1453c8090bdbc5d60905 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 27 Oct 2017 11:15:47 +0200 Subject: [PATCH 09/56] save as should only delete threshold for panels with alerts closes #9681 --- .../app/features/dashboard/save_as_modal.ts | 5 +- .../dashboard/specs/save_as_modal.jest.ts | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 public/app/features/dashboard/specs/save_as_modal.jest.ts diff --git a/public/app/features/dashboard/save_as_modal.ts b/public/app/features/dashboard/save_as_modal.ts index 7e0b754d559..99bf21ca600 100644 --- a/public/app/features/dashboard/save_as_modal.ts +++ b/public/app/features/dashboard/save_as_modal.ts @@ -49,7 +49,10 @@ export class SaveDashboardAsModalCtrl { if (dashboard.id > 0) { this.clone.rows.forEach(row => { row.panels.forEach(panel => { - delete panel.thresholds; + if (panel.type === "graph" && panel.alert) { + delete panel.thresholds; + } + delete panel.alert; }); }); diff --git a/public/app/features/dashboard/specs/save_as_modal.jest.ts b/public/app/features/dashboard/specs/save_as_modal.jest.ts new file mode 100644 index 00000000000..e511bba25b9 --- /dev/null +++ b/public/app/features/dashboard/specs/save_as_modal.jest.ts @@ -0,0 +1,67 @@ +import {SaveDashboardAsModalCtrl} from '../save_as_modal'; +import {describe, expect} from 'test/lib/common'; + +describe('saving dashboard as', () => { + function scenario(name, panel, verify) { + describe(name, () => { + var json = { + title: "name", + rows: [ { panels: [ + panel + ]}] + }; + + var mockDashboardSrv = { + getCurrent: function() { + return { + id: 5, + getSaveModelClone: function() { + return json; + } + }; + } + }; + + var ctrl = new SaveDashboardAsModalCtrl(mockDashboardSrv); + var ctx: any = { + clone: ctrl.clone, + ctrl: ctrl, + panel: {} + }; + for (let row of ctrl.clone.rows) { + for (let panel of row.panels) { + ctx.panel = panel; + } + } + it("verify", () => { + verify(ctx); + }); + }); + } + + scenario("default values", {}, (ctx) => { + var clone = ctx.clone; + expect(clone.id).toBe(null); + expect(clone.title).toBe("name Copy"); + expect(clone.editable).toBe(true); + expect(clone.hideControls).toBe(false); + }); + + var graphPanel = { id: 1, type: "graph", alert: { rule: 1}, thresholds: { value: 3000} }; + + scenario("should remove alert from graph panel", graphPanel , (ctx) => { + expect(ctx.panel.alert).toBe(undefined); + }); + + scenario("should remove threshold from graph panel", graphPanel, (ctx) => { + expect(ctx.panel.thresholds).toBe(undefined); + }); + + scenario("singlestat should keep threshold", { id: 1, type: "singlestat", thresholds: { value: 3000} }, (ctx) => { + expect(ctx.panel.thresholds).not.toBe(undefined); + }); + + scenario("table should keep threshold", { id: 1, type: "table", thresholds: { value: 3000} }, (ctx) => { + expect(ctx.panel.thresholds).not.toBe(undefined); + }); +}); From 357d394c66adf26ad0a3730782e552f4589b954f Mon Sep 17 00:00:00 2001 From: Tomas Strand Date: Fri, 27 Oct 2017 17:20:07 +0300 Subject: [PATCH 10/56] Alertlist: Inform when no alerts in current time range Shows info that no alerts are found for the currently selected interval in Alertlist. Fixes #9624 --- public/app/plugins/panel/alertlist/module.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/app/plugins/panel/alertlist/module.html b/public/app/plugins/panel/alertlist/module.html index a88c4ebadc7..0a3ff4fabb4 100644 --- a/public/app/plugins/panel/alertlist/module.html +++ b/public/app/plugins/panel/alertlist/module.html @@ -1,6 +1,17 @@
    +
  1. +
    +
    +
    +

    + No alerts in selected interval +

    +
    +
    +
    +
  2. From 43d45f9fae523e7231986be5435c7930e51c6c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 28 Oct 2017 12:59:32 +0200 Subject: [PATCH 11/56] fix: graphite annotation tooltip included undefined, fixes #9707 --- public/app/features/annotations/annotation_tooltip.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/annotations/annotation_tooltip.ts b/public/app/features/annotations/annotation_tooltip.ts index c950d3edd55..4828eb671a6 100644 --- a/public/app/features/annotations/annotation_tooltip.ts +++ b/public/app/features/annotations/annotation_tooltip.ts @@ -39,7 +39,7 @@ export function annotationTooltipDirective($sanitize, dashboardSrv, contextSrv, text = text + '
    ' + event.text; } } else if (title) { - text = title + '
    ' + text; + text = title + '
    ' + (_.isString(text) ? text : ''); title = ''; } From cdd17f487164a0be0a055121b9d694255a4916ad Mon Sep 17 00:00:00 2001 From: pkarmaka Date: Sat, 28 Oct 2017 04:10:18 -0700 Subject: [PATCH 12/56] [Bug Fix] Opentsdb Alias issue (#9613) --- public/app/plugins/datasource/opentsdb/datasource.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index 4d51b117ed4..7315485c6db 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -441,7 +441,7 @@ function (angular, _, dateMath) { } function mapMetricsToTargets(metrics, options, tsdbVersion) { - var interpolatedTagValue; + var interpolatedTagValue, arrTagV; return _.map(metrics, function(metricData) { if (tsdbVersion === 3) { return metricData.query.index; @@ -453,7 +453,8 @@ function (angular, _, dateMath) { return target.metric === metricData.metric && _.every(target.tags, function(tagV, tagK) { interpolatedTagValue = templateSrv.replace(tagV, options.scopedVars, 'pipe'); - return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*"; + arrTagV = interpolatedTagValue.split('|'); + return _.includes(arrTagV, metricData.tags[tagK]) || interpolatedTagValue === "*"; }); } }); From 3e3cef28ece4af95aabf02ebe59b26c8f4b01bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 28 Oct 2017 13:28:06 +0200 Subject: [PATCH 13/56] fix: undefined is not an object evaluating this., #9538 --- public/app/core/services/timer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/core/services/timer.ts b/public/app/core/services/timer.ts index 6356e1f2910..6355105ee0e 100644 --- a/public/app/core/services/timer.ts +++ b/public/app/core/services/timer.ts @@ -21,7 +21,7 @@ export class Timer { } cancelAll() { - _.each(this.timers, function (t) { + _.each(this.timers, t => { this.$timeout.cancel(t); }); this.timers = []; From 7dcfd800b35eb7d2b0f38f8fa6408d5903514cbe Mon Sep 17 00:00:00 2001 From: bergquist Date: Sun, 29 Oct 2017 19:32:49 +0100 Subject: [PATCH 14/56] changelog: adds note about closing #9681 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c48486a7e..8a574abaa05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,6 @@ * **Data Source Proxy**: Add support for whitelisting specified cookies that will be passed through to the data source when proxying data source requests [#5457](https://github.com/grafana/grafana/issues/5457), thanks [@robingustafsson](https://github.com/robingustafsson) * **Postgres/MySQL**: add __timeGroup macro for mysql [#9596](https://github.com/grafana/grafana/pull/9596), thanks [@svenklemm](https://github.com/svenklemm) - - ## Tech * **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) @@ -23,6 +21,10 @@ * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) * **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [#9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) +# 4.6.1 (unreleased) + +* **Singlestat**: Lost thresholds when using save dashboard as [#9681](https://github.com/grafana/grafana/issues/9681) + # 4.6.0 (2017-10-26) ## Fixes From e541e60bc3ea03e06a7ea8531e5ad39bf1c3c538 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Sun, 29 Oct 2017 20:02:44 +0100 Subject: [PATCH 15/56] sql: remove title from annotation help Fixes #9710 --- .../plugins/datasource/mysql/partials/annotations.editor.html | 1 - .../plugins/datasource/postgres/partials/annotations.editor.html | 1 - 2 files changed, 2 deletions(-) diff --git a/public/app/plugins/datasource/mysql/partials/annotations.editor.html b/public/app/plugins/datasource/mysql/partials/annotations.editor.html index 09581e2a552..b34eff5b011 100644 --- a/public/app/plugins/datasource/mysql/partials/annotations.editor.html +++ b/public/app/plugins/datasource/mysql/partials/annotations.editor.html @@ -21,7 +21,6 @@ An annotation is an event that is overlayed on top of graphs. The query can have up to four columns per row, the time_sec column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned. - column with alias: time_sec for the annotation event. Format is UTC in seconds, use UNIX_TIMESTAMP(column) -- column with alias title for the annotation title - column with alias: text for the annotation text - column with alias: tags for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2' diff --git a/public/app/plugins/datasource/postgres/partials/annotations.editor.html b/public/app/plugins/datasource/postgres/partials/annotations.editor.html index 07b838e739a..b56f7523087 100644 --- a/public/app/plugins/datasource/postgres/partials/annotations.editor.html +++ b/public/app/plugins/datasource/postgres/partials/annotations.editor.html @@ -21,7 +21,6 @@ An annotation is an event that is overlayed on top of graphs. The query can have up to four columns per row, the time column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned. - column with alias: time for the annotation event. Format is UTC in seconds, use extract(epoch from column) as "time" -- column with alias title for the annotation title - column with alias: text for the annotation text - column with alias: tags for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2' From e1765e360e026b622d006a74bf319028b5ec9a9c Mon Sep 17 00:00:00 2001 From: bergquist Date: Sun, 29 Oct 2017 20:21:25 +0100 Subject: [PATCH 16/56] tech: add missing include --- public/app/features/dashboard/specs/save_as_modal.jest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashboard/specs/save_as_modal.jest.ts b/public/app/features/dashboard/specs/save_as_modal.jest.ts index e511bba25b9..913209eb01f 100644 --- a/public/app/features/dashboard/specs/save_as_modal.jest.ts +++ b/public/app/features/dashboard/specs/save_as_modal.jest.ts @@ -1,5 +1,5 @@ import {SaveDashboardAsModalCtrl} from '../save_as_modal'; -import {describe, expect} from 'test/lib/common'; +import {describe, it, expect} from 'test/lib/common'; describe('saving dashboard as', () => { function scenario(name, panel, verify) { From e9645045a0bed41524457fc319307a4acc8a1224 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Tue, 24 Oct 2017 02:08:29 +0900 Subject: [PATCH 17/56] ace editor for text panel --- public/app/core/components/code_editor/code_editor.ts | 2 ++ public/app/plugins/panel/text/editor.html | 8 ++++++-- public/app/plugins/panel/text/module.ts | 9 ++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/public/app/core/components/code_editor/code_editor.ts b/public/app/core/components/code_editor/code_editor.ts index 2615a635c7e..cc3b1e46ad4 100644 --- a/public/app/core/components/code_editor/code_editor.ts +++ b/public/app/core/components/code_editor/code_editor.ts @@ -36,6 +36,8 @@ import 'brace/mode/text'; import 'brace/snippets/text'; import 'brace/mode/sql'; import 'brace/snippets/sql'; +import 'brace/mode/markdown'; +import 'brace/snippets/markdown'; const DEFAULT_THEME_DARK = "ace/theme/grafana-dark"; const DEFAULT_THEME_LIGHT = "ace/theme/textmate"; diff --git a/public/app/plugins/panel/text/editor.html b/public/app/plugins/panel/text/editor.html index 8e1283a39ba..eab53dc7615 100644 --- a/public/app/plugins/panel/text/editor.html +++ b/public/app/plugins/panel/text/editor.html @@ -15,5 +15,9 @@ (This area uses Markdown. HTML is not supported) - +
    +
    + + +
    +
    diff --git a/public/app/plugins/panel/text/module.ts b/public/app/plugins/panel/text/module.ts index 5f453aea15b..a3a58e968fc 100644 --- a/public/app/plugins/panel/text/module.ts +++ b/public/app/plugins/panel/text/module.ts @@ -23,6 +23,11 @@ export class TextPanelCtrl extends PanelCtrl { this.events.on('init-edit-mode', this.onInitEditMode.bind(this)); this.events.on('refresh', this.onRefresh.bind(this)); this.events.on('render', this.onRender.bind(this)); + $scope.$watch('ctrl.panel.content', + _.throttle(() => { + this.render(); + }, 1000) + ); } onInitEditMode() { @@ -66,7 +71,9 @@ export class TextPanelCtrl extends PanelCtrl { }); } - this.updateContent(this.remarkable.render(content)); + this.$scope.$applyAsync(() => { + this.updateContent(this.remarkable.render(content)); + }); } updateContent(html) { From 92d8b3f0950a698ccc79e6867aeaedc77dfc854c Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 30 Oct 2017 11:09:48 +0100 Subject: [PATCH 18/56] changelog: adds note about closing #9698 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a574abaa05..ff844d94bfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ ## New Features * **Data Source Proxy**: Add support for whitelisting specified cookies that will be passed through to the data source when proxying data source requests [#5457](https://github.com/grafana/grafana/issues/5457), thanks [@robingustafsson](https://github.com/robingustafsson) * **Postgres/MySQL**: add __timeGroup macro for mysql [#9596](https://github.com/grafana/grafana/pull/9596), thanks [@svenklemm](https://github.com/svenklemm) +* **Text**: Text panel are now edited in the ace editor. [#9698](https://github.com/grafana/grafana/pull/9698), thx [@mtanda](https://github.com/mtanda) + ## Tech * **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) From e7b604f538620777c8ebc4ddf21070fdad9d3bd7 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 30 Oct 2017 11:17:11 +0100 Subject: [PATCH 19/56] changelog: adds note about closing #9645 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff844d94bfe..751fe2d3feb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ * **Postgres/MySQL**: add __timeGroup macro for mysql [#9596](https://github.com/grafana/grafana/pull/9596), thanks [@svenklemm](https://github.com/svenklemm) * **Text**: Text panel are now edited in the ace editor. [#9698](https://github.com/grafana/grafana/pull/9698), thx [@mtanda](https://github.com/mtanda) +## Minor +* **Alert panel**: Adds placeholder text when no alerts are within the time range [#9624](https://github.com/grafana/grafana/issues/9624), thx [@straend](https://github.com/straend) ## Tech * **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) From 1a8d05bbcbab3584c086782b918ce3a184e0dbc9 Mon Sep 17 00:00:00 2001 From: Bart Van Bos Date: Mon, 30 Oct 2017 12:50:57 +0100 Subject: [PATCH 20/56] Correct help message of api_dataproxy_request_all_milliseconds --- pkg/metrics/metrics.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 4b155ae3208..4d7de98f2ea 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -225,7 +225,7 @@ func init() { M_DataSource_ProxyReq_Timer = prometheus.NewSummary(prometheus.SummaryOpts{ Name: "api_dataproxy_request_all_milliseconds", - Help: "summary for dashboard search duration", + Help: "summary for dataproxy request duration", Namespace: exporterName, }) From d23c77119e39e5b36d250a5f9feb42288e300843 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 30 Oct 2017 21:31:07 +0100 Subject: [PATCH 21/56] docs: adds prom grafana dashboard --- docs/sources/features/datasources/prometheus.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/features/datasources/prometheus.md b/docs/sources/features/datasources/prometheus.md index dceb2254e41..3748a15195f 100644 --- a/docs/sources/features/datasources/prometheus.md +++ b/docs/sources/features/datasources/prometheus.md @@ -95,3 +95,7 @@ Prometheus supports two ways to query annotations. - A Prometheus query for pending and firing alerts (for details see [Inspecting alerts during runtime](https://prometheus.io/docs/alerting/rules/#inspecting-alerts-during-runtime)) The step option is useful to limit the number of events returned from your query. + +## Getting Grafana metrics into Prometheus + +Since 4.6.0 Grafana exposes metrics for Prometheus on the `/metrics` endpoint. We also bundle a dashboard within Grafana so you can get started viewing your metrics faster. You can import the bundled dashboard by going to the data source edit page and click the dashboard tab. There you can find a dashboard for Grafana and one for Prometheus. Import and start viewing all the metrics! From ae11bf7c147539a64c0f947555318eb0af117735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 09:22:45 +0100 Subject: [PATCH 22/56] fix: dashboard links dropdown toggle did not update view, fixes #9732 --- public/app/features/dashlinks/editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashlinks/editor.html b/public/app/features/dashlinks/editor.html index d1d73520283..ae77dd988fc 100644 --- a/public/app/features/dashlinks/editor.html +++ b/public/app/features/dashlinks/editor.html @@ -15,7 +15,7 @@ With tags
    - +
    Title From caa8b6100e6dd46f0865984d7b868f1717430eb1 Mon Sep 17 00:00:00 2001 From: Sven Klemm <31455525+svenklemm@users.noreply.github.com> Date: Tue, 31 Oct 2017 12:23:21 +0100 Subject: [PATCH 23/56] always quote template variables for postgres when multi-value or include (#9714) all is allowed --- .../plugins/datasource/postgres/datasource.ts | 8 ++++-- .../postgres/specs/datasource_specs.ts | 26 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/public/app/plugins/datasource/postgres/datasource.ts b/public/app/plugins/datasource/postgres/datasource.ts index 68471f035ff..af3d83f50d8 100644 --- a/public/app/plugins/datasource/postgres/datasource.ts +++ b/public/app/plugins/datasource/postgres/datasource.ts @@ -15,9 +15,13 @@ export class PostgresDatasource { this.responseParser = new ResponseParser(this.$q); } - interpolateVariable(value) { + interpolateVariable(value, variable) { if (typeof value === 'string') { - return value; + if (variable.multi || variable.includeAll) { + return '\'' + value + '\''; + } else { + return value; + } } if (typeof value === 'number') { diff --git a/public/app/plugins/datasource/postgres/specs/datasource_specs.ts b/public/app/plugins/datasource/postgres/specs/datasource_specs.ts index 3f83bb76e7b..0c0b3ca303a 100644 --- a/public/app/plugins/datasource/postgres/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/postgres/specs/datasource_specs.ts @@ -2,6 +2,7 @@ import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common'; import moment from 'moment'; import helpers from 'test/specs/helpers'; import {PostgresDatasource} from '../datasource'; +import {CustomVariable} from 'app/features/templating/custom_variable'; describe('PostgreSQLDatasource', function() { var ctx = new helpers.ServiceTestContext(); @@ -195,22 +196,41 @@ describe('PostgreSQLDatasource', function() { }); describe('When interpolating variables', () => { + beforeEach(function() { + ctx.variable = new CustomVariable({},{}); + }); + describe('and value is a string', () => { it('should return an unquoted value', () => { - expect(ctx.ds.interpolateVariable('abc')).to.eql('abc'); + expect(ctx.ds.interpolateVariable('abc', ctx.variable)).to.eql('abc'); }); }); describe('and value is a number', () => { it('should return an unquoted value', () => { - expect(ctx.ds.interpolateVariable(1000)).to.eql(1000); + expect(ctx.ds.interpolateVariable(1000, ctx.variable)).to.eql(1000); }); }); describe('and value is an array of strings', () => { it('should return comma separated quoted values', () => { - expect(ctx.ds.interpolateVariable(['a', 'b', 'c'])).to.eql('\'a\',\'b\',\'c\''); + expect(ctx.ds.interpolateVariable(['a', 'b', 'c'], ctx.variable)).to.eql('\'a\',\'b\',\'c\''); }); }); + + describe('and variable allows multi-value and is a string', () => { + it('should return a quoted value', () => { + ctx.variable.multi = true; + expect(ctx.ds.interpolateVariable('abc', ctx.variable)).to.eql('\'abc\''); + }); + }); + + describe('and variable allows all and is a string', () => { + it('should return a quoted value', () => { + ctx.variable.includeAll = true; + expect(ctx.ds.interpolateVariable('abc', ctx.variable)).to.eql('\'abc\''); + }); + }); + }); }); From b6fafb13f5706f71c8bcc8614614ff8669645eea Mon Sep 17 00:00:00 2001 From: Sven Klemm <31455525+svenklemm@users.noreply.github.com> Date: Tue, 31 Oct 2017 12:23:50 +0100 Subject: [PATCH 24/56] always quote template variables for mysql when multi-value is allowed (#9712) * always quote template variables for mysql when multi-value is allowed * handle include all option similar to multi value * declare type * adjust tests to quoting change * dont specify type but let it be inferred * fix test for variable with includeAll --- .../plugins/datasource/mysql/datasource.ts | 8 ++++-- .../mysql/specs/datasource_specs.ts | 26 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/public/app/plugins/datasource/mysql/datasource.ts b/public/app/plugins/datasource/mysql/datasource.ts index e35896c0d04..ac5ccfeb5ca 100644 --- a/public/app/plugins/datasource/mysql/datasource.ts +++ b/public/app/plugins/datasource/mysql/datasource.ts @@ -15,9 +15,13 @@ export class MysqlDatasource { this.responseParser = new ResponseParser(this.$q); } - interpolateVariable(value) { + interpolateVariable(value, variable) { if (typeof value === 'string') { - return value; + if (variable.multi || variable.includeAll) { + return '\'' + value + '\''; + } else { + return value; + } } if (typeof value === 'number') { diff --git a/public/app/plugins/datasource/mysql/specs/datasource_specs.ts b/public/app/plugins/datasource/mysql/specs/datasource_specs.ts index f579ad15410..eb63f9c5b37 100644 --- a/public/app/plugins/datasource/mysql/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/mysql/specs/datasource_specs.ts @@ -2,6 +2,7 @@ import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common'; import moment from 'moment'; import helpers from 'test/specs/helpers'; import {MysqlDatasource} from '../datasource'; +import {CustomVariable} from 'app/features/templating/custom_variable'; describe('MySQLDatasource', function() { var ctx = new helpers.ServiceTestContext(); @@ -195,22 +196,41 @@ describe('MySQLDatasource', function() { }); describe('When interpolating variables', () => { + beforeEach(function() { + ctx.variable = new CustomVariable({},{}); + }); + describe('and value is a string', () => { it('should return an unquoted value', () => { - expect(ctx.ds.interpolateVariable('abc')).to.eql('abc'); + expect(ctx.ds.interpolateVariable('abc', ctx.variable)).to.eql('abc'); }); }); describe('and value is a number', () => { it('should return an unquoted value', () => { - expect(ctx.ds.interpolateVariable(1000)).to.eql(1000); + expect(ctx.ds.interpolateVariable(1000, ctx.variable)).to.eql(1000); }); }); describe('and value is an array of strings', () => { it('should return comma separated quoted values', () => { - expect(ctx.ds.interpolateVariable(['a', 'b', 'c'])).to.eql('\'a\',\'b\',\'c\''); + expect(ctx.ds.interpolateVariable(['a', 'b', 'c'], ctx.variable)).to.eql('\'a\',\'b\',\'c\''); }); }); + + describe('and variable allows multi-value and value is a string', () => { + it('should return a quoted value', () => { + ctx.variable.multi = true; + expect(ctx.ds.interpolateVariable('abc', ctx.variable)).to.eql('\'abc\''); + }); + }); + + describe('and variable allows all and value is a string', () => { + it('should return a quoted value', () => { + ctx.variable.includeAll = true; + expect(ctx.ds.interpolateVariable('abc', ctx.variable)).to.eql('\'abc\''); + }); + }); + }); }); From 1be476b5f5aedec9f2ce9d5d45d33700a0e0e672 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 31 Oct 2017 11:30:14 +0100 Subject: [PATCH 25/56] tech: switch to golang 1.9.2 --- appveyor.yml | 2 +- circle.yml | 2 +- docs/sources/project/building_from_source.md | 2 +- scripts/build/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 19de1d3a793..5d67edca9d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ clone_folder: c:\gopath\src\github.com\grafana\grafana environment: nodejs_version: "6" GOPATH: c:\gopath - GOVERSION: 1.9.1 + GOVERSION: 1.9.2 install: - rmdir c:\go /s /q diff --git a/circle.yml b/circle.yml index 8380bc2a2ff..4eb600bfde3 100644 --- a/circle.yml +++ b/circle.yml @@ -9,7 +9,7 @@ machine: GOPATH: "/home/ubuntu/.go_workspace" ORG_PATH: "github.com/grafana" REPO_PATH: "${ORG_PATH}/grafana" - GODIST: "go1.9.1.linux-amd64.tar.gz" + GODIST: "go1.9.2.linux-amd64.tar.gz" post: - mkdir -p ~/download - mkdir -p ~/docker diff --git a/docs/sources/project/building_from_source.md b/docs/sources/project/building_from_source.md index e4ccedb7299..b91aacb2c2b 100644 --- a/docs/sources/project/building_from_source.md +++ b/docs/sources/project/building_from_source.md @@ -13,7 +13,7 @@ dev environment. Grafana ships with its own required backend server; also comple ## Dependencies -- [Go 1.9.1](https://golang.org/dl/) +- [Go 1.9.2](https://golang.org/dl/) - [NodeJS LTS](https://nodejs.org/download/) - [Git](https://git-scm.com/downloads) diff --git a/scripts/build/Dockerfile b/scripts/build/Dockerfile index 89b0a1a46dd..6e48b42c8e8 100644 --- a/scripts/build/Dockerfile +++ b/scripts/build/Dockerfile @@ -21,7 +21,7 @@ RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A170311380 RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash - && \ yum install -y nodejs --nogpgcheck -ENV GOLANG_VERSION 1.9.1 +ENV GOLANG_VERSION 1.9.2 RUN wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo && \ yum install -y yarn --nogpgcheck && \ From 497993e2b233e748967ad59a9a53e864b5c9dd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 13:04:10 +0100 Subject: [PATCH 26/56] Update ROADMAP.md --- ROADMAP.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 3ce0c33f088..74a3a80b788 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,11 +1,10 @@ -# Roadmap (2017-08-29) +# Roadmap (2017-10-31) This roadmap is a tentative plan for the core development team. Things change constantly as PRs come in and priorities change. But it will give you an idea of our current vision and plan. ### Short term (1-4 months) - - Release Grafana v4.5 with fixes and minor enhancements - Release Grafana v5 - User groups - Dashboard folders @@ -13,17 +12,25 @@ But it will give you an idea of our current vision and plan. - New Dashboard layout engine - New sidemenu & nav UX - Elasticsearch alerting + - React migration foundation (core components) + - Graphite 1.1 Tags Support -### Long term +### Long term (4 - 8 months) - Backend plugins to support more Auth options, Alerting data sources & notifications -- Universal time series transformations for any data source (meta queries) -- Reporting -- Web socket & live data streams -- Migrate to Angular2 or react +- Alerting improvements (silence, per series tracking, etc) +- Dashboard as configuration and other automation / provisioning improvements +- Progress on React migration +- Change visualization (panel type) on the fly. +- Multi stat panel (vertical version of singlestat with bars/graph mode with big number etc) +- Repeat panel by query results +### In a distant future far far away + +- Meta queries +- Integrated light weight TSDB +- Web socket & live data sources ### Outside contributions We know this is being worked on right now by contributors (and we hope to merge it when it's ready). -- Clustering for alert engine (load distribution) From 948a5259a2c3b2eb6fa3a6fa06cdc5c9d7b9e5d6 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 31 Oct 2017 15:53:45 +0300 Subject: [PATCH 27/56] fix: color picker bug at series overrides page, #9715 (#9738) --- .../app/core/components/colorpicker/SeriesColorPicker.tsx | 2 +- public/app/plugins/panel/graph/series_overrides_ctrl.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/public/app/core/components/colorpicker/SeriesColorPicker.tsx b/public/app/core/components/colorpicker/SeriesColorPicker.tsx index 6b6d387a2b2..3b24b9a4661 100644 --- a/public/app/core/components/colorpicker/SeriesColorPicker.tsx +++ b/public/app/core/components/colorpicker/SeriesColorPicker.tsx @@ -43,7 +43,7 @@ export class SeriesColorPicker extends React.Component { render() { return (
    - {this.props.series && this.renderAxisSelection()} + {this.props.series.yaxis && this.renderAxisSelection()}
    ); diff --git a/public/app/plugins/panel/graph/series_overrides_ctrl.js b/public/app/plugins/panel/graph/series_overrides_ctrl.js index 2df993ff70e..5ee5b5e8e47 100644 --- a/public/app/plugins/panel/graph/series_overrides_ctrl.js +++ b/public/app/plugins/panel/graph/series_overrides_ctrl.js @@ -29,7 +29,7 @@ define([ $scope.setOverride = function(item, subItem) { // handle color overrides if (item.propertyName === 'color') { - $scope.openColorSelector(); + $scope.openColorSelector($scope.override['color']); return; } @@ -52,15 +52,17 @@ define([ $scope.ctrl.render(); }; - $scope.openColorSelector = function() { + $scope.openColorSelector = function(color) { + var fakeSeries = {color: color}; popoverSrv.show({ element: $element.find(".dropdown")[0], position: 'top center', openOn: 'click', - template: '', + template: '', model: { autoClose: true, colorSelected: $scope.colorSelected, + series: fakeSeries }, onClose: function() { $scope.ctrl.render(); From a503c1d39c98d78af580672002527a7fccf37eab Mon Sep 17 00:00:00 2001 From: Sven Klemm <31455525+svenklemm@users.noreply.github.com> Date: Tue, 31 Oct 2017 13:55:32 +0100 Subject: [PATCH 28/56] change default sslmode for postgres to verify-full (#9736) --- docs/sources/installation/configuration.md | 4 ++-- pkg/tsdb/postgres/postgres.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 627a76a963e..5da485144c8 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -551,7 +551,7 @@ session provider you have configured. - **file:** session file path, e.g. `data/sessions` - **mysql:** go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name` -- **postgres:** ex: user=a password=b host=localhost port=5432 dbname=c sslmode=require +- **postgres:** ex: user=a password=b host=localhost port=5432 dbname=c sslmode=verify-full - **memcache:** ex: 127.0.0.1:11211 - **redis:** ex: `addr=127.0.0.1:6379,pool_size=100,prefix=grafana` @@ -580,7 +580,7 @@ CREATE TABLE session ( ); ``` -Postgres valid `sslmode` are `disable`, `require` (default), `verify-ca`, and `verify-full`. +Postgres valid `sslmode` are `disable`, `require`, `verify-ca`, and `verify-full` (default). ### cookie_name diff --git a/pkg/tsdb/postgres/postgres.go b/pkg/tsdb/postgres/postgres.go index 6fc9c89e7be..f6fe7797bcf 100644 --- a/pkg/tsdb/postgres/postgres.go +++ b/pkg/tsdb/postgres/postgres.go @@ -51,7 +51,7 @@ func generateConnectionString(datasource *models.DataSource) string { } } - sslmode := datasource.JsonData.Get("sslmode").MustString("require") + sslmode := datasource.JsonData.Get("sslmode").MustString("verify-full") return fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", datasource.User, password, datasource.Url, datasource.Database, sslmode) } From 7336a98bb164f562ccba8cfdaea89fab4cf98c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 13:56:00 +0100 Subject: [PATCH 29/56] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 751fe2d3feb..b4846d9db44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ # 4.6.1 (unreleased) * **Singlestat**: Lost thresholds when using save dashboard as [#9681](https://github.com/grafana/grafana/issues/9681) +* **Graph**: Fix for series override color picker [#9715](https://github.com/grafana/grafana/issues/9715) # 4.6.0 (2017-10-26) From afd4f37f39e6640f8ed85998ccfe1f293433cbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 13:58:01 +0100 Subject: [PATCH 30/56] Update codecov.yml --- codecov.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/codecov.yml b/codecov.yml index 3d764c1a5b1..82a86e0232b 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,5 +7,7 @@ coverage: project: yes patch: yes changes: no - -comment: false + +comment: + layout: "diff" + behavior: "once" From c3a9a04daddf83e8d9659e8f34e3af60e3e67678 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 31 Oct 2017 13:58:38 +0100 Subject: [PATCH 31/56] converted confirm_click.js to .ts (#9674) * converted confirm_click.js to .ts * deleted confirm_click.ts * removed import of confirm_click --- public/app/core/core.ts | 1 - public/app/core/directives/confirm_click.js | 23 --------------------- 2 files changed, 24 deletions(-) delete mode 100644 public/app/core/directives/confirm_click.js diff --git a/public/app/core/core.ts b/public/app/core/core.ts index 9630fdac9c0..fb92fd81d19 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -1,5 +1,4 @@ import "./directives/dash_class"; -import "./directives/confirm_click"; import "./directives/dash_edit_link"; import "./directives/dropdown_typeahead"; import "./directives/metric_segment"; diff --git a/public/app/core/directives/confirm_click.js b/public/app/core/directives/confirm_click.js deleted file mode 100644 index 95b60347e10..00000000000 --- a/public/app/core/directives/confirm_click.js +++ /dev/null @@ -1,23 +0,0 @@ -define([ - '../core_module', -], -function (coreModule) { - 'use strict'; - - coreModule.default.directive('confirmClick', function() { - return { - restrict: 'A', - link: function(scope, elem, attrs) { - elem.bind('click', function() { - var message = attrs.confirmation || "Are you sure you want to do that?"; - if (window.confirm(message)) { - var action = attrs.confirmClick; - if (action) { - scope.$apply(scope.$eval(action)); - } - } - }); - }, - }; - }); -}); From 3c572aece61431f0c263d002d4f2b51c16e39a1a Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 31 Oct 2017 12:56:06 +0100 Subject: [PATCH 32/56] changelog: adds note about closing #9713 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4846d9db44..0f9c70c540d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ * **Singlestat**: Lost thresholds when using save dashboard as [#9681](https://github.com/grafana/grafana/issues/9681) * **Graph**: Fix for series override color picker [#9715](https://github.com/grafana/grafana/issues/9715) +* **Go**: build using golang 1.9.2 [#9713](https://github.com/grafana/grafana/issues/9713) # 4.6.0 (2017-10-26) From ae5b3fd4b5042062dfa91918f28ec57a9542b806 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 31 Oct 2017 14:14:50 +0100 Subject: [PATCH 33/56] github: dont require bug/fr in title --- .github/ISSUE_TEMPLATE.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 57fca7f44cb..082482fcb74 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -4,8 +4,6 @@ Read before posting: - Checkout FAQ: https://community.grafana.com/c/howto/faq - Checkout How to troubleshoot metric query issues: https://community.grafana.com/t/how-to-troubleshoot-metric-query-issues/50 -Please prefix your title with [Bug] or [Feature request]. - Please include this information: - What Grafana version are you using? - What datasource are you using? From 1206ce261cbd7d8e47c9306c781919efa9d4171c Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 31 Oct 2017 14:29:10 +0100 Subject: [PATCH 34/56] fix for dashboard tag link bug, fixes #9737 (#9739) --- public/app/features/dashlinks/editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashlinks/editor.html b/public/app/features/dashlinks/editor.html index ae77dd988fc..11dfdf74c1f 100644 --- a/public/app/features/dashlinks/editor.html +++ b/public/app/features/dashlinks/editor.html @@ -13,7 +13,7 @@
    With tags - +
    From ec94dfa8906ebbb63bc3c1dc1acf1c09561ae9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 14:29:25 +0100 Subject: [PATCH 35/56] tests: migrated tests for link_srv to jest, #9666 --- public/app/features/panellinks/link_srv.ts | 8 ++-- .../panellinks/specs/link_srv_specs.ts | 46 ------------------- 2 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 public/app/features/panellinks/specs/link_srv_specs.ts diff --git a/public/app/features/panellinks/link_srv.ts b/public/app/features/panellinks/link_srv.ts index 873e0233e41..71192a86487 100644 --- a/public/app/features/panellinks/link_srv.ts +++ b/public/app/features/panellinks/link_srv.ts @@ -5,8 +5,7 @@ import kbn from 'app/core/utils/kbn'; export class LinkSrv { /** @ngInject */ - constructor(private templateSrv, private timeSrv) { - } + constructor(private templateSrv, private timeSrv) {} getLinkUrl(link) { var url = this.templateSrv.replace(link.url || ''); @@ -29,7 +28,9 @@ export class LinkSrv { var paramsArray = []; _.each(params, function(value, key) { - if (value === null) { return; } + if (value === null) { + return; + } if (value === true) { paramsArray.push(key); } else if (_.isArray(value)) { @@ -107,7 +108,6 @@ export class LinkSrv { return info; } - } angular.module('grafana.services').service('linkSrv', LinkSrv); diff --git a/public/app/features/panellinks/specs/link_srv_specs.ts b/public/app/features/panellinks/specs/link_srv_specs.ts deleted file mode 100644 index 397e97ca758..00000000000 --- a/public/app/features/panellinks/specs/link_srv_specs.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common'; -import 'app/features/panellinks/link_srv'; -import _ from 'lodash'; - -describe('linkSrv', function() { - var _linkSrv; - - beforeEach(angularMocks.module('grafana.core')); - beforeEach(angularMocks.module('grafana.services')); - - beforeEach(angularMocks.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 38ec8ddefc9c5827ba9640c70a176577ab2883b8 Mon Sep 17 00:00:00 2001 From: Akshay Chhajed Date: Tue, 31 Oct 2017 18:59:27 +0530 Subject: [PATCH 36/56] Transitioning fig to docker-compose v3 --- docker/blocks/collectd/docker-compose.yaml | 11 ++++++++ docker/blocks/collectd/fig | 11 -------- docker/blocks/elastic/docker-compose.yaml | 8 ++++++ docker/blocks/elastic/fig | 8 ------ docker/blocks/elastic1/docker-compose.yaml | 8 ++++++ docker/blocks/elastic1/fig | 8 ------ docker/blocks/elastic5/docker-compose.yaml | 8 ++++++ docker/blocks/elastic5/fig | 8 ------ docker/blocks/graphite/docker-compose.yaml | 16 ++++++++++++ docker/blocks/graphite/fig | 16 ------------ docker/blocks/graphite1/docker-compose.yaml | 16 ++++++++++++ docker/blocks/graphite1/fig | 16 ------------ docker/blocks/influxdb/docker-compose.yaml | 17 +++++++++++++ docker/blocks/influxdb/fig | 17 ------------- docker/blocks/jaeger/docker-compose.yaml | 6 +++++ docker/blocks/jaeger/fig | 6 ----- docker/blocks/memcached/docker-compose.yaml | 5 ++++ docker/blocks/memcached/fig | 5 ---- docker/blocks/mysql/docker-compose.yaml | 14 +++++++++++ docker/blocks/mysql/fig | 14 ----------- .../blocks/mysql_opendata/docker-compose.yaml | 9 +++++++ docker/blocks/mysql_opendata/fig | 9 ------- docker/blocks/mysql_tests/docker-compose.yaml | 9 +++++++ docker/blocks/mysql_tests/fig | 9 ------- docker/blocks/openldap/docker-compose.yaml | 10 ++++++++ docker/blocks/openldap/fig | 10 -------- docker/blocks/opentsdb/docker-compose.yaml | 11 ++++++++ docker/blocks/opentsdb/fig | 11 -------- docker/blocks/postgres/docker-compose.yaml | 9 +++++++ docker/blocks/postgres/fig | 9 ------- .../blocks/postgres_tests/docker-compose.yaml | 7 ++++++ docker/blocks/postgres_tests/fig | 7 ------ docker/blocks/prometheus/docker-compose.yaml | 25 +++++++++++++++++++ docker/blocks/prometheus/fig | 25 ------------------- docker/blocks/smtp/docker-compose.yaml | 4 +++ docker/blocks/smtp/fig | 4 --- docker/compose_header.yml | 2 ++ docker/create_docker_compose.sh | 12 ++++++--- 38 files changed, 203 insertions(+), 197 deletions(-) create mode 100644 docker/blocks/collectd/docker-compose.yaml delete mode 100644 docker/blocks/collectd/fig create mode 100644 docker/blocks/elastic/docker-compose.yaml delete mode 100644 docker/blocks/elastic/fig create mode 100644 docker/blocks/elastic1/docker-compose.yaml delete mode 100644 docker/blocks/elastic1/fig create mode 100644 docker/blocks/elastic5/docker-compose.yaml delete mode 100644 docker/blocks/elastic5/fig create mode 100644 docker/blocks/graphite/docker-compose.yaml delete mode 100644 docker/blocks/graphite/fig create mode 100644 docker/blocks/graphite1/docker-compose.yaml delete mode 100644 docker/blocks/graphite1/fig create mode 100644 docker/blocks/influxdb/docker-compose.yaml delete mode 100644 docker/blocks/influxdb/fig create mode 100644 docker/blocks/jaeger/docker-compose.yaml delete mode 100644 docker/blocks/jaeger/fig create mode 100644 docker/blocks/memcached/docker-compose.yaml delete mode 100644 docker/blocks/memcached/fig create mode 100644 docker/blocks/mysql/docker-compose.yaml delete mode 100644 docker/blocks/mysql/fig create mode 100644 docker/blocks/mysql_opendata/docker-compose.yaml delete mode 100644 docker/blocks/mysql_opendata/fig create mode 100644 docker/blocks/mysql_tests/docker-compose.yaml delete mode 100644 docker/blocks/mysql_tests/fig create mode 100644 docker/blocks/openldap/docker-compose.yaml delete mode 100644 docker/blocks/openldap/fig create mode 100644 docker/blocks/opentsdb/docker-compose.yaml delete mode 100644 docker/blocks/opentsdb/fig create mode 100644 docker/blocks/postgres/docker-compose.yaml delete mode 100644 docker/blocks/postgres/fig create mode 100644 docker/blocks/postgres_tests/docker-compose.yaml delete mode 100644 docker/blocks/postgres_tests/fig create mode 100644 docker/blocks/prometheus/docker-compose.yaml delete mode 100644 docker/blocks/prometheus/fig create mode 100644 docker/blocks/smtp/docker-compose.yaml delete mode 100644 docker/blocks/smtp/fig create mode 100644 docker/compose_header.yml diff --git a/docker/blocks/collectd/docker-compose.yaml b/docker/blocks/collectd/docker-compose.yaml new file mode 100644 index 00000000000..c95827f7928 --- /dev/null +++ b/docker/blocks/collectd/docker-compose.yaml @@ -0,0 +1,11 @@ + collectd: + build: blocks/collectd + environment: + HOST_NAME: myserver + GRAPHITE_HOST: graphite + GRAPHITE_PORT: 2003 + GRAPHITE_PREFIX: collectd. + REPORT_BY_CPU: 'false' + COLLECT_INTERVAL: 10 + links: + - graphite diff --git a/docker/blocks/collectd/fig b/docker/blocks/collectd/fig deleted file mode 100644 index 99f45a66d12..00000000000 --- a/docker/blocks/collectd/fig +++ /dev/null @@ -1,11 +0,0 @@ -collectd: - build: blocks/collectd - environment: - HOST_NAME: myserver - GRAPHITE_HOST: graphite - GRAPHITE_PORT: 2003 - GRAPHITE_PREFIX: collectd. - REPORT_BY_CPU: 'false' - COLLECT_INTERVAL: 10 - links: - - graphite diff --git a/docker/blocks/elastic/docker-compose.yaml b/docker/blocks/elastic/docker-compose.yaml new file mode 100644 index 00000000000..193b8f252f6 --- /dev/null +++ b/docker/blocks/elastic/docker-compose.yaml @@ -0,0 +1,8 @@ + elasticsearch: + image: elasticsearch:2.4.1 + command: elasticsearch -Des.network.host=0.0.0.0 + ports: + - "9200:9200" + - "9300:9300" + volumes: + - ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml diff --git a/docker/blocks/elastic/fig b/docker/blocks/elastic/fig deleted file mode 100644 index fa79a9af59c..00000000000 --- a/docker/blocks/elastic/fig +++ /dev/null @@ -1,8 +0,0 @@ -elasticsearch: - image: elasticsearch:2.4.1 - command: elasticsearch -Des.network.host=0.0.0.0 - ports: - - "9200:9200" - - "9300:9300" - volumes: - - ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml diff --git a/docker/blocks/elastic1/docker-compose.yaml b/docker/blocks/elastic1/docker-compose.yaml new file mode 100644 index 00000000000..518ae76e6ee --- /dev/null +++ b/docker/blocks/elastic1/docker-compose.yaml @@ -0,0 +1,8 @@ + elasticsearch1: + image: elasticsearch:1.7.6 + command: elasticsearch -Des.network.host=0.0.0.0 + ports: + - "11200:9200" + - "11300:9300" + volumes: + - ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml diff --git a/docker/blocks/elastic1/fig b/docker/blocks/elastic1/fig deleted file mode 100644 index c33e51f16a2..00000000000 --- a/docker/blocks/elastic1/fig +++ /dev/null @@ -1,8 +0,0 @@ -elasticsearch1: - image: elasticsearch:1.7.6 - command: elasticsearch -Des.network.host=0.0.0.0 - ports: - - "11200:9200" - - "11300:9300" - volumes: - - ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml diff --git a/docker/blocks/elastic5/docker-compose.yaml b/docker/blocks/elastic5/docker-compose.yaml new file mode 100644 index 00000000000..5b12be9ada4 --- /dev/null +++ b/docker/blocks/elastic5/docker-compose.yaml @@ -0,0 +1,8 @@ +# You need to run 'sysctl -w vm.max_map_count=262144' on the host machine + + elasticsearch5: + image: elasticsearch:5 + command: elasticsearch + ports: + - "10200:9200" + - "10300:9300" diff --git a/docker/blocks/elastic5/fig b/docker/blocks/elastic5/fig deleted file mode 100644 index 6e5cd89ab3d..00000000000 --- a/docker/blocks/elastic5/fig +++ /dev/null @@ -1,8 +0,0 @@ -# You need to run 'sysctl -w vm.max_map_count=262144' on the host machine - -elasticsearch5: - image: elasticsearch:5 - command: elasticsearch - ports: - - "10200:9200" - - "10300:9300" diff --git a/docker/blocks/graphite/docker-compose.yaml b/docker/blocks/graphite/docker-compose.yaml new file mode 100644 index 00000000000..2bd0dc322cc --- /dev/null +++ b/docker/blocks/graphite/docker-compose.yaml @@ -0,0 +1,16 @@ + graphite: + build: blocks/graphite + ports: + - "8080:80" + - "2003:2003" + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + + fake-graphite-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: graphite + FD_PORT: 2003 + diff --git a/docker/blocks/graphite/fig b/docker/blocks/graphite/fig deleted file mode 100644 index b7e030e388e..00000000000 --- a/docker/blocks/graphite/fig +++ /dev/null @@ -1,16 +0,0 @@ -graphite: - build: blocks/graphite - ports: - - "8080:80" - - "2003:2003" - volumes: - - /etc/localtime:/etc/localtime:ro - - /etc/timezone:/etc/timezone:ro - -fake-graphite-data: - image: grafana/fake-data-gen - net: bridge - environment: - FD_DATASOURCE: graphite - FD_PORT: 2003 - diff --git a/docker/blocks/graphite1/docker-compose.yaml b/docker/blocks/graphite1/docker-compose.yaml new file mode 100644 index 00000000000..577a393b123 --- /dev/null +++ b/docker/blocks/graphite1/docker-compose.yaml @@ -0,0 +1,16 @@ + graphite: + build: blocks/graphite1 + ports: + - "8080:80" + - "2003:2003" + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + + fake-graphite-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: graphite + FD_PORT: 2003 + diff --git a/docker/blocks/graphite1/fig b/docker/blocks/graphite1/fig deleted file mode 100644 index 5337376ff5c..00000000000 --- a/docker/blocks/graphite1/fig +++ /dev/null @@ -1,16 +0,0 @@ -graphite: - build: blocks/graphite1 - ports: - - "8080:80" - - "2003:2003" - volumes: - - /etc/localtime:/etc/localtime:ro - - /etc/timezone:/etc/timezone:ro - -fake-graphite-data: - image: grafana/fake-data-gen - net: bridge - environment: - FD_DATASOURCE: graphite - FD_PORT: 2003 - diff --git a/docker/blocks/influxdb/docker-compose.yaml b/docker/blocks/influxdb/docker-compose.yaml new file mode 100644 index 00000000000..3434f5d09b9 --- /dev/null +++ b/docker/blocks/influxdb/docker-compose.yaml @@ -0,0 +1,17 @@ + influxdb: + image: influxdb:latest + container_name: influxdb + ports: + - "2004:2004" + - "8083:8083" + - "8086:8086" + volumes: + - ./blocks/influxdb/influxdb.conf:/etc/influxdb/influxdb.conf + + fake-influxdb-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: influxdb + FD_PORT: 8086 + diff --git a/docker/blocks/influxdb/fig b/docker/blocks/influxdb/fig deleted file mode 100644 index 8821c010a98..00000000000 --- a/docker/blocks/influxdb/fig +++ /dev/null @@ -1,17 +0,0 @@ -influxdb: - image: influxdb:latest - container_name: influxdb - ports: - - "2004:2004" - - "8083:8083" - - "8086:8086" - volumes: - - ./blocks/influxdb/influxdb.conf:/etc/influxdb/influxdb.conf - -fake-influxdb-data: - image: grafana/fake-data-gen - net: bridge - environment: - FD_DATASOURCE: influxdb - FD_PORT: 8086 - diff --git a/docker/blocks/jaeger/docker-compose.yaml b/docker/blocks/jaeger/docker-compose.yaml new file mode 100644 index 00000000000..2b57c863425 --- /dev/null +++ b/docker/blocks/jaeger/docker-compose.yaml @@ -0,0 +1,6 @@ + jaeger: + image: jaegertracing/all-in-one:latest + ports: + - "127.0.0.1:6831:6831/udp" + - "16686:16686" + diff --git a/docker/blocks/jaeger/fig b/docker/blocks/jaeger/fig deleted file mode 100644 index ab9e2ec599b..00000000000 --- a/docker/blocks/jaeger/fig +++ /dev/null @@ -1,6 +0,0 @@ -jaeger: - image: jaegertracing/all-in-one:latest - ports: - - "localhost:6831:6831/udp" - - "16686:16686" - diff --git a/docker/blocks/memcached/docker-compose.yaml b/docker/blocks/memcached/docker-compose.yaml new file mode 100644 index 00000000000..b3201da0f95 --- /dev/null +++ b/docker/blocks/memcached/docker-compose.yaml @@ -0,0 +1,5 @@ + memcached: + image: memcached:latest + ports: + - "11211:11211" + diff --git a/docker/blocks/memcached/fig b/docker/blocks/memcached/fig deleted file mode 100644 index a0da9df2bc2..00000000000 --- a/docker/blocks/memcached/fig +++ /dev/null @@ -1,5 +0,0 @@ -memcached: - image: memcached:latest - ports: - - "11211:11211" - diff --git a/docker/blocks/mysql/docker-compose.yaml b/docker/blocks/mysql/docker-compose.yaml new file mode 100644 index 00000000000..6eee158ac43 --- /dev/null +++ b/docker/blocks/mysql/docker-compose.yaml @@ -0,0 +1,14 @@ + mysql: + image: mysql:latest + environment: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: grafana + MYSQL_USER: grafana + MYSQL_PASSWORD: password + ports: + - "3306:3306" + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all] + diff --git a/docker/blocks/mysql/fig b/docker/blocks/mysql/fig deleted file mode 100644 index 24cb47b61a7..00000000000 --- a/docker/blocks/mysql/fig +++ /dev/null @@ -1,14 +0,0 @@ -mysql: - image: mysql:latest - environment: - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_DATABASE: grafana - MYSQL_USER: grafana - MYSQL_PASSWORD: password - ports: - - "3306:3306" - volumes: - - /etc/localtime:/etc/localtime:ro - - /etc/timezone:/etc/timezone:ro - command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all] - diff --git a/docker/blocks/mysql_opendata/docker-compose.yaml b/docker/blocks/mysql_opendata/docker-compose.yaml new file mode 100644 index 00000000000..594eeed284a --- /dev/null +++ b/docker/blocks/mysql_opendata/docker-compose.yaml @@ -0,0 +1,9 @@ + mysql_opendata: + build: blocks/mysql_opendata + environment: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: testdata + MYSQL_USER: grafana + MYSQL_PASSWORD: password + ports: + - "3307:3306" diff --git a/docker/blocks/mysql_opendata/fig b/docker/blocks/mysql_opendata/fig deleted file mode 100644 index a374fbd0931..00000000000 --- a/docker/blocks/mysql_opendata/fig +++ /dev/null @@ -1,9 +0,0 @@ -mysql_opendata: - build: blocks/mysql_opendata - environment: - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_DATABASE: testdata - MYSQL_USER: grafana - MYSQL_PASSWORD: password - ports: - - "3307:3306" diff --git a/docker/blocks/mysql_tests/docker-compose.yaml b/docker/blocks/mysql_tests/docker-compose.yaml new file mode 100644 index 00000000000..646cc7ee369 --- /dev/null +++ b/docker/blocks/mysql_tests/docker-compose.yaml @@ -0,0 +1,9 @@ + mysqltests: + image: mysql:latest + environment: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: grafana_tests + MYSQL_USER: grafana + MYSQL_PASSWORD: password + ports: + - "3306:3306" diff --git a/docker/blocks/mysql_tests/fig b/docker/blocks/mysql_tests/fig deleted file mode 100644 index 880c955d218..00000000000 --- a/docker/blocks/mysql_tests/fig +++ /dev/null @@ -1,9 +0,0 @@ -mysqltests: - image: mysql:latest - environment: - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_DATABASE: grafana_tests - MYSQL_USER: grafana - MYSQL_PASSWORD: password - ports: - - "3306:3306" diff --git a/docker/blocks/openldap/docker-compose.yaml b/docker/blocks/openldap/docker-compose.yaml new file mode 100644 index 00000000000..be06524a57d --- /dev/null +++ b/docker/blocks/openldap/docker-compose.yaml @@ -0,0 +1,10 @@ + openldap: + build: blocks/openldap + environment: + SLAPD_PASSWORD: grafana + SLAPD_DOMAIN: grafana.org + SLAPD_ADDITIONAL_MODULES: memberof + ports: + - "389:389" + + diff --git a/docker/blocks/openldap/fig b/docker/blocks/openldap/fig deleted file mode 100644 index b9528f2d4d7..00000000000 --- a/docker/blocks/openldap/fig +++ /dev/null @@ -1,10 +0,0 @@ -openldap: - build: blocks/openldap - environment: - SLAPD_PASSWORD: grafana - SLAPD_DOMAIN: grafana.org - SLAPD_ADDITIONAL_MODULES: memberof - ports: - - "389:389" - - diff --git a/docker/blocks/opentsdb/docker-compose.yaml b/docker/blocks/opentsdb/docker-compose.yaml new file mode 100644 index 00000000000..ee064bb107d --- /dev/null +++ b/docker/blocks/opentsdb/docker-compose.yaml @@ -0,0 +1,11 @@ + opentsdb: + image: opower/opentsdb:latest + ports: + - "4242:4242" + + fake-opentsdb-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: opentsdb + diff --git a/docker/blocks/opentsdb/fig b/docker/blocks/opentsdb/fig deleted file mode 100644 index c346475e9a3..00000000000 --- a/docker/blocks/opentsdb/fig +++ /dev/null @@ -1,11 +0,0 @@ -opentsdb: - image: opower/opentsdb:latest - ports: - - "4242:4242" - -fake-opentsdb-data: - image: grafana/fake-data-gen - net: bridge - environment: - FD_DATASOURCE: opentsdb - diff --git a/docker/blocks/postgres/docker-compose.yaml b/docker/blocks/postgres/docker-compose.yaml new file mode 100644 index 00000000000..eced00aafeb --- /dev/null +++ b/docker/blocks/postgres/docker-compose.yaml @@ -0,0 +1,9 @@ + postgrestest: + image: postgres:latest + environment: + POSTGRES_USER: grafana + POSTGRES_PASSWORD: password + POSTGRES_DATABASE: grafana + ports: + - "5432:5432" + command: postgres -c log_connections=on -c logging_collector=on -c log_destination=stderr -c log_directory=/var/log/postgresql diff --git a/docker/blocks/postgres/fig b/docker/blocks/postgres/fig deleted file mode 100644 index 049339a15c7..00000000000 --- a/docker/blocks/postgres/fig +++ /dev/null @@ -1,9 +0,0 @@ -postgrestest: - image: postgres:latest - environment: - POSTGRES_USER: grafana - POSTGRES_PASSWORD: password - POSTGRES_DATABASE: grafana - ports: - - "5432:5432" - command: postgres -c log_connections=on -c logging_collector=on -c log_destination=stderr -c log_directory=/var/log/postgresql diff --git a/docker/blocks/postgres_tests/docker-compose.yaml b/docker/blocks/postgres_tests/docker-compose.yaml new file mode 100644 index 00000000000..3d9a82c034c --- /dev/null +++ b/docker/blocks/postgres_tests/docker-compose.yaml @@ -0,0 +1,7 @@ + postgrestest: + image: postgres:latest + environment: + POSTGRES_USER: grafanatest + POSTGRES_PASSWORD: grafanatest + ports: + - "5432:5432" diff --git a/docker/blocks/postgres_tests/fig b/docker/blocks/postgres_tests/fig deleted file mode 100644 index 049afe185c8..00000000000 --- a/docker/blocks/postgres_tests/fig +++ /dev/null @@ -1,7 +0,0 @@ -postgrestest: - image: postgres:latest - environment: - POSTGRES_USER: grafanatest - POSTGRES_PASSWORD: grafanatest - ports: - - "5432:5432" diff --git a/docker/blocks/prometheus/docker-compose.yaml b/docker/blocks/prometheus/docker-compose.yaml new file mode 100644 index 00000000000..ccb1238a179 --- /dev/null +++ b/docker/blocks/prometheus/docker-compose.yaml @@ -0,0 +1,25 @@ + prometheus: + build: blocks/prometheus + network_mode: host + ports: + - "9090:9090" + + node_exporter: + image: prom/node-exporter + network_mode: host + ports: + - "9100:9100" + + fake-prometheus-data: + image: grafana/fake-data-gen + network_mode: host + ports: + - "9091:9091" + environment: + FD_DATASOURCE: prom + + alertmanager: + image: quay.io/prometheus/alertmanager + network_mode: host + ports: + - "9093:9093" diff --git a/docker/blocks/prometheus/fig b/docker/blocks/prometheus/fig deleted file mode 100644 index 7d9bea68046..00000000000 --- a/docker/blocks/prometheus/fig +++ /dev/null @@ -1,25 +0,0 @@ -prometheus: - build: blocks/prometheus - net: host - ports: - - "9090:9090" - -node_exporter: - image: prom/node-exporter - net: host - ports: - - "9100:9100" - -fake-prometheus-data: - image: grafana/fake-data-gen - net: host - ports: - - "9091:9091" - environment: - FD_DATASOURCE: prom - -alertmanager: - image: quay.io/prometheus/alertmanager - net: host - ports: - - "9093:9093" diff --git a/docker/blocks/smtp/docker-compose.yaml b/docker/blocks/smtp/docker-compose.yaml new file mode 100644 index 00000000000..85d598b6167 --- /dev/null +++ b/docker/blocks/smtp/docker-compose.yaml @@ -0,0 +1,4 @@ + snmpd: + image: namshi/smtp + ports: + - "25:25" diff --git a/docker/blocks/smtp/fig b/docker/blocks/smtp/fig deleted file mode 100644 index 3aa25e01311..00000000000 --- a/docker/blocks/smtp/fig +++ /dev/null @@ -1,4 +0,0 @@ -snmpd: - image: namshi/smtp - ports: - - "25:25" diff --git a/docker/compose_header.yml b/docker/compose_header.yml new file mode 100644 index 00000000000..117e40b314e --- /dev/null +++ b/docker/compose_header.yml @@ -0,0 +1,2 @@ +version: "3" +services: diff --git a/docker/create_docker_compose.sh b/docker/create_docker_compose.sh index 8588c1c474a..9d28ede8e7e 100755 --- a/docker/create_docker_compose.sh +++ b/docker/create_docker_compose.sh @@ -7,8 +7,9 @@ template_dir=templates grafana_config_file=conf.tmp grafana_config=config -fig_file=docker-compose.yml -fig_config=fig +compose_header_file=compose_header.yml +fig_file=docker-compose.yaml +fig_config=docker-compose.yaml if [ "$#" == 0 ]; then blocks=`ls $blocks_dir` @@ -23,13 +24,16 @@ if [ "$#" == 0 ]; then exit 0 fi -for file in $gogs_config_file $fig_file; do +for file in $grafana_config_file $fig_file; do if [ -e $file ]; then echo "Deleting $file" rm $file fi done +echo "Adding Compose header to $fig_file" +cat $compose_header_file >> $fig_file + for dir in $@; do current_dir=$blocks_dir/$dir if [ ! -d "$current_dir" ]; then @@ -45,7 +49,7 @@ for dir in $@; do if [ -e $current_dir/$fig_config ]; then echo "Adding $current_dir/$fig_config to $fig_file" - cat $current_dir/fig >> $fig_file + cat $current_dir/$fig_config >> $fig_file echo "" >> $fig_file fi done From 7f83460f429f68898499c5b1d8ea77699eb4a695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 14:30:06 +0100 Subject: [PATCH 37/56] tests: migrated tests for link_srv to jest, #9666 --- .../panellinks/specs/link_srv.jest.ts | 47 +++++++++++++++++++ public/test/mocks/angular.ts | 17 +++++++ 2 files changed, 64 insertions(+) create mode 100644 public/app/features/panellinks/specs/link_srv.jest.ts create mode 100644 public/test/mocks/angular.ts diff --git a/public/app/features/panellinks/specs/link_srv.jest.ts b/public/app/features/panellinks/specs/link_srv.jest.ts new file mode 100644 index 00000000000..2ec38961e29 --- /dev/null +++ b/public/app/features/panellinks/specs/link_srv.jest.ts @@ -0,0 +1,47 @@ +import { LinkSrv } from '../link_srv'; +import _ from 'lodash'; + +jest.mock('angular', () => { + let AngularJSMock = require('test/mocks/angular'); + return new AngularJSMock(); +}); + +describe('linkSrv', function() { + var linkSrv; + var templateSrvMock = {}; + var timeSrvMock = {}; + + beforeEach(() => { + linkSrv = new LinkSrv(templateSrvMock, timeSrvMock); + }); + + 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).toBe('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).toBe('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).toBe('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).toBe('http://example.com'); + + var url2 = linkSrv.appendToQueryString('http://example.com?', toAppend); + expect(url2).toBe('http://example.com?'); + + var url3 = linkSrv.appendToQueryString('http://example.com?foo=bar', toAppend); + expect(url3).toBe('http://example.com?foo=bar'); + }); + }); + }); +}); diff --git a/public/test/mocks/angular.ts b/public/test/mocks/angular.ts new file mode 100644 index 00000000000..185d64214fd --- /dev/null +++ b/public/test/mocks/angular.ts @@ -0,0 +1,17 @@ +export default class AngularJSMock { + service: any; + controller: any; + directive: any; + + constructor() { + this.service = jest.fn(); + this.controller = jest.fn(); + this.directive = jest.fn(); + } + + module() { + return this; + } +} + +module.exports = AngularJSMock; From a1c1704d1f863d8c7b1ae4a295cffd9553393316 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 31 Oct 2017 14:57:57 +0100 Subject: [PATCH 38/56] Adding energy, area, and acceleration units (#9336) * Adding more units * move changes to kbn.ts * remove accidental commits --- public/app/core/utils/kbn.ts | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/public/app/core/utils/kbn.ts b/public/app/core/utils/kbn.ts index f1c44cfae0e..baadb604685 100644 --- a/public/app/core/utils/kbn.ts +++ b/public/app/core/utils/kbn.ts @@ -475,6 +475,7 @@ kbn.valueFormats.wpm = kbn.formatBuilders.simpleCountUnit('wpm'); // Energy kbn.valueFormats.watt = kbn.formatBuilders.decimalSIPrefix('W'); kbn.valueFormats.kwatt = kbn.formatBuilders.decimalSIPrefix('W', 1); +kbn.valueFormats.kwattm = kbn.formatBuilders.decimalSIPrefix('W/Min', 1); kbn.valueFormats.voltamp = kbn.formatBuilders.decimalSIPrefix('VA'); kbn.valueFormats.kvoltamp = kbn.formatBuilders.decimalSIPrefix('VA', 1); kbn.valueFormats.voltampreact = kbn.formatBuilders.decimalSIPrefix('var'); @@ -488,6 +489,7 @@ kbn.valueFormats.kamp = kbn.formatBuilders.decimalSIPrefix('A', 1); kbn.valueFormats.volt = kbn.formatBuilders.decimalSIPrefix('V'); kbn.valueFormats.kvolt = kbn.formatBuilders.decimalSIPrefix('V', 1); kbn.valueFormats.dBm = kbn.formatBuilders.decimalSIPrefix('dBm'); +kbn.valueFormats.ohm = kbn.formatBuilders.decimalSIPrefix('Ω'); // Temperature kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C'); @@ -514,6 +516,12 @@ 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'); +kbn.valueFormats.lengthft = kbn.formatBuilders.fixedUnit('ft'); + +// Area +kbn.valueFormats.areaM2 = kbn.formatBuilders.fixedUnit('m²'); +kbn.valueFormats.areaF2 = kbn.formatBuilders.fixedUnit('ft²'); +kbn.valueFormats.areaMI2 = kbn.formatBuilders.fixedUnit('mi²'); // Mass kbn.valueFormats.massmg = kbn.formatBuilders.decimalSIPrefix('g', -1); @@ -527,6 +535,11 @@ kbn.valueFormats.velocitykmh = kbn.formatBuilders.fixedUnit('km/h'); kbn.valueFormats.velocitymph = kbn.formatBuilders.fixedUnit('mph'); kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn'); +// Acceleration +kbn.valueFormats.accMS2 = kbn.formatBuilders.fixedUnit('m/sec²'); +kbn.valueFormats.accFS2 = kbn.formatBuilders.fixedUnit('f/sec²'); +kbn.valueFormats.accG = kbn.formatBuilders.fixedUnit('g'); + // Volume kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L'); kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1); @@ -540,6 +553,11 @@ kbn.valueFormats.flowcms = kbn.formatBuilders.fixedUnit('cms'); kbn.valueFormats.flowcfs = kbn.formatBuilders.fixedUnit('cfs'); kbn.valueFormats.flowcfm = kbn.formatBuilders.fixedUnit('cfm'); +// Angle +kbn.valueFormats.degree = kbn.formatBuilders.fixedUnit('°'); +kbn.valueFormats.radian = kbn.formatBuilders.fixedUnit('rad'); +kbn.valueFormats.grad = kbn.formatBuilders.fixedUnit('grad'); + // Time kbn.valueFormats.hertz = kbn.formatBuilders.decimalSIPrefix('Hz'); @@ -877,6 +895,14 @@ kbn.getUnitFormats = function() { { text: 'mile (mi)', value: 'lengthmi' }, ], }, + { + text: 'area', + submenu: [ + {text: 'Square Meters (m²)', value: 'areaM2' }, + {text: 'Square Feet (ft²)', value: 'areaF2' }, + {text: 'Square Miles (mi²)', value: 'areaMI2'}, + ] + }, { text: 'mass', submenu: [ @@ -916,6 +942,7 @@ kbn.getUnitFormats = function() { { text: 'kilovolt-ampere reactive (kvar)', value: 'kvoltampreact' }, { text: 'watt-hour (Wh)', value: 'watth' }, { text: 'kilowatt-hour (kWh)', value: 'kwatth' }, + { text: 'kilowatt-min (kWm)', value: 'kwattm' }, { text: 'joule (J)', value: 'joule' }, { text: 'electron volt (eV)', value: 'ev' }, { text: 'Ampere (A)', value: 'amp' }, @@ -923,6 +950,7 @@ kbn.getUnitFormats = function() { { text: 'Volt (V)', value: 'volt' }, { text: 'Kilovolt (kV)', value: 'kvolt' }, { text: 'Decibel-milliwatt (dBm)', value: 'dBm' }, + { text: 'Ohm (Ω)', value: 'ohm' } ], }, { @@ -962,6 +990,22 @@ kbn.getUnitFormats = function() { { text: 'Cubic feet/min (cfm)', value: 'flowcfm' }, ], }, + { + text: 'angle', + submenu: [ + { text: 'Degrees (°)', value: 'degree' }, + { text: 'Radians', value: 'radian' }, + { text: 'Gradian', value: 'grad' } + ] + }, + { + text: 'acceleration', + submenu: [ + { text: 'Meters/sec²', value: 'accMS2' }, + { text: 'Feet/sec²', value: 'accFS2' }, + { text: 'G unit', value: 'accG' } + ] + } ]; }; From ae367db3771e400a971d5416f67c4c3857c837b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 31 Oct 2017 16:07:45 +0100 Subject: [PATCH 39/56] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 74a3a80b788..4273d8df6a9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -8,7 +8,7 @@ But it will give you an idea of our current vision and plan. - Release Grafana v5 - User groups - Dashboard folders - - Dashboard permissions (on folders as well), permissions on groups or users + - Dashboard & folder permissions (assigned to users or groups) - New Dashboard layout engine - New sidemenu & nav UX - Elasticsearch alerting From f5d2ce2a72ba6e83988f999a720696476ecac4cf Mon Sep 17 00:00:00 2001 From: cglewis Date: Tue, 31 Oct 2017 10:21:20 -0700 Subject: [PATCH 40/56] MAINTAINER is deprecated, now using LABEL --- docker/blocks/graphite1/Dockerfile | 2 +- docker/blocks/openldap/Dockerfile | 2 +- docker/blocks/smtp/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/blocks/graphite1/Dockerfile b/docker/blocks/graphite1/Dockerfile index a3ab7c4f4af..be4f0573cad 100644 --- a/docker/blocks/graphite1/Dockerfile +++ b/docker/blocks/graphite1/Dockerfile @@ -1,5 +1,5 @@ FROM phusion/baseimage:0.9.22 -MAINTAINER Denys Zhdanov +LABEL maintainer="Denys Zhdanov " RUN apt-get -y update \ && apt-get -y upgrade \ diff --git a/docker/blocks/openldap/Dockerfile b/docker/blocks/openldap/Dockerfile index d16987cb3ab..d073e274356 100644 --- a/docker/blocks/openldap/Dockerfile +++ b/docker/blocks/openldap/Dockerfile @@ -1,6 +1,6 @@ FROM debian:jessie -MAINTAINER Christian Luginbühl +LABEL maintainer="Christian Luginbühl " ENV OPENLDAP_VERSION 2.4.40 diff --git a/docker/blocks/smtp/Dockerfile b/docker/blocks/smtp/Dockerfile index c1a3adba7c8..9326e077ed9 100644 --- a/docker/blocks/smtp/Dockerfile +++ b/docker/blocks/smtp/Dockerfile @@ -1,5 +1,5 @@ FROM centos:centos7 -MAINTAINER Przemyslaw Ozgo +LABEL maintainer="Przemyslaw Ozgo " RUN \ yum update -y && \ From 624b75b58c86fcc5a7066324d908a9e6202399c2 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 31 Oct 2017 18:24:44 +0100 Subject: [PATCH 41/56] docs: update testdata enable explanantion --- docs/sources/features/datasources/testdata.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/features/datasources/testdata.md b/docs/sources/features/datasources/testdata.md index 491e5b60fbb..d99f9cabe08 100644 --- a/docs/sources/features/datasources/testdata.md +++ b/docs/sources/features/datasources/testdata.md @@ -17,7 +17,7 @@ This make is much easier to verify functionally since the data can be shared ver ## Enable -`Grafana TestData` is not enabled by default. To enable it you have to go to `/plugins/testdata/edit` and click the enable button to enable. +`Grafana TestData` is not enabled by default. To enable it, first navigate to the Plugins section, found in your Grafana main menu. Click the Apps tabs in the Plugins section and select the Grafana TestData App. (Or navigate to http://your_grafana_instance/plugins/testdata/edit to go directly there). Finally click the enable button to enable. ## Create mock data. From c8f7361e3f54c7c8294513815dc6ee74568e5034 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 1 Nov 2017 07:51:40 +0100 Subject: [PATCH 42/56] converted ng_model_on_blur.js to ts, deletedkeyboard_manager.js (#9676) --- ...g_model_on_blur.js => ng_model_on_blur.ts} | 34 +- public/app/core/services/all.js | 1 - public/app/core/services/keyboard_manager.js | 291 ------------------ 3 files changed, 20 insertions(+), 306 deletions(-) rename public/app/core/directives/{ng_model_on_blur.js => ng_model_on_blur.ts} (71%) delete mode 100644 public/app/core/services/keyboard_manager.js diff --git a/public/app/core/directives/ng_model_on_blur.js b/public/app/core/directives/ng_model_on_blur.ts similarity index 71% rename from public/app/core/directives/ng_model_on_blur.js rename to public/app/core/directives/ng_model_on_blur.ts index b3c73e54dba..e80721b26b3 100644 --- a/public/app/core/directives/ng_model_on_blur.js +++ b/public/app/core/directives/ng_model_on_blur.ts @@ -1,11 +1,8 @@ -define([ - '../core_module', - 'app/core/utils/rangeutil', -], -function (coreModule, rangeUtil) { - 'use strict'; +import coreModule from '../core_module'; +import rangeUtil from 'app/core/utils/rangeutil'; - coreModule.default.directive('ngModelOnblur', function() { +export class NgModelOnBlur { + constructor() { return { restrict: 'A', priority: 1, @@ -23,22 +20,27 @@ function (coreModule, rangeUtil) { }); } }; - }); + } +} - coreModule.default.directive('emptyToNull', function () { + +export class EmptyToNull { + constructor() { return { restrict: 'A', require: 'ngModel', link: function (scope, elm, attrs, ctrl) { ctrl.$parsers.push(function (viewValue) { - if(viewValue === "") { return null; } + if (viewValue === "") { return null; } return viewValue; }); } }; - }); + } +} - coreModule.default.directive('validTimeSpan', function() { +export class ValidTimeSpan { + constructor() { return { require: 'ngModel', link: function(scope, elm, attrs, ctrl) { @@ -54,5 +56,9 @@ function (coreModule, rangeUtil) { }; } }; - }); -}); + } +} + +coreModule.directive('ngModelOnblur', NgModelOnBlur); +coreModule.directive('emptyToNull', EmptyToNull); +coreModule.directive('validTimeSpan', ValidTimeSpan); diff --git a/public/app/core/services/all.js b/public/app/core/services/all.js index 1fea3e5a248..a308febb219 100644 --- a/public/app/core/services/all.js +++ b/public/app/core/services/all.js @@ -3,7 +3,6 @@ define([ './util_srv', './context_srv', './timer', - './keyboard_manager', './analytics', './popover_srv', './segment_srv', diff --git a/public/app/core/services/keyboard_manager.js b/public/app/core/services/keyboard_manager.js deleted file mode 100644 index b5eefda81a6..00000000000 --- a/public/app/core/services/keyboard_manager.js +++ /dev/null @@ -1,291 +0,0 @@ -define([ - 'angular', - 'lodash', - '../core_module', -], -function (angular, _, coreModule) { - 'use strict'; - - // This service was based on OpenJS library available in BSD License - // http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php - coreModule.default.factory('keyboardManager', ['$window', '$timeout', function ($window, $timeout) { - var keyboardManagerService = {}; - - var defaultOpt = { - 'type': 'keydown', - 'propagate': false, - 'inputDisabled': false, - 'target': $window.document, - 'keyCode': false - }; - // Store all keyboard combination shortcuts - keyboardManagerService.keyboardEvent = {}; - // Add a new keyboard combination shortcut - keyboardManagerService.bind = function (label, callback, opt) { - var fct, elt, code, k; - // Initialize opt object - opt = angular.extend({}, defaultOpt, opt); - label = label.toLowerCase(); - elt = opt.target; - - if (typeof opt.target === 'string') { - elt = document.getElementById(opt.target); - } - - fct = function (e) { - e = e || $window.event; - - // Disable event handler when focus input and textarea - if (opt['inputDisabled']) { - var elt; - if (e.target) { - elt = e.target; - } - else if (e.srcElement) { - elt = e.srcElement; - } - - if (elt.nodeType === 3) { - elt = elt.parentNode; - } - - if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA') { - return; - } - } - - // Find out which key is pressed - if (e.keyCode) { - code = e.keyCode; - } - else if (e.which) { - code = e.which; - } - - var character = String.fromCharCode(code).toLowerCase(); - - if (code === 188) { - character = ","; // If the user presses , when the type is onkeydown - } - if (code === 190) { - character = "."; // If the user presses , when the type is onkeydown - } - - var keys = label.split("+"); - // Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked - var kp = 0; - // Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken - var shift_nums = { - "`": "~", - "1": "!", - "2": "@", - "3": "#", - "4": "$", - "5": "%", - "6": "^", - "7": "&", - "8": "*", - "9": "(", - "0": ")", - "-": "_", - "=": "+", - ";": ":", - "'": "\"", - ",": "<", - ".": ">", - "/": "?", - "»": "?", - "«": "?", - "¿": "?", - "\\": "|" - }; - // Special Keys - and their codes - var special_keys = { - 'esc': 27, - 'escape': 27, - 'tab': 9, - 'space': 32, - 'return': 13, - 'enter': 13, - 'backspace': 8, - - 'scrolllock': 145, - 'scroll_lock': 145, - 'scroll': 145, - 'capslock': 20, - 'caps_lock': 20, - 'caps': 20, - 'numlock': 144, - 'num_lock': 144, - 'num': 144, - - 'pause': 19, - 'break': 19, - - 'insert': 45, - 'home': 36, - 'delete': 46, - 'end': 35, - - 'pageup': 33, - 'page_up': 33, - 'pu': 33, - - 'pagedown': 34, - 'page_down': 34, - 'pd': 34, - - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - - 'f1': 112, - 'f2': 113, - 'f3': 114, - 'f4': 115, - 'f5': 116, - 'f6': 117, - 'f7': 118, - 'f8': 119, - 'f9': 120, - 'f10': 121, - 'f11': 122, - 'f12': 123 - }; - // Some modifiers key - var modifiers = { - shift: { - wanted: false, - pressed: e.shiftKey ? true : false - }, - ctrl : { - wanted: false, - pressed: e.ctrlKey ? true : false - }, - alt : { - wanted: false, - pressed: e.altKey ? true : false - }, - meta : { //Meta is Mac specific - wanted: false, - pressed: e.metaKey ? true : false - } - }; - // Foreach keys in label (split on +) - for (var i = 0, l = keys.length; k = keys[i], i < l; i++) { - switch (k) { - case 'ctrl': - case 'control': - kp++; - modifiers.ctrl.wanted = true; - break; - case 'shift': - case 'alt': - case 'meta': - kp++; - modifiers[k].wanted = true; - break; - } - - if (k.length > 1) { // If it is a special key - if (special_keys[k] === code) { - kp++; - } - } else if (opt['keyCode']) { // If a specific key is set into the config - if (opt['keyCode'] === code) { - kp++; - } - } else { // The special keys did not match - if (character === k) { - kp++; - } - else { - if (shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase - character = shift_nums[character]; - if (character === k) { - kp++; - } - } - } - } - } - - if (kp === keys.length && - modifiers.ctrl.pressed === modifiers.ctrl.wanted && - modifiers.shift.pressed === modifiers.shift.wanted && - modifiers.alt.pressed === modifiers.alt.wanted && - modifiers.meta.pressed === modifiers.meta.wanted) { - $timeout(function() { - callback(e); - }, 1); - - if (!opt['propagate']) { // Stop the event - // e.cancelBubble is supported by IE - this will kill the bubbling process. - e.cancelBubble = true; - e.returnValue = false; - - // e.stopPropagation works in Firefox. - if (e.stopPropagation) { - e.stopPropagation(); - e.preventDefault(); - } - return false; - } - } - - }; - // Store shortcut - keyboardManagerService.keyboardEvent[label] = { - 'callback': fct, - 'target': elt, - 'event': opt['type'] - }; - //Attach the function with the event - if (elt.addEventListener) { - elt.addEventListener(opt['type'], fct, false); - } - else if (elt.attachEvent) { - elt.attachEvent('on' + opt['type'], fct); - } - else { - elt['on' + opt['type']] = fct; - } - }; - - keyboardManagerService.unbindAll = function() { - _.each(keyboardManagerService.keyboardEvent, function(value, key) { - keyboardManagerService.unbind(key); - }); - }; - - // Remove the shortcut - just specify the shortcut and I will remove the binding - keyboardManagerService.unbind = function (label) { - label = label.toLowerCase(); - - var binding = keyboardManagerService.keyboardEvent[label]; - delete(keyboardManagerService.keyboardEvent[label]); - - if (!binding) { - return; - } - - var type = binding['event'], - elt = binding['target'], - callback = binding['callback']; - - if (elt.detachEvent) { - elt.detachEvent('on' + type, callback); - } - else if (elt.removeEventListener) { - elt.removeEventListener(type, callback, false); - } - else { - elt['on' + type] = false; - } - }; - // - return keyboardManagerService; - }]); - -}); From fec37f22b839584c08b47442f5f1fa11582cf453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 1 Nov 2017 08:08:16 +0100 Subject: [PATCH 43/56] fix: fixed compiler error from #9676 --- public/app/core/directives/ng_model_on_blur.ts | 2 +- public/app/features/panel/metrics_panel_ctrl.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/public/app/core/directives/ng_model_on_blur.ts b/public/app/core/directives/ng_model_on_blur.ts index e80721b26b3..383d04e3961 100644 --- a/public/app/core/directives/ng_model_on_blur.ts +++ b/public/app/core/directives/ng_model_on_blur.ts @@ -1,5 +1,5 @@ import coreModule from '../core_module'; -import rangeUtil from 'app/core/utils/rangeutil'; +import * as rangeUtil from 'app/core/utils/rangeutil'; export class NgModelOnBlur { constructor() { diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index 839dbba72e8..c139f5c8313 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -226,7 +226,6 @@ class MetricsPanelCtrl extends PanelCtrl { interval: this.interval, intervalMs: this.intervalMs, targets: this.panel.targets, - format: this.panel.renderer === 'png' ? 'png' : 'json', maxDataPoints: this.resolution, scopedVars: scopedVars, cacheTimeout: this.panel.cacheTimeout From c3bd07f9b4cae013ff108bc4cc0a21415eb29620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 1 Nov 2017 09:59:24 +0100 Subject: [PATCH 44/56] testdata: added manual entry mode to test data --- pkg/tsdb/testdata/scenarios.go | 40 ++++++++++++++++ .../dashboard/timepicker/input_date.ts | 19 ++++---- .../app/testdata/datasource/datasource.ts | 6 +-- .../plugins/app/testdata/datasource/module.ts | 2 - .../app/testdata/datasource/query_ctrl.ts | 48 ++++++++++++++++--- .../app/testdata/partials/query.editor.html | 22 ++++++++- 6 files changed, 112 insertions(+), 25 deletions(-) diff --git a/pkg/tsdb/testdata/scenarios.go b/pkg/tsdb/testdata/scenarios.go index 0a7f1467933..e907fa8aae0 100644 --- a/pkg/tsdb/testdata/scenarios.go +++ b/pkg/tsdb/testdata/scenarios.go @@ -1,6 +1,7 @@ package testdata import ( + "encoding/json" "math/rand" "strconv" "strings" @@ -142,6 +143,45 @@ func init() { }, }) + registerScenario(&Scenario{ + Id: "manual_entry", + Name: "Manual Entry", + Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult { + queryRes := tsdb.NewQueryResult() + + points := query.Model.Get("points").MustArray() + + series := newSeriesForQuery(query) + startTime := context.TimeRange.GetFromAsMsEpoch() + endTime := context.TimeRange.GetToAsMsEpoch() + + for _, val := range points { + pointValues := val.([]interface{}) + + var value null.Float + var time int64 + + if valueFloat, err := strconv.ParseFloat(string(pointValues[0].(json.Number)), 64); err == nil { + value = null.FloatFrom(valueFloat) + } + + if timeInt, err := strconv.ParseInt(string(pointValues[1].(json.Number)), 10, 64); err != nil { + continue + } else { + time = timeInt + } + + if time >= startTime && time <= endTime { + series.Points = append(series.Points, tsdb.NewTimePoint(value, float64(time))) + } + } + + queryRes.Series = append(queryRes.Series, series) + + return queryRes + }, + }) + registerScenario(&Scenario{ Id: "csv_metric_values", Name: "CSV Metric Values", diff --git a/public/app/features/dashboard/timepicker/input_date.ts b/public/app/features/dashboard/timepicker/input_date.ts index b6988a3ff16..ca3f5fa7ae9 100644 --- a/public/app/features/dashboard/timepicker/input_date.ts +++ b/public/app/features/dashboard/timepicker/input_date.ts @@ -1,5 +1,3 @@ -/// - import moment from 'moment'; import * as dateMath from 'app/core/utils/datemath'; @@ -7,16 +5,16 @@ export function inputDateDirective() { return { restrict: 'A', require: 'ngModel', - link: function ($scope, $elem, attrs, ngModel) { + link: function($scope, $elem, attrs, ngModel) { var format = 'YYYY-MM-DD HH:mm:ss'; - var fromUser = function (text) { + var fromUser = function(text) { if (text.indexOf('now') !== -1) { if (!dateMath.isValid(text)) { - ngModel.$setValidity("error", false); + ngModel.$setValidity('error', false); return undefined; } - ngModel.$setValidity("error", true); + ngModel.$setValidity('error', true); return text; } @@ -28,15 +26,15 @@ export function inputDateDirective() { } if (!parsed.isValid()) { - ngModel.$setValidity("error", false); + ngModel.$setValidity('error', false); return undefined; } - ngModel.$setValidity("error", true); + ngModel.$setValidity('error', true); return parsed; }; - var toUser = function (currentValue) { + var toUser = function(currentValue) { if (moment.isMoment(currentValue)) { return currentValue.format(format); } else { @@ -46,7 +44,6 @@ export function inputDateDirective() { ngModel.$parsers.push(fromUser); ngModel.$formatters.push(toUser); - } + }, }; } - diff --git a/public/app/plugins/app/testdata/datasource/datasource.ts b/public/app/plugins/app/testdata/datasource/datasource.ts index 90ae9e3aa47..2df33ea4ac6 100644 --- a/public/app/plugins/app/testdata/datasource/datasource.ts +++ b/public/app/plugins/app/testdata/datasource/datasource.ts @@ -1,7 +1,4 @@ -/// - import _ from 'lodash'; -import angular from 'angular'; class TestDataDatasource { id: any; @@ -21,7 +18,8 @@ class TestDataDatasource { intervalMs: options.intervalMs, maxDataPoints: options.maxDataPoints, stringInput: item.stringInput, - jsonInput: angular.fromJson(item.jsonInput), + points: item.points, + alias: item.alias, datasourceId: this.id, }; }); diff --git a/public/app/plugins/app/testdata/datasource/module.ts b/public/app/plugins/app/testdata/datasource/module.ts index 309b7443836..9d7eaf3cc83 100644 --- a/public/app/plugins/app/testdata/datasource/module.ts +++ b/public/app/plugins/app/testdata/datasource/module.ts @@ -1,5 +1,3 @@ -/// - import {TestDataDatasource} from './datasource'; import {TestDataQueryCtrl} from './query_ctrl'; diff --git a/public/app/plugins/app/testdata/datasource/query_ctrl.ts b/public/app/plugins/app/testdata/datasource/query_ctrl.ts index e783584eb5d..dd5f59c0a5a 100644 --- a/public/app/plugins/app/testdata/datasource/query_ctrl.ts +++ b/public/app/plugins/app/testdata/datasource/query_ctrl.ts @@ -1,14 +1,16 @@ -/// - import _ from 'lodash'; -import {QueryCtrl} from 'app/plugins/sdk'; +import { QueryCtrl } from 'app/plugins/sdk'; +import moment from 'moment'; export class TestDataQueryCtrl extends QueryCtrl { static templateUrl = 'partials/query.editor.html'; scenarioList: any; scenario: any; + newPointValue: number; + newPointTime: any; + selectedPoint: any; /** @ngInject **/ constructor($scope, $injector, private backendSrv) { @@ -16,19 +18,53 @@ export class TestDataQueryCtrl extends QueryCtrl { this.target.scenarioId = this.target.scenarioId || 'random_walk'; this.scenarioList = []; + this.newPointTime = moment(); + this.selectedPoint = { text: 'Select point', value: null }; + } + + getPoints() { + return _.map(this.target.points, (point, index) => { + return { + text: moment(point[1]).format('MMMM Do YYYY, H:mm:ss') + ' : ' + point[0], + value: index, + }; + }); + } + + pointSelected(option) { + this.selectedPoint = option; + } + + deletePoint() { + this.target.points.splice(this.selectedPoint.value, 1); + this.selectedPoint = { text: 'Select point', value: null }; + this.refresh(); + } + + addPoint() { + this.target.points = this.target.points || []; + this.target.points.push([this.newPointValue, this.newPointTime.valueOf()]); + this.target.points = _.sortBy(this.target.points, p => p[1]); + this.refresh(); } $onInit() { return this.backendSrv.get('/api/tsdb/testdata/scenarios').then(res => { this.scenarioList = res; - this.scenario = _.find(this.scenarioList, {id: this.target.scenarioId}); + this.scenario = _.find(this.scenarioList, { id: this.target.scenarioId }); }); } scenarioChanged() { - this.scenario = _.find(this.scenarioList, {id: this.target.scenarioId}); + this.scenario = _.find(this.scenarioList, { id: this.target.scenarioId }); this.target.stringInput = this.scenario.stringInput; + + if (this.target.scenarioId === 'manual_entry') { + this.target.points = this.target.points || []; + } else { + delete this.target.points; + } + this.refresh(); } } - diff --git a/public/app/plugins/app/testdata/partials/query.editor.html b/public/app/plugins/app/testdata/partials/query.editor.html index a39582d5397..247918bce1f 100644 --- a/public/app/plugins/app/testdata/partials/query.editor.html +++ b/public/app/plugins/app/testdata/partials/query.editor.html @@ -1,8 +1,8 @@
    - -
    + +
    @@ -18,5 +18,23 @@
    +
    +
    + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    From e19b4a92919c4d0cfbe0739fde22b1c394d47fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 1 Nov 2017 10:45:20 +0100 Subject: [PATCH 45/56] plugins: fix for loading external plugins behind auth proxy, fixes #9509 --- public/app/features/plugins/plugin_loader.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/app/features/plugins/plugin_loader.ts b/public/app/features/plugins/plugin_loader.ts index c450f2e474a..c1dd3246fa1 100644 --- a/public/app/features/plugins/plugin_loader.ts +++ b/public/app/features/plugins/plugin_loader.ts @@ -40,7 +40,10 @@ System.config({ css: 'vendor/plugin-css/css.js' }, meta: { - '*': {esModule: true} + '*': { + esModule: true, + authorization: true, + } } }); From ebcb8be19a3aab98f9c1e49c646a9309f02d7d51 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Wed, 1 Nov 2017 18:47:21 +0900 Subject: [PATCH 46/56] add period alias --- pkg/tsdb/cloudwatch/cloudwatch.go | 1 + .../plugins/datasource/cloudwatch/partials/query.parameter.html | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 266b71ec14e..1a2cda80d08 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -287,6 +287,7 @@ func formatAlias(query *CloudWatchQuery, stat string, dimensions map[string]stri data["namespace"] = query.Namespace data["metric"] = query.MetricName data["stat"] = stat + data["period"] = strconv.Itoa(query.Period) for k, v := range dimensions { data[k] = v } diff --git a/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html b/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html index 67351358696..fd14fb7d077 100644 --- a/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html +++ b/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html @@ -49,6 +49,7 @@
  3. {{stat}}
  4. {{namespace}}
  5. {{region}}
  6. +
  7. {{period}}
  8. {{YOUR_DIMENSION_NAME}}
  9. From 4a63d696ff59f23cd67f64f5a5e8698eaff8ff2c Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Wed, 1 Nov 2017 18:48:07 +0900 Subject: [PATCH 47/56] fix default alias --- pkg/tsdb/cloudwatch/cloudwatch.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 266b71ec14e..6f56a26f024 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -267,7 +267,10 @@ func parseQuery(model *simplejson.Json) (*CloudWatchQuery, error) { period = int(d.Seconds()) } - alias := model.Get("alias").MustString("{{metric}}_{{stat}}") + alias := model.Get("alias").MustString() + if alias == "" { + alias = "{{metric}}_{{stat}}" + } return &CloudWatchQuery{ Region: region, From f46b7560e8228d08bd44d741c00f336b6239010b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 1 Nov 2017 10:50:24 +0100 Subject: [PATCH 48/56] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f9c70c540d..f0d768d05cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * **Singlestat**: Lost thresholds when using save dashboard as [#9681](https://github.com/grafana/grafana/issues/9681) * **Graph**: Fix for series override color picker [#9715](https://github.com/grafana/grafana/issues/9715) * **Go**: build using golang 1.9.2 [#9713](https://github.com/grafana/grafana/issues/9713) +* **Plugins**: Fixed problem with loading plugin js files behind auth proxy [#9509](https://github.com/grafana/grafana/issues/9509) # 4.6.0 (2017-10-26) From d854abccad1201d7adc1bb03ce19d6322bf96b30 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 1 Nov 2017 11:00:47 +0100 Subject: [PATCH 49/56] changelog: adds note about closing #9707 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0d768d05cf..bea1deee41c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ * **Graph**: Fix for series override color picker [#9715](https://github.com/grafana/grafana/issues/9715) * **Go**: build using golang 1.9.2 [#9713](https://github.com/grafana/grafana/issues/9713) * **Plugins**: Fixed problem with loading plugin js files behind auth proxy [#9509](https://github.com/grafana/grafana/issues/9509) +* **Graphite**: Annotation tooltip should render empty string when undefined [#9707](https://github.com/grafana/grafana/issues/9707) # 4.6.0 (2017-10-26) From 575f746baa110c8ff5d41cfae033745f46a14d64 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 1 Nov 2017 11:03:10 +0100 Subject: [PATCH 50/56] changelog: set release date for 4.6.1 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bea1deee41c..73da7a39ef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) * **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [#9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) -# 4.6.1 (unreleased) +# 4.6.1 (2017-11-01) * **Singlestat**: Lost thresholds when using save dashboard as [#9681](https://github.com/grafana/grafana/issues/9681) * **Graph**: Fix for series override color picker [#9715](https://github.com/grafana/grafana/issues/9715) From 894951c7d4ea43c0d12baec026d93d71f7f99d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 1 Nov 2017 11:10:43 +0100 Subject: [PATCH 51/56] fix: panel view now wraps, no scrolling required, fixes #9746 --- .../app/features/dashboard/row/add_panel.html | 34 ++++++++----------- public/sass/components/_row.scss | 12 ++----- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/public/app/features/dashboard/row/add_panel.html b/public/app/features/dashboard/row/add_panel.html index 5a4ecc118cd..f68b3549be6 100644 --- a/public/app/features/dashboard/row/add_panel.html +++ b/public/app/features/dashboard/row/add_panel.html @@ -3,25 +3,21 @@ -
    -
    - -
    -
    +
    + +
    -
    -
    -
    - -
    {{panel.name}}
    -
    -
    -
    +
    +
    + +
    {{panel.name}}
    +
    +
diff --git a/public/sass/components/_row.scss b/public/sass/components/_row.scss index 840db839607..0cdc3428f3e 100644 --- a/public/sass/components/_row.scss +++ b/public/sass/components/_row.scss @@ -61,6 +61,7 @@ margin: 0 $panel-margin $panel-margin*2 $panel-margin; padding: $panel-margin*2; display: flex; + flex-direction: row; } .dash-row-dropview-close { @@ -71,19 +72,10 @@ height: 20px; } -.add-panel-panels-scroll { - width: 100%; - overflow: auto; - -ms-overflow-style: none; - - &::-webkit-scrollbar { - display: none - } -} - .add-panel-panels { display: flex; flex-direction: row; + flex-wrap: wrap; } .add-panel-item { From d5d42c046d029edf81ec96672874a4b60727229b Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 1 Nov 2017 12:54:35 +0100 Subject: [PATCH 52/56] packages: update published package version --- packaging/publish/publish_both.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/publish/publish_both.sh b/packaging/publish/publish_both.sh index 0a76851f6fa..af349567bbc 100755 --- a/packaging/publish/publish_both.sh +++ b/packaging/publish/publish_both.sh @@ -1,5 +1,5 @@ #! /usr/bin/env bash -version=4.5.2 +version=4.6.1 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${version}_amd64.deb From 4dae217afc0b7ce26decd1cb0aaea38129d50e1e Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 1 Nov 2017 13:31:10 +0100 Subject: [PATCH 53/56] docs: update latest release to 4.6.1 --- docs/sources/installation/debian.md | 6 +++--- docs/sources/installation/rpm.md | 10 +++++----- docs/sources/installation/windows.md | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 7ecb6d14b0c..8f29a9bc7d1 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -15,7 +15,7 @@ weight = 1 Description | Download ------------ | ------------- -Stable for Debian-based Linux | [grafana_4.6.0_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.0_amd64.deb) +Stable for Debian-based Linux | [grafana_4.6.1_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.1_amd64.deb) @@ -26,9 +26,9 @@ installation. ```bash -wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.0_amd64.deb +wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.1_amd64.deb sudo apt-get install -y adduser libfontconfig -sudo dpkg -i grafana_4.6.0_amd64.deb +sudo dpkg -i grafana_4.6.1_amd64.deb ``` @@ -27,7 +27,7 @@ installation. You can install Grafana using Yum directly. ```bash -$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.0-1.x86_64.rpm +$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.1-1.x86_64.rpm ``` Or install manually using `rpm`. @@ -35,15 +35,15 @@ Or install manually using `rpm`. #### On CentOS / Fedora / Redhat: ```bash -$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.0-1.x86_64.rpm +$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.1-1.x86_64.rpm $ sudo yum install initscripts fontconfig -$ sudo rpm -Uvh grafana-4.6.0-1.x86_64.rpm +$ sudo rpm -Uvh grafana-4.6.1-1.x86_64.rpm ``` #### On OpenSuse: ```bash -$ sudo rpm -i --nodeps grafana-4.6.0-1.x86_64.rpm +$ sudo rpm -i --nodeps grafana-4.6.1-1.x86_64.rpm ``` ## Install via YUM Repository diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 181d26d694c..1b6f296d9f4 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -13,7 +13,7 @@ weight = 3 Description | Download ------------ | ------------- -Latest stable package for Windows | [grafana.4.6.0.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.0.windows-x64.zip) +Latest stable package for Windows | [grafana.4.6.1.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.1.windows-x64.zip) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. From 8b10fe1abc9455dbe6d4b6c344c3e6f660f48602 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 31 Oct 2017 15:29:43 +0100 Subject: [PATCH 54/56] ignore docker-compose.yaml --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d50081192c9..fbd92fe0b51 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ public/css/*.min.css conf/custom.ini fig.yml docker-compose.yml +docker-compose.yaml profile.cov /grafana .notouch From 6292d7c204a2614975c7863eb87ae1ce2e35c9c6 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 1 Nov 2017 19:28:28 +0100 Subject: [PATCH 55/56] reduce docker-compose header version --- docker/compose_header.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/compose_header.yml b/docker/compose_header.yml index 117e40b314e..e7bf4f38b02 100644 --- a/docker/compose_header.yml +++ b/docker/compose_header.yml @@ -1,2 +1,2 @@ -version: "3" +version: "2" services: From 538a8cff1ef3ccf2dcf77d0bce8538aaa30b58f6 Mon Sep 17 00:00:00 2001 From: Ratna Deep Simhadri Date: Wed, 1 Nov 2017 23:04:51 -0700 Subject: [PATCH 56/56] chore(docs): update the search Query Example - Updated the last Search Dashboards Example , so that the Example Request and Response seem related --- docs/sources/http_api/dashboard.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/http_api/dashboard.md b/docs/sources/http_api/dashboard.md index 300e5613db4..0538754bd96 100644 --- a/docs/sources/http_api/dashboard.md +++ b/docs/sources/http_api/dashboard.md @@ -258,7 +258,7 @@ Query parameters: **Example Request**: ```http -GET /api/search?query=MyDashboard&starred=true&tag=prod HTTP/1.1 +GET /api/search?query=Production%20Overview&starred=true&tag=prod HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk @@ -276,8 +276,8 @@ Content-Type: application/json "title":"Production Overview", "uri":"db/production-overview", "type":"dash-db", - "tags":[], - "isStarred":false + "tags":[prod], + "isStarred":true } ] -``` \ No newline at end of file +```