From 62d11c147b5827d6b44352c4f9acd891526a7ee2 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Wed, 19 Apr 2017 14:12:59 +0900 Subject: [PATCH 01/42] (cloudwatch) fix dimension value find query (#8159) --- .../app/plugins/datasource/cloudwatch/query_parameter_ctrl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js index f7db203826b..211c46bf855 100644 --- a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js +++ b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js @@ -104,7 +104,7 @@ function (angular, _) { query = $scope.datasource.getDimensionKeys($scope.target.namespace, $scope.target.region); } else if (segment.type === 'value') { var dimensionKey = $scope.dimSegments[$index-2].value; - query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, {}); + query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, target.dimensions); } return query.then($scope.transformToSegments(true)).then(function(results) { From 7078d5d52451c0b1f48b8f2252b6c1ef6a73bd12 Mon Sep 17 00:00:00 2001 From: Daniel Schmitz Date: Wed, 19 Apr 2017 15:53:23 +0800 Subject: [PATCH 02/42] Added metrics/matches to telegram notifications; Added some HTML to beautify --- pkg/services/alerting/notifiers/telegram.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go index f70d299bc6c..d2ad03d2bd0 100644 --- a/pkg/services/alerting/notifiers/telegram.go +++ b/pkg/services/alerting/notifiers/telegram.go @@ -87,7 +87,7 @@ func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error { bodyJSON.Set("chat_id", this.ChatID) bodyJSON.Set("parse_mode", "html") - message := fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message) + message := fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message) ruleUrl, err := evalContext.GetRuleUrl() if err == nil { @@ -96,6 +96,19 @@ func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error { if evalContext.ImagePublicUrl != "" { message = message + fmt.Sprintf("Image: %s\n", evalContext.ImagePublicUrl) } + + metrics := "" + fieldLimitCount := 4 + for index, evt := range evalContext.EvalMatches { + metrics += fmt.Sprintf("\n%s: %s", evt.Metric, evt.Value) + if index > fieldLimitCount { + break + } + } + if metrics != "" { + message = message + fmt.Sprintf("\nMetrics:%s", metrics); + } + bodyJSON.Set("text", message) url := fmt.Sprintf(telegeramApiUrl, this.BotToken, "sendMessage") From e164eba677b1edea133c70c6e43a606dfbeb931b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 19 Apr 2017 10:09:52 +0200 Subject: [PATCH 03/42] mysql: began work on backend macro engine --- .../sqlstore/migrations/migrations.go | 1 - pkg/services/sqlstore/sql_test_data.go | 4 +- pkg/tsdb/mysql/macros.go | 75 +++++++++++++++++++ pkg/tsdb/mysql/macros_test.go | 22 ++++++ pkg/tsdb/mysql/mysql.go | 39 ++++++---- .../datasource/mysql}/img/mysql_logo.svg | 0 6 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 pkg/tsdb/mysql/macros.go create mode 100644 pkg/tsdb/mysql/macros_test.go rename public/{ => app/plugins/datasource/mysql}/img/mysql_logo.svg (100%) diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index 163c6d762a8..bf334d57bb0 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -24,7 +24,6 @@ func AddMigrations(mg *Migrator) { addPreferencesMigrations(mg) addAlertMigrations(mg) addAnnotationMig(mg) - addStatsMigrations(mg) addTestDataMigrations(mg) } diff --git a/pkg/services/sqlstore/sql_test_data.go b/pkg/services/sqlstore/sql_test_data.go index a83ab76ecc0..ad8d36dfce5 100644 --- a/pkg/services/sqlstore/sql_test_data.go +++ b/pkg/services/sqlstore/sql_test_data.go @@ -14,7 +14,7 @@ func init() { func sqlRandomWalk(m1 string, m2 string, intWalker int64, floatWalker float64, sess *session) error { - timeWalker := time.Now().UTC().Add(time.Hour * -1) + timeWalker := time.Now().UTC().Add(time.Hour * -200) now := time.Now().UTC() step := time.Minute @@ -29,7 +29,7 @@ func sqlRandomWalk(m1 string, m2 string, intWalker int64, floatWalker float64, s timeWalker = timeWalker.Add(step) row.Id = 0 - row.ValueBigInt += rand.Int63n(100) - 100 + row.ValueBigInt += rand.Int63n(200) - 100 row.ValueDouble += rand.Float64() - 0.5 row.ValueFloat += rand.Float32() - 0.5 row.TimeEpoch = timeWalker.Unix() diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go new file mode 100644 index 00000000000..971b41c3b07 --- /dev/null +++ b/pkg/tsdb/mysql/macros.go @@ -0,0 +1,75 @@ +package mysql + +import ( + "fmt" + "regexp" + + "github.com/grafana/grafana/pkg/tsdb" +) + +//const rsString = `(?:"([^"]*)")`; +const rsIdentifier = `([_a-zA-Z0-9]+)` +const sExpr = `\$` + rsIdentifier + `\((.*)\)` + +type SqlMacroEngine interface { + Interpolate(sql string) (string, error) +} + +type MySqlMacroEngine struct { + TimeRange *tsdb.TimeRange +} + +func NewMysqlMacroEngine(timeRange *tsdb.TimeRange) SqlMacroEngine { + return &MySqlMacroEngine{ + TimeRange: timeRange, + } +} + +func (m *MySqlMacroEngine) Interpolate(sql string) (string, error) { + rExp, _ := regexp.Compile(sExpr) + var macroError error + + sql = ReplaceAllStringSubmatchFunc(rExp, sql, func(groups []string) string { + res, err := m.EvaluateMacro(groups[1], groups[2:len(groups)]) + if macroError != nil { + macroError = err + return "macro_error()" + } + return res + }) + + if macroError != nil { + return "", macroError + } + + return sql, nil +} + +func ReplaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string { + result := "" + lastIndex := 0 + + for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) { + groups := []string{} + for i := 0; i < len(v); i += 2 { + groups = append(groups, str[v[i]:v[i+1]]) + } + + result += str[lastIndex:v[0]] + repl(groups) + lastIndex = v[1] + } + + return result + str[lastIndex:] +} + +func (m *MySqlMacroEngine) EvaluateMacro(name string, args []string) (string, error) { + switch name { + case "__time": + if len(args) == 0 { + return "", fmt.Errorf("missing time column argument for macro %v", name) + } + return "UNIX_TIMESTAMP(" + args[0] + ") as time_sec", nil + default: + return "", fmt.Errorf("Unknown macro %v", name) + } +} diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go new file mode 100644 index 00000000000..1dcd5e1e978 --- /dev/null +++ b/pkg/tsdb/mysql/macros_test.go @@ -0,0 +1,22 @@ +package mysql + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestMacroEngine(t *testing.T) { + Convey("MacroEngine", t, func() { + + Convey("interpolate simple function", func() { + engine := &MySqlMacroEngine{} + + sql, err := engine.Interpolate("select $__time(time_column)") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "select UNIX_TIMESTAMP(time_column) as time_sec") + }) + + }) +} diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index be59079c65c..44dcc2648f2 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -99,40 +99,49 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co defer rows.Close() - result.QueryResults[query.RefId] = e.TransformToTimeSeries(query, rows) + res, err := e.TransformToTimeSeries(query, rows) + if err != nil { + result.Error = err + return result + } + + result.QueryResults[query.RefId] = &tsdb.QueryResult{RefId: query.RefId, Series: res} } return result } -func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows) *tsdb.QueryResult { - result := &tsdb.QueryResult{RefId: query.RefId} +func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows) (tsdb.TimeSeriesSlice, error) { pointsBySeries := make(map[string]*tsdb.TimeSeries) columnNames, err := rows.Columns() if err != nil { - result.Error = err - return result + return nil, err } rowData := NewStringStringScan(columnNames) - for rows.Next() { + rowLimit := 1000000 + rowCount := 0 + + for ; rows.Next(); rowCount += 1 { + if rowCount > rowLimit { + return nil, fmt.Errorf("MySQL query row limit exceeded, limit %d", rowLimit) + } + err := rowData.Update(rows.Rows) if err != nil { - e.log.Error("Mysql response parsing", "error", err) - result.Error = err - return result + e.log.Error("MySQL response parsing", "error", err) + return nil, fmt.Errorf("MySQL response parsing error %v", err) } if rowData.metric == "" { rowData.metric = "Unknown" } - e.log.Info("Rows", "metric", rowData.metric, "time", rowData.time, "value", rowData.value) + //e.log.Debug("Rows", "metric", rowData.metric, "time", rowData.time, "value", rowData.value) if !rowData.time.Valid { - result.Error = fmt.Errorf("Found row with no time value") - return result + return nil, fmt.Errorf("Found row with no time value") } if series, exist := pointsBySeries[rowData.metric]; exist { @@ -144,11 +153,13 @@ func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows) } } + seriesList := make(tsdb.TimeSeriesSlice, 0) for _, value := range pointsBySeries { - result.Series = append(result.Series, value) + seriesList = append(seriesList, value) } - return result + e.log.Debug("TransformToTimeSeries", "rowCount", rowCount, "timeSeriesCount", len(seriesList)) + return seriesList, nil } type stringStringScan struct { diff --git a/public/img/mysql_logo.svg b/public/app/plugins/datasource/mysql/img/mysql_logo.svg similarity index 100% rename from public/img/mysql_logo.svg rename to public/app/plugins/datasource/mysql/img/mysql_logo.svg From d123b951e9bb57e930fef43d468f8f81cbfe98b9 Mon Sep 17 00:00:00 2001 From: Daniel Schmitz Date: Wed, 19 Apr 2017 17:02:52 +0800 Subject: [PATCH 04/42] Fixed parsing error --- pkg/services/alerting/notifiers/telegram.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go index d2ad03d2bd0..71169c15599 100644 --- a/pkg/services/alerting/notifiers/telegram.go +++ b/pkg/services/alerting/notifiers/telegram.go @@ -106,7 +106,7 @@ func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error { } } if metrics != "" { - message = message + fmt.Sprintf("\nMetrics:%s", metrics); + message = message + fmt.Sprintf("\nMetrics:%s", metrics) } bodyJSON.Set("text", message) From 1e29d4fcfaad6a1d0f4300c5fa12e0375460147d Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 19 Apr 2017 15:07:47 +0200 Subject: [PATCH 05/42] docs: adds note in changelog for #8110 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 128abbb1662..2c98ec2c091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * **Units**: New number format: Scientific notation [#7781](https://github.com/grafana/grafana/issues/7781) thx [@cadnce](https://github.com/cadnce) * **Oauth**: Add common type for oauth authorization errors [#6428](https://github.com/grafana/grafana/issues/6428) thx [@amenzhinsky](https://github.com/amenzhinsky) * **Templating**: Data source variable now supports multi value and panel repeats [#7030](https://github.com/grafana/grafana/issues/7030) thx [@mtanda](https://github.com/mtanda) +* **Telegram**: Telegram alert is not sending metric and legend. [#8110](https://github.com/grafana/grafana/issues/8110), thx [@bashgeek](https://github.com/bashgeek) ## Fixes * **Table Panel**: Fixed annotation display in table panel, [#8023](https://github.com/grafana/grafana/issues/8023) From 11806dfa785ee918b119522dd75faf013dd99506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 19 Apr 2017 17:26:29 +0200 Subject: [PATCH 06/42] mysql: progress --- pkg/tsdb/models.go | 9 +++++---- pkg/tsdb/mysql/macros.go | 11 ++++++++--- pkg/tsdb/mysql/macros_test.go | 14 +++++++++++++- pkg/tsdb/mysql/mysql.go | 27 ++++++++++++++++++++++++--- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go index 838767dd5d9..0757a0f33b3 100644 --- a/pkg/tsdb/models.go +++ b/pkg/tsdb/models.go @@ -45,10 +45,11 @@ func (br *BatchResult) WithError(err error) *BatchResult { } type QueryResult struct { - Error error `json:"-"` - ErrorString string `json:"error"` - RefId string `json:"refId"` - Series TimeSeriesSlice `json:"series"` + Error error `json:"-"` + ErrorString string `json:"error,omitempty"` + RefId string `json:"refId"` + Meta *simplejson.Json `json:"meta,omitempty"` + Series TimeSeriesSlice `json:"series"` } type TimeSeries struct { diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index 971b41c3b07..5577819d784 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -30,8 +30,8 @@ func (m *MySqlMacroEngine) Interpolate(sql string) (string, error) { var macroError error sql = ReplaceAllStringSubmatchFunc(rExp, sql, func(groups []string) string { - res, err := m.EvaluateMacro(groups[1], groups[2:len(groups)]) - if macroError != nil { + res, err := m.EvaluateMacro(groups[1], groups[2:]) + if err != nil && macroError == nil { macroError = err return "macro_error()" } @@ -68,7 +68,12 @@ func (m *MySqlMacroEngine) EvaluateMacro(name string, args []string) (string, er if len(args) == 0 { return "", fmt.Errorf("missing time column argument for macro %v", name) } - return "UNIX_TIMESTAMP(" + args[0] + ") as time_sec", nil + return fmt.Sprintf("UNIX_TIMESTAMP(%s) as time_sec", args[0]), nil + case "__timeFilter": + if len(args) == 0 { + return "", fmt.Errorf("missing time column argument for macro %v", name) + } + return fmt.Sprintf("UNIX_TIMESTAMP(%s) > %d AND UNIX_TIMESTAMP(%s) < %d", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil default: return "", fmt.Errorf("Unknown macro %v", name) } diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index 1dcd5e1e978..a1af3caf62d 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -3,13 +3,14 @@ package mysql import ( "testing" + "github.com/grafana/grafana/pkg/tsdb" . "github.com/smartystreets/goconvey/convey" ) func TestMacroEngine(t *testing.T) { Convey("MacroEngine", t, func() { - Convey("interpolate simple function", func() { + Convey("interpolate __time function", func() { engine := &MySqlMacroEngine{} sql, err := engine.Interpolate("select $__time(time_column)") @@ -18,5 +19,16 @@ func TestMacroEngine(t *testing.T) { So(sql, ShouldEqual, "select UNIX_TIMESTAMP(time_column) as time_sec") }) + Convey("interpolate __timeFilter function", func() { + engine := &MySqlMacroEngine{ + TimeRange: &tsdb.TimeRange{From: "5m", To: "now"}, + } + + sql, err := engine.Interpolate("WHERE $__timeFilter(time_column)") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "WHERE UNIX_TIMESTAMP(time_column) > 18446744066914186738 AND UNIX_TIMESTAMP(time_column) < 18446744066914187038") + }) + }) } diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 44dcc2648f2..fd00cdff47e 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -10,6 +10,7 @@ import ( "github.com/go-xorm/core" "github.com/go-xorm/xorm" "github.com/grafana/grafana/pkg/components/null" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/tsdb" @@ -81,6 +82,7 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co QueryResults: make(map[string]*tsdb.QueryResult), } + macroEngine := NewMysqlMacroEngine(context.TimeRange) session := e.engine.NewSession() defer session.Close() db := session.DB() @@ -91,9 +93,20 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co continue } + queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: query.RefId} + result.QueryResults[query.RefId] = queryResult + + rawSql, err := macroEngine.Interpolate(rawSql) + if err != nil { + queryResult.Error = err + continue + } + + queryResult.Meta.Set("sql", rawSql) + rows, err := db.Query(rawSql) if err != nil { - result.QueryResults[query.RefId] = &tsdb.QueryResult{Error: err} + queryResult.Error = err continue } @@ -101,16 +114,24 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co res, err := e.TransformToTimeSeries(query, rows) if err != nil { - result.Error = err + queryResult.Error = err return result } - result.QueryResults[query.RefId] = &tsdb.QueryResult{RefId: query.RefId, Series: res} + queryResult.Series = res + queryResult.Meta.Set("rowCount", countPointsInAllSeries(res)) } return result } +func countPointsInAllSeries(seriesList tsdb.TimeSeriesSlice) (count int) { + for _, series := range seriesList { + count += len(series.Points) + } + return count +} + func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows) (tsdb.TimeSeriesSlice, error) { pointsBySeries := make(map[string]*tsdb.TimeSeries) columnNames, err := rows.Columns() From 98266bd95ac06b06ece2451c46443a54afa887ac Mon Sep 17 00:00:00 2001 From: raj dutt Date: Wed, 19 Apr 2017 13:19:01 -0400 Subject: [PATCH 07/42] Update alerting.md typo in API URL --- docs/sources/http_api/alerting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/http_api/alerting.md b/docs/sources/http_api/alerting.md index 22aadb80f58..0a422e10f4d 100644 --- a/docs/sources/http_api/alerting.md +++ b/docs/sources/http_api/alerting.md @@ -202,7 +202,7 @@ This API can also be used to create, update and delete alert notifications. **Example Request**: - DELETE /api/alerts-notifications/1 HTTP/1.1 + DELETE /api/alert-notifications/1 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk From f1276774a00017f4f5210f1d7584fbe8362890ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 20 Apr 2017 11:16:37 +0200 Subject: [PATCH 08/42] typescript: updated tslint and fixed new warnings --- package.json | 4 +- public/app/core/components/search/search.ts | 12 +- public/app/core/controllers/signup_ctrl.ts | 2 +- .../app/core/directives/plugin_component.ts | 2 +- public/app/core/services/backend_srv.ts | 6 +- public/app/core/time_series2.ts | 2 +- public/app/core/utils/file_export.ts | 8 +- .../app/features/annotations/editor_ctrl.ts | 4 +- public/app/features/dashboard/row/row_ctrl.ts | 1 - public/app/features/dashboard/time_srv.ts | 6 +- .../app/features/panel/metrics_panel_ctrl.ts | 4 +- .../features/playlist/playlist_edit_ctrl.ts | 2 +- public/app/features/plugins/ds_edit_ctrl.ts | 2 +- public/app/features/templating/all.ts | 2 +- .../plugins/datasource/grafana/datasource.ts | 2 +- .../plugins/datasource/influxdb/datasource.ts | 8 +- .../datasource/influxdb/influx_query.ts | 2 +- .../plugins/datasource/influxdb/query_part.ts | 2 +- .../plugins/datasource/mixed/datasource.ts | 2 +- .../mysql/partials/query.editor.html | 2 +- public/app/plugins/panel/alertlist/module.ts | 2 +- public/app/plugins/panel/dashlist/module.ts | 2 +- .../plugins/panel/gettingstarted/module.ts | 2 +- public/app/plugins/panel/graph/graph.ts | 4 +- public/app/plugins/panel/graph/module.ts | 4 +- public/app/plugins/panel/pluginlist/module.ts | 2 +- public/app/plugins/panel/singlestat/module.ts | 14 +- public/app/plugins/panel/table/editor.ts | 2 +- .../app/plugins/panel/table/transformers.ts | 6 +- public/app/plugins/panel/text/module.ts | 2 +- public/app/plugins/sdk.ts | 2 +- public/test/lib/common.ts | 2 +- tasks/options/exec.js | 4 +- yarn.lock | 292 +++--------------- 34 files changed, 107 insertions(+), 308 deletions(-) diff --git a/package.json b/package.json index 326c813dc93..c72b93ddd1a 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,8 @@ "systemjs-builder": "^0.15.34", "tether": "^1.4.0", "tether-drop": "https://github.com/torkelo/drop", - "tslint": "^4.5.1", - "typescript": "^2.1.4", + "tslint": "^5.1.0", + "typescript": "^2.2.2", "virtual-scroll": "^1.1.1" } } diff --git a/public/app/core/components/search/search.ts b/public/app/core/components/search/search.ts index bff6d3149f2..ec58a5c9f5c 100644 --- a/public/app/core/components/search/search.ts +++ b/public/app/core/components/search/search.ts @@ -117,7 +117,7 @@ export class SearchCtrl { queryHasNoFilters() { var query = this.query; return query.query === '' && query.starred === false && query.tag.length === 0; - }; + } filterByTag(tag, evt) { this.query.tag.push(tag); @@ -127,7 +127,7 @@ export class SearchCtrl { evt.stopPropagation(); evt.preventDefault(); } - }; + } removeTag(tag, evt) { this.query.tag = _.without(this.query.tag, tag); @@ -135,7 +135,7 @@ export class SearchCtrl { this.giveSearchFocus = this.giveSearchFocus + 1; evt.stopPropagation(); evt.preventDefault(); - }; + } getTags() { return this.backendSrv.get('/api/dashboards/tags').then((results) => { @@ -146,19 +146,19 @@ export class SearchCtrl { this.search(); } }); - }; + } showStarred() { this.query.starred = !this.query.starred; this.giveSearchFocus = this.giveSearchFocus + 1; this.search(); - }; + } search() { this.showImport = false; this.selectedIndex = 0; this.searchDashboards(); - }; + } } diff --git a/public/app/core/controllers/signup_ctrl.ts b/public/app/core/controllers/signup_ctrl.ts index 36544586a31..459f215a1fc 100644 --- a/public/app/core/controllers/signup_ctrl.ts +++ b/public/app/core/controllers/signup_ctrl.ts @@ -44,7 +44,7 @@ export class SignUpCtrl { window.location.href = config.appSubUrl + '/'; } }); - }; + } } coreModule.controller('SignUpCtrl', SignUpCtrl); diff --git a/public/app/core/directives/plugin_component.ts b/public/app/core/directives/plugin_component.ts index 83c030cb317..3e446b14b9e 100644 --- a/public/app/core/directives/plugin_component.ts +++ b/public/app/core/directives/plugin_component.ts @@ -75,7 +75,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $ if (!PanelCtrl || PanelCtrl.registered) { return componentInfo; - }; + } if (PanelCtrl.templatePromise) { return PanelCtrl.templatePromise.then(res => { diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts index 041cd1ab1db..16edc364340 100644 --- a/public/app/core/services/backend_srv.ts +++ b/public/app/core/services/backend_srv.ts @@ -23,7 +23,7 @@ export class BackendSrv { post(url, data) { return this.request({ method: 'POST', url: url, data: data }); - }; + } patch(url, data) { return this.request({ method: 'PATCH', url: url, data: data }); @@ -98,7 +98,7 @@ export class BackendSrv { this.$timeout(this.requestErrorHandler.bind(this, err), 50); throw err; }); - }; + } addCanceler(requestId, canceler) { if (requestId in this.inFlightRequests) { @@ -186,7 +186,7 @@ export class BackendSrv { this.inFlightRequests[options.requestId].shift(); } }); - }; + } loginPing() { return this.request({url: '/api/login/ping', method: 'GET', retry: 1 }); diff --git a/public/app/core/time_series2.ts b/public/app/core/time_series2.ts index e5d6c342fd0..daf03f8f827 100644 --- a/public/app/core/time_series2.ts +++ b/public/app/core/time_series2.ts @@ -92,7 +92,7 @@ export default class TimeSeries { this.yaxis = override.yaxis; } } - }; + } getFlotPairs(fillStyle) { var result = []; diff --git a/public/app/core/utils/file_export.ts b/public/app/core/utils/file_export.ts index 27f1064286f..f2f0192e034 100644 --- a/public/app/core/utils/file_export.ts +++ b/public/app/core/utils/file_export.ts @@ -12,7 +12,7 @@ export function exportSeriesListToCsv(seriesList) { }); }); saveSaveBlob(text, 'grafana_data_export.csv'); -}; +} export function exportSeriesListToCsvColumns(seriesList) { var text = 'sep=;\nTime;'; @@ -47,7 +47,7 @@ export function exportSeriesListToCsvColumns(seriesList) { text += '\n'; } saveSaveBlob(text, 'grafana_data_export.csv'); -}; +} export function exportTableDataToCsv(table) { var text = 'sep=;\n'; @@ -64,9 +64,9 @@ export function exportTableDataToCsv(table) { text += '\n'; }); saveSaveBlob(text, 'grafana_data_export.csv'); -}; +} export function saveSaveBlob(payload, fname) { var blob = new Blob([payload], { type: "text/csv;charset=utf-8" }); window.saveAs(blob, fname); -}; +} diff --git a/public/app/features/annotations/editor_ctrl.ts b/public/app/features/annotations/editor_ctrl.ts index deb90691d91..74c4768b5ad 100644 --- a/public/app/features/annotations/editor_ctrl.ts +++ b/public/app/features/annotations/editor_ctrl.ts @@ -69,7 +69,7 @@ export class AnnotationsEditorCtrl { this.reset(); this.mode = 'list'; this.$scope.broadcastRefresh(); - }; + } add() { this.annotations.push(this.currentAnnotation); @@ -77,7 +77,7 @@ export class AnnotationsEditorCtrl { this.mode = 'list'; this.$scope.broadcastRefresh(); this.$scope.dashboard.updateSubmenuVisibility(); - }; + } removeAnnotation(annotation) { var index = _.indexOf(this.annotations, annotation); diff --git a/public/app/features/dashboard/row/row_ctrl.ts b/public/app/features/dashboard/row/row_ctrl.ts index ce92821dfef..34b03b3c3be 100644 --- a/public/app/features/dashboard/row/row_ctrl.ts +++ b/public/app/features/dashboard/row/row_ctrl.ts @@ -216,7 +216,6 @@ coreModule.directive('panelDropZone', function($timeout) { } if (indrag === true) { - var dropZoneSpan = 12 - row.span; if (dropZoneSpan > 1) { return showPanel(dropZoneSpan, 'Drop Here'); } diff --git a/public/app/features/dashboard/time_srv.ts b/public/app/features/dashboard/time_srv.ts index 7891232d53b..abef388f7eb 100644 --- a/public/app/features/dashboard/time_srv.ts +++ b/public/app/features/dashboard/time_srv.ts @@ -60,7 +60,7 @@ class TimeSrv { if (_.isString(this.time.to) && this.time.to.indexOf('Z') >= 0) { this.time.to = moment(this.time.to).utc(); } - }; + } private parseUrlParam(value) { if (value.indexOf('now') !== -1) { @@ -92,7 +92,7 @@ class TimeSrv { if (params.refresh) { this.refresh = params.refresh || this.refresh; } - }; + } private routeUpdated() { var params = this.$location.search(); @@ -154,7 +154,7 @@ class TimeSrv { private cancelNextRefresh() { this.timer.cancel(this.refreshTimer); - }; + } setTime(time, fromRouteUpdate?) { _.extend(this.time, time); diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index b42d4a8b02a..a3303468bb3 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -136,7 +136,7 @@ class MetricsPanelCtrl extends PanelCtrl { this.calculateInterval(); return this.datasource; - }; + } calculateInterval() { var intervalOverride = this.panel.interval; @@ -194,7 +194,7 @@ class MetricsPanelCtrl extends PanelCtrl { if (this.panel.hideTimeOverride) { this.timeInfo = ''; } - }; + } issueQueries(datasource) { this.datasource = datasource; diff --git a/public/app/features/playlist/playlist_edit_ctrl.ts b/public/app/features/playlist/playlist_edit_ctrl.ts index d291b7c97d5..50cd810af93 100644 --- a/public/app/features/playlist/playlist_edit_ctrl.ts +++ b/public/app/features/playlist/playlist_edit_ctrl.ts @@ -74,7 +74,7 @@ export class PlaylistEditCtrl { return playlistItem === listedPlaylistItem; }); this.filterFoundPlaylistItems(); - }; + } savePlaylist(playlist, playlistItems) { var savePromise; diff --git a/public/app/features/plugins/ds_edit_ctrl.ts b/public/app/features/plugins/ds_edit_ctrl.ts index 3297d8c8322..57028fe4adc 100644 --- a/public/app/features/plugins/ds_edit_ctrl.ts +++ b/public/app/features/plugins/ds_edit_ctrl.ts @@ -154,7 +154,7 @@ export class DataSourceEditCtrl { this.$location.path('datasources/edit/' + result.id); }); } - }; + } confirmDelete() { this.backendSrv.delete('/api/datasources/' + this.current.id).then(() => { diff --git a/public/app/features/templating/all.ts b/public/app/features/templating/all.ts index 7205da52d19..72478d8ddd3 100644 --- a/public/app/features/templating/all.ts +++ b/public/app/features/templating/all.ts @@ -17,4 +17,4 @@ export { CustomVariable, ConstantVariable, AdhocVariable, -} +}; diff --git a/public/app/plugins/datasource/grafana/datasource.ts b/public/app/plugins/datasource/grafana/datasource.ts index aec46ac7bfe..8fb987e75e5 100644 --- a/public/app/plugins/datasource/grafana/datasource.ts +++ b/public/app/plugins/datasource/grafana/datasource.ts @@ -13,7 +13,7 @@ class GrafanaDatasource { metricFindQuery() { return this.$q.when([]); - }; + } annotationQuery(options) { return this.backendSrv.get('/api/annotations', { diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index 98c7ba87bd2..6af6a849e95 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -120,7 +120,7 @@ export default class InfluxDatasource { return {data: seriesList}; }); - }; + } annotationQuery(options) { if (!options.annotation.query) { @@ -137,7 +137,7 @@ export default class InfluxDatasource { } return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations(); }); - }; + } targetContainsTemplate(target) { for (let group of target.groupBy) { @@ -155,7 +155,7 @@ export default class InfluxDatasource { } return false; - }; + } metricFindQuery(query) { var interpolated = this.templateSrv.replace(query, null, 'regex'); @@ -256,7 +256,7 @@ export default class InfluxDatasource { } } }); - }; + } getTimeFilter(options) { var from = this.getInfluxTime(options.rangeRaw.from, false); diff --git a/public/app/plugins/datasource/influxdb/influx_query.ts b/public/app/plugins/datasource/influxdb/influx_query.ts index 0fc1f1184c1..c7fc795af53 100644 --- a/public/app/plugins/datasource/influxdb/influx_query.ts +++ b/public/app/plugins/datasource/influxdb/influx_query.ts @@ -195,7 +195,7 @@ export default class InfluxQuery { var escapedValues = _.map(value, kbn.regexEscape); return escapedValues.join('|'); - }; + } render(interpolate?) { var target = this.target; diff --git a/public/app/plugins/datasource/influxdb/query_part.ts b/public/app/plugins/datasource/influxdb/query_part.ts index 20274ccc580..683b3bddd55 100644 --- a/public/app/plugins/datasource/influxdb/query_part.ts +++ b/public/app/plugins/datasource/influxdb/query_part.ts @@ -28,7 +28,7 @@ function createPart(part): any { } return new QueryPart(part, def); -}; +} function register(options: any) { index[options.type] = new QueryPartDef(options); diff --git a/public/app/plugins/datasource/mixed/datasource.ts b/public/app/plugins/datasource/mixed/datasource.ts index 21fca3d1865..e024bb41fc9 100644 --- a/public/app/plugins/datasource/mixed/datasource.ts +++ b/public/app/plugins/datasource/mixed/datasource.ts @@ -30,4 +30,4 @@ class MixedDatasource { } } -export {MixedDatasource, MixedDatasource as Datasource} +export {MixedDatasource, MixedDatasource as Datasource}; diff --git a/public/app/plugins/datasource/mysql/partials/query.editor.html b/public/app/plugins/datasource/mysql/partials/query.editor.html index 932fbc64516..a8f7ffb96da 100644 --- a/public/app/plugins/datasource/mysql/partials/query.editor.html +++ b/public/app/plugins/datasource/mysql/partials/query.editor.html @@ -1,7 +1,7 @@
- +
diff --git a/public/app/plugins/panel/alertlist/module.ts b/public/app/plugins/panel/alertlist/module.ts index 9749394d205..3795e1c8197 100644 --- a/public/app/plugins/panel/alertlist/module.ts +++ b/public/app/plugins/panel/alertlist/module.ts @@ -139,4 +139,4 @@ class AlertListPanel extends PanelCtrl { export { AlertListPanel, AlertListPanel as PanelCtrl -} +}; diff --git a/public/app/plugins/panel/dashlist/module.ts b/public/app/plugins/panel/dashlist/module.ts index 01372af2fb7..2c4f98fc205 100644 --- a/public/app/plugins/panel/dashlist/module.ts +++ b/public/app/plugins/panel/dashlist/module.ts @@ -125,4 +125,4 @@ class DashListCtrl extends PanelCtrl { } } -export {DashListCtrl, DashListCtrl as PanelCtrl} +export {DashListCtrl, DashListCtrl as PanelCtrl}; diff --git a/public/app/plugins/panel/gettingstarted/module.ts b/public/app/plugins/panel/gettingstarted/module.ts index f0ee0bf36e4..8b3dca60d3d 100644 --- a/public/app/plugins/panel/gettingstarted/module.ts +++ b/public/app/plugins/panel/gettingstarted/module.ts @@ -116,4 +116,4 @@ class GettingStartedPanelCtrl extends PanelCtrl { } } -export {GettingStartedPanelCtrl, GettingStartedPanelCtrl as PanelCtrl} +export {GettingStartedPanelCtrl, GettingStartedPanelCtrl as PanelCtrl}; diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index cfc31867bdb..ca1b5021ab0 100755 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -271,7 +271,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) { }; for (let i = 0; i < data.length; i++) { - var series = data[i]; + let series = data[i]; series.data = series.getFlotPairs(series.nullPointMode || panel.nullPointMode); // if hidden remove points and disable stack @@ -287,7 +287,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) { options.series.bars.align = 'center'; for (let i = 0; i < data.length; i++) { - var series = data[i]; + let series = data[i]; series.data = [[i + 1, series.stats[panel.xaxis.values[0]]]]; } diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index e98d1c25ad7..0a55fe0a9df 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -284,7 +284,7 @@ class GraphCtrl extends MetricsPanelCtrl { } info.yaxis = override.yaxis = info.yaxis === 2 ? 1 : 2; this.render(); - }; + } addSeriesOverride(override) { this.panel.seriesOverrides.push(override || {}); @@ -316,4 +316,4 @@ class GraphCtrl extends MetricsPanelCtrl { } -export {GraphCtrl, GraphCtrl as PanelCtrl} +export {GraphCtrl, GraphCtrl as PanelCtrl}; diff --git a/public/app/plugins/panel/pluginlist/module.ts b/public/app/plugins/panel/pluginlist/module.ts index 8a47061feb0..2695a0af5c0 100644 --- a/public/app/plugins/panel/pluginlist/module.ts +++ b/public/app/plugins/panel/pluginlist/module.ts @@ -70,4 +70,4 @@ class PluginListCtrl extends PanelCtrl { } } -export {PluginListCtrl, PluginListCtrl as PanelCtrl} +export {PluginListCtrl, PluginListCtrl as PanelCtrl}; diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 0c5d72c7274..c4d7ed06aa4 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -214,8 +214,8 @@ class SingleStatCtrl extends MetricsPanelCtrl { // check value to text mappings if its enabled if (this.panel.mappingType === 1) { - for (var i = 0; i < this.panel.valueMaps.length; i++) { - var map = this.panel.valueMaps[i]; + for (let i = 0; i < this.panel.valueMaps.length; i++) { + let map = this.panel.valueMaps[i]; // special null case if (map.value === 'null') { if (data.value === null || data.value === void 0) { @@ -233,8 +233,8 @@ class SingleStatCtrl extends MetricsPanelCtrl { } } } else if (this.panel.mappingType === 2) { - for (var i = 0; i < this.panel.rangeMaps.length; i++) { - var map = this.panel.rangeMaps[i]; + for (let i = 0; i < this.panel.rangeMaps.length; i++) { + let map = this.panel.rangeMaps[i]; // special null case if (map.from === 'null' && map.to === 'null') { if (data.value === null || data.value === void 0) { @@ -257,13 +257,13 @@ class SingleStatCtrl extends MetricsPanelCtrl { if (data.value === null || data.value === void 0) { data.valueFormated = "no value"; } - }; + } removeValueMap(map) { var index = _.indexOf(this.panel.valueMaps, map); this.panel.valueMaps.splice(index, 1); this.render(); - }; + } addValueMap() { this.panel.valueMaps.push({value: '', op: '=', text: '' }); @@ -273,7 +273,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { var index = _.indexOf(this.panel.rangeMaps, rangeMap); this.panel.rangeMaps.splice(index, 1); this.render(); - }; + } addRangeMap() { this.panel.rangeMaps.push({from: '', to: '', text: ''}); diff --git a/public/app/plugins/panel/table/editor.ts b/public/app/plugins/panel/table/editor.ts index db1b6e3c3ec..6b803cc0444 100644 --- a/public/app/plugins/panel/table/editor.ts +++ b/public/app/plugins/panel/table/editor.ts @@ -101,7 +101,7 @@ export class TablePanelEditorCtrl { setUnitFormat(column, subItem) { column.unit = subItem.value; this.panelCtrl.render(); - }; + } addColumnStyle() { var columnStyleDefaults = { diff --git a/public/app/plugins/panel/table/transformers.ts b/public/app/plugins/panel/table/transformers.ts index 58e9758a6b9..15cc9e71134 100644 --- a/public/app/plugins/panel/table/transformers.ts +++ b/public/app/plugins/panel/table/transformers.ts @@ -42,7 +42,7 @@ transformers['timeseries_to_columns'] = { // group by time var points = {}; - for (var i = 0; i < data.length; i++) { + for (let i = 0; i < data.length; i++) { var series = data[i]; model.columns.push({text: series.target}); @@ -63,7 +63,7 @@ transformers['timeseries_to_columns'] = { var point = points[time]; var values = [point.time]; - for (var i = 0; i < data.length; i++) { + for (let i = 0; i < data.length; i++) { var value = point[i]; values.push(value); } @@ -242,4 +242,4 @@ function transformDataToTable(data, panel) { return model; } -export {transformers, transformDataToTable} +export {transformers, transformDataToTable}; diff --git a/public/app/plugins/panel/text/module.ts b/public/app/plugins/panel/text/module.ts index 8c321e2e0c3..5f453aea15b 100644 --- a/public/app/plugins/panel/text/module.ts +++ b/public/app/plugins/panel/text/module.ts @@ -79,4 +79,4 @@ export class TextPanelCtrl extends PanelCtrl { } } -export {TextPanelCtrl as PanelCtrl} +export {TextPanelCtrl as PanelCtrl}; diff --git a/public/app/plugins/sdk.ts b/public/app/plugins/sdk.ts index 468b6baa4a0..32ee7e34db9 100644 --- a/public/app/plugins/sdk.ts +++ b/public/app/plugins/sdk.ts @@ -18,4 +18,4 @@ export { MetricsPanelCtrl, QueryCtrl, alertTab, -} +}; diff --git a/public/test/lib/common.ts b/public/test/lib/common.ts index c7e8147c9c9..ca07fe01f32 100644 --- a/public/test/lib/common.ts +++ b/public/test/lib/common.ts @@ -21,4 +21,4 @@ export { sinon, expect, angularMocks, -} +}; diff --git a/tasks/options/exec.js b/tasks/options/exec.js index ad52f0b7f2c..f2955b3c24c 100644 --- a/tasks/options/exec.js +++ b/tasks/options/exec.js @@ -1,8 +1,8 @@ module.exports = function(config, grunt) { 'use strict' return { - tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json", - tslintfile : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json <%= tslint.source.files.src %>", + tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check", + tslintfile : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check <%= tslint.source.files.src %>", tscompile: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics", tswatch: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics --watch", }; diff --git a/yarn.lock b/yarn.lock index cc58c1e77c0..74cad3c2407 100644 --- a/yarn.lock +++ b/yarn.lock @@ -68,12 +68,6 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" -ansi-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba" - dependencies: - string-width "^1.0.1" - ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -255,7 +249,7 @@ aws4@^1.2.1: version "1.5.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" -babel-code-frame@^6.20.0, babel-code-frame@^6.22.0: +babel-code-frame@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" dependencies: @@ -499,20 +493,6 @@ boom@2.x.x: dependencies: hoek "2.x.x" -boxen@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6" - dependencies: - ansi-align "^1.1.0" - camelcase "^2.1.0" - chalk "^1.1.1" - cli-boxes "^1.0.0" - filled-array "^1.0.0" - object-assign "^4.0.1" - repeating "^2.0.0" - string-width "^1.0.1" - widest-line "^1.0.0" - brace-expansion@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" @@ -603,7 +583,7 @@ camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" -camelcase@^2.0.0, camelcase@^2.1.0: +camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -615,10 +595,6 @@ caniuse-db@^1.0.30000617: version "1.0.30000618" resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000618.tgz#821258ff484f662864f28ffbcf849a6247acf1fa" -capture-stack-trace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" - caseless@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" @@ -697,10 +673,6 @@ clean-css@3.4.x, clean-css@~3.4.2: commander "2.8.x" source-map "0.4.x" -cli-boxes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" - cli-cursor@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" @@ -823,7 +795,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.5.0: +concat-stream@1.5.0, concat-stream@^1.4.1, concat-stream@^1.4.6: version "1.5.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: @@ -831,28 +803,6 @@ concat-stream@1.5.0: readable-stream "~2.0.0" typedarray "~0.0.5" -concat-stream@^1.4.1, concat-stream@^1.4.6: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -configstore@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" - dependencies: - dot-prop "^3.0.0" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - object-assign "^4.0.1" - os-tmpdir "^1.0.0" - osenv "^0.1.0" - uuid "^2.0.1" - write-file-atomic "^1.1.2" - xdg-basedir "^2.0.0" - connect@^3.3.5: version "3.5.0" resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198" @@ -910,12 +860,6 @@ crc@^3.4.4: version "3.4.4" resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b" -create-error-class@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - dependencies: - capture-stack-trace "^1.0.0" - cross-spawn@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" @@ -1062,7 +1006,7 @@ diff@^2.0.2: version "2.2.3" resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99" -diff@^3.0.1: +diff@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" @@ -1116,18 +1060,6 @@ dot-case@^2.1.0: dependencies: no-case "^2.2.0" -dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" - dependencies: - is-obj "^1.0.0" - -duplexer2@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - dependencies: - readable-stream "^2.0.2" - each-async@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/each-async/-/each-async-0.1.3.tgz#b436025b08da2f86608025519e3096763dedfca3" @@ -1534,10 +1466,6 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -filled-array@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84" - finalhandler@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" @@ -1735,9 +1663,9 @@ glob@7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.1, glob@~7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.0.0: + version "7.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -1746,9 +1674,9 @@ glob@^7.0.0, glob@^7.1.1, glob@~7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.3, glob@^7.0.5, glob@~7.0.0: - version "7.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" +glob@^7.1.1, glob@~7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -1801,27 +1729,7 @@ gonzales-pe@3.4.7: dependencies: minimist "1.1.x" -got@^5.0.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35" - dependencies: - create-error-class "^3.0.1" - duplexer2 "^0.1.4" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - node-status-codes "^1.0.0" - object-assign "^4.0.1" - parse-json "^2.1.0" - pinkie-promise "^2.0.0" - read-all-stream "^3.0.0" - readable-stream "^2.0.5" - timed-out "^3.0.0" - unzip-response "^1.0.2" - url-parse-lax "^1.0.0" - -graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.0, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -2311,7 +2219,7 @@ inherits@1: version "1.0.2" resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -2430,10 +2338,6 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: jsonpointer "^4.0.0" xtend "^4.0.0" -is-npm@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" - is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" @@ -2444,10 +2348,6 @@ is-number@^2.0.2, is-number@^2.1.0: dependencies: kind-of "^3.0.2" -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -2476,21 +2376,13 @@ is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - is-resolvable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" dependencies: tryit "^1.0.1" -is-retry-allowed@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - -is-stream@^1.0.0, is-stream@^1.0.1: +is-stream@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -2811,20 +2703,10 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" -latest-version@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b" - dependencies: - package-json "^2.0.0" - lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" -lazy-req@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac" - lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -3006,10 +2888,6 @@ lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb" -lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" @@ -3294,10 +3172,6 @@ node-sass@^3.7.0: request "^2.61.0" sass-graph "^2.1.1" -node-status-codes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f" - "nomnom@>= 1.5.x": version "1.8.1" resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" @@ -3442,22 +3316,13 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@0, osenv@^0.1.0: +osenv@0: version "0.1.4" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -package-json@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb" - dependencies: - got "^5.0.0" - registry-auth-token "^3.0.1" - registry-url "^3.0.3" - semver "^5.1.0" - pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" @@ -3477,7 +3342,7 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" -parse-json@^2.1.0, parse-json@^2.2.0: +parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: @@ -3536,6 +3401,10 @@ path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -3621,10 +3490,6 @@ prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" @@ -3723,7 +3588,7 @@ raw-body@~2.2.0: iconv-lite "0.4.15" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6, rc@~1.1.6: +rc@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" dependencies: @@ -3732,13 +3597,6 @@ rc@^1.0.1, rc@^1.1.6, rc@~1.1.6: minimist "^1.2.0" strip-json-comments "~1.0.4" -read-all-stream@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" - dependencies: - pinkie-promise "^2.0.0" - readable-stream "^2.0.0" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -3769,7 +3627,7 @@ readable-stream@1.1: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2: +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5: version "2.2.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" dependencies: @@ -3852,18 +3710,6 @@ regex-cache@^0.4.2: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" -registry-auth-token@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.1.0.tgz#997c08256e0c7999837b90e944db39d8a790276b" - dependencies: - rc "^1.1.6" - -registry-url@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - dependencies: - rc "^1.0.1" - relateurl@0.2.x: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" @@ -3961,10 +3807,16 @@ resolve-pkg@^0.1.0: dependencies: resolve-from "^2.0.0" -resolve@1.1.x, resolve@^1.1.6, resolve@^1.1.7, resolve@~1.1.0: +resolve@1.1.x, resolve@^1.1.6, resolve@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" +resolve@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" + dependencies: + path-parse "^1.0.5" + restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" @@ -4048,13 +3900,7 @@ sass-lint@^1.10.2: path-is-absolute "^1.0.0" util "^0.10.3" -semver-diff@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" - dependencies: - semver "^5.0.3" - -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@~5.3.0: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -4122,10 +3968,6 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - snake-case@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f" @@ -4468,10 +4310,6 @@ through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" -timed-out@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217" - tiny-emitter@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.1.0.tgz#ab405a21ffed814a76c19739648093d70654fecb" @@ -4544,18 +4382,23 @@ tryor@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" -tslint@^4.0.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-4.4.2.tgz#b14cb79ae039c72471ab4c2627226b940dda19c6" +tslint@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.1.0.tgz#51a47baeeb58956fcd617bd2cf00e2ef0eea2ed9" dependencies: - babel-code-frame "^6.20.0" + babel-code-frame "^6.22.0" colors "^1.1.2" - diff "^3.0.1" + diff "^3.2.0" findup-sync "~0.3.0" glob "^7.1.1" optimist "~0.6.0" - resolve "^1.1.7" - update-notifier "^1.0.2" + resolve "^1.3.2" + semver "^5.3.0" + tsutils "^1.4.0" + +tsutils@^1.4.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.7.0.tgz#2e63ccc2d6912bb095f7e363ff4100721dc86f50" tunnel-agent@~0.4.1: version "0.4.3" @@ -4578,13 +4421,13 @@ type-is@~1.6.10, type-is@~1.6.14: media-typer "0.3.0" mime-types "~2.1.13" -typedarray@^0.0.6, typedarray@~0.0.5: +typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^2.1.4: - version "2.1.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.5.tgz#6fe9479e00e01855247cea216e7561bafcdbcd4a" +typescript@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.2.tgz#606022508479b55ffa368b58fee963a03dfd7b0c" uglify-js@2.6.x: version "2.6.4" @@ -4640,23 +4483,6 @@ unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" -unzip-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" - -update-notifier@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a" - dependencies: - boxen "^0.6.0" - chalk "^1.0.0" - configstore "^2.0.0" - is-npm "^1.0.0" - latest-version "^2.0.0" - lazy-req "^1.1.0" - semver-diff "^2.0.0" - xdg-basedir "^2.0.0" - upper-case-first@^1.1.0, upper-case-first@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115" @@ -4671,12 +4497,6 @@ uri-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/uri-path/-/uri-path-1.0.0.tgz#9747f018358933c31de0fccfd82d138e67262e32" -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - user-home@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" @@ -4718,7 +4538,7 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@^2.0.1, uuid@^2.0.2: +uuid@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" @@ -4809,12 +4629,6 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.1" -widest-line@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c" - dependencies: - string-width "^1.0.1" - window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" @@ -4858,14 +4672,6 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write-file-atomic@^1.1.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" @@ -4879,12 +4685,6 @@ ws@1.0.1: options ">=0.0.5" ultron "1.0.x" -xdg-basedir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" - dependencies: - os-homedir "^1.0.0" - xml-char-classes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" From 4368c5a896e0bb30fa491ec27f89285c566bd86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 20 Apr 2017 11:26:30 +0200 Subject: [PATCH 09/42] build: moved copy node modules ahead of tslint --- public/app/features/panel/panel_directive.ts | 1 + tasks/default_task.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 63fdba693cb..1f0df861613 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -144,6 +144,7 @@ module.directive('grafanaPanel', function($rootScope, $document) { function updatePanelCornerInfo() { var cornerMode = ctrl.getInfoMode(); + console.log('update error', cornerMode); cornerInfoElem[0].className = 'panel-info-corner panel-info-corner--' + cornerMode; if (cornerMode) { diff --git a/tasks/default_task.js b/tasks/default_task.js index 2a9d1871406..76e11444ddf 100644 --- a/tasks/default_task.js +++ b/tasks/default_task.js @@ -16,10 +16,10 @@ module.exports = function(grunt) { grunt.registerTask('default', [ 'jscs', 'jshint', - 'exec:tslint', - 'clean:gen', 'copy:node_modules', 'copy:public_to_gen', + 'exec:tslint', + 'clean:gen', 'phantomjs', 'css', 'exec:tscompile' From 2cb2c4073e1158de12ce24d0746de99a13dd8c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 20 Apr 2017 11:27:12 +0200 Subject: [PATCH 10/42] build: moved copy node modules ahead of tslint --- tasks/build_task.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/build_task.js b/tasks/build_task.js index e6751aa399d..f9988dc1181 100644 --- a/tasks/build_task.js +++ b/tasks/build_task.js @@ -8,10 +8,10 @@ module.exports = function(grunt) { 'jshint:source', 'jshint:tests', 'jscs', - 'exec:tslint', 'clean:release', 'copy:node_modules', 'copy:public_to_gen', + 'exec:tslint', 'exec:tscompile', 'karma:test', 'phantomjs', From fc878bc8ad11faf825348f0a5f33bb9e264ba9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 20 Apr 2017 11:59:11 +0200 Subject: [PATCH 11/42] build: fixed order --- pkg/tsdb/mysql/macros.go | 2 +- pkg/tsdb/mysql/macros_test.go | 9 +++++++++ public/app/features/panel/panel_directive.ts | 1 - public/app/plugins/datasource/mysql/module.ts | 2 +- tasks/default_task.js | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index 5577819d784..0c57be1ddd1 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -9,7 +9,7 @@ import ( //const rsString = `(?:"([^"]*)")`; const rsIdentifier = `([_a-zA-Z0-9]+)` -const sExpr = `\$` + rsIdentifier + `\((.*)\)` +const sExpr = `\$` + rsIdentifier + `\(([^\)]*)\)` type SqlMacroEngine interface { Interpolate(sql string) (string, error) diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index a1af3caf62d..6fc84fa3b1e 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -19,6 +19,15 @@ func TestMacroEngine(t *testing.T) { So(sql, ShouldEqual, "select UNIX_TIMESTAMP(time_column) as time_sec") }) + Convey("interpolate __time function wrapped in aggregation", func() { + engine := &MySqlMacroEngine{} + + sql, err := engine.Interpolate("select min($__time(time_column))") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "select min(UNIX_TIMESTAMP(time_column)) as time_sec)") + }) + Convey("interpolate __timeFilter function", func() { engine := &MySqlMacroEngine{ TimeRange: &tsdb.TimeRange{From: "5m", To: "now"}, diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 1f0df861613..63fdba693cb 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -144,7 +144,6 @@ module.directive('grafanaPanel', function($rootScope, $document) { function updatePanelCornerInfo() { var cornerMode = ctrl.getInfoMode(); - console.log('update error', cornerMode); cornerInfoElem[0].className = 'panel-info-corner panel-info-corner--' + cornerMode; if (cornerMode) { diff --git a/public/app/plugins/datasource/mysql/module.ts b/public/app/plugins/datasource/mysql/module.ts index 8cff67ff1af..315e11b637a 100644 --- a/public/app/plugins/datasource/mysql/module.ts +++ b/public/app/plugins/datasource/mysql/module.ts @@ -14,7 +14,7 @@ class MysqlQueryCtrl extends QueryCtrl { super($scope, $injector); this.target.resultFormat = 'time_series'; - this.target.alias = "{{table}}{{col_3}}"; + this.target.alias = ""; this.resultFormats = [ {text: 'Time series', value: 'time_series'}, {text: 'Table', value: 'table'}, diff --git a/tasks/default_task.js b/tasks/default_task.js index 76e11444ddf..60ccf158d3c 100644 --- a/tasks/default_task.js +++ b/tasks/default_task.js @@ -14,12 +14,12 @@ module.exports = function(grunt) { ); grunt.registerTask('default', [ + 'clean:gen', 'jscs', 'jshint', 'copy:node_modules', 'copy:public_to_gen', 'exec:tslint', - 'clean:gen', 'phantomjs', 'css', 'exec:tscompile' From 50e70cf3db764f0c43676525f9406555be1d3731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 20 Apr 2017 13:04:42 +0200 Subject: [PATCH 12/42] build: fixed unit test --- pkg/tsdb/mysql/macros_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index 6fc84fa3b1e..c5c18270be1 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -25,7 +25,7 @@ func TestMacroEngine(t *testing.T) { sql, err := engine.Interpolate("select min($__time(time_column))") So(err, ShouldBeNil) - So(sql, ShouldEqual, "select min(UNIX_TIMESTAMP(time_column)) as time_sec)") + So(sql, ShouldEqual, "select min(UNIX_TIMESTAMP(time_column) as time_sec)") }) Convey("interpolate __timeFilter function", func() { From 6ec1d16327c9514e62b0c9c2ca93f6fa3b2aade0 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 20 Apr 2017 13:26:36 +0200 Subject: [PATCH 13/42] fix: cli admin reset-password fixes cmd args Fixes the homepath and config command line args. This allows the command to be used even when the homepath is different from the default. Fixes #7730 --- docs/sources/administration/cli.md | 20 +++++++++++++++++++- pkg/cmd/grafana-cli/commands/commands.go | 20 +++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/docs/sources/administration/cli.md b/docs/sources/administration/cli.md index 8c7755506e8..4578f70ffd6 100644 --- a/docs/sources/administration/cli.md +++ b/docs/sources/administration/cli.md @@ -27,6 +27,24 @@ To show all admin commands: ### Reset admin password -You can reset the password for the admin user using the CLI. +You can reset the password for the admin user using the CLI. The use case for this command is when you have lost the admin password. `grafana-cli admin reset-admin-password ...` + +If running the command returns this error: + +> Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath + +then there are two flags that can be used to set homepath and the config file path. + +`grafana-cli admin reset-admin-password --homepath "/usr/share/grafana" newpass` + +If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API]({{< relref "http_api/user/#change-password" >}}) can be used. Here is an example with curl using basic auth: + +``` +curl -X PUT -H "Content-Type: application/json" -d '{ + "oldPassword": "admin", + "newPassword": "newpass", + "confirmNew": "newpass" +}' http://admin:admin@:3000/api/user/password +``` diff --git a/pkg/cmd/grafana-cli/commands/commands.go b/pkg/cmd/grafana-cli/commands/commands.go index 8b2ecfcf7f5..d8f01bbdcab 100644 --- a/pkg/cmd/grafana-cli/commands/commands.go +++ b/pkg/cmd/grafana-cli/commands/commands.go @@ -11,22 +11,18 @@ import ( "github.com/grafana/grafana/pkg/setting" ) -var configFile = flag.String("config", "", "path to config file") -var homePath = flag.String("homepath", "", "path to grafana install/home path, defaults to working directory") - func runDbCommand(command func(commandLine CommandLine) error) func(context *cli.Context) { return func(context *cli.Context) { + cmd := &contextCommandLine{context} - flag.Parse() setting.NewConfigContext(&setting.CommandLineArgs{ - Config: *configFile, - HomePath: *homePath, + Config: cmd.String("config"), + HomePath: cmd.String("homepath"), Args: flag.Args(), }) sqlstore.NewEngine() - cmd := &contextCommandLine{context} if err := command(cmd); err != nil { logger.Errorf("\n%s: ", color.RedString("Error")) logger.Errorf("%s\n\n", err) @@ -95,6 +91,16 @@ var adminCommands = []cli.Command{ Name: "reset-admin-password", Usage: "reset-admin-password ", Action: runDbCommand(resetPasswordCommand), + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "homepath", + Usage: "path to grafana install/home path, defaults to working directory", + }, + cli.StringFlag{ + Name: "config", + Usage: "path to config file", + }, + }, }, } From 459d195291c27d812ad5d362592905266256d849 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 20 Apr 2017 13:35:51 +0200 Subject: [PATCH 14/42] docs: fix link --- docs/sources/administration/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/administration/cli.md b/docs/sources/administration/cli.md index 4578f70ffd6..645f75ab412 100644 --- a/docs/sources/administration/cli.md +++ b/docs/sources/administration/cli.md @@ -39,7 +39,7 @@ then there are two flags that can be used to set homepath and the config file pa `grafana-cli admin reset-admin-password --homepath "/usr/share/grafana" newpass` -If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API]({{< relref "http_api/user/#change-password" >}}) can be used. Here is an example with curl using basic auth: +If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API](http://docs.grafana.org/http_api/user/#change-password) can be used. Here is an example with curl using basic auth: ``` curl -X PUT -H "Content-Type: application/json" -d '{ From 1bbc149089e415309ef321dd2b588168a79bdc9c Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 20 Apr 2017 13:59:36 +0200 Subject: [PATCH 15/42] docs: document API calls for /auth/keys --- docs/sources/http_api/auth.md | 77 +++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/sources/http_api/auth.md b/docs/sources/http_api/auth.md index ef62f271715..d8ded124ac5 100644 --- a/docs/sources/http_api/auth.md +++ b/docs/sources/http_api/auth.md @@ -41,3 +41,80 @@ You use the token in all requests in the `Authorization` header, like this: Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk The `Authorization` header value should be `Bearer `. + +# Auth HTTP resources / actions + +## Api Keys + +`GET /api/auth/keys` + +**Example Request**: + + GET /api/auth/keys HTTP/1.1 + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +**Example Response**: + + HTTP/1.1 200 + Content-Type: application/json + + [ + { + "id": 3, + "name": "API", + "role": "Admin" + }, + { + "id": 1, + "name": "TestAdmin", + "role": "Admin" + } + ] + +## Create API Key + +`POST /api/auth/keys` + +**Example Request**: + + POST /api/auth/keys HTTP/1.1 + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + + { + "name": "mykey", + "role": "Admin" + } + +JSON Body schema: + +- **name** – The key name +- **role** – Sets the access level/Grafana Role for the key. Can be one of the following values: `Viewer`, `Editor`, `Read Only Editor` or `Admin`. + +**Example Response**: + + HTTP/1.1 200 + Content-Type: application/json + + {"name":"mykey","key":"eyJrIjoiWHZiSWd3NzdCYUZnNUtibE9obUpESmE3bzJYNDRIc0UiLCJuIjoibXlrZXkiLCJpZCI6MX1="} + +## Delete API Key + +`DELETE /api/auth/keys/:id` + +**Example Request**: + + DELETE /api/auth/keys/3 HTTP/1.1 + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +**Example Response**: + + HTTP/1.1 200 + Content-Type: application/json + + {"message":"API key deleted"} From c78c460f79efd95b779a88ab8c50cec76b85dffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 20 Apr 2017 17:10:09 +0200 Subject: [PATCH 16/42] mysql: worked on mysql data soruce --- docker/blocks/mysql/fig | 2 + pkg/api/metrics.go | 5 +- pkg/tsdb/models.go | 1 + pkg/tsdb/mysql/mysql.go | 18 ++++--- public/app/features/dashboard/time_srv.ts | 4 +- .../app/features/panel/metrics_panel_ctrl.ts | 10 ++++ .../panel/partials/query_editor_row.html | 4 +- .../plugins/datasource/mysql/datasource.ts | 47 ++++++++++--------- public/app/plugins/datasource/mysql/module.ts | 44 +++++++++++++++-- .../mysql/partials/query.editor.html | 18 ++++++- 10 files changed, 114 insertions(+), 39 deletions(-) diff --git a/docker/blocks/mysql/fig b/docker/blocks/mysql/fig index 731d0fbbdc5..24cb47b61a7 100644 --- a/docker/blocks/mysql/fig +++ b/docker/blocks/mysql/fig @@ -10,3 +10,5 @@ mysql: 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/pkg/api/metrics.go b/pkg/api/metrics.go index d10491950ef..abd6527431a 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -50,13 +50,16 @@ func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response { return ApiError(500, "Metric request error", err) } + statusCode := 200 for _, res := range resp.Results { if res.Error != nil { res.ErrorString = res.Error.Error() + resp.Message = res.ErrorString + statusCode = 500 } } - return Json(200, &resp) + return Json(statusCode, &resp) } // GET /api/tsdb/testdata/scenarios diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go index 0757a0f33b3..3e82dc6ca43 100644 --- a/pkg/tsdb/models.go +++ b/pkg/tsdb/models.go @@ -27,6 +27,7 @@ type Request struct { type Response struct { BatchTimings []*BatchTiming `json:"timings"` Results map[string]*QueryResult `json:"results"` + Message string `json:"message,omitempty"` } type BatchTiming struct { diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index fd00cdff47e..d655b816520 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -112,14 +112,18 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co defer rows.Close() - res, err := e.TransformToTimeSeries(query, rows) - if err != nil { - queryResult.Error = err - return result - } + format := query.Model.Get("format").MustString("time_series") - queryResult.Series = res - queryResult.Meta.Set("rowCount", countPointsInAllSeries(res)) + if format == "time_series" { + res, err := e.TransformToTimeSeries(query, rows) + if err != nil { + queryResult.Error = err + return result + } + + queryResult.Series = res + queryResult.Meta.Set("rowCount", countPointsInAllSeries(res)) + } } return result diff --git a/public/app/features/dashboard/time_srv.ts b/public/app/features/dashboard/time_srv.ts index abef388f7eb..1385751decc 100644 --- a/public/app/features/dashboard/time_srv.ts +++ b/public/app/features/dashboard/time_srv.ts @@ -184,8 +184,8 @@ class TimeSrv { timeRangeForUrl() { var range = this.timeRange().raw; - if (moment.isMoment(range.from)) { range.from = range.from.valueOf(); } - if (moment.isMoment(range.to)) { range.to = range.to.valueOf(); } + if (moment.isMoment(range.from)) { range.from = range.from.valueOf().toString(); } + if (moment.isMoment(range.to)) { range.to = range.to.valueOf().toString(); } return range; } diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index a3303468bb3..00050870088 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -106,6 +106,16 @@ class MetricsPanelCtrl extends PanelCtrl { this.loading = false; this.error = err.message || "Request Error"; this.inspector = {error: err}; + + if (err.data) { + if (err.data.message) { + this.error = err.data.message; + } + if (err.data.error) { + this.error = err.data.error; + } + } + this.events.emit('data-error', err); console.log('Panel data error:', err); }); diff --git a/public/app/features/panel/partials/query_editor_row.html b/public/app/features/panel/partials/query_editor_row.html index 55933bbbae8..4cdc04da512 100644 --- a/public/app/features/panel/partials/query_editor_row.html +++ b/public/app/features/panel/partials/query_editor_row.html @@ -1,7 +1,7 @@
-
-
- -
-
-
-
- -
-
+
-
+
-
+
{{ctrl.lastQueryMeta.sql}}
{{ctrl.lastQueryError}}
diff --git a/vendor/github.com/go-sql-driver/mysql/row_columntypes.go b/vendor/github.com/go-sql-driver/mysql/row_columntypes.go new file mode 100644 index 00000000000..1dbfe472e7b --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/row_columntypes.go @@ -0,0 +1,78 @@ +package mysql + +const ( + // In case we get something unexpected + FieldTypeUnknown = "UNKNOWN" + + // Human-readable names for each distinct type byte + FieldTypeNameDecimal = "DECIMAL" + FieldTypeNameTiny = "TINY" + FieldTypeNameShort = "SHORT" + FieldTypeNameLong = "LONG" + FieldTypeNameFloat = "FLOAT" + FieldTypeNameDouble = "DOUBLE" + FieldTypeNameNULL = "NULL" + FieldTypeNameTimestamp = "TIMESTAMP" + FieldTypeNameLongLong = "LONGLONG" + FieldTypeNameInt24 = "INT24" + FieldTypeNameDate = "DATE" + FieldTypeNameTime = "TIME" + FieldTypeNameDateTime = "DATETIME" + FieldTypeNameYear = "YEAR" + FieldTypeNameNewDate = "NEWDATE" + FieldTypeNameVarChar = "VARCHAR" + FieldTypeNameBit = "BIT" + FieldTypeNameJSON = "JSON" + FieldTypeNameNewDecimal = "NEWDECIMAL" + FieldTypeNameEnum = "ENUM" + FieldTypeNameSet = "SET" + FieldTypeNameTinyBLOB = "TINYBLOB" + FieldTypeNameMediumBLOB = "MEDIUMBLOB" + FieldTypeNameLongBLOB = "LONGBLOB" + FieldTypeNameBLOB = "BLOB" + FieldTypeNameVarString = "VARSTRING" + FieldTypeNameString = "STRING" + FieldTypeNameGeometry = "GEOMETRY" +) + +// mapping from each type identifier to human readable string +var mysqlTypeMap = map[byte]string{ + fieldTypeDecimal: FieldTypeNameDecimal, + fieldTypeTiny: FieldTypeNameTiny, + fieldTypeShort: FieldTypeNameShort, + fieldTypeLong: FieldTypeNameLong, + fieldTypeFloat: FieldTypeNameFloat, + fieldTypeDouble: FieldTypeNameDouble, + fieldTypeNULL: FieldTypeNameNULL, + fieldTypeTimestamp: FieldTypeNameTimestamp, + fieldTypeLongLong: FieldTypeNameLongLong, + fieldTypeInt24: FieldTypeNameInt24, + fieldTypeDate: FieldTypeNameDate, + fieldTypeTime: FieldTypeNameTime, + fieldTypeDateTime: FieldTypeNameDateTime, + fieldTypeYear: FieldTypeNameYear, + fieldTypeNewDate: FieldTypeNameNewDate, + fieldTypeVarChar: FieldTypeNameVarChar, + fieldTypeBit: FieldTypeNameBit, + fieldTypeJSON: FieldTypeNameJSON, + fieldTypeNewDecimal: FieldTypeNameNewDecimal, + fieldTypeEnum: FieldTypeNameEnum, + fieldTypeSet: FieldTypeNameSet, + fieldTypeTinyBLOB: FieldTypeNameTinyBLOB, + fieldTypeMediumBLOB: FieldTypeNameMediumBLOB, + fieldTypeLongBLOB: FieldTypeNameLongBLOB, + fieldTypeBLOB: FieldTypeNameBLOB, + fieldTypeVarString: FieldTypeNameVarString, + fieldTypeString: FieldTypeNameString, + fieldTypeGeometry: FieldTypeNameGeometry, +} + +// Make Rows implement the optional RowsColumnTypeDatabaseTypeName interface. +// See https://github.com/golang/go/commit/2a85578b0ecd424e95b29d810b7a414a299fd6a7 +// - (go 1.8 required for this to have any effect) +func (rows *mysqlRows) ColumnTypeDatabaseTypeName(index int) string { + if typeName, ok := mysqlTypeMap[rows.rs.columns[index].fieldType]; ok { + return typeName + } + return FieldTypeUnknown +} From ea53e7221eea8247ab5314a74b352900a6d3452f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 21 Apr 2017 15:52:42 +0200 Subject: [PATCH 18/42] mysql: added query help --- public/app/plugins/datasource/mysql/module.ts | 1 + .../mysql/partials/query.editor.html | 35 ++++++++++++++++--- public/sass/components/_gf-form.scss | 10 ++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/public/app/plugins/datasource/mysql/module.ts b/public/app/plugins/datasource/mysql/module.ts index 6725a4fe0a6..afaa2b9e143 100644 --- a/public/app/plugins/datasource/mysql/module.ts +++ b/public/app/plugins/datasource/mysql/module.ts @@ -23,6 +23,7 @@ class MysqlQueryCtrl extends QueryCtrl { target: MysqlQuery; lastQueryMeta: QueryMeta; lastQueryError: string; + showHelp: boolean; constructor($scope, $injector) { super($scope, $injector); diff --git a/public/app/plugins/datasource/mysql/partials/query.editor.html b/public/app/plugins/datasource/mysql/partials/query.editor.html index 3dba49f9a89..de54f0ce942 100644 --- a/public/app/plugins/datasource/mysql/partials/query.editor.html +++ b/public/app/plugins/datasource/mysql/partials/query.editor.html @@ -12,9 +12,12 @@
-
- - +
+
-
{{ctrl.lastQueryMeta.sql}}
-
{{ctrl.lastQueryError}}
+
+
{{ctrl.lastQueryMeta.sql}}
+
+ +
+
Time series:
+- return column named time_sec (UTC in seconds), use UNIX_TIMESTAMP(column)
+- return column named value for the time point value
+- return column named metric to represent the series name
+
+Table:
+- return any set of columns
+
+Macros:
+- $__time(column) -> UNIX_TIMESTAMP(column) as time_sec
+- $__timeFilter(column) ->  UNIX_TIMESTAMP(time_date_time) > from AND UNIX_TIMESTAMP(time_date_time) < 1492750877
+		
+
+ + + +
+
{{ctrl.lastQueryError}}
+
diff --git a/public/sass/components/_gf-form.scss b/public/sass/components/_gf-form.scss index 94691334fe2..9c88435fcc2 100644 --- a/public/sass/components/_gf-form.scss +++ b/public/sass/components/_gf-form.scss @@ -66,6 +66,16 @@ $gf-form-margin: 0.25rem; } } +.gf-form-pre { + display: block; + flex-grow: 1; + font-size: $font-size-sm; + margin: 0; + margin-right: $gf-form-margin; + border: $input-btn-border-width solid transparent; + @include border-radius($label-border-radius-sm); +} + .gf-form-error { padding: $input-padding-y $input-padding-x; margin-right: $gf-form-margin; From 2c51f114405d8c7db54c79f8524987f6da29327a Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 21 Apr 2017 14:07:36 +0200 Subject: [PATCH 19/42] singlestat: fix variable spelling --- public/app/plugins/panel/singlestat/module.ts | 20 +++++++++---------- .../singlestat/specs/singlestat-specs.ts | 18 ++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index c4d7ed06aa4..c8ab03bd688 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -192,10 +192,10 @@ class SingleStatCtrl extends MetricsPanelCtrl { if (this.panel.valueName === 'name') { data.value = 0; data.valueRounded = 0; - data.valueFormated = this.series[0].alias; + data.valueFormatted = this.series[0].alias; } else if (_.isString(lastValue)) { data.value = 0; - data.valueFormated = _.escape(lastValue); + data.valueFormatted = _.escape(lastValue); data.valueRounded = 0; } else { data.value = this.series[0].stats[this.panel.valueName]; @@ -203,7 +203,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { var decimalInfo = this.getDecimalsForValue(data.value); var formatFunc = kbn.valueFormats[this.panel.format]; - data.valueFormated = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals); + data.valueFormatted = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals); data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals); } @@ -219,7 +219,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { // special null case if (map.value === 'null') { if (data.value === null || data.value === void 0) { - data.valueFormated = map.text; + data.valueFormatted = map.text; return; } continue; @@ -228,7 +228,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { // value/number to text mapping var value = parseFloat(map.value); if (value === data.valueRounded) { - data.valueFormated = map.text; + data.valueFormatted = map.text; return; } } @@ -238,7 +238,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { // special null case if (map.from === 'null' && map.to === 'null') { if (data.value === null || data.value === void 0) { - data.valueFormated = map.text; + data.valueFormatted = map.text; return; } continue; @@ -248,14 +248,14 @@ class SingleStatCtrl extends MetricsPanelCtrl { var from = parseFloat(map.from); var to = parseFloat(map.to); if (to >= data.valueRounded && from <= data.valueRounded) { - data.valueFormated = map.text; + data.valueFormatted = map.text; return; } } } if (data.value === null || data.value === void 0) { - data.valueFormated = "no value"; + data.valueFormatted = "no value"; } } @@ -317,7 +317,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { if (panel.prefix) { body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, panel.prefix); } - var value = applyColoringThresholds(data.value, data.valueFormated); + var value = applyColoringThresholds(data.value, data.valueFormatted); body += getSpan('singlestat-panel-value', panel.valueFontSize, value); if (panel.postfix) { body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.postfix); } @@ -329,7 +329,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { function getValueText() { var result = panel.prefix ? panel.prefix : ''; - result += data.valueFormated; + result += data.valueFormatted; result += panel.postfix ? panel.postfix : ''; return result; diff --git a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts index 3f67063bc0f..9c7a979af12 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts @@ -49,8 +49,8 @@ describe('SingleStatCtrl', function() { expect(ctx.data.valueRounded).to.be(15); }); - it('should set formated falue', function() { - expect(ctx.data.valueFormated).to.be('15'); + it('should set formatted falue', function() { + expect(ctx.data.valueFormatted).to.be('15'); }); }); @@ -65,8 +65,8 @@ describe('SingleStatCtrl', function() { expect(ctx.data.valueRounded).to.be(0); }); - it('should set formated falue', function() { - expect(ctx.data.valueFormated).to.be('test.cpu1'); + it('should set formatted falue', function() { + expect(ctx.data.valueFormatted).to.be('test.cpu1'); }); }); @@ -80,8 +80,8 @@ describe('SingleStatCtrl', function() { expect(ctx.data.valueRounded).to.be(100); }); - it('should set formated falue', function() { - expect(ctx.data.valueFormated).to.be('100'); + it('should set formatted falue', function() { + expect(ctx.data.valueFormatted).to.be('100'); }); }); @@ -100,7 +100,7 @@ describe('SingleStatCtrl', function() { }); it('Should replace value with text', function() { - expect(ctx.data.valueFormated).to.be('OK'); + expect(ctx.data.valueFormatted).to.be('OK'); }); }); @@ -112,7 +112,7 @@ describe('SingleStatCtrl', function() { }); it('Should replace value with text OK', function() { - expect(ctx.data.valueFormated).to.be('OK'); + expect(ctx.data.valueFormatted).to.be('OK'); }); }); @@ -124,7 +124,7 @@ describe('SingleStatCtrl', function() { }); it('Should replace value with text NOT OK', function() { - expect(ctx.data.valueFormated).to.be('NOT OK'); + expect(ctx.data.valueFormatted).to.be('NOT OK'); }); }); From 8874be4c663a089a2e01998c7c9753731c459665 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 21 Apr 2017 16:11:49 +0200 Subject: [PATCH 20/42] singlestat: add support for table data If data is of type Table, then will return the first row of data. The user can select which column should be shown in the SingleStat. --- .../app/plugins/panel/singlestat/editor.html | 10 ++- public/app/plugins/panel/singlestat/module.ts | 75 ++++++++++++++-- ...inglestat-specs.ts => singlestat_specs.ts} | 86 ++++++++++++++++--- 3 files changed, 153 insertions(+), 18 deletions(-) rename public/app/plugins/panel/singlestat/specs/{singlestat-specs.ts => singlestat_specs.ts} (67%) diff --git a/public/app/plugins/panel/singlestat/editor.html b/public/app/plugins/panel/singlestat/editor.html index 50f18ea6146..937f3c6cd9d 100644 --- a/public/app/plugins/panel/singlestat/editor.html +++ b/public/app/plugins/panel/singlestat/editor.html @@ -3,11 +3,19 @@
Value
-
+
+
+
+ +
+ +
+
+
diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index c8ab03bd688..7003130b64c 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -14,6 +14,7 @@ import {MetricsPanelCtrl} from 'app/plugins/sdk'; class SingleStatCtrl extends MetricsPanelCtrl { static templateUrl = 'module.html'; + dataType = 'timeseries'; series: any[]; data: any; fontSizes: any[]; @@ -22,6 +23,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { panel: any; events: any; valueNameOptions: any[] = ['min','max','avg', 'current', 'total', 'name', 'first', 'delta', 'diff', 'range']; + tableColumnOptions: any; // Set and populate defaults panelDefaults = { @@ -67,7 +69,8 @@ class SingleStatCtrl extends MetricsPanelCtrl { maxValue: 100, thresholdMarkers: true, thresholdLabels: false - } + }, + tableColumn: '' }; /** @ngInject */ @@ -98,11 +101,16 @@ class SingleStatCtrl extends MetricsPanelCtrl { } onDataReceived(dataList) { - this.series = dataList.map(this.seriesHandler.bind(this)); - - var data: any = {}; - this.setValues(data); - + const data: any = {}; + if (dataList.length > 0 && dataList[0].type === 'table'){ + this.dataType = 'table'; + const tableData = dataList.map(this.tableHandler.bind(this)); + this.setTableValues(tableData, data); + } else { + this.dataType = 'timeseries'; + this.series = dataList.map(this.seriesHandler.bind(this)); + this.setValues(data); + } this.data = data; this.render(); } @@ -117,6 +125,61 @@ class SingleStatCtrl extends MetricsPanelCtrl { return series; } + tableHandler(tableData) { + const datapoints = []; + const columnNames = {}; + + tableData.columns.forEach((column, columnIndex) => { + columnNames[columnIndex] = column.text; + }); + + this.tableColumnOptions = columnNames; + if (!_.find(tableData.columns, ['text', this.panel.tableColumn])) { + this.setTableColumnToSensibleDefault(tableData); + } + + tableData.rows.forEach((row) => { + const datapoint = {}; + + row.forEach((value, columnIndex) => { + const key = columnNames[columnIndex]; + datapoint[key] = value; + }); + + datapoints.push(datapoint); + }); + + return datapoints; + } + + setTableColumnToSensibleDefault(tableData) { + if (this.tableColumnOptions.length === 1) { + this.panel.tableColumn = this.tableColumnOptions[0]; + } else { + this.panel.tableColumn = _.find(tableData.columns, (col) => { return col.type !== 'time'; }).text; + } + } + + setTableValues(tableData, data) { + if (!tableData || tableData.length === 0) { + return; + } + + if (tableData[0].length === 0 || !tableData[0][0][this.panel.tableColumn]) { + return; + } + + let highestValue = 0; + let lowestValue = Number.MAX_VALUE; + const datapoint = tableData[0][0]; + data.value = datapoint[this.panel.tableColumn]; + + var decimalInfo = this.getDecimalsForValue(data.value); + var formatFunc = kbn.valueFormats[this.panel.format]; + data.valueFormatted = formatFunc(datapoint[this.panel.tableColumn], decimalInfo.decimals, decimalInfo.scaledDecimals); + data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0); + } + setColoring(options) { if (options.background) { this.panel.colorValue = false; diff --git a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts similarity index 67% rename from public/app/plugins/panel/singlestat/specs/singlestat-specs.ts rename to public/app/plugins/panel/singlestat/specs/singlestat_specs.ts index 9c7a979af12..51ade2f9a98 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts @@ -26,11 +26,7 @@ describe('SingleStatCtrl', function() { beforeEach(function() { setupFunc(); - var data = [ - {target: 'test.cpu1', datapoints: ctx.datapoints} - ]; - - ctx.ctrl.onDataReceived(data); + ctx.ctrl.onDataReceived(ctx.data); ctx.data = ctx.ctrl.data; }); }; @@ -41,7 +37,9 @@ describe('SingleStatCtrl', function() { singleStatScenario('with defaults', function(ctx) { ctx.setup(function() { - ctx.datapoints = [[10,1], [20,2]]; + ctx.data = [ + {target: 'test.cpu1', datapoints: [[10,1], [20,2]]} + ]; }); it('Should use series avg as default main value', function() { @@ -56,7 +54,9 @@ describe('SingleStatCtrl', function() { singleStatScenario('showing serie name instead of value', function(ctx) { ctx.setup(function() { - ctx.datapoints = [[10,1], [20,2]]; + ctx.data = [ + {target: 'test.cpu1', datapoints: [[10,1], [20,2]]} + ]; ctx.ctrl.panel.valueName = 'name'; }); @@ -72,7 +72,9 @@ describe('SingleStatCtrl', function() { singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) { ctx.setup(function() { - ctx.datapoints = [[99.999,1], [99.99999,2]]; + ctx.data = [ + {target: 'test.cpu1', datapoints: [[99.999,1], [99.99999,2]]} + ]; }); it('Should be rounded', function() { @@ -87,7 +89,9 @@ describe('SingleStatCtrl', function() { singleStatScenario('When value to text mapping is specified', function(ctx) { ctx.setup(function() { - ctx.datapoints = [[9.9,1]]; + ctx.data = [ + {target: 'test.cpu1', datapoints: [[9.9,1]]} + ]; ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}]; }); @@ -106,7 +110,9 @@ describe('SingleStatCtrl', function() { singleStatScenario('When range to text mapping is specifiedfor first range', function(ctx) { ctx.setup(function() { - ctx.datapoints = [[41,50]]; + ctx.data = [ + {target: 'test.cpu1', datapoints: [[41,50]]} + ]; ctx.ctrl.panel.mappingType = 2; ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}]; }); @@ -118,7 +124,9 @@ describe('SingleStatCtrl', function() { singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) { ctx.setup(function() { - ctx.datapoints = [[65,75]]; + ctx.data = [ + {target: 'test.cpu1', datapoints: [[65,75]]} + ]; ctx.ctrl.panel.mappingType = 2; ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}]; }); @@ -128,4 +136,60 @@ describe('SingleStatCtrl', function() { }); }); + const tableData = [{ + "columns": [ + { + "text": "Time", + "type": "time" + }, + { + "text": "test1" + }, + { + "text": "mean" + }, + { + "text": "test2" + } + ], + "rows": [ + [ + 1492759673649, + 'ignore1', + 15, + 'ignore2' + ] + ], + "type": "table" + }]; + + singleStatScenario('When table data', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.ctrl.panel.tableColumn = 'mean'; + }); + + it('Should use series avg as default main value', function() { + expect(ctx.data.value).to.be(15); + expect(ctx.data.valueRounded).to.be(15); + }); + + it('should set formatted value', function() { + expect(ctx.data.valueFormatted).to.be('15'); + }); + }); + + singleStatScenario('When table data has multiple columns', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.ctrl.panel.tableColumn = ''; + }); + + it('Should set column to first column that is not time', function() { + expect(ctx.ctrl.panel.tableColumn).to.be('test1'); + }); + }); + }); + + From b22b3e5bb9faaea49daa4a859edbb6ffb5d6fada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 21 Apr 2017 16:28:01 +0200 Subject: [PATCH 21/42] mysql: added default query template --- pkg/services/sqlstore/sql_test_data.go | 5 ----- public/app/plugins/datasource/mysql/module.ts | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/services/sqlstore/sql_test_data.go b/pkg/services/sqlstore/sql_test_data.go index ad8d36dfce5..ffb3f0fc997 100644 --- a/pkg/services/sqlstore/sql_test_data.go +++ b/pkg/services/sqlstore/sql_test_data.go @@ -61,11 +61,6 @@ func InsertSqlTestData(cmd *m.InsertSqlTestDataCommand) error { sqlRandomWalk("server2", "frontend", 100, 1.123, sess) sqlRandomWalk("server3", "frontend", 100, 1.123, sess) - sqlRandomWalk("server1", "backend", 100, 1.123, sess) - sqlRandomWalk("server2", "backend", 100, 1.123, sess) - sqlRandomWalk("server3", "backend", 100, 1.123, sess) - sqlRandomWalk("db-server1", "backend", 100, 1.123, sess) - return err }) } diff --git a/public/app/plugins/datasource/mysql/module.ts b/public/app/plugins/datasource/mysql/module.ts index afaa2b9e143..23fa783b195 100644 --- a/public/app/plugins/datasource/mysql/module.ts +++ b/public/app/plugins/datasource/mysql/module.ts @@ -9,12 +9,23 @@ export interface MysqlQuery { refId: string; format: string; alias: string; + rawSql: string; } export interface QueryMeta { sql: string; } + +var defaulQuery = `SELECT + UNIX_TIMESTAMP() as time_sec, + as value, + as metric +FROM +WHERE $__timeFilter(time_column) +ORDER BY ASC +`; + class MysqlQueryCtrl extends QueryCtrl { static templateUrl = 'partials/query.editor.html'; @@ -35,6 +46,10 @@ class MysqlQueryCtrl extends QueryCtrl { {text: 'Table', value: 'table'}, ]; + if (!this.target.rawSql) { + this.target.rawSql = defaulQuery; + } + this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope); this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope); } From a49ef90a1df3592d717cf7dd75b7902fecd77b9d Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 21 Apr 2017 16:43:14 +0200 Subject: [PATCH 22/42] singlestat: value mapping for table data Adds support for value mapping for table data in the single stat panel. --- public/app/plugins/panel/singlestat/module.ts | 5 + .../singlestat/specs/singlestat_specs.ts | 147 ++++++++++++------ 2 files changed, 105 insertions(+), 47 deletions(-) diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 7003130b64c..8000b844bf9 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -178,6 +178,8 @@ class SingleStatCtrl extends MetricsPanelCtrl { var formatFunc = kbn.valueFormats[this.panel.format]; data.valueFormatted = formatFunc(datapoint[this.panel.tableColumn], decimalInfo.decimals, decimalInfo.scaledDecimals); data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0); + + this.setValueMapping(data); } setColoring(options) { @@ -274,7 +276,10 @@ class SingleStatCtrl extends MetricsPanelCtrl { data.scopedVars = _.extend({}, this.panel.scopedVars); data.scopedVars["__name"] = {value: this.series[0].label}; } + this.setValueMapping(data); + } + setValueMapping(data) { // check value to text mappings if its enabled if (this.panel.mappingType === 1) { for (let i = 0; i < this.panel.valueMaps.length; i++) { diff --git a/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts index 51ade2f9a98..2bc36d67c3a 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts @@ -136,60 +136,113 @@ describe('SingleStatCtrl', function() { }); }); - const tableData = [{ - "columns": [ - { - "text": "Time", - "type": "time" - }, - { - "text": "test1" - }, - { - "text": "mean" - }, - { - "text": "test2" - } - ], - "rows": [ - [ - 1492759673649, - 'ignore1', - 15, - 'ignore2' - ] - ], - "type": "table" - }]; + describe('When table data', function() { + const tableData = [{ + "columns": [ + { "text": "Time", "type": "time" }, + { "text": "test1" }, + { "text": "mean" }, + { "text": "test2" } + ], + "rows": [ + [1492759673649, 'ignore1', 15, 'ignore2'] + ], + "type": "table" + }]; - singleStatScenario('When table data', function(ctx) { - ctx.setup(function() { - ctx.data = tableData; - ctx.ctrl.panel.tableColumn = 'mean'; + singleStatScenario('with default values', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.ctrl.panel.tableColumn = 'mean'; + }); + + it('Should use first rows value as default main value', function() { + expect(ctx.data.value).to.be(15); + expect(ctx.data.valueRounded).to.be(15); + }); + + it('should set formatted value', function() { + expect(ctx.data.valueFormatted).to.be('15'); + }); }); - it('Should use series avg as default main value', function() { - expect(ctx.data.value).to.be(15); - expect(ctx.data.valueRounded).to.be(15); + singleStatScenario('When table data has multiple columns', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.ctrl.panel.tableColumn = ''; + }); + + it('Should set column to first column that is not time', function() { + expect(ctx.ctrl.panel.tableColumn).to.be('test1'); + }); }); - it('should set formatted value', function() { - expect(ctx.data.valueFormatted).to.be('15'); + singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.data[0].rows[0] = [1492759673649,'ignore1', 99.99999, 'ignore2']; + ctx.ctrl.panel.tableColumn = 'mean'; + }); + + it('Should be rounded', function() { + expect(ctx.data.value).to.be(99.99999); + expect(ctx.data.valueRounded).to.be(100); + }); + + it('should set formatted falue', function() { + expect(ctx.data.valueFormatted).to.be('100'); + }); + }); + + singleStatScenario('When value to text mapping is specified', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.data[0].rows[0] = [1492759673649,'ignore1', 9.9, 'ignore2']; + ctx.ctrl.panel.tableColumn = 'mean'; + ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}]; + }); + + it('value should remain', function() { + expect(ctx.data.value).to.be(9.9); + }); + + it('round should be rounded up', function() { + expect(ctx.data.valueRounded).to.be(10); + }); + + it('Should replace value with text', function() { + expect(ctx.data.valueFormatted).to.be('OK'); + }); + }); + + singleStatScenario('When range to text mapping is specified for first range', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.data[0].rows[0] = [1492759673649,'ignore1', 41, 'ignore2']; + ctx.ctrl.panel.tableColumn = 'mean'; + ctx.ctrl.panel.mappingType = 2; + ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}]; + }); + + it('Should replace value with text OK', function() { + expect(ctx.data.valueFormatted).to.be('OK'); + }); + }); + + singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.data[0].rows[0] = [1492759673649,'ignore1', 65, 'ignore2']; + ctx.ctrl.panel.tableColumn = 'mean'; + ctx.ctrl.panel.mappingType = 2; + ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}]; + }); + + it('Should replace value with text NOT OK', function() { + expect(ctx.data.valueFormatted).to.be('NOT OK'); + }); }); }); - - singleStatScenario('When table data has multiple columns', function(ctx) { - ctx.setup(function() { - ctx.data = tableData; - ctx.ctrl.panel.tableColumn = ''; - }); - - it('Should set column to first column that is not time', function() { - expect(ctx.ctrl.panel.tableColumn).to.be('test1'); - }); - }); - }); From 6160978019e9a43843de062d3af0e36a9b6503d4 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 21 Apr 2017 16:54:56 +0200 Subject: [PATCH 23/42] singlestat: with table data, support string values If the selected table column is string then show that in the singlestat --- public/app/plugins/panel/singlestat/module.ts | 14 ++++++++++---- .../panel/singlestat/specs/singlestat_specs.ts | 12 ++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 8000b844bf9..406aedb3877 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -174,10 +174,16 @@ class SingleStatCtrl extends MetricsPanelCtrl { const datapoint = tableData[0][0]; data.value = datapoint[this.panel.tableColumn]; - var decimalInfo = this.getDecimalsForValue(data.value); - var formatFunc = kbn.valueFormats[this.panel.format]; - data.valueFormatted = formatFunc(datapoint[this.panel.tableColumn], decimalInfo.decimals, decimalInfo.scaledDecimals); - data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0); + if (_.isString(data.value)) { + data.valueFormatted = _.escape(data.value); + data.value = 0; + data.valueRounded = 0; + } else { + const decimalInfo = this.getDecimalsForValue(data.value); + const formatFunc = kbn.valueFormats[this.panel.format]; + data.valueFormatted = formatFunc(datapoint[this.panel.tableColumn], decimalInfo.decimals, decimalInfo.scaledDecimals); + data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0); + } this.setValueMapping(data); } diff --git a/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts index 2bc36d67c3a..6e05266b8fe 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat_specs.ts @@ -242,6 +242,18 @@ describe('SingleStatCtrl', function() { expect(ctx.data.valueFormatted).to.be('NOT OK'); }); }); + + singleStatScenario('When value is string', function(ctx) { + ctx.setup(function() { + ctx.data = tableData; + ctx.data[0].rows[0] = [1492759673649,'ignore1', 65, 'ignore2']; + ctx.ctrl.panel.tableColumn = 'test1'; + }); + + it('Should replace value with text NOT OK', function() { + expect(ctx.data.valueFormatted).to.be('ignore1'); + }); + }); }); }); From fdc68a8baaec44aafd7c7eb0425bf696daf95d92 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Sat, 22 Apr 2017 02:01:29 +0200 Subject: [PATCH 24/42] docker: adds mysqldb with test data Downloads a large open dataset from NYC Open Data. Then converts date columns into the mysql format. --- docker/blocks/mysql_opendata/Dockerfile | 19 ++++++ docker/blocks/mysql_opendata/fig | 9 +++ docker/blocks/mysql_opendata/import_csv.sql | 72 +++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 docker/blocks/mysql_opendata/Dockerfile create mode 100644 docker/blocks/mysql_opendata/fig create mode 100644 docker/blocks/mysql_opendata/import_csv.sql diff --git a/docker/blocks/mysql_opendata/Dockerfile b/docker/blocks/mysql_opendata/Dockerfile new file mode 100644 index 00000000000..ba75ba8e791 --- /dev/null +++ b/docker/blocks/mysql_opendata/Dockerfile @@ -0,0 +1,19 @@ +## MySQL with Open Data Set from NYC Open Data (https://data.cityofnewyork.us) + +FROM mysql:latest + +ENV MYSQL_DATABASE="testdata" \ + MYSQL_ROOT_PASSWORD="rootpass" \ + MYSQL_USER="grafana" \ + MYSQL_PASSWORD="password" + +# Install requirement (wget) +RUN apt-get update && apt-get install -y wget && apt-get install unzip + +# Fetch NYC Data Set +RUN wget https://data.cityofnewyork.us/download/fpz8-jqf4/application%2Fzip -O /tmp/data.zip && \ + unzip -j /tmp/data.zip 311_Service_Requests_from_2011.csv -d /var/lib/mysql-files + +ADD import_csv.sql /docker-entrypoint-initdb.d/ + +EXPOSE 3306 diff --git a/docker/blocks/mysql_opendata/fig b/docker/blocks/mysql_opendata/fig new file mode 100644 index 00000000000..9742d5c5f07 --- /dev/null +++ b/docker/blocks/mysql_opendata/fig @@ -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: + - "3306:3306" diff --git a/docker/blocks/mysql_opendata/import_csv.sql b/docker/blocks/mysql_opendata/import_csv.sql new file mode 100644 index 00000000000..749f71fae42 --- /dev/null +++ b/docker/blocks/mysql_opendata/import_csv.sql @@ -0,0 +1,72 @@ +use testdata; +DROP TABLE IF EXISTS `nyc_open_data`; +CREATE TABLE IF NOT EXISTS `nyc_open_data` ( + UniqueKey bigint(255), + `CreatedDate` varchar(255), + `ClosedDate` varchar(255), + Agency varchar(255), + AgencyName varchar(255), + ComplaintType varchar(255), + Descriptor varchar(255), + LocationType varchar(255), + IncidentZip varchar(255), + IncidentAddress varchar(255), + StreetName varchar(255), + CrossStreet1 varchar(255), + CrossStreet2 varchar(255), + IntersectionStreet1 varchar(255), + IntersectionStreet2 varchar(255), + AddressType varchar(255), + City varchar(255), + Landmark varchar(255), + FacilityType varchar(255), + Status varchar(255), + `DueDate` varchar(255), + ResolutionDescription varchar(2048), + `ResolutionActionUpdatedDate` varchar(255), + CommunityBoard varchar(255), + Borough varchar(255), + XCoordinateStatePlane varchar(255), + YCoordinateStatePlane varchar(255), + ParkFacilityName varchar(255), + ParkBorough varchar(255), + SchoolName varchar(255), + SchoolNumber varchar(255), + SchoolRegion varchar(255), + SchoolCode varchar(255), + SchoolPhoneNumber varchar(255), + SchoolAddress varchar(255), + SchoolCity varchar(255), + SchoolState varchar(255), + SchoolZip varchar(255), + SchoolNotFound varchar(255), + SchoolOrCitywideComplaint varchar(255), + VehicleType varchar(255), + TaxiCompanyBorough varchar(255), + TaxiPickUpLocation varchar(255), + BridgeHighwayName varchar(255), + BridgeHighwayDirection varchar(255), + RoadRamp varchar(255), + BridgeHighwaySegment varchar(255), + GarageLotName varchar(255), + FerryDirection varchar(255), + FerryTerminalName varchar(255), + Latitude varchar(255), + Longitude varchar(255), + Location varchar(255) +); +LOAD DATA INFILE '/var/lib/mysql-files/311_Service_Requests_from_2011.csv' INTO TABLE nyc_open_data FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY ',' IGNORE 1 LINES; +update nyc_open_data set CreatedDate = STR_TO_DATE(CreatedDate, '%m/%d/%Y %r') where CreatedDate <> ''; +update nyc_open_data set ClosedDate = STR_TO_DATE(ClosedDate, '%m/%d/%Y %r') where ClosedDate <> ''; +update nyc_open_data set DueDate = STR_TO_DATE(DueDate, '%m/%d/%Y %r') where DueDate <> ''; +update nyc_open_data set ResolutionActionUpdatedDate = STR_TO_DATE(ResolutionActionUpdatedDate, '%m/%d/%Y %r') where ResolutionActionUpdatedDate <> ''; + +update nyc_open_data set CreatedDate=null where CreatedDate = ''; +update nyc_open_data set ClosedDate=null where ClosedDate = ''; +update nyc_open_data set DueDate=null where DueDate = ''; +update nyc_open_data set ResolutionActionUpdatedDate=null where ResolutionActionUpdatedDate = ''; + +alter table nyc_open_data modify CreatedDate datetime null; +alter table nyc_open_data modify ClosedDate datetime null; +alter table nyc_open_data modify DueDate datetime null; +alter table nyc_open_data modify ResolutionActionUpdatedDate datetime null; From 01fc6da3b2f796e2fabb4497fa3855432cca276b Mon Sep 17 00:00:00 2001 From: Alexander-N Date: Sun, 23 Apr 2017 12:30:19 +0200 Subject: [PATCH 25/42] fix: make organisation filter case insensitive --- public/app/core/components/sidemenu/sidemenu.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/app/core/components/sidemenu/sidemenu.ts b/public/app/core/components/sidemenu/sidemenu.ts index a6bc170fddd..62258a25e7d 100644 --- a/public/app/core/components/sidemenu/sidemenu.ts +++ b/public/app/core/components/sidemenu/sidemenu.ts @@ -84,7 +84,11 @@ export class SideMenuCtrl { return; } - if (this.orgItems.length < this.maxShownOrgs && (this.orgFilter === '' || org.name.indexOf(this.orgFilter) !== -1)){ + if (this.orgItems.length === this.maxShownOrgs) { + return; + } + + if (this.orgFilter === '' || (org.name.toLowerCase().indexOf(this.orgFilter.toLowerCase()) !== -1)) { this.orgItems.push({ text: "Switch to " + org.name, icon: "fa fa-fw fa-random", From 253b8be449f17fba40624b16c73c57ffbe3552de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 23 Apr 2017 13:50:49 +0200 Subject: [PATCH 26/42] mysql: updated test data --- docker/blocks/mysql_opendata/Dockerfile | 4 ++-- docker/blocks/mysql_opendata/fig | 2 +- docker/blocks/mysql_opendata/import_csv.sql | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docker/blocks/mysql_opendata/Dockerfile b/docker/blocks/mysql_opendata/Dockerfile index ba75ba8e791..22277a0af3e 100644 --- a/docker/blocks/mysql_opendata/Dockerfile +++ b/docker/blocks/mysql_opendata/Dockerfile @@ -11,8 +11,8 @@ ENV MYSQL_DATABASE="testdata" \ RUN apt-get update && apt-get install -y wget && apt-get install unzip # Fetch NYC Data Set -RUN wget https://data.cityofnewyork.us/download/fpz8-jqf4/application%2Fzip -O /tmp/data.zip && \ - unzip -j /tmp/data.zip 311_Service_Requests_from_2011.csv -d /var/lib/mysql-files +RUN wget https://data.cityofnewyork.us/download/57g5-etyj/application%2Fzip -O /tmp/data.zip && \ + unzip -j /tmp/data.zip 311_Service_Requests_from_2015.csv -d /var/lib/mysql-files ADD import_csv.sql /docker-entrypoint-initdb.d/ diff --git a/docker/blocks/mysql_opendata/fig b/docker/blocks/mysql_opendata/fig index 9742d5c5f07..a374fbd0931 100644 --- a/docker/blocks/mysql_opendata/fig +++ b/docker/blocks/mysql_opendata/fig @@ -6,4 +6,4 @@ mysql_opendata: MYSQL_USER: grafana MYSQL_PASSWORD: password ports: - - "3306:3306" + - "3307:3306" diff --git a/docker/blocks/mysql_opendata/import_csv.sql b/docker/blocks/mysql_opendata/import_csv.sql index 749f71fae42..97ac889e8dd 100644 --- a/docker/blocks/mysql_opendata/import_csv.sql +++ b/docker/blocks/mysql_opendata/import_csv.sql @@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS `nyc_open_data` ( Longitude varchar(255), Location varchar(255) ); -LOAD DATA INFILE '/var/lib/mysql-files/311_Service_Requests_from_2011.csv' INTO TABLE nyc_open_data FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY ',' IGNORE 1 LINES; +LOAD DATA INFILE '/var/lib/mysql-files/311_Service_Requests_from_2015.csv' INTO TABLE nyc_open_data FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY ',' IGNORE 1 LINES; update nyc_open_data set CreatedDate = STR_TO_DATE(CreatedDate, '%m/%d/%Y %r') where CreatedDate <> ''; update nyc_open_data set ClosedDate = STR_TO_DATE(ClosedDate, '%m/%d/%Y %r') where ClosedDate <> ''; update nyc_open_data set DueDate = STR_TO_DATE(DueDate, '%m/%d/%Y %r') where DueDate <> ''; @@ -70,3 +70,9 @@ alter table nyc_open_data modify CreatedDate datetime null; alter table nyc_open_data modify ClosedDate datetime null; alter table nyc_open_data modify DueDate datetime null; alter table nyc_open_data modify ResolutionActionUpdatedDate datetime null; + +ALTER TABLE `nyc_open_data` ADD INDEX `IX_ComplaintType` (`ComplaintType`); +ALTER TABLE `nyc_open_data` ADD INDEX `IX_CreatedDate` (`CreatedDate`); +ALTER TABLE `nyc_open_data` ADD INDEX `IX_LocationType` (`LocationType`); +ALTER TABLE `nyc_open_data` ADD INDEX `IX_AgencyName` (`AgencyName`); +ALTER TABLE `nyc_open_data` ADD INDEX `IX_City` (`City`); From 8f17a84f315341ee0d36d1f3800c7b9e019d8434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 23 Apr 2017 14:22:47 +0200 Subject: [PATCH 27/42] mysql: added basic templating support --- public/app/plugins/datasource/mysql/datasource.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/mysql/datasource.ts b/public/app/plugins/datasource/mysql/datasource.ts index 70799048319..b25e183198a 100644 --- a/public/app/plugins/datasource/mysql/datasource.ts +++ b/public/app/plugins/datasource/mysql/datasource.ts @@ -7,11 +7,22 @@ export class MysqlDatasource { name: any; /** @ngInject */ - constructor(instanceSettings, private backendSrv, private $q) { + constructor(instanceSettings, private backendSrv, private $q, private templateSrv) { this.name = instanceSettings.name; this.id = instanceSettings.id; } + interpolateVariable(value) { + if (typeof value === 'string') { + return '\"' + value + '\"'; + } + + var quotedValues = _.map(value, function(val) { + return '\"' + val + '\"'; + }); + return quotedValues.join(','); + } + query(options) { var queries = _.filter(options.targets, item => { return item.hide !== true; @@ -21,7 +32,7 @@ export class MysqlDatasource { intervalMs: options.intervalMs, maxDataPoints: options.maxDataPoints, datasourceId: this.id, - rawSql: item.rawSql, + rawSql: this.templateSrv.replace(item.rawSql, options.scopedVars, this.interpolateVariable), format: item.format, }; }); From 413ee33d5d85ceecb850153631aaa7fd818b21f4 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Sun, 23 Apr 2017 20:07:20 +0200 Subject: [PATCH 28/42] mysql: fix go vet error --- pkg/tsdb/mysql/mysql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 35203339af8..344231cca3d 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -189,7 +189,7 @@ func (e MysqlExecutor) getTypedRowData(types []*sql.ColumnType, rows *core.Rows) case mysql.FieldTypeNameDouble: values[i] = new(float64) default: - return nil, fmt.Errorf("Database type %s not supported", stype) + return nil, fmt.Errorf("Database type %s not supported", stype.DatabaseTypeName()) } } From 7784e4e24bbc167b409e207184500f0439c91216 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Sun, 23 Apr 2017 21:56:58 +0200 Subject: [PATCH 29/42] mysql: add datetime type to table data --- pkg/tsdb/mysql/mysql.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 344231cca3d..705db1e50da 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -7,6 +7,8 @@ import ( "strconv" "sync" + "time" + "github.com/go-sql-driver/mysql" "github.com/go-xorm/core" "github.com/go-xorm/xorm" @@ -188,6 +190,8 @@ func (e MysqlExecutor) getTypedRowData(types []*sql.ColumnType, rows *core.Rows) values[i] = new(int64) case mysql.FieldTypeNameDouble: values[i] = new(float64) + case mysql.FieldTypeNameDateTime: + values[i] = new(time.Time) default: return nil, fmt.Errorf("Database type %s not supported", stype.DatabaseTypeName()) } From 2b029912aa2ca7bfc9ca356b54df1648f1a75e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 10:58:53 +0200 Subject: [PATCH 30/42] mysql: query editor fix --- .gitignore | 1 + .../plugins/datasource/mysql/datasource.ts | 2 +- public/app/plugins/datasource/mysql/module.ts | 72 +---------------- .../plugins/datasource/mysql/query_ctrl.ts | 79 +++++++++++++++++++ 4 files changed, 82 insertions(+), 72 deletions(-) create mode 100644 public/app/plugins/datasource/mysql/query_ctrl.ts diff --git a/.gitignore b/.gitignore index 721a2a71ad4..1ab7068c96a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ public/css/*.min.css *.swp .idea/ *.iml +*.tmp .vscode/ /data/* diff --git a/public/app/plugins/datasource/mysql/datasource.ts b/public/app/plugins/datasource/mysql/datasource.ts index b25e183198a..f798ce0e838 100644 --- a/public/app/plugins/datasource/mysql/datasource.ts +++ b/public/app/plugins/datasource/mysql/datasource.ts @@ -6,7 +6,7 @@ export class MysqlDatasource { id: any; name: any; - /** @ngInject */ + /** @ngInject **/ constructor(instanceSettings, private backendSrv, private $q, private templateSrv) { this.name = instanceSettings.name; this.id = instanceSettings.id; diff --git a/public/app/plugins/datasource/mysql/module.ts b/public/app/plugins/datasource/mysql/module.ts index 23fa783b195..e706ca3cd44 100644 --- a/public/app/plugins/datasource/mysql/module.ts +++ b/public/app/plugins/datasource/mysql/module.ts @@ -3,77 +3,7 @@ import angular from 'angular'; import _ from 'lodash'; import {MysqlDatasource} from './datasource'; -import {QueryCtrl} from 'app/plugins/sdk'; - -export interface MysqlQuery { - refId: string; - format: string; - alias: string; - rawSql: string; -} - -export interface QueryMeta { - sql: string; -} - - -var defaulQuery = `SELECT - UNIX_TIMESTAMP() as time_sec, - as value, - as metric -FROM
-WHERE $__timeFilter(time_column) -ORDER BY ASC -`; - -class MysqlQueryCtrl extends QueryCtrl { - static templateUrl = 'partials/query.editor.html'; - - showLastQuerySQL: boolean; - formats: any[]; - target: MysqlQuery; - lastQueryMeta: QueryMeta; - lastQueryError: string; - showHelp: boolean; - - constructor($scope, $injector) { - super($scope, $injector); - - this.target.format = this.target.format || 'time_series'; - this.target.alias = ""; - this.formats = [ - {text: 'Time series', value: 'time_series'}, - {text: 'Table', value: 'table'}, - ]; - - if (!this.target.rawSql) { - this.target.rawSql = defaulQuery; - } - - this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope); - this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope); - } - - onDataReceived(dataList) { - this.lastQueryMeta = null; - this.lastQueryError = null; - - let anySeriesFromQuery = _.find(dataList, {refId: this.target.refId}); - if (anySeriesFromQuery) { - this.lastQueryMeta = anySeriesFromQuery.meta; - } - } - - onDataError(err) { - if (err.data && err.data.results) { - let queryRes = err.data.results[this.target.refId]; - if (queryRes) { - this.lastQueryMeta = queryRes.meta; - this.lastQueryError = queryRes.error; - } - } - } -} +import {MysqlQueryCtrl} from './query_ctrl'; class MysqlConfigCtrl { static templateUrl = 'partials/config.html'; diff --git a/public/app/plugins/datasource/mysql/query_ctrl.ts b/public/app/plugins/datasource/mysql/query_ctrl.ts new file mode 100644 index 00000000000..17242fac1f0 --- /dev/null +++ b/public/app/plugins/datasource/mysql/query_ctrl.ts @@ -0,0 +1,79 @@ +/// + +import angular from 'angular'; +import _ from 'lodash'; +import {MysqlDatasource} from './datasource'; +import {QueryCtrl} from 'app/plugins/sdk'; + +export interface MysqlQuery { + refId: string; + format: string; + alias: string; + rawSql: string; +} + +export interface QueryMeta { + sql: string; +} + + +var defaulQuery = `SELECT + UNIX_TIMESTAMP() as time_sec, + as value, + as metric +FROM
+WHERE $__timeFilter(time_column) +ORDER BY ASC +`; + +export class MysqlQueryCtrl extends QueryCtrl { + static templateUrl = 'partials/query.editor.html'; + + showLastQuerySQL: boolean; + formats: any[]; + target: MysqlQuery; + lastQueryMeta: QueryMeta; + lastQueryError: string; + showHelp: boolean; + + /** @ngInject **/ + constructor($scope, $injector) { + super($scope, $injector); + + this.target.format = this.target.format || 'time_series'; + this.target.alias = ""; + this.formats = [ + {text: 'Time series', value: 'time_series'}, + {text: 'Table', value: 'table'}, + ]; + + if (!this.target.rawSql) { + this.target.rawSql = defaulQuery; + } + + this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope); + this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope); + } + + onDataReceived(dataList) { + this.lastQueryMeta = null; + this.lastQueryError = null; + + let anySeriesFromQuery = _.find(dataList, {refId: this.target.refId}); + if (anySeriesFromQuery) { + this.lastQueryMeta = anySeriesFromQuery.meta; + } + } + + onDataError(err) { + if (err.data && err.data.results) { + let queryRes = err.data.results[this.target.refId]; + if (queryRes) { + this.lastQueryMeta = queryRes.meta; + this.lastQueryError = queryRes.error; + } + } + } +} + + From b8259d7583573c887b222a3e4657b026f4232bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:18:34 +0200 Subject: [PATCH 31/42] Create ROADMAP.md --- ROADMAP.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000000..5d785f50333 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,22 @@ +Grafana Roadmap (2017-04-23) +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) + + - New Heatmap Panel (Implemented and available in master) + - Support for MySQL & Postgres as data sources (Work started and a alpha version for MySQL is available in master) + - User Groups & Dashboard folders with ACLs (work started, not yet completed, https://github.com/grafana/grafana/issues/1611#issuecomment-287742633) + - Improve new user UX + - Improve docs + - Support for alerting for Elasticsearch (can be tested in [branch](https://github.com/grafana/grafana/tree/alerting-elasticsearch) but needs more work) + +# Long term + +- Improved dashboard panel layout engine (to make it easier and enable more flexible layouts) +- Backend plugins to support more Auth options, Alerting data sources & notifications +- Universial time series transformations for any data source (meta queries) +- Reporting +- Web socket & live data streams +- Migrate to Angular2 + From 663f7ee239d53b4d62840722b003c4ff87cee67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:24:19 +0200 Subject: [PATCH 32/42] Update ROADMAP.md --- ROADMAP.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index 5d785f50333..ceb348a6fb9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,6 +10,8 @@ But it will give you an idea of our current vision and plan. - Improve new user UX - Improve docs - Support for alerting for Elasticsearch (can be tested in [branch](https://github.com/grafana/grafana/tree/alerting-elasticsearch) but needs more work) + - Graph annotations (create from grafana, region annotations, better annotation viz) + - Improve alerting (clustering, condition types) # Long term @@ -19,4 +21,10 @@ But it will give you an idea of our current vision and plan. - Reporting - Web socket & live data streams - Migrate to Angular2 +- Improve Alerting capabilities +## Outside contributions +We know this is being worked on right now by contributors (and we hope to merge it when it's ready). + +- Dashboard revisions (be able to revert dashboard changes) +- Clustering for alert engine (load distribution) From 16d27a4a8d8e1c2efcce5d6590be81733ef45225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:25:44 +0200 Subject: [PATCH 33/42] Update ROADMAP.md --- ROADMAP.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index ceb348a6fb9..91f8fee1bdd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,8 +1,9 @@ -Grafana Roadmap (2017-04-23) +¤# Grafana Roadmap (2017-04-23) + 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) +### Short term (1-4 months) - New Heatmap Panel (Implemented and available in master) - Support for MySQL & Postgres as data sources (Work started and a alpha version for MySQL is available in master) @@ -13,7 +14,7 @@ But it will give you an idea of our current vision and plan. - Graph annotations (create from grafana, region annotations, better annotation viz) - Improve alerting (clustering, condition types) -# Long term +### Long term - Improved dashboard panel layout engine (to make it easier and enable more flexible layouts) - Backend plugins to support more Auth options, Alerting data sources & notifications @@ -23,7 +24,7 @@ But it will give you an idea of our current vision and plan. - Migrate to Angular2 - Improve Alerting capabilities -## Outside contributions +### Outside contributions We know this is being worked on right now by contributors (and we hope to merge it when it's ready). - Dashboard revisions (be able to revert dashboard changes) From 09b7516d47e47cd5d6b967cb0bcdf25bf1b815c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:27:05 +0200 Subject: [PATCH 34/42] Update ROADMAP.md --- ROADMAP.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 91f8fee1bdd..fe981967198 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,9 +12,9 @@ But it will give you an idea of our current vision and plan. - Improve docs - Support for alerting for Elasticsearch (can be tested in [branch](https://github.com/grafana/grafana/tree/alerting-elasticsearch) but needs more work) - Graph annotations (create from grafana, region annotations, better annotation viz) - - Improve alerting (clustering, condition types) + - Improve alerting (clustering, silence rules) -### Long term +### Long term (in our dreams) - Improved dashboard panel layout engine (to make it easier and enable more flexible layouts) - Backend plugins to support more Auth options, Alerting data sources & notifications @@ -22,7 +22,7 @@ But it will give you an idea of our current vision and plan. - Reporting - Web socket & live data streams - Migrate to Angular2 -- Improve Alerting capabilities + ### Outside contributions We know this is being worked on right now by contributors (and we hope to merge it when it's ready). From 48acffe095456deba51cef81ea20922205a3b567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:27:28 +0200 Subject: [PATCH 35/42] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index fe981967198..eefca8baeac 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,7 +14,7 @@ But it will give you an idea of our current vision and plan. - Graph annotations (create from grafana, region annotations, better annotation viz) - Improve alerting (clustering, silence rules) -### Long term (in our dreams) +### Long term - Improved dashboard panel layout engine (to make it easier and enable more flexible layouts) - Backend plugins to support more Auth options, Alerting data sources & notifications From ef36ffb5d0a83a3566985915a07cf15e263dbfa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:27:59 +0200 Subject: [PATCH 36/42] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index eefca8baeac..6e5fbdb3f4c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,4 +1,4 @@ -¤# Grafana Roadmap (2017-04-23) +# Grafana Roadmap (2017-04-23) 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. From 9e0acdda232582d4eb23f8e01231c6592293ff7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 11:28:09 +0200 Subject: [PATCH 37/42] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6e5fbdb3f4c..260c4151442 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,4 +1,4 @@ -# Grafana Roadmap (2017-04-23) +# Roadmap (2017-04-23) 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. From 92d723d6f5b21375f6733031d1dce4f88fe647bd Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 24 Apr 2017 11:40:13 +0200 Subject: [PATCH 38/42] docker: remove downloaded temp files from opendata image --- docker/blocks/mysql_opendata/Dockerfile | 3 ++- docker/blocks/mysql_opendata/import_csv.sql | 26 +++++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docker/blocks/mysql_opendata/Dockerfile b/docker/blocks/mysql_opendata/Dockerfile index 22277a0af3e..c1086d19b82 100644 --- a/docker/blocks/mysql_opendata/Dockerfile +++ b/docker/blocks/mysql_opendata/Dockerfile @@ -12,7 +12,8 @@ RUN apt-get update && apt-get install -y wget && apt-get install unzip # Fetch NYC Data Set RUN wget https://data.cityofnewyork.us/download/57g5-etyj/application%2Fzip -O /tmp/data.zip && \ - unzip -j /tmp/data.zip 311_Service_Requests_from_2015.csv -d /var/lib/mysql-files + unzip -j /tmp/data.zip 311_Service_Requests_from_2015.csv -d /var/lib/mysql-files && \ + rm /tmp/data.zip ADD import_csv.sql /docker-entrypoint-initdb.d/ diff --git a/docker/blocks/mysql_opendata/import_csv.sql b/docker/blocks/mysql_opendata/import_csv.sql index 97ac889e8dd..d77361f3b9d 100644 --- a/docker/blocks/mysql_opendata/import_csv.sql +++ b/docker/blocks/mysql_opendata/import_csv.sql @@ -56,23 +56,25 @@ CREATE TABLE IF NOT EXISTS `nyc_open_data` ( Location varchar(255) ); LOAD DATA INFILE '/var/lib/mysql-files/311_Service_Requests_from_2015.csv' INTO TABLE nyc_open_data FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY ',' IGNORE 1 LINES; -update nyc_open_data set CreatedDate = STR_TO_DATE(CreatedDate, '%m/%d/%Y %r') where CreatedDate <> ''; -update nyc_open_data set ClosedDate = STR_TO_DATE(ClosedDate, '%m/%d/%Y %r') where ClosedDate <> ''; -update nyc_open_data set DueDate = STR_TO_DATE(DueDate, '%m/%d/%Y %r') where DueDate <> ''; -update nyc_open_data set ResolutionActionUpdatedDate = STR_TO_DATE(ResolutionActionUpdatedDate, '%m/%d/%Y %r') where ResolutionActionUpdatedDate <> ''; +UPDATE nyc_open_data SET CreatedDate = STR_TO_DATE(CreatedDate, '%m/%d/%Y %r') WHERE CreatedDate <> ''; +UPDATE nyc_open_data SET ClosedDate = STR_TO_DATE(ClosedDate, '%m/%d/%Y %r') WHERE ClosedDate <> ''; +UPDATE nyc_open_data SET DueDate = STR_TO_DATE(DueDate, '%m/%d/%Y %r') WHERE DueDate <> ''; +UPDATE nyc_open_data SET ResolutionActionUpdatedDate = STR_TO_DATE(ResolutionActionUpdatedDate, '%m/%d/%Y %r') WHERE ResolutionActionUpdatedDate <> ''; -update nyc_open_data set CreatedDate=null where CreatedDate = ''; -update nyc_open_data set ClosedDate=null where ClosedDate = ''; -update nyc_open_data set DueDate=null where DueDate = ''; -update nyc_open_data set ResolutionActionUpdatedDate=null where ResolutionActionUpdatedDate = ''; +UPDATE nyc_open_data SET CreatedDate=null WHERE CreatedDate = ''; +UPDATE nyc_open_data SET ClosedDate=null WHERE ClosedDate = ''; +UPDATE nyc_open_data SET DueDate=null WHERE DueDate = ''; +UPDATE nyc_open_data SET ResolutionActionUpdatedDate=null WHERE ResolutionActionUpdatedDate = ''; -alter table nyc_open_data modify CreatedDate datetime null; -alter table nyc_open_data modify ClosedDate datetime null; -alter table nyc_open_data modify DueDate datetime null; -alter table nyc_open_data modify ResolutionActionUpdatedDate datetime null; +ALTER TABLE nyc_open_data modify CreatedDate datetime NULL; +ALTER TABLE nyc_open_data modify ClosedDate datetime NULL; +ALTER TABLE nyc_open_data modify DueDate datetime NULL; +ALTER TABLE nyc_open_data modify ResolutionActionUpdatedDate datetime NULL; ALTER TABLE `nyc_open_data` ADD INDEX `IX_ComplaintType` (`ComplaintType`); ALTER TABLE `nyc_open_data` ADD INDEX `IX_CreatedDate` (`CreatedDate`); ALTER TABLE `nyc_open_data` ADD INDEX `IX_LocationType` (`LocationType`); ALTER TABLE `nyc_open_data` ADD INDEX `IX_AgencyName` (`AgencyName`); ALTER TABLE `nyc_open_data` ADD INDEX `IX_City` (`City`); + +SYSTEM rm /var/lib/mysql-files/311_Service_Requests_from_2015.csv From c485fed74454f1b07b8f5c967da26849aa0bc7a0 Mon Sep 17 00:00:00 2001 From: sbhenderson Date: Mon, 24 Apr 2017 04:44:29 -0500 Subject: [PATCH 39/42] Fix to issue 2524 by limiting number of returned measurements for display. (#8092) --- .../app/plugins/datasource/influxdb/query_builder.js | 8 +++++++- .../datasource/influxdb/specs/query_builder_specs.ts | 10 +++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/query_builder.js b/public/app/plugins/datasource/influxdb/query_builder.js index 4b45d9bf6a6..d8051338838 100644 --- a/public/app/plugins/datasource/influxdb/query_builder.js +++ b/public/app/plugins/datasource/influxdb/query_builder.js @@ -91,7 +91,13 @@ function (_) { query += ' WHERE ' + whereConditions.join(' '); } } - + if (type === 'MEASUREMENTS') + { + query += ' LIMIT 100'; + //Solve issue #2524 by limiting the number of measurements returned + //LIMIT must be after WITH MEASUREMENT and WHERE clauses + //This also could be used for TAG KEYS and TAG VALUES, if desired + } return query; }; diff --git a/public/app/plugins/datasource/influxdb/specs/query_builder_specs.ts b/public/app/plugins/datasource/influxdb/specs/query_builder_specs.ts index b075a1ef544..0120e349b50 100644 --- a/public/app/plugins/datasource/influxdb/specs/query_builder_specs.ts +++ b/public/app/plugins/datasource/influxdb/specs/query_builder_specs.ts @@ -34,31 +34,31 @@ describe('InfluxQueryBuilder', function() { it('should have no conditions in measurement query for query with no tags', function() { var builder = new InfluxQueryBuilder({ measurement: '', tags: [] }); var query = builder.buildExploreQuery('MEASUREMENTS'); - expect(query).to.be('SHOW MEASUREMENTS'); + expect(query).to.be('SHOW MEASUREMENTS LIMIT 100'); }); it('should have no conditions in measurement query for query with no tags and empty query', function() { var builder = new InfluxQueryBuilder({ measurement: '', tags: [] }); var query = builder.buildExploreQuery('MEASUREMENTS', undefined, ''); - expect(query).to.be('SHOW MEASUREMENTS'); + expect(query).to.be('SHOW MEASUREMENTS LIMIT 100'); }); it('should have WITH MEASUREMENT in measurement query for non-empty query with no tags', function() { var builder = new InfluxQueryBuilder({ measurement: '', tags: [] }); var query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'something'); - expect(query).to.be('SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/'); + expect(query).to.be('SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ LIMIT 100'); }); it('should have WITH MEASUREMENT WHERE in measurement query for non-empty query with tags', function() { var builder = new InfluxQueryBuilder({ measurement: '', tags: [{key: 'app', value: 'email'}] }); var query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'something'); - expect(query).to.be("SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ WHERE \"app\" = 'email'"); + expect(query).to.be("SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ WHERE \"app\" = 'email' LIMIT 100"); }); it('should have where condition in measurement query for query with tags', function() { var builder = new InfluxQueryBuilder({measurement: '', tags: [{key: 'app', value: 'email'}]}); var query = builder.buildExploreQuery('MEASUREMENTS'); - expect(query).to.be("SHOW MEASUREMENTS WHERE \"app\" = 'email'"); + expect(query).to.be("SHOW MEASUREMENTS WHERE \"app\" = 'email' LIMIT 100"); }); it('should have where tag name IN filter in tag values query for query with one tag', function() { From ae5e004b6980e4cacf7cc9b50b4beef5eea99340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 14:55:43 +0200 Subject: [PATCH 40/42] mysql: time filter macro updated --- pkg/tsdb/mysql/macros.go | 2 +- pkg/tsdb/mysql/macros_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index 0c57be1ddd1..def2fde9fcc 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -73,7 +73,7 @@ func (m *MySqlMacroEngine) EvaluateMacro(name string, args []string) (string, er if len(args) == 0 { return "", fmt.Errorf("missing time column argument for macro %v", name) } - return fmt.Sprintf("UNIX_TIMESTAMP(%s) > %d AND UNIX_TIMESTAMP(%s) < %d", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil + return fmt.Sprintf("%s > FROM_UNIXTIME(%d) AND %s < FROM_UNIXTIME(%d)", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil default: return "", fmt.Errorf("Unknown macro %v", name) } diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index c5c18270be1..5b6b885ff0e 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -36,7 +36,7 @@ func TestMacroEngine(t *testing.T) { sql, err := engine.Interpolate("WHERE $__timeFilter(time_column)") So(err, ShouldBeNil) - So(sql, ShouldEqual, "WHERE UNIX_TIMESTAMP(time_column) > 18446744066914186738 AND UNIX_TIMESTAMP(time_column) < 18446744066914187038") + So(sql, ShouldEqual, "WHERE time_column > FROM_UNIXTIME(18446744066914186738) AND time_column < FROM_UNIXTIME(18446744066914187038)") }) }) From 787fea90b9fbeecc77a135ba45bab033aaba4417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 15:17:57 +0200 Subject: [PATCH 41/42] heatmap: changed name of heatmap data format option, #8054 --- public/app/plugins/panel/heatmap/axes_editor.ts | 4 ++-- public/app/plugins/panel/heatmap/heatmap_ctrl.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/panel/heatmap/axes_editor.ts b/public/app/plugins/panel/heatmap/axes_editor.ts index 5b84f272d95..cd0f465636a 100644 --- a/public/app/plugins/panel/heatmap/axes_editor.ts +++ b/public/app/plugins/panel/heatmap/axes_editor.ts @@ -26,8 +26,8 @@ export class AxesEditorCtrl { }; this.dataFormats = { - 'Timeseries': 'timeseries', - 'ES histogram': 'es_histogram' + 'TS': 'timeseries', + 'TS Pre-bucketed': 'tsbuckets' }; } diff --git a/public/app/plugins/panel/heatmap/heatmap_ctrl.ts b/public/app/plugins/panel/heatmap/heatmap_ctrl.ts index c9877a2b41c..c0d3a7bd25d 100644 --- a/public/app/plugins/panel/heatmap/heatmap_ctrl.ts +++ b/public/app/plugins/panel/heatmap/heatmap_ctrl.ts @@ -135,7 +135,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl { let xBucketSize, yBucketSize, heatmapStats, bucketsData; let logBase = this.panel.yAxis.logBase; - if (this.panel.dataFormat === 'es_histogram') { + if (this.panel.dataFormat === 'tsbuckets') { heatmapStats = this.parseHistogramSeries(this.series); bucketsData = elasticHistogramToHeatmap(this.series); From d085aaad417cf1df722773596a4ef175255b5f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Apr 2017 17:06:58 +0200 Subject: [PATCH 42/42] fix: variable srv addVariable function, only used in tests --- public/app/features/templating/variable_srv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/templating/variable_srv.ts b/public/app/features/templating/variable_srv.ts index ac2948dbd4b..022203b9eb9 100644 --- a/public/app/features/templating/variable_srv.ts +++ b/public/app/features/templating/variable_srv.ts @@ -92,7 +92,7 @@ export class VariableSrv { addVariable(model) { var variable = this.createVariableFromModel(model); - this.variables.push(this.createVariableFromModel(variable)); + this.variables.push(variable); return variable; }