From a8eaf8cd9c1c9e1409d6245f47dce5ba8e68039e Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Wed, 6 Apr 2016 15:00:54 -0400 Subject: [PATCH 01/16] extend JobDetailService to process job_event host results, resolves #1410 --- awx/ui/client/src/helpers/JobDetail.js | 24 +- .../host-event-details.partial.html | 88 ++--- .../host-event/host-event-modal.partial.html | 3 +- .../host-event/host-event-stdout.partial.html | 15 +- .../host-event/host-event.controller.js | 124 +++---- .../host-events/host-events.partial.html | 4 +- .../src/job-detail/job-detail.controller.js | 102 +++--- .../src/job-detail/job-detail.service.js | 315 ++++++++++-------- 8 files changed, 359 insertions(+), 316 deletions(-) diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js index 689e7139b5..0c6ea3359c 100644 --- a/awx/ui/client/src/helpers/JobDetail.js +++ b/awx/ui/client/src/helpers/JobDetail.js @@ -822,7 +822,6 @@ export default url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : ''; url += (scope.search_task_status === 'failed') ? '&failed=true' : ''; url += '&page_size=' + scope.tasksMaxRows + '&order=id'; - scope.plays.every(function(p, idx) { if (p.id === scope.selectedPlay) { play = scope.plays[idx]; @@ -931,7 +930,7 @@ export default }]) // Call when the selected task needs to change - .factory('SelectTask', ['LoadHosts', function(LoadHosts) { + .factory('SelectTask', ['LoadHosts', 'JobDetailService', function(LoadHosts, JobDetailService) { return function(params) { var scope = params.scope, id = params.id, @@ -946,11 +945,16 @@ export default scope.tasks[idx].taskActiveClass = ''; } }); - - LoadHosts({ - scope: scope, - callback: callback, - clear: true + // /api/v1/jobs/16/job_events/?parent=832&event__startswith=runner&page_size=200&order=host_name,counte + var params = { + parent: scope.selectedTask, + event__startswith: 'runner', + page_size: scope.hostResultsMaxRows, + order: 'host_name,counter', + }; + JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ + scope.hostResults = JobDetailService.processHostResults(res.results) + scope.hostResultsLoading = false; }); }; }]) @@ -960,8 +964,7 @@ export default return function(params) { var scope = params.scope, callback = params.callback, - url; - + url; scope.hostResults = []; if (scope.selectedTask) { @@ -970,6 +973,7 @@ export default url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : ''; url += (scope.search_host_status === 'failed') ? 'failed=true&' : ''; url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order=host_name,counter'; + console.log(url) scope.hostResultsLoading = true; Rest.setUrl(url); Rest.get() @@ -1020,7 +1024,6 @@ export default msg = event.event_data.res; } } - if (event.event !== "runner_on_no_hosts") { scope.hostResults.push({ id: event.id, @@ -1037,7 +1040,6 @@ export default }); scope.hostResultsLoading = false; - if (callback) { scope.$emit(callback); } diff --git a/awx/ui/client/src/job-detail/host-event/host-event-details.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-details.partial.html index 66a60fcec9..f650b4335a 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event-details.partial.html +++ b/awx/ui/client/src/job-detail/host-event/host-event-details.partial.html @@ -1,49 +1,49 @@
-
-
EVENT
- -
- -
- STATUS - - - - - {{event.status || "No result found"}} - -
-
- ID - {{event.id || "No result found"}} -
-
- CREATED - {{event.created || "No result found"}} -
-
- PLAY - {{event.play || "No result found"}} -
-
- TASK - {{event.task || "No result found"}} -
-
- MODULE - {{event.event_data.res.invocation.module_name || "No result found"}} -
+
+
EVENT
+ +
+ +
+ STATUS + + + + + {{processEventStatus(event).status || "No result found"}} + +
+
+ ID + {{event.id || "No result found"}} +
+
+ CREATED + {{event.created || "No result found"}} +
+
+ PLAY + {{event.play || "No result found"}} +
+
+ TASK + {{event.task || "No result found"}} +
+
+ MODULE + {{event.event_data.res.invocation.module_name || "No result found"}} +
-
RESULTS
- -
- {{key}} - {{value}} -
+
RESULTS
+ +
+ {{key}} + {{value}} +
diff --git a/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html index db106deb1b..1981b61a04 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html +++ b/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html @@ -14,8 +14,7 @@ - - +
diff --git a/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html index 436c25262a..29f3966e86 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html +++ b/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html @@ -1,13 +1,2 @@ -
-
-
STANDARD OUT
- -
- -
\ No newline at end of file + \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-event/host-event.controller.js b/awx/ui/client/src/job-detail/host-event/host-event.controller.js index ac46279d0f..1c7284ae30 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event.controller.js +++ b/awx/ui/client/src/job-detail/host-event/host-event.controller.js @@ -4,68 +4,78 @@ * All Rights Reserved *************************************************/ + export default - ['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'moment', 'event', - function($stateParams, $scope, $state, Wait, JobDetailService, moment, event){ - // Avoid rendering objects in the details fieldset - // ng-if="processResults(value)" via host-event-details.partial.html - $scope.processResults = function(value){ - if (typeof value == 'object'){return false} - else {return true} - }; + ['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'moment', 'event', + function($stateParams, $scope, $state, Wait, JobDetailService, moment, event){ - var codeMirror = function(){ - var el = $('#HostEvent-json')[0]; - var editor = CodeMirror.fromTextArea(el, { - lineNumbers: true, - mode: {name: "javascript", json: true} - }); - editor.getDoc().setValue(JSON.stringify($scope.json, null, 4)); - }; + $scope.processEventStatus = JobDetailService.processEventStatus; + // Avoid rendering objects in the details fieldset + // ng-if="processResults(value)" via host-event-details.partial.html + $scope.processResults = function(value){ + if (typeof value == 'object'){return false;} + else {return true;} + }; - $scope.getActiveHostIndex = function(){ - var result = $scope.hostResults.filter(function( obj ) { - return obj.id == $scope.event.id; - }); - return $scope.hostResults.indexOf(result[0]) - }; + var codeMirror = function(el, json){ + var el = $(el)[0]; + var editor = CodeMirror.fromTextArea(el, { + lineNumbers: true, + mode: {name: "javascript", json: true} + }); + editor.getDoc().setValue(JSON.stringify(json, null, 4)); + }; - $scope.showPrev = function(){ - return $scope.getActiveHostIndex() != 0 - }; + $scope.getActiveHostIndex = function(){ + var result = $scope.hostResults.filter(function( obj ) { + return obj.id == $scope.event.id; + }); + return $scope.hostResults.indexOf(result[0]); + }; - $scope.showNext = function(){ - return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]) - }; + $scope.showPrev = function(){ + return $scope.getActiveHostIndex() != 0; + }; - $scope.goNext = function(){ - var index = $scope.getActiveHostIndex() + 1; - var id = $scope.hostResults[index].id; - $state.go('jobDetail.host-event.details', {eventId: id}) - }; + $scope.showNext = function(){ + return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]); + }; - $scope.goPrev = function(){ - var index = $scope.getActiveHostIndex() - 1; - var id = $scope.hostResults[index].id; - $state.go('jobDetail.host-event.details', {eventId: id}) - }; + $scope.goNext = function(){ + var index = $scope.getActiveHostIndex() + 1; + var id = $scope.hostResults[index].id; + $state.go('jobDetail.host-event.details', {eventId: id}); + }; - var init = function(){ - $scope.event = event.data.results[0]; - $scope.event.created = moment($scope.event.created).format(); - $scope.processEventStatus = JobDetailService.processEventStatus($scope.event); - $scope.hostResults = $stateParams.hostResults; - $scope.json = JobDetailService.processJson($scope.event); - if ($state.current.name == 'jobDetail.host-event.json'){ - codeMirror(); - } - try { - $scope.stdout = $scope.event.event_data.res.stdout - } - catch(err){ - $scope.sdout = null; - } - $('#HostEvent').modal('show'); - }; - init(); - }]; \ No newline at end of file + $scope.goPrev = function(){ + var index = $scope.getActiveHostIndex() - 1; + var id = $scope.hostResults[index].id; + $state.go('jobDetail.host-event.details', {eventId: id}); + }; + + var init = function(){ + console.log(event) + $scope.event = event.data.results[0]; + $scope.event.created = moment($scope.event.created).format(); + $scope.hostResults = $stateParams.hostResults; + $scope.json = JobDetailService.processJson($scope.event); + if ($state.current.name == 'jobDetail.host-event.json'){ + codeMirror('#HostEvent-json', $scope.json); + } + try { + $scope.stdout = JobDetailService.processJson($scope.event.event_data.res) + console.log($scope.stdout) + if ($state.current.name == 'jobDetail.host-event.stdout'){ + codeMirror('#HostEvent-stdout', $scope.stdout); + } + } + catch(err){ + $scope.sdout = null; + } + console.log($scope) + + + $('#HostEvent').modal('show'); + }; + init(); + }]; \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-events/host-events.partial.html b/awx/ui/client/src/job-detail/host-events/host-events.partial.html index 9d0ccca40f..7fb46f3234 100644 --- a/awx/ui/client/src/job-detail/host-events/host-events.partial.html +++ b/awx/ui/client/src/job-detail/host-events/host-events.partial.html @@ -36,9 +36,9 @@ - + - {{event.status}} + {{processEventStatus(event).status}} {{event.play}} {{event.task}} diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js index d06fa5881f..91264dd1b4 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -16,7 +16,7 @@ export default 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList', 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun', - 'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit', + 'LoadPlays', 'LoadTasks', 'HostsEdit', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'EditSchedule', 'ParseTypeChange', 'JobDetailService', function( @@ -25,7 +25,7 @@ export default SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, LoadHostSummary, ReloadHostSummaryList, JobIsFinished, SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, - PlaybookRun, LoadPlays, LoadTasks, LoadHosts, + PlaybookRun, LoadPlays, LoadTasks, HostsEdit, ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule, ParseTypeChange, JobDetailService ) { @@ -376,64 +376,26 @@ export default var params = { parent: task.id, event__startswith: 'runner', - page_size: scope.hostResultsMaxRows }; JobDetailService.getRelatedJobEvents(scope.job.id, params) .success(function(data) { + console.log(data) var idx, event, status, status_text, item, msg; - if (data.results.length > 0) { + if (data.results.length > 0) {$ lastEventId = data.results[0].id; } scope.next_host_results = data.next; for (idx=data.results.length - 1; idx >= 0; idx--) { event = data.results[idx]; - if (event.event === "runner_on_skipped") { - status = 'skipped'; - } - else if (event.event === "runner_on_unreachable") { - status = 'unreachable'; - } - else { - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - } - switch(status) { - case "successful": - status_text = 'OK'; - break; - case "changed": - status_text = "Changed"; - break; - case "failed": - status_text = "Failed"; - break; - case "unreachable": - status_text = "Unreachable"; - break; - case "skipped": - status_text = "Skipped"; - } + event.status = JobDetailService.processEventStatus(event).status; + msg = JobDetailService.processEventMsg(event); + item = JobDetailService.processEventItem(event); - if (event.event_data && event.event_data.res) { - item = event.event_data.res.item; - if (typeof item === "object") { - item = JSON.stringify(item); - } - } - - msg = ''; - if (event.event_data && event.event_data.res) { - if (typeof event.event_data.res === 'object') { - msg = event.event_data.res.msg; - } else { - msg = event.event_data.res; - } - } - - if (event.event !== "runner_on_no_hosts") { + if (event.event !== "runner_on$_no_hosts") { task.hostResults[event.id] = { id: event.id, - status: status, - status_text: status_text, + status: event.status, + status_text: event.status.toUpperCase(), host_id: event.host, task_id: event.parent, name: event.event_data.host, @@ -673,7 +635,7 @@ export default scope.$emit('LoadTasks', events_url); }); }); - + if (scope.removeLoadJob) { scope.removeLoadJob(); @@ -1037,6 +999,16 @@ export default scope.searchTasksEnabled = true; } if (!scope.liveEventProcessing || scope.pauseLiveEvents) { + // /api/v1/jobs/15/job_tasks/?event_id=762&task__icontains=create&page_size=200&order=id + var params = { + event_id: scope.selectedPlay, + task__icontains: scope.search_task_name, + page_size: scope.tasksMaxRows, + + }; + if (scope.search_task_status === 'failed'){ + params.failed = true; + } LoadTasks({ scope: scope }); @@ -1058,8 +1030,20 @@ export default scope.searchHostsEnabled = true; } if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - LoadHosts({ - scope: scope + scope.hostResultsLoading = true; + var params = { + parent: scope.selectedTask, + event__startswith: 'runner', + page_size: scope.hostResultsMaxRows, + order: 'host_name,counter', + host_name__icontains: scope.search_host_name + } + if (scope.search_host_status === 'failed'){ + params.failed = true; + } + JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ + scope.hostResults = JobDetailService.processHostResults(res.results) + scope.hostResultsLoading = false; }); } }; @@ -1104,8 +1088,20 @@ export default scope.filterHostStatus = function() { scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all'; if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - LoadHosts({ - scope: scope + console.log('filterHostStattus', scope) + var params = { + parent: scope.selectedTask, + event__startswith: 'runner', + page_size: scope.hostResultsMaxRows, + order: 'host_name,counter' + } + if (scope.search_host_status === 'failed'){ + params.failed = true; + } + scope.hostResultsLoading = true; + JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ + scope.hostResults = JobDetailService.processHostResults(res.results) + scope.hostResultsLoading = false; }); } }; diff --git a/awx/ui/client/src/job-detail/job-detail.service.js b/awx/ui/client/src/job-detail/job-detail.service.js index 381ff56c18..2beecdc215 100644 --- a/awx/ui/client/src/job-detail/job-detail.service.js +++ b/awx/ui/client/src/job-detail/job-detail.service.js @@ -1,18 +1,17 @@ export default - ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){ - return { + ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){ + return { - /* - For ES6 - it might be useful to set some default params here, e.g. - getJobHostSummaries: function(id, page_size=200, order='host_name'){} - without ES6, we'd have to supply defaults like this: - this.page_size = params.page_size ? params.page_size : 200; - */ + /* + * For ES6 + * it might be useful to set some default params here, e.g. + * getJobHostSummaries: function(id, page_size=200, order='host_name'){} + * without ES6, we'd have to supply defaults like this: + * this.page_size = params.page_size ? params.page_size : 200; + */ // the the API passes through Ansible's event_data response // we need to massage away the verbose and redundant properties - processJson: function(data){ // a deep copy var result = $.extend(true, {}, data); @@ -44,147 +43,195 @@ export default } }); } - catch(err){result.event_data = null;} + catch(err){result.event_data = undefined;} return result }, - + // Return Ansible's passed-through response msg on a job_event + processEventMsg: function(event){ + return typeof event.event_data.res === 'object' ? event.event_data.res.msg : event.event_data.res; + }, + // Return only Ansible's passed-through response item on a job_event + processEventItem: function(event){ + try{ + var item = event.event_data.res.item; + return typeof item === 'object' ? JSON.stringify(item) : item + } + catch(err){return;} + }, + // Generate a helper class for job_event statuses + // the stack for which status to display is + // unreachable > failed > changed > ok + // uses the API's runner events and convenience properties .failed .changed to determine status. + // see: job_event_callback.py processEventStatus: function(event){ - // Generate a helper class for job_event statuses - // the stack for which status to display is - // unreachable > failed > changed > ok - // uses the API's runner events and convenience properties .failed .changed to determine status. - // see: job_event_callback.py if (event.event == 'runner_on_unreachable'){ - event.status = 'Unreachable'; - return 'HostEvents-status--unreachable' + return { + class: 'HostEvents-status--unreachable', + status: 'unreachable' + } } // equiv to 'runner_on_error' && 'runner on failed' if (event.failed){ - event.status = 'Failed'; - return 'HostEvents-status--failed' + return { + class: 'HostEvents-status--failed', + status: 'failed' + } } // catch the changed case before ok, because both can be true if (event.changed){ - event.status = 'Changed'; - return 'HostEvents-status--changed' + return { + class: 'HostEvents-status--changed', + status: 'changed' + } } if (event.event == 'runner_on_ok'){ - event.status = 'OK'; - return 'HostEvents-status--ok' + return { + class: 'HostEvents-status--ok', + status: 'ok' + } } if (event.event == 'runner_on_skipped'){ - event.status = 'Skipped'; - return 'HostEvents-status--skipped' + return { + class: 'HostEvents-status--skipped', + status: 'skipped' + } } else{ // study a case where none of these apply } - }, + }, - // GET events related to a job run - // e.g. - // ?event=playbook_on_stats - // ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter - getRelatedJobEvents: function(id, params){ - var url = GetBasePath('jobs'); - url = url + id + '/job_events/?'; - Object.keys(params).forEach(function(key, index) { - // the API is tolerant of extra ampersands - // ?&event=playbook_on_start == ?event=playbook_on_stats - url = url + '&' + key + '=' + params[key]; - }); - Rest.setUrl(url); - return Rest.get() - .success(function(data){ - return data - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - // GET job host summaries related to a job run - // e.g. ?page_size=200&order=host_name - getJobHostSummaries: function(id, params){ - var url = GetBasePath('jobs'); - url = url + id + '/job_host_summaries/?' - Object.keys(params).forEach(function(key, index) { - // the API is tolerant of extra ampersands - url = url + '&' + key + '=' + params[key]; - }); - Rest.setUrl(url); - return Rest.get() - .success(function(data){ - return data - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - // GET job plays related to a job run - // e.g. ?page_size=200 - getJobPlays: function(id, params){ - var url = GetBasePath('jobs'); - url = url + id + '/job_plays/?'; - Object.keys(params).forEach(function(key, index) { - // the API is tolerant of extra ampersands - url = url + '&' + key + '=' + params[key]; - }); - Rest.setUrl(url); - return Rest.get() - .success(function(data){ - return data - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - getJobTasks: function(id, params){ - var url = GetBasePath('jobs'); - url = url + id + '/job_tasks/?'; - Object.keys(params).forEach(function(key, index) { - // the API is tolerant of extra ampersands - url = url + '&' + key + '=' + params[key]; - }); - Rest.setUrl(url); - return Rest.get() - .success(function(data){ - return data - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - getJob: function(id){ - var url = GetBasePath('jobs'); - url = url + id; - Rest.setUrl(url); - return Rest.get() - .success(function(data){ - return data - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }, - // GET next set of paginated results - // expects 'next' param returned by the API e.g. - // "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1" - getNextPage: function(url){ - return Rest.get() - .success(function(data){ - return data - }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - } - } - } - ]; \ No newline at end of file + // Consumes a response from this.getRelatedJobEvents + // returns an array for view logic to iterate over to build host result rows + processHostResults: function(data){ + var self = this; + var results = []; + data.forEach(function(element, index, array){ + var event = element; + if (event.event !== 'runner_on_no_hosts'){ + var status = self.processEventStatus(event); + var msg = self.processEventMsg(event); + var item = self.processEventItem(event); + results.push({ + id: event.id, + status: status.status, + status_text: status.status.charAt(0).toUpperCase() + status.status.slice(1), + host_id: event.host, + task_id: event.parent, + name: event.event_data.host, + created: event.created, + msg: typeof msg === 'undefined' ? undefined : msg, + item: typeof item === 'undefined' ? undefined : item + }); + } + }); + return results; + }, + + // GET events related to a job run + // e.g. + // ?event=playbook_on_stats + // ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter + getRelatedJobEvents: function(id, params){ + var url = GetBasePath('jobs'); + url = url + id + '/job_events/?'; + Object.keys(params).forEach(function(key, index) { + // the API is tolerant of extra ampersands + // ?&event=playbook_on_start == ?event=playbook_on_stats + url = url + '&' + key + '=' + params[key]; + }); + Rest.setUrl(url); + return Rest.get() + .success(function(data){ + return data + }) + .error(function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }, + // GET job host summaries related to a job run + // e.g. ?page_size=200&order=host_name + getJobHostSummaries: function(id, params){ + var url = GetBasePath('jobs'); + url = url + id + '/job_host_summaries/?' + Object.keys(params).forEach(function(key, index) { + // the API is tolerant of extra ampersands + url = url + '&' + key + '=' + params[key]; + }); + Rest.setUrl(url); + return Rest.get() + .success(function(data){ + return data + }) + .error(function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }, + // GET job plays related to a job run + // e.g. ?page_size=200 + getJobPlays: function(id, params){ + var url = GetBasePath('jobs'); + url = url + id + '/job_plays/?'; + Object.keys(params).forEach(function(key, index) { + // the API is tolerant of extra ampersands + url = url + '&' + key + '=' + params[key]; + }); + Rest.setUrl(url); + return Rest.get() + .success(function(data){ + return data + }) + .error(function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }, + getJobTasks: function(id, params){ + var url = GetBasePath('jobs'); + url = url + id + '/job_tasks/?'; + Object.keys(params).forEach(function(key, index) { + // the API is tolerant of extra ampersands + url = url + '&' + key + '=' + params[key]; + }); + Rest.setUrl(url); + return Rest.get() + .success(function(data){ + return data + }) + .error(function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }, + getJob: function(id){ + var url = GetBasePath('jobs'); + url = url + id; + Rest.setUrl(url); + return Rest.get() + .success(function(data){ + return data + }) + .error(function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + }, + // GET next set of paginated results + // expects 'next' param returned by the API e.g. + // "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1" + getNextPage: function(url){ + return Rest.get() + .success(function(data){ + return data + }) + .error(function(data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + } + } + } + ]; \ No newline at end of file From ae839341458583eee63db0d3753fcd079b986494 Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Thu, 7 Apr 2016 15:12:56 -0400 Subject: [PATCH 02/16] modularize host-summary and use socket.io/jobs/ endpoint --- awx/ui/client/src/helpers/JobDetail.js | 106 +----------------- awx/ui/client/src/helpers/JobSubmission.js | 1 + .../job-detail/host-event/host-event.route.js | 30 +---- .../client/src/job-detail/host-event/main.js | 3 +- .../host-summary/host-summary-factory.js | 0 .../host-summary/host-summary.controller.js | 53 +++++++++ .../host-summary/host-summary.partial.html | 66 +++++++++++ .../src/job-detail/job-detail.controller.js | 53 +++------ .../src/job-detail/job-detail.partial.html | 73 +----------- .../client/src/job-detail/job-detail.route.js | 25 ++++- .../src/job-detail/job-detail.service.js | 70 ++++++------ 11 files changed, 205 insertions(+), 275 deletions(-) create mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary-factory.js create mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.controller.js create mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.partial.html diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js index 0c6ea3359c..4911981939 100644 --- a/awx/ui/client/src/helpers/JobDetail.js +++ b/awx/ui/client/src/helpers/JobDetail.js @@ -930,7 +930,7 @@ export default }]) // Call when the selected task needs to change - .factory('SelectTask', ['LoadHosts', 'JobDetailService', function(LoadHosts, JobDetailService) { + .factory('SelectTask', ['JobDetailService', function(JobDetailService) { return function(params) { var scope = params.scope, id = params.id, @@ -953,111 +953,12 @@ export default order: 'host_name,counter', }; JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ - scope.hostResults = JobDetailService.processHostResults(res.results) + scope.hostResults = JobDetailService.processHostEvents(res.results) scope.hostResultsLoading = false; }); }; }]) - // Refresh the list of hosts - .factory('LoadHosts', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { - return function(params) { - var scope = params.scope, - callback = params.callback, - url; - scope.hostResults = []; - - if (scope.selectedTask) { - // If we have a selected task, then get the list of hosts - url = scope.job.related.job_events + '?parent=' + scope.selectedTask + '&'; - url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : ''; - url += (scope.search_host_status === 'failed') ? 'failed=true&' : ''; - url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order=host_name,counter'; - console.log(url) - scope.hostResultsLoading = true; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - scope.next_host_results = data.next; - scope.hostResults = []; - data.results.forEach(function(event) { - var status, status_text, item, msg; - if (event.event === "runner_on_skipped") { - status = 'skipped'; - } - else if (event.event === "runner_on_unreachable") { - status = 'unreachable'; - } - else { - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - } - switch(status) { - case "successful": - status_text = 'OK'; - break; - case "changed": - status_text = "Changed"; - break; - case "failed": - status_text = "Failed"; - break; - case "unreachable": - status_text = "Unreachable"; - break; - case "skipped": - status_text = "Skipped"; - } - - if (event.event_data && event.event_data.res) { - item = event.event_data.res.item; - if (typeof item === "object") { - item = JSON.stringify(item); - item = item.replace(/\"/g,'').replace(/:/g,': ').replace(/,/g,', '); - } - } - - msg = ''; - if (event.event_data && event.event_data.res) { - if (typeof event.event_data.res === 'object') { - msg = event.event_data.res.msg; - } else { - msg = event.event_data.res; - } - } - if (event.event !== "runner_on_no_hosts") { - scope.hostResults.push({ - id: event.id, - status: status, - status_text: status_text, - host_id: event.host, - task_id: event.parent, - name: event.event_data.host, - created: event.created, - msg: msg, - item: item - }); - } - }); - - scope.hostResultsLoading = false; - if (callback) { - scope.$emit(callback); - } - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - } - else { - if (callback) { - scope.$emit(callback); - } - //$('#hosts-table-detail').mCustomScrollbar("update"); - } - }; - }]) - // Refresh the list of hosts in the hosts summary section .factory('ReloadHostSummaryList', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { return function(params) { @@ -1069,7 +970,6 @@ export default url += (scope.search_host_summary_name) ? 'host_name__icontains=' + scope.search_host_summary_name + '&': ''; url += (scope.search_host_summary_status === 'failed') ? 'failed=true&' : ''; url += '&page_size=' + scope.hostSummariesMaxRows + '&order=host_name'; - scope.hosts = []; scope.hostSummariesLoading = true; @@ -1098,7 +998,6 @@ export default }); scope.hostSummariesLoading = false; - if (callback) { scope.$emit(callback); } @@ -1564,7 +1463,6 @@ export default function(DrawPlays, DrawTasks, DrawHostResults, DrawHostSummaries, DrawGraph) { return function(params) { var scope = params.scope; - if (!scope.pauseLiveEvents) { DrawPlays({ scope: scope }); DrawTasks({ scope: scope }); diff --git a/awx/ui/client/src/helpers/JobSubmission.js b/awx/ui/client/src/helpers/JobSubmission.js index aee3570311..37caa00329 100644 --- a/awx/ui/client/src/helpers/JobSubmission.js +++ b/awx/ui/client/src/helpers/JobSubmission.js @@ -804,6 +804,7 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, if((scope.portalMode===false || scope.$parent.portalMode===false ) && Empty(data.system_job) || (base === 'home')){ $location.path('/jobs/' + job); + // use $state.go with reload: true option to re-instantiate sockets in } }); diff --git a/awx/ui/client/src/job-detail/host-event/host-event.route.js b/awx/ui/client/src/job-detail/host-event/host-event.route.js index 7d4f1cc011..1d270039ab 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event.route.js +++ b/awx/ui/client/src/job-detail/host-event/host-event.route.js @@ -35,19 +35,14 @@ var hostEventModal = { $('.modal-backdrop').remove(); $('body').removeClass('modal-open'); } - } + }; var hostEventDetails = { name: 'jobDetail.host-event.details', url: '/details', controller: 'HostEventController', templateUrl: templateUrl('job-detail/host-event/host-event-details'), - resolve: { - features: ['FeaturesService', function(FeaturesService){ - return FeaturesService.get(); - }] - } - } + }; var hostEventJson = { name: 'jobDetail.host-event.json', @@ -60,27 +55,12 @@ var hostEventModal = { }] } }; - var hostEventTiming = { - name: 'jobDetail.host-event.timing', - url: '/timing', - controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-timing'), - resolve: { - features: ['FeaturesService', function(FeaturesService){ - return FeaturesService.get(); - }] - } - }; + var hostEventStdout = { name: 'jobDetail.host-event.stdout', url: '/stdout', controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-stdout'), - resolve: { - features: ['FeaturesService', function(FeaturesService){ - return FeaturesService.get(); - }] - } + templateUrl: templateUrl('job-detail/host-event/host-event-stdout') }; - export {hostEventDetails, hostEventJson, hostEventTiming, hostEventStdout, hostEventModal} \ No newline at end of file + export {hostEventDetails, hostEventJson, hostEventStdout, hostEventModal} \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-event/main.js b/awx/ui/client/src/job-detail/host-event/main.js index c2b82530a1..0670181f09 100644 --- a/awx/ui/client/src/job-detail/host-event/main.js +++ b/awx/ui/client/src/job-detail/host-event/main.js @@ -4,7 +4,7 @@ * All Rights Reserved *************************************************/ - import {hostEventModal, hostEventDetails, hostEventTiming, + import {hostEventModal, hostEventDetails, hostEventJson, hostEventStdout} from './host-event.route'; import controller from './host-event.controller'; @@ -15,7 +15,6 @@ .run(['$stateExtender', function($stateExtender){ $stateExtender.addState(hostEventModal); $stateExtender.addState(hostEventDetails); - $stateExtender.addState(hostEventTiming); $stateExtender.addState(hostEventJson); $stateExtender.addState(hostEventStdout); }]); \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary-factory.js b/awx/ui/client/src/job-detail/host-summary/host-summary-factory.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js new file mode 100644 index 0000000000..2af1b81443 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js @@ -0,0 +1,53 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$scope', '$rootScope', '$stateParams', 'JobDetailService', 'jobSocket', function($scope, $rootScope, $stateParams, JobDetailService, jobSocket){ + + // the job_events socket should be substituted for a job_host_summary socket post 3.0 + var page_size = 200; + var socketListener = function(){ + console.log(jobSocket) + jobSocket.on('summary_complete', function(data) { + JobDetailService.getJob($stateParams.id).success(function(res){ + console.log('job at summary_complete.', res) + }); + }); + jobSocket.on('status_changed', function(data) { + JobDetailService.getJob($stateParams.id).success(function(res){ + console.log('job at data.stats.', data.status, res) + }); + JobDetailService.getJobHostSummaries($stateParams.id, {}).success(function(res){ + console.log('jobhostSummaries at summary_complete.', data.status, res) + }); + }); + } + $scope.loading = $scope.hosts.length > 0 ? false : true; + $scope.done = true; + $scope.events = []; + $scope.$watchCollection('events', function(c){ + var filtered = $scope.events.filter(function(event){ + return ((event.failed || event.changed || + 'runner_on_ok' || 'runner_on_async_ok' || + 'runner_on_unreachable' || 'runner_on_skipped') + && event.host_name != ''); + }); + var grouped = _.groupBy(filtered, 'host_name'); + //$scope.hosts = + }); + + + $scope.search = function(host_name){}; + $scope.filter = function(filter){}; + + var init = function(){ + socketListener(); + JobDetailService.getJobHostSummaries($stateParams.id, {}).success(function(res){ + console.log('jobhostSummaries at init.', res) + }); + }; + init(); + }]; \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html b/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html new file mode 100644 index 0000000000..d86c5b3545 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html @@ -0,0 +1,66 @@ + +
+ +
+
+
+ + + +
+
+
+
+ + +
+
+
+ +
+ + + + + + + +
HostsCompleted Tasks
+
+ +
+ + + + + + + + + + + + + + + + +
+ {{ host.name }} + + {{ host.ok }} + {{ host.changed }} + {{ host.unreachable }} + {{ host.failed }} +
Waiting...
Loading...
No matching hosts
+
+ +
+ +
+ +
+ +
+ +
diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js index 91264dd1b4..cbedbde7cb 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -277,7 +277,6 @@ export default scope.$emit('LoadHostSummaries'); }); - if (scope.removeInitialLoadComplete) { scope.removeInitialLoadComplete(); } @@ -292,12 +291,10 @@ export default }; JobDetailService.getRelatedJobEvents(scope.job.id, params) .success(function(data) { - if (data.results.length > 0) { LoadHostSummary({ scope: scope, data: data.results[0].event_data }); - } UpdateDOM({ scope: scope }); }) .error(function(data, status) { @@ -379,33 +376,12 @@ export default }; JobDetailService.getRelatedJobEvents(scope.job.id, params) .success(function(data) { - console.log(data) var idx, event, status, status_text, item, msg; if (data.results.length > 0) {$ lastEventId = data.results[0].id; } scope.next_host_results = data.next; - for (idx=data.results.length - 1; idx >= 0; idx--) { - event = data.results[idx]; - event.status = JobDetailService.processEventStatus(event).status; - msg = JobDetailService.processEventMsg(event); - item = JobDetailService.processEventItem(event); - - if (event.event !== "runner_on$_no_hosts") { - task.hostResults[event.id] = { - id: event.id, - status: event.status, - status_text: event.status.toUpperCase(), - host_id: event.host, - task_id: event.parent, - name: event.event_data.host, - created: event.created, - msg: msg, - counter: event.counter, - item: item - }; - } - } + task.hostResults = JobDetailService.processHostEvents(data.results); scope.$emit('LoadHostSummaries'); }); } else { @@ -999,13 +975,6 @@ export default scope.searchTasksEnabled = true; } if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - // /api/v1/jobs/15/job_tasks/?event_id=762&task__icontains=create&page_size=200&order=id - var params = { - event_id: scope.selectedPlay, - task__icontains: scope.search_task_name, - page_size: scope.tasksMaxRows, - - }; if (scope.search_task_status === 'failed'){ params.failed = true; } @@ -1042,7 +1011,7 @@ export default params.failed = true; } JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ - scope.hostResults = JobDetailService.processHostResults(res.results) + scope.hostResults = JobDetailService.processHostEvents(res.results) scope.hostResultsLoading = false; }); } @@ -1088,7 +1057,6 @@ export default scope.filterHostStatus = function() { scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all'; if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - console.log('filterHostStattus', scope) var params = { parent: scope.selectedTask, event__startswith: 'runner', @@ -1100,7 +1068,7 @@ export default } scope.hostResultsLoading = true; JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ - scope.hostResults = JobDetailService.processHostResults(res.results) + scope.hostResults = JobDetailService.processHostEvents(res.results) scope.hostResultsLoading = false; }); } @@ -1109,6 +1077,21 @@ export default scope.filterHostSummaryStatus = function() { scope.search_host_summary_status = (scope.search_host_summary_status === 'all') ? 'failed' : 'all'; if (!scope.liveEventProcessing || scope.pauseLiveEvents) { + // /api/v1/jobs/11/job_host_summaries/?failed=true&&page_size=200&order=host_name + var params = { + page_size: scope.hostSummariesMaxRows, + order: 'host_name' + } + if (scope.search_host_summary_status === 'failed'){ + params.failed = true; + } + /* + JobDetailService.getJobHostSummaries(scope.job.id, params).success(function(res){ + scope.next_host_summaries = res.next; + scope.hosts = res.results; + console.log(res.results) + }); + */ ReloadHostSummaryList({ scope: scope }); diff --git a/awx/ui/client/src/job-detail/job-detail.partial.html b/awx/ui/client/src/job-detail/job-detail.partial.html index 2ced4bf551..616b463386 100644 --- a/awx/ui/client/src/job-detail/job-detail.partial.html +++ b/awx/ui/client/src/job-detail/job-detail.partial.html @@ -388,75 +388,10 @@
- - + + diff --git a/awx/ui/client/src/job-detail/job-detail.route.js b/awx/ui/client/src/job-detail/job-detail.route.js index 3494845759..62678016fe 100644 --- a/awx/ui/client/src/job-detail/job-detail.route.js +++ b/awx/ui/client/src/job-detail/job-detail.route.js @@ -5,12 +5,11 @@ *************************************************/ import {templateUrl} from '../shared/template-url/template-url.factory'; +import HostSummaryController from './host-summary/host-summary.controller'; export default { name: 'jobDetail', url: '/jobs/:id', - templateUrl: templateUrl('job-detail/job-detail'), - controller: 'JobDetailController', ncyBreadcrumb: { parent: 'jobs', label: "{{ job.id }} - {{ job.name }}" @@ -26,10 +25,32 @@ export default { endpoint: "job_events" }); $rootScope.event_socket.init(); + // returns should really be providing $rootScope.event_socket + // otherwise, we have to inject the entire $rootScope into the controller return true; } else { return true; } + }], + jobSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { + var job_socket = Socket({ + scope: $rootScope, + endpoint: "jobs" + }); + job_socket.init(); + // returns should really be providing $rootScope.job_socket + // otherwise, we have to inject the entire $rootScope into the controller + return job_socket; }] + }, + views: { + '': { + templateUrl: templateUrl('job-detail/job-detail'), + controller: 'JobDetailController', + }, + 'host-summary@jobDetail': { + templateUrl: templateUrl('job-detail/host-summary/host-summary'), + controller: HostSummaryController + } } }; diff --git a/awx/ui/client/src/job-detail/job-detail.service.js b/awx/ui/client/src/job-detail/job-detail.service.js index 2beecdc215..640aa4def7 100644 --- a/awx/ui/client/src/job-detail/job-detail.service.js +++ b/awx/ui/client/src/job-detail/job-detail.service.js @@ -63,52 +63,47 @@ export default // the stack for which status to display is // unreachable > failed > changed > ok // uses the API's runner events and convenience properties .failed .changed to determine status. - // see: job_event_callback.py + // see: job_event_callback.py for more filters to support processEventStatus: function(event){ - if (event.event == 'runner_on_unreachable'){ - return { - class: 'HostEvents-status--unreachable', - status: 'unreachable' - } + if (event.event == 'runner_on_unreachable'){ + return { + class: 'HostEvents-status--unreachable', + status: 'unreachable' } - // equiv to 'runner_on_error' && 'runner on failed' - if (event.failed){ - return { - class: 'HostEvents-status--failed', - status: 'failed' - } + } + // equiv to 'runner_on_error' && 'runner on failed' + if (event.failed){ + return { + class: 'HostEvents-status--failed', + status: 'failed' } - // catch the changed case before ok, because both can be true - if (event.changed){ - return { - class: 'HostEvents-status--changed', - status: 'changed' - } + } + // catch the changed case before ok, because both can be true + if (event.changed){ + return { + class: 'HostEvents-status--changed', + status: 'changed' } - if (event.event == 'runner_on_ok'){ - return { - class: 'HostEvents-status--ok', - status: 'ok' - } + } + if (event.event == 'runner_on_ok' || event.event == 'runner_on_async_ok'){ + return { + class: 'HostEvents-status--ok', + status: 'ok' } - if (event.event == 'runner_on_skipped'){ - return { - class: 'HostEvents-status--skipped', - status: 'skipped' - } - } - else{ - // study a case where none of these apply + } + if (event.event == 'runner_on_skipped'){ + return { + class: 'HostEvents-status--skipped', + status: 'skipped' } + } }, - - // Consumes a response from this.getRelatedJobEvents + // Consumes a response from this.getRelatedJobEvents(id, params) // returns an array for view logic to iterate over to build host result rows - processHostResults: function(data){ + processHostEvents: function(data){ var self = this; var results = []; - data.forEach(function(element, index, array){ - var event = element; + data.forEach(function(event){ if (event.event !== 'runner_on_no_hosts'){ var status = self.processEventStatus(event); var msg = self.processEventMsg(event); @@ -116,7 +111,7 @@ export default results.push({ id: event.id, status: status.status, - status_text: status.status.charAt(0).toUpperCase() + status.status.slice(1), + status_text: _.head(status.status).toUpperCase() + _.tail(status.status), host_id: event.host, task_id: event.parent, name: event.event_data.host, @@ -128,7 +123,6 @@ export default }); return results; }, - // GET events related to a job run // e.g. // ?event=playbook_on_stats From 2a5a97fc35b5cf4c20bf7d8b11524c7718ba3ca2 Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Fri, 8 Apr 2016 13:19:02 -0400 Subject: [PATCH 03/16] refactor Event Summary view to resolve #1245 --- awx/ui/client/legacy-styles/job-details.less | 2 +- awx/ui/client/src/helpers/JobDetail.js | 213 +++--------------- awx/ui/client/src/helpers/JobSubmission.js | 6 +- .../host-summary/host-summary-factory.js | 0 .../host-summary/host-summary.block.less | 10 + .../host-summary/host-summary.controller.js | 147 ++++++++---- .../host-summary/host-summary.partial.html | 123 +++++----- .../src/job-detail/job-detail.controller.js | 167 ++------------ .../src/job-detail/job-detail.partial.html | 2 +- 9 files changed, 227 insertions(+), 443 deletions(-) delete mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary-factory.js create mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.block.less diff --git a/awx/ui/client/legacy-styles/job-details.less b/awx/ui/client/legacy-styles/job-details.less index d3cc2bae50..d4a21a9421 100644 --- a/awx/ui/client/legacy-styles/job-details.less +++ b/awx/ui/client/legacy-styles/job-details.less @@ -503,7 +503,7 @@ } #graph-section svg{ - margin-top: 15px; + margin: 0 auto; } path.slice{ diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js index 4911981939..3a98789f7d 100644 --- a/awx/ui/client/src/helpers/JobDetail.js +++ b/awx/ui/client/src/helpers/JobDetail.js @@ -40,9 +40,9 @@ export default angular.module('JobDetailHelper', ['Utilities', 'RestServices', 'ModalDialog']) .factory('DigestEvent', ['$rootScope', '$log', 'UpdatePlayStatus', 'UpdateHostStatus', 'AddHostResult', - 'GetElapsed', 'UpdateTaskStatus', 'DrawGraph', 'LoadHostSummary', 'JobIsFinished', 'AddNewTask', 'AddNewPlay', + 'GetElapsed', 'UpdateTaskStatus', 'JobIsFinished', 'AddNewTask', 'AddNewPlay', function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, GetElapsed, - UpdateTaskStatus, DrawGraph, LoadHostSummary, JobIsFinished, AddNewTask, AddNewPlay) { + UpdateTaskStatus, JobIsFinished, AddNewTask, AddNewPlay) { return function(params) { var scope = params.scope, @@ -185,7 +185,7 @@ export default }; }]) - .factory('GetElapsed', [ function() { + .factory('GetElapsed', ['moment', function(moment) { return function(params) { var start = params.start, end = params.end, @@ -299,7 +299,7 @@ export default }; }]) - .factory('AddNewTask', ['DrawGraph', 'UpdatePlayStatus', 'SetActivePlay', 'SetActiveTask', function(DrawGraph, UpdatePlayStatus, SetActivePlay, SetActiveTask) { + .factory('AddNewTask', ['UpdatePlayStatus', 'SetActivePlay', 'SetActiveTask', function(UpdatePlayStatus, SetActivePlay, SetActiveTask) { return function(params) { var scope = params.scope, event = params.event, @@ -351,7 +351,7 @@ export default }; }]) - .factory('UpdateJobStatus', ['GetElapsed', 'Empty', 'JobIsFinished', function(GetElapsed, Empty, JobIsFinished) { + .factory('UpdateJobStatus', ['moment', 'GetElapsed', 'Empty', 'JobIsFinished', function(moment, GetElapsed, Empty, JobIsFinished) { return function(params) { var scope = params.scope, failed = params.failed, @@ -363,17 +363,17 @@ export default scope.job_status.status = 'failed'; } if (JobIsFinished(scope) && !Empty(modified)) { - scope.job_status.finished = modified; + scope.job_status.finished = moment(modified).format('l'); } if (!Empty(started) && Empty(scope.job_status.started)) { - scope.job_status.started = started; + scope.job_status.started = moment(started).format('l'); } if (!Empty(scope.job_status.finished) && !Empty(scope.job_status.started)) { scope.job_status.elapsed = GetElapsed({ - start: scope.job_status.started, - end: scope.job_status.finished + start: started, + end: finished }); - } + } }; }]) @@ -959,127 +959,39 @@ export default }; }]) - // 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; - - url = scope.job.related.job_host_summaries + '?'; - url += (scope.search_host_summary_name) ? 'host_name__icontains=' + scope.search_host_summary_name + '&': ''; - url += (scope.search_host_summary_status === 'failed') ? 'failed=true&' : ''; - url += '&page_size=' + scope.hostSummariesMaxRows + '&order=host_name'; - scope.hosts = []; - scope.hostSummariesLoading = true; - - Rest.setUrl(url); - Rest.get() - .success(function(data) { - scope.next_host_summaries = data.next; - scope.hosts = []; - data.results.forEach(function(event) { - var name; - if (event.host_name) { - name = event.host_name; - } - else { - name = ""; - } - scope.hosts.push({ - id: name, - name: event.host_name, - ok: event.ok, - changed: event.changed, - unreachable: event.dark, - failed: event.failures, - status: (event.failed) ? 'failed' : 'successful' - }); - }); - - scope.hostSummariesLoading = false; - 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, - data = params.data, - host; - scope.host_summary.ok = 0; - for (host in data.ok) { - if (!data.changed[host] && !data.dark[host] && !data.failures[host]) { - scope.host_summary.ok += 1; - } - } - scope.host_summary.changed = 0; - for (host in data.changed) { - if (!data.dark[host] && !data.failures[host]) { - scope.host_summary.changed += 1; - } - } - scope.host_summary.unreachable = 0; - for (host in data.dark) { - scope.host_summary.unreachable += 1; - } - scope.host_summary.failed = 0; - for (host in data.failures) { - scope.host_summary.failed += 1; - } - scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed + - scope.host_summary.unreachable + scope.host_summary.failed; - }; - }]) - - .factory('DrawGraph', ['DonutChart', function(DonutChart) { return function(params) { - var scope = params.scope, + var count = params.count, graph_data = []; - // Ready the data - if (scope.host_summary.ok) { + if (count.ok.length > 0) { graph_data.push({ label: 'OK', - value: scope.host_summary.ok, + value: count.ok.length, color: '#60D66F' }); } - if (scope.host_summary.changed) { + if (count.changed.length > 0) { graph_data.push({ label: 'CHANGED', - value: scope.host_summary.changed, + value: count.changed.length, color: '#FF9900' }); } - if (scope.host_summary.unreachable) { + if (count.unreachable.length > 0) { graph_data.push({ label: 'UNREACHABLE', - value: scope.host_summary.unreachable, + value: count.unreachable.length, color: '#FF0000' }); } - if (scope.host_summary.failed) { + if (count.failed.length > 0) { graph_data.push({ label: 'FAILED', - value: scope.host_summary.failed, + value: count.failed.length, color: '#ff5850' }); } - scope.graph_data = graph_data; - var total_count = 0, gd_obj; - for (gd_obj in graph_data) { - total_count += graph_data[gd_obj].value; - } - scope.total_count_for_graph = total_count; DonutChart({ data: graph_data }); @@ -1121,44 +1033,42 @@ export default "font-family": 'Open Sans', "font-style": "normal", "font-weight":400, - "src": "url(/static/assets/OpenSans-Regular.ttf)" + "src": "url(/static/assets/OpenSans-Regular.ttf)", + "width": 500, + "height": 300, }); d3.select(element.find(".nv-label text")[0]) - .attr("class", "DashboardGraphs-hostStatusLabel--successful") + .attr("class", "HostSummary-graph--successful") .style({ "font-family": 'Open Sans', - "text-anchor": "start", "font-size": "16px", "text-transform" : "uppercase", "fill" : colors[0], "src": "url(/static/assets/OpenSans-Regular.ttf)" }); d3.select(element.find(".nv-label text")[1]) - .attr("class", "DashboardGraphs-hostStatusLabel--failed") + .attr("class", "HostSummary-graph--changed") .style({ "font-family": 'Open Sans', - "text-anchor" : "end !imporant", "font-size": "16px", "text-transform" : "uppercase", "fill" : colors[1], "src": "url(/static/assets/OpenSans-Regular.ttf)" }); d3.select(element.find(".nv-label text")[2]) - .attr("class", "DashboardGraphs-hostStatusLabel--successful") + .attr("class", "HostSummary-graph--failed") .style({ "font-family": 'Open Sans', - "text-anchor" : "end !imporant", "font-size": "16px", "text-transform" : "uppercase", "fill" : colors[2], "src": "url(/static/assets/OpenSans-Regular.ttf)" }); d3.select(element.find(".nv-label text")[3]) - .attr("class", "DashboardGraphs-hostStatusLabel--failed") + .attr("class", "HostSummary-graph--unreachable") .style({ "font-family": 'Open Sans', - "text-anchor" : "end !imporant", "font-size": "16px", "text-transform" : "uppercase", "fill" : colors[3], @@ -1399,68 +1309,8 @@ export default }; }]) - .factory('DrawHostSummaries', [ function() { - return function(params) { - var scope = params.scope, - result = [], - filteredListA = [], - filteredListB = [], - idx = 0, - hostSummaries, - key, - keys = Object.keys(scope.jobData.hostSummaries); - if (keys.length > 0) { - hostSummaries = JSON.parse(JSON.stringify(scope.jobData.hostSummaries)); - if (scope.search_host_summary_name) { - for (key in hostSummaries) { - if (hostSummaries[key].name.indexOf(scope.search_host_summary_name) > 0) { - filteredListA[key] = hostSummaries[key]; - } - } - } - else { - filteredListA = hostSummaries; - } - - if (scope.search_host_summary_status === 'failed') { - for (key in filteredListA) { - if (filteredListA[key].status === 'failed' || filteredListA[key].status === 'unreachable') { - filteredListB[key] = filteredListA[key]; - } - } - } - else { - filteredListB = filteredListA; - } - - keys = Object.keys(filteredListB); - - keys.sort(function(a,b) { - if (filteredListB[a].name > filteredListB[b].name) { - return 1; - } - if (filteredListB[a].name < filteredListB[b].name) { - return -1; - } - // a must be equal to b - return 0; - }); - - while (idx < keys.length && result.length < scope.hostSummariesMaxRows) { - result.push(filteredListB[keys[idx]]); - idx++; - } - } - setTimeout( function() { - scope.$apply( function() { - scope.hosts = result; - }); - }); - }; - }]) - - .factory('UpdateDOM', ['DrawPlays', 'DrawTasks', 'DrawHostResults', 'DrawHostSummaries', 'DrawGraph', - function(DrawPlays, DrawTasks, DrawHostResults, DrawHostSummaries, DrawGraph) { + .factory('UpdateDOM', ['DrawPlays', 'DrawTasks', 'DrawHostResults', + function(DrawPlays, DrawTasks, DrawHostResults) { return function(params) { var scope = params.scope; if (!scope.pauseLiveEvents) { @@ -1469,17 +1319,10 @@ export default DrawHostResults({ scope: scope }); } - DrawHostSummaries({ scope: scope }); - setTimeout(function() { scope.playsLoading = false; scope.tasksLoading = false; scope.hostResultsLoading = false; - scope.LoadHostSummaries = false; },100); - - if (scope.host_summary.total > 0) { - DrawGraph({ scope: scope, resize: true }); - } }; }]); diff --git a/awx/ui/client/src/helpers/JobSubmission.js b/awx/ui/client/src/helpers/JobSubmission.js index 37caa00329..e357e5d436 100644 --- a/awx/ui/client/src/helpers/JobSubmission.js +++ b/awx/ui/client/src/helpers/JobSubmission.js @@ -752,9 +752,9 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, * */ // Submit request to run a playbook - .factory('PlaybookRun', ['$location','$stateParams', 'LaunchJob', 'PromptForPasswords', 'Rest', 'GetBasePath', 'Alert', 'ProcessErrors', 'Wait', 'Empty', + .factory('PlaybookRun', ['$location', '$state', '$stateParams', 'LaunchJob', 'PromptForPasswords', 'Rest', 'GetBasePath', 'Alert', 'ProcessErrors', 'Wait', 'Empty', 'PromptForCredential', 'PromptForVars', 'PromptForSurvey' , 'CreateLaunchDialog', - function ($location, $stateParams, LaunchJob, PromptForPasswords, Rest, GetBasePath, Alert, ProcessErrors, Wait, Empty, + function ($location, $state, $stateParams, LaunchJob, PromptForPasswords, Rest, GetBasePath, Alert, ProcessErrors, Wait, Empty, PromptForCredential, PromptForVars, PromptForSurvey, CreateLaunchDialog) { return function (params) { var //parent_scope = params.scope, @@ -803,8 +803,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, var job = data.job || data.system_job; if((scope.portalMode===false || scope.$parent.portalMode===false ) && Empty(data.system_job) || (base === 'home')){ - $location.path('/jobs/' + job); // use $state.go with reload: true option to re-instantiate sockets in + $state.go('jobDetail', {id: job}, {reload: true}) } }); diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary-factory.js b/awx/ui/client/src/job-detail/host-summary/host-summary-factory.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.block.less b/awx/ui/client/src/job-detail/host-summary/host-summary.block.less new file mode 100644 index 0000000000..de182dcbc5 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.block.less @@ -0,0 +1,10 @@ +.HostSummary-graph--successful{ + text-anchor: start !important; +} +.HostSummary-graph--failed{ + text-anchor: end !important; +} +.HostSummary-graph--changed{ + text-anchor: end !important; +} +.HostSUmmary-graph--unreachable{} \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js index 2af1b81443..a457c21ed7 100644 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js @@ -5,49 +5,114 @@ *************************************************/ export default - ['$scope', '$rootScope', '$stateParams', 'JobDetailService', 'jobSocket', function($scope, $rootScope, $stateParams, JobDetailService, jobSocket){ + ['$scope', '$rootScope', '$stateParams', 'Wait', 'JobDetailService', 'jobSocket', 'DrawGraph', function($scope, $rootScope, $stateParams, Wait, JobDetailService, jobSocket, DrawGraph){ - // the job_events socket should be substituted for a job_host_summary socket post 3.0 var page_size = 200; - var socketListener = function(){ - console.log(jobSocket) - jobSocket.on('summary_complete', function(data) { - JobDetailService.getJob($stateParams.id).success(function(res){ - console.log('job at summary_complete.', res) - }); - }); - jobSocket.on('status_changed', function(data) { - JobDetailService.getJob($stateParams.id).success(function(res){ - console.log('job at data.stats.', data.status, res) - }); - JobDetailService.getJobHostSummaries($stateParams.id, {}).success(function(res){ - console.log('jobhostSummaries at summary_complete.', data.status, res) - }); - }); - } - $scope.loading = $scope.hosts.length > 0 ? false : true; - $scope.done = true; - $scope.events = []; - $scope.$watchCollection('events', function(c){ - var filtered = $scope.events.filter(function(event){ - return ((event.failed || event.changed || - 'runner_on_ok' || 'runner_on_async_ok' || - 'runner_on_unreachable' || 'runner_on_skipped') - && event.host_name != ''); - }); - var grouped = _.groupBy(filtered, 'host_name'); - //$scope.hosts = - }); + $scope.loading = $scope.hosts.length > 0 ? false : true; + $scope.filter = 'all'; + $scope.search = null; - $scope.search = function(host_name){}; - $scope.filter = function(filter){}; - - var init = function(){ - socketListener(); - JobDetailService.getJobHostSummaries($stateParams.id, {}).success(function(res){ - console.log('jobhostSummaries at init.', res) - }); + var buildTooltips = function(hosts){ + var count = { + ok : _.filter(hosts, function(o){ + return o.changed === 0 && o.ok > 0; + }), + skipped : _.filter(hosts, function(o){ + return o.skipped > 0; + }), + unreachable : _.filter(hosts, function(o){ + return o.dark > 0; + }), + failed : _.filter(hosts, function(o){ + return o.failed === true; + }), + changed : _.filter(hosts, function(o){ + return o.changed > 0; + }) + }; + var tooltips = { + 0: 'No host events were ', + 1: ' host event was ', + 2: ' host events were ' + }; + return {count, tooltips} }; - init(); - }]; \ No newline at end of file + var socketListener = function(){ + // emitted by the API in the same function used to persist host summary data + // JobEvent.update_host_summary_from_stats() from /awx/main.models.jobs.py + jobSocket.on('summary_complete', function(data) { + // discard socket msgs we don't care about in this context + if ($stateParams.id === data['unified_job_id']){ + JobDetailService.getJobHostSummaries($stateParams.id, {page_size: page_size}) + .success(function(res){ + init() + }); + } + }); + // UnifiedJob.def socketio_emit_status() from /awx/main.models.unified_jobs.py + jobSocket.on('status_changed', function(data) { + if ($stateParams.id === data['unified_job_id']){ + $scope.status = data['status']; + } + }); + }; + + $scope.search = function(){ + Wait('start') + JobDetailService.getJobHostSummaries($stateParams.id, { + page_size: page_size, + host_name__icontains: $scope.searchTerm, + }).success(function(res){ + $scope.hosts = res.results; + $scope.next = res.next; + Wait('stop') + }) + }; + $scope.setFilter = function(filter){ + $scope.filter = filter; + var getAll = function(){ + Wait('start'); + JobDetailService.getJobHostSummaries($stateParams.id, { + page_size: page_size + }).success(function(res){ + Wait('stop') + $scope.hosts = res.results; + $scope.next = res.next; + }); + }; + var getFailed = function(){ + Wait('start'); + JobDetailService.getJobHostSummaries($stateParams.id, { + page_size: page_size, + failed: true + }).success(function(res){ + Wait('stop') + $scope.hosts = res.results; + $scope.next = res.next; + }); + } + var get = filter == 'all' ? getAll() : getFailed() + }; + + $scope.$watchCollection('hosts', function(curr, prev){ + $scope.tooltips = buildTooltips(curr); + DrawGraph({count: $scope.tooltips.count, resize:true}); + }); + + var init = function(){ + Wait('start'); + JobDetailService.getJobHostSummaries($stateParams.id, {page_size: page_size}) + .success(function(res){ + $scope.hosts = res.results; + $scope.next = res.next; + Wait('stop'); + }); + JobDetailService.getJob($stateParams.id) + .success(function(res){ + $scope.status = status; + }); + }; + socketListener(); + init(); + }]; \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html b/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html index d86c5b3545..f44b4540ca 100644 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html @@ -1,66 +1,71 @@ -
+
+
+
+
+
+ + -
-
-
- - - -
-
-
-
- - -
-
-
+
+
+
+
+
+ + +
+
+
-
- - - - - - - -
HostsCompleted Tasks
-
+
+ + + + + + + +
HostsCompleted Tasks
+
-
- - - - - - - - - - - - - - - - -
- {{ host.name }} - - {{ host.ok }} - {{ host.changed }} - {{ host.unreachable }} - {{ host.failed }} -
Waiting...
Loading...
No matching hosts
-
+
+ + + + + + + + + + + + + + + + +
+ {{ host.host_name }} + + {{ host.ok }} + {{ host.changed }} + {{ host.skipped }} + {{ host.dark }} + {{ host.failures }} +
Waiting...
Loading...
No matching hosts
+
-
- -
+
+ +
-
+
-
- -
+
+ +
diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js index cbedbde7cb..9a004fdc8f 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -13,8 +13,7 @@ export default [ '$location', '$rootScope', '$filter', '$scope', '$compile', '$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait', - 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', - 'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList', + 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun', 'LoadPlays', 'LoadTasks', 'HostsEdit', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', @@ -22,8 +21,8 @@ export default function( $location, $rootScope, $filter, $scope, $compile, $stateParams, $log, ClearScope, GetBasePath, Wait, ProcessErrors, - SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, - LoadHostSummary, ReloadHostSummaryList, JobIsFinished, + SelectPlay, SelectTask, Socket, GetElapsed, + JobIsFinished, SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, PlaybookRun, LoadPlays, LoadTasks, HostsEdit, ParseVariableString, GetChoices, fieldChoices, @@ -192,7 +191,6 @@ export default scope.searchPlaysEnabled = true; scope.searchTasksEnabled = true; scope.searchHostsEnabled = true; - scope.searchHostSummaryEnabled = true; scope.search_play_status = 'all'; scope.search_task_status = 'all'; scope.search_host_status = 'all'; @@ -291,10 +289,6 @@ export default }; JobDetailService.getRelatedJobEvents(scope.job.id, params) .success(function(data) { - LoadHostSummary({ - scope: scope, - data: data.results[0].event_data - }); UpdateDOM({ scope: scope }); }) .error(function(data, status) { @@ -623,7 +617,6 @@ export default scope.playsLoading = true; scope.tasksLoading = true; scope.hostResultsLoading = true; - scope.LoadHostSummaries = true; // Load the job record JobDetailService.getJob(job_id) @@ -749,10 +742,6 @@ export default // First time. User just loaded page. scope.$emit('LoadJob'); } - else { - // Check if the graph needs to redraw - setTimeout(function() { DrawGraph({ scope: scope, resize: true }); }, 500); - } }); scope.adjustSize = function() { @@ -800,7 +789,6 @@ export default // Summary table height adjusting. height = ($('#job-detail-container').height() / 2) - $('#hosts-summary-section .JobDetail-searchHeaderRow').outerHeight() - $('#hosts-summary-section .table-header').outerHeight() - 20; - // $('#hosts-summary-table').height(height); //$('#hosts-summary-table').mCustomScrollbar("update"); scope.$emit('RefreshCompleted'); }; @@ -850,52 +838,6 @@ export default } }; - scope.toggleSummary = function(hide) { - var docw, doch, height = $('#job-detail-container').height(), slide_width; - if (!hide) { - docw = $(window).width(); - doch = $(window).height(); - slide_width = (docw < 840) ? '100%' : '80%'; - $('#summary-button').hide(); - $('.overlay').css({ - 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, - width: slide_width, - 'z-index': 1090, - 'padding-right': '15px', - 'padding-left': '15px' - }).show('slide', {'direction': 'right'}); - - setTimeout(function() { DrawGraph({ scope: scope, resize: true }); }, 500); - } - else { - $('.overlay').hide(); - $('#summary-button').show(); - $('#job-summary-container').hide('slide', {'direction': 'right'}); - } - }; - scope.objectIsEmpty = function(obj) { if (angular.isObject(obj)) { return (Object.keys(obj).length > 0) ? false : true; @@ -903,6 +845,17 @@ export default return true; }; + scope.toggleLessEvents = function() { + if (!scope.lessEvents) { + $('#events-summary').slideUp(200); + scope.lessEvents = true; + } + else { + $('#events-summary').slideDown(200); + scope.lessEvents = false; + } + }; + scope.toggleLessStatus = function() { if (!scope.lessStatus) { $('#job-status-form').slideUp(200); @@ -925,18 +878,6 @@ export default } }; - scope.toggleLessEvents = function() { - if (!scope.lessEvents) { - $('#events-summary').slideUp(200); - scope.lessEvents = true; - } - else { - $('#events-summary').slideDown(200); - scope.lessEvents = false; - DrawGraph({scope:scope}); - } - }; - scope.filterPlayStatus = function() { scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all'; if (!scope.liveEventProcessing || scope.pauseLiveEvents) { @@ -1017,86 +958,6 @@ export default } }; - scope.searchHostsKeyPress = function(e) { - if (e.keyCode === 13) { - scope.searchHosts(); - e.stopPropagation(); - } - }; - - scope.searchHostSummary = function() { - if (scope.search_host_summary_name) { - scope.searchHostSummaryEnabled = false; - } - else { - scope.searchHostSummaryEnabled = true; - } - if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - ReloadHostSummaryList({ - scope: scope - }); - } - }; - - scope.searchHostSummaryKeyPress = function(e) { - if (e.keyCode === 13) { - scope.searchHostSummary(); - e.stopPropagation(); - } - }; - - scope.filterTaskStatus = function() { - scope.search_task_status = (scope.search_task_status === 'all') ? 'failed' : 'all'; - if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - LoadTasks({ - scope: scope - }); - } - }; - - scope.filterHostStatus = function() { - scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all'; - if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - var params = { - parent: scope.selectedTask, - event__startswith: 'runner', - page_size: scope.hostResultsMaxRows, - order: 'host_name,counter' - } - if (scope.search_host_status === 'failed'){ - params.failed = true; - } - scope.hostResultsLoading = true; - JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ - scope.hostResults = JobDetailService.processHostEvents(res.results) - scope.hostResultsLoading = false; - }); - } - }; - - scope.filterHostSummaryStatus = function() { - scope.search_host_summary_status = (scope.search_host_summary_status === 'all') ? 'failed' : 'all'; - if (!scope.liveEventProcessing || scope.pauseLiveEvents) { - // /api/v1/jobs/11/job_host_summaries/?failed=true&&page_size=200&order=host_name - var params = { - page_size: scope.hostSummariesMaxRows, - order: 'host_name' - } - if (scope.search_host_summary_status === 'failed'){ - params.failed = true; - } - /* - JobDetailService.getJobHostSummaries(scope.job.id, params).success(function(res){ - scope.next_host_summaries = res.next; - scope.hosts = res.results; - console.log(res.results) - }); - */ - ReloadHostSummaryList({ - scope: scope - }); - } - }; if (scope.removeDeleteFinished) { scope.removeDeleteFinished(); diff --git a/awx/ui/client/src/job-detail/job-detail.partial.html b/awx/ui/client/src/job-detail/job-detail.partial.html index 616b463386..8d723b4dd8 100644 --- a/awx/ui/client/src/job-detail/job-detail.partial.html +++ b/awx/ui/client/src/job-detail/job-detail.partial.html @@ -389,7 +389,7 @@ - From 833f68dd7f4180adf30a94c84b0811b8134f71a5 Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Sat, 9 Apr 2016 11:05:18 -0400 Subject: [PATCH 04/16] responsive job details & extend GetBaseUrl with /api/v1/job_events endpoint. resolves #1263 --- awx/ui/client/src/helpers/Jobs.js | 2 +- .../host-event/host-event-modal.partial.html | 2 +- .../host-event/host-event.controller.js | 14 +++--- .../job-detail/host-event/host-event.route.js | 21 ++------ .../host-events/host-events.block.less | 3 ++ .../host-summary/host-summary.controller.js | 12 ++--- .../src/job-detail/job-detail.block.less | 33 +++++++++---- .../src/job-detail/job-detail.controller.js | 48 +++---------------- .../src/job-detail/job-detail.partial.html | 4 +- .../src/job-detail/job-detail.service.js | 13 +++++ awx/ui/client/src/shared/api-loader.js | 2 + 11 files changed, 67 insertions(+), 87 deletions(-) diff --git a/awx/ui/client/src/helpers/Jobs.js b/awx/ui/client/src/helpers/Jobs.js index 7700bdcd1d..6b0095b6da 100644 --- a/awx/ui/client/src/helpers/Jobs.js +++ b/awx/ui/client/src/helpers/Jobs.js @@ -75,7 +75,7 @@ export default scope.viewJobDetails = function(job) { var goToJobDetails = function(state) { - $state.go(state, {id: job.id}); + $state.go(state, {id: job.id}, {reload:true}); } switch(job.type) { diff --git a/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html index 1981b61a04..919617a333 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html +++ b/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html @@ -1,4 +1,4 @@ -