Commit 373118c5 by Torkel Ödegaard

Merge branch 'master' of github.com:torkelo/grafana-private into pro

parents 634d8c99 846cf934
# 1.9.0 (unreleased) # 1.9.1 (unreleased)
**Enhancements**
- [Issue #1028](https://github.com/grafana/grafana/issues/1028). Graph: New legend option ``hideEmtpy`` to hide series with only null values
**Fixes**
- [Issue #1199](https://github.com/grafana/grafana/issues/1199). Graph: fix for series tooltip when one series is hidden/disabled
- [Issue #1207](https://github.com/grafana/grafana/issues/1207). Graphite: movingAverage / movingMedian parameter type impovement, now handles int and interval parameter
# 1.9.0 (2014-12-02)
**Enhancements** **Enhancements**
- [Issue #1130](https://github.com/grafana/grafana/issues/1130). SinglestatPanel: Added null point handling, and value to text mapping - [Issue #1130](https://github.com/grafana/grafana/issues/1130). SinglestatPanel: Added null point handling, and value to text mapping
...@@ -16,7 +25,7 @@ ...@@ -16,7 +25,7 @@
# 1.9.0-rc1 (2014-11-17) # 1.9.0-rc1 (2014-11-17)
**UI Improvements* **UI Improvements**
- [Issue #770](https://github.com/grafana/grafana/issues/770). UI: Panel dropdown menu replaced with a new panel menu - [Issue #770](https://github.com/grafana/grafana/issues/770). UI: Panel dropdown menu replaced with a new panel menu
**Graph** **Graph**
......
{ {
"version": "1.9.0-rc1", "version": "1.9.0",
"url": "http://grafanarel.s3.amazonaws.com/grafana-1.9.0-rc1.tar.gz" "url": "http://grafanarel.s3.amazonaws.com/grafana-1.9.0.tar.gz"
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"company": "Coding Instinct AB" "company": "Coding Instinct AB"
}, },
"name": "grafana", "name": "grafana",
"version": "1.9.0-rc1", "version": "1.9.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://github.com/torkelo/grafana.git" "url": "http://github.com/torkelo/grafana.git"
......
...@@ -162,6 +162,11 @@ function (angular, _, config, gfunc, Parser) { ...@@ -162,6 +162,11 @@ function (angular, _, config, gfunc, Parser) {
return new MetricSegment({ value: segment.text, expandable: segment.expandable }); return new MetricSegment({ value: segment.text, expandable: segment.expandable });
}); });
if ($scope.altSegments.length === 0) {
return;
}
// add template variables
_.each(templateSrv.variables, function(variable) { _.each(templateSrv.variables, function(variable) {
$scope.altSegments.unshift(new MetricSegment({ $scope.altSegments.unshift(new MetricSegment({
type: 'template', type: 'template',
...@@ -170,6 +175,7 @@ function (angular, _, config, gfunc, Parser) { ...@@ -170,6 +175,7 @@ function (angular, _, config, gfunc, Parser) {
})); }));
}); });
// add wildcard option
$scope.altSegments.unshift(new MetricSegment('*')); $scope.altSegments.unshift(new MetricSegment('*'));
}) })
.then(null, function(err) { .then(null, function(err) {
......
<div class="editor-row"> <div class="editor-row">
<div class="section"> <div class="section">
<h5>Drilldown / detail link<tip>These links appear in the dropdown menu in the panel menu</tip></h5> <h5>Drilldown / detail link<tip>These links appear in the dropdown menu in the panel menu. </tip></h5>
<div class="grafana-target" ng-repeat="link in panel.links"j> <div class="grafana-target" ng-repeat="link in panel.links"j>
<div class="grafana-target-inner"> <div class="grafana-target-inner">
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
<input type="text" ng-model="link.url" class="input-large grafana-target-segment-input"> <input type="text" ng-model="link.url" class="input-large grafana-target-segment-input">
</li> </li>
<li class="grafana-target-segment">params</li> <li class="grafana-target-segment">params
<tip>Use var-variableName=value to pass templating variables.</tip>
</li>
<li> <li>
<input type="text" ng-model="link.params" class="input-medium grafana-target-segment-input"> <input type="text" ng-model="link.params" class="input-medium grafana-target-segment-input">
</li> </li>
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
<editor-opt-bool text="Values" model="panel.legend.values" change="render()"></editor-opt-bool> <editor-opt-bool text="Values" model="panel.legend.values" change="render()"></editor-opt-bool>
<editor-opt-bool text="Table" model="panel.legend.alignAsTable" change="render()"></editor-opt-bool> <editor-opt-bool text="Table" model="panel.legend.alignAsTable" change="render()"></editor-opt-bool>
<editor-opt-bool text="Right side" model="panel.legend.rightSide" change="render()"></editor-opt-bool> <editor-opt-bool text="Right side" model="panel.legend.rightSide" change="render()"></editor-opt-bool>
<editor-opt-bool text="Hide empty" model="panel.legend.hideEmpty" tip="Hides series with only null values" change="render()"></editor-opt-bool>
</div> </div>
<div class="section" ng-if="panel.legend.values"> <div class="section" ng-if="panel.legend.values">
......
...@@ -99,9 +99,9 @@ function ($) { ...@@ -99,9 +99,9 @@ function ($) {
lasthoverIndex = hoverIndex; lasthoverIndex = hoverIndex;
} }
results.push({ value: value, hoverIndex: newhoverIndex }); results.push({ value: value, hoverIndex: newhoverIndex, series: series });
} else { } else {
results.push({ value: value, hoverIndex: hoverIndex }); results.push({ value: value, hoverIndex: hoverIndex, series: series });
} }
} }
...@@ -149,8 +149,8 @@ function ($) { ...@@ -149,8 +149,8 @@ function ($) {
timestamp = dashboard.formatDate(seriesHoverInfo.time); timestamp = dashboard.formatDate(seriesHoverInfo.time);
for (i = 0; i < seriesHoverInfo.length; i++) { for (i = 0; i < seriesHoverInfo.length; i++) {
series = seriesList[i];
hoverInfo = seriesHoverInfo[i]; hoverInfo = seriesHoverInfo[i];
series = hoverInfo.series;
value = series.formatValue(hoverInfo.value); value = series.formatValue(hoverInfo.value);
seriesHtml += '<div class="graph-tooltip-list-item"><div class="graph-tooltip-series-name">'; seriesHtml += '<div class="graph-tooltip-list-item"><div class="graph-tooltip-series-name">';
......
...@@ -125,6 +125,12 @@ function (angular, app, _, kbn, $) { ...@@ -125,6 +125,12 @@ function (angular, app, _, kbn, $) {
for (i = 0; i < seriesList.length; i++) { for (i = 0; i < seriesList.length; i++) {
var series = seriesList[i]; var series = seriesList[i];
// ignore empty series
if (panel.legend.hideEmpty && series.allIsNull) {
continue;
}
var html = '<div class="graph-legend-series'; var html = '<div class="graph-legend-series';
if (series.yaxis === 2) { html += ' pull-right'; } if (series.yaxis === 2) { html += ' pull-right'; }
if (scope.hiddenSeries[series.alias]) { html += ' graph-legend-series-hidden'; } if (scope.hiddenSeries[series.alias]) { html += ' graph-legend-series-hidden'; }
......
...@@ -128,10 +128,6 @@ function (angular, app, _, TimeSeries, kbn, PanelMeta) { ...@@ -128,10 +128,6 @@ function (angular, app, _, TimeSeries, kbn, PanelMeta) {
}; };
$scope.getDecimalsForValue = function(value) { $scope.getDecimalsForValue = function(value) {
var opts = {};
if (value === 0 || value === 1) {
return { decimals: 0, scaledDecimals: 0 };
}
var delta = value / 2; var delta = value / 2;
var dec = -Math.floor(Math.log(delta) / Math.LN10); var dec = -Math.floor(Math.log(delta) / Math.LN10);
...@@ -157,13 +153,12 @@ function (angular, app, _, TimeSeries, kbn, PanelMeta) { ...@@ -157,13 +153,12 @@ function (angular, app, _, TimeSeries, kbn, PanelMeta) {
size *= magn; size *= magn;
if (opts.minTickSize != null && size < opts.minTickSize) { // reduce starting decimals if not needed
size = opts.minTickSize; if (Math.floor(value) === value) { dec = 0; }
}
var result = {}; var result = {};
result.decimals = Math.max(0, dec); result.decimals = Math.max(0, dec);
result.scaledDecimals = result.decimals - Math.floor(Math.log(size) / Math.LN11) + 2; result.scaledDecimals = result.decimals - Math.floor(Math.log(size) / Math.LN10) + 2;
return result; return result;
}; };
......
...@@ -55,7 +55,7 @@ function (angular, app, _, $) { ...@@ -55,7 +55,7 @@ function (angular, app, _, $) {
function getColorForValue(value) { function getColorForValue(value) {
for (var i = data.thresholds.length - 1; i >= 0 ; i--) { for (var i = data.thresholds.length - 1; i >= 0 ; i--) {
if (value > data.thresholds[i]) { if (value >= data.thresholds[i]) {
return data.colorMap[i]; return data.colorMap[i];
} }
} }
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<i bs-tooltip="'Expand row'" data-placement="right" class="icon-caret-left pointer" ></i> <i bs-tooltip="'Expand row'" data-placement="right" class="icon-caret-left pointer" ></i>
</span> </span>
</div> </div>
<span class="row-text pointer" ng-click="toggle_row(row)" ng-bind="row.title"></span> <div class="row-text pointer" ng-click="toggle_row(row)" ng-bind="row.title"></div>
</div> </div>
<div class="row-open" ng-show="!row.collapse"> <div class="row-open" ng-show="!row.collapse">
<div class='row-tab bgSuccess dropdown' ng-show="row.editable"> <div class='row-tab bgSuccess dropdown' ng-show="row.editable">
......
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
<input type="text" <input type="text"
class="input-mini grafana-target-segment-input" class="input-mini grafana-target-segment-input"
ng-model="panel.cacheTimeout" ng-model="panel.cacheTimeout"
bs-tooltip="'Graphite parameter to overwride memcache default timeout (unit is seconds)'" bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'"
data-placement="right" data-placement="right"
spellcheck='false' spellcheck='false'
placeholder="60"> placeholder="60">
......
...@@ -117,18 +117,8 @@ function (angular, $, kbn, _, moment) { ...@@ -117,18 +117,8 @@ function (angular, $, kbn, _, moment) {
var newPanel = angular.copy(panel); var newPanel = angular.copy(panel);
newPanel.id = this.getNextPanelId(); newPanel.id = this.getNextPanelId();
while(rowIndex < this.rows.length) { var currentRow = this.rows[rowIndex];
var currentRow = this.rows[rowIndex]; currentRow.panels.push(newPanel);
if (this.rowSpan(currentRow) <= 9) {
currentRow.panels.push(newPanel);
return;
}
rowIndex++;
}
var newRow = angular.copy(row);
newRow.panels = [newPanel];
this.rows.push(newRow);
}; };
p.formatDate = function(date, format) { p.formatDate = function(date, format) {
......
define([ define([
'lodash' 'lodash',
'jquery'
], ],
function (_) { function (_, $) {
'use strict'; 'use strict';
var index = []; var index = [];
...@@ -157,7 +158,12 @@ function (_) { ...@@ -157,7 +158,12 @@ function (_) {
addFuncDef({ addFuncDef({
name: 'sumSeriesWithWildcards', name: 'sumSeriesWithWildcards',
category: categories.Combine, category: categories.Combine,
params: [{ name: "node", type: "int" }], params: [
{ name: "node", type: "int" },
{ name: "node", type: "int", optional: true },
{ name: "node", type: "int", optional: true },
{ name: "node", type: "int", optional: true }
],
defaultParams: [3] defaultParams: [3]
}); });
...@@ -329,6 +335,11 @@ function (_) { ...@@ -329,6 +335,11 @@ function (_) {
}); });
addFuncDef({ addFuncDef({
name: 'offsetToZero',
category: categories.Transform,
});
addFuncDef({
name: 'transformNull', name: 'transformNull',
category: categories.Transform, category: categories.Transform,
params: [{ name: "amount", type: "int", }], params: [{ name: "amount", type: "int", }],
...@@ -501,15 +512,15 @@ function (_) { ...@@ -501,15 +512,15 @@ function (_) {
addFuncDef({ addFuncDef({
name: 'movingAverage', name: 'movingAverage',
category: categories.Filter, category: categories.Filter,
params: [{ name: "window size", type: "int" }], params: [{ name: "windowSize", type: "int_or_interval", options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
defaultParams: [10] defaultParams: [10]
}); });
addFuncDef({ addFuncDef({
name: 'movingMedian', name: 'movingMedian',
category: categories.Filter, category: categories.Filter,
params: [{ name: "windowSize", type: "select", options: ['1min', '5min', '15min', '30min', '1hour'] }], params: [{ name: "windowSize", type: "int_or_interval", options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
defaultParams: ['1min'] defaultParams: ['5']
}); });
addFuncDef({ addFuncDef({
...@@ -561,6 +572,17 @@ function (_) { ...@@ -561,6 +572,17 @@ function (_) {
defaultParams: [5] defaultParams: [5]
}); });
addFuncDef({
name: 'useSeriesAbove',
category: categories.Filter,
params: [
{ name: "value", type: "int" },
{ name: "search", type: "string" },
{ name: "replace", type: "string" }
],
defaultParams: [0, 'search', 'replace']
});
_.each(categories, function(funcList, catName) { _.each(categories, function(funcList, catName) {
categories[catName] = _.sortBy(funcList, 'name'); categories[catName] = _.sortBy(funcList, 'name');
}); });
...@@ -584,6 +606,9 @@ function (_) { ...@@ -584,6 +606,9 @@ function (_) {
if (paramType === 'int' || paramType === 'value_or_series' || paramType === 'boolean') { if (paramType === 'int' || paramType === 'value_or_series' || paramType === 'boolean') {
return value; return value;
} }
else if (paramType === 'int_or_interval' && $.isNumeric(value)) {
return value;
}
return "'" + value + "'"; return "'" + value + "'";
......
...@@ -24,6 +24,7 @@ function (angular, _, $, config, kbn, moment) { ...@@ -24,6 +24,7 @@ function (angular, _, $, config, kbn, moment) {
this.supportMetrics = true; this.supportMetrics = true;
this.annotationEditorSrc = 'app/partials/graphite/annotation_editor.html'; this.annotationEditorSrc = 'app/partials/graphite/annotation_editor.html';
this.cacheTimeout = datasource.cacheTimeout; this.cacheTimeout = datasource.cacheTimeout;
this.withCredentials = datasource.withCredentials;
} }
GraphiteDatasource.prototype.query = function(options) { GraphiteDatasource.prototype.query = function(options) {
...@@ -209,8 +210,10 @@ function (angular, _, $, config, kbn, moment) { ...@@ -209,8 +210,10 @@ function (angular, _, $, config, kbn, moment) {
}; };
GraphiteDatasource.prototype.doGraphiteRequest = function(options) { GraphiteDatasource.prototype.doGraphiteRequest = function(options) {
if (this.basicAuth) { if (this.basicAuth || this.withCredentials) {
options.withCredentials = true; options.withCredentials = true;
}
if (this.basicAuth) {
options.headers = options.headers || {}; options.headers = options.headers || {};
options.headers.Authorization = 'Basic ' + this.basicAuth; options.headers.Authorization = 'Basic ' + this.basicAuth;
} }
......
...@@ -67,9 +67,16 @@ define([ ...@@ -67,9 +67,16 @@ define([
} }
if (this.match('identifier') || this.match('number')) { if (this.match('identifier') || this.match('number')) {
// hack to handle float numbers in metric segments
var parts = this.consumeToken().value.split('.');
if (parts.length === 2) {
this.tokens.splice(this.index, 0, { type: '.' });
this.tokens.splice(this.index + 1, 0, { type: 'number', value: parts[1] });
}
return { return {
type: 'segment', type: 'segment',
value: this.consumeToken().value value: parts[0]
}; };
} }
......
...@@ -438,6 +438,9 @@ select.grafana-target-segment-input { ...@@ -438,6 +438,9 @@ select.grafana-target-segment-input {
max-height: 600px; max-height: 600px;
overflow: hidden; overflow: hidden;
line-height: 14px; line-height: 14px;
a {
color: @tooltipLinkColor;
}
} }
.grafana-tooltip hr { .grafana-tooltip hr {
...@@ -445,8 +448,6 @@ select.grafana-target-segment-input { ...@@ -445,8 +448,6 @@ select.grafana-target-segment-input {
color: #c8c8c8; color: #c8c8c8;
margin: 0px; margin: 0px;
border-bottom:0px solid #c8c8c8; border-bottom:0px solid #c8c8c8;
/*height:0px;
background-color: rgb(58, 57, 57);*/
} }
.tooltip.in { .tooltip.in {
......
...@@ -181,6 +181,7 @@ form input.ng-invalid { ...@@ -181,6 +181,7 @@ form input.ng-invalid {
font-size: 0.9em; font-size: 0.9em;
text-align: center; text-align: center;
line-height: 31px; line-height: 31px;
height: 31px;
} }
.row-close { .row-close {
......
...@@ -280,6 +280,7 @@ ...@@ -280,6 +280,7 @@
@tooltipBackground: rgb(58, 57, 57); @tooltipBackground: rgb(58, 57, 57);
@tooltipArrowWidth: 5px; @tooltipArrowWidth: 5px;
@tooltipArrowColor: @tooltipBackground; @tooltipArrowColor: @tooltipBackground;
@tooltipLinkColor: @linkColor;
@popoverBackground: @heroUnitBackground; @popoverBackground: @heroUnitBackground;
@popoverArrowWidth: 10px; @popoverArrowWidth: 10px;
......
...@@ -289,6 +289,7 @@ ...@@ -289,6 +289,7 @@
@tooltipBackground: #000; @tooltipBackground: #000;
@tooltipArrowWidth: 5px; @tooltipArrowWidth: 5px;
@tooltipArrowColor: @tooltipBackground; @tooltipArrowColor: @tooltipBackground;
@tooltipLinkColor: darken(@white,11%);
@popoverBackground: @white; @popoverBackground: @white;
@popoverArrowWidth: 15px; @popoverArrowWidth: 15px;
......
...@@ -70,16 +70,6 @@ define([ ...@@ -70,16 +70,6 @@ define([
expect(dashboard.rows[0].panels[1].id).to.be(11); expect(dashboard.rows[0].panels[1].id).to.be(11);
}); });
it('duplicate should add row if there is no space left', function() {
var panel = { span: 12, attr: '123' };
dashboard.rows = [{ panels: [panel] }];
dashboard.duplicatePanel(panel, dashboard.rows[0]);
expect(dashboard.rows[0].panels[0].span).to.be(12);
expect(dashboard.rows[0].panels.length).to.be(1);
expect(dashboard.rows[1].panels[0].attr).to.be('123');
});
}); });
describe('when creating dashboard with editable false', function() { describe('when creating dashboard with editable false', function() {
......
...@@ -46,6 +46,18 @@ define([ ...@@ -46,6 +46,18 @@ define([
expect(func.render('hello')).to.equal("scaleToSeconds(hello, 1)"); expect(func.render('hello')).to.equal("scaleToSeconds(hello, 1)");
}); });
it('should handle int or interval params with number', function() {
var func = gfunc.createFuncInstance('movingMedian');
func.params[0] = '5';
expect(func.render('hello')).to.equal("movingMedian(hello, 5)");
});
it('should handle int or interval params with interval string', function() {
var func = gfunc.createFuncInstance('movingMedian');
func.params[0] = '5min';
expect(func.render('hello')).to.equal("movingMedian(hello, '5min')");
});
it('should handle metric param and int param and string param', function() { it('should handle metric param and int param and string param', function() {
var func = gfunc.createFuncInstance('groupByNode'); var func = gfunc.createFuncInstance('groupByNode');
func.params[0] = 5; func.params[0] = 5;
......
...@@ -136,6 +136,22 @@ define([ ...@@ -136,6 +136,22 @@ define([
}); });
}); });
describe('when getting altSegments and metricFindQuery retuns empty array', function() {
beforeEach(function() {
ctx.scope.target.target = 'test.count';
ctx.scope.datasource.metricFindQuery.returns(ctx.$q.when([]));
ctx.scope.init();
ctx.scope.getAltSegments(1);
ctx.scope.$digest();
ctx.scope.$parent = { get_data: sinon.spy() };
});
it('should have no segments', function() {
expect(ctx.scope.altSegments.length).to.be(0);
});
});
describe('targetChanged', function() { describe('targetChanged', function() {
beforeEach(function() { beforeEach(function() {
ctx.scope.datasource.metricFindQuery.returns(ctx.$q.when([{expandable: false}])); ctx.scope.datasource.metricFindQuery.returns(ctx.$q.when([{expandable: false}]));
......
...@@ -165,6 +165,14 @@ define([ ...@@ -165,6 +165,14 @@ define([
expect(rootNode.params[1].value).to.be('#B'); expect(rootNode.params[1].value).to.be('#B');
}); });
it('should parse metric expression with ip number segments', function() {
var parser = new Parser('5.10.123.5');
var rootNode = parser.getAst();
expect(rootNode.segments[0].value).to.be('5');
expect(rootNode.segments[1].value).to.be('10');
expect(rootNode.segments[2].value).to.be('123');
expect(rootNode.segments[3].value).to.be('5');
});
}); });
......
...@@ -39,7 +39,6 @@ angular.module("ang-drag-drop",[]) ...@@ -39,7 +39,6 @@ angular.module("ang-drag-drop",[])
element.attr("draggable", false); element.attr("draggable", false);
attrs.$observe("uiDraggable", function (newValue) { attrs.$observe("uiDraggable", function (newValue) {
console.log(newValue);
if(newValue){ if(newValue){
element.attr("draggable", newValue); element.attr("draggable", newValue);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment