From 5c22cb1f698282ae79d0d2090d345fc35f31bfeb Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Tue, 29 Nov 2016 17:39:56 -0800 Subject: [PATCH 1/7] moving some functions from JobDetailService to jobResultsService in order to decouple the old job details from the new job results so we can remove the job detail files at some point --- .../host-event/host-event.controller.js | 6 +- .../host-event/host-event.route.js | 8 +- .../src/job-results/job-results.service.js | 98 ++++++++++++++++++- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/awx/ui/client/src/job-results/host-event/host-event.controller.js b/awx/ui/client/src/job-results/host-event/host-event.controller.js index 6015dd3a63..e6c5fc71c7 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.controller.js +++ b/awx/ui/client/src/job-results/host-event/host-event.controller.js @@ -6,10 +6,10 @@ export default - ['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'hostEvent', 'hostResults', - function($stateParams, $scope, $state, Wait, JobDetailService, hostEvent, hostResults){ + ['$stateParams', '$scope', '$state', 'Wait', 'jobResultsService', 'hostEvent', 'hostResults', + function($stateParams, $scope, $state, Wait, jobResultsService, hostEvent, hostResults){ - $scope.processEventStatus = JobDetailService.processEventStatus; + $scope.processEventStatus = jobResultsService.processEventStatus; $scope.hostResults = []; // Avoid rendering objects in the details fieldset // ng-if="processResults(value)" via host-event-details.partial.html diff --git a/awx/ui/client/src/job-results/host-event/host-event.route.js b/awx/ui/client/src/job-results/host-event/host-event.route.js index 23d5fe2451..eb796fa7df 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.route.js +++ b/awx/ui/client/src/job-results/host-event/host-event.route.js @@ -13,14 +13,14 @@ var hostEventModal = { templateUrl: templateUrl('job-results/host-event/host-event-modal'), 'abstract': false, resolve: { - hostEvent: ['JobDetailService', '$stateParams', function(JobDetailService, $stateParams) { - return JobDetailService.getRelatedJobEvents($stateParams.id, { + hostEvent: ['jobResultsService', '$stateParams', function(jobResultsService, $stateParams) { + return jobResultsService.getRelatedJobEvents($stateParams.id, { id: $stateParams.eventId }).then(function(res) { return res.data.results[0]; }); }], - hostResults: ['JobDetailService', '$stateParams', function(JobDetailService, $stateParams) { - return JobDetailService.getJobEventChildren($stateParams.taskId).then(res => res.data.results); + hostResults: ['jobResultsService', '$stateParams', function(jobResultsService, $stateParams) { + return jobResultsService.getJobEventChildren($stateParams.taskId).then(res => res.data.results); }] }, onExit: function() { diff --git a/awx/ui/client/src/job-results/job-results.service.js b/awx/ui/client/src/job-results/job-results.service.js index cb51dc8864..3817a922b8 100644 --- a/awx/ui/client/src/job-results/job-results.service.js +++ b/awx/ui/client/src/job-results/job-results.service.js @@ -5,8 +5,8 @@ *************************************************/ -export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', 'GetBasePath', 'Alert', -function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun, GetBasePath, Alert) { +export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', 'GetBasePath', 'Alert', '$rootScope', +function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun, GetBasePath, Alert, $rootScope) { var val = { // the playbook_on_stats event returns the count data in a weird format. // format to what we need! @@ -190,6 +190,100 @@ function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybo }); return val.promise; + }, + // 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 for more filters to support + processEventStatus: function(event){ + 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' + }; + } + // 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' || 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' + }; + } + }, + // 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/?' + this.stringifyParams(params); + 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 }); + }); + }, + getJobEventChildren: function(id){ + var url = GetBasePath('job_events'); + url = url + id + '/children/?order_by=host_name'; + 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 }); + }); + }, + 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 & redundant stdout/stderr properties + processJson: function(data){ + // configure fields to ignore + var ignored = [ + 'type', + 'event_data', + 'related', + 'summary_fields', + 'url', + 'ansible_facts', + ]; + // remove ignored properties + var result = _.chain(data).cloneDeep().forEach(function(value, key, collection){ + if (ignored.indexOf(key) > -1){ + delete collection[key]; + } + }).value(); + return result; } }; return val; From edaf3e1f2555e15c973141698e751b6e26e263b9 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Tue, 28 Feb 2017 11:54:09 -0800 Subject: [PATCH 2/7] removing old job-details folder --- .../host-event-codemirror.partial.html | 2 - .../host-event-details.partial.html | 45 -- .../host-event/host-event-modal.partial.html | 36 -- .../host-event/host-event-timing.partial.html | 1 - .../host-event/host-event.block.less | 150 ------ .../host-event/host-event.controller.js | 110 ----- .../job-detail/host-event/host-event.route.js | 65 --- .../client/src/job-detail/host-event/main.js | 21 - .../host-events/host-events.route.js | 32 -- .../client/src/job-detail/host-events/main.js | 15 - .../host-summary/host-summary.block.less | 17 - .../host-summary/host-summary.partial.html | 72 --- .../host-summary/host-summary.route.js | 21 - .../src/job-detail/host-summary/main.js | 15 - .../src/job-detail/job-detail.block.less | 240 ---------- .../src/job-detail/job-detail.partial.html | 435 ------------------ .../client/src/job-detail/job-detail.route.js | 91 ---- .../src/job-detail/job-detail.service.js | 215 --------- awx/ui/client/src/job-detail/main.js | 24 - 19 files changed, 1607 deletions(-) delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event-codemirror.partial.html delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event-details.partial.html delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event.block.less delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event.controller.js delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event.route.js delete mode 100644 awx/ui/client/src/job-detail/host-event/main.js delete mode 100644 awx/ui/client/src/job-detail/host-events/host-events.route.js delete mode 100644 awx/ui/client/src/job-detail/host-events/main.js delete mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.block.less delete mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.partial.html delete mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.route.js delete mode 100644 awx/ui/client/src/job-detail/host-summary/main.js delete mode 100644 awx/ui/client/src/job-detail/job-detail.block.less delete mode 100644 awx/ui/client/src/job-detail/job-detail.partial.html delete mode 100644 awx/ui/client/src/job-detail/job-detail.route.js delete mode 100644 awx/ui/client/src/job-detail/job-detail.service.js delete mode 100644 awx/ui/client/src/job-detail/main.js diff --git a/awx/ui/client/src/job-detail/host-event/host-event-codemirror.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-codemirror.partial.html deleted file mode 100644 index 7c744d2169..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event-codemirror.partial.html +++ /dev/null @@ -1,2 +0,0 @@ - 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 deleted file mode 100644 index c287788f19..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event-details.partial.html +++ /dev/null @@ -1,45 +0,0 @@ -
-
EVENT
- -
- STATUS - - - - - {{processEventStatus(event).status || "No result found"}} - -
-
- ID - {{event.id || "No result found"}} -
-
- CREATED - {{(event.created | longDate) || "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}} -
-
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 deleted file mode 100644 index db236894e8..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html deleted file mode 100644 index 06171bd1c5..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html +++ /dev/null @@ -1 +0,0 @@ -
timing
\ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-event/host-event.block.less b/awx/ui/client/src/job-detail/host-event/host-event.block.less deleted file mode 100644 index 9b31b74e87..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event.block.less +++ /dev/null @@ -1,150 +0,0 @@ -// @import "./client/src/shared/branding/colors.less"; -// @import "./client/src/shared/branding/colors.default.less"; -// @import "./client/src/shared/layouts/one-plus-two.less"; -// -// .noselect { -// -webkit-touch-callout: none; /* iOS Safari */ -// -webkit-user-select: none; /* Chrome/Safari/Opera */ -// -khtml-user-select: none; /* Konqueror */ -// -moz-user-select: none; /* Firefox */ -// -ms-user-select: none; /* Internet Explorer/Edge */ -// user-select: none; /* Non-prefixed version, currently -// not supported by any browser */ -// } -// -// @media screen and (min-width: 768px){ -// .HostEvent .modal-dialog{ -// width: 700px; -// } -// } -// .HostEvent .CodeMirror{ -// overflow-x: hidden; -// } -// .HostEvent-controls button.HostEvent-close{ -// color: #FFFFFF; -// text-transform: uppercase; -// padding-left: 15px; -// padding-right: 15px; -// background-color: @default-link; -// border-color: @default-link; -// &:hover{ -// background-color: @default-link-hov; -// border-color: @default-link-hov; -// } -// } -// .HostEvent-body{ -// margin-bottom: 10px; -// } -// .HostEvent-tab { -// color: @btn-txt; -// background-color: @btn-bg; -// font-size: 12px; -// border: 1px solid @btn-bord; -// height: 30px; -// border-radius: 5px; -// margin-right: 20px; -// padding-left: 10px; -// padding-right: 10px; -// padding-bottom: 5px; -// padding-top: 5px; -// transition: background-color 0.2s; -// text-transform: uppercase; -// text-align: center; -// white-space: nowrap; -// .noselect; -// } -// .HostEvent-tab:hover { -// color: @btn-txt; -// background-color: @btn-bg-hov; -// cursor: pointer; -// } -// .HostEvent-tab--selected{ -// color: @btn-txt-sel!important; -// background-color: @default-icon!important; -// border-color: @default-icon!important; -// } -// .HostEvent-view--container{ -// width: 100%; -// display: flex; -// flex-direction: row; -// flex-wrap: nowrap; -// justify-content: space-between; -// } -// .HostEvent .modal-footer{ -// border: 0; -// margin-top: 0px; -// padding-top: 5px; -// } -// .HostEvent-controls{ -// float: right; -// button { -// margin-left: 10px; -// } -// } -// .HostEvent-status--ok{ -// color: @green; -// } -// .HostEvent-status--unreachable{ -// color: @unreachable; -// } -// .HostEvent-status--changed{ -// color: @changed; -// } -// .HostEvent-status--failed{ -// color: @default-err; -// } -// .HostEvent-status--skipped{ -// color: @skipped; -// } -// .HostEvent-title{ -// color: @default-interface-txt; -// font-weight: 600; -// margin-bottom: 8px; -// } -// // .HostEvent .modal-body{ -// // max-height: 500px; -// // overflow-y: auto; -// // padding: 20px; -// // } -// .HostEvent-nav{ -// padding-top: 12px; -// padding-bottom: 12px; -// } -// .HostEvent-field{ -// margin-bottom: 8px; -// flex: 0 1 12em; -// } -// .HostEvent-field--label{ -// text-transform: uppercase; -// flex: 0 1 80px; -// max-width: 80px; -// font-size: 12px; -// word-wrap: break-word; -// } -// .HostEvent-field{ -// .OnePlusTwo-left--detailsRow; -// } -// .HostEvent-field--content{ -// word-wrap: break-word; -// max-width: 13em; -// flex: 0 1 13em; -// } -// .HostEvent-details--left, .HostEvent-details--right{ -// flex: 1 1 47%; -// } -// .HostEvent-details--left{ -// margin-right: 40px; -// } -// .HostEvent-details--right{ -// .HostEvent-field--label{ -// flex: 0 1 25em; -// } -// .HostEvent-field--content{ -// max-width: 15em; -// flex: 0 1 15em; -// align-self: flex-end; -// } -// } -// .HostEvent-button:disabled { -// pointer-events: all!important; -// } 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 deleted file mode 100644 index f86452b005..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event.controller.js +++ /dev/null @@ -1,110 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - - export default - ['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'hostEvent', 'hostResults', - function($stateParams, $scope, $state, Wait, JobDetailService, hostEvent, hostResults){ - - $scope.processEventStatus = JobDetailService.processEventStatus; - $scope.hostResults = []; - // 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.isStdOut = function(){ - if ($state.current.name === 'jobDetails.host-event.stdout' || $state.current.name === 'jobDetaisl.histe-event.stderr'){ - return 'StandardOut-preContainer StandardOut-preContent'; - } - }; - /*ignore jslint start*/ - var initCodeMirror = function(el, data, mode){ - var container = document.getElementById(el); - var editor = CodeMirror.fromTextArea(container, { // jshint ignore:line - lineNumbers: true, - mode: mode - }); - editor.setSize("100%", 300); - editor.getDoc().setValue(data); - }; - /*ignore jslint end*/ - $scope.isActiveState = function(name){ - return $state.current.name === name; - }; - - $scope.getActiveHostIndex = function(){ - var result = $scope.hostResults.filter(function( obj ) { - return obj.id === $scope.event.id; - }); - return $scope.hostResults.indexOf(result[0]); - }; - - $scope.showPrev = function(){ - return $scope.getActiveHostIndex() !== 0; - }; - - $scope.showNext = function(){ - return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]); - }; - - $scope.goNext = function(){ - var index = $scope.getActiveHostIndex() + 1; - var id = $scope.hostResults[index].id; - $state.go('jobDetail.host-event.details', {eventId: id}); - }; - - $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(){ - $scope.event = _.cloneDeep(hostEvent); - $scope.hostResults = hostResults; - $scope.json = JobDetailService.processJson(hostEvent); - - // grab standard out & standard error if present, and remove from the results displayed in the details panel - if (hostEvent.event_data.res.stdout){ - $scope.stdout = hostEvent.event_data.res.stdout; - delete $scope.event.event_data.res.stdout; - } - if (hostEvent.event_data.res.stderr){ - $scope.stderr = hostEvent.event_data.res.stderr; - delete $scope.event.event_data.res.stderr; - } - // instantiate Codemirror - // try/catch pattern prevents the abstract-state controller from complaining about element being null - if ($state.current.name === 'jobDetail.host-event.json'){ - try{ - initCodeMirror('HostEvent-codemirror', JSON.stringify($scope.json, null, 4), {name: "javascript", json: true}); - } - catch(err){ - // element with id HostEvent-codemirror is not the view controlled by this instance of HostEventController - } - } - else if ($state.current.name === 'jobDetail.host-event.stdout'){ - try{ - initCodeMirror('HostEvent-codemirror', $scope.stdout, 'shell'); - } - catch(err){ - // element with id HostEvent-codemirror is not the view controlled by this instance of HostEventController - } - } - else if ($state.current.name === 'jobDetail.host-event.stderr'){ - try{ - initCodeMirror('HostEvent-codemirror', $scope.stderr, 'shell'); - } - catch(err){ - // element with id HostEvent-codemirror is not the view controlled by this instance of HostEventController - } - } - $('#HostEvent').modal('show'); - }; - init(); - }]; 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 deleted file mode 100644 index 86e499c2b0..0000000000 --- a/awx/ui/client/src/job-detail/host-event/host-event.route.js +++ /dev/null @@ -1,65 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import { templateUrl } from '../../shared/template-url/template-url.factory'; - -var hostEventModal = { - name: 'jobDetail.host-event', - url: '/task/:taskId/host-event/:eventId', - controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-modal'), - 'abstract': true, - resolve: { - hostEvent: ['JobDetailService', '$stateParams', function(JobDetailService, $stateParams) { - return JobDetailService.getRelatedJobEvents($stateParams.id, { - id: $stateParams.eventId - }).then(function(res) { - return res.data.results[0]; }); - }], - hostResults: ['JobDetailService', '$stateParams', function(JobDetailService, $stateParams) { - return JobDetailService.getJobEventChildren($stateParams.taskUuid).then(res => res.data.results); - }] - }, - onExit: function() { - // close the modal - // using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X" - $('#HostEvent').modal('hide'); - // hacky way to handle user browsing away via URL bar - $('.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'), -}; - -var hostEventJson = { - name: 'jobDetail.host-event.json', - url: '/json', - controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-codemirror') -}; - -var hostEventStdout = { - name: 'jobDetail.host-event.stdout', - url: '/stdout', - controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-codemirror') -}; - -var hostEventStderr = { - name: 'jobDetail.host-event.stderr', - url: '/stderr', - controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-codemirror') -}; - - -export { hostEventDetails, hostEventJson, hostEventModal, hostEventStdout, hostEventStderr }; diff --git a/awx/ui/client/src/job-detail/host-event/main.js b/awx/ui/client/src/job-detail/host-event/main.js deleted file mode 100644 index 4379427ff8..0000000000 --- a/awx/ui/client/src/job-detail/host-event/main.js +++ /dev/null @@ -1,21 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - import {hostEventModal, hostEventDetails, - hostEventJson, hostEventStdout, hostEventStderr} from './host-event.route'; - import controller from './host-event.controller'; - - export default - angular.module('jobDetail.hostEvent', []) - .controller('HostEventController', controller) - - .run(['$stateExtender', function($stateExtender){ - $stateExtender.addState(hostEventModal); - $stateExtender.addState(hostEventDetails); - $stateExtender.addState(hostEventJson); - $stateExtender.addState(hostEventStdout); - $stateExtender.addState(hostEventStderr); - }]); diff --git a/awx/ui/client/src/job-detail/host-events/host-events.route.js b/awx/ui/client/src/job-detail/host-events/host-events.route.js deleted file mode 100644 index 835d17b2b9..0000000000 --- a/awx/ui/client/src/job-detail/host-events/host-events.route.js +++ /dev/null @@ -1,32 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../../shared/template-url/template-url.factory'; - -export default { - name: 'jobDetail.host-events', - url: '/host-events/{hostName:any}?:filter', - controller: 'HostEventsController', - params: { - page_size: 10 - }, - templateUrl: templateUrl('job-detail/host-events/host-events'), - onExit: function(){ - // close the modal - // using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X" - $('#HostEvents').modal('hide'); - // hacky way to handle user browsing away via URL bar - $('.modal-backdrop').remove(); - $('body').removeClass('modal-open'); - }, - resolve: { - hosts: ['JobDetailService','$stateParams', function(JobDetailService, $stateParams) { - return JobDetailService.getRelatedJobEvents($stateParams.id, { - host_name: $stateParams.hostName - }).success(function(res){ return res.results[0];}); - }] - } -}; diff --git a/awx/ui/client/src/job-detail/host-events/main.js b/awx/ui/client/src/job-detail/host-events/main.js deleted file mode 100644 index 766dd92ca4..0000000000 --- a/awx/ui/client/src/job-detail/host-events/main.js +++ /dev/null @@ -1,15 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import route from './host-events.route'; -import controller from './host-events.controller'; - -export default - angular.module('jobDetail.hostEvents', []) - .controller('HostEventsController', controller) - .run(['$stateExtender', function($stateExtender){ - $stateExtender.addState(route); - }]); 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 deleted file mode 100644 index 00af0d30ea..0000000000 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.block.less +++ /dev/null @@ -1,17 +0,0 @@ -@import '../../shared/branding/colors.default.less'; -.HostSummary-graph--successful{ - text-anchor: start !important; -} -.HostSummary-graph--failed{ - text-anchor: end !important; -} -.HostSummary-graph--changed{ - text-anchor: start !important; -} -.HostSummary-loading{ - border: none; -} -.HostSummary-loading{ - padding-left: 0px !important; - color: @default-interface-txt; -} 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 deleted file mode 100644 index 5452990e76..0000000000 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.partial.html +++ /dev/null @@ -1,72 +0,0 @@ - -
-
4 Please select a host below to view a summary of all associated tasks.
-
-
-
-
- - - -
-
-
-
-
- - -
-
-
- -
- - - - - - - -
HostsCompleted Tasks
-
- -
- - - - - - - - - - - - - - - - -
- {{ host.host_name }} - - {{ host.ok - host.changed }} - {{ host.changed }} - {{ host.skipped }} - {{ host.dark }} - {{ host.failures }} -
Initiating job run.
Job is running. Summary will be available on completion.
No matching hosts
-
- -
- -
- -
-
Host Status Summary
-
- -
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 deleted file mode 100644 index a2de70e5d4..0000000000 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.route.js +++ /dev/null @@ -1,21 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import {templateUrl} from '../../shared/template-url/template-url.factory'; - -export default { - name: 'jobDetail.host-summary', - url: '/event-summary', - views:{ - 'host-summary': { - controller: 'HostSummaryController', - templateUrl: templateUrl('job-detail/host-summary/host-summary'), - } - }, - ncyBreadcrumb: { - skip: true // Never display this state in breadcrumb. - } -}; diff --git a/awx/ui/client/src/job-detail/host-summary/main.js b/awx/ui/client/src/job-detail/host-summary/main.js deleted file mode 100644 index fad85ffaf3..0000000000 --- a/awx/ui/client/src/job-detail/host-summary/main.js +++ /dev/null @@ -1,15 +0,0 @@ -/************************************************* - * 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.block.less b/awx/ui/client/src/job-detail/job-detail.block.less deleted file mode 100644 index c23b8d321d..0000000000 --- a/awx/ui/client/src/job-detail/job-detail.block.less +++ /dev/null @@ -1,240 +0,0 @@ -/** @define SetupItem */ - -@import '../shared/branding/colors.less'; -@import '../shared/branding/colors.default.less'; -@import '../shared/layouts/one-plus-two.less'; - -@breakpoint-md: 1200px; -@breakpoint-sm: 623px; - -.JobDetail-tasks.section{ - margin-top:40px; -} -.JobDetail-instructions{ - color: @default-interface-txt; - margin: 10px 0 10px 0; - - .badge { - background-color: @default-list-header-bg; - color: @default-interface-txt; - padding: 5px 7px; - } -} -.JobDetail{ - .OnePlusTwo-container(100%, @breakpoint-md); - - &.fullscreen { - .JobDetail-rightSide { - max-width: 100%; - } - } -} - -.JobDetail-leftSide{ - .OnePlusTwo-left--panel(100%, @breakpoint-md); -} - -.JobDetail-rightSide{ - .OnePlusTwo-right--panel(100%, @breakpoint-md); - @media (max-width: @breakpoint-md - 1px) { - padding-right: 15px; - } -} -.JobDetail-panelHeader{ - display: flex; - height: 30px; -} -.JobDetail-expandContainer{ - flex: 1; - margin: 0px; - line-height: 30px; - white-space: nowrap; -} - -.JobDetail-panelHeaderText{ - color: @default-interface-txt; - flex: 1 0 auto; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - text-transform: uppercase; -} - -.JobDetail-panelHeaderText:hover{ - color: @default-interface-txt; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - text-transform: uppercase; -} - -.JobDetail-expandArrow{ - color: @default-icon-hov; - font-size: 14px; - font-weight: bold; - margin-right: 10px; - text-transform: uppercase; - margin-left: 10px; -} - -.JobDetail-resultsDetails{ - display: flex; - flex-wrap: wrap; - flex-direction: row; - padding-top: 25px; - @media screen and(max-width: @breakpoint-sm){ - flex-direction: column; - } -} - -.JobDetail-resultRow{ - width: 100%; - display: flex; - padding-bottom: 10px; - flex-wrap: wrap; -} - -.JobDetail-resultRow--variables { - flex-direction: column; -} - -.JobDetail-resultRowLabel{ - text-transform: uppercase; - color: @default-interface-txt; - font-size: 14px; - font-weight: normal!important; - width: 30%; - margin-right: 20px; - @media screen and(max-width: @breakpoint-md){ - flex: 2.5 0 auto; - } -} - -.JobDetail-resultRowLabel--fullWidth { - width: 100%; - margin-right: 0px; -} - -.JobDetail-resultRowText{ - width: ~"calc(70% - 20px)"; - flex: 1 0 auto; - text-transform: none; - word-wrap: break-word; -} - -.JobDetail-resultRowText--fullWidth { - width: 100%; -} - -.JobDetail-searchHeaderRow{ - display: flex; - flex-wrap: wrap; - flex-direction: row; - height: 50px; - margin-top: 20px; - @media screen and(max-width: @breakpoint-sm){ - height: auto; - } -} - -.JobDetail-searchContainer{ - flex: 2 0 auto; - @media screen and(max-width: @breakpoint-sm){ - margin-bottom: 0px; - } -} - -.JobDetail-tableToggleContainer{ - flex: 1 0 auto; - display: flex; - justify-content: flex-end; -} - -.JobDetail-tableToggle{ - padding-left:10px; - padding-right: 10px; - border: 1px solid @d7grey; -} - -.JobDetail-tableToggle.active{ - background-color: @default-link; - border: 1px solid @default-link; - color: @default-bg; - - &:hover { - background-color: @default-link-hov; - } -} -.JobDetail .nvd3.nv-noData{ - color: @default-interface-txt; - font-size: 12px; - text-transform: uppercase; - font-family: 'Open Sans', sans-serif; -} -.JobDetail .nv-series{ - padding-right: 30px; - display: block; -} -.JobDetail-instructions .badge{ - background-color: @default-list-header-bg; - color: @default-interface-txt; -} -.JobDetail-tableToggle--left{ - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; -} - -.JobDetail-tableToggle--right{ - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; -} - -.JobDetail-searchInput{ - border-radius: 5px !important; -} - -.JobDetail-tableHeader:last-of-type{ - text-align:justify; -} - -.JobDetail-statusIcon{ - padding-right: 10px; - padding-left: 10px; -} - -.JobDetail-tableRow--selected, -.JobDetail-tableRow--selected > :first-child{ - border-left: 5px solid @list-row-select-bord; -} - -.JobDetail-tableRow--selected > :first-child > .JobDetail-statusIcon{ - margin-left: -5px; -} - -.JobDetails-table--noResults { - tr > td { - border-top: none !important; - } -} - -.JobDetail-statusIcon--results{ - padding-left: 0px; - padding-right: 10px; -} - -.JobDetail-graphSection{ - height: 320px; - width:100%; -} - -.JobDetail-stdoutActionButton--active{ - display: none; - visibility: hidden; - flex:none; - width:0px; - padding-right: 0px; -} - -.JobDetail-leftSide.JobDetail-stdoutActionButton--active { - margin-right: 0px; -} diff --git a/awx/ui/client/src/job-detail/job-detail.partial.html b/awx/ui/client/src/job-detail/job-detail.partial.html deleted file mode 100644 index bd0b488b18..0000000000 --- a/awx/ui/client/src/job-detail/job-detail.partial.html +++ /dev/null @@ -1,435 +0,0 @@ -
-
-
- -
- -
-
- -
- - - -
-
- -
-
- -
{{ job_status.status_label }}
-
- -
- -
-
Previous Task Failed - - - - -
-
- -
- -
-
- -
- - -
- -
- -
{{ job_status.started | longDate }}
-
- -
- -
{{ job_type }}
-
- -
- -
{{ job_status.finished | longDate }}
-
- -
- - -
- -
- -
{{ job_status.elapsed }}
-
- -
- - -
- -
- - -
- -
- - -
- -
- -
{{ job.playbook }}
-
- -
- - -
- -
- - -
- -
- - -
- -
- -
{{ job.forks }}
-
- -
- -
{{ job.limit }}
-
- -
- -
{{ verbosity }}
-
- -
- -
{{ job.job_tags }}
-
- -
- -
{{ job.skip_tags }}
-
- -
- - -
- -
-
- - - -
- - -
-
-
1 Please select from a play below to view its associated tasks.
-
-
-
- - - -
-
-
-
- - -
-
-
- - -
- - - - - - - - -
PlaysStartedElapsed
-
-
- - - - - - - - - - - - - - - - - - -
{{ play.name }}{{ play.created | date: 'HH:mm:ss' }}{{ play.elapsed }}
Waiting...
Loading...
No matching plays
-
-
- -
-
- - -
-
2 Please select a task below to view its associated hosts
-
-
-
- - - -
-
-
-
- - -
-
-
- -
- - - - - - - - - -
TasksStartedElapsed
-
-
- - - - - - - - - - - - - - - - - - - -
{{ task.name }}{{ task.created | date: 'HH:mm:ss' }}{{ task.elapsed }}
Waiting...
Loading...
No matching tasks
-
-
-
- - -
-
3 Please select a host below to view associated task details.
-
-
-
- - - -
-
-
-
- - -
-
-
-
- - - - - - - - -
HostsItemMessage
-
- -
- - - - - - - - - - - - - - - - - -
- {{ result.name }}{{ result.name }} - {{ result.item }}{{ result.msg }}
Waiting...
Loading...
No matching host events
-
-
-
- -
-
- - - - - - - -
- - - -
-
-
-
STANDARD OUT
-
- - - - -
-
- -
-
- -
-
- - - - diff --git a/awx/ui/client/src/job-detail/job-detail.route.js b/awx/ui/client/src/job-detail/job-detail.route.js deleted file mode 100644 index 94088c126b..0000000000 --- a/awx/ui/client/src/job-detail/job-detail.route.js +++ /dev/null @@ -1,91 +0,0 @@ -// <<<<<<< 4cf6a946a1aa14b7d64a8e1e8dabecfd3d056f27 -// //<<<<<<< bc59236851902d7c768aa26abdb7dc9c9dc27a5a -// /************************************************* -// * Copyright (c) 2016 Ansible, Inc. -// * -// * All Rights Reserved -// *************************************************/ -// -// // <<<<<<< a3d9eea2c9ddb4e16deec9ec38dea16bf37c559d -// // import { templateUrl } from '../shared/template-url/template-url.factory'; -// // -// // export default { -// // name: 'jobDetail', -// // url: '/jobs/{id: int}', -// // ncyBreadcrumb: { -// // parent: 'jobs', -// // label: "{{ job.id }} - {{ job.name }}" -// // }, -// // data: { -// // socket: { -// // "groups": { -// // "jobs": ["status_changed", "summary"], -// // "job_events": [] -// // } -// // } -// // }, -// // templateUrl: templateUrl('job-detail/job-detail'), -// // controller: 'JobDetailController' -// // }; -// // ======= -// // import {templateUrl} from '../shared/template-url/template-url.factory'; -// // -// // export default { -// // name: 'jobDetail', -// // url: '/jobs/:id', -// // ncyBreadcrumb: { -// // parent: 'jobs', -// // label: "{{ job.id }} - {{ job.name }}" -// // }, -// // socket: { -// // "groups":{ -// // "jobs": ["status_changed", "summary"], -// // "job_events": [] -// // } -// // }, -// // templateUrl: templateUrl('job-detail/job-detail'), -// // controller: 'JobDetailController' -// // }; -// //======= -// ======= -// >>>>>>> Rebase of devel (w/ channels) + socket rework for new job details -// // /************************************************* -// // * Copyright (c) 2016 Ansible, Inc. -// // * -// // * All Rights Reserved -// // *************************************************/ -// // -// // import {templateUrl} from '../shared/template-url/template-url.factory'; -// // -// // export default { -// // name: 'jobDetail', -// // url: '/jobs/:id', -// // ncyBreadcrumb: { -// // parent: 'jobs', -// // label: "{{ job.id }} - {{ job.name }}" -// // }, -// // socket: { -// // "groups":{ -// // "jobs": ["status_changed", "summary"], -// // "job_events": [] -// // } -// // }, -// // resolve: { -// // jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { -// // if (!$rootScope.event_socket) { -// // $rootScope.event_socket = Socket({ -// // scope: $rootScope, -// // 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; -// // } -// // }] -// // }, -// // 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 deleted file mode 100644 index 8e436a3e96..0000000000 --- a/awx/ui/client/src/job-detail/job-detail.service.js +++ /dev/null @@ -1,215 +0,0 @@ -export default - ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){ - return { - 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 & redundant stdout/stderr properties - processJson: function(data){ - // configure fields to ignore - var ignored = [ - 'type', - 'event_data', - 'related', - 'summary_fields', - 'url', - 'ansible_facts', - ]; - // remove ignored properties - var result = _.chain(data).cloneDeep().forEach(function(value, key, collection){ - if (ignored.indexOf(key) > -1){ - delete collection[key]; - } - }).value(); - 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;} - }, - processsEventTip: function(event, status){ - try{ - var string = `Event ID: ${ event.id }
Status: ${ _.capitalize(status.status)}. Click for details`; - return typeof item === 'object' ? JSON.stringify(string) : string; - } - 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 for more filters to support - processEventStatus: function(event){ - 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' - }; - } - // 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' || 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' - }; - } - }, - // Consumes a response from this.getRelatedJobEvents(id, params) - // returns an array for view logic to iterate over to build host result rows - processHostEvents: function(data){ - var self = this; - var results = []; - data.forEach(function(event){ - if (event.event !== 'runner_on_no_hosts'){ - var status = self.processEventStatus(event); - var msg = self.processEventMsg(event); - var item = self.processEventItem(event); - var tip = self.processsEventTip(event, status); - results.push({ - id: event.id, - status: status.status, - status_text: _.capitalize(status.status), - host_id: event.host, - task_id: event.parent, - name: event.event_data.host, - created: event.created, - tip: typeof tip === 'undefined' ? undefined : tip, - 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/?' + this.stringifyParams(params); - 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 }); - }); - }, - getJobEventChildren: function(uuid){ - var url = GetBasePath('job_events'); - url = `${url}?parent__uuid=${uuid}&order_by=host_name`; - 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/?' + this.stringifyParams(params); - 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/?' + this.stringifyParams(params); - 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/?' + this.stringifyParams(params); - 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(params){ - var url = GetBasePath('unified_jobs') + '?' + this.stringifyParams(params); - 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){ - 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 }); - }); - } - }; - }]; diff --git a/awx/ui/client/src/job-detail/main.js b/awx/ui/client/src/job-detail/main.js deleted file mode 100644 index 628f537e43..0000000000 --- a/awx/ui/client/src/job-detail/main.js +++ /dev/null @@ -1,24 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -// import route from './job-detail.route'; -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, - hostSummary.name - ]) - .controller('JobDetailController', controller) - .service('JobDetailService', service); - // .run(['$stateExtender', function($stateExtender) { - // $stateExtender.addState(route); - // }]); From 14d9eb92772bdf3b895b76129d2017e1c1e6d313 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Tue, 28 Feb 2017 12:25:57 -0800 Subject: [PATCH 3/7] removing some old stale code from host event stdout after decoupling job-results from job-details --- awx/ui/client/src/app.js | 2 -- .../host-event/host-event.controller.js | 26 ++++--------------- .../host-event/host-event.route.js | 3 --- .../src/job-results/job-results.service.js | 13 ---------- 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 7289c1af85..c479867951 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -46,7 +46,6 @@ import inventories from './inventories/main'; import inventoryScripts from './inventory-scripts/main'; import organizations from './organizations/main'; import managementJobs from './management-jobs/main'; -import jobDetail from './job-detail/main'; import workflowResults from './workflow-results/main'; import jobResults from './job-results/main'; import jobSubmission from './job-submission/main'; @@ -119,7 +118,6 @@ var tower = angular.module('Tower', [ login.name, activityStream.name, footer.name, - jobDetail.name, workflowResults.name, jobResults.name, jobSubmission.name, diff --git a/awx/ui/client/src/job-results/host-event/host-event.controller.js b/awx/ui/client/src/job-results/host-event/host-event.controller.js index e6c5fc71c7..b195d69b09 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.controller.js +++ b/awx/ui/client/src/job-results/host-event/host-event.controller.js @@ -6,48 +6,32 @@ export default - ['$stateParams', '$scope', '$state', 'Wait', 'jobResultsService', 'hostEvent', 'hostResults', - function($stateParams, $scope, $state, Wait, jobResultsService, hostEvent, hostResults){ + ['$stateParams', '$scope', '$state', 'Wait', 'jobResultsService', 'hostEvent', + function($stateParams, $scope, $state, Wait, jobResultsService, hostEvent){ $scope.processEventStatus = jobResultsService.processEventStatus; - $scope.hostResults = []; - // 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.isStdOut = function(){ - if ($state.current.name === 'jobDetail.host-event.stdout' || $state.current.name === 'jobDetail.host-event.stderr'){ - return 'StandardOut-preContainer StandardOut-preContent'; - } - }; - /*ignore jslint start*/ + var initCodeMirror = function(el, data, mode){ var container = document.getElementById(el); - var editor = CodeMirror.fromTextArea(container, { // jshint ignore:line + var editor = CodeMirror.fromTextArea(container, { lineNumbers: true, mode: mode }); editor.setSize("100%", 200); editor.getDoc().setValue(data); }; - /*ignore jslint end*/ + $scope.isActiveState = function(name){ return $state.current.name === name; }; - $scope.getActiveHostIndex = function(){ - var result = $scope.hostResults.filter(function( obj ) { - return obj.id === $scope.event.id; - }); - return $scope.hostResults.indexOf(result[0]); - }; - var init = function(){ hostEvent.event_name = hostEvent.event; $scope.event = _.cloneDeep(hostEvent); - $scope.hostResults = hostResults; // grab standard out & standard error if present from the host // event's "res" object, for things like Ansible modules diff --git a/awx/ui/client/src/job-results/host-event/host-event.route.js b/awx/ui/client/src/job-results/host-event/host-event.route.js index eb796fa7df..a1fd784434 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.route.js +++ b/awx/ui/client/src/job-results/host-event/host-event.route.js @@ -18,9 +18,6 @@ var hostEventModal = { id: $stateParams.eventId }).then(function(res) { return res.data.results[0]; }); - }], - hostResults: ['jobResultsService', '$stateParams', function(jobResultsService, $stateParams) { - return jobResultsService.getJobEventChildren($stateParams.taskId).then(res => res.data.results); }] }, onExit: function() { diff --git a/awx/ui/client/src/job-results/job-results.service.js b/awx/ui/client/src/job-results/job-results.service.js index 3817a922b8..5cf6f488e5 100644 --- a/awx/ui/client/src/job-results/job-results.service.js +++ b/awx/ui/client/src/job-results/job-results.service.js @@ -247,19 +247,6 @@ function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybo msg: 'Call to ' + url + '. GET returned: ' + status }); }); }, - getJobEventChildren: function(id){ - var url = GetBasePath('job_events'); - url = url + id + '/children/?order_by=host_name'; - 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 }); - }); - }, stringifyParams: function(params){ return _.reduce(params, (result, value, key) => { return result + key + '=' + value + '&'; From daa3746ef7352fd9f95919796ea700d0f91c9de7 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Tue, 28 Feb 2017 12:35:33 -0800 Subject: [PATCH 4/7] removing helpers/JobDetail.js --- awx/ui/client/src/app.js | 1 - awx/ui/client/src/helpers.js | 2 -- .../src/job-results/host-event/host-event.controller.js | 4 ++-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index c479867951..246df0c7bc 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -189,7 +189,6 @@ var tower = angular.module('Tower', [ 'LogViewerStatusDefinition', 'StandardOutHelper', 'LogViewerOptionsDefinition', - 'JobDetailHelper', 'lrInfiniteScroll', 'LoadConfigHelper', 'PortalJobsListDefinition', diff --git a/awx/ui/client/src/helpers.js b/awx/ui/client/src/helpers.js index b22938443d..765b81be5f 100644 --- a/awx/ui/client/src/helpers.js +++ b/awx/ui/client/src/helpers.js @@ -12,7 +12,6 @@ import Credentials from "./helpers/Credentials"; import Events from "./helpers/Events"; import Groups from "./helpers/Groups"; import Hosts from "./helpers/Hosts"; -import JobDetail from "./helpers/JobDetail"; import JobSubmission from "./helpers/JobSubmission"; import JobTemplates from "./helpers/JobTemplates"; import Jobs from "./helpers/Jobs"; @@ -38,7 +37,6 @@ export Events, Groups, Hosts, - JobDetail, JobSubmission, JobTemplates, Jobs, diff --git a/awx/ui/client/src/job-results/host-event/host-event.controller.js b/awx/ui/client/src/job-results/host-event/host-event.controller.js index b195d69b09..08e228209b 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.controller.js +++ b/awx/ui/client/src/job-results/host-event/host-event.controller.js @@ -17,14 +17,14 @@ var initCodeMirror = function(el, data, mode){ var container = document.getElementById(el); - var editor = CodeMirror.fromTextArea(container, { + var editor = CodeMirror.fromTextArea(container, { // jshint ignore:line lineNumbers: true, mode: mode }); editor.setSize("100%", 200); editor.getDoc().setValue(data); }; - + /*ignore jslint end*/ $scope.isActiveState = function(name){ return $state.current.name === name; }; From dc5716f0ea51d23e632e3bebea3e593a9fba1648 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Tue, 28 Feb 2017 13:44:40 -0800 Subject: [PATCH 5/7] changing jobDetail to jobResults throughout the app --- awx/ui/client/src/app.js | 22 +++++++++---------- .../host-event/host-event-modal.partial.html | 16 +++++++------- .../host-event/host-event.controller.js | 6 ++--- .../host-event/host-event.route.js | 8 +++---- .../src/job-results/job-results.partial.html | 2 +- .../src/job-results/job-results.route.js | 2 +- .../src/job-results/job-results.service.js | 10 ++++----- .../src/job-results/parse-stdout.service.js | 2 +- .../launchjob.factory.js | 14 ++++++------ .../job-submission.controller.js | 18 +++++++-------- .../client/src/jobs/jobs-list.controller.js | 16 +++++++------- awx/ui/client/src/lists/AllJobs.js | 8 +++---- awx/ui/client/src/lists/CompletedJobs.js | 6 ++--- awx/ui/client/src/lists/Jobs.js | 6 ++--- .../organizations-projects.controller.js | 8 +++---- .../projects/list/projects-list.controller.js | 8 +++---- .../adhoc/standard-out-adhoc.partial.html | 6 ++--- .../standard-out-inventory-sync.partial.html | 6 ++--- .../log/standard-out-log.controller.js | 2 +- .../standard-out-management-jobs.partial.html | 4 ++-- .../standard-out-scm-update.partial.html | 6 ++--- .../standard-out/standard-out.controller.js | 6 ++--- .../workflow-chart.directive.js | 2 +- 23 files changed, 92 insertions(+), 92 deletions(-) diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 246df0c7bc..f17df84b89 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -347,19 +347,19 @@ var tower = angular.module('Tower', [ $rootScope.$on("$stateChangeStart", function (event, next) { // Remove any lingering intervals - // except on jobDetails.* states - var jobDetailStates = [ - 'jobDetail', - 'jobDetail.host-summary', - 'jobDetail.host-event.details', - 'jobDetail.host-event.json', - 'jobDetail.host-events', - 'jobDetail.host-event.stdout' + // except on jobResults.* states + var jobResultStates = [ + 'jobResult', + 'jobResult.host-summary', + 'jobResult.host-event.details', + 'jobResult.host-event.json', + 'jobResult.host-events', + 'jobResult.host-event.stdout' ]; - if ($rootScope.jobDetailInterval && !_.includes(jobDetailStates, next.name) ) { - window.clearInterval($rootScope.jobDetailInterval); + if ($rootScope.jobResultInterval && !_.includes(jobResultStates, next.name) ) { + window.clearInterval($rootScope.jobResultInterval); } - if ($rootScope.jobStdOutInterval && !_.includes(jobDetailStates, next.name) ) { + if ($rootScope.jobStdOutInterval && !_.includes(jobResultStates, next.name) ) { window.clearInterval($rootScope.jobStdOutInterval); } diff --git a/awx/ui/client/src/job-results/host-event/host-event-modal.partial.html b/awx/ui/client/src/job-results/host-event/host-event-modal.partial.html index cf9dc67ac4..f8d488b4b3 100644 --- a/awx/ui/client/src/job-results/host-event/host-event-modal.partial.html +++ b/awx/ui/client/src/job-results/host-event/host-event-modal.partial.html @@ -9,7 +9,7 @@ {{event.host_name}} - @@ -40,19 +40,19 @@
- - - @@ -64,7 +64,7 @@
- +
diff --git a/awx/ui/client/src/job-results/host-event/host-event.controller.js b/awx/ui/client/src/job-results/host-event/host-event.controller.js index 08e228209b..781f971793 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.controller.js +++ b/awx/ui/client/src/job-results/host-event/host-event.controller.js @@ -56,7 +56,7 @@ } // instantiate Codemirror // try/catch pattern prevents the abstract-state controller from complaining about element being null - if ($state.current.name === 'jobDetail.host-event.json'){ + if ($state.current.name === 'jobResult.host-event.json'){ try{ initCodeMirror('HostEvent-codemirror', JSON.stringify($scope.json, null, 4), {name: "javascript", json: true}); } @@ -64,7 +64,7 @@ // element with id HostEvent-codemirror is not the view controlled by this instance of HostEventController } } - else if ($state.current.name === 'jobDetail.host-event.stdout'){ + else if ($state.current.name === 'jobResult.host-event.stdout'){ try{ initCodeMirror('HostEvent-codemirror', $scope.stdout, 'shell'); } @@ -72,7 +72,7 @@ // element with id HostEvent-codemirror is not the view controlled by this instance of HostEventController } } - else if ($state.current.name === 'jobDetail.host-event.stderr'){ + else if ($state.current.name === 'jobResult.host-event.stderr'){ try{ initCodeMirror('HostEvent-codemirror', $scope.stderr, 'shell'); } diff --git a/awx/ui/client/src/job-results/host-event/host-event.route.js b/awx/ui/client/src/job-results/host-event/host-event.route.js index a1fd784434..650a82bb25 100644 --- a/awx/ui/client/src/job-results/host-event/host-event.route.js +++ b/awx/ui/client/src/job-results/host-event/host-event.route.js @@ -7,7 +7,7 @@ import { templateUrl } from '../../shared/template-url/template-url.factory'; var hostEventModal = { - name: 'jobDetail.host-event', + name: 'jobResult.host-event', url: '/host-event/:eventId', controller: 'HostEventController', templateUrl: templateUrl('job-results/host-event/host-event-modal'), @@ -31,21 +31,21 @@ var hostEventModal = { }; var hostEventJson = { - name: 'jobDetail.host-event.json', + name: 'jobResult.host-event.json', url: '/json', controller: 'HostEventController', templateUrl: templateUrl('job-results/host-event/host-event-codemirror') }; var hostEventStdout = { - name: 'jobDetail.host-event.stdout', + name: 'jobResult.host-event.stdout', url: '/stdout', controller: 'HostEventController', templateUrl: templateUrl('job-results/host-event/host-event-stdout') }; var hostEventStderr = { - name: 'jobDetail.host-event.stderr', + name: 'jobResult.host-event.stderr', url: '/stderr', controller: 'HostEventController', templateUrl: templateUrl('job-results/host-event/host-event-stderr') diff --git a/awx/ui/client/src/job-results/job-results.partial.html b/awx/ui/client/src/job-results/job-results.partial.html index e48174311d..c2c56384de 100644 --- a/awx/ui/client/src/job-results/job-results.partial.html +++ b/awx/ui/client/src/job-results/job-results.partial.html @@ -108,7 +108,7 @@ ng-show="!previousTaskFailed"> {{job.job_explanation}} -
Previous Task Failed
- - - + + +
diff --git a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html index 451f10c5e8..5df1bd84c7 100644 --- a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html +++ b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html @@ -8,9 +8,9 @@ RESULTS
- - - + + +
diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js index 45564fffc6..bf8a8f89ef 100644 --- a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js +++ b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js @@ -20,7 +20,7 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce // Open up a socket for events depending on the type of job function openSockets() { - if ($state.current.name === 'jobDetail') { + if ($state.current.name === 'jobResult') { $log.debug("socket watching on job_events-" + job_id); $scope.$on(`ws-job_events-${job_id}`, function() { $log.debug("socket fired on job_events-" + job_id); diff --git a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html index bb7a6c1e64..8c9740a5eb 100644 --- a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html +++ b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html @@ -8,8 +8,8 @@ RESULTS
- - + +
diff --git a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html index 458b2c6dd2..249cb0bf72 100644 --- a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html +++ b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html @@ -8,9 +8,9 @@ RESULTS
- - - + + +
diff --git a/awx/ui/client/src/standard-out/standard-out.controller.js b/awx/ui/client/src/standard-out/standard-out.controller.js index 64f34cb68f..0cabd74389 100644 --- a/awx/ui/client/src/standard-out/standard-out.controller.js +++ b/awx/ui/client/src/standard-out/standard-out.controller.js @@ -33,14 +33,14 @@ export function JobStdoutController ($rootScope, $scope, $state, $stateParams, if (data.status === 'failed' || data.status === 'canceled' || data.status === 'error' || data.status === 'successful') { // Go out and refresh the job details - getJobDetails(); + getjobResults(); } }); // Set the parse type so that CodeMirror knows how to display extra params YAML/JSON $scope.parseType = 'yaml'; - function getJobDetails() { + function getjobResults() { // Go out and get the job details based on the job type. jobType gets defined // in the data block of the route declaration for each of the different types @@ -260,7 +260,7 @@ export function JobStdoutController ($rootScope, $scope, $state, $stateParams, RelaunchJob({ scope: $scope, id: typeId, type: job.type, name: job.name }); }; - getJobDetails(); + getjobResults(); } diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js index e7379fe19c..08ea0b4142 100644 --- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js +++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js @@ -830,7 +830,7 @@ export default [ '$state','moment', '$timeout', '$window', this.on("click", function(d) { if(d.job.id && d.unifiedJobTemplate) { if(d.unifiedJobTemplate.unified_job_type === 'job') { - $state.go('jobDetail', {id: d.job.id}); + $state.go('jobResult', {id: d.job.id}); } else if(d.unifiedJobTemplate.unified_job_type === 'inventory_update') { $state.go('inventorySyncStdout', {id: d.job.id}); From 66352ce5c9750678572ebce691f1eb8793912adc Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Tue, 28 Feb 2017 13:49:06 -0800 Subject: [PATCH 6/7] removing last reference to job detail of any kind --- awx/ui/client/legacy-styles/ansible-ui.less | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/awx/ui/client/legacy-styles/ansible-ui.less b/awx/ui/client/legacy-styles/ansible-ui.less index 4cc306cb36..763abab7f2 100644 --- a/awx/ui/client/legacy-styles/ansible-ui.less +++ b/awx/ui/client/legacy-styles/ansible-ui.less @@ -1671,7 +1671,7 @@ tr td button i { .modal-body { min-height: 120px; padding: 20px 0; - + .alert { padding: 10px; margin: 0; @@ -1984,10 +1984,6 @@ tr td button i { width: 73px; } -.JobDetails-status { - margin-bottom: 12px; -} - .red-text { color: @red; } From 7f16036171065827a22ffbb4fff57e5ad49fe430 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Wed, 1 Mar 2017 12:56:30 -0800 Subject: [PATCH 7/7] fixing merge conflicts --- awx/ui/client/src/helpers/JobDetail.js | 1198 ----------------- .../host-events/host-events.block.less | 93 -- .../host-events/host-events.controller.js | 48 - .../host-events/host-events.partial.html | 52 - .../host-summary/host-summary.controller.js | 131 -- .../src/job-detail/job-detail.controller.js | 1027 -------------- 6 files changed, 2549 deletions(-) delete mode 100644 awx/ui/client/src/helpers/JobDetail.js delete mode 100644 awx/ui/client/src/job-detail/host-events/host-events.block.less delete mode 100644 awx/ui/client/src/job-detail/host-events/host-events.controller.js delete mode 100644 awx/ui/client/src/job-detail/host-events/host-events.partial.html delete mode 100644 awx/ui/client/src/job-detail/host-summary/host-summary.controller.js delete mode 100644 awx/ui/client/src/job-detail/job-detail.controller.js diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js deleted file mode 100644 index ad049ed481..0000000000 --- a/awx/ui/client/src/helpers/JobDetail.js +++ /dev/null @@ -1,1198 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name helpers.function:JobDetail - * @description helper moduler for jobdetails controller - # Playbook events will be structured to form the following hierarchy: - # - playbook_on_start (once for each playbook file) - # - playbook_on_vars_prompt (for each play, but before play starts, we - # currently don't handle responding to these prompts) - # - playbook_on_play_start (once for each play) - # - playbook_on_import_for_host - # - playbook_on_not_import_for_host - # - playbook_on_no_hosts_matched - # - playbook_on_no_hosts_remaining - # - playbook_on_setup - # - runner_on* - # - playbook_on_task_start (once for each task within a play) - # - runner_on_failed - # - runner_on_ok - # - runner_on_error - # - runner_on_skipped - # - runner_on_unreachable - # - runner_on_no_hosts - # - runner_on_async_poll - # - runner_on_async_ok - # - runner_on_async_failed - # - runner_on_file_diff - # - playbook_on_notify (once for each notification from the play) - # - playbook_on_stats - -*/ - - -export default - angular.module('JobDetailHelper', ['Utilities', 'RestServices', 'ModalDialog']) - - .factory('DigestEvent', ['$rootScope', '$log', 'UpdatePlayStatus', 'UpdateHostStatus', 'AddHostResult', - 'GetElapsed', 'UpdateTaskStatus', 'JobIsFinished', 'AddNewTask', 'AddNewPlay', - function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, GetElapsed, - UpdateTaskStatus, JobIsFinished, AddNewTask, AddNewPlay) { - return function(params) { - - var scope = params.scope, - event = params.event, - msg; - - $log.debug('processing event: ' + event.id); - $log.debug(event); - - function getMsg(event) { - var 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; - } - } - return msg; - } - - switch (event.event) { - case 'playbook_on_start': - if (!JobIsFinished(scope)) { - scope.job_status.started = event.created; - scope.job_status.status = 'running'; - } - break; - - case 'playbook_on_play_start': - AddNewPlay({ scope: scope, event: event }); - break; - - case 'playbook_on_setup': - AddNewTask({ scope: scope, event: event }); - break; - - case 'playbook_on_task_start': - AddNewTask({ scope: scope, event: event }); - break; - - case 'runner_on_ok': - case 'runner_on_async_ok': - msg = getMsg(event); - UpdateHostStatus({ - scope: scope, - name: event.host_name, - host_id: event.host, - task_id: event.parent, - status: ( (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful' ), - id: event.id, - created: event.created, - modified: event.modified, - message: msg, - counter: event.counter, - item: (event.event_data && event.event_data.res) ? event.event_data.res.item : '' - }); - break; - - case 'playbook_on_no_hosts_matched': - UpdatePlayStatus({ - scope: scope, - play_id: event.parent, - failed: false, - changed: false, - modified: event.modified, - no_hosts: true - }); - break; - - case 'runner_on_unreachable': - msg = getMsg(event); - UpdateHostStatus({ - scope: scope, - name: event.host_name, - host_id: event.host, - task_id: event.parent, - status: 'unreachable', - id: event.id, - created: event.created, - modified: event.modified, - message: msg, - counter: event.counter, - item: (event.event_data && event.event_data.res) ? event.event_data.res.item : '' - }); - break; - - case 'runner_on_error': - case 'runner_on_async_failed': - msg = getMsg(event); - UpdateHostStatus({ - scope: scope, - name: event.host_name, - host_id: event.host, - task_id: event.parent, - status: 'failed', - id: event.id, - created: event.created, - modified: event.modified, - message: msg, - counter: event.counter, - item: (event.event_data && event.event_data.res) ? event.event_data.res.item : '' - }); - break; - - case 'runner_on_no_hosts': - UpdateTaskStatus({ - scope: scope, - failed: event.failed, - changed: event.changed, - task_id: event.parent, - modified: event.modified, - no_hosts: true - }); - break; - - case 'runner_on_skipped': - msg = getMsg(event); - UpdateHostStatus({ - scope: scope, - name: event.host_name, - host_id: event.host, - task_id: event.parent, - status: 'skipped', - id: event.id, - created: event.created, - modified: event.modified, - message: msg, - counter: event.counter, - item: (event.event_data && event.event_data.res) ? event.event_data.res.item : '' - }); - } - }; - }]) - - .factory('JobIsFinished', [ function() { - return function(scope) { - return (scope.job_status.status === 'failed' || scope.job_status.status === 'canceled' || - scope.job_status.status === 'error' || scope.job_status.status === 'successful'); - }; - }]) - - .factory('GetElapsed', [function() { - return function(params) { - var start = params.start, - end = params.end, - dt1, dt2, sec, hours, min; - dt1 = new Date(start); - dt2 = new Date(end); - if ( dt2.getTime() !== dt1.getTime() ) { - sec = Math.floor( (dt2.getTime() - dt1.getTime()) / 1000 ); - hours = Math.floor(sec / 3600); - sec = sec - (hours * 3600); - if (('' + hours).length < 2) { - hours = ('00' + hours).substr(-2, 2); - } - min = Math.floor(sec / 60); - sec = sec - (min * 60); - min = ('00' + min).substr(-2,2); - sec = ('00' + sec).substr(-2,2); - return hours + ':' + min + ':' + sec; - } - else { - return '00:00:00'; - } - }; - }]) - - .factory('SetActivePlay', [ function() { - return function(params) { - //find the most recent task in the list of 'active' tasks - - var scope = params.scope, - activeList = [], - newActivePlay, - key; - - for (key in scope.jobData.plays) { - if (scope.jobData.plays[key].taskCount > 0) { - activeList.push(key); - } - } - - if (activeList.length > 0) { - newActivePlay = scope.jobData.plays[activeList[activeList.length - 1]].id; - if (newActivePlay && scope.activePlay && newActivePlay !== scope.activePlay) { - scope.jobData.plays[scope.activePlay].tasks = {}; - scope.jobData.plays[scope.activePlay].playActiveClass = ''; - scope.activeTask = null; - } - if (newActivePlay) { - scope.activePlay = newActivePlay; - scope.jobData.plays[scope.activePlay].playActiveClass = 'JobDetail-tableRow--selected'; - } - } - }; - }]) - - .factory('SetActiveTask', [ function() { - return function(params) { - //find the most recent task in the list of 'active' tasks - var scope = params.scope, - key, - newActiveTask, - activeList = []; - - for (key in scope.jobData.plays[scope.activePlay].tasks) { - if (scope.jobData.plays[scope.activePlay].tasks[key].reportedHosts > 0 || scope.jobData.plays[scope.activePlay].tasks[key].status === 'no-matching-hosts') { - activeList.push(key); - } - } - - if (activeList.length > 0) { - newActiveTask = scope.jobData.plays[scope.activePlay].tasks[activeList[activeList.length - 1]].id; - if (newActiveTask && scope.activeTask && newActiveTask !== scope.activeTask) { - if (scope.activeTask && scope.jobData.plays[scope.activePlay].tasks[scope.activeTask] !== undefined) { - scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = ''; - scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].hostResults = {}; - } - } - if (newActiveTask) { - scope.activeTask = newActiveTask; - scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'JobDetail-tableRow--selected'; - } - } - }; - }]) - - .factory('AddNewPlay', ['SetActivePlay', function(SetActivePlay) { - return function(params) { - var scope = params.scope, - event = params.event, - status, status_text; - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - - scope.jobData.plays[event.id] = { - id: event.id, - name: event.play, - created: event.created, - status: status, - status_text: status_text, - elapsed: '00:00:00', - hostCount: 0, - taskCount: 0, - fistTask: null, - unreachableCount: 0, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - tasks: {} - }; - - SetActivePlay({ scope: scope }); - }; - }]) - - .factory('AddNewTask', ['UpdatePlayStatus', 'SetActivePlay', 'SetActiveTask', function(UpdatePlayStatus, SetActivePlay, SetActiveTask) { - return function(params) { - var scope = params.scope, - event = params.event, - status, status_text; - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - - scope.jobData.plays[event.parent].tasks[event.id] = { - id: event.id, - play_id: event.parent, - name: (event.task) ? event.task : event.event_display, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - created: event.created, - modified: event.modified, - hostCount: (scope.jobData.plays[event.parent]) ? scope.jobData.plays[event.parent].hostCount : 0, - reportedHosts: 0, - successfulCount: 0, - failedCount: 0, - changedCount: 0, - skippedCount: 0, - unreachableCount: 0, - successfulStyle: { display: 'none'}, - failedStyle: { display: 'none' }, - changedStyle: { display: 'none' }, - skippedStyle: { display: 'none' }, - unreachableStyle: { display: 'none' }, - hostResults: {} - }; - - if (scope.jobData.plays[event.parent].firstTask === undefined || scope.jobData.plays[event.parent].firstTask === null) { - scope.jobData.plays[event.parent].firstTask = event.id; - } - scope.jobData.plays[event.parent].taskCount++; - - SetActivePlay({ scope: scope }); - - SetActiveTask({ scope: scope }); - - UpdatePlayStatus({ - scope: scope, - play_id: event.parent, - failed: event.failed, - changed: event.changed, - modified: event.modified - }); - }; - }]) - - .factory('UpdateJobStatus', ['GetElapsed', 'Empty', 'JobIsFinished', 'longDateFilter', function(GetElapsed, Empty, JobIsFinished, longDateFilter) { - return function(params) { - var scope = params.scope, - failed = params.failed, - modified = params.modified, - started = params.started, - finished = params.finished; - - if (failed && scope.job_status.status !== 'failed' && scope.job_status.status !== 'error' && - scope.job_status.status !== 'canceled') { - scope.job_status.status = 'failed'; - } - if (JobIsFinished(scope) && !Empty(modified)) { - scope.job_status.finished = longDateFilter(modified); - } - if (!Empty(started) && Empty(scope.job_status.started)) { - scope.job_status.started = longDateFilter(modified); - } - if (!Empty(scope.job_status.finished) && !Empty(scope.job_status.started)) { - scope.job_status.elapsed = GetElapsed({ - start: started, - end: finished - }); - } - }; - }]) - - // Update the status of a play - .factory('UpdatePlayStatus', ['GetElapsed', 'UpdateJobStatus', function(GetElapsed, UpdateJobStatus) { - return function(params) { - var scope = params.scope, - failed = params.failed, - changed = params.changed, - id = params.play_id, - modified = params.modified, - no_hosts = params.no_hosts, - play; - - if (scope.jobData.plays[id] !== undefined) { - play = scope.jobData.plays[id]; - if (failed) { - play.status = 'failed'; - play.status_text = 'Failed'; - } - else if (play.status !== 'changed' && play.status !== 'failed') { - // once the status becomes 'changed' or 'failed' don't modify it - if (no_hosts) { - play.status = 'no-matching-hosts'; - play.status_text = 'No matching hosts'; - } else { - play.status = (changed) ? 'changed' : (failed) ? 'failed' : 'successful'; - play.status_text = (changed) ? 'Changed' : (failed) ? 'Failed' : 'OK'; - } - } - play.taskCount = (play.taskCount > 0) ? play.taskCount : 1; // set to a minimum of 1 to force drawing - play.status_tip = "Event ID: " + play.id + "
Status: " + play.status_text; - play.finished = modified; - play.elapsed = GetElapsed({ - start: play.created, - end: modified - }); - //play.status_text = (status_text) ? status_text : play.status; - } - - UpdateJobStatus({ - scope: scope, - failed: null, - modified: modified - }); - }; - }]) - - .factory('UpdateTaskStatus', ['UpdatePlayStatus', 'GetElapsed', function(UpdatePlayStatus, GetElapsed) { - return function(params) { - var scope = params.scope, - failed = params.failed, - changed = params.changed, - id = params.task_id, - modified = params.modified, - no_hosts = params.no_hosts, - play, task; - - // find the task in our hierarchy - for (play in scope.jobData.plays) { - if (scope.jobData.plays[play].tasks[id]) { - task = scope.jobData.plays[play].tasks[id]; - } - } - - if (task) { - if (no_hosts){ - task.status = 'no-matching-hosts'; - task.status_text = 'No matching hosts'; - } - else if (failed) { - task.status = 'failed'; - task.status_text = 'Failed'; - } - else if (task.status !== 'changed' && task.status !== 'failed') { - // once the status becomes 'changed' or 'failed' don't modify it - task.status = (failed) ? 'failed' : (changed) ? 'changed' : 'successful'; - task.status_text = (failed) ? 'Failed' : (changed) ? 'Changed' : 'OK'; - } - task.status_tip = "Event ID: " + task.id + "
Status: " + task.status_text; - task.finished = params.modified; - task.elapsed = GetElapsed({ - start: task.created, - end: modified - }); - - UpdatePlayStatus({ - scope: scope, - failed: failed, - changed: changed, - play_id: task.play_id, - modified: modified, - no_hosts: no_hosts - }); - } - }; - }]) - - // Each time a runner event is received update host summary totals and the parent task - .factory('UpdateHostStatus', ['UpdateTaskStatus', 'AddHostResult', function(UpdateTaskStatus, AddHostResult) { - return function(params) { - var scope = params.scope, - status = params.status, // successful, changed, unreachable, failed, skipped - name = params.name, - event_id = params.id, - host_id = params.host_id, - task_id = params.task_id, - modified = params.modified, - created = params.created, - msg = params.message, - item = params.item, - counter = params.counter; - - if (scope.jobData.hostSummaries[host_id] !== undefined) { - scope.jobData.hostSummaries[host_id].ok += (status === 'successful') ? 1 : 0; - scope.jobData.hostSummaries[host_id].changed += (status === 'changed') ? 1 : 0; - scope.jobData.hostSummaries[host_id].unreachable += (status === 'unreachable') ? 1 : 0; - scope.jobData.hostSummaries[host_id].failed += (status === 'failed') ? 1 : 0; - if (status === 'failed' || status === 'unreachable') { - scope.jobData.hostSummaries[host_id].status = 'failed'; - } - } - else { - scope.jobData.hostSummaries[host_id] = { - id: host_id, - name: name, - ok: (status === 'successful') ? 1 : 0, - changed: (status === 'changed') ? 1 : 0, - unreachable: (status === 'unreachable') ? 1 : 0, - failed: (status === 'failed') ? 1 : 0, - status: (status === 'failed' || status === 'unreachable') ? 'failed' : 'successful' - }; - } - UpdateTaskStatus({ - scope: scope, - task_id: task_id, - failed: ((status === 'failed' || status === 'unreachable') ? true :false), - changed: ((status === 'changed') ? true : false), - modified: modified - }); - - AddHostResult({ - scope: scope, - task_id: task_id, - host_id: host_id, - event_id: event_id, - status: status, - name: name, - created: created, - counter: counter, - message: msg, - item: item - }); - }; - }]) - - // Add a new host result - .factory('AddHostResult', ['SetTaskStyles', 'SetActivePlay', 'SetActiveTask', function(SetTaskStyles, SetActivePlay, SetActiveTask) { - return function(params) { - var scope = params.scope, - task_id = params.task_id, - host_id = params.host_id, - event_id = params.event_id, - status = params.status, - created = params.created, - counter = params.counter, - name = params.name, - msg = params.message, - item = params.item, - status_text = '', - task, play, play_id; - - 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 (typeof item === "object") { - item = JSON.stringify(item); - } - - for (play in scope.jobData.plays) { - for (task in scope.jobData.plays[play].tasks) { - if (parseInt(task,10) === parseInt(task_id,10)) { - play_id = parseInt(play,10); - } - } - } - - if (play_id) { - scope.jobData.plays[play_id].tasks[task_id].hostResults[event_id] = { - id: event_id, - status: status, - status_text: status_text, - host_id: host_id, - task_id: task_id, - name: name, - created: created, - counter: counter, - msg: msg, - item: item - }; - - // increment the unreachable count on the play - if (status === 'unreachable') { - scope.jobData.plays[play_id].unreachableCount++; - } - - // update the task status bar - task = scope.jobData.plays[play_id].tasks[task_id]; - - if (task_id === scope.jobData.plays[play_id].firstTask) { - scope.jobData.plays[play_id].hostCount++; - task.hostCount++; - } - - task.reportedHosts += 1; - task.failedCount += (status === 'failed') ? 1 : 0; - task.changedCount += (status === 'changed') ? 1 : 0; - task.successfulCount += (status === 'successful') ? 1 : 0; - task.skippedCount += (status === 'skipped') ? 1 : 0; - task.unreachableCount += (status === 'unreachable') ? 1 : 0; - - SetTaskStyles({ - task: task - }); - - SetActivePlay({ scope: scope }); - - SetActiveTask({ scope: scope }); - } - }; - }]) - - .factory('SetTaskStyles', [ function() { - return function(params) { - var task = params.task, - diff; - - task.missingCount = task.hostCount - (task.failedCount + task.changedCount + task.skippedCount + task.successfulCount + - task.unreachableCount); - if(task.missingCount<0){ - task.hostCount = (task.failedCount + task.changedCount + task.skippedCount + task.successfulCount + - task.unreachableCount); - } - task.missingPct = (task.hostCount > 0) ? Math.ceil((100 * (task.missingCount / task.hostCount))) : 0; - task.failedPct = (task.hostCount > 0) ? Math.ceil((100 * (task.failedCount / task.hostCount))) : 0; - task.changedPct = (task.hostCount > 0) ? Math.ceil((100 * (task.changedCount / task.hostCount))) : 0; - task.skippedPct = (task.hostCount > 0) ? Math.ceil((100 * (task.skippedCount / task.hostCount))) : 0; - task.successfulPct = (task.hostCount > 0) ? Math.ceil((100 * (task.successfulCount / task.hostCount))) : 0; - task.unreachablePct = (task.hostCount > 0) ? Math.ceil((100 * (task.unreachableCount / task.hostCount))) : 0; - - // cap % at 100 - task.missingPct = (task.missingPct > 100) ? 100 : task.missingPct; - task.failedPct = (task.failedPct > 100) ? 100 : task.failedPct; - task.changedPct = (task.changedPct > 100) ? 100 : task.changedPct; - task.skippedPct = (task.skippedPct > 100) ? 100 : task.skippedPct; - task.successfulPct = ( task.successfulPct > 100) ? 100 : task.successfulPct; - task.unreachablePct = (task.unreachablePct > 100) ? 100 : task.unreachablePct; - - diff = (task.failedPct + task.changedPct + task.skippedPct + task.successfulPct + task.unreachablePct + task.missingPct) - 100; - if (diff > 0) { - if (task.failedPct > diff) { - task.failedPct = task.failedPct - diff; - } - else if (task.changedPct > diff) { - task.changedPct = task.changedPct - diff; - } - else if (task.skippedPct > diff) { - task.skippedPct = task.skippedPct - diff; - } - else if (task.successfulPct > diff) { - task.successfulPct = task.successfulPct - diff; - } - else if (task.unreachablePct > diff) { - task.unreachablePct = task.unreachablePct - diff; - } - else if (task.missingPct > diff) { - task.missingPct = task.missingPct - diff; - } - } - task.successfulStyle = (task.successfulPct > 0) ? { 'display': 'inline-block' }: { 'display': 'none' }; - task.changedStyle = (task.changedPct > 0) ? { 'display': 'inline-block'} : { 'display': 'none' }; - task.skippedStyle = (task.skippedPct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' }; - task.failedStyle = (task.failedPct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' }; - task.unreachableStyle = (task.unreachablePct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' }; - task.missingStyle = (task.missingPct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' }; - }; - }]) - - .factory('LoadPlays', ['Rest', 'ProcessErrors', 'GetElapsed', 'SelectPlay', 'JobIsFinished', - function(Rest, ProcessErrors, GetElapsed, SelectPlay, JobIsFinished) { - return function(params) { - var scope = params.scope, - callback = params.callback, - url; - - scope.plays = []; - - scope.playsLoading = true; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - scope.next_plays = data.next; - scope.plays = []; - data.results.forEach(function(event, idx) { - var status, status_text, start, end, elapsed; - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - start = event.started; - - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].started; - } - else if (JobIsFinished(scope)) { - // this is the last play and the job already finished - end = scope.job_status.finished; - } - if (end) { - elapsed = GetElapsed({ - start: start, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - scope.plays.push({ - id: event.id, - name: event.play, - created: start, - finished: end, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - elapsed: elapsed, - hostCount: 0, - fistTask: null, - playActiveClass: '', - unreachableCount: (event.unreachable_count) ? event.unreachable_count : 0, - }); - }); - - // set the active task - SelectPlay({ - scope: scope, - id: (scope.plays.length > 0) ? scope.plays[0].id : null, - callback: callback - }); - scope.playsLoading = false; - }) - .error(function(data) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - }; - }]) - - // Call when the selected Play needs to change - .factory('SelectPlay', ['LoadTasks', function(LoadTasks) { - return function(params) { - var scope = params.scope, - id = params.id, - callback = params.callback; - - scope.selectedPlay = id; - scope.plays.forEach(function(play, idx) { - if (play.id === scope.selectedPlay) { - scope.plays[idx].playActiveClass = 'JobDetail-tableRow--selected'; - } - else { - scope.plays[idx].playActiveClass = ''; - } - }); - - LoadTasks({ - scope: scope, - callback: callback, - clear: true - }); - - }; - }]) - - .factory('LoadTasks', ['Rest', 'ProcessErrors', 'GetElapsed', 'SelectTask', 'SetTaskStyles', function(Rest, ProcessErrors, GetElapsed, SelectTask, SetTaskStyles) { - return function(params) { - var scope = params.scope, - callback = params.callback, - url, play; - - scope.tasks = []; - if (scope.selectedPlay) { - url = scope.job.url + 'job_tasks/?event_id=' + scope.selectedPlay; - - scope.plays.every(function(p, idx) { - if (p.id === scope.selectedPlay) { - play = scope.plays[idx]; - return false; - } - return true; - }); - - scope.tasksLoading = true; - - Rest.setUrl(url); - Rest.get() - .success(function(data) { - scope.next_tasks = data.next; - scope.tasks = []; - data.results.forEach(function(event, idx) { - var end, elapsed, status, status_text; - - if (play.firstTask === undefined || play.firstTask === null) { - play.firstTask = event.id; - play.hostCount = (event.host_count) ? event.host_count : 0; - } - - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].created; - } - else { - // no next event (task), get the end time of the play - scope.plays.every(function(play) { - if (play.id === scope.selectedPlay) { - end = play.finished; - return false; - } - return true; - }); - } - - if (end) { - elapsed = GetElapsed({ - start: event.created, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - - scope.tasks.push({ - id: event.id, - play_id: scope.selectedPlay, - name: event.name, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - created: event.created, - modified: event.modified, - finished: end, - elapsed: elapsed, - hostCount: (event.host_count) ? event.host_count : 0, - reportedHosts: (event.reported_hosts) ? event.reported_hosts : 0, - successfulCount: (event.successful_count) ? event.successful_count : 0, - failedCount: (event.failed_count) ? event.failed_count : 0, - changedCount: (event.changed_count) ? event.changed_count : 0, - skippedCount: (event.skipped_count) ? event.skipped_count : 0, - unreachableCount: (event.unreachable_count) ? event.unreachable_count : 0, - taskActiveClass: '' - }); - - if (play.firstTask !== event.id) { - // this is not the first task - scope.tasks[scope.tasks.length - 1].hostCount = play.hostCount; - } - - SetTaskStyles({ - task: scope.tasks[scope.tasks.length - 1] - }); - }); - - // set the active task - SelectTask({ - scope: scope, - id: (scope.tasks.length > 0) ? scope.tasks[0].id : null, - callback: callback - }); - - scope.tasksLoading = false; - - }) - .error(function(data) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - } - else { - SelectTask({ - scope: scope, - id: null, - callback: callback - }); - } - }; - }]) - - // Call when the selected task needs to change - .factory('SelectTask', ['JobDetailService', function(JobDetailService) { - return function(params) { - var scope = params.scope, - id = params.id; - - scope.selectedTask = id; - scope.tasks.forEach(function(task, idx) { - if (task.id === scope.selectedTask) { - scope.tasks[idx].taskActiveClass = 'JobDetail-tableRow--selected'; - } - else { - scope.tasks[idx].taskActiveClass = ''; - } - }); - if (scope.selectedTask !== null){ - 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.processHostEvents(res.results); - scope.hostResultsLoading = false; - }); - } - else{ - scope.hostResults = []; - scope.hostResultsLoading = false; - } - }; - }]) - - .factory('DrawGraph', ['DonutChart', function(DonutChart) { - return function(params) { - var count = params.count, - graph_data = []; - // Ready the data - if (count.ok.length > 0) { - graph_data.push({ - label: 'OK', - value: count.ok.length, - color: '#5CB85C' - }); - } - if (count.changed.length > 0) { - graph_data.push({ - label: 'CHANGED', - value: count.changed.length, - color: '#FF9900' - }); - } - if (count.unreachable.length > 0) { - graph_data.push({ - label: 'UNREACHABLE', - value: count.unreachable.length, - color: '#FF0000' - }); - } - if (count.failures.length > 0) { - graph_data.push({ - label: 'FAILED', - value: count.failures.length, - color: '#D9534F' - }); - } - DonutChart({ - data: graph_data - }); - }; - }]) - - .factory('DonutChart', [function() { - return function(params) { - var dataset = params.data, - element = $("#graph-section"), - colors, total,job_detail_chart; - - colors = _.map(dataset, function(d){ - return d.color; - }); - total = d3.sum(dataset.map(function(d) { - return d.value; - })); - job_detail_chart = nv.models.pieChart() - .margin({bottom: 15}) - .x(function(d) { - return d.label +': '+ Math.floor((d.value/total)*100) + "%"; - }) - .y(function(d) { return d.value; }) - .showLabels(false) - .showLegend(true) - .growOnHover(false) - .labelThreshold(0.01) - .tooltipContent(function(x, y) { - return '

'+x+'

'+ '

' + Math.floor(y.replace(',','')) + ' HOSTS ' + '

'; - }) - .color(colors); - job_detail_chart.legend.rightAlign(false); - job_detail_chart.legend.margin({top: 5, right: 450, left:0, bottom: 0}); - d3.select(element.find('svg')[0]) - .datum(dataset) - .transition().duration(350) - .call(job_detail_chart) - .style({ - "font-family": 'Open Sans', - "font-style": "normal", - "font-weight":400, - "src": "url(/static/assets/OpenSans-Regular.ttf)", - "width": 600, - "height": 300, - "color": '#848992' - }); - d3.select(element.find(".nv-noData")[0]) - .style({ - "text-anchor": 'start' - }); - return job_detail_chart; - }; - }]) - - - .factory('DrawPlays', [function() { - return function(params) { - var scope = params.scope, - idx = 0, - result = [], - newKeys = [], - //plays = JSON.parse(JSON.stringify(scope.jobData.plays)), - plays = scope.jobData.plays, - filteredListX = [], - filteredListB = [], - key, - keys; - - function listSort(a,b) { - if (parseInt(a,10) < parseInt(b,10)) { - return -1; - } - if (parseInt(a,10) > parseInt(b,10)) { - return 1; - } - return 0; - } - - // Only draw plays that are in the 'active' list - for (key in plays) { - if (plays[key].taskCount > 0) { - filteredListX[key] = plays[key]; - } - } - - keys = Object.keys(filteredListB); - keys.sort(function(a,b) { return listSort(a,b); }).reverse(); - for (idx=0; idx < scope.playsMaxRows && idx < keys.length; idx++) { - newKeys.push(keys[idx]); - } - newKeys.sort(function(a,b) { return listSort(a,b); }); - idx = 0; - while (idx < newKeys.length) { - result.push(filteredListB[newKeys[idx]]); - idx++; - } - setTimeout( function() { - scope.$apply( function() { - scope.plays = result; - scope.selectedPlay = scope.activePlay; - if (scope.liveEventProcessing) { - $('#plays-table-detail').scrollTop($('#plays-table-detail').prop("scrollHeight")); - } - }); - }); - }; - }]) - - .factory('DrawTasks', [ function() { - return function(params) { - var scope = params.scope, - result = [], - filteredListX = [], - filteredListB = [], - idx, key, keys, newKeys, tasks, t; - - function listSort(a,b) { - if (parseInt(a,10) < parseInt(b,10)) { - return -1; - } - if (parseInt(a,10) > parseInt(b,10)) { - return 1; - } - return 0; - } - - if (scope.activePlay && scope.jobData.plays[scope.activePlay]) { - - //tasks = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks)); - tasks = scope.jobData.plays[scope.activePlay].tasks; - - // Only draw tasks that are in the 'active' list - for (key in tasks) { - t = tasks[key]; - if (t.reportedHosts > 0 || t.hostCount > 0 || t.successfulCount >0 || t.failedCount > 0 || - t.changedCount > 0 || t.skippedCount > 0 || t.unreachableCount > 0) { - filteredListX[key] = tasks[key]; - } - } - - keys = Object.keys(filteredListB); - keys.sort(function(a,b) { return listSort(a,b); }).reverse(); - newKeys = []; - for (idx=0; result.length < scope.tasksMaxRows && idx < keys.length; idx++) { - newKeys.push(keys[idx]); - } - newKeys.sort(function(a,b) { return listSort(a,b); }); - idx = 0; - while (idx < newKeys.length) { - result.push(filteredListB[newKeys[idx]]); - idx++; - } - } - - setTimeout( function() { - scope.$apply( function() { - scope.tasks = result; - scope.selectedTask = scope.activeTask; - if (scope.liveEventProcessing) { - $('#tasks-table-detail').scrollTop($('#tasks-table-detail').prop("scrollHeight")); - } - }); - }); - - }; - }]) - - .factory('DrawHostResults', [ function() { - return function(params) { - var scope = params.scope, - result = [], - filteredListB = [], - idx = 0, - hostResults, - keys; - - if (scope.activePlay && scope.activeTask && scope.jobData.plays[scope.activePlay] && - scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) { - - hostResults = scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].hostResults; - - keys = Object.keys(filteredListB); - keys.sort(function compare(a, b) { - if (filteredListB[a].name === filteredListB[b].name) { - if (filteredListB[a].counter < filteredListB[b].counter) { - return -1; - } - if (filteredListB[a].counter >filteredListB[b].counter) { - return 1; - } - } else { - 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.hostResultsMaxRows) { - result.push(filteredListB[keys[idx]]); - idx++; - } - } - - setTimeout( function() { - scope.$apply( function() { - scope.hostResults = result; - if (scope.liveEventProcessing) { - $('#hosts-table-detail').scrollTop($('#hosts-table-detail').prop("scrollHeight")); - } - }); - }); - - }; - }]) - - .factory('UpdateDOM', ['DrawPlays', 'DrawTasks', 'DrawHostResults', - function(DrawPlays, DrawTasks, DrawHostResults) { - return function(params) { - var scope = params.scope; - if (!scope.pauseLiveEvents) { - DrawPlays({ scope: scope }); - DrawTasks({ scope: scope }); - DrawHostResults({ scope: scope }); - } - - setTimeout(function() { - scope.playsLoading = false; - scope.tasksLoading = false; - scope.hostResultsLoading = false; - },100); - }; - }]); diff --git a/awx/ui/client/src/job-detail/host-events/host-events.block.less b/awx/ui/client/src/job-detail/host-events/host-events.block.less deleted file mode 100644 index df52944cf0..0000000000 --- a/awx/ui/client/src/job-detail/host-events/host-events.block.less +++ /dev/null @@ -1,93 +0,0 @@ -@import "./client/src/shared/branding/colors.less"; -@import "./client/src/shared/branding/colors.default.less"; - -.HostEvents .CodeMirror{ - border: none; -} -.HostEvents .modal-footer{ - border: 0; - margin-top: 0px; - padding: 0px 20px 20px 20px; -} -button.HostEvents-close{ - width: 70px; - color: #FFFFFF!important; - text-transform: uppercase; - padding-left: 15px; - padding-right: 15px; - background-color: @default-link; - border-color: @default-link; - &:hover{ - background-color: @default-link-hov; - border-color: @default-link-hov; - } -} -.HostEvents-status--ok{ - color: @green; -} -.HostEvents-status--unreachable{ - color: @unreachable; -} -.HostEvents-status--changed{ - color: @changed; -} -.HostEvents-status--failed{ - color: @default-err; -} -.HostEvents-status--skipped{ - color: @skipped; -} - -.HostEvents-filter--form{ - padding-top: 15px; - padding-bottom: 15px; - float: right; - display: inline-block; -} -.HostEvents .modal-body{ - padding: 20px; -} -.HostEvents .select2-container{ - text-transform: capitalize; - max-width: 220px; - float: right; -} -.HostEvents-form--container{ - padding-top: 15px; - padding-bottom: 15px; -} -.HostEvents-title{ - text-transform: uppercase; - color: @default-interface-txt; - font-weight: 600; -} -.HostEvents-status i { - padding-right: 10px; -} -.HostEvents-table--header { - height: 30px; - font-size: 14px; - font-weight: normal; - text-transform: uppercase; - color: @default-interface-txt; - background-color: @default-list-header-bg; - padding-left: 15px; - padding-right: 15px; - border-bottom-width: 0px; -} -.HostEvents-table--header:first-of-type{ - border-top-left-radius: 5px; -} -.HostEvents-table--header:last-of-type{ - border-top-right-radius: 5px; -} -.HostEvents-table--row{ - color: @default-data-txt; - border: 0 !important; -} -.HostEvents-table--row:nth-child(odd){ - background: @default-tertiary-bg; -} -.HostEvents-table--cell{ - border: 0 !important; -} 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 deleted file mode 100644 index 5664c89877..0000000000 --- a/awx/ui/client/src/job-detail/host-events/host-events.controller.js +++ /dev/null @@ -1,48 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$stateParams', '$scope', '$rootScope', '$state', 'Wait', - 'JobDetailService', 'CreateSelect2', 'hosts', - function($stateParams, $scope, $rootScope, $state, Wait, - JobDetailService, CreateSelect2, hosts){ - - // pagination not implemented yet, but it'll depend on this - $scope.page_size = $stateParams.page_size; - - $scope.processEventStatus = JobDetailService.processEventStatus; - $scope.activeFilter = $stateParams.filter || null; - - $scope.filters = ['all', 'changed', 'failed', 'ok', 'unreachable', 'skipped']; - - // watch select2 for changes - $('.HostEvents-select').on("select2:select", function () { - $scope.activeFilter = $('.HostEvents-select').val(); - }); - - var init = function(){ - $scope.hostName = $stateParams.hostName; - // create filter dropdown - CreateSelect2({ - element: '.HostEvents-select', - multiple: false - }); - // process the filter if one was passed - if ($stateParams.filter){ - $scope.activeFilter = $stateParams.filter; - - $('#HostEvents').modal('show'); - } - else{ - $scope.results = hosts.data.results; - $('#HostEvents').modal('show'); - } - }; - - - init(); - - }]; 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 deleted file mode 100644 index 00bacf066c..0000000000 --- a/awx/ui/client/src/job-detail/host-events/host-events.partial.html +++ /dev/null @@ -1,52 +0,0 @@ - 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 deleted file mode 100644 index cd5a241622..0000000000 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js +++ /dev/null @@ -1,131 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - export default - ['$scope', '$rootScope', '$stateParams', 'Wait', 'JobDetailService', 'DrawGraph', function($scope, $rootScope, $stateParams, Wait, JobDetailService, DrawGraph){ - - var page_size = 200; - $scope.loading = $scope.hosts.length > 0 ? false : true; - $scope.filter = 'all'; - - var buildGraph = function(hosts){ - // status waterfall: unreachable > failed > changed > ok > skipped - var count; - count = { - ok : _.filter(hosts, function(o){ - return o.failures === 0 && o.changed === 0 && o.ok > 0; - }), - skipped : _.filter(hosts, function(o){ - return o.skipped > 0; - }), - unreachable : _.filter(hosts, function(o){ - return o.dark > 0; - }), - failures : _.filter(hosts, function(o){ - return o.failed === true; - }), - changed : _.filter(hosts, function(o){ - return o.changed > 0; - }) - }; - return count; - }; - var init = function(){ - Wait('start'); - JobDetailService.getJobHostSummaries($stateParams.id, {page_size: page_size, order_by: 'host_name'}) - .success(function(res){ - $scope.hosts = res.results; - $scope.next = res.next; - $scope.count = buildGraph(res.results); - Wait('stop'); - DrawGraph({count: $scope.count, resize:true}); - }); - JobDetailService.getJob({id: $stateParams.id}) - .success(function(res){ - $scope.status = res.results[0].status; - }); - }; - if ($rootScope.removeJobSummaryComplete) { - $rootScope.removeJobSummaryComplete(); - } - // 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 - $scope.$on('ws-jobs-summary', function(e, data) { - // discard socket msgs we don't care about in this context - if (parseInt($stateParams.id) === data.unified_job_id){ - init(); - } - }); - - $scope.$on('ws-jobs', function(e, data) { - if (parseInt($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 ', - 1: ' host event was ', - 2: ' host events were ' - }; - if (n >= 2){ - return n + dict[2] + status; - } - else{ - return n !== 0 ? n + dict[n] + status : dict[n] + status; - } - }; - return grammar(n, status); - }; - $scope.getNextPage = function(){ - if ($scope.next){ - JobDetailService.getNextPage($scope.next).success(function(res){ - res.results.forEach(function(key, index){ - $scope.hosts.push(res.results[index]); - }); - $scope.hosts.push(res.results); - $scope.next = res.next; - }); - } - }; - - $scope.setFilter = function(filter){ - $scope.filter = filter; - var getAll = function(){ - Wait('start'); - JobDetailService.getJobHostSummaries($stateParams.id, { - page_size: page_size, - order_by: 'host_name' - }).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, - order_by: 'host_name' - }).success(function(res){ - Wait('stop'); - $scope.hosts = res.results; - $scope.next = res.next; - }); - }; - $scope.get = filter === 'all' ? getAll() : getFailed(); - }; - - init(); - // calling the init routine twice will size the d3 chart correctly - no idea why - // instantiating the graph inside a setTimeout() SHOULD have the same effect, but it doesn't - // instantiating the graph further down the promise chain e.g. .then() or .finally() also does not work - init(); - }]; diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js deleted file mode 100644 index c3479e397b..0000000000 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ /dev/null @@ -1,1027 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:JobDetail - * @description This controller's for the Job Detail Page -*/ - -export default - [ '$location', '$rootScope', '$filter', '$scope', '$compile', '$state', '$stateParams', '$log', 'ClearScope', - 'GetBasePath', 'Wait', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed', 'JobIsFinished', - 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'RelaunchPlaybook', 'LoadPlays', 'LoadTasks', - 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'EditSchedule', - 'ParseTypeChange', 'JobDetailService', - function( - $location, $rootScope, $filter, $scope, $compile, $state, $stateParams, $log, ClearScope, - GetBasePath, Wait, ProcessErrors, SelectPlay, SelectTask, GetElapsed, JobIsFinished, - SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, RelaunchPlaybook, LoadPlays, LoadTasks, - ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule, - ParseTypeChange, JobDetailService - ) { - ClearScope(); - - var job_id = $stateParams.id, - scope = $scope, - api_complete = false, - refresh_count = 0, - lastEventId = 0, - verbosity_options, - job_type_options; - - scope.plays = []; - scope.parseType = 'yaml'; - scope.previousTaskFailed = false; - $scope.stdoutFullScreen = false; - - scope.$watch('job_status', function(job_status) { - if (job_status && job_status.explanation && job_status.explanation.split(":")[0] === "Previous Task Failed") { - scope.previousTaskFailed = true; - var taskObj = JSON.parse(job_status.explanation.substring(job_status.explanation.split(":")[0].length + 1)); - // return a promise from the options request with the permission type choices (including adhoc) as a param - var fieldChoice = fieldChoices({ - scope: $scope, - url: 'api/v1/unified_jobs/', - field: 'type' - }); - - // manipulate the choices from the options request to be set on - // scope and be usable by the list form - fieldChoice.then(function (choices) { - choices = - fieldLabels({ - choices: choices - }); - scope.explanation_fail_type = choices[taskObj.job_type]; - scope.explanation_fail_name = taskObj.job_name; - scope.explanation_fail_id = taskObj.job_id; - scope.task_detail = scope.explanation_fail_type + " failed for " + scope.explanation_fail_name + " with ID " + scope.explanation_fail_id + "."; - }); - } else { - scope.previousTaskFailed = false; - } - }, true); - - scope.$watch('plays', function(plays) { - for (var play in plays) { - if (plays[play].elapsed) { - plays[play].finishedTip = "Play completed at " + $filter("longDate")(plays[play].finished) + "."; - } else { - plays[play].finishedTip = "Play not completed."; - } - } - }); - scope.hosts = []; - scope.tasks = []; - scope.$watch('tasks', function(tasks) { - for (var task in tasks) { - if (tasks[task].elapsed) { - tasks[task].finishedTip = "Task completed at " + $filter("longDate")(tasks[task].finished) + "."; - } else { - tasks[task].finishedTip = "Task not completed."; - } - if (tasks[task].successfulCount) { - tasks[task].successfulCountTip = tasks[task].successfulCount; - tasks[task].successfulCountTip += (tasks[task].successfulCount === 1) ? " host event was" : " host events were"; - tasks[task].successfulCountTip += " ok."; - } else { - tasks[task].successfulCountTip = "No host events were ok."; - } - if (tasks[task].changedCount) { - tasks[task].changedCountTip = tasks[task].changedCount; - tasks[task].changedCountTip += (tasks[task].changedCount === 1) ? " host event" : " host events"; - tasks[task].changedCountTip += " changed."; - } else { - tasks[task].changedCountTip = "No host events changed."; - } - if (tasks[task].skippedCount) { - tasks[task].skippedCountTip = tasks[task].skippedCount; - tasks[task].skippedCountTip += (tasks[task].skippedCount === 1) ? " host event was" : " hosts events were"; - tasks[task].skippedCountTip += " skipped."; - } else { - tasks[task].skippedCountTip = "No host events were skipped."; - } - if (tasks[task].failedCount) { - tasks[task].failedCountTip = tasks[task].failedCount; - tasks[task].failedCountTip += (tasks[task].failedCount === 1) ? " host event" : " host events"; - tasks[task].failedCountTip += " failed."; - } else { - tasks[task].failedCountTip = "No host events failed."; - } - if (tasks[task].unreachableCount) { - tasks[task].unreachableCountTip = tasks[task].unreachableCount; - tasks[task].unreachableCountTip += (tasks[task].unreachableCount === 1) ? " host event was" : " hosts events were"; - tasks[task].unreachableCountTip += " unreachable."; - } else { - tasks[task].unreachableCountTip = "No host events were unreachable."; - } - if (tasks[task].missingCount) { - tasks[task].missingCountTip = tasks[task].missingCount; - tasks[task].missingCountTip += (tasks[task].missingCount === 1) ? " host event was" : " host events were"; - tasks[task].missingCountTip += " missing."; - } else { - tasks[task].missingCountTip = "No host events were missing."; - } - } - }); - scope.hostResults = []; - - scope.hostResultsMaxRows = 200; - scope.tasksMaxRows = 200; - scope.playsMaxRows = 200; - - // Set the following to true when 'Loading...' message desired - scope.playsLoading = true; - scope.tasksLoading = true; - scope.hostResultsLoading = true; - - // Turn on the 'Waiting...' message until events begin arriving - scope.waiting = true; - - scope.liveEventProcessing = true; // true while job is active and live events are arriving - scope.pauseLiveEvents = false; // control play/pause state of event processing - - scope.job_status = {}; - scope.job_id = job_id; - scope.auto_scroll = false; - - scope.haltEventQueue = false; - scope.processing = false; - scope.lessStatus = false; - scope.lessDetail = false; - // pops the event summary panel open if we're in the host summary child state - //scope.lessEvents = ($state.current.name === 'jobDetail.host-summary' || $state.current.name === 'jobDetail.host-events') ? false : true; - if ($state.current.name === 'jobDetail.host-summary' ){ - scope.lessEvents = false; - } - else{ - scope.lessEvents = true; - } - scope.jobData = {}; - scope.jobData.hostSummaries = {}; - - verbosity_options = [ - { value: 0, label: 'Default' }, - { value: 1, label: 'Verbose' }, - { value: 3, label: 'Debug' } - ]; - - job_type_options = [ - { value: 'run', label: 'Run' }, - { value: 'check', label: 'Check' } - ]; - - GetChoices({ - scope: scope, - url: GetBasePath('unified_jobs'), - field: 'status', - variable: 'status_choices', - }); - - scope.eventsHelpText = "

Successful

\n" + - "

Changed

\n" + - "

Unreachable

\n" + - "

Failed

\n"; - - scope.$on(`ws-job_events-${job_id}`, function(e, data) { - // update elapsed time on each event received - scope.job_status.elapsed = GetElapsed({ - start: scope.job.created, - end: Date.now() - }); - if (api_complete && data.id > lastEventId) { - scope.waiting = false; - data.event = data.event_name; - DigestEvent({ scope: scope, event: data }); - } - UpdateDOM({ scope: scope }); - }); - - scope.$on(`ws-jobs`, function(e, data) { - // if we receive a status change event for the current job indicating the job - // is finished, stop event queue processing and reload - if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10)) { - if (data.status === 'failed' || data.status === 'canceled' || - data.status === 'error' || data.status === 'successful' || data.status === 'running') { - $scope.liveEventProcessing = false; - if (!scope.pauseLiveEvents) { - $scope.$emit('LoadJob'); //this is what is used for the refresh - } - } - } - }); - - scope.$on('ws-jobs-summary', function() { - // the job host summary should now be available from the API - $log.debug('Trigging reload of job_host_summaries'); - scope.$emit('InitialLoadComplete'); - }); - - if (scope.removeInitialLoadComplete) { - scope.removeInitialLoadComplete(); - } - scope.removeInitialLoadComplete = scope.$on('InitialLoadComplete', function() { - Wait('stop'); - - if (JobIsFinished(scope)) { - scope.liveEventProcessing = false; // signal that event processing is over and endless scroll - scope.pauseLiveEvents = false; // should be enabled - var params = { - event: 'playbook_on_stats' - }; - JobDetailService.getRelatedJobEvents(scope.job.id, params) - .success(function() { - UpdateDOM({ scope: scope }); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call failed. GET returned: ' + status }); - }); - $log.debug('Job completed!'); - $log.debug(scope.jobData); - } - else { - api_complete = true; //trigger events to start processing - UpdateDOM({ scope: scope}); - } - }); - - if (scope.removeLoadHosts) { - scope.removeLoadHosts(); - } - scope.removeLoadHosts = scope.$on('LoadHosts', function() { - if (scope.activeTask) { - - var play = scope.jobData.plays[scope.activePlay], - task; - if(play){ - task = play.tasks[scope.activeTask]; - } - if (play && task) { - var params = { - parent: task.id, - event__startswith: 'runner', - page_size: scope.hostResultsMaxRows - }; - JobDetailService.getRelatedJobEvents(scope.job.id, params) - .success(function(data) { - if (data.results.length > 0) { - lastEventId = data.results[0].id; - } - scope.next_host_results = data.next; - task.hostResults = JobDetailService.processHostEvents(data.results); - scope.$emit('InitialLoadComplete'); - }); - } else { - scope.$emit('InitialLoadComplete'); - } - } else { - scope.$emit('InitialLoadComplete'); - } - }); - - if (scope.removeLoadTasks) { - scope.removeLoadTasks(); - } - scope.removeLoadTasks = scope.$on('LoadTasks', function() { - if (scope.activePlay) { - var play = scope.jobData.plays[scope.activePlay]; - - if (play) { - var params = { - event_id: play.id, - page_size: scope.tasksMaxRows, - order: 'id' - }; - JobDetailService.getJobTasks(scope.job.id, params) - .success(function(data) { - scope.next_tasks = data.next; - if (data.results.length > 0) { - lastEventId = data.results[data.results.length - 1].id; - if (scope.liveEventProcessing) { - scope.activeTask = data.results[data.results.length - 1].id; - } - else { - scope.activeTask = data.results[0].id; - } - scope.selectedTask = scope.activeTask; - } - data.results.forEach(function(event, idx) { - var end, elapsed, status, status_text; - - if (play.firstTask === undefined || play.firstTask === null) { - play.firstTask = event.id; - play.hostCount = (event.host_count) ? event.host_count : 0; - } - - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].created; - } - else { - // no next event (task), get the end time of the play - if(scope.jobData.plays[scope.activePlay]){ - end = scope.jobData.plays[scope.activePlay].finished; - } - } - - if (end) { - elapsed = GetElapsed({ - start: event.created, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - - play.tasks[event.id] = { - id: event.id, - play_id: scope.activePlay, - name: event.name, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - created: event.created, - modified: event.modified, - finished: end, - elapsed: elapsed, - hostCount: (event.host_count) ? event.host_count : 0, - reportedHosts: (event.reported_hosts) ? event.reported_hosts : 0, - successfulCount: (event.successful_count) ? event.successful_count : 0, - failedCount: (event.failed_count) ? event.failed_count : 0, - changedCount: (event.changed_count) ? event.changed_count : 0, - skippedCount: (event.skipped_count) ? event.skipped_count : 0, - unreachableCount: (event.unreachable_count) ? event.unreachable_count : 0, - taskActiveClass: '', - hostResults: {} - }; - if (play.firstTask !== event.id) { - // this is not the first task - play.tasks[event.id].hostCount = play.tasks[play.firstTask].hostCount; - } - if (play.tasks[event.id].reportedHosts === 0 && play.tasks[event.id].successfulCount === 0 && - play.tasks[event.id].failedCount === 0 && play.tasks[event.id].changedCount === 0 && - play.tasks[event.id].skippedCount === 0 && play.tasks[event.id].unreachableCount === 0) { - play.tasks[event.id].status = 'no-matching-hosts'; - play.tasks[event.id].status_text = 'No matching hosts'; - play.tasks[event.id].status_tip = "Event ID: " + event.id + "
Status: No matching hosts"; - } - play.taskCount++; - SetTaskStyles({ - task: play.tasks[event.id] - }); - }); - if (scope.activeTask && scope.jobData.plays[scope.activePlay] && scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) { - scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'JobDetail-tableRow--selected'; - } - scope.$emit('LoadHosts'); - }) - .error(function(data) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call failed. GET returned: ' + status }); - }); - } else { - scope.$emit('InitialLoadComplete'); - } - } else { - scope.$emit('InitialLoadComplete'); - } - }); - - if (scope.removeLoadPlays) { - scope.removeLoadPlays(); - } - scope.removeLoadPlays = scope.$on('LoadPlays', function(e, events_url) { - scope.jobData.plays = {}; - var params = { - order_by: 'id' - }; - - JobDetailService.getJobPlays(scope.job.id, params) - .success( function(data) { - scope.next_plays = data.next; - if (data.results.length > 0) { - lastEventId = data.results[data.results.length - 1].id; - if (scope.liveEventProcessing) { - scope.activePlay = data.results[data.results.length - 1].id; - } - else { - scope.activePlay = data.results[0].id; - } - scope.selectedPlay = scope.activePlay; - } else { - // if we are here, there are no plays and the job has failed, let the user know they may want to consult stdout - if ( (scope.job_status.status === 'failed' || scope.job_status.status === 'error') && - (!scope.job_status.explanation)) { - scope.job_status.explanation = "See standard out for more details"; - } - } - data.results.forEach(function(event, idx) { - var status, status_text, start, end, elapsed, ok, changed, failed, skipped; - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - start = event.started; - - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].started; - } - else if (JobIsFinished(scope)) { - // this is the last play and the job already finished - end = scope.job_status.finished; - } - if (end) { - elapsed = GetElapsed({ - start: start, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - scope.jobData.plays[event.id] = { - id: event.id, - name: event.play, - created: start, - finished: end, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - elapsed: elapsed, - hostCount: 0, - fistTask: null, - taskCount: 0, - playActiveClass: '', - unreachableCount: (event.unreachable_count) ? event.unreachable_count : 0, - tasks: {} - }; - - ok = (event.ok_count) ? event.ok_count : 0; - changed = (event.changed_count) ? event.changed_count : 0; - failed = (event.failed_count) ? event.failed_count : 0; - skipped = (event.skipped_count) ? event.skipped_count : 0; - - scope.jobData.plays[event.id].hostCount = ok + changed + failed + skipped; - - if (scope.jobData.plays[event.id].hostCount > 0 || event.unreachable_count > 0 || scope.job_status.status === 'successful' || - scope.job_status.status === 'failed' || scope.job_status.status === 'error' || scope.job_status.status === 'canceled') { - // force the play to be on the 'active' list - scope.jobData.plays[event.id].taskCount = 1; - } - - if (scope.jobData.plays[event.id].hostCount === 0 && event.unreachable_count === 0) { - scope.jobData.plays[event.id].status = 'no-matching-hosts'; - scope.jobData.plays[event.id].status_text = 'No matching hosts'; - scope.jobData.plays[event.id].status_tip = "Event ID: " + event.id + "
Status: No matching hosts"; - } - }); - if (scope.activePlay && scope.jobData.plays[scope.activePlay]) { - scope.jobData.plays[scope.activePlay].playActiveClass = 'JobDetail-tableRow--selected'; - } - scope.$emit('LoadTasks', events_url); - }); - }); - - - if (scope.removeLoadJob) { - scope.removeLoadJob(); - } - scope.removeLoadJobRow = scope.$on('LoadJob', function() { - Wait('start'); - scope.job_status = {}; - - scope.playsLoading = true; - scope.tasksLoading = true; - scope.hostResultsLoading = true; - - // Load the job record - 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 : ''; - scope.inventory_name = (data.summary_fields.inventory) ? data.summary_fields.inventory.name : ''; - scope.job_template_url = '/#/templates/' + data.unified_job_template; - scope.inventory_url = (scope.inventory_name && data.inventory) ? '/#/inventories/' + data.inventory : ''; - scope.project_url = (scope.project_name && data.project) ? '/#/projects/' + data.project : ''; - scope.credential_url = (data.credential) ? '/#/credentials/' + data.credential : ''; - scope.cloud_credential_url = (data.cloud_credential) ? '/#/credentials/' + data.cloud_credential : ''; - scope.playbook = data.playbook; - scope.credential = data.credential; - scope.cloud_credential = data.cloud_credential; - scope.forks = data.forks; - scope.limit = data.limit; - scope.verbosity = data.verbosity; - scope.job_tags = data.job_tags; - scope.variables = ParseVariableString(data.extra_vars); - - // If we get created_by back from the server then use it. This means that the job was kicked - // off by a user and not a schedule AND that the user still exists in the system. - if(data.summary_fields.created_by) { - scope.users_url = '/#/users/' + data.summary_fields.created_by.id; - scope.created_by = data.summary_fields.created_by.username; - } - else { - if(data.summary_fields.schedule) { - // Build the Launched By link to point to the schedule that kicked it off - scope.scheduled_by = (data.summary_fields.schedule.name) ? data.summary_fields.schedule.name.toString() : ''; - } - // If there is no schedule or created_by then we can assume that the job was - // created by a deleted user - } - - if (data.summary_fields.credential) { - scope.credential_name = data.summary_fields.credential.name; - scope.credential_url = data.related.credential - .replace('api/v1', '#'); - } else { - scope.credential_name = ""; - } - - if (data.summary_fields.cloud_credential) { - scope.cloud_credential_name = data.summary_fields.cloud_credential.name; - scope.cloud_credential_url = data.related.cloud_credential - .replace('api/v1', '#'); - } else { - scope.cloud_credential_name = ""; - } - - if (data.summary_fields.network_credential) { - scope.network_credential_name = data.summary_fields.network_credential.name; - scope.network_credential_url = data.related.network_credential - .replace('api/v1', '#'); - } else { - scope.network_credential_name = ""; - } - - for (i=0; i < verbosity_options.length; i++) { - if (verbosity_options[i].value === data.verbosity) { - scope.verbosity = verbosity_options[i].label; - } - } - - for (i=0; i < job_type_options.length; i++) { - if (job_type_options[i].value === data.job_type) { - scope.job_type = job_type_options[i].label; - } - } - - // In the case the job is already completed, or an error already happened, - // populate scope.job_status info - scope.job_status.status = (data.status === 'waiting' || data.status === 'new') ? 'pending' : data.status; - scope.job_status.started = data.started; - scope.job_status.status_class = ((data.status === 'error' || data.status === 'failed') && data.job_explanation) ? "alert alert-danger" : ""; - scope.job_status.explanation = data.job_explanation; - if(data.result_traceback) { - scope.job_status.traceback = data.result_traceback.trim().split('\n').join('
'); - } - if (data.status === 'successful' || data.status === 'failed' || data.status === 'error' || data.status === 'canceled') { - scope.job_status.finished = data.finished; - scope.liveEventProcessing = false; - scope.pauseLiveEvents = false; - scope.waiting = false; - scope.playsLoading = false; - scope.tasksLoading = false; - scope.hostResultsLoading = false; - } - else { - scope.job_status.finished = null; - } - - if (data.started && data.finished) { - scope.job_status.elapsed = GetElapsed({ - start: data.started, - end: data.finished - }); - } - else { - scope.job_status.elapsed = '00:00:00'; - } - scope.status_choices.every(function(status) { - if (status.value === scope.job.status) { - scope.job_status.status_label = status.label; - return false; - } - return true; - }); - //scope.setSearchAll('host'); - ParseTypeChange({ scope: scope, field_id: 'pre-formatted-variables', readOnly: true }); - scope.$emit('LoadPlays', data.related.job_events); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve job: ' + $stateParams.id + '. GET returned: ' + status }); - }); - }); - - - if (scope.removeRefreshCompleted) { - scope.removeRefreshCompleted(); - } - scope.removeRefreshCompleted = scope.$on('RefreshCompleted', function() { - refresh_count++; - if (refresh_count === 1) { - // First time. User just loaded page. - scope.$emit('LoadJob'); - } - }); - - scope.adjustSize = function() { - var height, ww = $(window).width(); - if (ww < 1024) { - $('#job-summary-container').hide(); - $('#job-detail-container').css({ "width": "100%", "padding-right": "15px" }); - $('#summary-button').show(); - } - else { - $('.overlay').hide(); - $('#summary-button').hide(); - $('#hide-summary-button').hide(); - $('#job-summary-container .job_well').css({ - 'box-shadow': 'none', - 'height': 'auto' - }); - $('#job-summary-container').css({ - "width": "41.66666667%", - "padding-left": "7px", - "padding-right": "15px", - "z-index": 0 - }); - setTimeout(function() { $('#job-summary-container .job_well').height($('#job-detail-container').height() - 18); }, 500); - $('#job-summary-container').show(); - } - - scope.lessStatus = false; // close the view more status option - - - height = $(window).height() - $('#main-menu-container .navbar').outerHeight() - - $('#job-detail-container').outerHeight() - 20; - scope.$emit('RefreshCompleted'); - }; - - setTimeout(function() { scope.adjustSize(); }, 500); - - // Use debounce for the underscore library to adjust after user resizes window. - $(window).resize(_.debounce(function(){ - scope.adjustSize(); - }, 500)); - - function flashPlayTip() { - setTimeout(function(){ - $('#play-help').popover('show'); - },500); - setTimeout(function() { - $('#play-help').popover('hide'); - }, 5000); - } - - scope.selectPlay = function(id) { - if (scope.liveEventProcessing && !scope.pauseLiveEvents) { - scope.pauseLiveEvents = true; - flashPlayTip(); - } - SelectPlay({ - scope: scope, - id: id - }); - }; - - scope.selectTask = function(id) { - if (scope.liveEventProcessing && !scope.pauseLiveEvents) { - scope.pauseLiveEvents = true; - flashPlayTip(); - } - SelectTask({ - scope: scope, - id: id - }); - }; - - scope.togglePlayButton = function() { - if (scope.pauseLiveEvents) { - scope.pauseLiveEvents = false; - scope.$emit('LoadJob'); - } - }; - - scope.objectIsEmpty = function(obj) { - if (angular.isObject(obj)) { - return (Object.keys(obj).length > 0) ? false : true; - } - return true; - }; - - scope.toggleLessEvents = function() { - if (!scope.lessEvents) { - $('#events-summary').slideUp(0); - scope.lessEvents = true; - } - else { - $('#events-summary').slideDown(0); - scope.lessEvents = false; - } - }; - - scope.toggleLessStatus = function() { - if (!scope.lessStatus) { - $('#job-status-form').slideUp(200); - scope.lessStatus = true; - } - else { - $('#job-status-form').slideDown(200); - scope.lessStatus = false; - } - }; - - scope.toggleLessDetail = function() { - if (!scope.lessDetail) { - $('#job-detail-details').slideUp(200); - scope.lessDetail = true; - } - else { - $('#job-detail-details').slideDown(200); - scope.lessDetail = false; - } - }; - - if (scope.removeDeleteFinished) { - scope.removeDeleteFinished(); - } - scope.removeDeleteFinished = scope.$on('DeleteFinished', function(e, action) { - Wait('stop'); - if (action !== 'cancel') { - Wait('stop'); - $location.url('/jobs'); - } - }); - - scope.deleteJob = function() { - DeleteJob({ - scope: scope, - id: scope.job.id, - job: scope.job, - callback: 'DeleteFinished' - }); - }; - - scope.relaunchJob = function() { - RelaunchPlaybook({ - scope: scope, - id: scope.job.id - }); - }; - - scope.playsScrollDown = function() { - // check for more plays when user scrolls to bottom of play list... - if (((!scope.liveEventProcessing) || (scope.liveEventProcessing && scope.pauseLiveEvents)) && scope.next_plays) { - $('#playsMoreRows').fadeIn(); - scope.playsLoading = true; - JobDetailService.getNextPage(scope.next_plays) - .success( function(data) { - scope.next_plays = data.next; - data.results.forEach(function(event, idx) { - var status, status_text, start, end, elapsed, ok, changed, failed, skipped; - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - start = event.started; - - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].started; - } - else if (JobIsFinished(scope)) { - // this is the last play and the job already finished - end = scope.job_status.finished; - } - if (end) { - elapsed = GetElapsed({ - start: start, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - scope.plays.push({ - id: event.id, - name: event.play, - created: start, - finished: end, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - elapsed: elapsed, - hostCount: 0, - fistTask: null, - playActiveClass: '', - unreachableCount: (event.unreachable_count) ? event.unreachable_count : 0, - }); - - ok = (event.ok_count) ? event.ok_count : 0; - changed = (event.changed_count) ? event.changed_count : 0; - failed = (event.failed_count) ? event.failed_count : 0; - skipped = (event.skipped_count) ? event.skipped_count : 0; - - scope.plays[scope.plays.length - 1].hostCount = ok + changed + failed + skipped; - scope.playsLoading = false; - }); - $('#playsMoreRows').fadeOut(400); - }) - .error( function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + scope.next_plays + '. GET returned: ' + status }); - }); - } - }; - - scope.tasksScrollDown = function() { - // check for more tasks when user scrolls to bottom of task list... - if (((!scope.liveEventProcessing) || (scope.liveEventProcessing && scope.pauseLiveEvents)) && scope.next_tasks) { - $('#tasksMoreRows').fadeIn(); - scope.tasksLoading = true; - JobDetailService.getNextPage(scope.next_tasks) - .success(function(data) { - scope.next_tasks = data.next; - data.results.forEach(function(event, idx) { - var end, elapsed, status, status_text; - if (idx < data.results.length - 1) { - // end date = starting date of the next event - end = data.results[idx + 1].created; - } - else { - // no next event (task), get the end time of the play - scope.plays.every(function(p, j) { - if (p.id === scope.selectedPlay) { - end = scope.plays[j].finished; - return false; - } - return true; - }); - } - if (end) { - elapsed = GetElapsed({ - start: event.created, - end: end - }); - } - else { - elapsed = '00:00:00'; - } - - status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful'; - status_text = (event.failed) ? 'Failed' : (event.changed) ? 'Changed' : 'OK'; - - scope.tasks.push({ - id: event.id, - play_id: scope.selectedPlay, - name: event.name, - status: status, - status_text: status_text, - status_tip: "Event ID: " + event.id + "
Status: " + status_text, - created: event.created, - modified: event.modified, - finished: end, - elapsed: elapsed, - hostCount: event.host_count, // hostCount, - reportedHosts: event.reported_hosts, - successfulCount: event.successful_count, - failedCount: event.failed_count, - changedCount: event.changed_count, - skippedCount: event.skipped_count, - taskActiveClass: '' - }); - SetTaskStyles({ - task: scope.tasks[scope.tasks.length - 1] - }); - }); - $('#tasksMoreRows').fadeOut(400); - scope.tasksLoading = false; - }) - .error(function(data, status) { - $('#tasksMoreRows').fadeOut(400); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + scope.next_tasks + '. GET returned: ' + status }); - }); - } - }; - - scope.hostResultsScrollDown = function() { - // check for more hosts when user scrolls to bottom of host results list... - if (((!scope.liveEventProcessing) || (scope.liveEventProcessing && scope.pauseLiveEvents)) && scope.next_host_results) { - $('#hostResultsMoreRows').fadeIn(); - scope.hostResultsLoading = true; - JobDetailService.getNextPage(scope.next_host_results) - .success(function(data) { - scope.next_host_results = data.next; - data.results.forEach(function(row) { - var status, status_text, item, msg; - if (row.event === "runner_on_skipped") { - status = 'skipped'; - } - else if (row.event === "runner_on_unreachable") { - status = 'unreachable'; - } - else { - status = (row.failed) ? 'failed' : (row.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 (row.event_data && row.event_data.res) { - item = row.event_data.res.item; - if (typeof item === "object") { - item = JSON.stringify(item); - } - } - msg = ''; - if (row.event_data && row.event_data.res) { - if (typeof row.event_data.res === 'object') { - msg = row.event_data.res.msg; - } else { - msg = row.event_data.res; - } - } - scope.hostResults.push({ - id: row.id, - status: status, - status_text: status_text, - host_id: row.host, - task_id: row.parent, - name: row.event_data.host, - created: row.created, - msg: (row.event_data && row.event_data.res) ? row.event_data.res.msg : '', - item: item - }); - scope.hostResultsLoading = false; - }); - $('#hostResultsMoreRows').fadeOut(400); - }) - .error(function(data, status) { - $('#hostResultsMoreRows').fadeOut(400); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + scope.next_host_results + '. GET returned: ' + status }); - }); - } - }; - - scope.refresh = function(){ - $scope.$emit('LoadJob'); - }; - - // Click binding for the expand/collapse button on the standard out log - $scope.toggleStdoutFullscreen = function() { - $scope.stdoutFullScreen = !$scope.stdoutFullScreen; - }; - - scope.editSchedule = function() { - // We need to get the schedule's ID out of the related links - // An example of the related schedule link looks like /api/v1/schedules/5 - // where 5 is the ID we are trying to capture - var regex = /\/api\/v1\/schedules\/(\d+)\//; - var id = scope.job.related.schedule.match(regex)[1]; - - if(scope.job.job_template && id) { - $state.go('jobTemplateSchedules.edit', {id: scope.job.job_template, schedule_id: id}); - } - }; - - // SchedulesRefresh is the callback string that we passed to the edit schedule modal - // When the modal successfully updates the schedule it will emit this event and pass - // the updated schedule object - if (scope.removeSchedulesRefresh) { - scope.removeSchedulesRefresh(); - } - scope.$on('SchedulesRefresh', function(e, data) { - if (data) { - scope.scheduled_by = data.name; - } - }); - } -];