mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'series_style_overrides'
This commit is contained in:
commit
5bf794e24e
@ -34,7 +34,7 @@
|
||||
"grunt-string-replace": "~0.2.4",
|
||||
"grunt-usemin": "^2.1.1",
|
||||
"jshint-stylish": "~0.1.5",
|
||||
"karma": "~0.12.16",
|
||||
"karma": "~0.12.21",
|
||||
"karma-chrome-launcher": "~0.1.4",
|
||||
"karma-coffee-preprocessor": "~0.1.2",
|
||||
"karma-coverage": "^0.2.5",
|
||||
|
@ -5,15 +5,57 @@ define([
|
||||
function (_, kbn) {
|
||||
'use strict';
|
||||
|
||||
var ts = {};
|
||||
|
||||
ts.ZeroFilled = function (opts) {
|
||||
function TimeSeries(opts) {
|
||||
this.datapoints = opts.datapoints;
|
||||
this.info = opts.info;
|
||||
this.label = opts.info.alias;
|
||||
}
|
||||
|
||||
function matchSeriesOverride(aliasOrRegex, seriesAlias) {
|
||||
if (!aliasOrRegex) { return false; }
|
||||
|
||||
if (aliasOrRegex[0] === '/') {
|
||||
var match = aliasOrRegex.match(new RegExp('^/(.*?)/(g?i?m?y?)$'));
|
||||
var regex = new RegExp(match[1], match[2]);
|
||||
return seriesAlias.match(regex) != null;
|
||||
}
|
||||
|
||||
return aliasOrRegex === seriesAlias;
|
||||
}
|
||||
|
||||
function translateFillOption(fill) {
|
||||
return fill === 0 ? 0.001 : fill/10;
|
||||
}
|
||||
|
||||
TimeSeries.prototype.applySeriesOverrides = function(overrides) {
|
||||
this.lines = {};
|
||||
this.points = {};
|
||||
this.bars = {};
|
||||
this.info.yaxis = 1;
|
||||
this.zindex = 0;
|
||||
delete this.stack;
|
||||
|
||||
for (var i = 0; i < overrides.length; i++) {
|
||||
var override = overrides[i];
|
||||
if (!matchSeriesOverride(override.alias, this.info.alias)) {
|
||||
continue;
|
||||
}
|
||||
if (override.lines !== void 0) { this.lines.show = override.lines; }
|
||||
if (override.points !== void 0) { this.points.show = override.points; }
|
||||
if (override.bars !== void 0) { this.bars.show = override.bars; }
|
||||
if (override.fill !== void 0) { this.lines.fill = translateFillOption(override.fill); }
|
||||
if (override.stack !== void 0) { this.stack = override.stack; }
|
||||
if (override.linewidth !== void 0) { this.lines.lineWidth = override.linewidth; }
|
||||
if (override.pointradius !== void 0) { this.points.radius = override.pointradius; }
|
||||
if (override.steppedLine !== void 0) { this.lines.steps = override.steppedLine; }
|
||||
if (override.zindex !== void 0) { this.zindex = override.zindex; }
|
||||
if (override.yaxis !== void 0) {
|
||||
this.info.yaxis = override.yaxis;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ts.ZeroFilled.prototype.getFlotPairs = function (fillStyle, yFormats) {
|
||||
TimeSeries.prototype.getFlotPairs = function (fillStyle, yFormats) {
|
||||
var result = [];
|
||||
|
||||
this.color = this.info.color;
|
||||
@ -74,5 +116,6 @@ function (_, kbn) {
|
||||
return result;
|
||||
};
|
||||
|
||||
return ts;
|
||||
return TimeSeries;
|
||||
|
||||
});
|
@ -118,7 +118,7 @@ function (angular, $, kbn, moment, _) {
|
||||
lines: {
|
||||
show: panel.lines,
|
||||
zero: false,
|
||||
fill: panel.fill === 0 ? 0.001 : panel.fill/10,
|
||||
fill: translateFillOption(panel.fill),
|
||||
lineWidth: panel.linewidth,
|
||||
steps: panel.steppedLine
|
||||
},
|
||||
@ -154,11 +154,12 @@ function (angular, $, kbn, moment, _) {
|
||||
};
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var _d = data[i].getFlotPairs(panel.nullPointMode, panel.y_formats);
|
||||
data[i].data = _d;
|
||||
var series = data[i];
|
||||
series.applySeriesOverrides(panel.seriesOverrides);
|
||||
series.data = series.getFlotPairs(panel.nullPointMode, panel.y_formats);
|
||||
}
|
||||
|
||||
if (panel.bars && data.length && data[0].info.timeStep) {
|
||||
if (data.length && data[0].info.timeStep) {
|
||||
options.series.bars.barWidth = data[0].info.timeStep / 1.5;
|
||||
}
|
||||
|
||||
@ -167,21 +168,27 @@ function (angular, $, kbn, moment, _) {
|
||||
addAnnotations(options);
|
||||
configureAxisOptions(data, options);
|
||||
|
||||
var sortedSeries = _.sortBy(data, function(series) { return series.zindex; });
|
||||
|
||||
// if legend is to the right delay plot draw a few milliseconds
|
||||
// so the legend width calculation can be done
|
||||
if (shouldDelayDraw(panel)) {
|
||||
legendSideLastValue = panel.legend.rightSide;
|
||||
setTimeout(function() {
|
||||
plot = $.plot(elem, data, options);
|
||||
plot = $.plot(elem, sortedSeries, options);
|
||||
addAxisLabels();
|
||||
}, 50);
|
||||
}
|
||||
else {
|
||||
plot = $.plot(elem, data, options);
|
||||
plot = $.plot(elem, sortedSeries, options);
|
||||
addAxisLabels();
|
||||
}
|
||||
}
|
||||
|
||||
function translateFillOption(fill) {
|
||||
return fill === 0 ? 0.001 : fill/10;
|
||||
}
|
||||
|
||||
function shouldDelayDraw(panel) {
|
||||
if (panel.legend.rightSide) {
|
||||
return true;
|
||||
|
@ -34,12 +34,12 @@
|
||||
|
||||
<div class="editor-row small" style="padding-bottom: 0;">
|
||||
<label>Axis:</label>
|
||||
<button ng-click="toggleYAxis(series)"
|
||||
<button ng-click="toggleYAxis(series);dismiss();"
|
||||
class="btn btn-mini"
|
||||
ng-class="{'btn-success': series.yaxis === 1 }">
|
||||
Left
|
||||
</button>
|
||||
<button ng-click="toggleYAxis(series)"
|
||||
<button ng-click="toggleYAxis(series);dismiss();"
|
||||
class="btn btn-mini"
|
||||
ng-class="{'btn-success': series.yaxis === 2 }">
|
||||
Right
|
||||
|
@ -27,7 +27,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-content" ng-repeat="tab in panelMeta.fullEditorTabs" ng-show="editorTabs[editor.index] == tab.title">
|
||||
<div class="tab-content" ng-repeat="tab in panelMeta.fullEditorTabs" ng-if="editorTabs[editor.index] == tab.title">
|
||||
<div ng-include src="tab.src"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,16 +1,3 @@
|
||||
/** @scratch /panels/5
|
||||
* include::panels/histogram.asciidoc[]
|
||||
*/
|
||||
|
||||
/** @scratch /panels/histogram/0
|
||||
* == Histogram
|
||||
* Status: *Stable*
|
||||
*
|
||||
* The histogram panel allow for the display of time charts. It includes several modes and tranformations
|
||||
* to display event counts, mean, min, max and total of numeric fields, and derivatives of counter
|
||||
* fields.
|
||||
*
|
||||
*/
|
||||
define([
|
||||
'angular',
|
||||
'app',
|
||||
@ -18,7 +5,8 @@ define([
|
||||
'lodash',
|
||||
'kbn',
|
||||
'moment',
|
||||
'./timeSeries',
|
||||
'components/timeSeries',
|
||||
'./seriesOverridesCtrl',
|
||||
'services/panelSrv',
|
||||
'services/annotationsSrv',
|
||||
'services/datasourceSrv',
|
||||
@ -29,11 +17,10 @@ define([
|
||||
'jquery.flot.stack',
|
||||
'jquery.flot.stackpercent'
|
||||
],
|
||||
function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
|
||||
function (angular, app, $, _, kbn, moment, TimeSeries) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.panels.graph', []);
|
||||
var module = angular.module('grafana.panels.graph');
|
||||
app.useModule(module);
|
||||
|
||||
module.controller('GraphCtrl', function($scope, $rootScope, $timeout, panelSrv, annotationsSrv) {
|
||||
@ -179,7 +166,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
targets: [{}],
|
||||
|
||||
aliasColors: {},
|
||||
aliasYAxis: {},
|
||||
|
||||
seriesOverrides: [],
|
||||
};
|
||||
|
||||
_.defaults($scope.panel,_d);
|
||||
@ -258,18 +246,15 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
var datapoints = seriesData.datapoints;
|
||||
var alias = seriesData.target;
|
||||
var color = $scope.panel.aliasColors[alias] || $rootScope.colors[index];
|
||||
var yaxis = $scope.panel.aliasYAxis[alias] || 1;
|
||||
|
||||
var seriesInfo = {
|
||||
alias: alias,
|
||||
color: color,
|
||||
enable: true,
|
||||
yaxis: yaxis
|
||||
};
|
||||
|
||||
$scope.legend.push(seriesInfo);
|
||||
|
||||
var series = new timeSeries.ZeroFilled({
|
||||
var series = new TimeSeries({
|
||||
datapoints: datapoints,
|
||||
info: seriesInfo,
|
||||
});
|
||||
@ -347,8 +332,12 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
};
|
||||
|
||||
$scope.toggleYAxis = function(info) {
|
||||
info.yaxis = info.yaxis === 2 ? 1 : 2;
|
||||
$scope.panel.aliasYAxis[info.alias] = info.yaxis;
|
||||
var override = _.findWhere($scope.panel.seriesOverrides, { alias: info.alias });
|
||||
if (!override) {
|
||||
override = { alias: info.alias };
|
||||
$scope.panel.seriesOverrides.push(override);
|
||||
}
|
||||
override.yaxis = info.yaxis === 2 ? 1 : 2;
|
||||
$scope.render();
|
||||
};
|
||||
|
||||
@ -357,6 +346,15 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
$scope.render();
|
||||
};
|
||||
|
||||
$scope.addSeriesOverride = function() {
|
||||
$scope.panel.seriesOverrides.push({});
|
||||
};
|
||||
|
||||
$scope.removeSeriesOverride = function(override) {
|
||||
$scope.panel.seriesOverrides = _.without($scope.panel.seriesOverrides, override);
|
||||
$scope.render();
|
||||
};
|
||||
|
||||
panelSrv.init($scope);
|
||||
});
|
||||
|
||||
|
80
src/app/panels/graph/seriesOverridesCtrl.js
Normal file
80
src/app/panels/graph/seriesOverridesCtrl.js
Normal file
@ -0,0 +1,80 @@
|
||||
define([
|
||||
'angular',
|
||||
'app',
|
||||
'lodash',
|
||||
], function(angular, app, _) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.panels.graph', []);
|
||||
app.useModule(module);
|
||||
|
||||
module.controller('SeriesOverridesCtrl', function($scope) {
|
||||
$scope.overrideMenu = [];
|
||||
$scope.currentOverrides = [];
|
||||
$scope.override = $scope.override || {};
|
||||
|
||||
$scope.addOverrideOption = function(name, propertyName, values) {
|
||||
var option = {};
|
||||
option.text = name;
|
||||
option.propertyName = propertyName;
|
||||
option.index = $scope.overrideMenu.length;
|
||||
option.values = values;
|
||||
|
||||
option.submenu = _.map(values, function(value, index) {
|
||||
return {
|
||||
text: String(value),
|
||||
click: 'setOverride(' + option.index + ',' + index + ')'
|
||||
};
|
||||
});
|
||||
|
||||
$scope.overrideMenu.push(option);
|
||||
};
|
||||
|
||||
$scope.setOverride = function(optionIndex, valueIndex) {
|
||||
var option = $scope.overrideMenu[optionIndex];
|
||||
var value = option.values[valueIndex];
|
||||
$scope.override[option.propertyName] = value;
|
||||
$scope.updateCurrentOverrides();
|
||||
$scope.render();
|
||||
};
|
||||
|
||||
$scope.removeOverride = function(option) {
|
||||
delete $scope.override[option.propertyName];
|
||||
$scope.updateCurrentOverrides();
|
||||
$scope.render();
|
||||
};
|
||||
|
||||
$scope.getSeriesNames = function() {
|
||||
return _.map($scope.legend, function(info) {
|
||||
return info.alias;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateCurrentOverrides = function() {
|
||||
$scope.currentOverrides = [];
|
||||
_.each($scope.overrideMenu, function(option) {
|
||||
var value = $scope.override[option.propertyName];
|
||||
if (_.isUndefined(value)) { return; }
|
||||
$scope.currentOverrides.push({
|
||||
name: option.text,
|
||||
propertyName: option.propertyName,
|
||||
value: String(value)
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addOverrideOption('Bars', 'bars', [true, false]);
|
||||
$scope.addOverrideOption('Lines', 'lines', [true, false]);
|
||||
$scope.addOverrideOption('Line fill', 'fill', [0,1,2,3,4,5,6,7,8,9,10]);
|
||||
$scope.addOverrideOption('Line width', 'linewidth', [0,1,2,3,4,5,6,7,8,9,10]);
|
||||
$scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
|
||||
$scope.addOverrideOption('Points', 'points', [true, false]);
|
||||
$scope.addOverrideOption('Points Radius', 'pointradius', [1,2,3,4,5]);
|
||||
$scope.addOverrideOption('Stack', 'stack', [true, false]);
|
||||
$scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
|
||||
$scope.addOverrideOption('Z-index', 'zindex', [-1,-2,-3,0,1,2,3]);
|
||||
$scope.updateCurrentOverrides();
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="section">
|
||||
<h5>Chart Options</h5>
|
||||
@ -64,3 +62,49 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="section">
|
||||
<h5>Series specific overrides <tip>Regex match example: /server[0-3]/i </tip></h5>
|
||||
<div>
|
||||
<div class="grafana-target" ng-repeat="override in panel.seriesOverrides" ng-controller="SeriesOverridesCtrl">
|
||||
<div class="grafana-target-inner-wrapper">
|
||||
<div class="grafana-target-inner">
|
||||
|
||||
<ul class="grafana-target-controls-left">
|
||||
<li class="grafana-target-segment">
|
||||
<i class="icon-remove pointer" ng-click="removeSeriesOverride(override)"></i>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="grafana-segment-list">
|
||||
<li class="grafana-target-segment">
|
||||
alias or regex
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
ng-model="override.alias"
|
||||
bs-typeahead="getSeriesNames"
|
||||
ng-blur="render()"
|
||||
data-min-length=0 data-items=100
|
||||
class="input-medium grafana-target-segment-input" >
|
||||
</li>
|
||||
<li class="grafana-target-segment" ng-repeat="option in currentOverrides">
|
||||
<i class="pointer icon-remove" ng-click="removeOverride(option)"></i>
|
||||
{{option.name}}: {{option.value}}
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle grafana-target-segment" data-toggle="dropdown" gf-dropdown="overrideMenu" bs-tooltip="'set option to override'">
|
||||
<i class="icon-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-success" style="margin-top: 20px" ng-click="addSeriesOverride()">Add series override rule</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -144,33 +144,17 @@ function (angular, $, kbn, _, moment) {
|
||||
};
|
||||
|
||||
p.updateSchema = function(old) {
|
||||
var i, j, row, panel;
|
||||
var oldVersion = this.version;
|
||||
this.version = 3;
|
||||
var panelUpgrades = [];
|
||||
this.version = 4;
|
||||
|
||||
if (oldVersion === 3) {
|
||||
if (oldVersion === 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Version 3 schema changes
|
||||
// ensure panel ids
|
||||
var maxId = this.getNextPanelId();
|
||||
for (i = 0; i < this.rows.length; i++) {
|
||||
row = this.rows[i];
|
||||
for (j = 0; j < row.panels.length; j++) {
|
||||
panel = row.panels[j];
|
||||
if (!panel.id) {
|
||||
panel.id = maxId;
|
||||
maxId += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// version 2 schema changes
|
||||
if (oldVersion < 2) {
|
||||
|
||||
if (oldVersion === 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Version 2 schema changes
|
||||
if (old.services) {
|
||||
if (old.services.filter) {
|
||||
this.time = old.services.filter.time;
|
||||
@ -179,19 +163,18 @@ function (angular, $, kbn, _, moment) {
|
||||
delete this.services;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.rows.length; i++) {
|
||||
row = this.rows[i];
|
||||
for (j = 0; j < row.panels.length; j++) {
|
||||
panel = row.panels[j];
|
||||
panelUpgrades.push(function(panel) {
|
||||
// rename panel type
|
||||
if (panel.type === 'graphite') {
|
||||
panel.type = 'graph';
|
||||
}
|
||||
|
||||
if (panel.type === 'graph') {
|
||||
if (_.isBoolean(panel.legend)) {
|
||||
panel.legend = { show: panel.legend };
|
||||
if (panel.type !== 'graph') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_.isBoolean(panel.legend)) { panel.legend = { show: panel.legend }; }
|
||||
|
||||
if (panel.grid) {
|
||||
if (panel.grid.min) {
|
||||
panel.grid.leftMin = panel.grid.min;
|
||||
@ -213,11 +196,45 @@ function (angular, $, kbn, _, moment) {
|
||||
panel.y_formats[1] = panel.y2_format;
|
||||
delete panel.y2_format;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.version = 3;
|
||||
// schema version 3 changes
|
||||
if (oldVersion < 3) {
|
||||
// ensure panel ids
|
||||
var maxId = this.getNextPanelId();
|
||||
panelUpgrades.push(function(panel) {
|
||||
if (!panel.id) {
|
||||
panel.id = maxId;
|
||||
maxId += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// schema version 4 changes
|
||||
if (oldVersion < 4) {
|
||||
// move aliasYAxis changes
|
||||
panelUpgrades.push(function(panel) {
|
||||
if (panel.type !== 'graph') { return; }
|
||||
_.each(panel.aliasYAxis, function(value, key) {
|
||||
panel.seriesOverrides = [{ alias: key, yaxis: value }];
|
||||
});
|
||||
delete panel.aliasYAxis;
|
||||
});
|
||||
}
|
||||
|
||||
if (panelUpgrades.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.rows.length; i++) {
|
||||
var row = this.rows[i];
|
||||
for (var j = 0; j < row.panels.length; j++) {
|
||||
for (var k = 0; k < panelUpgrades.length; k++) {
|
||||
panelUpgrades[k](row.panels[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -104,7 +104,7 @@ function (angular, _) {
|
||||
|
||||
// Post init phase
|
||||
$scope.fullscreen = false;
|
||||
$scope.editor = { index: 1 };
|
||||
$scope.editor = { index: 3 };
|
||||
if ($scope.panelMeta.fullEditorTabs) {
|
||||
$scope.editorTabs = _.pluck($scope.panelMeta.fullEditorTabs, 'title');
|
||||
}
|
||||
|
@ -154,3 +154,17 @@
|
||||
.annotation-tags {
|
||||
color: @purple;
|
||||
}
|
||||
|
||||
.graph-series-override {
|
||||
input {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.graph-series-override-option {
|
||||
float: left;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
.graph-series-override-selector {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ define([
|
||||
{
|
||||
type: 'graphite',
|
||||
legend: true,
|
||||
aliasYAxis: { test: 2 },
|
||||
grid: { min: 1, max: 10 }
|
||||
}
|
||||
]
|
||||
@ -134,8 +135,13 @@ define([
|
||||
expect(graph.grid.leftMax).to.be(10);
|
||||
});
|
||||
|
||||
it('move aliasYAxis to series override', function() {
|
||||
expect(graph.seriesOverrides[0].alias).to.be("test");
|
||||
expect(graph.seriesOverrides[0].yaxis).to.be(2);
|
||||
});
|
||||
|
||||
it('dashboard schema version should be set to latest', function() {
|
||||
expect(model.version).to.be(3);
|
||||
expect(model.version).to.be(4);
|
||||
});
|
||||
|
||||
});
|
||||
|
107
src/test/specs/grafanaGraph-specs.js
Normal file
107
src/test/specs/grafanaGraph-specs.js
Normal file
@ -0,0 +1,107 @@
|
||||
define([
|
||||
'./helpers',
|
||||
'angular',
|
||||
'jquery',
|
||||
'components/timeSeries',
|
||||
'directives/grafanaGraph'
|
||||
], function(helpers, angular, $, TimeSeries) {
|
||||
'use strict';
|
||||
|
||||
describe('grafanaGraph', function() {
|
||||
|
||||
beforeEach(module('grafana.directives'));
|
||||
|
||||
function graphScenario(desc, func) {
|
||||
describe(desc, function() {
|
||||
var ctx = {};
|
||||
ctx.setup = function (setupFunc) {
|
||||
beforeEach(inject(function($rootScope, $compile) {
|
||||
var scope = $rootScope.$new();
|
||||
var element = angular.element("<div style='width:500px' grafana-graph><div>");
|
||||
|
||||
scope.height = '200px';
|
||||
scope.panel = {
|
||||
legend: {},
|
||||
grid: {},
|
||||
y_formats: [],
|
||||
seriesOverrides: []
|
||||
};
|
||||
scope.dashboard = { timezone: 'browser' };
|
||||
scope.range = {
|
||||
from: new Date('2014-08-09 10:00:00'),
|
||||
to: new Date('2014-09-09 13:00:00')
|
||||
};
|
||||
ctx.data = [];
|
||||
ctx.data.push(new TimeSeries({
|
||||
datapoints: [[1,1],[2,2]],
|
||||
info: { alias: 'series1', enable: true }
|
||||
}));
|
||||
ctx.data.push(new TimeSeries({
|
||||
datapoints: [[1,1],[2,2]],
|
||||
info: { alias: 'series2', enable: true }
|
||||
}));
|
||||
|
||||
setupFunc(scope, ctx.data);
|
||||
|
||||
$compile(element)(scope);
|
||||
scope.$digest();
|
||||
$.plot = ctx.plotSpy = sinon.spy();
|
||||
|
||||
scope.$emit('render', ctx.data);
|
||||
ctx.plotData = ctx.plotSpy.getCall(0).args[1];
|
||||
ctx.plotOptions = ctx.plotSpy.getCall(0).args[2];
|
||||
}));
|
||||
};
|
||||
|
||||
func(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
graphScenario('simple lines options', function(ctx) {
|
||||
ctx.setup(function(scope) {
|
||||
scope.panel.lines = true;
|
||||
scope.panel.fill = 5;
|
||||
scope.panel.linewidth = 3;
|
||||
scope.panel.steppedLine = true;
|
||||
});
|
||||
|
||||
it('should configure plot with correct options', function() {
|
||||
expect(ctx.plotOptions.series.lines.show).to.be(true);
|
||||
expect(ctx.plotOptions.series.lines.fill).to.be(0.5);
|
||||
expect(ctx.plotOptions.series.lines.lineWidth).to.be(3);
|
||||
expect(ctx.plotOptions.series.lines.steps).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
graphScenario('series option overrides, fill & points', function(ctx) {
|
||||
ctx.setup(function(scope, data) {
|
||||
scope.panel.lines = true;
|
||||
scope.panel.fill = 5;
|
||||
scope.panel.seriesOverrides = [
|
||||
{ alias: 'test', fill: 0, points: true }
|
||||
];
|
||||
|
||||
data[1].info.alias = 'test';
|
||||
});
|
||||
|
||||
it('should match second series and fill zero, and enable points', function() {
|
||||
expect(ctx.plotOptions.series.lines.fill).to.be(0.5);
|
||||
expect(ctx.plotData[1].lines.fill).to.be(0.001);
|
||||
expect(ctx.plotData[1].points.show).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
graphScenario('should order series order according to zindex', function(ctx) {
|
||||
ctx.setup(function(scope) {
|
||||
scope.panel.seriesOverrides = [{ alias: 'series1', zindex: 2 }];
|
||||
});
|
||||
|
||||
it('should move zindex 2 last', function() {
|
||||
expect(ctx.plotData[0].info.alias).to.be('series2');
|
||||
expect(ctx.plotData[1].info.alias).to.be('series1');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
51
src/test/specs/seriesOverridesCtrl-specs.js
Normal file
51
src/test/specs/seriesOverridesCtrl-specs.js
Normal file
@ -0,0 +1,51 @@
|
||||
define([
|
||||
'./helpers',
|
||||
'panels/graph/seriesOverridesCtrl'
|
||||
], function(helpers) {
|
||||
'use strict';
|
||||
|
||||
describe('SeriesOverridesCtrl', function() {
|
||||
var ctx = new helpers.ControllerTestContext();
|
||||
|
||||
beforeEach(module('grafana.services'));
|
||||
beforeEach(module('grafana.panels.graph'));
|
||||
|
||||
beforeEach(ctx.providePhase());
|
||||
beforeEach(ctx.createControllerPhase('SeriesOverridesCtrl'));
|
||||
beforeEach(function() {
|
||||
ctx.scope.render = function() {};
|
||||
});
|
||||
|
||||
describe('Controller should init overrideMenu', function() {
|
||||
it('click should include option and value index', function() {
|
||||
expect(ctx.scope.overrideMenu[1].submenu[1].click).to.be('setOverride(1,1)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When setting an override', function() {
|
||||
beforeEach(function() {
|
||||
ctx.scope.setOverride(1, 0);
|
||||
});
|
||||
|
||||
it('should set override property', function() {
|
||||
expect(ctx.scope.override.lines).to.be(true);
|
||||
});
|
||||
|
||||
it('should update view model', function() {
|
||||
expect(ctx.scope.currentOverrides[0].name).to.be('Lines');
|
||||
expect(ctx.scope.currentOverrides[0].value).to.be('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When removing overide', function() {
|
||||
it('click should include option and value index', function() {
|
||||
ctx.scope.setOverride(1,0);
|
||||
ctx.scope.removeOverride({ propertyName: 'lines' });
|
||||
expect(ctx.scope.currentOverrides.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
115
src/test/specs/timeSeries-specs.js
Normal file
115
src/test/specs/timeSeries-specs.js
Normal file
@ -0,0 +1,115 @@
|
||||
define([
|
||||
'components/timeSeries'
|
||||
], function(TimeSeries) {
|
||||
'use strict';
|
||||
|
||||
describe("TimeSeries", function() {
|
||||
var points, series;
|
||||
var yAxisFormats = ['short', 'ms'];
|
||||
var testData = {
|
||||
info: { alias: 'test' },
|
||||
datapoints: [
|
||||
[1,2],[null,3],[10,4],[8,5]
|
||||
]
|
||||
};
|
||||
|
||||
describe('when getting flot pairs', function() {
|
||||
it('with connected style, should ignore nulls', function() {
|
||||
series = new TimeSeries(testData);
|
||||
points = series.getFlotPairs('connected', yAxisFormats);
|
||||
expect(points.length).to.be(3);
|
||||
});
|
||||
|
||||
it('with null as zero style, should replace nulls with zero', function() {
|
||||
series = new TimeSeries(testData);
|
||||
points = series.getFlotPairs('null as zero', yAxisFormats);
|
||||
expect(points.length).to.be(4);
|
||||
expect(points[1][1]).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('series overrides', function() {
|
||||
var series;
|
||||
beforeEach(function() {
|
||||
series = new TimeSeries(testData);
|
||||
});
|
||||
|
||||
describe('fill & points', function() {
|
||||
beforeEach(function() {
|
||||
series.info.alias = 'test';
|
||||
series.applySeriesOverrides([{ alias: 'test', fill: 0, points: true }]);
|
||||
});
|
||||
|
||||
it('should set fill zero, and enable points', function() {
|
||||
expect(series.lines.fill).to.be(0.001);
|
||||
expect(series.points.show).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('series option overrides, bars, true & lines false', function() {
|
||||
beforeEach(function() {
|
||||
series.info.alias = 'test';
|
||||
series.applySeriesOverrides([{ alias: 'test', bars: true, lines: false }]);
|
||||
});
|
||||
|
||||
it('should disable lines, and enable bars', function() {
|
||||
expect(series.lines.show).to.be(false);
|
||||
expect(series.bars.show).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('series option overrides, linewidth, stack', function() {
|
||||
beforeEach(function() {
|
||||
series.info.alias = 'test';
|
||||
series.applySeriesOverrides([{ alias: 'test', linewidth: 5, stack: false }]);
|
||||
});
|
||||
|
||||
it('should disable stack, and set lineWidth', function() {
|
||||
expect(series.stack).to.be(false);
|
||||
expect(series.lines.lineWidth).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('series option overrides, pointradius, steppedLine', function() {
|
||||
beforeEach(function() {
|
||||
series.info.alias = 'test';
|
||||
series.applySeriesOverrides([{ alias: 'test', pointradius: 5, steppedLine: true }]);
|
||||
});
|
||||
|
||||
it('should set pointradius, and set steppedLine', function() {
|
||||
expect(series.points.radius).to.be(5);
|
||||
expect(series.lines.steps).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('override match on regex', function() {
|
||||
beforeEach(function() {
|
||||
series.info.alias = 'test_01';
|
||||
series.applySeriesOverrides([{ alias: '/.*01/', lines: false }]);
|
||||
});
|
||||
|
||||
it('should match second series', function() {
|
||||
expect(series.lines.show).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('override series y-axis, and z-index', function() {
|
||||
beforeEach(function() {
|
||||
series.info.alias = 'test';
|
||||
series.applySeriesOverrides([{ alias: 'test', yaxis: 2, zindex: 2 }]);
|
||||
});
|
||||
|
||||
it('should set yaxis', function() {
|
||||
expect(series.info.yaxis).to.be(2);
|
||||
});
|
||||
|
||||
it('should set zindex', function() {
|
||||
expect(series.zindex).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -118,10 +118,13 @@ require([
|
||||
'specs/lexer-specs',
|
||||
'specs/parser-specs',
|
||||
'specs/gfunc-specs',
|
||||
'specs/timeSeries-specs',
|
||||
'specs/row-ctrl-specs',
|
||||
'specs/graphiteTargetCtrl-specs',
|
||||
'specs/influxdb-datasource-specs',
|
||||
'specs/graph-ctrl-specs',
|
||||
'specs/grafanaGraph-specs',
|
||||
'specs/seriesOverridesCtrl-specs',
|
||||
'specs/filterSrv-specs',
|
||||
'specs/kbn-format-specs',
|
||||
'specs/dashboardSrv-specs',
|
||||
|
Loading…
Reference in New Issue
Block a user