Merge branch 'master' into alerting_definitions

This commit is contained in:
bergquist 2016-04-22 15:52:56 +02:00
commit ba5978abd3
27 changed files with 144 additions and 81 deletions

View File

@ -1,3 +1,16 @@
# 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)
# 3.0.0-beta5 (2016-04-15)
### Bug fixes

View File

@ -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": {

View File

@ -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"},

View File

@ -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 == "" {

View File

@ -126,8 +126,8 @@ 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")
if retryCount < 3 {
fmt.Printf("\nFailed downloading. Will retry once.\n%v\n", r)
downloadFile(pluginName, filePath, url)
} else {
panic(r)
@ -164,14 +164,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()
}
}

View File

@ -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())
}

View File

@ -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() {

View File

@ -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

View File

@ -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);
});

View File

@ -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();
}

View File

@ -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);

View File

@ -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"});
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -80,6 +80,13 @@ function (_, $) {
category: categories.Calculate,
});
addFuncDef({
name: 'stddevSeries',
params: optionalSeriesRefArgs,
defaultParams: [''],
category: categories.Calculate,
});
addFuncDef({
name: 'divideSeries',
params: optionalSeriesRefArgs,

View File

@ -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');
}

View File

@ -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 + "'";
}

View File

@ -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;
}

View File

@ -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", () => {

View File

@ -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];

View File

@ -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;

View File

@ -30,7 +30,7 @@ export class TableRenderer {
}
if (_.isArray(v)) {
v = v.join(',&nbsp;');
v = v.join(', ');
}
return v;

View File

@ -67,18 +67,20 @@
}
// Links within the dropdown menu
> li > a {
display: block;
padding: 3px 20px 3px 15px;
clear: both;
font-weight: normal;
line-height: $line-height-base;
color: $dropdownLinkColor;
white-space: nowrap;
> li {
> a {
display: block;
padding: 3px 20px 3px 15px;
clear: both;
font-weight: normal;
line-height: $line-height-base;
color: $dropdownLinkColor;
white-space: nowrap;
i {
padding-right: 5px;
color: $link-color-disabled;
i {
padding-right: 5px;
color: $link-color-disabled;
}
}
}
}

View File

@ -85,7 +85,8 @@
}
.graph-legend-table {
overflow-y: scroll;
overflow-y: auto;
overflow-x: hidden;
.graph-legend-series {
display: table-row;

View File

@ -24,7 +24,7 @@ describe("Emitter", () => {
expect(sub2Called).to.be(true);
});
it.only('should handle errors', () => {
it('should handle errors', () => {
var events = new Emitter();
var sub1Called = 0;
var sub2Called = 0;

View File

@ -99,6 +99,11 @@ define([
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.*.filters');
});
it('should not escape custom all value', function() {
var target = _templateSrv.replace('this.$test', {}, 'regex');
expect(target).to.be('this.*');
});
});
describe('lucene format', function() {
@ -127,7 +132,7 @@ define([
it('multi value and regex format should render regex string', function() {
var result = _templateSrv.formatValue(['test.','test2'], 'regex');
expect(result).to.be('test\\.|test2');
expect(result).to.be('(test\\.|test2)');
});
it('multi value and pipe should render pipe string', function() {

View File

@ -280,7 +280,7 @@ define([
});
it('should add All option with custom value', function() {
expect(scenario.variable.options[0].value).to.be('*');
expect(scenario.variable.options[0].value).to.be('$__all');
});
});

View File

@ -25,6 +25,19 @@ module.exports = function(grunt) {
'typescript:build'
]);
grunt.registerTask('test', ['default', 'karma:test']);
grunt.registerTask('test', ['default', 'karma:test', 'no-only-tests']);
grunt.registerTask('no-only-tests', function() {
var files = grunt.file.expand('public/**/*_specs\.ts', 'public/**/*_specs\.js');
files.forEach(function(spec) {
var rows = grunt.file.read(spec).split('\n');
rows.forEach(function(row) {
if (row.indexOf('.only(') > 0) {
grunt.log.errorlns(row);
grunt.fail.warn('found only statement in test: ' + spec)
}
});
});
});
};