diff --git a/awx/ui/static/js/controllers/JobDetail.js b/awx/ui/static/js/controllers/JobDetail.js index afb6fd3f2b..d8e6dc90c0 100644 --- a/awx/ui/static/js/controllers/JobDetail.js +++ b/awx/ui/static/js/controllers/JobDetail.js @@ -403,7 +403,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc if (!scope.auto_scroll && scope.activeTask && scope.hostResults.length) { 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 += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; + url += (scope.searchAllStatus === 'failed') ? 'failed=true&' : ''; url += 'host__name__gt=' + scope.hostResults[scope.hostResults.length - 1].name + '&host__isnull=false&page_size=' + (scope.hostTableRows / 3) + '&order_by=host__name'; Wait('start'); Rest.setUrl(url); @@ -448,7 +449,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc if (!scope.auto_scroll && scope.activeTask && scope.hostResults.length) { 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 += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; + url += (scope.searchAllStatus === 'failed') ? 'failed=true&' : ''; url += 'host__name__lt=' + scope.hostResults[0].name + '&host__isnull=false&page_size=' + (scope.hostTableRows / 3) + '&order_by=-host__name'; Wait('start'); Rest.setUrl(url); @@ -490,7 +492,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc var url; if (!scope.auto_scroll && scope.hosts) { url = GetBasePath('jobs') + job_id + '/job_host_summaries/?'; - url += (scope.summary_host_name) ? 'host__name__icontains=' + scope.summary_host_name + '&': ''; + url += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; + url += (scope.searchAllStatus === 'failed') ? 'failed=true&' : ''; url += 'host__name__gt=' + scope.hosts[scope.hosts.length - 1].name + '&page_size=' + (scope.hostSummaryTableRows / 3) + '&order_by=host__name'; Wait('start'); Rest.setUrl(url); @@ -533,7 +536,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc var url; if (!scope.auto_scroll && scope.hosts) { url = GetBasePath('jobs') + job_id + '/job_host_summaries/?'; - url += (scope.summary_host_name) ? 'host__name__icontains=' + scope.summary_host_name + '&': ''; + url += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; + url += (scope.searchAllStatus === 'failed') ? 'failed=true&' : ''; url += 'host__name__lt=' + scope.hosts[0].name + '&page_size=' + (scope.hostSummaryTableRows / 3) + '&order_by=-host__name'; Wait('start'); Rest.setUrl(url); @@ -578,6 +582,7 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc scope.hosts = []; url = GetBasePath('jobs') + $routeParams.id + '/job_host_summaries/?'; url += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&': ''; + url += (scope.searchAllStatus === 'failed') ? 'failed=true&' : ''; url += 'page_size=' + scope.hostSummaryTableRows + '&order_by=host__name'; Rest.setUrl(url); Rest.get() @@ -626,6 +631,28 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc scope.searchAllByHost(); } }; + + scope.filterByStatus = function(choice) { + var tmp = []; + if (choice === 'Failed') { + scope.searchAllStatus = 'failed'; + scope.plays.forEach(function(row) { + if (row.status === 'failed') { + tmp.push(row.id); + } + }); + tmp.sort(); + scope.activePlay = tmp[tmp.length - 1]; + } + else { + scope.searchAllStatus = ''; + scope.activePlay = scope.plays[scope.plays.length - 1].id; + } + scope.searchSummaryHosts(); + setTimeout(function() { + SelectPlay({ scope: scope, id: scope.activePlay }); + }, 500); + }; } JobDetailController.$inject = [ '$scope', '$compile', '$routeParams', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath', 'Wait', diff --git a/awx/ui/static/js/helpers/JobDetail.js b/awx/ui/static/js/helpers/JobDetail.js index 878dcf3a3b..1b0be0ba3c 100644 --- a/awx/ui/static/js/helpers/JobDetail.js +++ b/awx/ui/static/js/helpers/JobDetail.js @@ -232,7 +232,7 @@ function(UpdatePlayStatus, UpdateHostStatus, UpdatePlayChild, AddHostResult, Sel scope.job_status.status_class = ""; scope.host_summary = {}; LoadHostSummary({ scope: scope, data: event.event_data }); - DrawGraph({ scope: scope }); + DrawGraph({ scope: scope, resize: true }); } }); }; @@ -735,32 +735,34 @@ function(UpdatePlayStatus, UpdateHostStatus, UpdatePlayChild, AddHostResult, Sel // is the job done? if so, only select hosts for the last task? - //Wait('start'); scope.hostResults = []; - url = GetBasePath('jobs') + $routeParams.id + '/job_events/?parent=' + id + '&'; - url += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; - url += 'host__isnull=false&page_size=' + scope.hostTableRows + '&order_by=host__name'; - 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 : '' ) + if (id > 0) { + // If we have a selected task, then get the list of hosts + url = GetBasePath('jobs') + $routeParams.id + '/job_events/?parent=' + id + '&'; + url += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; + url += (scope.searchAllStatus === 'failed') ? 'failed=true&' : ''; + url += 'host__isnull=false&page_size=' + scope.hostTableRows + '&order_by=host__name'; + 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 : '' ) + }); }); + SelectHost({ scope: scope }); + }) + .error(function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); }); - //Wait('stop'); - SelectHost({ scope: scope }); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); + } }; }]) diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 10a8af6ad6..24620dc4f4 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -439,9 +439,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi } scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function() { var base = $location.path().replace(/^\//, '').split('/')[0]; - if (base === 'jobs') { - scope.refreshJobs(); - } else { + if (base !== 'jobs') { $location.path('/jobs'); } }); diff --git a/awx/ui/static/less/job-details.less b/awx/ui/static/less/job-details.less index bb77bb06ec..ec133ff6c7 100644 --- a/awx/ui/static/less/job-details.less +++ b/awx/ui/static/less/job-details.less @@ -10,7 +10,7 @@ @failed-hosts-color: #DA4D49; @successful-hosts-color: #5bb75b; @changed-hosts-color: #FF9900; -@skipped-hosts-color: #00BFFF; +@skipped-hosts-color: #01BCC5; @unreachable-hosts-color: #A9A9A9; @@ -303,13 +303,12 @@ label.small-label { .badge-column a { width: 20%; } - .legend { - margin: 8px 0; - } } .legend { + display: inline-block; font-size: 12px; + text-align: center; i { font-size: 10px; margin-left: 5px; @@ -329,8 +328,6 @@ label.small-label { .header { margin-top: 20px; .legend { - text-align: center; - margin: 15px 0 0 0; i { margin-left: 10px } @@ -353,7 +350,8 @@ polyline{ } svg text.percent{ - fill:white; + fill:@black; text-anchor:middle; font-size:12px; + font-weight: bold; } diff --git a/awx/ui/static/lib/ansible/directives.js b/awx/ui/static/lib/ansible/directives.js index 953451b264..fce48f8e82 100644 --- a/awx/ui/static/lib/ansible/directives.js +++ b/awx/ui/static/lib/ansible/directives.js @@ -746,6 +746,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job .directive('awToggleButton', [ function() { return function(scope, element) { $(element).click(function() { + var next, choice; $(this).find('.btn').toggleClass('active'); if ($(this).find('.btn-primary').size()>0) { $(this).find('.btn').toggleClass('btn-primary'); @@ -760,6 +761,19 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job $(this).find('.btn').toggleClass('btn-info'); } $(this).find('.btn').toggleClass('btn-default'); + + // Add data-after-toggle="functionName" to the btn-group, and we'll + // execute here. The newly active choice is passed as a parameter. + if ($(this).attr('data-after-toggle')) { + next = $(this).attr('data-after-toggle'); + choice = $(this).find('.active').text(); + setTimeout(function() { + scope.$apply(function() { + scope[next](choice); + }); + }); + } + }); }; }]); diff --git a/awx/ui/static/partials/job_detail.html b/awx/ui/static/partials/job_detail.html index a361a11aa7..c42cad0ba7 100644 --- a/awx/ui/static/partials/job_detail.html +++ b/awx/ui/static/partials/job_detail.html @@ -52,7 +52,9 @@