diff --git a/awx/ui/static/css/ansible-ui.css b/awx/ui/static/css/ansible-ui.css index f1f0bb05be..000736837a 100644 --- a/awx/ui/static/css/ansible-ui.css +++ b/awx/ui/static/css/ansible-ui.css @@ -370,6 +370,10 @@ color: #5bb75b; } + .job-changed { + color: #FF9900; + } + .job-detail-status { font-size: 15px; font-weight: bold; diff --git a/awx/ui/static/js/controllers/JobEvents.js b/awx/ui/static/js/controllers/JobEvents.js index 690f7e5bcd..5afbb7f17e 100644 --- a/awx/ui/static/js/controllers/JobEvents.js +++ b/awx/ui/static/js/controllers/JobEvents.js @@ -19,7 +19,7 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest, var list = JobEventList; list.base = $location.path(); - var defaultUrl = GetBasePath('jobs') + $routeParams.id + '/job_events/?parent__isnull=1'; + var defaultUrl = GetBasePath('jobs') + $routeParams.id + '/job_events/'; //?parent__isnull=1'; var view = GenerateList; var base = $location.path().replace(/^\//,'').split('/')[0]; @@ -32,6 +32,47 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest, scope.parentNode = 'parent-event'; // used in ngClass to dynamicall set row level class and control scope.childNode = 'child-event'; // link color and cursor + function formatJSON(eventData) { + //turn JSON event data into an html form + var html = ''; + if (eventData.res) { + var found = false; + var n, rows; + if (typeof eventData.res == 'string') { + n = eventData['res'].match(/\n/g); + rows = (n) ? n.length : 1; + found = true; + html += "\n"; + html += "\n"; + } + else { + for (var fld in eventData.res) { + if ( (fld == 'msg' || fld == 'stdout' || fld == 'stderr') && + (eventData.res[fld] !== null && eventData.res[fld] !== '') ) { + html += "\n"; + n = eventData['res'][fld].match(/\n/g); + rows = (n) ? n.length : 1; + html += "\n"; + found = true; + } + } + } + html = (found) ? "
\n" + html + "
\n" : ''; + } + html = (html == '' ) ? null : html; + return html; + } + if (scope.RemovePostRefresh) { scope.RemovePostRefresh(); } @@ -41,62 +82,35 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest, var cDate; for (var i=0; i < set.length; i++) { set[i].event_display = set[i].event_display.replace(/^\u00a0*/g,''); - if (set[i].parent == null && set[i]['ngclick'] === undefined && set[i]['ngicon'] == undefined) { - set[i].parent = 0; + if (set[i].event_level < 3 ) { set[i]['ngclick'] = "toggleChildren(" + set[i].id + ", \"" + set[i].related.children + "\")"; - set[i]['ngicon'] = 'icon-expand-alt'; - set[i]['level'] = 0; - set[i]['spaces'] = 0; + set[i]['ngicon'] = 'icon-collapse-alt'; set[i]['class'] = 'parentNode'; } - scope.jobevents[i].status = (scope.jobevents[i].failed) ? 'error' : 'success'; + else { + set[i]['class'] = 'childNode'; + set[i]['event_detail'] = formatJSON(set[i].event_data); + } + set[i]['show'] = true; + set[i]['spaces'] = set[i].event_level * 24; + if (scope.jobevents[i].failed) { + scope.jobevents[i].status = 'error'; + } + else if (scope.jobevents[i].changed) { + scope.jobevents[i].status = 'changed'; + } + else { + scope.jobevents[i].status = 'success'; + } cDate = new Date(set[i].created); set[i].created = FormatDate(cDate); } - - // Expand all parent nodes - if (scope.removeSetExpanded) { - scope.removeSetExpanded(); - } - scope.removeSetExpanded = scope.$on('setExpanded', function(event) { - // After ToggleChildren completes, look for the next parent that needs to be expanded - var found = false; - for (var i=0; i < set.length && found == false && scope.expand; i++) { - if (set[i]['related']['children'] && (set[i]['ngicon'] == undefined || set[i]['ngicon'] == 'icon-expand-alt')) { - found = true; - ToggleChildren({ - scope: scope, - list: list, - id: set[i].id, - children: set[i]['related']['children'] - }); - } - } - if (found == false) { - // After looping through all the nodes and finding nothing to expand, turn off - // auto-expand. From now on user will manually collapse and expand nodes. - scope.expand = false; - } - }); - // Start the auto expansion - set = scope[list.name]; - for (var i=0; i < set.length; i++) { - if (set[i]['related']['children'] && (set[i]['ngicon'] == undefined || set[i]['ngicon'] == 'icon-expand-alt')) { - ToggleChildren({ - scope: scope, - list: list, - id: set[i].id, - children: set[i]['related']['children'] - }); - } - } - }); SearchInit({ scope: scope, set: 'jobevents', list: list, url: defaultUrl }); PaginateInit({ scope: scope, list: list, url: defaultUrl }); - // Called from Inventories tab host failed events link: + // Called from Inventories tab, host failed events link: if ($routeParams.host) { scope[list.iterator + 'SearchField'] = 'host'; scope[list.iterator + 'SearchValue'] = $routeParams.host; diff --git a/awx/ui/static/js/helpers/Children.js b/awx/ui/static/js/helpers/Children.js index 93921f0c6c..4f053bf8ad 100644 --- a/awx/ui/static/js/helpers/Children.js +++ b/awx/ui/static/js/helpers/Children.js @@ -3,7 +3,9 @@ * * ChildrenHelper * - * Used in job_events to expand/collapse children + * Used in job_events to expand/collapse children by setting the + * 'show' attribute of each job_event in the set of job_events. + * See the filter in job_events.js list. * */ @@ -18,37 +20,28 @@ angular.module('ChildrenHelper', ['RestServices', 'Utilities']) var children = params.children; var set = scope[list.name]; // set is now a pointer to scope[list.name] - function calcSpaces(lvl) { - return lvl * 24; + function expand(node) { + set[node]['ngicon'] = 'icon-collapse-alt'; + for (var i = node + 1; i < set.length; i++) { + if (set[i].parent == set[node].id) { + set[i]['show'] = true; + if (set[i].related.children) { + expand(i); + } + } + } } - function formatJSON(eventData) { - //turn JSON event data into an html form - var html = ''; - if (eventData.res) { - var found = false; - for (var fld in eventData.res) { - if ( (fld == 'msg' || fld == 'stdout' || fld == 'stderr') && - (eventData.res[fld] !== null && eventData.res[fld] !== '') ) { - html += "\n"; - html += "\n"; - found = true; - } + function collapse(node) { + set[node]['ngicon'] = 'icon-expand-alt'; + for (var i = node + 1; i < set.length; i++) { + if (set[i].parent == set[node].id) { + set[i]['show'] = false; + if (set[i]['related']['children']) { + collapse(i); + } } - html = (found) ? "
\n" + html + "
\n" : ''; - } - html = (html == '' ) ? null : html; - return html; + } } // Scan the array list and find the clicked element @@ -62,90 +55,11 @@ angular.module('ChildrenHelper', ['RestServices', 'Utilities']) } // Expand or collapse children based on clicked element's icon if (set[clicked]['ngicon'] == 'icon-expand-alt') { - // Expand: lookup and display children - var url = children; - var search = scope[list.iterator + 'SearchParams'].replace(/^\&/,'').replace(/^\?/,''); - url += (search) ? '?' + search : ""; - Rest.setUrl(url); - Rest.get() - .success( function(data, status, headers, config) { - var found = false; - var level = (set[clicked].level !== undefined) ? set[clicked].level + 1 : 1; - var spaces = calcSpaces(level); - set[clicked]['ngicon'] = 'icon-collapse-alt'; - for (var j=0; j < data.results.length; j++) { - data.results[j].level = level; - data.results[j].spaces = spaces; - data.results[j].status = (data.results[j].failed) ? 'error' : 'success'; - data.results[j].event_display = data.results[j].event_display.replace(/^\u00a0*/g,''); - cDate = new Date(data.results[j].created); - data.results[j].created = FormatDate(cDate); - if (data.results[j].related.children) { - data.results[j]['ngclick'] = "toggleChildren(" + data.results[j].id + ", \"" + data.results[j].related.children + "\")"; - data.results[j]['ngicon'] = 'icon-expand-alt'; - data.results[j]['class'] = 'parentNode'; - } - else { - data.results[j]['class'] = 'childNode'; - // For child nodes, include some of the even_data detail, but in a nicer non-JSONy format - data.results[j]['event_detail'] = formatJSON(data.results[j]['event_data']); - } - /*if (data.results[j]['event_data']['res'] && data.results[j]['event_data']['res']['msg']) { - // Display the actual result message - data.results[j]['event_display'] = data.results[j]['event_data']['res']['msg']; - } - if (data.results[j]['event'] == 'playbook_on_stats') { - data.results[j]['event_display'] = 'Play Recap ****** '; - for (var key in data.results[j]['event_data']) { - var count = 0; - for (var itm in data.results[j]['event_data'][key]) { - count += data.results[j]['event_data'][key][itm]; - } - data.results[j]['event_display'] += key + ": " + count + " "; - } - } - */ - if (clicked == (set.length - 1)) { - set.push(data.results[j]); - } - else { - set.splice(clicked + 1, 0, data.results[j]); - } - clicked++; - } - scope.$emit('setExpanded'); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Call to ' + children + ' failed. GET returned status: ' + status }); - }); + // Expand: lookup and display children + expand(clicked); } else { - // Collapse: find and remove children - var parents = []; - function findChildren(parent, idx) { - // recursive look through the tree finding all - // parents including and related the clicked element - for (var i=idx; i < set.length; i++) { - if (set[i].parent == parent) { - parents.push(parent); - findChildren(set[i].id, i + 1); - } - } - } - findChildren(id, clicked + 1); - // Remove all the children of the clicked element - var count; - for (var i=0; i < parents.length; i++) { - count = 0; - for (var j=clicked + 1; j< set.length; j++) { - if (set[j].parent == parents[i]) { - set.splice(j,1); - j=clicked; // start back a the top of the list - } - } - } - set[clicked]['ngicon'] = 'icon-expand-alt'; + collapse(clicked); } } }]); diff --git a/awx/ui/static/js/lists/JobEvents.js b/awx/ui/static/js/lists/JobEvents.js index 85a037f044..a5585c51c5 100644 --- a/awx/ui/static/js/lists/JobEvents.js +++ b/awx/ui/static/js/lists/JobEvents.js @@ -16,6 +16,7 @@ angular.module('JobEventsListDefinition', []) index: false, hover: true, hasChildren: true, + filterBy: '\{ show: true \}', fields: { created: { diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js index 108cfcd747..48c794382f 100644 --- a/awx/ui/static/lib/ansible/list-generator.js +++ b/awx/ui/static/lib/ansible/list-generator.js @@ -193,6 +193,7 @@ angular.module('ListGenerator', ['GeneratorHelpers']) html += (options.mode == 'lookup' || options.mode == 'select') ? "ng-class=\"" + list.iterator + "_\{\{ " + list.iterator + ".id \}\}_class\" " : ""; html += "class=\"" + list.iterator + "_class\" ng-repeat=\"" + list.iterator + " in " + list.name; html += (list.orderBy) ? " | orderBy:'" + list.orderBy + "'" : ""; + html += (list.filterBy) ? " | filter: " + list.filterBy : ""; html += "\""; html += (options.mode == 'lookup' || options.mode == 'select') ? " ng-click=\"toggle_" + list.iterator +"({{ " + list.iterator + ".id }})\"" : ""; html += ">\n";