Commit dbafc8c9 by Torkel Ödegaard

feat(plugins): work on plugin directive loading

parent 6c6c3a50
...@@ -4,4 +4,5 @@ define([ ...@@ -4,4 +4,5 @@ define([
'./panel_srv', './panel_srv',
'./panel_helper', './panel_helper',
'./solo_panel_ctrl', './solo_panel_ctrl',
'./panel_loader',
], function () {}); ], function () {});
define([ define([
'angular', 'angular',
'jquery', 'jquery',
'app/core/config',
], ],
function (angular, $, config) { function (angular, $) {
'use strict'; 'use strict';
var module = angular.module('grafana.directives'); var module = angular.module('grafana.directives');
module.directive('panelLoader', function($compile, $parse) {
return {
restrict: 'E',
link: function(scope, elem, attr) {
var getter = $parse(attr.type), panelType = getter(scope);
var module = config.panels[panelType].module;
System.import(module).then(function() {
var panelEl = angular.element(document.createElement('grafana-panel-' + panelType));
elem.append(panelEl);
$compile(panelEl)(scope);
}).catch(function(err) {
console.log('Failed to load panel:', err);
scope.appEvent('alert-error', ['Panel Load Error', 'Failed to load panel ' + panelType + ', ' + err]);
});
}
};
});
module.directive('grafanaPanel', function() { module.directive('grafanaPanel', function() {
return { return {
restrict: 'E', restrict: 'E',
......
///<reference path="../../headers/common.d.ts" />
import angular from 'angular';
import config from 'app/core/config';
/** @ngInject */
function panelLoader($parse, dynamicDirectiveSrv) {
return dynamicDirectiveSrv.create({
directive: scope => {
let modulePath = config.panels[scope.panel.type].module;
return System.import(modulePath).then(function(panelModule) {
return {
name: 'panel-directive-' + scope.panel.type,
fn: panelModule.panel,
};
});
},
});
}
angular.module('grafana.directives').directive('panelLoader', panelLoader);
<div class="editor-row" style="margin-bottom: 20px;">
<span style="float: right; font-size: 12px;"><i>Last updated by Grafana October 4, 2015 12:15:04 by $username</i></span>
<div class="section">
<h5>General Alerting Options</h5>
<div class="tight-form last">
<ul class="tight-form-list">
<li class="tight-form-item">
Alert Title
</li>
<li>
<input type="text" class="input-xlarge tight-form-input"></input>
</li>
<li class="tight-form-item">
Alerting Backend
</li>
<li>
<select class="input-medium tight-form-input">
<option>Grafana Alerting</option>
</select>
</li>
<li class="tight-form-item last">
<label class="checkbox-label" for="alerting-enabled">Enabled</label>
<input class="cr1" id="alerting-enabled" type="checkbox">
<label for="alerting-enabled" class="cr1"></label>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="editor-row" style="margin-bottom: 20px;">
<h5>Choose your query:</h5>
<p>Select an exising query to alert on:</p>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" /></li>
<li class="tight-form-item">None</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" /></li>
<li class="tight-form-item" style="min-width: 15px; text-align: center">A</li>
<li class="tight-form-item">apps</li>
<li class="tight-form-item"><i class="fa fa-asterisk"><i></i></i></li>
<li class="tight-form-item">fakesite</li>
<li class="tight-form-item">counters</li>
<li class="tight-form-item">requests</li>
<li class="tight-form-item">count</li>
<li class="tight-form-item">scaleToSeconds(1)</li>
<li class="tight-form-item last">aliasByNode(2)</li>
<li><div class="copy-query" bs-tooltip="'Copy to custom query'" data-placement="top"></div></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" /></li>
<li class="tight-form-item" style="min-width: 15px; text-align: center">B</li>
<li class="tight-form-item last"><span class="query-keyword">Metric:</span> us-west-2 AWS/EC2 CPUUtilization <span class="query-keyword">Stats:</span> Minimum Maximum <span class="query-keyword">Dimensions</span> InstanceIS <span class="query-segment-operator">=</span> i-b0e8a447 <span class="query-keyword">Alias</span> {{stat}} <span class="query-keyword">Period</span> 60</li>
<li><div class="copy-query" bs-tooltip="'Copy to custom query'" data-placement="top"></div></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" /></li>
<li class="tight-form-item" style="min-width: 15px; text-align: center">C</li>
<li class="tight-form-item last"><span class="query-keyword">Query:</span> avg(counters_logins) by(server) <span class="query-keyword">Legend Format:</span> {{app}} - {{server}} <span class="query-keyword">Step:</span> 1s <span class="query-keyword">Resolution:</span> 1/2</li>
<li><div class="copy-query" bs-tooltip="'Copy to custom query'" data-placement="top"></div></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" /></li>
<li class="tight-form-item" style="min-width: 15px; text-align: center">D</li>
<li class="tight-form-item last"><span class="query-keyword">SELECT</span> mean(value) <span class="query-keyword">FROM</span> logins.count <span class="query-keyword">WHERE</span> hostname <span class="query-segment-operator">=</span> /$Hostname$/ <span class="query-keyword">GROUP BY</span> time($internal) hostname</li>
<li><div class="copy-query" bs-tooltip="'Copy to custom query'" data-placement="top"></div></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form last">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" checked /></li>
<li class="tight-form-item" style="min-width: 15px; text-align: center">E</li>
<li class="tight-form-item last"><span class="query-keyword">Metric:</span> apps.backend.backend_01.counters.requests.count <span class="query-keyword">Alias:</span> Bristow <span class="query-keyword">Aggregator:</span> Sum <span class="query-keyword">Downsample:</span> 1m <span class="query-keyword">Aggregator</span> Sum <span class="query-keyword">Tags</span> host = test</li>
<li><div class="copy-query" bs-tooltip="'Copy to custom query'" data-placement="top"></div></li>
</ul>
<div class="clearfix"></div>
</div>
</div>
<div class="editor-row" style="margin-bottom: 20px;">
<p>Or write a new custom alerting query:</p>
<div class="section">
<div class="tight-form last">
<ul class="tight-form-list">
<li class="tight-form-item"><input type="radio" class="radio input-small" name="query" style="margin: 0 4px 4px;" /></li>
<li class="tight-form-item">
<a class="pointer">
<i class="fa fa-pencil"></i>
</a>
</li>
<li class="tight-form-item">
select metric
</li>
<li>
<a class="tight-form-item tight-form-func last dropdown-toggle"><i class="fa fa-plus"></i></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="editor-row" style="margin-bottom: 10px;">
<div class="section">
<h5>Define Your States</h5>
<div class="tight-form last">
<ul class="tight-form-list">
<li class="tight-form-item">
by
</li>
<li>
<select class="input-medium tight-form-input">
<option>Averaging</option>
</select>
</li>
<li class="tight-form-item">
the values in the query over the last
</li>
<li>
<input type="text" class="input-mini tight-form-input last"></input>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="editor-row" style="margin-bottom: 20px;">
<div class="section">
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 100px;">
<span class="alert-state alert-state-warning">Warn</span>
</li>
<li>
<input type="text" class="input-mini tight-form-input" value=">" style="text-align: center;"></input>
</li>
<li>
<input type="text" class="input-mini tight-form-input" value="#B" style="text-align: center;"></input>
</li>
<li class="tight-form-item">
.notify
</li>
<li class="alert-notify-emails">
<bootstrap-tagsinput tagclass="label label-tag label-tag-email"></bootstrap-tagsinput>
</li>
<li class="tight-form-item last">
<label class="checkbox-label" for="state-enabled">Enabled</label>
<input class="cr1" id="state-enabled" type="checkbox">
<label for="state-enabled" class="cr1"></label>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form last">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 100px;">
<span class="alert-state alert-state-critical">Critical</span>
</li>
<li>
<input type="text" class="input-mini tight-form-input"></input>
</li>
<li>
<input type="text" class="input-mini tight-form-input"></input>
</li>
<li class="tight-form-item">
.notify
</li>
<li class="alert-notify-emails">
<bootstrap-tagsinput tagclass="label label-tag label-tag-email"></bootstrap-tagsinput>
</li>
<li class="tight-form-item last">
<label class="checkbox-label" for="state-enabled2">Enabled</label>
<input class="cr1" id="state-enabled2" type="checkbox">
<label for="state-enabled2" class="cr1"></label>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="editor-row">
<div class="section">
<h5>What to Say <span style="float: right; font-size: 12px; font-weight: normal;"><a href="#">Variables</a> | <a href="#">Preview</a></span></h5>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 100px;">
Summary
</li>
<li>
<input type="text" class="input-xxlarge tight-form-input last"></input>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form last">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 100px;">
Description
</li>
<li>
<textarea class="tight-form-textarea input-xxlarge last"></textarea>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
<div ng-repeat="(name, panel) in row.panels track by panel.id" class="panel" ui-draggable="!dashboardViewState.fullscreen" drag="panel.id" <div ng-repeat="(name, panel) in row.panels track by panel.id" class="panel" ui-draggable="!dashboardViewState.fullscreen" drag="panel.id"
ui-on-Drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width> ui-on-Drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width>
<panel-loader type="panel.type" class="panel-margin"></panel-loader> <panel-loader class="panel-margin"></panel-loader>
</div> </div>
<div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="onDrop($data, row)" data-drop="true"> <div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="onDrop($data, row)" data-drop="true">
......
...@@ -11,14 +11,8 @@ function (angular, app, _, config, PanelMeta) { ...@@ -11,14 +11,8 @@ function (angular, app, _, config, PanelMeta) {
var module = angular.module('grafana.panels.dashlist', []); var module = angular.module('grafana.panels.dashlist', []);
app.useModule(module); app.useModule(module);
module.directive('grafanaPanelDashlist', function() { /** @ngInject */
return { function DashListPanelCtrl($scope, panelSrv, backendSrv) {
controller: 'DashListPanelCtrl',
templateUrl: 'app/plugins/panel/dashlist/module.html',
};
});
module.controller('DashListPanelCtrl', function($scope, panelSrv, backendSrv) {
$scope.panelMeta = new PanelMeta({ $scope.panelMeta = new PanelMeta({
panelName: 'Dashboard list', panelName: 'Dashboard list',
...@@ -73,5 +67,16 @@ function (angular, app, _, config, PanelMeta) { ...@@ -73,5 +67,16 @@ function (angular, app, _, config, PanelMeta) {
}; };
$scope.init(); $scope.init();
}); }
function dashListPanelDirective() {
return {
controller: DashListPanelCtrl,
templateUrl: 'app/plugins/panel/dashlist/module.html',
};
}
return {
panel: dashListPanelDirective
};
}); });
...@@ -4,7 +4,7 @@ define([ ...@@ -4,7 +4,7 @@ define([
'moment', 'moment',
'lodash', 'lodash',
'app/core/utils/kbn', 'app/core/utils/kbn',
'./graph.tooltip', './graph_tooltip',
'jquery.flot', 'jquery.flot',
'jquery.flot.events', 'jquery.flot.events',
'jquery.flot.selection', 'jquery.flot.selection',
......
declare var GraphTooltip: any;
export default GraphTooltip;
declare var panel: any;
declare var GraphCtrl: any;
export {panel, GraphCtrl};
...@@ -12,16 +12,8 @@ define([ ...@@ -12,16 +12,8 @@ define([
function (angular, _, moment, kbn, TimeSeries, PanelMeta) { function (angular, _, moment, kbn, TimeSeries, PanelMeta) {
'use strict'; 'use strict';
var module = angular.module('grafana.panels.graph'); /** @ngInject */
function GraphCtrl($scope, $rootScope, panelSrv, annotationsSrv, panelHelper) {
module.directive('grafanaPanelGraph', function() {
return {
controller: 'GraphCtrl',
templateUrl: 'app/plugins/panel/graph/module.html',
};
});
module.controller('GraphCtrl', function($scope, $rootScope, panelSrv, annotationsSrv, panelHelper) {
$scope.panelMeta = new PanelMeta({ $scope.panelMeta = new PanelMeta({
panelName: 'Graph', panelName: 'Graph',
...@@ -294,7 +286,17 @@ function (angular, _, moment, kbn, TimeSeries, PanelMeta) { ...@@ -294,7 +286,17 @@ function (angular, _, moment, kbn, TimeSeries, PanelMeta) {
}; };
panelSrv.init($scope); panelSrv.init($scope);
}
}); function graphPanelDirective() {
return {
controller: GraphCtrl,
templateUrl: 'app/plugins/panel/graph/module.html',
};
}
return {
GraphCtrl: GraphCtrl,
panel: graphPanelDirective,
};
}); });
define([ ///<reference path="../../../../headers/common.d.ts" />
'./helpers',
'app/features/panel/panel_srv',
'app/features/panel/panel_helper',
'app/plugins/panel/graph/module'
], function(helpers) {
'use strict';
describe('GraphCtrl', function() { import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
var ctx = new helpers.ControllerTestContext();
beforeEach(module('grafana.services')); import 'app/features/panel/panel_srv';
beforeEach(module('grafana.panels.graph')); import 'app/features/panel/panel_helper';
beforeEach(ctx.providePhase()); import angular from 'angular';
beforeEach(ctx.createControllerPhase('GraphCtrl')); import {GraphCtrl} from '../module';
import helpers from '../../../../../test/specs/helpers';
describe('get_data with 2 series', function() { angular.module('grafana.controllers').controller('GraphCtrl', GraphCtrl);
beforeEach(function() {
ctx.annotationsSrv.getAnnotations = sinon.stub().returns(ctx.$q.when([]));
ctx.datasource.query = sinon.stub().returns(ctx.$q.when({
data: [
{ target: 'test.cpu1', datapoints: [[1, 10]]},
{ target: 'test.cpu2', datapoints: [[1, 10]]}
]
}));
ctx.scope.render = sinon.spy();
ctx.scope.refreshData(ctx.datasource);
ctx.scope.$digest();
});
it('should send time series to render', function() { describe('GraphCtrl', function() {
var data = ctx.scope.render.getCall(0).args[0]; var ctx = new helpers.ControllerTestContext();
expect(data.length).to.be(2);
}); beforeEach(angularMocks.module('grafana.services'));
beforeEach(angularMocks.module('grafana.controllers'));
beforeEach(ctx.providePhase());
beforeEach(ctx.createControllerPhase('GraphCtrl'));
describe('get_data failure following success', function() { describe('get_data with 2 series', function() {
beforeEach(function() { beforeEach(function() {
ctx.datasource.query = sinon.stub().returns(ctx.$q.reject('Datasource Error')); ctx.annotationsSrv.getAnnotations = sinon.stub().returns(ctx.$q.when([]));
ctx.scope.refreshData(ctx.datasource); ctx.datasource.query = sinon.stub().returns(ctx.$q.when({
ctx.scope.$digest(); data: [
}); { target: 'test.cpu1', datapoints: [[1, 10]]},
{ target: 'test.cpu2', datapoints: [[1, 10]]}
]
}));
ctx.scope.render = sinon.spy();
ctx.scope.refreshData(ctx.datasource);
ctx.scope.$digest();
});
it('should send time series to render', function() {
var data = ctx.scope.render.getCall(0).args[0];
expect(data.length).to.be(2);
});
describe('get_data failure following success', function() {
beforeEach(function() {
ctx.datasource.query = sinon.stub().returns(ctx.$q.reject('Datasource Error'));
ctx.scope.refreshData(ctx.datasource);
ctx.scope.$digest();
}); });
}); });
...@@ -48,4 +51,3 @@ define([ ...@@ -48,4 +51,3 @@ define([
}); });
}); });
define([ ///<reference path="../../../../headers/common.d.ts" />
'./helpers',
'angular', import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
'jquery',
'app/core/time_series', import '../module';
'app/plugins/panel/graph/graph' import angular from 'angular';
], function(helpers, angular, $, TimeSeries) { import $ from 'jquery';
'use strict'; import helpers from '../../../../../test/specs/helpers';
import TimeSeries from '../../../../core/time_series2';
describe('grafanaGraph', function() {
describe('grafanaGraph', function() {
beforeEach(module('grafana.directives'));
beforeEach(angularMocks.module('grafana.directives'));
function graphScenario(desc, func) {
describe(desc, function() { function graphScenario(desc, func) {
var ctx = {}; describe(desc, function() {
var ctx: any = {};
ctx.setup = function(setupFunc) {
beforeEach(angularMocks.module(function($provide) {
$provide.value("timeSrv", new helpers.TimeSrvStub());
}));
beforeEach(angularMocks.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: [],
tooltip: {
shared: true
}
};
scope.panelRenderingComplete = sinon.spy();
scope.appEvent = sinon.spy();
scope.onAppEvent = sinon.spy();
scope.hiddenSeries = {};
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]],
alias: 'series1'
}));
ctx.data.push(new TimeSeries({
datapoints: [[1,1],[2,2]],
alias: 'series2'
}));
ctx.setup = function (setupFunc) { setupFunc(scope, ctx.data);
beforeEach(module(function($provide) { $compile(element)(scope);
$provide.value("timeSrv", new helpers.TimeSrvStub()); scope.$digest();
})); $.plot = ctx.plotSpy = sinon.spy();
beforeEach(inject(function($rootScope, $compile) { scope.$emit('render', ctx.data);
var scope = $rootScope.$new(); ctx.plotData = ctx.plotSpy.getCall(0).args[1];
var element = angular.element("<div style='width:500px' grafana-graph><div>"); ctx.plotOptions = ctx.plotSpy.getCall(0).args[2];
}));
scope.height = '200px'; };
scope.panel = {
legend: {},
grid: { },
y_formats: [],
seriesOverrides: [],
tooltip: {
shared: true
}
};
scope.panelRenderingComplete = sinon.spy();
scope.appEvent = sinon.spy();
scope.onAppEvent = sinon.spy();
scope.hiddenSeries = {};
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]],
alias: 'series1'
}));
ctx.data.push(new TimeSeries({
datapoints: [[1,1],[2,2]],
alias: 'series2'
}));
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); func(ctx);
}); });
} }
graphScenario('simple lines options', function(ctx) { graphScenario('simple lines options', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.lines = true; scope.panel.lines = true;
scope.panel.fill = 5; scope.panel.fill = 5;
scope.panel.linewidth = 3; scope.panel.linewidth = 3;
scope.panel.steppedLine = true; scope.panel.steppedLine = true;
}); });
it('should configure plot with correct options', function() { it('should configure plot with correct options', function() {
expect(ctx.plotOptions.series.lines.show).to.be(true); expect(ctx.plotOptions.series.lines.show).to.be(true);
expect(ctx.plotOptions.series.lines.fill).to.be(0.5); expect(ctx.plotOptions.series.lines.fill).to.be(0.5);
expect(ctx.plotOptions.series.lines.lineWidth).to.be(3); expect(ctx.plotOptions.series.lines.lineWidth).to.be(3);
expect(ctx.plotOptions.series.lines.steps).to.be(true); expect(ctx.plotOptions.series.lines.steps).to.be(true);
});
}); });
});
graphScenario('grid thresholds 100, 200', function(ctx) { graphScenario('grid thresholds 100, 200', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.grid = { scope.panel.grid = {
threshold1: 100, threshold1: 100,
threshold1Color: "#111", threshold1Color: "#111",
threshold2: 200, threshold2: 200,
threshold2Color: "#222", threshold2Color: "#222",
}; };
}); });
it('should add grid markings', function() { it('should add grid markings', function() {
var markings = ctx.plotOptions.grid.markings; var markings = ctx.plotOptions.grid.markings;
expect(markings[0].yaxis.from).to.be(100); expect(markings[0].yaxis.from).to.be(100);
expect(markings[0].yaxis.to).to.be(200); expect(markings[0].yaxis.to).to.be(200);
expect(markings[0].color).to.be('#111'); expect(markings[0].color).to.be('#111');
expect(markings[1].yaxis.from).to.be(200); expect(markings[1].yaxis.from).to.be(200);
expect(markings[1].yaxis.to).to.be(Infinity); expect(markings[1].yaxis.to).to.be(Infinity);
});
}); });
});
graphScenario('inverted grid thresholds 200, 100', function(ctx) { graphScenario('inverted grid thresholds 200, 100', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.grid = { scope.panel.grid = {
threshold1: 200, threshold1: 200,
threshold1Color: "#111", threshold1Color: "#111",
threshold2: 100, threshold2: 100,
threshold2Color: "#222", threshold2Color: "#222",
}; };
}); });
it('should add grid markings', function() { it('should add grid markings', function() {
var markings = ctx.plotOptions.grid.markings; var markings = ctx.plotOptions.grid.markings;
expect(markings[0].yaxis.from).to.be(200); expect(markings[0].yaxis.from).to.be(200);
expect(markings[0].yaxis.to).to.be(100); expect(markings[0].yaxis.to).to.be(100);
expect(markings[0].color).to.be('#111'); expect(markings[0].color).to.be('#111');
expect(markings[1].yaxis.from).to.be(100); expect(markings[1].yaxis.from).to.be(100);
expect(markings[1].yaxis.to).to.be(-Infinity); expect(markings[1].yaxis.to).to.be(-Infinity);
});
}); });
});
graphScenario('grid thresholds from zero', function(ctx) { graphScenario('grid thresholds from zero', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.grid = { scope.panel.grid = {
threshold1: 0, threshold1: 0,
threshold1Color: "#111", threshold1Color: "#111",
}; };
}); });
it('should add grid markings', function() { it('should add grid markings', function() {
var markings = ctx.plotOptions.grid.markings; var markings = ctx.plotOptions.grid.markings;
expect(markings[0].yaxis.from).to.be(0); expect(markings[0].yaxis.from).to.be(0);
});
}); });
});
graphScenario('when logBase is log 10', function(ctx) { graphScenario('when logBase is log 10', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.grid = { scope.panel.grid = {
leftMax: null, leftMax: null,
rightMax: null, rightMax: null,
leftMin: null, leftMin: null,
rightMin: null, rightMin: null,
leftLogBase: 10, leftLogBase: 10,
}; };
}); });
it('should apply axis transform and ticks', function() { it('should apply axis transform and ticks', function() {
var axis = ctx.plotOptions.yaxes[0]; var axis = ctx.plotOptions.yaxes[0];
expect(axis.transform(100)).to.be(Math.log(100+0.1)); expect(axis.transform(100)).to.be(Math.log(100+0.1));
expect(axis.ticks[0]).to.be(0); expect(axis.ticks[0]).to.be(0);
expect(axis.ticks[1]).to.be(1); expect(axis.ticks[1]).to.be(1);
});
}); });
});
graphScenario('should use timeStep for barWidth', function(ctx) { graphScenario('should use timeStep for barWidth', function(ctx) {
ctx.setup(function(scope, data) { ctx.setup(function(scope, data) {
scope.panel.bars = true; scope.panel.bars = true;
data[0] = new TimeSeries({ data[0] = new TimeSeries({
datapoints: [[1,10],[2,20]], datapoints: [[1,10],[2,20]],
alias: 'series1', alias: 'series1',
});
}); });
});
it('should set barWidth', function() { it('should set barWidth', function() {
expect(ctx.plotOptions.series.bars.barWidth).to.be(10/1.5); expect(ctx.plotOptions.series.bars.barWidth).to.be(10/1.5);
});
}); });
});
graphScenario('series option overrides, fill & points', function(ctx) { graphScenario('series option overrides, fill & points', function(ctx) {
ctx.setup(function(scope, data) { ctx.setup(function(scope, data) {
scope.panel.lines = true; scope.panel.lines = true;
scope.panel.fill = 5; scope.panel.fill = 5;
scope.panel.seriesOverrides = [ scope.panel.seriesOverrides = [
{ alias: 'test', fill: 0, points: true } { alias: 'test', fill: 0, points: true }
]; ];
data[1].alias = 'test'; data[1].alias = 'test';
}); });
it('should match second series and fill zero, and enable points', function() { it('should match second series and fill zero, and enable points', function() {
expect(ctx.plotOptions.series.lines.fill).to.be(0.5); expect(ctx.plotOptions.series.lines.fill).to.be(0.5);
expect(ctx.plotData[1].lines.fill).to.be(0.001); expect(ctx.plotData[1].lines.fill).to.be(0.001);
expect(ctx.plotData[1].points.show).to.be(true); expect(ctx.plotData[1].points.show).to.be(true);
});
}); });
});
graphScenario('should order series order according to zindex', function(ctx) { graphScenario('should order series order according to zindex', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.seriesOverrides = [{ alias: 'series1', zindex: 2 }]; scope.panel.seriesOverrides = [{ alias: 'series1', zindex: 2 }];
}); });
it('should move zindex 2 last', function() { it('should move zindex 2 last', function() {
expect(ctx.plotData[0].alias).to.be('series2'); expect(ctx.plotData[0].alias).to.be('series2');
expect(ctx.plotData[1].alias).to.be('series1'); expect(ctx.plotData[1].alias).to.be('series1');
});
}); });
});
graphScenario('when series is hidden', function(ctx) { graphScenario('when series is hidden', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.hiddenSeries = {'series2': true}; scope.hiddenSeries = {'series2': true};
}); });
it('should remove datapoints and disable stack', function() { it('should remove datapoints and disable stack', function() {
expect(ctx.plotData[0].alias).to.be('series1'); expect(ctx.plotData[0].alias).to.be('series1');
expect(ctx.plotData[1].data.length).to.be(0); expect(ctx.plotData[1].data.length).to.be(0);
expect(ctx.plotData[1].stack).to.be(false); expect(ctx.plotData[1].stack).to.be(false);
});
}); });
});
graphScenario('when stack and percent', function(ctx) { graphScenario('when stack and percent', function(ctx) {
ctx.setup(function(scope) { ctx.setup(function(scope) {
scope.panel.percentage = true; scope.panel.percentage = true;
scope.panel.stack = true; scope.panel.stack = true;
}); });
it('should show percentage', function() { it('should show percentage', function() {
var axis = ctx.plotOptions.yaxes[0]; var axis = ctx.plotOptions.yaxes[0];
expect(axis.tickFormatter(100, axis)).to.be("100%"); expect(axis.tickFormatter(100, axis)).to.be("100%");
});
}); });
}); });
}); });
define([ ///<reference path="../../../../headers/common.d.ts" />
'jquery',
'app/plugins/panel/graph/graph.tooltip' import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
], function($, GraphTooltip) {
'use strict'; import $ from 'jquery';
import GraphTooltip from '../graph_tooltip';
var scope = {
appEvent: sinon.spy(), var scope = {
onAppEvent: sinon.spy(), appEvent: sinon.spy(),
onAppEvent: sinon.spy(),
};
var elem = $('<div></div>');
var dashboard = { };
function describeSharedTooltip(desc, fn) {
var ctx: any = {};
ctx.scope = scope;
ctx.scope.panel = {
tooltip: {
shared: true
},
legend: { },
stack: false
}; };
var elem = $('<div></div>'); ctx.setup = function(setupFn) {
var dashboard = { }; ctx.setupFn = setupFn;
};
function describeSharedTooltip(desc, fn) { describe(desc, function() {
var ctx = {}; beforeEach(function() {
ctx.scope = scope; ctx.setupFn();
ctx.scope.panel = { var tooltip = new GraphTooltip(elem, dashboard, scope);
tooltip: { ctx.results = tooltip.getMultiSeriesPlotHoverInfo(ctx.data, ctx.pos);
shared: true
},
legend: { },
stack: false
};
ctx.setup = function(setupFn) {
ctx.setupFn = setupFn;
};
describe(desc, function() {
beforeEach(function() {
ctx.setupFn();
var tooltip = new GraphTooltip(elem, dashboard, scope);
ctx.results = tooltip.getMultiSeriesPlotHoverInfo(ctx.data, ctx.pos);
});
fn(ctx);
});
}
describeSharedTooltip("steppedLine false, stack false", function(ctx) {
ctx.setup(function() {
ctx.data = [
{ data: [[10, 15], [12, 20]], lines: {} },
{ data: [[10, 2], [12, 3]], lines: {} }
];
ctx.pos = { x: 11 };
}); });
it('should return 2 series', function() { fn(ctx);
expect(ctx.results.length).to.be(2); });
}); }
it('should add time to results array', function() {
expect(ctx.results.time).to.be(10); describeSharedTooltip("steppedLine false, stack false", function(ctx) {
}); ctx.setup(function() {
it('should set value and hoverIndex', function() { ctx.data = [
expect(ctx.results[0].value).to.be(15); { data: [[10, 15], [12, 20]], lines: {} },
expect(ctx.results[1].value).to.be(2); { data: [[10, 2], [12, 3]], lines: {} }
expect(ctx.results[0].hoverIndex).to.be(0); ];
}); ctx.pos = { x: 11 };
}); });
describeSharedTooltip("one series is hidden", function(ctx) { it('should return 2 series', function() {
ctx.setup(function() { expect(ctx.results.length).to.be(2);
ctx.data = [ });
{ data: [[10, 15], [12, 20]], }, it('should add time to results array', function() {
{ data: [] } expect(ctx.results.time).to.be(10);
];
ctx.pos = { x: 11 };
});
}); });
it('should set value and hoverIndex', function() {
expect(ctx.results[0].value).to.be(15);
expect(ctx.results[1].value).to.be(2);
expect(ctx.results[0].hoverIndex).to.be(0);
});
});
describeSharedTooltip("one series is hidden", function(ctx) {
ctx.setup(function() {
ctx.data = [
{ data: [[10, 15], [12, 20]], },
{ data: [] }
];
ctx.pos = { x: 11 };
});
});
describeSharedTooltip("steppedLine false, stack true, individual false", function(ctx) { describeSharedTooltip("steppedLine false, stack true, individual false", function(ctx) {
ctx.setup(function() { ctx.setup(function() {
ctx.data = [ ctx.data = [
{ {
data: [[10, 15], [12, 20]], data: [[10, 15], [12, 20]],
lines: {}, lines: {},
datapoints: { datapoints: {
pointsize: 2, pointsize: 2,
points: [[10,15], [12,20]], points: [[10,15], [12,20]],
},
stack: true,
}, },
{ stack: true,
data: [[10, 2], [12, 3]], },
lines: {}, {
datapoints: { data: [[10, 2], [12, 3]],
pointsize: 2, lines: {},
points: [[10, 2], [12, 3]], datapoints: {
}, pointsize: 2,
stack: true points: [[10, 2], [12, 3]],
} },
]; stack: true
ctx.scope.panel.stack = true; }
ctx.pos = { x: 11 }; ];
}); ctx.scope.panel.stack = true;
ctx.pos = { x: 11 };
});
it('should show stacked value', function() { it('should show stacked value', function() {
expect(ctx.results[1].value).to.be(17); expect(ctx.results[1].value).to.be(17);
});
}); });
});
describeSharedTooltip("steppedLine false, stack true, individual false, series stack false", function(ctx) { describeSharedTooltip("steppedLine false, stack true, individual false, series stack false", function(ctx) {
ctx.setup(function() { ctx.setup(function() {
ctx.data = [ ctx.data = [
{ {
data: [[10, 15], [12, 20]], data: [[10, 15], [12, 20]],
lines: {}, lines: {},
datapoints: { datapoints: {
pointsize: 2, pointsize: 2,
points: [[10, 15], [12, 20]], points: [[10, 15], [12, 20]],
},
stack: true
}, },
{ stack: true
data: [[10, 2], [12, 3]], },
lines: {}, {
datapoints: { data: [[10, 2], [12, 3]],
pointsize: 2, lines: {},
points: [[10, 2], [12, 3]], datapoints: {
}, pointsize: 2,
stack: false points: [[10, 2], [12, 3]],
} },
]; stack: false
ctx.scope.panel.stack = true; }
ctx.pos = { x: 11 }; ];
}); ctx.scope.panel.stack = true;
ctx.pos = { x: 11 };
it('should not show stacked value', function() { });
expect(ctx.results[1].value).to.be(2);
});
it('should not show stacked value', function() {
expect(ctx.results[1].value).to.be(2);
}); });
describeSharedTooltip("steppedLine false, stack true, individual true", function(ctx) { });
ctx.setup(function() {
ctx.data = [
{
data: [[10, 15], [12, 20]],
lines: {},
datapoints: {
pointsize: 2,
points: [[10, 15], [12, 20]],
},
stack: true
},
{
data: [[10, 2], [12, 3]],
lines: {},
datapoints: {
pointsize: 2,
points: [[10, 2], [12, 3]],
},
stack: false
}
];
ctx.scope.panel.stack = true;
ctx.scope.panel.tooltip.value_type = 'individual';
ctx.pos = { x: 11 };
});
it('should not show stacked value', function() { describeSharedTooltip("steppedLine false, stack true, individual true", function(ctx) {
expect(ctx.results[1].value).to.be(2); ctx.setup(function() {
}); ctx.data = [
{
data: [[10, 15], [12, 20]],
lines: {},
datapoints: {
pointsize: 2,
points: [[10, 15], [12, 20]],
},
stack: true
},
{
data: [[10, 2], [12, 3]],
lines: {},
datapoints: {
pointsize: 2,
points: [[10, 2], [12, 3]],
},
stack: false
}
];
ctx.scope.panel.stack = true;
ctx.scope.panel.tooltip.value_type = 'individual';
ctx.pos = { x: 11 };
});
it('should not show stacked value', function() {
expect(ctx.results[1].value).to.be(2);
}); });
}); });
declare module "test/specs/helpers" { declare let helpers: any;
let helpers: any; export default helpers;
export default helpers;
}
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