diff --git a/src/app/controllers/dash.js b/src/app/controllers/dash.js index 2abb8e77054..e40db93fd7e 100644 --- a/src/app/controllers/dash.js +++ b/src/app/controllers/dash.js @@ -11,7 +11,7 @@ function (angular, $, config, _) { var module = angular.module('grafana.controllers'); module.controller('DashCtrl', function( - $scope, $rootScope, dashboardKeybindings, filterSrv, dashboard, panelMoveSrv, timer) { + $scope, $rootScope, dashboardKeybindings, filterSrv, dashboardSrv, panelMoveSrv, timer) { $scope.editor = { index: 0 }; $scope.panelNames = config.panels; @@ -26,7 +26,7 @@ function (angular, $, config, _) { $rootScope.fullscreen = false; - $scope.dashboard = dashboard.create(dashboardData); + $scope.dashboard = dashboardSrv.create(dashboardData); $scope.grafana.style = $scope.dashboard.style; $scope.filter = filterSrv; @@ -107,16 +107,6 @@ function (angular, $, config, _) { return $scope.editorTabs; }; - $scope.colors = [ - "#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1 - "#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2 - "#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3 - "#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", //4 - "#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", //5 - "#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", //6 - "#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7 - ]; - $scope.init(); }); }); diff --git a/src/app/controllers/grafanaCtrl.js b/src/app/controllers/grafanaCtrl.js index c5efceeccd7..8254c02e9d9 100644 --- a/src/app/controllers/grafanaCtrl.js +++ b/src/app/controllers/grafanaCtrl.js @@ -29,6 +29,16 @@ function (angular, config, _) { $rootScope.$emit(name, payload); }; + $rootScope.colors = [ + "#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1 + "#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2 + "#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3 + "#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", //4 + "#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", //5 + "#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", //6 + "#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7 + ]; + $scope.init(); }); diff --git a/src/app/panels/graph/module.html b/src/app/panels/graph/module.html index a61a632dd8e..8e27adf5c31 100644 --- a/src/app/panels/graph/module.html +++ b/src/app/panels/graph/module.html @@ -1,4 +1,4 @@ -
diff --git a/src/app/panels/graph/module.js b/src/app/panels/graph/module.js index 8f8ad44c3dc..8daa773c620 100644 --- a/src/app/panels/graph/module.js +++ b/src/app/panels/graph/module.js @@ -19,6 +19,7 @@ define([ 'kbn', 'moment', './timeSeries', + 'services/panelSrv', 'services/annotationsSrv', 'services/datasourceSrv', 'jquery.flot', @@ -35,7 +36,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { var module = angular.module('grafana.panels.graph', []); app.useModule(module); - module.controller('graph', function($scope, $rootScope, $timeout, panelSrv, annotationsSrv) { + module.controller('GraphCtrl', function($scope, $rootScope, $timeout, panelSrv, annotationsSrv) { $scope.panelMeta = { modals : [], @@ -190,12 +191,14 @@ function (angular, app, $, _, kbn, moment, timeSeries) { $scope.init = function() { panelSrv.init($scope); $scope.hiddenSeries = {}; - $scope.get_data(); + if (!$scope.skipDataOnInit) { + $scope.get_data(); + } }; $scope.updateTimeRange = function () { - $scope.range = this.filter.timeRange(); - $scope.rangeUnparsed = this.filter.timeRange(false); + $scope.range = $scope.filter.timeRange(); + $scope.rangeUnparsed = $scope.filter.timeRange(false); $scope.resolution = Math.ceil($(window).width() * ($scope.panel.span / 12)); $scope.interval = '10m'; @@ -264,7 +267,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { $scope.seriesHandler = function(seriesData, index) { var datapoints = seriesData.datapoints; var alias = seriesData.target; - var color = $scope.panel.aliasColors[alias] || $scope.colors[index]; + var color = $scope.panel.aliasColors[alias] || $rootScope.colors[index]; var yaxis = $scope.panel.aliasYAxis[alias] || 1; var seriesInfo = { diff --git a/src/app/panels/overview/module.html b/src/app/panels/overview/module.html new file mode 100644 index 00000000000..cc682893a87 --- /dev/null +++ b/src/app/panels/overview/module.html @@ -0,0 +1,25 @@ +
+ +

hello

+
+
+

{{series.info.alias}}

+ {{series.info.avg}} Avg +
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
diff --git a/src/app/panels/overview/module.js b/src/app/panels/overview/module.js new file mode 100644 index 00000000000..0a3521a0566 --- /dev/null +++ b/src/app/panels/overview/module.js @@ -0,0 +1,107 @@ +define([ + 'angular', + 'app', + 'lodash', + '../graph/timeSeries', + 'services/panelSrv', +], +function (angular, app, _, timeSeries) { + 'use strict'; + + var module = angular.module('grafana.panels.overview', []); + app.useModule(module); + + module.controller('OverviewCtrl', function($scope, panelSrv) { + + $scope.panelMeta = { + description : "A panel to show an overview of different metrics through avg, total, current numbers and sparklines", + fullEditorTabs : [ + { + title: 'General', + src:'app/partials/panelgeneral.html' + }, + { + title: 'Metrics', + src:'app/partials/metrics.html' + } + ], + fullscreenEdit: true, + }; + + // Set and populate defaults + var _d = { + targets: [{}] + }; + + _.defaults($scope.panel, _d); + + $scope.init = function() { + panelSrv.init(this); + + if (!$scope.skipDataOnInit) { + $scope.get_data(); + } + //$scope.$on('refresh', $scope.render); + //$scope.render(); + }; + + $scope.get_data = function() { + delete $scope.panel.error; + $scope.panelMeta.loading = true; + + $scope.rangeUnparsed = $scope.filter.timeRange(false); + + var metricsQuery = { + range: $scope.rangeUnparsed, + interval: '1min', + targets: $scope.panel.targets, + maxDataPoints: 100, + }; + + return $scope.datasource.query($scope.filter, metricsQuery) + .then($scope.dataHandler) + .then(null, function(err) { + $scope.panelMeta.loading = false; + $scope.panel.error = err.message || "Timeseries data request error"; + $scope.inspector.error = err; + $scope.render([]); + }); + }; + + $scope.dataHandler = function(results) { + $scope.panelMeta.loading = false; + $scope.series = _.map(results.data, $scope.seriesHandler); + + console.log($scope.series); + }; + + $scope.seriesHandler = function(seriesData) { + var datapoints = seriesData.datapoints; + var alias = seriesData.target; + + var seriesInfo = { + alias: alias, + enable: true, + }; + + var series = new timeSeries.ZeroFilled({ + datapoints: datapoints, + info: seriesInfo, + }); + + series.points = series.getFlotPairs('connected', 'short'); + + return series; + }; + + $scope.render = function() { + + }; + + $scope.openEditor = function() { + }; + + $scope.init(); + + }); +}); diff --git a/src/app/partials/solo-panel.html b/src/app/partials/solo-panel.html new file mode 100644 index 00000000000..f349d32a716 --- /dev/null +++ b/src/app/partials/solo-panel.html @@ -0,0 +1,8 @@ +
+
+
+
+ +
+
+
diff --git a/src/app/routes/all.js b/src/app/routes/all.js index 5342515d545..c09d09dc46f 100644 --- a/src/app/routes/all.js +++ b/src/app/routes/all.js @@ -1,5 +1,6 @@ define([ './dashboard-from-db', + './solo-panel-route', './dashboard-from-file', './dashboard-from-script', './dashboard-default', diff --git a/src/app/routes/solo-panel-route.js b/src/app/routes/solo-panel-route.js new file mode 100644 index 00000000000..653ebdb31d6 --- /dev/null +++ b/src/app/routes/solo-panel-route.js @@ -0,0 +1,45 @@ +define([ + 'angular', +], +function (angular) { + "use strict"; + + var module = angular.module('grafana.routes'); + + module.config(function($routeProvider) { + $routeProvider + .when('/solo-panel/db/:id', { + templateUrl: 'app/partials/solo-panel.html', + controller : 'SoloPanelCtrl', + }); + }); + + module.controller('SoloPanelCtrl', function($scope, $rootScope, datasourceSrv, $routeParams, alertSrv, dashboardSrv, filterSrv) { + + var db = datasourceSrv.getGrafanaDB(); + + db.getDashboard($routeParams.id, false) + .then(function(dashboardData) { + $scope.initPanelScope(dashboardData); + }).then(null, function(error) { + alertSrv.set('Error', error, 'error'); + }); + + $scope.initPanelScope = function(dashboardData) { + $scope.dashboard = dashboardSrv.create(dashboardData); + $scope.grafana.style = $scope.dashboard.style; + $scope.row = { + height: '300px', + }; + $scope.test = "Hej"; + $scope.$index = 0; + $scope.panel = $scope.dashboard.rows[0].panels[0]; + $scope.panel.span = 12; + + $scope.filter = filterSrv; + $scope.filter.init($scope.dashboard); + }; + + }); + +}); diff --git a/src/app/services/all.js b/src/app/services/all.js index a9462629f5d..a1479355def 100644 --- a/src/app/services/all.js +++ b/src/app/services/all.js @@ -10,6 +10,6 @@ define([ './playlistSrv', './unsavedChangesSrv', './dashboard/dashboardKeyBindings', - './dashboard/dashboardModel', + './dashboard/dashboardSrv', ], function () {}); diff --git a/src/app/services/dashboard/dashboardModel.js b/src/app/services/dashboard/dashboardSrv.js similarity index 97% rename from src/app/services/dashboard/dashboardModel.js rename to src/app/services/dashboard/dashboardSrv.js index ba8d24d097c..002f19cca15 100644 --- a/src/app/services/dashboard/dashboardModel.js +++ b/src/app/services/dashboard/dashboardSrv.js @@ -10,7 +10,7 @@ function (angular, $, kbn, _) { var module = angular.module('grafana.services'); - module.service('dashboard', function(timer, $rootScope, $timeout) { + module.service('dashboardSrv', function(timer, $rootScope, $timeout) { function DashboardModel (data) { diff --git a/src/test/specs/dashboardModel-specs.js b/src/test/specs/dashboardSrv-specs.js similarity index 89% rename from src/test/specs/dashboardModel-specs.js rename to src/test/specs/dashboardSrv-specs.js index 5b92caafe46..6a43845a7d7 100644 --- a/src/test/specs/dashboardModel-specs.js +++ b/src/test/specs/dashboardSrv-specs.js @@ -1,5 +1,5 @@ define([ - 'services/dashboard/dashboardModel' + 'services/dashboard/dashboardSrv' ], function() { 'use strict'; @@ -8,8 +8,8 @@ define([ beforeEach(module('grafana.services')); - beforeEach(inject(function(dashboard) { - model = dashboard.create({}); + beforeEach(inject(function(dashboardSrv) { + model = dashboardSrv.create({}); })); it('should have title', function() { @@ -30,8 +30,8 @@ define([ beforeEach(module('grafana.services')); - beforeEach(inject(function(dashboard) { - model = dashboard.create({ + beforeEach(inject(function(dashboardSrv) { + model = dashboardSrv.create({ services: { filter: { time: { from: 'now-1d', to: 'now'}, list: [1] }}, rows: [ { diff --git a/src/test/specs/graph-ctrl-specs.js b/src/test/specs/graph-ctrl-specs.js new file mode 100644 index 00000000000..c01353feb62 --- /dev/null +++ b/src/test/specs/graph-ctrl-specs.js @@ -0,0 +1,44 @@ +define([ + './helpers', + 'panels/graph/module' +], function(helpers) { + 'use strict'; + + describe('GraphCtrl', function() { + var ctx = new helpers.ControllerTestContext(); + + beforeEach(module('grafana.services')); + beforeEach(module('grafana.panels.graph')); + + beforeEach(ctx.providePhase()); + beforeEach(ctx.createControllerPhase('GraphCtrl')); + + describe('get_data with 2 series', function() { + 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.get_data(); + ctx.scope.$digest(); + }); + + it('should build legend model', function() { + expect(ctx.scope.legend[0].alias).to.be('test.cpu1'); + expect(ctx.scope.legend[1].alias).to.be('test.cpu2'); + }); + + it('should send time series to render', function() { + var data = ctx.scope.render.getCall(0).args[0]; + expect(data.length).to.be(2); + }); + + }); + }); + +}); + diff --git a/src/test/specs/graph-panel-controller-specs.js b/src/test/specs/graph-panel-controller-specs.js deleted file mode 100644 index 72c2934c4e5..00000000000 --- a/src/test/specs/graph-panel-controller-specs.js +++ /dev/null @@ -1,31 +0,0 @@ -/*define([ - 'panels/graphite/module' -], function() { - 'use strict'; - - describe('Graph panel controller', function() { - var _graphPanelCtrl; - - beforeEach(module('grafana.panels.graphite')); - beforeEach(module(function($provide){ - $provide.value('filterSrv',{}); - })); - - beforeEach(inject(function($controller, $rootScope) { - _graphPanelCtrl = $controller('graphite', { - $scope: $rootScope.$new() - }); - })); - - describe('init', function() { - beforeEach(function() { - }); - - it('asd', function() { - - }); - }); - }); - -}); -*/ \ No newline at end of file diff --git a/src/test/specs/helpers.js b/src/test/specs/helpers.js index 5c5fc3edfc3..5ca005adcad 100644 --- a/src/test/specs/helpers.js +++ b/src/test/specs/helpers.js @@ -1,11 +1,14 @@ define([ -], function() { + 'kbn' +], function(kbn) { 'use strict'; function ControllerTestContext() { var self = this; + this.timeRange = { from:'now-1h', to: 'now'}; this.datasource = {}; + this.annotationsSrv = {}; this.datasourceSrv = { getMetricSources: function() {}, get: function() { return self.datasource; } @@ -14,6 +17,7 @@ define([ this.providePhase = function() { return module(function($provide) { $provide.value('datasourceSrv', self.datasourceSrv); + $provide.value('annotationsSrv', self.annotationsSrv); }); }; @@ -22,9 +26,20 @@ define([ self.scope = $rootScope.$new(); self.scope.panel = {}; self.scope.filter = { - timeRange: function() {} + timeRange: function(parse) { + if (!parse) { + return self.timeRange; + } + return { + from : kbn.parseDate(self.timeRange.from), + to : kbn.parseDate(self.timeRange.to) + }; + } }; + $rootScope.colors = []; + for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); } + self.$q = $q; self.scope.skipDataOnInit = true; self.controller = $controller(controllerName, { diff --git a/src/test/specs/overview-ctrl-specs.js b/src/test/specs/overview-ctrl-specs.js new file mode 100644 index 00000000000..777dc2bc033 --- /dev/null +++ b/src/test/specs/overview-ctrl-specs.js @@ -0,0 +1,30 @@ +define([ + './helpers', + 'panels/overview/module' +], function(helpers) { + 'use strict'; + + describe('OverviewCtrl', function() { + var ctx = new helpers.ControllerTestContext(); + + beforeEach(module('grafana.services')); + beforeEach(module('grafana.panels.overview')); + + beforeEach(ctx.providePhase()); + beforeEach(ctx.createControllerPhase('OverviewCtrl')); + + describe('when query return error', function() { + beforeEach(function() { + ctx.datasource.query = function() { + return ctx.$q.reject({ message: 'Some error' }); + }; + ctx.scope.get_data(); + ctx.scope.$digest(); + }); + + it('panel.error should be set', function() { + expect(ctx.scope.panel.error).to.be("Some error"); + }); + }); + }); +}); diff --git a/src/test/test-main.js b/src/test/test-main.js index b0ea2988bcd..cd494dba1b5 100644 --- a/src/test/test-main.js +++ b/src/test/test-main.js @@ -118,10 +118,12 @@ require([ 'specs/parser-specs', 'specs/gfunc-specs', 'specs/graphiteTargetCtrl-specs', + 'specs/graph-ctrl-specs', 'specs/filterSrv-specs', 'specs/kbn-format-specs', - 'specs/dashboardModel-specs', - 'specs/influxSeries-specs' + 'specs/dashboardSrv-specs', + 'specs/influxSeries-specs', + 'specs/overview-ctrl-specs', ], function () { window.__karma__.start(); });