From 8d29b170bcc19982bd96f64e742d35922acf4363 Mon Sep 17 00:00:00 2001 From: Joe Fiorini Date: Thu, 22 Jan 2015 11:17:51 -0500 Subject: [PATCH] Extract html string to template --- .../static/js/directives/job-status-graph.js | 318 ++++++++---------- awx/ui/static/partials/job_status_graph.html | 39 +++ .../unit/directives/job-status-graph-test.js | 76 +++++ 3 files changed, 252 insertions(+), 181 deletions(-) create mode 100644 awx/ui/static/partials/job_status_graph.html create mode 100644 awx/ui/tests/unit/directives/job-status-graph-test.js diff --git a/awx/ui/static/js/directives/job-status-graph.js b/awx/ui/static/js/directives/job-status-graph.js index a24df54c9b..529fa01ad7 100644 --- a/awx/ui/static/js/directives/job-status-graph.js +++ b/awx/ui/static/js/directives/job-status-graph.js @@ -1,201 +1,157 @@ angular.module('GraphDirectives', []) - .directive('jobStatusGraph', ['$rootScope', '$compile', '$location' , '$window', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'jobStatusGraphData', - function ($rootScope, $compile , $location, $window, Rest, GetBasePath, ProcessErrors, Wait, jobStatusGraphData) { - return function (scope, element, attr) { + .directive('jobStatusGraph', ['$rootScope', '$compile', '$location' , '$window', 'Wait', 'jobStatusGraphData', + function ($rootScope, $compile , $location, $window, Rest, Wait, jobStatusGraphData) { + return { + restrict: 'A', + templateUrl: '/static/partials/job_status_graph.html', + link: link + }; - var html, url, job_status_chart, - period="month", - job_type="all"; + function link(scope, element, attr) { - var cleanup = angular.noop; + var html, url, job_status_chart, + period="month", + job_type="all"; - var data; - scope.$watch(attr.data, function(value) { - if (value) { - scope.$emit('graphDataReady', value); - } - }); + var cleanup = angular.noop; - scope.$on('$destroy', cleanup); + var data; + scope.$watch(attr.data, function(value) { + if (value) { + scope.$emit('graphDataReady', value); + } + }); - html = "
\n"; - html += "
Job Status
\n"; // for All Jobs, Past Month + scope.$on('$destroy', cleanup); - html += "
\n"; - html += "
\n"; - html += "Job Type: \n"; - html += "All\n"; - html += " \n"; - - html += "\n"; - html += "
\n"; - - html += "
\n"; //end of filter div - - html += "
\n"; - html += "
\n"; - html += "Period: \n"; - html += "Past Month\n"; - html += " \n"; - - html += "\n"; - html += "
\n"; - html += "
\n"; //end of filter div - - html += "
\n"; // end of row - - html +="
\n"; - html += "
\n"; - html += "
\n"; - - // html += "\n"; - - cleanup = _.compose( - [ cleanup, - scope.$on('DataReceived:JobStatusGraph', + cleanup = _.compose( + [ cleanup, + scope.$on('DataReceived:JobStatusGraph', function(e, data) { scope.$emit('graphDataReady', data); }) - ]); + ]); - function createGraph(period, jobtype){ - jobStatusGraphData.get(period, jobtype).then(function(data) { - scope.$emit('graphDataReady', data); - }); - } + function createGraph(period, jobtype){ + console.log('createGraph'); + // jobStatusGraphData.get(period, jobtype).then(function(data) { + // scope.$emit('graphDataReady', data); + // }); + } - element.html($compile(html)(scope)); + cleanup = _.compose( + [ cleanup, + angular.element($window).bind('resize', function() { + if($(window).width()<500){ + $('.graph-container').height(300); + } + else{ + var winHeight = $(window).height(), + available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120; + $('.graph-container').height(available_height/2); + job_status_chart.update(); + } + }) + ]); - cleanup = _.compose( - [ cleanup, - angular.element($window).bind('resize', function() { - if($(window).width()<500){ - $('.graph-container').height(300); - } - else{ - var winHeight = $(window).height(), - available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120; - $('.graph-container').height(available_height/2); - job_status_chart.update(); - } - }) - ]); + if (scope.removeGraphDataReady) { + scope.removeGraphDataReady(); + } + scope.removeGraphDataReady = scope.$on('graphDataReady', function (e, data) { - if (scope.removeGraphDataReady) { - scope.removeGraphDataReady(); - } - scope.removeGraphDataReady = scope.$on('graphDataReady', function (e, data, third) { + console.log("building graph", data); + var timeFormat, graphData = [ + { + "color": "#00aa00", + "key": "Successful", + "values": data.jobs.successful + }, + { + "key" : "Failed" , + "color" : "#aa0000", + "values": data.jobs.failed + } + ]; - var timeFormat, graphData = [ - { - "color": "#00aa00", - "key": "Successful", - "values": data.jobs.successful - }, - { - "key" : "Failed" , - "color" : "#aa0000", - "values": data.jobs.failed - } - ]; - - if(period==="day"){ - timeFormat="%H:%M"; - } - else { - timeFormat = '%m/%d'; - } - graphData.map(function(series) { - series.values = series.values.map(function(d) { - return { - x: d[0], - y: d[1] - }; - }); - return series; - }); - - nv.addGraph({ - generate: function() { - var width = $('.graph-container').width(), // nv.utils.windowSize().width/3, - height = $('.graph-container').height()*0.7; //nv.utils.windowSize().height/5, - job_status_chart = nv.models.lineChart() - .margin({top: 5, right: 75, bottom: 80, left: 85}) //Adjust chart margins to give the x-axis some breathing room. - .x(function(d,i) { return i; }) - .useInteractiveGuideline(true) //We want nice looking tooltips and a guideline! - .transitionDuration(350) //how fast do you want the lines to transition? - .showLegend(true) //Show the legend, allowing users to turn on/off line series. - .showYAxis(true) //Show the y-axis - .showXAxis(true) //Show the x-axis - // .width(width) - // .height(height) - ; - - job_status_chart.xAxis - .axisLabel("Time")//.showMaxMin(true) - .tickFormat(function(d) { - var dx = graphData[0].values[d] && graphData[0].values[d].x || 0; - return dx ? d3.time.format(timeFormat)(new Date(Number(dx+'000'))) : ''; - }); - - job_status_chart.yAxis //Chart y-axis settings - .axisLabel('Jobs') - .tickFormat(d3.format('.f')); - - d3.select('.job-status-graph svg') - .datum(graphData).transition() - .attr('width', width) - .attr('height', height) - .duration(1000) - .call(job_status_chart) - .style({ - // 'width': width, - // 'height': height, - "font-family": 'Open Sans', - "font-style": "normal", - "font-weight":400, - "src": "url(/static/fonts/OpenSans-Regular.ttf)" - }); - - // when the Period drop down filter is used, create a new graph based on the - d3.selectAll(".n") - .on("click", function() { - period = this.getAttribute("id"); - $('#period-dropdown').replaceWith(""+this.text+"\n"); - - createGraph(period, job_type); - }); - - //On click, update with new data - d3.selectAll(".m") - .on("click", function() { - job_type = this.getAttribute("id"); - $('#type-dropdown').replaceWith(""+this.text+"\n"); - - data - createGraph(period, job_type); - }); - - scope.$emit('WidgetLoaded'); - return job_status_chart; - - }, - - - }); - + if(period==="day"){ + timeFormat="%H:%M"; + } + else { + timeFormat = '%m/%d'; + } + graphData.map(function(series) { + series.values = series.values.map(function(d) { + return { + x: d[0], + y: d[1] + }; }); + return series; + }); + + var job_status_chart = nv.models.lineChart() + .margin({top: 5, right: 75, bottom: 80, left: 85}) //Adjust chart margins to give the x-axis some breathing room. + .x(function(d,i) { return i; }) + .useInteractiveGuideline(true) //We want nice looking tooltips and a guideline! + .transitionDuration(350) //how fast do you want the lines to transition? + .showLegend(true) //Show the legend, allowing users to turn on/off line series. + .showYAxis(true) //Show the y-axis + .showXAxis(true) //Show the x-axis + // .width(width) + // .height(height) + ; - }; + var width = $('.graph-container').width(); // nv.utils.windowSize().width/3, + var height = $('.graph-container').height()*0.7; //nv.utils.windowSize().height/5, + + job_status_chart.xAxis + .axisLabel("Time")//.showMaxMin(true) + .tickFormat(function(d) { + var dx = graphData[0].values[d] && graphData[0].values[d].x || 0; + return dx ? d3.time.format(timeFormat)(new Date(Number(dx+'000'))) : ''; + }); + + job_status_chart.yAxis //Chart y-axis settings + .axisLabel('Jobs') + .tickFormat(d3.format('.f')); + + d3.select(element.find('svg')[0]) + .datum(graphData).transition() + .attr('width', width) + .attr('height', height) + .duration(1000) + .call(job_status_chart) + .style({ + // 'width': width, + // 'height': height, + "font-family": 'Open Sans', + "font-style": "normal", + "font-weight":400, + "src": "url(/static/fonts/OpenSans-Regular.ttf)" + }); + + // when the Period drop down filter is used, create a new graph based on the + d3.selectAll(element.find(".n")[0]) + .on("click", function() { + period = this.getAttribute("id"); + $('#period-dropdown').replaceWith(""+this.text+"\n"); + + createGraph(period, job_type); + }); + + //On click, update with new data + d3.selectAll(element.find(".m")[0]) + .on("click", function() { + job_type = this.getAttribute("id"); + $('#type-dropdown').replaceWith(""+this.text+"\n"); + + createGraph(period, job_type); + }); + + return job_status_chart; + + }); + } }]); diff --git a/awx/ui/static/partials/job_status_graph.html b/awx/ui/static/partials/job_status_graph.html new file mode 100644 index 0000000000..a463d63f13 --- /dev/null +++ b/awx/ui/static/partials/job_status_graph.html @@ -0,0 +1,39 @@ +
+
Job Status
+ +
+ + + +
+ +
+
+
+ diff --git a/awx/ui/tests/unit/directives/job-status-graph-test.js b/awx/ui/tests/unit/directives/job-status-graph-test.js new file mode 100644 index 0000000000..49246063d1 --- /dev/null +++ b/awx/ui/tests/unit/directives/job-status-graph-test.js @@ -0,0 +1,76 @@ +describe('Job Status Graph Directive', function() { + var element, scope, httpBackend; + + beforeEach(module('Tower')); + + beforeEach(module(function($provide) { + $provide.value('LoadBasePaths', angular.noop); + })); + + beforeEach(inject(function($rootScope, $compile, $httpBackend) { + httpBackend = $httpBackend; + $httpBackend.expectGET('/static/js/local_config.js').respond({ + }); + + $httpBackend.whenGET('/static/partials/job_status_graph.html') + .respond("
"); + + // $httpBackend.whenGET('/api/').respond(200, + // {"available_versions": {"v1": "/api/v1/"}, "description": "Ansible Tower REST API", "current_version": "/api/v1/"}); + + scope = $rootScope.$new(); + + element = '
'; + + // Takes jobs grouped by result (successful or failure + // Then looks at each array of arrays, where index 0 is the timestamp & index 1 is the count of jobs with that status + scope.data = + { jobs: + { successful: [[1, 0], [2, 0], [3,0], [4,0], [5,0]], + failed: [[1,0],[2,0],[3,0],[4,0],[5,0]] + } + }; + + element = $compile(element)(scope); + scope.$digest(); + + $httpBackend.flush(); + + })); + + afterEach(function() { + httpBackend.verifyNoOutstandingExpectation(); + httpBackend.verifyNoOutstandingRequest(); + }); + + function filterDataSeries(key, data) { + return data.map(function(datum) { + return datum.values; + })[key]; + } + + it('uses successes & failures from scope', function() { + var chartContainer = d3.select(element.find('svg')[0]); + var lineData = chartContainer.datum(); + + var successfulSeries = filterDataSeries(0, lineData); + var failedSeries = filterDataSeries(1, lineData); + + console.log("test done"); + expect(successfulSeries).to.eql( + [ {x: 1, y: 0, series: 0}, + {x: 2, y: 0, series: 0}, + {x: 3, y: 0, series: 0}, + {x: 4, y: 0, series: 0}, + {x: 5, y: 0, series: 0}]); + + expect(failedSeries).to.eql( + [ {x: 1, y: 0, series: 1}, + {x: 2, y: 0, series: 1}, + {x: 3, y: 0, series: 1}, + {x: 4, y: 0, series: 1}, + {x: 5, y: 0, series: 1}]); + }); + +}); +