diff --git a/package.json b/package.json index 31c552fe6c2..eecf826776e 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/app/panels/graph/timeSeries.js b/src/app/components/timeSeries.js similarity index 51% rename from src/app/panels/graph/timeSeries.js rename to src/app/components/timeSeries.js index f1794cd6a30..85c27f1da88 100644 --- a/src/app/panels/graph/timeSeries.js +++ b/src/app/components/timeSeries.js @@ -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; -}); \ No newline at end of file + return TimeSeries; + +}); diff --git a/src/app/directives/addGraphiteFunc.js b/src/app/directives/addGraphiteFunc.js index ca5943da508..6898b838845 100644 --- a/src/app/directives/addGraphiteFunc.js +++ b/src/app/directives/addGraphiteFunc.js @@ -97,4 +97,4 @@ function (angular, app, _, $, gfunc) { }; }); } -}); \ No newline at end of file +}); diff --git a/src/app/directives/grafanaGraph.js b/src/app/directives/grafanaGraph.js index a91967b967b..38ef36bc912 100755 --- a/src/app/directives/grafanaGraph.js +++ b/src/app/directives/grafanaGraph.js @@ -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; diff --git a/src/app/panels/graph/legend.html b/src/app/panels/graph/legend.html index 5524a8047fe..0e5edc459ce 100755 --- a/src/app/panels/graph/legend.html +++ b/src/app/panels/graph/legend.html @@ -34,12 +34,12 @@
- -
-
+
diff --git a/src/app/panels/graph/module.js b/src/app/panels/graph/module.js index 647e52c257e..6897cc090b0 100644 --- a/src/app/panels/graph/module.js +++ b/src/app/panels/graph/module.js @@ -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); }); diff --git a/src/app/panels/graph/seriesOverridesCtrl.js b/src/app/panels/graph/seriesOverridesCtrl.js new file mode 100644 index 00000000000..4f54c6d0e6f --- /dev/null +++ b/src/app/panels/graph/seriesOverridesCtrl.js @@ -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(); + + }); + +}); diff --git a/src/app/panels/graph/styleEditor.html b/src/app/panels/graph/styleEditor.html index ec18121cba7..de7318d4500 100644 --- a/src/app/panels/graph/styleEditor.html +++ b/src/app/panels/graph/styleEditor.html @@ -1,5 +1,3 @@ - -
Chart Options
@@ -64,3 +62,49 @@
+ +
+
+
Series specific overrides Regex match example: /server[0-3]/i
+
+
+
+
+ +
    +
  • + +
  • +
+ +
    +
  • + alias or regex +
  • +
  • + +
  • +
  • + + {{option.name}}: {{option.value}} +
  • + +
+
+
+
+
+
+ + +
+
diff --git a/src/app/services/dashboard/dashboardSrv.js b/src/app/services/dashboard/dashboardSrv.js index ff1e149c3b7..f2d67bf1839 100644 --- a/src/app/services/dashboard/dashboardSrv.js +++ b/src/app/services/dashboard/dashboardSrv.js @@ -144,80 +144,97 @@ 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 (old.services) { + if (old.services.filter) { + this.time = old.services.filter.time; + this.templating.list = old.services.filter.list; } + delete this.services; } - } - if (oldVersion === 2) { - return; - } - - // Version 2 schema changes - if (old.services) { - if (old.services.filter) { - this.time = old.services.filter.time; - this.templating.list = old.services.filter.list; - } - 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; + delete panel.grid.min; } - if (panel.grid) { - if (panel.grid.min) { - panel.grid.leftMin = panel.grid.min; - delete panel.grid.min; - } - - if (panel.grid.max) { - panel.grid.leftMax = panel.grid.max; - delete panel.grid.max; - } + if (panel.grid.max) { + panel.grid.leftMax = panel.grid.max; + delete panel.grid.max; } + } - if (panel.y_format) { - panel.y_formats[0] = panel.y_format; - delete panel.y_format; - } + if (panel.y_format) { + panel.y_formats[0] = panel.y_format; + delete panel.y_format; + } - if (panel.y2_format) { - panel.y_formats[1] = panel.y2_format; - delete panel.y2_format; - } + if (panel.y2_format) { + panel.y_formats[1] = panel.y2_format; + delete panel.y2_format; + } + }); + } + + // 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]); } } } - - this.version = 3; }; return { diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index 3c362818f2d..cae4f14ff98 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -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'); } diff --git a/src/css/less/graph.less b/src/css/less/graph.less index 79e87ab8f47..8f049a44ae5 100644 --- a/src/css/less/graph.less +++ b/src/css/less/graph.less @@ -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; + } +} diff --git a/src/test/specs/dashboardSrv-specs.js b/src/test/specs/dashboardSrv-specs.js index 5e4e96401de..a2c7c1772f6 100644 --- a/src/test/specs/dashboardSrv-specs.js +++ b/src/test/specs/dashboardSrv-specs.js @@ -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); }); }); diff --git a/src/test/specs/grafanaGraph-specs.js b/src/test/specs/grafanaGraph-specs.js new file mode 100644 index 00000000000..5f3ad0dd413 --- /dev/null +++ b/src/test/specs/grafanaGraph-specs.js @@ -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("
"); + + 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'); + }); + }); + + }); +}); + diff --git a/src/test/specs/helpers.js b/src/test/specs/helpers.js index cd31779cc99..de2be527f9f 100644 --- a/src/test/specs/helpers.js +++ b/src/test/specs/helpers.js @@ -69,7 +69,7 @@ define([ } return { from : kbn.parseDate(this.time.from), - to : kbn.parseDate(this.time.to) + to : kbn.parseDate(this.time.to) }; }; diff --git a/src/test/specs/seriesOverridesCtrl-specs.js b/src/test/specs/seriesOverridesCtrl-specs.js new file mode 100644 index 00000000000..e211b6dab35 --- /dev/null +++ b/src/test/specs/seriesOverridesCtrl-specs.js @@ -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); + }); + }); + + }); + +}); + diff --git a/src/test/specs/timeSeries-specs.js b/src/test/specs/timeSeries-specs.js new file mode 100644 index 00000000000..cf28c1aa450 --- /dev/null +++ b/src/test/specs/timeSeries-specs.js @@ -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); + }); + }); + + }); + + }); + +}); diff --git a/src/test/test-main.js b/src/test/test-main.js index 9c7cfe73341..4e231c8c1aa 100644 --- a/src/test/test-main.js +++ b/src/test/test-main.js @@ -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',