diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js index 562b73d0eb..90c68cc943 100644 --- a/awx/ui/client/src/helpers/JobDetail.js +++ b/awx/ui/client/src/helpers/JobDetail.js @@ -42,7 +42,7 @@ export default .factory('DigestEvent', ['$rootScope', '$log', 'UpdatePlayStatus', 'UpdateHostStatus', 'AddHostResult', 'GetElapsed', 'UpdateTaskStatus', 'JobIsFinished', 'AddNewTask', 'AddNewPlay', function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, GetElapsed, - UpdateTaskStatus, JobIsFinished, AddNewTask, AddNewPlay, longDateFilter) { + UpdateTaskStatus, JobIsFinished, AddNewTask, AddNewPlay) { return function(params) { var scope = params.scope, @@ -485,8 +485,7 @@ export default created = params.created, msg = params.message, item = params.item, - counter = params.counter, - h, host; + counter = params.counter; if (scope.jobData.hostSummaries[host_id] !== undefined) { scope.jobData.hostSummaries[host_id].ok += (status === 'successful') ? 1 : 0; @@ -920,7 +919,7 @@ export default order: 'host_name,counter', }; JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){ - scope.hostResults = JobDetailService.processHostEvents(res.results) + scope.hostResults = JobDetailService.processHostEvents(res.results); scope.hostResultsLoading = false; }); }; diff --git a/awx/ui/client/src/job-detail/host-events/host-events.controller.js b/awx/ui/client/src/job-detail/host-events/host-events.controller.js index 15ab24d4ca..8869248a04 100644 --- a/awx/ui/client/src/job-detail/host-events/host-events.controller.js +++ b/awx/ui/client/src/job-detail/host-events/host-events.controller.js @@ -110,7 +110,6 @@ var init = function(){ $scope.hostName = $stateParams.hostName; // create filter dropdown - console.log($stateParams) CreateSelect2({ element: '.HostEvents-select', multiple: false 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 e06ee53611..692d10bd5d 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 @@ -8,14 +8,13 @@ ['$scope', '$rootScope', '$stateParams', 'Wait', 'JobDetailService', 'jobSocket', 'DrawGraph', function($scope, $rootScope, $stateParams, Wait, JobDetailService, jobSocket, DrawGraph){ var page_size = 200; - $scope.loading = $scope.hosts.length > 0 ? false : true; $scope.filter = 'all'; $scope.search = null; - var buildTooltips = function(hosts){ + var buildGraph = function(hosts){ // status waterfall: unreachable > failed > changed > ok > skipped - var count, grammar, text = {}; + var count; count = { ok : _.filter(hosts, function(o){ return o.failures === 0 && o.changed === 0 && o.ok > 0; @@ -33,6 +32,25 @@ return o.changed > 0; }) }; + return count; + }; + 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']){ + 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.buildTooltip = function(n, status){ var grammar = function(n, status){ var dict = { 0: 'No host events were ', @@ -46,28 +64,13 @@ return n !== 0 ? n + dict[n] + status : dict[n] + status; } }; + /* _.forIn(count, function(value, key){ text[key] = grammar(value.length, key); }); - return {count, text} + */ + return grammar(n, status) }; - 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']){ - 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.getNextPage = function(){ if ($scope.next){ JobDetailService.getNextPage($scope.next).success(function(res){ @@ -80,14 +83,14 @@ } }; $scope.search = function(){ - Wait('start') + 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') + Wait('stop'); }) }; $scope.setFilter = function(filter){ @@ -113,12 +116,12 @@ $scope.next = res.next; }); } - var get = filter == 'all' ? getAll() : getFailed() + var get = filter == 'all' ? getAll() : getFailed(); }; $scope.$watchCollection('hosts', function(curr, prev){ - $scope.tooltips = buildTooltips(curr); - DrawGraph({count: $scope.tooltips.count, resize:true}); + $scope.count = buildGraph(curr); + DrawGraph({count: $scope.count, resize:true}); }); var init = function(){ @@ -129,9 +132,9 @@ $scope.next = res.next; Wait('stop'); }); - JobDetailService.getJob($stateParams.id) + JobDetailService.getJob({id: $stateParams.id}) .success(function(res){ - $scope.status = status; + $scope.status = res.results[0].status; }); }; socketListener(); 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 0011d4a97d..84d3b3aba5 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 @@ -14,9 +14,9 @@
+ class="JobDetail-tableToggle btn btn-xs" ng-class="{'btn-default': filter === 'failed', 'btn-primary': filter === 'all'}">All + ng-class="{'btn-default': filter === 'all', 'btn-primary': filter === 'failed'}" ng-disabled='count.failures == 0' class="JobDetail-tableToggle btn btn-xs">Failed
@@ -40,11 +40,11 @@ {{ host.host_name }} - {{ host.ok - host.changed }} - {{ host.changed }} - {{ host.skipped }} - {{ host.dark }} - {{ host.failures }} + {{ host.ok - host.changed }} + {{ host.changed }} + {{ host.skipped }} + {{ host.dark }} + {{ host.failures }} diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.route.js b/awx/ui/client/src/job-detail/host-summary/host-summary.route.js new file mode 100644 index 0000000000..f451b63ad5 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.route.js @@ -0,0 +1,27 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import {templateUrl} from '../../shared/template-url/template-url.factory'; + +export default { + name: 'jobDetail.host-summary', + resolve: { + jobSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { + var job_socket = Socket({ + scope: $rootScope, + endpoint: "jobs" + }); + job_socket.init(); + return job_socket; + }] + }, + views:{ + 'host-summary': { + controller: 'HostSummaryController', + templateUrl: templateUrl('job-detail/host-summary/host-summary'), + } + } +}; diff --git a/awx/ui/client/src/job-detail/host-summary/main.js b/awx/ui/client/src/job-detail/host-summary/main.js new file mode 100644 index 0000000000..fad85ffaf3 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-summary/main.js @@ -0,0 +1,15 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import route from './host-summary.route'; +import controller from './host-summary.controller'; + +export default + angular.module('jobDetail.hostSummary', []) + .controller('HostSummaryController', controller) + .run(['$stateExtender', function($stateExtender){ + $stateExtender.addState(route); + }]); \ No newline at end of file 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 4c1ed966ce..80f4c9d50c 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -413,7 +413,8 @@ export default var params = { order_by: 'id' }; - JobDetailService.getJobPlays(scope.job.id, params) + if (scope.job.summary_fields.unified_job_template.unified_job_type == 'job'){ + JobDetailService.getJobPlays(scope.job.id, params) .success( function(data) { scope.next_plays = data.next; if (data.results.length > 0) { @@ -498,6 +499,7 @@ export default } scope.$emit('LoadTasks', events_url); }); + } }); @@ -513,9 +515,10 @@ export default scope.hostResultsLoading = true; // Load the job record - JobDetailService.getJob(job_id) - .success(function(data) { - var i; + JobDetailService.getJob({id: job_id}) + .success(function(res) { + var i, + data = res.results[0]; scope.job = data; scope.job_template_name = data.name; scope.project_name = (data.summary_fields.project) ? data.summary_fields.project.name : ''; 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 d5aac4646b..585b18a071 100644 --- a/awx/ui/client/src/job-detail/job-detail.partial.html +++ b/awx/ui/client/src/job-detail/job-detail.partial.html @@ -157,7 +157,7 @@ -
+
@@ -376,21 +376,21 @@
-
+
-
-
+
+
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 7c4b811c62..7ab8102253 100644 --- a/awx/ui/client/src/job-detail/job-detail.route.js +++ b/awx/ui/client/src/job-detail/job-detail.route.js @@ -38,19 +38,9 @@ export default { 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 - } - } + templateUrl: templateUrl('job-detail/job-detail'), + controller: 'JobDetailController' }; 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 e144bdc735..b50d14630b 100644 --- a/awx/ui/client/src/job-detail/job-detail.service.js +++ b/awx/ui/client/src/job-detail/job-detail.service.js @@ -2,13 +2,10 @@ export default ['$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; - */ + stringifyParams: function(params){ + return _.reduce(params, (result, value, key) => { + return result + key + '=' + value + '&'}, ''); + }, // the the API passes through Ansible's event_data response // we need to massage away the verbose and redundant properties @@ -129,12 +126,7 @@ export default // ?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]; - }); + url = url + id + '/job_events/?' + this.stringifyParams(params); Rest.setUrl(url); return Rest.get() .success(function(data){ @@ -162,11 +154,7 @@ export default // 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]; - }); + url = url + id + '/job_host_summaries/?' + this.stringifyParams(params); Rest.setUrl(url); return Rest.get() .success(function(data){ @@ -181,11 +169,7 @@ export default // 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]; - }); + url = url + id + '/job_plays/?' + this.stringifyParams(params); Rest.setUrl(url); return Rest.get() .success(function(data){ @@ -198,11 +182,7 @@ export default }, 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]; - }); + url = url + id + '/job_tasks/?' + this.stringifyParams(params); Rest.setUrl(url); return Rest.get() .success(function(data){ @@ -213,9 +193,8 @@ export default msg: 'Call to ' + url + '. GET returned: ' + status }); }); }, - getJob: function(id){ - var url = GetBasePath('jobs'); - url = url + id; + getJob: function(params){ + var url = GetBasePath('unified_jobs') + '?' + this.stringifyParams(params); Rest.setUrl(url); return Rest.get() .success(function(data){ diff --git a/awx/ui/client/src/job-detail/main.js b/awx/ui/client/src/job-detail/main.js index f497b76677..891bfe373b 100644 --- a/awx/ui/client/src/job-detail/main.js +++ b/awx/ui/client/src/job-detail/main.js @@ -9,11 +9,13 @@ import controller from './job-detail.controller'; import service from './job-detail.service'; import hostEvents from './host-events/main'; import hostEvent from './host-event/main'; +import hostSummary from './host-summary/main'; export default angular.module('jobDetail', [ hostEvents.name, - hostEvent.name + hostEvent.name, + hostSummary.name ]) .controller('JobDetailController', controller) .service('JobDetailService', service)