mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Lots of progress on per series overrides
This commit is contained in:
parent
937ac84538
commit
c6489d9b01
@ -34,7 +34,7 @@
|
|||||||
"grunt-string-replace": "~0.2.4",
|
"grunt-string-replace": "~0.2.4",
|
||||||
"grunt-usemin": "^2.1.1",
|
"grunt-usemin": "^2.1.1",
|
||||||
"jshint-stylish": "~0.1.5",
|
"jshint-stylish": "~0.1.5",
|
||||||
"karma": "~0.12.16",
|
"karma": "~0.12.21",
|
||||||
"karma-chrome-launcher": "~0.1.4",
|
"karma-chrome-launcher": "~0.1.4",
|
||||||
"karma-coffee-preprocessor": "~0.1.2",
|
"karma-coffee-preprocessor": "~0.1.2",
|
||||||
"karma-coverage": "^0.2.5",
|
"karma-coverage": "^0.2.5",
|
||||||
|
@ -156,7 +156,7 @@ function (angular, $, kbn, moment, _) {
|
|||||||
for (var i = 0; i < data.length; i++) {
|
for (var i = 0; i < data.length; i++) {
|
||||||
var _d = data[i].getFlotPairs(panel.nullPointMode, panel.y_formats);
|
var _d = data[i].getFlotPairs(panel.nullPointMode, panel.y_formats);
|
||||||
data[i].data = _d;
|
data[i].data = _d;
|
||||||
data[0].lines = { show: false };
|
data[0].lines = { show: false, dashes: true };
|
||||||
data[0].bars = { show: true };
|
data[0].bars = { show: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 ng-include src="tab.src"></div>
|
||||||
</div>
|
</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([
|
define([
|
||||||
'angular',
|
'angular',
|
||||||
'app',
|
'app',
|
||||||
@ -19,6 +6,7 @@ define([
|
|||||||
'kbn',
|
'kbn',
|
||||||
'moment',
|
'moment',
|
||||||
'./timeSeries',
|
'./timeSeries',
|
||||||
|
'./seriesOverridesCtrl',
|
||||||
'services/panelSrv',
|
'services/panelSrv',
|
||||||
'services/annotationsSrv',
|
'services/annotationsSrv',
|
||||||
'services/datasourceSrv',
|
'services/datasourceSrv',
|
||||||
@ -30,10 +18,9 @@ define([
|
|||||||
'jquery.flot.stackpercent'
|
'jquery.flot.stackpercent'
|
||||||
],
|
],
|
||||||
function (angular, app, $, _, kbn, moment, timeSeries) {
|
function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var module = angular.module('grafana.panels.graph', []);
|
var module = angular.module('grafana.panels.graph');
|
||||||
app.useModule(module);
|
app.useModule(module);
|
||||||
|
|
||||||
module.controller('GraphCtrl', function($scope, $rootScope, $timeout, panelSrv, annotationsSrv) {
|
module.controller('GraphCtrl', function($scope, $rootScope, $timeout, panelSrv, annotationsSrv) {
|
||||||
@ -363,49 +350,11 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
|||||||
$scope.panel.seriesOverrides.push({});
|
$scope.panel.seriesOverrides.push({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.removeSeriesOverride = function(override) {
|
||||||
|
$scope.panel.seriesOverrides = _.without($scope.panel.seriesOverrides, override);
|
||||||
|
};
|
||||||
|
|
||||||
panelSrv.init($scope);
|
panelSrv.init($scope);
|
||||||
});
|
});
|
||||||
|
|
||||||
angular
|
|
||||||
.module('grafana.directives')
|
|
||||||
.directive('seriesOverrideOption', function($compile) {
|
|
||||||
var template =
|
|
||||||
'<div class="dropdown"> ' +
|
|
||||||
'<a class="dropdown-toggle" gf-dropdown="options" data-toggle="dropdown">' +
|
|
||||||
'<i class="icon-minus"></i></a>' +
|
|
||||||
'</div>';
|
|
||||||
|
|
||||||
return {
|
|
||||||
scope: true,
|
|
||||||
link: function($scope, elem, attrs) {
|
|
||||||
var $template = $(template);
|
|
||||||
elem.append($template);
|
|
||||||
var $link = $(elem).find('a');
|
|
||||||
|
|
||||||
$scope.options = $scope.$eval(attrs.options);
|
|
||||||
$scope.options.unshift(null);
|
|
||||||
|
|
||||||
$scope.options = _.map($scope.options, function(option, index) {
|
|
||||||
return {
|
|
||||||
text: option === null ? '<i class="icon-minus"></i>' : String(option),
|
|
||||||
value: option,
|
|
||||||
click: 'setValue(' + index + ')'
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.setValue = function(index) {
|
|
||||||
var value = $scope.options[index].value;
|
|
||||||
if (value === null) {
|
|
||||||
$link.html('<i class="icon-minus"></i>');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$link.html(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$compile(elem.contents())($scope);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
66
src/app/panels/graph/seriesOverridesCtrl.js
Normal file
66
src/app/panels/graph/seriesOverridesCtrl.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
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.removeOverride = function(option) {
|
||||||
|
delete $scope.override[option.propertyName];
|
||||||
|
$scope.updateCurrentOverrides();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.updateCurrentOverrides = function() {
|
||||||
|
$scope.currentOverrides = [];
|
||||||
|
_.each($scope.overrideMenu, function(option) {
|
||||||
|
if (!_.isUndefined($scope.override[option.propertyName])) {
|
||||||
|
$scope.currentOverrides.push({
|
||||||
|
name: option.text,
|
||||||
|
propertyName: option.propertyName,
|
||||||
|
value: String($scope.override[option.propertyName])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addOverrideOption('Bars', 'bars', [true, false]);
|
||||||
|
$scope.addOverrideOption('Lines', 'lines', [true, false]);
|
||||||
|
$scope.addOverrideOption('Points', 'points', [true, false]);
|
||||||
|
$scope.addOverrideOption('Line fill', 'fill', [1,2,3,4,5,6,7,8]);
|
||||||
|
$scope.updateCurrentOverrides();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -66,36 +66,43 @@
|
|||||||
<div class="editor-row">
|
<div class="editor-row">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h5>Series specific overrides</h5>
|
<h5>Series specific overrides</h5>
|
||||||
<table class="table table-striped">
|
|
||||||
<tr>
|
|
||||||
<th>Series alias/regex</th>
|
|
||||||
<th>Bars</th>
|
|
||||||
<th>Lines</th>
|
|
||||||
<th>Points</th>
|
|
||||||
<th>Fill</th>
|
|
||||||
<th>Width</th>
|
|
||||||
<th>Radius</th>
|
|
||||||
<th>Staircase</th>
|
|
||||||
<th>Stack</th>
|
|
||||||
<th>Y-axis</th>
|
|
||||||
<th>Z-index</th>
|
|
||||||
<th>Color</th>
|
|
||||||
</tr>
|
|
||||||
<tr ng-repeat="override in panel.seriesOverrides">
|
|
||||||
<td>
|
|
||||||
<input type="text" class="input input-medium">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<series-override-option data-options="[true, false]" data-attr="override.bars">
|
|
||||||
</series-override-option>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<series-override-option data-options="[1,2,3,4,5]">
|
|
||||||
</series-override-option>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<button class="btn btn-success" ng-click="addSeriesOverride()">Add</button>
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<a class="grafana-target-segment" ng-click="removeSeriesOverride(override)" role="menuitem">
|
||||||
|
<i class="icon-remove"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="grafana-segment-list">
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
alias or regex
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="text" class="input-medium grafana-target-segment-input" >
|
||||||
|
</li>
|
||||||
|
<li class="grafana-target-segment" ng-repeat="option in currentOverrides">
|
||||||
|
<a class="pointer" ng-click="removeOverride(option)">
|
||||||
|
<i class="icon-remove"></i>
|
||||||
|
</a>
|
||||||
|
{{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>
|
||||||
|
|
||||||
|
<button class="btn btn-success" style="margin-top: 20px" ng-click="addSeriesOverride()">Add series override rule</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -154,3 +154,17 @@
|
|||||||
.annotation-tags {
|
.annotation-tags {
|
||||||
color: @purple;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
68
src/test/specs/grafanaGraph-specs.js
Normal file
68
src/test/specs/grafanaGraph-specs.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
define([
|
||||||
|
'./helpers',
|
||||||
|
'angular',
|
||||||
|
'jquery',
|
||||||
|
'directives/grafanaGraph'
|
||||||
|
], function(helpers, angular, $) {
|
||||||
|
'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: []
|
||||||
|
};
|
||||||
|
scope.dashboard = { timezone: 'browser' };
|
||||||
|
scope.range = {
|
||||||
|
from: new Date('2014-08-09 10:00:00'),
|
||||||
|
to: new Date('2014-09-09 13:00:00')
|
||||||
|
};
|
||||||
|
|
||||||
|
setupFunc(scope);
|
||||||
|
|
||||||
|
$compile(element)(scope);
|
||||||
|
scope.$digest();
|
||||||
|
$.plot = ctx.plotSpy = sinon.spy();
|
||||||
|
|
||||||
|
scope.$emit('render', []);
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
40
src/test/specs/seriesOverridesCtrl-specs.js
Normal file
40
src/test/specs/seriesOverridesCtrl-specs.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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'));
|
||||||
|
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -122,6 +122,8 @@ require([
|
|||||||
'specs/graphiteTargetCtrl-specs',
|
'specs/graphiteTargetCtrl-specs',
|
||||||
'specs/influxdb-datasource-specs',
|
'specs/influxdb-datasource-specs',
|
||||||
'specs/graph-ctrl-specs',
|
'specs/graph-ctrl-specs',
|
||||||
|
'specs/grafanaGraph-specs',
|
||||||
|
'specs/seriesOverridesCtrl-specs',
|
||||||
'specs/filterSrv-specs',
|
'specs/filterSrv-specs',
|
||||||
'specs/kbn-format-specs',
|
'specs/kbn-format-specs',
|
||||||
'specs/dashboardSrv-specs',
|
'specs/dashboardSrv-specs',
|
||||||
|
Loading…
Reference in New Issue
Block a user