From 200a52839180aa32322dd7e6fb8286344caf1fe0 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Thu, 15 May 2014 13:49:52 -0400 Subject: [PATCH] Improvements to job detail page graph rendering and auto-resizing. --- awx/ui/static/js/controllers/JobDetail.js | 118 +++------------- awx/ui/static/js/helpers/JobDetail.js | 158 ++++++++++++---------- awx/ui/static/less/job-details.less | 37 +++-- awx/ui/static/partials/job_detail.html | 132 +++++++++--------- 4 files changed, 201 insertions(+), 244 deletions(-) diff --git a/awx/ui/static/js/controllers/JobDetail.js b/awx/ui/static/js/controllers/JobDetail.js index 341543da4a..c5415d7c9a 100644 --- a/awx/ui/static/js/controllers/JobDetail.js +++ b/awx/ui/static/js/controllers/JobDetail.js @@ -8,7 +8,7 @@ 'use strict'; function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadcrumbs, LoadBreadCrumbs, GetBasePath, Wait, Rest, ProcessErrors, DigestEvents, - SelectPlay, SelectTask, Socket, GetElapsed, SelectHost, FilterAllByHostName) { + SelectPlay, SelectTask, Socket, GetElapsed, SelectHost, FilterAllByHostName, DrawGraph) { ClearScope(); @@ -251,6 +251,10 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc // First time. User just loaded page. scope.$emit('LoadJob'); } + else { + // Check if we need to redraw the group + setTimeout(function() { DrawGraph({ scope: scope }); }, 500); + } }); scope.adjustSize = function() { @@ -275,7 +279,7 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc "padding-right": "15px", "z-index": 0 }); - setTimeout(function() { $('#job-summary-container .job_well').height($('#job-detail-container').height() - 18); }, 500); + setTimeout(function() { $('#job-summary-container .job_well').height($('#job-detail-container').height() - 17); }, 500); $('#job-summary-container').show(); } // Detail table height adjusting. First, put page height back to 'normal'. @@ -304,99 +308,6 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc scope.$emit('RefreshCompleted'); }; - /*function refreshHostRows() { - var url; - if (scope.activeTask) { - scope.hostResults = []; - scope.auto_scroll = true; - url = GetBasePath('jobs') + job_id + '/job_events/?parent=' + scope.activeTask + '&'; - url += (scope.task_host_name) ? 'host__name__icontains=' + scope.task_host_name + '&' : ''; - url += 'host__isnull=false&page_size=' + scope.hostTableRows + '&order_by=host__name'; - Wait('start'); - Rest.setUrl(url); - Rest.get() - .success(function(data) { - data.results.forEach(function(row) { - scope.hostResults.push({ - id: row.id, - status: ( (row.failed) ? 'failed': (row.changed) ? 'changed' : 'successful' ), - host_id: row.host, - task_id: row.parent, - name: row.event_data.host, - created: row.created, - msg: ( (row.event_data && row.event_data.res) ? row.event_data.res.msg : '' ) - }); - }); - $('#hosts-table-detail').mCustomScrollbar("update"); - setTimeout( function() { $('#hosts-table-detail').mCustomScrollbar("scrollTo", "bottom"); }, 700); - Wait('stop'); - scope.$emit('RefreshCompleted'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - } - else { - $('#hosts-table-detail').mCustomScrollbar("update"); - scope.$emit('RefreshCompleted'); - } - } - - function refreshSummaryHostRows() { - if (scope.hosts.length < scope.hostSummaryTableRows) { - var url = GetBasePath('jobs') + job_id + '/job_host_summaries/?'; - url += (scope.summary_host_name) ? 'host__name__icontains=' + scope.summary_host_name + '&': ''; - url += '&page_size=' + scope.hostSummaryTableRows + '&order_by=host__name'; - Wait('start'); - Rest.setUrl(url); - Rest.get() - .success(function(data) { - data.results.forEach(function(row) { - var found = false; - scope.hosts.every(function(host) { - if (host.id === row.host) { - found = true; - return false; - } - return true; - }); - if (!found) { - scope.hosts.push({ - id: row.host, - name: row.summary_fields.host.name, - ok: row.ok, - changed: row.changed, - unreachable: row.dark, - failed: row.failures - }); - } - }); - scope.hosts.sort(function(a,b) { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); - $('#hosts-summary-table').mCustomScrollbar("update"); - setTimeout( function() { $('#hosts-summary-table').mCustomScrollbar("scrollTo", "bottom"); }, 700); - Wait('stop'); - scope.$emit('RefreshCompleted'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - } - else { - $('#hosts-table-detail').mCustomScrollbar("update"); - scope.$emit('RefreshCompleted'); - } - }*/ - setTimeout(function() { scope.adjustSize(); }, 500); // Use debounce for the underscore library to adjust after user resizes window. @@ -443,10 +354,23 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc width: $(document).width(), height: $(document).height() }).show(); + + // Adjust the summary table height $('#job-summary-container .job_well').height(height - 18).css({ 'box-shadow': '-3px 3px 5px 0 #ccc' }); + height = Math.floor($('#job-detail-container').height() * 0.5) - + $('#hosts-summary-section .header').outerHeight() - + $('#hosts-summary-section .table-header').outerHeight() - + $('#hide-summary-button').outerHeight() - + $('#summary-search-section').outerHeight() - + $('#hosts-summary-section .header').outerHeight() - + $('#hosts-summary-section .legend').outerHeight(); + $('#hosts-summary-table').height(height - 50); + $('#hosts-summary-table').mCustomScrollbar("update"); + $('#hide-summary-button').show(); + $('#job-summary-container').css({ top: 0, right: 0, @@ -455,6 +379,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc 'padding-right': '15px', 'padding-left': '15px' }).show('slide', {'direction': 'right'}); + + setTimeout(function() { DrawGraph({ scope: scope }); }, 500); } else { $('.overlay').hide(); @@ -754,5 +680,5 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc } JobDetailController.$inject = [ '$scope', '$compile', '$routeParams', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath', 'Wait', - 'Rest', 'ProcessErrors', 'DigestEvents', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'SelectHost', 'FilterAllByHostName' + 'Rest', 'ProcessErrors', 'DigestEvents', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'SelectHost', 'FilterAllByHostName', 'DrawGraph' ]; diff --git a/awx/ui/static/js/helpers/JobDetail.js b/awx/ui/static/js/helpers/JobDetail.js index 5afbe80366..4fe4812041 100644 --- a/awx/ui/static/js/helpers/JobDetail.js +++ b/awx/ui/static/js/helpers/JobDetail.js @@ -494,35 +494,31 @@ function(UpdatePlayStatus, UpdateHostStatus, UpdatePlayChild, AddHostResult, Sel }); if (!host_found) { - if (scope.hosts.length < 10 || name > scope.hosts[0].name) { - // This is a new host we want added to the list - scope.hosts.push({ - id: host_id, - name: name, - ok: (status === 'successful') ? 1 : 0, - changed: (status === 'changed') ? 1 : 0, - unreachable: (status === 'unreachable') ? 1 : 0, - failed: (status === 'failed') ? 1 : 0 - }); - scope.hosts.sort(function(a,b) { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); - // Only keep 10 hosts - if (scope.hosts.length > scope.hostSummaryTableRows) { - scope.hosts.splice(0,1); + scope.hosts.push({ + id: host_id, + name: name, + ok: (status === 'successful') ? 1 : 0, + changed: (status === 'changed') ? 1 : 0, + unreachable: (status === 'unreachable') ? 1 : 0, + failed: (status === 'failed') ? 1 : 0 + }); + scope.hosts.sort(function(a,b) { + if (a.name < b.name) { + return -1; } - $('#tasks-table-detail').mCustomScrollbar("update"); - setTimeout( function() { + if (a.name > b.name) { + return 1; + } + return 0; + }); + if (scope.hosts.length > scope.hostSummaryTableRows) { + scope.hosts.pop(); + } + $('#tasks-table-detail').mCustomScrollbar("update"); + /*setTimeout( function() { scope.auto_scroll = true; $('#hosts-summary-table').mCustomScrollbar("scrollTo", "bottom"); - }, 700); - } + }, 700);*/ } UpdateTaskStatus({ @@ -774,61 +770,77 @@ function(UpdatePlayStatus, UpdateHostStatus, UpdatePlayChild, AddHostResult, Sel return function(params) { var scope = params.scope, dark = 0, failed = 0, changed = 0, ok = 0, - svg_height, svg_width, graph_data, svg, url; + width, height, svg_height, svg_width, svg_radius, svg, url; - svg_width = $('#graph-section').width(); - svg_height = 300; - if ($('#graph-section svg').length === 0) { - svg = d3.select("#graph-section").append("svg").attr("width", svg_width).attr("height", svg_height); + width = $('#job-summary-container .job_well').width(); + height = $('#job-summary-container .job_well').height() - $('#summary-well-top-section').height() - $('#graph-section .header').outerHeight() - 15; + svg_radius = Math.min(width, height); + svg_width = width; + svg_height = height; + if (svg_height > 0 && svg_width > 0) { + if ($('#graph-section svg').length > 0) { + $("#completedHostsDonut").attr('id', 'completedHostsDonut_old'); + svg = d3.select("#graph-section svg").attr("width", svg_width).attr("height", svg_height); + $('#completedHostsDonut').remove(); + svg.append("g").attr("id","completedHostsDonut"); + $('#completedHostsDonut').hide(); + scope.$emit('GraphLoadData'); + } + else { + svg = d3.select("#graph-section").append("svg").attr("width", svg_width).attr("height", svg_height); + svg.append("g").attr("id","completedHostsDonut"); + scope.$emit('GraphLoadData'); + } } - else { - svg = d3.select("#graph-section svg"); - } - svg.append("g").attr("id","completedHostsDonutNew"); - $('#completedHostsDonutNew').hide(); - + if (scope.removeRenderGraph) { scope.removeRenderGraph(); } - scope.removeRenderGraph = scope.$on('RenderGraph', function() { - Donut3D.draw("completedHostsDonutNew", graph_data, Math.floor(svg_width / 2), 150, 130, 100, 15, 0.4); - $('#completedHostsDonut').remove(); - $('#completedHostsDonutNew').attr('id','completedHostsDonut'); + scope.removeRenderGraph = scope.$on('RenderGraph', function(e, graph_data) { + Donut3D.draw("completedHostsDonut", graph_data, Math.floor(svg_width / 2), Math.floor(svg_height / 2), Math.floor(svg_radius * 0.50), Math.floor(svg_radius * 0.25), 18, 0.4); + $('#completedHostsDonut_old').remove(); $('#completedHostsDonut').show(); + $('#graph-section .legend').show(); }); - url = GetBasePath('jobs') + scope.job_id + '/job_host_summaries/'; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - if (data.count) { - data.results.forEach(function(row) { - if (row.dark) { - dark ++; - } - else if (row.failures) { - failed++; - } - else if (row.changed) { - changed++; - } - else if (row.ok) { - ok++; - } - }); - graph_data = [ - { label: 'OK', value: ok, color: '#9ED89E' }, - { label: 'Changed', value: changed, color: '#FFC773' }, - { label: 'Failed', value: failed, color: '#DA4D49' }, - { label: 'Unreachable', value: dark, color: '#A9A9A9' } - ]; - scope.$emit('RenderGraph'); - } - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); + if (scope.removeGraphLoadData) { + scope.removeGraphLoadData(); + } + scope.removeGraphLoadData = scope.$on('GraphLoadData', function() { + url = GetBasePath('jobs') + scope.job_id + '/job_host_summaries/'; + Rest.setUrl(url); + Rest.get() + .success(function(data) { + var graph_data; + if (data.count) { + data.results.forEach(function(row) { + if (row.dark) { + dark ++; + } + else if (row.failures) { + failed++; + } + else if (row.changed) { + changed++; + } + else if (row.ok) { + ok++; + } + }); + graph_data = [ + { label: 'OK', value: ok, color: '#9ED89E' }, + { label: 'Changed', value: changed, color: '#FFC773' }, + { label: 'Failed', value: failed, color: '#DA4D49' }, + { label: 'Unreachable', value: dark, color: '#A9A9A9' } + ]; + scope.$emit('RenderGraph', graph_data); + } + }) + .error(function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }); }; }]) diff --git a/awx/ui/static/less/job-details.less b/awx/ui/static/less/job-details.less index 1107c2b5ba..14d7f794a3 100644 --- a/awx/ui/static/less/job-details.less +++ b/awx/ui/static/less/job-details.less @@ -301,24 +301,39 @@ label.small-label { .badge-column a { width: 20%; } + .legend { + margin: 8px 0; + } +} + +.legend { + font-size: 12px; + i { + margin-left: 5px; + } + i:first-child { + margin-left: 0; + } } .mCSB_container { margin-right: 18px; } - #graph-section { - position: relative; - .legend { - font-size: 12px; - margin-top: 10px; - } - i { - margin-left: 5px; - } - i:first-child { - margin-left: 0; + width: 100%; + .header { + margin-top: 20px; + .legend { + text-align: center; + margin: 15px 0 0 0; + i { + margin-left: 10px + } + i:first-child { + margin-left: 0; + } + } } } diff --git a/awx/ui/static/partials/job_detail.html b/awx/ui/static/partials/job_detail.html index 320d06dc2f..670abba5b5 100644 --- a/awx/ui/static/partials/job_detail.html +++ b/awx/ui/static/partials/job_detail.html @@ -135,81 +135,85 @@
-
- -
-
-
-
Filter Events
+
+
+
-
-
-
- -
- - -
-
+
+
+
Filter Events
-
-
- -
- - -
-
-
-
-
-
-
-
-
Host Summary
-
- - - -
-
-
-
Host
-
Events - +
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
-
-
- -
- {{ host.ok }} - {{ host.changed }} - {{ host.unreachable }} - {{ host.failed }} +
+
+
Host Summary
+
+ + +
-
-
-
No hosts matched
-
-
-
-
- -
-
-
Host Status Overview
Successful Changed Unreachable Failed
+
+
+
Host
+
Completed Tasks + +
+
+
+ +
+
+ +
+
+
Host Status Overview
+
-
+