diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b8239bd437..9d4ee020dce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# 3.0.0-beta6 (unreleased) + +### Enhancements +* **Singlestat**: Support for gauges in singlestat panel. closes [#3688](https://github.com/grafana/grafana/pull/3688) + +### Bug fixes +* **InfluxDB 0.12**: Fixed issue templating and `show tag values` query only returning tags for first measurement, fixes [#4726](https://github.com/grafana/grafana/issues/4726) +* **Templating**: Fixed issue with regex formating when matching multiple values, fixes [#4755](https://github.com/grafana/grafana/issues/4755) +* **Templating**: Fixed issue with custom all value and escaping, fixes [#4736](https://github.com/grafana/grafana/issues/4736) +* **Dashlist**: Fixed issue dashboard list panel and caching tags, fixes [#4768](https://github.com/grafana/grafana/issues/4768) +* **Graph**: Fixed issue with unneeded scrollbar in legend for Firefox, fixes [#4760](https://github.com/grafana/grafana/issues/4760) +* **Table panel**: Fixed issue table panel formating string array properties, fixes [#4791](https://github.com/grafana/grafana/issues/4791) +* **grafana-cli**: Improve error message when failing to install plugins due to corrupt response, fixes [#4651](https://github.com/grafana/grafana/issues/4651) + # 3.0.0-beta5 (2016-04-15) ### Bug fixes diff --git a/docs/sources/http_api/dashboard.md b/docs/sources/http_api/dashboard.md index 68f6ab022cc..ead63c722aa 100644 --- a/docs/sources/http_api/dashboard.md +++ b/docs/sources/http_api/dashboard.md @@ -191,7 +191,7 @@ Will return the home dashboard. `GET /api/dashboards/tags` -Get all tabs of dashboards +Get all tags of dashboards **Example Request**: diff --git a/docs/sources/plugins/index.md b/docs/sources/plugins/index.md index 08654bfb946..bb5c8062223 100644 --- a/docs/sources/plugins/index.md +++ b/docs/sources/plugins/index.md @@ -15,7 +15,7 @@ Grafana already have a strong community of contributors and plugin developers. By making it easier to develop and install plugins we hope that the community can grow even stronger and develop new plugins that we would never think about. -You can discover available plugins on [Grafana.net](http://grafana.net) +You can discover available plugins on [Grafana.net](https://grafana.net) diff --git a/package.json b/package.json index f454a42ba7a..e71a9049dde 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "phantomjs-prebuilt": "^2.1.3", "reflect-metadata": "0.1.2", "rxjs": "5.0.0-beta.4", - "sass-lint": "^1.5.0", + "sass-lint": "^1.6.0", "systemjs": "0.19.24" }, "engines": { diff --git a/pkg/api/cloudwatch/metrics.go b/pkg/api/cloudwatch/metrics.go index f5e5274a202..5ecdaabf516 100644 --- a/pkg/api/cloudwatch/metrics.go +++ b/pkg/api/cloudwatch/metrics.go @@ -56,7 +56,7 @@ func init() { "HbaseBackupFailed", "MostRecentBackupDuration", "TimeSinceLastSuccessfulBackup"}, "AWS/ES": {"ClusterStatus.green", "ClusterStatus.yellow", "ClusterStatus.red", "Nodes", "SearchableDocuments", "DeletedDocuments", "CPUUtilization", "FreeStorageSpace", "JVMMemoryPressure", "AutomatedSnapshotFailure", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "DiskQueueLength", "ReadIOPS", "WriteIOPS"}, "AWS/Events": {"Invocations", "FailedInvocations", "TriggeredRules", "MatchedEvents", "ThrottledRules"}, - "AWS/Kinesis": {"PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "IncomingBytes", "IncomingRecords", "GetRecords.Bytes", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Success"}, + "AWS/Kinesis": {"GetRecords.Bytes", "GetRecords.IteratorAge", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Records", "GetRecords.Success", "IncomingBytes", "IncomingRecords", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "ReadProvisionedThroughputExceeded", "WriteProvisionedThroughputExceeded", "IteratorAgeMilliseconds", "OutgoingBytes", "OutgoingRecords"}, "AWS/Lambda": {"Invocations", "Errors", "Duration", "Throttles"}, "AWS/Logs": {"IncomingBytes", "IncomingLogEvents", "ForwardedBytes", "ForwardedLogEvents", "DeliveryErrors", "DeliveryThrottling"}, "AWS/ML": {"PredictCount", "PredictFailureCount"}, @@ -88,7 +88,7 @@ func init() { "AWS/ElasticMapReduce": {"ClusterId", "JobFlowId", "JobId"}, "AWS/ES": {}, "AWS/Events": {"RuleName"}, - "AWS/Kinesis": {"StreamName"}, + "AWS/Kinesis": {"StreamName", "ShardID"}, "AWS/Lambda": {"FunctionName"}, "AWS/Logs": {"LogGroupName", "DestinationType", "FilterName"}, "AWS/ML": {"MLModelId", "RequestMode"}, diff --git a/pkg/api/dashboard_snapshot.go b/pkg/api/dashboard_snapshot.go index 3c369ca5b7f..cdcb871314d 100644 --- a/pkg/api/dashboard_snapshot.go +++ b/pkg/api/dashboard_snapshot.go @@ -21,6 +21,10 @@ func GetSharingOptions(c *middleware.Context) { } func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapshotCommand) { + if cmd.Name == "" { + cmd.Name = "Unnamed snapshot" + } + if cmd.External { // external snapshot ref requires key and delete key if cmd.Key == "" || cmd.DeleteKey == "" { diff --git a/pkg/api/dataproxy.go b/pkg/api/dataproxy.go index eb88045cd51..b00ef595161 100644 --- a/pkg/api/dataproxy.go +++ b/pkg/api/dataproxy.go @@ -41,7 +41,6 @@ func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *ht req.URL.RawQuery = reqQueryVals.Encode() } else if ds.Type == m.DS_INFLUXDB { req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath) - reqQueryVals.Add("db", ds.Database) req.URL.RawQuery = reqQueryVals.Encode() if !ds.BasicAuth { req.Header.Del("Authorization") diff --git a/pkg/api/index.go b/pkg/api/index.go index 575ea35cfaf..53538fd2775 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -103,6 +103,10 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { } for _, include := range plugin.Includes { + if !c.HasUserRole(include.Role) { + continue + } + if include.Type == "page" && include.AddToNav { link := &dtos.NavLink{ Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/page/" + include.Slug, @@ -110,6 +114,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { } appLink.Children = append(appLink.Children, link) } + if include.Type == "dashboard" && include.AddToNav { link := &dtos.NavLink{ Url: setting.AppSubUrl + "/dashboard/db/" + include.Slug, @@ -124,7 +129,9 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "fa fa-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/edit"}) } - data.MainNavLinks = append(data.MainNavLinks, appLink) + if len(appLink.Children) > 0 { + data.MainNavLinks = append(data.MainNavLinks, appLink) + } } } diff --git a/pkg/cmd/grafana-cli/commands/commands.go b/pkg/cmd/grafana-cli/commands/commands.go index b3821a47844..ec454078f9b 100644 --- a/pkg/cmd/grafana-cli/commands/commands.go +++ b/pkg/cmd/grafana-cli/commands/commands.go @@ -4,6 +4,7 @@ import ( "os" "github.com/codegangsta/cli" + "github.com/fatih/color" "github.com/grafana/grafana/pkg/cmd/grafana-cli/log" ) @@ -12,7 +13,7 @@ func runCommand(command func(commandLine CommandLine) error) func(context *cli.C cmd := &contextCommandLine{context} if err := command(cmd); err != nil { - log.Error("\nError: ") + log.Errorf("\n%s: ", color.RedString("Error")) log.Errorf("%s\n\n", err) cmd.ShowHelp() diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index 81e7a15233b..eb5973d07be 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -126,11 +126,16 @@ func downloadFile(pluginName, filePath, url string) (err error) { defer func() { if r := recover(); r != nil { retryCount++ - if retryCount == 1 { - log.Debug("\nFailed downloading. Will retry once.\n") - downloadFile(pluginName, filePath, url) + if retryCount < 3 { + fmt.Println("Failed downloading. Will retry once.") + err = downloadFile(pluginName, filePath, url) } else { - panic(r) + failure := fmt.Sprintf("%v", r) + if failure == "runtime error: makeslice: len out of range" { + err = fmt.Errorf("Corrupt http response from source. Please try again.\n") + } else { + panic(r) + } } } }() @@ -164,14 +169,14 @@ func downloadFile(pluginName, filePath, url string) (err error) { return fmt.Errorf(permissionsDeniedMessage, newFile) } - defer dst.Close() src, err := zf.Open() if err != nil { - log.Errorf("%v", err) + log.Errorf("Failed to extract file: %v", err) } - defer src.Close() io.Copy(dst, src) + dst.Close() + src.Close() } } diff --git a/pkg/cmd/grafana-cli/commands/remove_command.go b/pkg/cmd/grafana-cli/commands/remove_command.go index e0ecbb2b788..9792ed9d095 100644 --- a/pkg/cmd/grafana-cli/commands/remove_command.go +++ b/pkg/cmd/grafana-cli/commands/remove_command.go @@ -3,7 +3,7 @@ package commands import ( "errors" - "github.com/grafana/grafana/pkg/cmd/grafana-cli/log" + "fmt" m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models" services "github.com/grafana/grafana/pkg/cmd/grafana-cli/services" ) @@ -15,22 +15,17 @@ func removeCommand(c CommandLine) error { pluginPath := c.GlobalString("pluginsDir") localPlugins := getPluginss(pluginPath) - log.Info("remove!\n") - plugin := c.Args().First() - log.Info("plugin: " + plugin + "\n") if plugin == "" { return errors.New("Missing plugin parameter") } - log.Infof("plugins : \n%v\n", localPlugins) - for _, p := range localPlugins { if p.Id == c.Args().First() { - log.Infof("removing plugin %s", p.Id) removePlugin(pluginPath, p.Id) + return nil } } - return nil + return fmt.Errorf("Could not find plugin named %s", c.Args().First()) } diff --git a/pkg/cmd/grafana-cli/main.go b/pkg/cmd/grafana-cli/main.go index 5cc3fb6f306..b9549e00c1a 100644 --- a/pkg/cmd/grafana-cli/main.go +++ b/pkg/cmd/grafana-cli/main.go @@ -8,7 +8,6 @@ import ( "github.com/codegangsta/cli" "github.com/grafana/grafana/pkg/cmd/grafana-cli/commands" "github.com/grafana/grafana/pkg/cmd/grafana-cli/log" - "strings" ) var version = "master" @@ -18,7 +17,7 @@ func getGrafanaPluginDir() string { defaultNix := "/var/lib/grafana/plugins" if currentOS == "windows" { - return "C:\\opt\\grafana\\plugins" + return "../data/plugins" } pwd, err := os.Getwd() @@ -29,16 +28,17 @@ func getGrafanaPluginDir() string { } if isDevenvironment(pwd) { - return "../../../data/plugins" + return "../data/plugins" } return defaultNix } func isDevenvironment(pwd string) bool { - // if grafana-cli is executed from the cmd folder we can assume + // if ../conf/defaults.ini exists, grafana is not installed as package // that its in development environment. - return strings.HasSuffix(pwd, "/pkg/cmd/grafana-cli") + _, err := os.Stat("../conf/defaults.ini") + return err == nil } func main() { diff --git a/pkg/models/dashboard_snapshot.go b/pkg/models/dashboard_snapshot.go index f920e91f2e4..4a4d1290b6d 100644 --- a/pkg/models/dashboard_snapshot.go +++ b/pkg/models/dashboard_snapshot.go @@ -45,7 +45,7 @@ type DashboardSnapshotDTO struct { type CreateDashboardSnapshotCommand struct { Dashboard *simplejson.Json `json:"dashboard" binding:"Required"` - Name string `json:"name" binding:"Required"` + Name string `json:"name"` Expires int64 `json:"expires"` // these are passed when storing an external snapshot ref diff --git a/pkg/models/org_user.go b/pkg/models/org_user.go index 48d17deb9db..d7a918751ef 100644 --- a/pkg/models/org_user.go +++ b/pkg/models/org_user.go @@ -1,7 +1,9 @@ package models import ( + "encoding/json" "errors" + "fmt" "time" ) @@ -37,6 +39,26 @@ func (r RoleType) Includes(other RoleType) bool { return r == other } +func (r *RoleType) UnmarshalJSON(data []byte) error { + var str string + err := json.Unmarshal(data, &str) + if err != nil { + return err + } + + *r = RoleType(str) + + if (*r).IsValid() == false { + if (*r) != "" { + return errors.New(fmt.Sprintf("JSON validation error: invalid role value: %s", *r)) + } + + *r = ROLE_VIEWER + } + + return nil +} + type OrgUser struct { Id int64 OrgId int64 diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 68268239c51..aa381abacc7 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/models" + m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" ) @@ -69,6 +69,12 @@ func (pb *PluginBase) registerPlugin(pluginDir string) error { pb.Dependencies.GrafanaVersion = "*" } + for _, include := range pb.Includes { + if include.Role == "" { + include.Role = m.RoleType(m.ROLE_VIEWER) + } + } + pb.PluginDir = pluginDir Plugins[pb.Id] = pb return nil @@ -80,14 +86,14 @@ type PluginDependencies struct { } type PluginInclude struct { - Name string `json:"name"` - Path string `json:"path"` - Type string `json:"type"` - Component string `json:"component"` - Role models.RoleType `json:"role"` - AddToNav bool `json:"addToNav"` - DefaultNav bool `json:"defaultNav"` - Slug string `json:"slug"` + Name string `json:"name"` + Path string `json:"path"` + Type string `json:"type"` + Component string `json:"component"` + Role m.RoleType `json:"role"` + AddToNav bool `json:"addToNav"` + DefaultNav bool `json:"defaultNav"` + Slug string `json:"slug"` Id string `json:"-"` } diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index a64094cb65e..ef36fd75ab6 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -216,7 +216,7 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error { func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { return inTransaction2(func(sess *session) error { dashboard := m.Dashboard{Slug: cmd.Slug, OrgId: cmd.OrgId} - has, err := x.Get(&dashboard) + has, err := sess.Get(&dashboard) if err != nil { return err } else if has == false { diff --git a/public/app/core/directives/plugin_component.ts b/public/app/core/directives/plugin_component.ts index 3e6383cc5c6..6708c0315f3 100644 --- a/public/app/core/directives/plugin_component.ts +++ b/public/app/core/directives/plugin_component.ts @@ -206,9 +206,12 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $ }); $compile(child)(scope); - elem.empty(); - elem.append(child); + + // let a binding digest cycle complete before adding to dom + setTimeout(function() { + elem.append(child); + }); } function registerPluginComponent(scope, elem, attrs, componentInfo) { diff --git a/public/app/features/dashboard/viewStateSrv.js b/public/app/features/dashboard/viewStateSrv.js index 2738105553a..cda5e69f006 100644 --- a/public/app/features/dashboard/viewStateSrv.js +++ b/public/app/features/dashboard/viewStateSrv.js @@ -36,7 +36,7 @@ function (angular, _, $) { self.update(payload); }); - $scope.onAppEvent('panel-instantiated', function(evt, payload) { + $scope.onAppEvent('panel-initialized', function(evt, payload) { self.registerPanel(payload.scope); }); diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 4f3df7e6e8a..48746e56ff4 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -50,8 +50,11 @@ export class PanelCtrl { } init() { - this.publishAppEvent('panel-instantiated', {scope: this.$scope}); this.calculatePanelHeight(); + + this.publishAppEvent('panel-initialized', {scope: this.$scope}); + this.events.emit('panel-initialized'); + this.refresh(); } diff --git a/public/app/features/plugins/partials/update_instructions.html b/public/app/features/plugins/partials/update_instructions.html index 55455e24af7..9648be53c86 100644 --- a/public/app/features/plugins/partials/update_instructions.html +++ b/public/app/features/plugins/partials/update_instructions.html @@ -14,7 +14,7 @@
Type the following on the command line to update {{plugin.name}}.
grafana-cli plugins update {{plugin.id}}
- Check out {{plugin.name}} on Grafana.net for README and changelog. If you do not have access to the command line, ask your Grafana administator.
+ Check out {{plugin.name}} on Grafana.net for README and changelog. If you do not have access to the command line, ask your Grafana administator.
Pro tip: To update all plugins at once, type
grafana-cli plugins update-all
on the command line.
diff --git a/public/app/features/templating/templateSrv.js b/public/app/features/templating/templateSrv.js
index 26dc77d36a9..f60414eac43 100644
--- a/public/app/features/templating/templateSrv.js
+++ b/public/app/features/templating/templateSrv.js
@@ -57,7 +57,7 @@ function (angular, _) {
}
var escapedValues = _.map(value, regexEscape);
- return escapedValues.join('|');
+ return '(' + escapedValues.join('|') + ')';
}
case "lucene": {
if (typeof value === 'string') {
@@ -152,6 +152,10 @@ function (angular, _) {
value = variable.current.value;
if (self.isAllValue(value)) {
value = self.getAllValue(variable);
+ // skip formating of custom all values
+ if (variable.allValue) {
+ return value;
+ }
}
var res = self.formatValue(value, format, variable);
diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js
index 799e27583d5..4cda10ac406 100644
--- a/public/app/features/templating/templateValuesSrv.js
+++ b/public/app/features/templating/templateValuesSrv.js
@@ -294,11 +294,6 @@ function (angular, _, kbn) {
};
this.addAllOption = function(variable) {
- if (variable.allValue) {
- variable.options.unshift({text: 'All', value: variable.allValue});
- return;
- }
-
variable.options.unshift({text: 'All', value: "$__all"});
};
diff --git a/public/app/plugins/datasource/elasticsearch/img/logo_large.png b/public/app/plugins/datasource/elasticsearch/img/logo_large.png
index 429dedac1a7..b76d01e5d74 100644
Binary files a/public/app/plugins/datasource/elasticsearch/img/logo_large.png and b/public/app/plugins/datasource/elasticsearch/img/logo_large.png differ
diff --git a/public/app/plugins/datasource/graphite/gfunc.js b/public/app/plugins/datasource/graphite/gfunc.js
index de482598fc5..a7907186811 100644
--- a/public/app/plugins/datasource/graphite/gfunc.js
+++ b/public/app/plugins/datasource/graphite/gfunc.js
@@ -80,6 +80,13 @@ function (_, $) {
category: categories.Calculate,
});
+ addFuncDef({
+ name: 'stddevSeries',
+ params: optionalSeriesRefArgs,
+ defaultParams: [''],
+ category: categories.Calculate,
+ });
+
addFuncDef({
name: 'divideSeries',
params: optionalSeriesRefArgs,
diff --git a/public/app/plugins/datasource/influxdb/README.md b/public/app/plugins/datasource/influxdb/README.md
index 45eaa51eb0f..d8d98cf5c6b 100644
--- a/public/app/plugins/datasource/influxdb/README.md
+++ b/public/app/plugins/datasource/influxdb/README.md
@@ -6,8 +6,8 @@ There are currently two separate datasources for InfluxDB in Grafana: InfluxDB 0
This is the plugin for InfluxDB 0.9. It is rapidly evolving and we continue to track its API.
-InfluxDB 0.8 is no longer maintained by InfluxDB Inc, but we provide support as a convenience to existing users. You can find it [here](https://www.grafana.net/plugins/grafana-influxdb-08-datasource).
+InfluxDB 0.8 is no longer maintained by InfluxDB Inc, but we provide support as a convenience to existing users. You can find it [here](https://grafana.net/plugins/grafana-influxdb-08-datasource).
Read more about InfluxDB here:
-[http://docs.grafana.org/datasources/influxdb/](http://docs.grafana.org/datasources/influxdb/)
\ No newline at end of file
+[http://docs.grafana.org/datasources/influxdb/](http://docs.grafana.org/datasources/influxdb/)
diff --git a/public/app/plugins/datasource/influxdb/influx_query.ts b/public/app/plugins/datasource/influxdb/influx_query.ts
index 85457c7a8b3..68392348f1a 100644
--- a/public/app/plugins/datasource/influxdb/influx_query.ts
+++ b/public/app/plugins/datasource/influxdb/influx_query.ts
@@ -152,7 +152,9 @@ export default class InfluxQuery {
if (interpolate) {
value = this.templateSrv.replace(value, this.scopedVars);
}
- value = "'" + value.replace('\\', '\\\\') + "'";
+ if (isNaN(+value)) {
+ value = "'" + value.replace('\\', '\\\\') + "'";
+ }
} else if (interpolate){
value = this.templateSrv.replace(value, this.scopedVars, 'regex');
}
@@ -166,6 +168,8 @@ export default class InfluxQuery {
if (!measurement.match('^/.*/')) {
measurement = '"' + measurement+ '"';
+ } else {
+ measurement = this.templateSrv.replace(measurement, this.scopedVars, 'regex');
}
if (policy !== 'default') {
diff --git a/public/app/plugins/datasource/influxdb/query_builder.js b/public/app/plugins/datasource/influxdb/query_builder.js
index 1921c672ba6..07d920350d7 100644
--- a/public/app/plugins/datasource/influxdb/query_builder.js
+++ b/public/app/plugins/datasource/influxdb/query_builder.js
@@ -25,8 +25,8 @@ function (_) {
}
}
- // quote value unless regex
- if (operator !== '=~' && operator !== '!~') {
+ // quote value unless regex or number
+ if (operator !== '=~' && operator !== '!~' && isNaN(+value)) {
value = "'" + value + "'";
}
diff --git a/public/app/plugins/datasource/influxdb/response_parser.ts b/public/app/plugins/datasource/influxdb/response_parser.ts
index 2e33b398a88..23173674361 100644
--- a/public/app/plugins/datasource/influxdb/response_parser.ts
+++ b/public/app/plugins/datasource/influxdb/response_parser.ts
@@ -12,17 +12,29 @@ export default class ResponseParser {
return [];
}
- var series = influxResults.series[0];
- return _.map(series.values, (value) => {
- if (_.isArray(value)) {
- if (query.toLowerCase().indexOf('show tag values') >= 0) {
- return { text: (value[1] || value[0]) };
+ var influxdb11format = query.toLowerCase().indexOf('show tag values') >= 0;
+
+ var res = {};
+ _.each(influxResults.series, serie => {
+ _.each(serie.values, value => {
+ if (_.isArray(value)) {
+ if (influxdb11format) {
+ addUnique(res, value[1] || value[0]);
+ } else {
+ addUnique(res, value[0]);
+ }
} else {
- return { text: value[0] };
+ addUnique(res, value);
}
- } else {
- return { text: value };
- }
+ });
+ });
+
+ return _.map(res, value => {
+ return { text: value};
});
}
}
+
+function addUnique(arr, value) {
+ arr[value] = value;
+}
diff --git a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts
index e58fe32dd1b..f545753d10e 100644
--- a/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts
+++ b/public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts
@@ -38,7 +38,7 @@ describe("influxdb response parser", () => {
{
"name": "hostnameTagValues",
"columns": ["hostname"],
- "values": [ ["server1"], ["server2"] ]
+ "values": [ ["server1"], ["server2"], ["server2"] ]
}
]
}
@@ -54,7 +54,7 @@ describe("influxdb response parser", () => {
});
});
- describe("response from 0.11.0", () => {
+ describe("response from 0.12.0", () => {
var response = {
"results": [
{
@@ -62,8 +62,19 @@ describe("influxdb response parser", () => {
{
"name": "cpu",
"columns": [ "key", "value"],
- "values": [ [ "source", "site" ], [ "source", "api" ] ]
- }
+ "values": [
+ [ "source", "site" ],
+ [ "source", "api" ]
+ ]
+ },
+ {
+ "name": "logins",
+ "columns": [ "key", "value"],
+ "values": [
+ [ "source", "site" ],
+ [ "source", "webapi"]
+ ]
+ },
]
}
]
@@ -72,15 +83,12 @@ describe("influxdb response parser", () => {
var result = this.parser.parse(query, response);
it("should get two responses", () => {
- expect(_.size(result)).to.be(2);
+ expect(_.size(result)).to.be(3);
expect(result[0].text).to.be('site');
expect(result[1].text).to.be('api');
+ expect(result[2].text).to.be('webapi');
});
});
-
-
-
-
});
describe("SHOW FIELD response", () => {
diff --git a/public/app/plugins/panel/dashlist/module.ts b/public/app/plugins/panel/dashlist/module.ts
index 77029bd7ceb..b6407cf103e 100644
--- a/public/app/plugins/panel/dashlist/module.ts
+++ b/public/app/plugins/panel/dashlist/module.ts
@@ -5,27 +5,26 @@ import config from 'app/core/config';
import {PanelCtrl} from 'app/plugins/sdk';
import {impressions} from 'app/features/dashboard/impression_store';
- // Set and populate defaults
-var panelDefaults = {
- query: '',
- limit: 10,
- tags: [],
- recent: false,
- search: false,
- starred: true,
- headings: true,
-};
-
class DashListCtrl extends PanelCtrl {
static templateUrl = 'module.html';
groups: any[];
modes: any[];
+ panelDefaults = {
+ query: '',
+ limit: 10,
+ tags: [],
+ recent: false,
+ search: false,
+ starred: true,
+ headings: true,
+ };
+
/** @ngInject */
constructor($scope, $injector, private backendSrv) {
super($scope, $injector);
- _.defaults(this.panel, panelDefaults);
+ _.defaults(this.panel, this.panelDefaults);
if (this.panel.tag) {
this.panel.tags = [this.panel.tag];
diff --git a/public/app/plugins/panel/graph/graph.js b/public/app/plugins/panel/graph/graph.js
index 9e6633b5551..669fe1fbc91 100755
--- a/public/app/plugins/panel/graph/graph.js
+++ b/public/app/plugins/panel/graph/graph.js
@@ -73,7 +73,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
var legendSeries = _.filter(data, function(series) {
return series.hideFromLegend(panel.legend) === false;
});
- var total = 23 + (22 * legendSeries.length);
+ var total = 23 + (21 * legendSeries.length);
return Math.min(total, Math.floor(panelHeight/2));
} else {
return 26;
diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts
index 1fcd44204f7..a11c537b178 100644
--- a/public/app/plugins/panel/graph/module.ts
+++ b/public/app/plugins/panel/graph/module.ts
@@ -13,85 +13,6 @@ import TimeSeries from 'app/core/time_series2';
import * as fileExport from 'app/core/utils/file_export';
import {MetricsPanelCtrl} from 'app/plugins/sdk';
-var panelDefaults = {
- // datasource name, null = default datasource
- datasource: null,
- // sets client side (flot) or native graphite png renderer (png)
- renderer: 'flot',
- yaxes: [
- {
- label: null,
- show: true,
- logBase: 1,
- min: null,
- max: null,
- format: 'short'
- },
- {
- label: null,
- show: true,
- logBase: 1,
- min: null,
- max: null,
- format: 'short'
- }
- ],
- xaxis: {
- show: true
- },
- grid : {
- threshold1: null,
- threshold2: null,
- threshold1Color: 'rgba(216, 200, 27, 0.27)',
- threshold2Color: 'rgba(234, 112, 112, 0.22)'
- },
- // show/hide lines
- lines : true,
- // fill factor
- fill : 1,
- // line width in pixels
- linewidth : 2,
- // show hide points
- points : false,
- // point radius in pixels
- pointradius : 5,
- // show hide bars
- bars : false,
- // enable/disable stacking
- stack : false,
- // stack percentage mode
- percentage : false,
- // legend options
- legend: {
- show: true, // disable/enable legend
- values: false, // disable/enable legend values
- min: false,
- max: false,
- current: false,
- total: false,
- avg: false
- },
- // how null points should be handled
- nullPointMode : 'connected',
- // staircase line mode
- steppedLine: false,
- // tooltip options
- tooltip : {
- value_type: 'cumulative',
- shared: true,
- msResolution: false,
- },
- // time overrides
- timeFrom: null,
- timeShift: null,
- // metric queries
- targets: [{}],
- // series color overrides
- aliasColors: {},
- // other style overrides
- seriesOverrides: [],
-};
-
class GraphCtrl extends MetricsPanelCtrl {
static template = template;
@@ -105,14 +26,93 @@ class GraphCtrl extends MetricsPanelCtrl {
datapointsWarning: boolean;
colors: any = [];
+ panelDefaults = {
+ // datasource name, null = default datasource
+ datasource: null,
+ // sets client side (flot) or native graphite png renderer (png)
+ renderer: 'flot',
+ yaxes: [
+ {
+ label: null,
+ show: true,
+ logBase: 1,
+ min: null,
+ max: null,
+ format: 'short'
+ },
+ {
+ label: null,
+ show: true,
+ logBase: 1,
+ min: null,
+ max: null,
+ format: 'short'
+ }
+ ],
+ xaxis: {
+ show: true
+ },
+ grid : {
+ threshold1: null,
+ threshold2: null,
+ threshold1Color: 'rgba(216, 200, 27, 0.27)',
+ threshold2Color: 'rgba(234, 112, 112, 0.22)'
+ },
+ // show/hide lines
+ lines : true,
+ // fill factor
+ fill : 1,
+ // line width in pixels
+ linewidth : 2,
+ // show hide points
+ points : false,
+ // point radius in pixels
+ pointradius : 5,
+ // show hide bars
+ bars : false,
+ // enable/disable stacking
+ stack : false,
+ // stack percentage mode
+ percentage : false,
+ // legend options
+ legend: {
+ show: true, // disable/enable legend
+ values: false, // disable/enable legend values
+ min: false,
+ max: false,
+ current: false,
+ total: false,
+ avg: false
+ },
+ // how null points should be handled
+ nullPointMode : 'connected',
+ // staircase line mode
+ steppedLine: false,
+ // tooltip options
+ tooltip : {
+ value_type: 'cumulative',
+ shared: true,
+ msResolution: false,
+ },
+ // time overrides
+ timeFrom: null,
+ timeShift: null,
+ // metric queries
+ targets: [{}],
+ // series color overrides
+ aliasColors: {},
+ // other style overrides
+ seriesOverrides: [],
+ };
+
/** @ngInject */
constructor($scope, $injector, private annotationsSrv) {
super($scope, $injector);
- _.defaults(this.panel, angular.copy(panelDefaults));
- _.defaults(this.panel.tooltip, panelDefaults.tooltip);
- _.defaults(this.panel.grid, panelDefaults.grid);
- _.defaults(this.panel.legend, panelDefaults.legend);
+ _.defaults(this.panel, this.panelDefaults);
+ _.defaults(this.panel.tooltip, this.panelDefaults.tooltip);
+ _.defaults(this.panel.grid, this.panelDefaults.grid);
+ _.defaults(this.panel.legend, this.panelDefaults.legend);
this.colors = $scope.$root.colors;
diff --git a/public/app/plugins/panel/pluginlist/module.html b/public/app/plugins/panel/pluginlist/module.html
index c73da35b391..8e74f173a07 100644
--- a/public/app/plugins/panel/pluginlist/module.html
+++ b/public/app/plugins/panel/pluginlist/module.html
@@ -22,7 +22,7 @@