diff --git a/awx/ui/static/js/controllers/JobDetail.js b/awx/ui/static/js/controllers/JobDetail.js index b145692500..ec3986b202 100644 --- a/awx/ui/static/js/controllers/JobDetail.js +++ b/awx/ui/static/js/controllers/JobDetail.js @@ -198,7 +198,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar url; url = scope.job.related.job_events + '?parent=' + task.id + '&'; - url += 'event__icontains=runner&page_size=' + scope.hostResultsMaxRows + '&order_by=-host__name'; + url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order_by=-host__name'; Rest.setUrl(url); Rest.get() @@ -860,8 +860,10 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar scope.viewHostResults = function(id) { EventViewer({ scope: scope, - url: scope.job.related.job_events + '?id=' + id, - title: 'Host Event' + url: scope.job.related.job_events, + parent_id: scope.activeTask, + event_id: id, + title: 'Host Events' }); }; diff --git a/awx/ui/static/js/helpers/EventViewer.js b/awx/ui/static/js/helpers/EventViewer.js index f5187bdb3e..b908971fd6 100644 --- a/awx/ui/static/js/helpers/EventViewer.js +++ b/awx/ui/static/js/helpers/EventViewer.js @@ -14,22 +14,17 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo return function(params) { var parent_scope = params.scope, url = params.url, + event_id = params.event_id, + parent_id = params.parent_id, title = params.title, //optional - scope = parent_scope.$new(true); + scope = parent_scope.$new(true), + current_event; - if (scope.removeModalReady) { - scope.removeModalReady(); - } - scope.removeModalReady = scope.$on('ModalReady', function() { - Wait('stop'); - $('#eventviewer-modal-dialog').dialog('open'); - }); - if (scope.removeJobReady) { - scope.removeJobReady(); - } - scope.removeEventReady = scope.$on('EventReady', function(e, data) { - var elem; + // show scope.events[idx] + function showEvent(idx) { + var elem, data = scope.events[idx]; + current_event = idx; $('#status-form-container').empty(); $('#results-form-container').empty(); @@ -79,6 +74,76 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo elem = angular.element(document.getElementById('eventviewer-modal-dialog')); $compile(elem)(scope); + } + + if (scope.removeModalReady) { + scope.removeModalReady(); + } + scope.removeModalReady = scope.$on('ModalReady', function() { + Wait('stop'); + $('#eventviewer-modal-dialog').dialog('open'); + }); + + if (scope.removeJobReady) { + scope.removeJobReady(); + } + scope.removeEventReady = scope.$on('EventReady', function(e, data) { + var elem, btns; + + scope.events = data; + + // find and show the selected event + data.every(function(row, idx) { + if (parseInt(row.id,10) === parseInt(event_id,10)) { + current_event = idx; + return false; + } + return true; + }); + showEvent(current_event); + + btns = []; + if (scope.events.length > 1) { + btns.push({ + label: "Prev", + onClick: function () { + if (current_event - 1 === 0) { + $('#events-prev-button').prop('disabled', true); + } + if (current_event - 1 < scope.events.length - 1) { + $('#events-next-button').prop('disabled', false); + } + showEvent(current_event - 1); + }, + icon: "fa-chevron-left", + "class": "btn btn-primary", + id: "events-prev-button" + }); + btns.push({ + label: "Next", + onClick: function() { + if (current_event + 1 > 0) { + $('#events-prev-button').prop('disabled', false); + } + if (current_event + 1 >= scope.events.length - 1) { + $('#events-next-button').prop('disabled', true); + } + showEvent(current_event + 1); + }, + icon: "fa-chevron-right", + "class": "btn btn-primary", + id: "events-next-button" + }); + } + btns.push({ + label: "OK", + onClick: function() { + scope.modalOK(); + }, + icon: "", + "class": "btn btn-primary", + id: "dialog-ok-button" + }); CreateDialog({ scope: scope, @@ -89,6 +154,8 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo id: 'eventviewer-modal-dialog', // onResizeStop: resizeText, title: ( (title) ? title : 'Event Details' ), + buttons: btns, + closeOnEscape: true, onClose: function() { try { scope.$destroy(); @@ -100,12 +167,16 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo onOpen: function() { $('#eventview-tabs a:first').tab('show'); $('#dialog-ok-button').focus(); + if (scope.events.length > 1 && current_event === 0) { + console.log('disabling prev button'); + $('#events-prev-button').prop('disabled', true); + } } }); }); GetEvent({ - url: url, + url: url + '?parent=' + parent_id + '&page_size=50&order_by=id', scope: scope }); @@ -120,65 +191,73 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo .factory('GetEvent', ['Wait', 'Rest', 'ProcessErrors', function(Wait, Rest, ProcessErrors) { return function(params) { var url = params.url, - scope = params.scope; + scope = params.scope, + results= []; function getStatus(data) { return (data.results[0].event === "runner_on_unreachable") ? "unreachable" : (data.results[0].event === "runner_on_skipped") ? 'skipped' : (data.results[0].failed) ? 'failed' : (data.results[0].changed) ? 'changed' : 'ok'; } - + console.log('url: ' + url); Wait('start'); Rest.setUrl(url); Rest.get() .success( function(data) { - var key, event_data = {}; - if (data.results.length > 0 && data.results[0].event_data.res) { - for (key in data.results[0].event_data) { - if (key !== "res") { - data.results[0].event_data.res[key] = data.results[0].event_data[key]; + scope.next_event_set = data.next; + scope.prev_event_set = data.prev; + console.log(data.results); + data.results.forEach(function(event) { + var key, event_data = {}; + if (event.event_data.res) { + for (key in event.event_data) { + if (key !== "res") { + event.event_data.res[key] = event.event_data[key]; + } } + if (event.event_data.res.ansible_facts) { + // don't show fact gathering results + event.event_data.res.task = "Gathering Facts"; + delete event.event_data.res.ansible_facts; + } + event.event_data.res.status = getStatus(data); + event_data = event.event_data.res; } - if (data.results[0].event_data.res.ansible_facts) { - // don't show fact gathering results - data.results[0].event_data.res.task = "Gathering Facts"; - delete data.results[0].event_data.res.ansible_facts; + else { + event.event_data.status = getStatus(data); + event_data = event.event_data; } - data.results[0].event_data.res.status = getStatus(data); - event_data = data.results[0].event_data.res; - } - else { - data.results[0].event_data.status = getStatus(data); - event_data = data.results[0].event_data; - } - // convert results to stdout - if (event_data.results && typeof event_data.results === "object" && Array.isArray(event_data.results)) { - event_data.stdout = ""; - event_data.results.forEach(function(row) { - event_data.stdout += row + "\n"; - }); - delete event_data.results; - } - if (event_data.invocation) { - for (key in event_data.invocation) { - event_data[key] = event_data.invocation[key]; + // convert results to stdout + if (event_data.results && typeof event_data.results === "object" && Array.isArray(event_data.results)) { + event_data.stdout = ""; + event_data.results.forEach(function(row) { + event_data.stdout += row + "\n"; + }); + delete event_data.results; } - delete event_data.invocation; - } - event_data.play = data.results[0].play; - if (data.results[0].task) { - event_data.task = data.results[0].task; - } - event_data.created = data.results[0].created; - event_data.role = data.results[0].role; - event_data.host_id = data.results[0].host; - event_data.host_name = data.results[0].host_name; - if (event_data.host) { - delete event_data.host; - } - event_data.id = data.results[0].id; - event_data.parent = data.results[0].parent; - event_data.event = (data.results[0].event_display) ? data.results[0].event_display : data.results[0].event; - scope.$emit('EventReady', event_data); + if (event_data.invocation) { + for (key in event_data.invocation) { + event_data[key] = event_data.invocation[key]; + } + delete event_data.invocation; + } + event_data.play = event.play; + if (event.task) { + event_data.task = event.task; + } + event_data.created = event.created; + event_data.role = event.role; + event_data.host_id = event.host; + event_data.host_name = event.host_name; + if (event_data.host) { + delete event_data.host; + } + event_data.id = event.id; + event_data.parent = event.parent; + event_data.event = (event.event_display) ? event.event_display : event.event; + results.push(event_data); + }); + + scope.$emit('EventReady', results); }) .error(function(data, status) { ProcessErrors(scope, data, status, null, { hdr: 'Error!', diff --git a/awx/ui/static/js/helpers/JobDetail.js b/awx/ui/static/js/helpers/JobDetail.js index c77b1b25bd..29a709854f 100644 --- a/awx/ui/static/js/helpers/JobDetail.js +++ b/awx/ui/static/js/helpers/JobDetail.js @@ -909,7 +909,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge url = scope.job.related.job_events + '?parent=' + scope.activeTask + '&'; url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : ''; url += (scope.search_host_status === 'failed') ? 'failed=true&' : ''; - url += 'event__icontains=runner&page_size=' + scope.hostResultsMaxRows + '&order_by=host__name'; + url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order_by=host__name'; Rest.setUrl(url); Rest.get() diff --git a/awx/ui/static/less/event-viewer.less b/awx/ui/static/less/event-viewer.less index 2a4fc4d0ff..ecf3f40e1f 100644 --- a/awx/ui/static/less/event-viewer.less +++ b/awx/ui/static/less/event-viewer.less @@ -20,6 +20,10 @@ } } +#events-next-button { + margin-right: 60px; +} + table.eventviewer-status { margin-top: 20px;