From 7c1efea037ca2af6d332ff59b0f3ffdd7d39e1b6 Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Sat, 19 Mar 2016 19:36:15 -0400 Subject: [PATCH] add onExit & onEnter hooks to $stateExtender, raze HostEventViewer and replace with host-events module, resolves #1132 --- awx/ui/client/src/about/about.route.js | 5 + awx/ui/client/src/app.js | 1 - awx/ui/client/src/helpers.js | 2 - awx/ui/client/src/helpers/HostEventsViewer.js | 287 ------------------ .../job-detail/host-event/host-event.route.js | 0 .../host-events/host-events.block.less | 82 +++++ .../host-events/host-events.controller.js | 184 +++++++++++ .../host-events/host-events.partial.html | 59 ++++ .../host-events/host-events.route.js | 27 ++ .../client/src/job-detail/host-events/main.js | 15 + .../src/job-detail/job-detail.controller.js | 17 +- .../src/job-detail/job-detail.partial.html | 47 +-- awx/ui/client/src/job-detail/main.js | 5 +- .../src/shared/stateExtender.provider.js | 4 +- 14 files changed, 388 insertions(+), 347 deletions(-) delete mode 100644 awx/ui/client/src/helpers/HostEventsViewer.js delete mode 100644 awx/ui/client/src/job-detail/host-event/host-event.route.js create mode 100644 awx/ui/client/src/job-detail/host-events/host-events.block.less create mode 100644 awx/ui/client/src/job-detail/host-events/host-events.controller.js create mode 100644 awx/ui/client/src/job-detail/host-events/host-events.partial.html create mode 100644 awx/ui/client/src/job-detail/host-events/host-events.route.js create mode 100644 awx/ui/client/src/job-detail/host-events/main.js diff --git a/awx/ui/client/src/about/about.route.js b/awx/ui/client/src/about/about.route.js index 5f8b5e9220..475cf1aea0 100644 --- a/awx/ui/client/src/about/about.route.js +++ b/awx/ui/client/src/about/about.route.js @@ -8,5 +8,10 @@ export default { ncyBreadcrumb: { label: "ABOUT" }, + onExit: function(){ + // hacky way to handle user browsing away via URL bar + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + }, templateUrl: templateUrl('about/about') }; diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index cbf50b22b6..48d7d07019 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -177,7 +177,6 @@ var tower = angular.module('Tower', [ 'StandardOutHelper', 'LogViewerOptionsDefinition', 'EventViewerHelper', - 'HostEventsViewerHelper', 'JobDetailHelper', 'SocketIO', 'lrInfiniteScroll', diff --git a/awx/ui/client/src/helpers.js b/awx/ui/client/src/helpers.js index b298a635ef..e8190ea50e 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 EventViewer from "./helpers/EventViewer"; import Events from "./helpers/Events"; import Groups from "./helpers/Groups"; -import HostEventsViewer from "./helpers/HostEventsViewer"; import Hosts from "./helpers/Hosts"; import JobDetail from "./helpers/JobDetail"; import JobSubmission from "./helpers/JobSubmission"; @@ -46,7 +45,6 @@ export EventViewer, Events, Groups, - HostEventsViewer, Hosts, JobDetail, JobSubmission, diff --git a/awx/ui/client/src/helpers/HostEventsViewer.js b/awx/ui/client/src/helpers/HostEventsViewer.js deleted file mode 100644 index e8fc5a940a..0000000000 --- a/awx/ui/client/src/helpers/HostEventsViewer.js +++ /dev/null @@ -1,287 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name helpers.function:HostEventsViewer - * @description view a list of events for a given job and host -*/ - -export default - angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities', 'EventViewerHelper']) - - .factory('HostEventsViewer', ['$log', '$compile', 'CreateDialog', 'Wait', 'GetBasePath', 'Empty', 'GetEvents', 'EventViewer', - function($log, $compile, CreateDialog, Wait, GetBasePath, Empty, GetEvents, EventViewer) { - return function(params) { - var parent_scope = params.scope, - scope = parent_scope.$new(true), - job_id = params.job_id, - url = params.url, - title = params.title, //optional - fixHeight, buildTable, - lastID, setStatus, buildRow, status; - - // initialize the status dropdown - scope.host_events_status_options = [ - { value: "all", name: "All" }, - { value: "changed", name: "Changed" }, - { value: "failed", name: "Failed" }, - { value: "ok", name: "OK" }, - { value: "unreachable", name: "Unreachable" } - ]; - scope.host_events_search_name = params.name; - status = (params.status) ? params.status : 'all'; - scope.host_events_status_options.every(function(opt, idx) { - if (opt.value === status) { - scope.host_events_search_status = scope.host_events_status_options[idx]; - return false; - } - return true; - }); - if (!scope.host_events_search_status) { - scope.host_events_search_status = scope.host_events_status_options[0]; - } - - $log.debug('job_id: ' + job_id + ' url: ' + url + ' title: ' + title + ' name: ' + name + ' status: ' + status); - - scope.eventsSearchActive = (scope.host_events_search_name) ? true : false; - - if (scope.removeModalReady) { - scope.removeModalReady(); - } - scope.removeModalReady = scope.$on('ModalReady', function() { - scope.hostViewSearching = false; - $('#host-events-modal-dialog').dialog('open'); - }); - - if (scope.removeJobReady) { - scope.removeJobReady(); - } - scope.removeEventReady = scope.$on('EventsReady', function(e, data, maxID) { - var elem, html; - - lastID = maxID; - html = buildTable(data); - $('#host-events').html(html); - elem = angular.element(document.getElementById('host-events-modal-dialog')); - $compile(elem)(scope); - - CreateDialog({ - scope: scope, - width: 675, - height: 600, - minWidth: 450, - callback: 'ModalReady', - id: 'host-events-modal-dialog', - onResizeStop: fixHeight, - title: ( (title) ? title : 'Host Events' ), - onClose: function() { - try { - scope.$destroy(); - } - catch(e) { - //ignore - } - }, - onOpen: function() { - fixHeight(); - } - }); - }); - - if (scope.removeRefreshHTML) { - scope.removeRefreshHTML(); - } - scope.removeRefreshHTML = scope.$on('RefreshHTML', function(e, data) { - var elem, html = buildTable(data); - $('#host-events').html(html); - scope.hostViewSearching = false; - elem = angular.element(document.getElementById('host-events')); - $compile(elem)(scope); - }); - - setStatus = function(result) { - var msg = '', status = 'ok', status_text = 'OK'; - if (!result.task && result.event_data && result.event_data.res && result.event_data.res.ansible_facts) { - result.task = "Gathering Facts"; - } - if (result.event === "runner_on_no_hosts") { - msg = "No hosts remaining"; - } - if (result.event === 'runner_on_unreachable') { - status = 'unreachable'; - status_text = 'Unreachable'; - } - else if (result.failed) { - status = 'failed'; - status_text = 'Failed'; - } - else if (result.changed) { - status = 'changed'; - status_text = 'Changed'; - } - if (result.event_data.res && result.event_data.res.msg) { - msg = result.event_data.res.msg; - } - result.msg = msg; - result.status = status; - result.status_text = status_text; - return result; - }; - - buildRow = function(res) { - var html = ''; - html += "\n"; - html += " " + res.status_text + "\n"; - html += "" + res.host_name + "\n"; - html += "" + res.play + "\n"; - html += "" + res.task + "\n"; - html += ""; - return html; - }; - - buildTable = function(data) { - var html = "\n"; - html += "\n"; - data.results.forEach(function(result) { - var res = setStatus(result); - html += buildRow(res); - }); - html += "\n"; - html += "
\n"; - return html; - }; - - fixHeight = function() { - var available_height = $('#host-events-modal-dialog').height() - $('#host-events-modal-dialog #search-form').height() - $('#host-events-modal-dialog #fixed-table-header').height(); - $('#host-events').height(available_height); - $log.debug('set height to: ' + available_height); - // Check width and reset search fields - if ($('#host-events-modal-dialog').width() <= 450) { - $('#host-events-modal-dialog #status-field').css({'margin-left': '7px'}); - } - else { - $('#host-events-modal-dialog #status-field').css({'margin-left': '15px'}); - } - }; - - GetEvents({ - url: url, - scope: scope, - callback: 'EventsReady' - }); - - scope.modalOK = function() { - $('#host-events-modal-dialog').dialog('close'); - scope.$destroy(); - }; - - scope.searchEvents = function() { - scope.eventsSearchActive = (scope.host_events_search_name) ? true : false; - GetEvents({ - scope: scope, - url: url, - callback: 'RefreshHTML' - }); - }; - - scope.searchEventKeyPress = function(e) { - if (e.keyCode === 13) { - scope.searchEvents(); - } - }; - - scope.showDetails = function(id) { - EventViewer({ - scope: parent_scope, - url: GetBasePath('jobs') + job_id + '/job_events/?id=' + id, - }); - }; - - if (scope.removeEventsScrollDownBuild) { - scope.removeEventsScrollDownBuild(); - } - scope.removeEventsScrollDownBuild = scope.$on('EventScrollDownBuild', function(e, data, maxID) { - var elem, html = ''; - lastID = maxID; - data.results.forEach(function(result) { - var res = setStatus(result); - html += buildRow(res); - }); - if (html) { - $('#host-events table tbody').append(html); - elem = angular.element(document.getElementById('host-events')); - $compile(elem)(scope); - } - }); - - scope.hostEventsScrollDown = function() { - GetEvents({ - scope: scope, - url: url, - gt: lastID, - callback: 'EventScrollDownBuild' - }); - }; - - }; - }]) - - .factory('GetEvents', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { - return function(params) { - var url = params.url, - scope = params.scope, - gt = params.gt, - callback = params.callback; - - if (scope.host_events_search_name) { - url += '?host_name=' + scope.host_events_search_name; - } - else { - url += '?host_name__isnull=false'; - } - - if (scope.host_events_search_status.value === 'changed') { - url += '&event__icontains=runner&changed=true'; - } - else if (scope.host_events_search_status.value === 'failed') { - url += '&event__icontains=runner&failed=true'; - } - else if (scope.host_events_search_status.value === 'ok') { - url += '&event=runner_on_ok&changed=false'; - } - else if (scope.host_events_search_status.value === 'unreachable') { - url += '&event=runner_on_unreachable'; - } - else if (scope.host_events_search_status.value === 'all') { - url += '&event__icontains=runner¬__event=runner_on_skipped'; - } - - if (gt) { - // used for endless scroll - url += '&id__gt=' + gt; - } - - url += '&page_size=50&order=id'; - - scope.hostViewSearching = true; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - var lastID; - scope.hostViewSearching = false; - if (data.results.length > 0) { - lastID = data.results[data.results.length - 1].id; - } - scope.$emit(callback, data, lastID); - }) - .error(function(data, status) { - scope.hostViewSearching = false; - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get events ' + url + '. GET returned: ' + status }); - }); - }; - }]); 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 e69de29bb2..0000000000 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 new file mode 100644 index 0000000000..bde3fe72fd --- /dev/null +++ b/awx/ui/client/src/job-detail/host-events/host-events.block.less @@ -0,0 +1,82 @@ +@import "awx/ui/client/src/shared/branding/colors.less"; +@import "awx/ui/client/src/shared/branding/colors.default.less"; + +.HostEvents .modal-footer{ + border: 0; + margin-top: 0px; + padding-top: 5px; +} +.HostEvents-status--ok{ + color: @green; +} +.HostEvents-status--unreachable{ + color: @unreachable; +} +.HostEvents-status--changed{ + color: @changed; +} +.HostEvents-status--failed{ + color: @warning; +} +.HostEvents-status--skipped{ + color: @skipped; +} +.HostEvents-search--form{ + max-width: 420px; + display: inline-block; +} +.HostEvents-close{ + width: 70px; +} +.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{ + 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: #848992; + background-color: #EBEBEB; + 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 new file mode 100644 index 0000000000..45a7268ed7 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-events/host-events.controller.js @@ -0,0 +1,184 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + export default + ['$stateParams', '$scope', '$rootScope', '$state', 'Wait', + 'JobDetailService', 'CreateSelect2', 'PaginateInit', + function($stateParams, $scope, $rootScope, $state, Wait, + JobDetailService, CreateSelect2, PaginateInit){ + + + $scope.search = function(){ + Wait('start'); + if ($scope.searchStr == undefined){ + return + } + // The API treats params as AND query + // We should discuss the possibility of an OR array + + // search play description + /* + JobDetailService.getRelatedJobEvents($stateParams.id, { + play: $scope.searchStr}) + .success(function(res){ + results.push(res.results); + }); + */ + // search host name + JobDetailService.getRelatedJobEvents($stateParams.id, { + host_name: $scope.searchStr}) + .success(function(res){ + $scope.results = res.results; + Wait('Stop') + }); + // search task + /* + JobDetailService.getRelatedJobEvents($stateParams.id, { + task: $scope.searchStr}) + .success(function(res){ + results.push(res.results); + }); + */ + }; + + $scope.filters = ['all', 'changed', 'failed', 'ok', 'unreachable', 'skipped']; + + var filter = function(filter){ + Wait('start'); + if (filter == 'all'){ + return JobDetailService.getRelatedJobEvents($stateParams.id, {host_name: $stateParams.hostName}) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + }); + } + // handle runner cases + if (filter == 'skipped'){ + return JobDetailService.getRelatedJobEvents($stateParams.id, { + host_name: $stateParams.hostName, + event: 'runner_on_skipped'}) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + }); + } + if (filter == 'unreachable'){ + return JobDetailService.getRelatedJobEvents($stateParams.id, { + host_name: $stateParams.hostName, + event: 'runner_on_unreachable'}) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + }); + } + if (filter == 'ok'){ + return JobDetailService.getRelatedJobEvents($stateParams.id, { + host_name: $stateParams.hostName, + event: 'runner_on_ok' + // add param changed: false if 'ok' shouldn't display changed hosts + }) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + }); + } + // handle convience properties .changed .failed + if (filter == 'changed'){ + return JobDetailService.getRelatedJobEvents($stateParams.id, { + host_name: $stateParams.hostName, + changed: true}) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + }); + } + if (filter == 'failed'){ + return JobDetailService.getRelatedJobEvents($stateParams.id, { + host_name: $stateParams.hostName, + failed: true}) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + }); + } + }; + + // watch select2 for changes + $('.HostEvents-select').on("select2:select", function (e) { + filter($('.HostEvents-select').val()); + }); + + $scope.processStatus = function(event, $index){ + // the stack for which status to display is + // unreachable > failed > changed > ok + // uses the API's runner events and convenience properties .failed .changed to determine status. + // see: job_event_callback.py + if (event.event == 'runner_on_unreachable'){ + $scope.results[$index].status = 'Unreachable'; + return 'HostEvents-status--unreachable' + } + // equiv to 'runner_on_error' && 'runner on failed' + if (event.failed){ + $scope.results[$index].status = 'Failed'; + return 'HostEvents-status--failed' + } + // catch the changed case before ok, because both can be true + if (event.changed){ + $scope.results[$index].status = 'Changed'; + return 'HostEvents-status--changed' + } + if (event.event == 'runner_on_ok'){ + $scope.results[$index].status = 'OK'; + return 'HostEvents-status--ok' + } + if (event.event == 'runner_on_skipped'){ + $scope.results[$index].status = 'Skipped'; + return 'HostEvents-status--skipped' + } + else{ + // study a case where none of these apply + } + }; + + + var init = function(){ + // create filter dropdown + CreateSelect2({ + element: '.HostEvents-select', + multiple: false + }); + // process the filter if one was passed + if ($stateParams.filter){ + filter($stateParams.filter).success(function(res){ + $scope.results = res.results; + PaginateInit({ scope: $scope, list: defaultUrl }); + Wait('stop'); + $('#HostEvents').modal('show'); + + + });; + } + else{ + Wait('start'); + JobDetailService.getRelatedJobEvents($stateParams.id, {host_name: $stateParams.hostName}) + .success(function(res){ + $scope.results = res.results; + Wait('stop'); + $('#HostEvents').modal('show'); + + }); + } + }; + + $scope.goBack = function(){ + // go back to the job details state + // we're leaning on $stateProvider's onExit to close the modal + $state.go('jobDetail'); + }; + + init(); + + }]; \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/host-events/host-events.partial.html b/awx/ui/client/src/job-detail/host-events/host-events.partial.html new file mode 100644 index 0000000000..a0ee6956bb --- /dev/null +++ b/awx/ui/client/src/job-detail/host-events/host-events.partial.html @@ -0,0 +1,59 @@ + \ No newline at end of file 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 new file mode 100644 index 0000000000..5365fea95c --- /dev/null +++ b/awx/ui/client/src/job-detail/host-events/host-events.route.js @@ -0,0 +1,27 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import {templateUrl} from '../../shared/template-url/template-url.factory'; + +export default { + name: 'jobDetail.hostEvents', + url: '/host-events/:hostName?:filter', + controller: 'HostEventsController', + 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: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } +}; diff --git a/awx/ui/client/src/job-detail/host-events/main.js b/awx/ui/client/src/job-detail/host-events/main.js new file mode 100644 index 0000000000..8a9487aec4 --- /dev/null +++ b/awx/ui/client/src/job-detail/host-events/main.js @@ -0,0 +1,15 @@ +/************************************************* + * 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) + }]); \ No newline at end of file diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js index e36dbb13de..1383f04c35 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -15,7 +15,7 @@ export default '$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList', - 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun', 'HostEventsViewer', + 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun', 'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'EditSchedule', 'ParseTypeChange', 'JobDetailService', 'EventViewer', @@ -25,7 +25,7 @@ export default SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, LoadHostSummary, ReloadHostSummaryList, JobIsFinished, SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, - PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, + PlaybookRun, LoadPlays, LoadTasks, LoadHosts, HostsEdit, ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule, ParseTypeChange, JobDetailService, EventViewer ) { @@ -43,7 +43,7 @@ export default 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; @@ -1400,17 +1400,6 @@ export default } }; - scope.hostEventsViewer = function(id, name, status) { - HostEventsViewer({ - scope: scope, - id: id, - name: name, - url: scope.job.related.job_events, - job_id: scope.job.id, - status: status - }); - }; - scope.refresh = function(){ $scope.$emit('LoadJob'); }; diff --git a/awx/ui/client/src/job-detail/job-detail.partial.html b/awx/ui/client/src/job-detail/job-detail.partial.html index 3ff7262d1c..aed0a5446e 100644 --- a/awx/ui/client/src/job-detail/job-detail.partial.html +++ b/awx/ui/client/src/job-detail/job-detail.partial.html @@ -1,9 +1,8 @@
- +
-
@@ -423,13 +422,13 @@ - {{ host.name }} + {{ host.name }} - {{ host.ok }} - {{ host.changed }} - {{ host.unreachable }} - {{ host.failed }} + {{ host.ok }} + {{ host.changed }} + {{ host.unreachable }} + {{ host.failed }} @@ -483,40 +482,6 @@
- -
diff --git a/awx/ui/client/src/job-detail/main.js b/awx/ui/client/src/job-detail/main.js index d985a310e6..8a9fc30aff 100644 --- a/awx/ui/client/src/job-detail/main.js +++ b/awx/ui/client/src/job-detail/main.js @@ -7,9 +7,12 @@ import route from './job-detail.route'; import controller from './job-detail.controller'; import service from './job-detail.service'; +import hostEvents from './host-events/main'; export default - angular.module('jobDetail', []) + angular.module('jobDetail', [ + hostEvents.name + ]) .controller('JobDetailController', controller) .service('JobDetailService', service) .run(['$stateExtender', function($stateExtender) { diff --git a/awx/ui/client/src/shared/stateExtender.provider.js b/awx/ui/client/src/shared/stateExtender.provider.js index f899f00c32..07b3c2051e 100644 --- a/awx/ui/client/src/shared/stateExtender.provider.js +++ b/awx/ui/client/src/shared/stateExtender.provider.js @@ -11,7 +11,9 @@ export default function($stateProvider){ resolve: state.resolve, params: state.params, data: state.data, - ncyBreadcrumb: state.ncyBreadcrumb + ncyBreadcrumb: state.ncyBreadcrumb, + onEnter: state.onEnter, + onExit: state.onExit }); } };