diff --git a/awx/ui/static/js/controllers/JobDetail.js b/awx/ui/static/js/controllers/JobDetail.js index 9d9c74b7d4..ce4231fa4c 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, $log, ClearScope, Breadcrumbs, LoadBreadCrumbs, GetBasePath, Wait, Rest, ProcessErrors, DigestEvents, - SelectPlay, SelectTask, Socket, GetElapsed, SelectHost, FilterAllByHostName, DrawGraph) { + SelectPlay, SelectTask, Socket, GetElapsed, SelectHost, FilterAllByHostName, DrawGraph, LoadHostSummary) { ClearScope(); @@ -59,16 +59,15 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, event_socket.init(); event_socket.on("job_events-" + job_id, function(data) { - data.event = data.event_name; - if (api_complete) { - // api loading is complete, process incoming event + if (api_complete && data.id > lastEventId) { + // api loading is complete, process incoming events DigestEvents({ scope: scope, events: [ data ] }); } else { - // waiting on api load, queue incoming event + // Waiting on values from the api to load. Until then queue incoming events. event_queue.push(data); } }); @@ -78,14 +77,37 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, } scope.removeAPIComplete = scope.$on('APIComplete', function() { // process any events sitting in the queue - var events = []; + var events = [], url; + + function notEmpty(x) { + return Object.keys(x).length > 0; + } + + function getMaxId(x) { + var keys = Object.keys(x); + keys.sort(); + return keys[keys.length - 1]; + } + + // Find the max event.id value in memory + if (notEmpty(scope.hostResults)) { + lastEventId = getMaxId(scope.hostResults); + } + else if (notEmpty(scope.tasks)) { + lastEventId = getMaxId(scope.tasks); + } + else if (notEmpty(scope.plays)) { + lastEventId = getMaxId(scope.plays); + } + + // Only process queued events > the max event in memory if (event_queue.length > 0) { event_queue.forEach(function(event) { if (event.id > lastEventId) { events.push(event); } }); - if (events.legnt > 0) { + if (events.length > 0) { DigestEvents({ scope: scope, events: events @@ -93,139 +115,59 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, } } api_complete = true; - }); - if (scope.removeJobHostSummariesReady) { - scope.removeJobHostSummariesReady(); - } - scope.removeJobHostSummariesReady = scope.$on('JobHostSummariesReady', function() { - var url = scope.job.related.job_events + '?parent=' + scope.activeTask + '&host__isnull=false&order_by=host__name'; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - data.results.forEach(function(event) { - scope.hostResults.push({ - id: event.id, - status: ( (event.failed) ? 'failed': (event.changed) ? 'changed' : 'successful' ), - host_id: event.host, - task_id: event.parent, - name: event.event_data.host, - created: event.created, - msg: ( (event.event_data && event.event_data.res) ? event.event_data.res.msg : '' ) - }); - scope.hostResultsMap[event.id] = scope.hostResults.length - 1; - if (event.id > lastEventId) { - lastEventId = event.id; + // Draw the graph + if (scope.job.status === 'successful' && scope.job.status === 'failed' && scope.job.status === 'error') { + // The job has already completed. graph values found on playbook stats + url = scope.job.related.job_events + '?event=playbook_on_stats'; + Rest.setUrl(url); + Rest.get() + .success(function(data) { + if (data.count > 0) { + LoadHostSummary({ + scope: scope, + data: data.results[0].event_data + }); + DrawGraph({ scope: scope, resize: true }); + Wait('stop'); } + }) + .error(function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); }); - scope.$emit('APIComplete'); - Wait('stop'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); + } + else { + // Draw the graph based on summary values in memory + Wait('stop'); + DrawGraph({ scope: scope, resize: true }); + } }); - if (scope.removeTasksReady) { - scope.removeTasksReady(); + if (scope.removeInitialDataLoaded) { + scope.removeInitialDataLoaded(); } - scope.removeTasksReady = scope.$on('TasksReady', function() { - var url = scope.job.related.job_host_summaries + '?page_size=' + scope.hostSummaryTableRows + '&order_by=host__name'; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - data.results.forEach(function(event) { - scope.hosts.push({ - id: event.host, - name: event.summary_fields.host.name, - ok: event.ok, - changed: event.changed, - unreachable: event.dark, - failed: event.failures - }); - scope.hostsMap[event.id] = scope.hosts.length - 1; - }); - scope.$emit('JobHostSummariesReady'); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); + scope.removeInitialDataLoaded= scope.$on('InitialDataLoaded', function() { + // Load data for the host summary table + if (!api_complete) { + ReloadHostSummaryList({ + scope: scope, + callback: 'APIComplete' }); + } }); if (scope.removePlaysReady) { scope.removePlaysReady(); } - scope.removePlaysReady = scope.$on('PlaysReady', function(e, events_url) { - var url = events_url + '?event__in=playbook_on_task_start,playbook_on_setup&parent=' + scope.activePlay + '&order_by=id', - task; - - Rest.setUrl(url); - Rest.get() - .success( function(data) { - data.results.forEach(function(event, idx) { - var end, play_id, elapsed; - - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].created; - } - else { - // no next event (task), get the end time of the play - end = scope.plays[scope.activePlay].finished; - } - if (end) { - elapsed = GetElapsed({ - start: event.created, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - play_id = (event.parent) ? event.parent : scope.activePlay; - - if (!scope.tasks[play_id]) { - scope.tasks[play_id] = {}; - } - - scope.tasks[play_id][event.id] = { - id: event.id, - play_id: play_id, - name: event.event_display, - status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), - created: event.created, - modified: event.modified, - finished: end, - elapsed: elapsed, - hostCount: 0, // hostCount, - reportedHosts: 0, - successfulCount: 0, - failedCount: 0, - changedCount: 0, - skippedCount: 0, - successfulStyle: { display: 'none'}, - failedStyle: { display: 'none' }, - changedStyle: { display: 'none' }, - skippedStyle: { display: 'none' }, - taskActiveClass: '' - }; - }); - if (data.results.length > 0) { - task = data.results[data.results.length - 1]; - lastEventId = task.id; - scope.tasks[scope.activePlay][task.id].taskActiveClass = 'active'; - scope.activeTask = task.id; - scope.activeTaskName = task.name; - } - scope.$emit('TasksReady', events_url); - }) - .error( function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); + scope.removePlaysReady = scope.$on('PlaysReady', function() { + // Select the most recent play, which will trigger tasks and hosts to load + var ids = Object.keys(scope.plays), + lastPlay = (ids.length > 0) ? ids[ids.length - 1] : null; + SelectPlay({ + scope: scope, + id: lastPlay, + }); }); if (scope.removeJobReady) { @@ -233,19 +175,18 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, } scope.removeJobReady = scope.$on('JobReady', function(e, events_url) { // Job finished loading. Now get the set of plays - var url = events_url + '?event=playbook_on_play_start&order_by=id', - play; + var url = scope.job.related.job_plays + '?order_by=id'; Rest.setUrl(url); Rest.get() .success( function(data) { - data.results.forEach(function(event, idx) { + data.forEach(function(event, idx) { var status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'none', - start = event.created, + start = event.start, end, elapsed; if (idx < data.results.length - 1) { // end date = starting date of the next event - end = data.results[idx + 1].created; + end = data.results[idx + 1].started; } else if (scope.job_status.status === 'successful' || scope.job_status.status === 'failed' || scope.job_status.status === 'error' || scope.job_status.status === 'canceled') { // this is the last play and the job already finished @@ -263,22 +204,19 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, scope.plays[event.id] = { id: event.id, name: event.play, - created: event.created, + created: start, finished: end, status: status, elapsed: elapsed, - children: [], playActiveClass: '' }; + scope.host_summary.total += data.total; + scope.host_summary.ok += data.ok; + scope.host_summary.changed += data.changed; + scope.host_summary.unreachable += data.unreachable; + scope.host_summary.failed += data.failed; }); - if (data.results.length > 0) { - play = data.results[data.results.length - 1]; - lastEventId = play.id; - scope.plays[play.id].playActiveClass = 'active'; - scope.activePlay = play.id; - scope.activePlayName = play.play; - } scope.$emit('PlaysReady', events_url); }) .error( function(data, status) { @@ -703,33 +641,7 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, }; scope.searchSummaryHosts = function() { - var url; - Wait('start'); - 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() - .success(function(data) { - data.results.forEach(function(row) { - scope.hosts.push({ - id: row.host, - name: row.summary_fields.host.name, - ok: row.ok, - changed: row.changed, - unreachable: row.dark, - failed: row.failures - }); - }); - Wait('stop'); - $('#hosts-summary-table').mCustomScrollbar("update"); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); + }; scope.searchAllByHost = function() { @@ -787,5 +699,6 @@ function JobDetailController ($scope, $compile, $routeParams, $log, ClearScope, } JobDetailController.$inject = [ '$scope', '$compile', '$routeParams', '$log', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath', 'Wait', - 'Rest', 'ProcessErrors', 'DigestEvents', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'SelectHost', 'FilterAllByHostName', 'DrawGraph' + 'Rest', 'ProcessErrors', 'DigestEvents', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'SelectHost', 'FilterAllByHostName', 'DrawGraph', + 'LoadHostSummary' ]; diff --git a/awx/ui/static/js/helpers/JobDetail.js b/awx/ui/static/js/helpers/JobDetail.js index baa5d12722..13bdb2c9c2 100644 --- a/awx/ui/static/js/helpers/JobDetail.js +++ b/awx/ui/static/js/helpers/JobDetail.js @@ -49,7 +49,7 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa events = params.events; events.forEach(function(event) { - var hostCount, play_id; + var hostCount; if (event.event === 'playbook_on_start') { if (scope.job_status.status!== 'failed' && scope.job_status.status !== 'canceled' && @@ -65,8 +65,7 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa name: event.play, created: event.created, status: (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'none', - elapsed: '00:00:00', - children: [] + elapsed: '00:00:00' }; SelectPlay({ scope: scope, @@ -74,31 +73,34 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }); } if (event.event === 'playbook_on_setup') { - hostCount = GetHostCount({ - scope: scope, - play_id: event.parent - }); - play_id = (event.parent) ? event.parent : scope.activePlay; - if (!scope.tasks[play_id]) { - scope.tasks[play_id] = {}; + if (scope.activePlay === event.parent) { + hostCount = GetHostCount({ + scope: scope, + play_id: event.parent + }); + scope.tasks[event.id] = { + id: event.id, + play_id: event.parent, + name: event.event_display, + status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), + created: event.created, + modified: event.modified, + hostCount: hostCount, + reportedHosts: 0, + successfulCount: 0, + failedCount: 0, + changedCount: 0, + skippedCount: 0, + successfulStyle: { display: 'none'}, + failedStyle: { display: 'none' }, + changedStyle: { display: 'none' }, + skippedStyle: { display: 'none' } + }; + SelectTask({ + scope: scope, + id: event.id + }); } - scope.tasks[play_id][event.id] = { - id: event.id, - name: event.event_display, - status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), - created: event.created, - modified: event.modified, - hostCount: hostCount, - reportedHosts: 0, - successfulCount: 0, - failedCount: 0, - changedCount: 0, - skippedCount: 0, - successfulStyle: { display: 'none'}, - failedStyle: { display: 'none' }, - changedStyle: { display: 'none' }, - skippedStyle: { display: 'none' } - }; UpdatePlayStatus({ scope: scope, play_id: event.parent, @@ -106,10 +108,6 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa changed: event.changed, modified: event.modified }); - SelectTask({ - scope: scope, - id: event.id - }); } if (event.event === 'playbook_on_no_hosts_matched') { UpdatePlayStatus({ @@ -122,29 +120,35 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }); } if (event.event === 'playbook_on_task_start') { - hostCount = GetHostCount({ - scope: scope, - play_id: event.parent - }); - scope.tasks.push({ - id: event.id, - name: event.task, - play_id: event.parent, - status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), - role: event.role, - created: event.created, - modified: event.modified, - hostCount: hostCount, - reportedHosts: 0, - successfulCount: 0, - failedCount: 0, - changedCount: 0, - skippedCount: 0, - successfulStyle: { display: 'none'}, - failedStyle: { display: 'none' }, - changedStyle: { display: 'none' }, - skippedStyle: { display: 'none' } - }); + if (scope.activePlay === event.parent) { + hostCount = GetHostCount({ + scope: scope, + play_id: event.parent + }); + scope.tasks[event.id] = { + id: event.id, + name: event.task, + play_id: event.parent, + status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), + role: event.role, + created: event.created, + modified: event.modified, + hostCount: hostCount, + reportedHosts: 0, + successfulCount: 0, + failedCount: 0, + changedCount: 0, + skippedCount: 0, + successfulStyle: { display: 'none'}, + failedStyle: { display: 'none' }, + changedStyle: { display: 'none' }, + skippedStyle: { display: 'none' } + }; + SelectTask({ + scope: scope, + id: event.id + }); + } if (event.role) { scope.hasRoles = true; } @@ -155,11 +159,6 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa changed: event.changed, modified: event.modified }); - SelectTask({ - scope: scope, - id: event.id - }); - DrawGraph({ scope: scope }); } if (event.event === 'runner_on_unreachable') { @@ -243,27 +242,24 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa //Get the # of expected hosts for a task by looking at the number //on the very first task for a play -.factory('GetHostCount', function() { +.factory('GetHostCount', [ 'FindFirstTaskofPlay', function(FindFirstTaskofPlay) { return function(params) { var scope = params.scope, - play_id = params.play_id, - taskIds; - taskIds = Object.keys(scope.tasks[play_id]); - if (taskIds.length > 0) { - return scope.tasks[play_id][taskIds.length - 1].hostCount; + task_id = FindFirstTaskofPlay({ scope: scope }); + if (task_id) { + return scope.tasks[task_id].hostCount; } return 0; }; -}) +}]) .factory('FindFirstTaskofPlay', function() { return function(params) { var scope = params.scope, - play_id = params.play_id, taskIds; - taskIds = Object.keys(scope.tasks[play_id]); + taskIds = Object.keys(scope.tasks); if (taskIds.length > 0) { - return scope.tasks[play_id][taskIds.length - 1].id; + return scope.tasks[taskIds.length - 1].id; } return null; }; @@ -394,7 +390,7 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }; }]) -// Update host summary totals and update the task +// Each time a runner event is received update host summary totals and the parent task .factory('UpdateHostStatus', ['UpdateTaskStatus', 'AddHostResult', function(UpdateTaskStatus, AddHostResult) { return function(params) { @@ -417,7 +413,7 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa host.failed += (status === 'failed') ? 1 : 0; } else { - // keep totalls for the summary graph + // Totals for the summary graph scope.host_summary.total += 1; scope.host_summary.ok += (status === 'successful') ? 1 : 0; scope.host_summary.changed += (status === 'changed') ? 1 : 0; @@ -570,32 +566,101 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }; }]) -.factory('SelectPlay', ['SelectTask', function(SelectTask) { +// Call SelectPlay whenever the the activePlay needs to change +.factory('SelectPlay', ['SelectTask', 'LoadTasks', function(SelectTask, LoadTasks) { return function(params) { var scope = params.scope, - id = params.id, - taskIds; + id = params.id; - scope.plays[scope.activePlay].playActiveClass = ''; + if (scope.plays[scope.activePlay]) { + scope.plays[scope.activePlay].playActiveClass = ''; + } scope.plays[id].playActiveClass = 'active'; scope.activePlay = id; scope.activePlayName = scope.plays[id].name; - // Select the last task - if (scope.tasks[scope.activePlay]) { - taskIds = Object.keys(scope.tasks[scope.activePlay]); - SelectTask({ - scope: scope, - id: taskIds[taskIds.length - 1] - }); - } - else { - // Not tasks found, clear the host list - scope.hostResults = []; - } + LoadTasks({ + scope: scope + }); + }; }]) +.factory('LoadTasks', ['Rest', 'ProcessErrors', 'GetElapsed', 'SelectTask', function(Rest, ProcessErrors, GetElapsed, SelectTask) { + return function(params) { + var scope = params.scope, + callback = params.callback, + url = scope.job.related.job_tasks + '?parent=' + scope.activePlay + '&order_by=id'; + + Rest.setUrl(url); + Rest.get() + .success(function(data) { + var tIds, lastId; + scope.tasks = {}; + data.results.forEach(function(event, idx) { + var end, elapsed; + + if (idx < data.results.length - 1) { + // end date = starting date of the next event + end = data.results[idx + 1].created; + } + else { + // no next event (task), get the end time of the play + end = scope.plays[scope.activePlay].finished; + } + if (end) { + elapsed = GetElapsed({ + start: event.created, + end: end + }); + } + else { + elapsed = '00:00:00'; + } + + scope.tasks[event.id] = { + id: event.id, + play_id: event.id, + name: event.event_display, + status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), + created: event.created, + modified: event.modified, + finished: end, + elapsed: elapsed, + hostCount: 0, // hostCount, + reportedHosts: 0, + successfulCount: 0, + failedCount: 0, + changedCount: 0, + skippedCount: 0, + successfulStyle: { display: 'none'}, + failedStyle: { display: 'none' }, + changedStyle: { display: 'none' }, + skippedStyle: { display: 'none' }, + taskActiveClass: '' + }; + }); + + // set the active task + tIds = Object.keys(scope.tasks); + lastId = (tIds.length > 0) ? tIds[tIds.length - 1] : null; + SelectTask({ + scope: scope, + id: lastId + }); + + if (callback) { + scope.$emit(callback); + } + }) + .error(function(data) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }; +}]) + +// Call SelectTask whenever the activeTask needs to change .factory('SelectTask', ['LoadHosts', function(LoadHosts) { return function(params) { var scope = params.scope, @@ -623,11 +688,14 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }; }]) +// Refresh the list of hosts .factory('LoadHosts', ['Rest', 'ProcessErrors', 'SelectHost', function(Rest, ProcessErrors, SelectHost) { return function(params) { var scope = params.scope, + callback = params.callback, url; scope.hostResults = []; + scope.hostResultsMap = {}; // If we have a selected task, then get the list of hosts url = scope.job.related.job_events + '?parent=' + scope.activeTask + '&'; url += (scope.search_all_hosts_name) ? 'host__name__icontains=' + scope.search_all_hosts_name + '&' : ''; @@ -646,8 +714,15 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa created: event.created, msg: ( (event.event_data && event.event_data.res) ? event.event_data.res.msg : '' ) }); + scope.hostResultsMap[event.id] = scope.hostResults.length - 1; }); SelectHost({ scope: scope }); + if (callback) { + scope.$emit(callback); + } + else { + scope.$emit('InitialDataLoaded'); + } }) .error(function(data, status) { ProcessErrors(scope, data, status, null, { hdr: 'Error!', @@ -667,6 +742,44 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }; }]) +// Refresh the list of hosts in the hosts summary section +.factory('ReloadHostSummaryList', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { + return function(params) { + var scope = params.scope, + callback = params.callback, + url; + scope.hosts = []; + scope.hostsMap = {}; + url = scope.job.related.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() + .success(function(data) { + data.results.forEach(function(event) { + scope.hosts.push({ + id: event.host, + name: event.summary_fields.host.name, + ok: event.ok, + changed: event.changed, + unreachable: event.dark, + failed: event.failures + }); + scope.hostsMap[event.id] = scope.hosts.length - 1; + }); + $('#hosts-summary-table').mCustomScrollbar("update"); + if (callback) { + scope.$emit(callback); + } + }) + .error(function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }; +}]) + .factory('LoadHostSummary', [ function() { return function(params) { var scope = params.scope, @@ -676,7 +789,7 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa scope.host_summary.unreachable = Object.keys(data.dark).length; scope.host_summary.failed = Object.keys(data.failures).length; scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed + - scope.host_summary.unreachable + scope.host_summary.failed; + scope.host_summary.unreachable + scope.host_summary.failed; }; }]) @@ -743,8 +856,8 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa return function(params) { var scope = params.scope, host = params.host, - job_id = scope.job_id, - url = GetBasePath('jobs') + job_id + '/job_events/?event__icontains=runner&host_name__icontains=' + host + '&parent__isnull=false'; + newActivePlay, + url = scope.job.related.job_events + '?event__icontains=runner&host_name__icontains=' + host + '&parent__isnull=false'; scope.search_all_tasks = []; scope.search_all_plays = []; @@ -755,7 +868,10 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa scope.removeAllPlaysReady = scope.$on('AllPlaysReady', function() { if (scope.activePlay) { setTimeout(function() { - SelectPlay({ scope: scope, id: scope.activePlay }); + SelectPlay({ + scope: scope, + id: newActivePlay + }); }, 500); } }); @@ -764,7 +880,7 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa scope.removeAllTasksReady(); } scope.removeAllTasksReady = scope.$on('AllTasksReady', function() { - url = GetBasePath('jobs') + job_id + '/job_events/?id__in=' + scope.search_all_tasks.join(); + url = scope.job.related.job_events + '?id__in=' + scope.search_all_tasks.join(); Rest.setUrl(url); Rest.get() .success(function(data) { @@ -776,10 +892,10 @@ function(UpdatePlayStatus, UpdateHostStatus, AddHostResult, SelectPlay, SelectTa }); if (scope.search_all_plays.length > 0) { scope.search_all_plays.sort(); - scope.activePlay = scope.search_all_plays[scope.search_all_plays.length - 1]; + newActivePlay = scope.search_all_plays[scope.search_all_plays.length - 1]; } else { - scope.activePlay = null; + newActivePlay = null; } } else { diff --git a/awx/ui/static/lib/ansible/filters.js b/awx/ui/static/lib/ansible/filters.js index e8d8a9ad08..1261554e8e 100644 --- a/awx/ui/static/lib/ansible/filters.js +++ b/awx/ui/static/lib/ansible/filters.js @@ -25,26 +25,18 @@ angular.module('AWFilters', []) } }; }]) - + // - // Filter a list of objects by id using an array of id values + // Filter an object of objects by id using an array of id values // Created specifically for Filter Events on job detail page. // .filter('FilterById', [ function() { return function(input, list) { - var found, results = []; - if (list.length > 0) { - input.forEach(function(row) { - found = false; - list.every(function(id) { - if (row.id === id) { - found = true; - return false; - } - return true; - }); - if (found) { - results.push(row); + var results = {}; + if (input && list.length > 0) { + list.forEach(function(row) { + if (input[row]) { + results[row] = input[row]; } }); return results; diff --git a/awx/ui/static/partials/job_detail.html b/awx/ui/static/partials/job_detail.html index 36684694a1..daa88788aa 100644 --- a/awx/ui/static/partials/job_detail.html +++ b/awx/ui/static/partials/job_detail.html @@ -20,8 +20,8 @@
{{ job_status.status }}
{{ job_status.explanation }}
- - + +
@@ -52,9 +52,8 @@
-
+
@@ -66,6 +65,11 @@ {{ play.name }}
+
+
+
No plays matched
+
+
@@ -80,7 +84,9 @@
-
+
@@ -156,7 +162,7 @@ placeholder="Host Name" ng-disabled="searchAllDisabled" ng-keypress="allHostNameKeyPress($event)" />
- +