mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 12:20:45 -03:30
Collapse/expand job_events list using the api parent/child relationship
This commit is contained in:
parent
c9da8294df
commit
2abd33cf22
@ -436,4 +436,17 @@
|
||||
.list-header .icon-sort-down,
|
||||
.list-header .icon-sort-up {
|
||||
color: #36454F;
|
||||
}
|
||||
|
||||
/* job_events syles */
|
||||
tr td i {
|
||||
float: none;
|
||||
margin-right: 10px;
|
||||
padding-top: 3px;
|
||||
padding-left: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#event_display-header {
|
||||
min-width: 250px;
|
||||
}
|
||||
@ -52,7 +52,8 @@ angular.module('ansible', [
|
||||
'JobHostDefinition',
|
||||
'GroupsHelper',
|
||||
'HostsHelper',
|
||||
'ParseHelper'
|
||||
'ParseHelper',
|
||||
'ChildrenHelper'
|
||||
])
|
||||
.config(['$routeProvider', function($routeProvider) {
|
||||
$routeProvider.
|
||||
|
||||
@ -12,21 +12,50 @@
|
||||
|
||||
function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobEventList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, LookUpInit)
|
||||
ClearScope, ProcessErrors, GetBasePath, LookUpInit, ToggleChildren)
|
||||
{
|
||||
ClearScope('htmlTemplate');
|
||||
var list = JobEventList;
|
||||
list.base = $location.path();
|
||||
var defaultUrl = GetBasePath('jobs') + $routeParams.id + '/job_events/';
|
||||
|
||||
var defaultUrl = GetBasePath('jobs') + $routeParams.id + '/job_events/?parent__isnull=1';
|
||||
|
||||
var view = GenerateList;
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
var scope = view.inject(list, { mode: 'edit' });
|
||||
scope.selected = [];
|
||||
|
||||
if (scope.RemovePostRefresh) {
|
||||
scope.RemovePostRefresh();
|
||||
}
|
||||
scope.RemovePostRefresh = scope.$on('PostRefresh', function() {
|
||||
// Initialize the parent levels
|
||||
var set = scope[list.name];
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SearchInit({ scope: scope, set: 'jobevents', list: list, url: defaultUrl });
|
||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||
scope.search(list.iterator);
|
||||
|
||||
scope.toggleChildren = function(id, children) {
|
||||
ToggleChildren({
|
||||
scope: scope,
|
||||
list: list,
|
||||
id: id,
|
||||
children: children
|
||||
});
|
||||
}
|
||||
|
||||
LoadBreadCrumbs();
|
||||
|
||||
if (scope.PostRefreshRemove) {
|
||||
@ -76,7 +105,7 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
||||
|
||||
JobEventsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobEventList',
|
||||
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||
'ProcessErrors','GetBasePath', 'LookUpInit'
|
||||
'ProcessErrors','GetBasePath', 'LookUpInit', 'ToggleChildren'
|
||||
];
|
||||
|
||||
function JobEventsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobEventForm,
|
||||
|
||||
112
ansibleworks/ui/static/js/helpers/Children.js
Normal file
112
ansibleworks/ui/static/js/helpers/Children.js
Normal file
@ -0,0 +1,112 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2013 AnsibleWorks, Inc.
|
||||
*
|
||||
* ChildrenHelper
|
||||
*
|
||||
* Used in job_events to expand/collapse children
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('ChildrenHelper', ['RestServices', 'Utilities'])
|
||||
.factory('ToggleChildren', ['Alert', 'Rest', 'GetBasePath','ProcessErrors',
|
||||
function(Alert, Rest, GetBasePath, ProcessErrors) {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var list = params.list;
|
||||
var id = params.id;
|
||||
var children = params.children;
|
||||
var set = scope[list.name]; // set is now a pointer to scope[list.name]
|
||||
|
||||
function calcSpaces(lvl) {
|
||||
return lvl * 24;
|
||||
}
|
||||
|
||||
// Scan the array list and find the clicked element
|
||||
var clicked;
|
||||
var found = false;
|
||||
for (var i = 0; i < set.length && found == false; i++){
|
||||
if (set[i].id == id) {
|
||||
clicked = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
// Expand or collapse children based on clicked element's icon
|
||||
if (set[clicked]['ngicon'] == 'icon-expand-alt') {
|
||||
// Expand: lookup and display children
|
||||
Rest.setUrl(children);
|
||||
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;
|
||||
//if (data.results[j].related.children === undefined) {
|
||||
// data.results[j].spaces += 12
|
||||
//}
|
||||
data.results[j].event_display = data.results[j].event_display.replace(/^\u00a0*/g,'');
|
||||
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';
|
||||
}
|
||||
if (clicked == (set.length - 1)) {
|
||||
set.push(data.results[j]);
|
||||
}
|
||||
else {
|
||||
set.splice(clicked + 1, 0, data.results[j]);
|
||||
}
|
||||
clicked++;
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + children + ' failed. GET returned status: ' + status });
|
||||
});
|
||||
}
|
||||
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';
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -102,15 +102,15 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
(list.fields[scope[iterator + 'SearchField']].searchType && list.fields[scope[iterator + 'SearchField']].searchType == 'gtzero') ) {
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField']].searchField) {
|
||||
scope[iterator + 'SearchParams'] = '?' + list.fields[scope[iterator + 'SearchField']].searchField + '__';
|
||||
scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField']].searchField + '__';
|
||||
}
|
||||
else if (list.fields[scope[iterator + 'SearchField']].sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] = '?' + list.fields[scope[iterator + 'SearchField']].sourceModel + '__' +
|
||||
scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField']].sourceModel + '__' +
|
||||
list.fields[scope[iterator + 'SearchField']].sourceField + '__';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = '?' + scope[iterator + 'SearchField'] + '__';
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField'] + '__';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField']].searchType &&
|
||||
@ -138,11 +138,16 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
scope[iterator + 'SearchParams'] += (sort_order) ? '&order_by=' + escape(sort_order) : '';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = '';
|
||||
scope[iterator + 'SearchParams'] += (sort_order) ? '?order_by=' + escape(sort_order) : '';
|
||||
scope[iterator + 'SearchParams'] = (sort_order) ? 'order_by=' + escape(sort_order) : "";
|
||||
}
|
||||
scope[iterator + 'Page'] = 0;
|
||||
url += scope[iterator + 'SearchParams'];
|
||||
if (/\/$/.test(url)) {
|
||||
url += '?' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
else {
|
||||
url += '&' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
url = url.replace(/\&\&/,'&');
|
||||
url += (scope[iterator + 'PageSize']) ? '&page_size=' + scope[iterator + 'PageSize'] : "";
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
}
|
||||
|
||||
@ -15,20 +15,19 @@ angular.module('JobEventsListDefinition', [])
|
||||
editTitle: 'Job Events',
|
||||
index: false,
|
||||
hover: true,
|
||||
hasChildren: true,
|
||||
|
||||
fields: {
|
||||
id: {
|
||||
label: 'Event ID',
|
||||
created: {
|
||||
label: 'Creation Date',
|
||||
key: true,
|
||||
desc: true,
|
||||
searchType: 'int'
|
||||
nosort: true
|
||||
},
|
||||
event_display: {
|
||||
label: 'Event',
|
||||
link: true
|
||||
},
|
||||
created: {
|
||||
label: 'Creation Date'
|
||||
hasChildren: true,
|
||||
link: true,
|
||||
nosort: true
|
||||
},
|
||||
host: {
|
||||
label: 'Host',
|
||||
@ -36,7 +35,8 @@ angular.module('JobEventsListDefinition', [])
|
||||
ngBind: 'jobevent.host_name',
|
||||
sourceModel: 'host',
|
||||
sourceField: 'name',
|
||||
searchField: 'hosts__name'
|
||||
searchField: 'hosts__name',
|
||||
nosort: true
|
||||
},
|
||||
status: {
|
||||
label: 'Status',
|
||||
@ -44,7 +44,8 @@ angular.module('JobEventsListDefinition', [])
|
||||
"class": 'job-\{\{ jobevent.status \}\}',
|
||||
searchField: 'failed',
|
||||
searchType: 'boolean',
|
||||
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }]
|
||||
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }],
|
||||
nosort: true
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
var html = '';
|
||||
|
||||
html += "<td ";
|
||||
html += "<td class=\"" + fld + "-column";
|
||||
html += "<td class=\"" + fld + "-column";
|
||||
html += (field['class']) ? " " + field['class'] : "";
|
||||
html += "\" ";
|
||||
html += (field.ngClass) ? this.attr(field, 'ngClass') : "";
|
||||
@ -92,6 +92,13 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
|
||||
// Add ngShow
|
||||
html += (field.ngShow) ? "<span " + Attr(field,'ngShow') + ">" : "";
|
||||
|
||||
// Add collapse/expand icon --used on job_events page
|
||||
if (list['hasChildren'] && field.hasChildren) {
|
||||
html += "<span style=\"padding-left: \{\{ " + list.iterator + ".spaces \}\}px\"><a href=\"\" ng-click=\"\{\{ " + list.iterator + ".ngclick \}\}\"> " +
|
||||
"<i class=\"\{\{ " + list.iterator + ".ngicon \}\}\" ng-show=\"'\{\{ " +
|
||||
list.iterator + ".related.children \}\}' !== ''\" ></i></a> ";
|
||||
}
|
||||
|
||||
// Start the Link
|
||||
if ((field.key || field.link || field.linkTo || field.ngClick ) && options['mode'] != 'lookup' && options['mode'] != 'select') {
|
||||
@ -111,7 +118,9 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
html += "<i ng-show=\"" + field.ngShowIcon + "\" class=\"" + field.icon + "\"></i> ";
|
||||
}
|
||||
else {
|
||||
html += Icon(field.icon) + " ";
|
||||
if (field.icon) {
|
||||
html += Icon(field.icon) + " ";
|
||||
}
|
||||
}
|
||||
|
||||
// Add data binds
|
||||
@ -120,15 +129,19 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
html += "{{ " + field.ngBind + " }}";
|
||||
}
|
||||
else {
|
||||
html += "{{" + list.iterator + "." + fld + "}}";
|
||||
html += "{{" + list.iterator + "." + fld + "}}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add additional text:
|
||||
if (field.text) {
|
||||
html += field.text;
|
||||
}
|
||||
|
||||
if (list['hasChildren'] && field.hasChildren) {
|
||||
html += "</span>";
|
||||
}
|
||||
|
||||
// close the link
|
||||
if ((field.key || field.link || field.linkTo || field.ngClick )
|
||||
&& options.mode != 'lookup' && options.mode != 'select') {
|
||||
|
||||
@ -153,20 +153,25 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
html += "<th>#</th>\n";
|
||||
}
|
||||
for (var fld in list.fields) {
|
||||
html += "<th class=\"list-header\" id=\"" + fld + "-header\" ng-click=\"sort('" + fld + "')\">" + list.fields[fld].label;
|
||||
html += " <i class=\"";
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].desc) {
|
||||
html += "icon-sort-down";
|
||||
html += "<th class=\"list-header\" id=\"" + fld + "-header\" ";
|
||||
html += (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) ? "ng-click=\"sort('" + fld + "')\"" : "";
|
||||
html += ">" + list.fields[fld].label;
|
||||
if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
|
||||
html += " <i class=\"";
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].desc) {
|
||||
html += "icon-sort-down";
|
||||
}
|
||||
else {
|
||||
html += "icon-sort-up";
|
||||
}
|
||||
}
|
||||
else {
|
||||
html += "icon-sort-up";
|
||||
else {
|
||||
html += "icon-sort";
|
||||
}
|
||||
html += "\"></i></a>";
|
||||
}
|
||||
else {
|
||||
html += "icon-sort";
|
||||
}
|
||||
html += "\"></i></a></th>\n";
|
||||
html += "</th>\n";
|
||||
}
|
||||
if (options.mode == 'select') {
|
||||
html += "<th>Select</th>";
|
||||
|
||||
@ -74,6 +74,7 @@
|
||||
<script src="{{ STATIC_URL }}js/helpers/Groups.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/Hosts.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/Parse.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/Children.js"></script>
|
||||
<script src="{{ STATIC_URL }}lib/ansible/directives.js"></script>
|
||||
<script src="{{ STATIC_URL }}lib/ansible/filters.js"></script>
|
||||
<script src="{{ STATIC_URL }}lib/ansible/api-loader.js"></script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user