From 1b3902a23bf6a846c717ec8ed6157b634adb6d19 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Wed, 3 Jul 2013 12:02:20 -0400 Subject: [PATCH] Job Events collapse/expand now handled using a filter on ng-repeat and setting 'show' attribute in job_events data set. No longer reading child rows from api on expand and throwing them away on collapse. New method is much faster. Added formatJSON() routine back in to transform relevant event_data bits into html form elments and display in list. --- awx/ui/static/css/ansible-ui.css | 4 + awx/ui/static/js/controllers/JobEvents.js | 106 ++++++++------- awx/ui/static/js/helpers/Children.js | 136 ++++---------------- awx/ui/static/js/lists/JobEvents.js | 1 + awx/ui/static/lib/ansible/list-generator.js | 1 + 5 files changed, 91 insertions(+), 157 deletions(-) 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";