diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js
index 0413571b90..62ca24f2b5 100644
--- a/awx/ui/static/js/controllers/Inventories.js
+++ b/awx/ui/static/js/controllers/Inventories.js
@@ -94,6 +94,11 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa
var defaultUrl = GetBasePath('inventory');
var form = InventoryForm;
var generator = GenerateForm;
+
+ form.well = true,
+ form.formLabelSize = null;
+ form.formFieldSize = null;
+
var scope = generator.inject(form, {mode: 'add', related: false});
scope.inventoryParseType = 'yaml';
@@ -398,7 +403,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope.inventoryEditHide = true;
scope.groupDeleteHide = false;
scope.createButtonShow = true;
- //scope.group_id = node.attr('group_id');
+ scope.group_id = node.attr('group_id');
//scope.groupName = n.data;
//scope.groupTitle = '
' + n.data + '
';
//scope.groupTitle += (node.attr('description')) ? '' + node.attr('description') + '
' : '';
@@ -413,7 +418,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope.createButtonShow = false;
//scope.groupName = 'All Hosts';
//scope.groupTitle = 'All Hosts
';
- //scope.group_id = null;
+ scope.group_id = null;
}
if (!scope.$$phase) {
@@ -463,20 +468,18 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
request: 'remove' });
} */
- scope.showEvents = function(host_name, last_job) {
- // When click on !Failed Events link, redirect to latest job/job_events for the host
- Rest.setUrl(last_job);
- Rest.get()
- .success( function(data, status, headers, config) {
- LoadBreadCrumbs({ path: '/jobs/' + data.id, title: data.name });
- $location.url('/jobs/' + data.id + '/job_events/?host=' + escape(host_name));
- })
- .error( function(data, status, headers, config) {
- ProcessErrors(scope, data, status, form,
- { hdr: 'Error!', msg: 'Failed to lookup last job: ' + last_job + '. GET status: ' + status });
- });
+ scope.viewLastEvents = function(host_id, last_job, host_name, last_job_name) {
+ // Choose View-> Latest job events
+ LoadBreadCrumbs({ path: '/jobs/' + last_job, title: last_job_name });
+ $location.url('/jobs/' + last_job + '/job_events/?host=' + escape(host_name));
}
+ scope.viewLastSummary = function(host_id, last_job, host_name, last_job_name) {
+ // Choose View-> Latest job events
+ LoadBreadCrumbs({ path: '/jobs/' + last_job, title: last_job_name });
+ $location.url('/jobs/' + last_job + '/job_host_summaries/?host=' + escape(host_name));
+ }
+
scope.toggleAllHosts = function() {
scope.hostDeleteDisabled = (scope.toggleAllFlag) ? false : true;
scope.hostDeleteDisabledClass = (scope.hostDeleteDisabled) ? "disabled" : "";
diff --git a/awx/ui/static/js/controllers/JobHosts.js b/awx/ui/static/js/controllers/JobHosts.js
index af915e5031..e7a28044cb 100644
--- a/awx/ui/static/js/controllers/JobHosts.js
+++ b/awx/ui/static/js/controllers/JobHosts.js
@@ -35,6 +35,14 @@ function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams,
SearchInit({ scope: scope, set: 'jobhosts', list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
+
+ // Called from Inventories tab, host failed events link:
+ if ($routeParams.host) {
+ scope[list.iterator + 'SearchField'] = 'host';
+ scope[list.iterator + 'SearchValue'] = $routeParams.host;
+ scope[list.iterator + 'SearchFieldLabel'] = list.fields['host'].label;
+ }
+
scope.search(list.iterator);
LoadBreadCrumbs();
diff --git a/awx/ui/static/js/forms/Inventories.js b/awx/ui/static/js/forms/Inventories.js
index 811752bd6d..912858c6f6 100644
--- a/awx/ui/static/js/forms/Inventories.js
+++ b/awx/ui/static/js/forms/Inventories.js
@@ -14,19 +14,12 @@ angular.module('InventoryFormDefinition', [])
editTitle: '{{ inventory_name }}',
name: 'inventory',
parseTypeName: 'inventoryParseType',
- well: false,
+ well: true,
+ /*,
formLabelSize: 'col-lg-3',
- formFieldSize: 'col-lg-9',
+ formFieldSize: 'col-lg-9',*/
fields: {
- has_active_failures: {
- label: 'Status',
- control: '' +
- ' Contains hosts with failed jobs
',
- type: 'custom',
- ngShow: 'has_active_failures',
- readonly: true
- },
inventory_name: {
realName: 'name',
label: 'Name',
@@ -116,18 +109,26 @@ angular.module('InventoryFormDefinition', [])
badgeShow: "\{\{ host.has_active_failures \}\}",
badgeIcon: 'icon-exclamation-sign',
badgeToolTip: 'Most recent job failed',
- badgePlacement: 'bottom'
+ badgePlacement: 'bottom',
+ columnClass: 'col-lg-3'
},
- /*description: {
- label: 'Description',
- ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')"
- },*/
groups: {
label: 'Groups',
searchable: false,
sourceModel: 'groups',
sourceField: 'name',
nosort: true
+ },
+ dropdown: {
+ type: 'DropDown',
+ label: 'View',
+ options: [
+ { ngClick: 'viewJobs(\{\{ host.id \}\})', label: 'Jobs' },
+ { ngClick: "viewLastEvents(\{\{ host.id \}\}, '\{\{ host.last_job \}\}', '\{\{ host.name \}\}', " +
+ "'\{\{ host.summary_fields.last_job.name \}\}')", label: 'Latest job events' },
+ { ngClick: "viewLastSummary(\{\{ host.id \}\}, '\{\{ host.last_job \}\}', '\{\{ host.name \}\}', " +
+ "'\{\{ host.summary_fields.last_job.name \}\}')", label: 'Latest host summary' }
+ ]
}
},
fieldActions: {
diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js
index 49bb98962f..c6105b2464 100644
--- a/awx/ui/static/js/helpers/Groups.js
+++ b/awx/ui/static/js/helpers/Groups.js
@@ -341,14 +341,14 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
.factory('GroupsDelete', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
- 'Prompt', 'ProcessErrors', 'GetBasePath', 'RefreshTree',
+ 'Prompt', 'ProcessErrors', 'GetBasePath', 'RefreshTree', 'Wait',
function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
- GetBasePath, RefreshTree) {
+ GetBasePath, RefreshTree, Wait) {
return function(params) {
// Delete the selected group node. Disassociates it from its parent.
var scope = params.scope;
var group_id = params.group_id;
- var inventory_id = params.inventory_id;
+ var inventory_id = params.inventory_id;
var obj = $('#tree-view li[group_id="' + group_id + '"]');
var parent = (obj.parent().last().prop('tagName') == 'LI') ? obj.parent().last() : obj.parent().parent().last();
var url;
@@ -360,16 +360,19 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
url = GetBasePath('inventory') + inventory_id + '/groups/';
}
var action_to_take = function() {
+ $('#prompt-modal').modal('hide');
+ Wait('start');
Rest.setUrl(url);
Rest.post({ id: group_id, disassociate: 1 })
.success( function(data, status, headers, config) {
- $('#prompt-modal').modal('hide');
scope.selectedNode = scope.selectedNode.parent().parent();
RefreshTree({ scope: scope });
+ Wait('stop');
})
.error( function(data, status, headers, config) {
- $('#prompt-modal').modal('hide');
+ //$('#prompt-modal').modal('hide');
RefreshTree({ scope: scope });
+ Wait('stop');
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
});
diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js
index 1520356bad..a51281bef2 100644
--- a/awx/ui/static/js/helpers/inventory.js
+++ b/awx/ui/static/js/helpers/inventory.js
@@ -179,7 +179,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
items: scope.treeController
}
});
-
+
$(tree_id).bind("loaded.jstree", function () {
scope['treeLoading'] = false;
scope.$emit('treeLoaded');
@@ -374,7 +374,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
// Call after GroupsEdit controller saves changes
$('#tree-view').jstree('rename_node', node, name);
node.attr('description', description);
- scope = angular.element(getElementById('htmlTemplate')).scope();
+ scope = angular.element(document.getElementById('htmlTemplate')).scope();
scope['selectedNodeName'] = name;
}
}])
@@ -450,7 +450,11 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
var form = InventoryForm;
var defaultUrl=GetBasePath('inventory');
var scope = params.scope
-
+
+ form.well = false,
+ form.formLabelSize = 'col-lg-3';
+ form.formFieldSize = 'col-lg-9';
+
generator.inject(form, {mode: 'edit', modal: true, related: false});
ParseTypeChange(scope,'inventory_variables', 'inventoryParseType');
diff --git a/awx/ui/static/js/helpers/search.js b/awx/ui/static/js/helpers/search.js
index 3508fc7560..bbbab6c1bc 100644
--- a/awx/ui/static/js/helpers/search.js
+++ b/awx/ui/static/js/helpers/search.js
@@ -112,6 +112,7 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
scope[iterator + 'Loading'] = true;
scope[iterator + 'SearchParms'] = '';
var url = defaultUrl;
+
if ( (scope[iterator + 'SelectShow'] == false && scope[iterator + 'SearchValue'] != '' && scope[iterator + 'SearchValue'] != undefined) ||
(scope[iterator + 'SelectShow'] && scope[iterator + 'SearchSelectValue']) ||
(list.fields[scope[iterator + 'SearchField']].searchType && list.fields[scope[iterator + 'SearchField']].searchType == 'gtzero') ) {
@@ -156,6 +157,11 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
else {
scope[iterator + 'SearchParams'] = (sort_order) ? 'order_by=' + escape(sort_order) : "";
}
+
+ if (iterator == 'inventory' && scope.inventoryFailureFilter) {
+ scope[iterator + 'SearchParams'] += '&has_active_failures=true';
+ }
+
scope[iterator + 'Page'] = (page) ? parseInt(page) - 1 : 0;
if (/\/$/.test(url)) {
url += '?' + scope[iterator + 'SearchParams'];
diff --git a/awx/ui/static/js/lists/Inventories.js b/awx/ui/static/js/lists/Inventories.js
index 053f99e256..66f754b734 100644
--- a/awx/ui/static/js/lists/Inventories.js
+++ b/awx/ui/static/js/lists/Inventories.js
@@ -21,7 +21,11 @@ angular.module('InventoriesListDefinition', [])
fields: {
name: {
key: true,
- label: 'Name'
+ label: 'Name',
+ badgeShow: "\{\{ inventory.has_active_failures \}\}",
+ badgeIcon: 'icon-exclamation-sign',
+ badgeToolTip: 'Contains hosts with active job failures',
+ badgePlacement: 'bottom'
},
description: {
label: 'Description'
@@ -32,7 +36,8 @@ angular.module('InventoriesListDefinition', [])
sourceModel: 'organization',
sourceField: 'name',
excludeModal: true
- },
+ }
+ /*,
has_active_failures: {
label: 'Failed Jobs?',
showValue: false,
@@ -45,7 +50,7 @@ angular.module('InventoriesListDefinition', [])
searchType: 'boolean',
searchOptions: [{ name: "No", value: 0 }, { name: "Yes", value: 1 }],
excludeModal: true
- }
+ }*/
},
actions: {
diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less
index c12eac4afc..dbdb538e66 100644
--- a/awx/ui/static/less/ansible-ui.less
+++ b/awx/ui/static/less/ansible-ui.less
@@ -179,8 +179,6 @@ a:hover {
text-decoration: none;
}
-
-
.site-footer {
width: 100%;
padding-top: 20px;
@@ -225,10 +223,6 @@ a:hover {
text-align: center;
}
-
-
-
-
.login-header {
text-align: center;
}
@@ -620,7 +614,7 @@ input[type="text"].job-successful {
}
- .host-badge {
+ .field-badge {
color: @red;
font-size: 12px;
}
diff --git a/awx/ui/static/lib/ansible/directives.js b/awx/ui/static/lib/ansible/directives.js
index 8248a7f4e5..279489a7c5 100644
--- a/awx/ui/static/lib/ansible/directives.js
+++ b/awx/ui/static/lib/ansible/directives.js
@@ -533,7 +533,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
html += "" + data.results[i].name + " ";
html += "" +
- "\n";
+ "\n";
}
html = (html !== '') ? "\n" : "";
var compiled = $compile(html)(scope);
@@ -580,7 +580,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
"> " +
"{{ treeData[0].name }} " +
"" +
- "" +
+ "" +
"\n" +
"\n";
var compiled = $compile(html)(scope);
diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js
index cc0c36faed..fb21106c18 100644
--- a/awx/ui/static/lib/ansible/form-generator.js
+++ b/awx/ui/static/lib/ansible/form-generator.js
@@ -63,7 +63,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
// From here use 'scope' to manipulate the form, as the form is not in '$scope'
$compile(element)(this.scope);
- if (!options.buildTree == false && !options.html) {
+ if (!options.buildTree && !options.html) {
// Reset the scope to prevent displaying old data from our last visit to this form
for (var fld in form.fields) {
this.scope[fld] = null;
@@ -72,6 +72,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
this.scope[set] = null;
}
if ( ((!options.modal) && options.related) || this.form.forceListeners ) {
+ console.log('adding listeners');
this.addListeners();
}
if (options.mode == 'add') {
@@ -1052,20 +1053,6 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
}
}
- html += "";
- html += " \n";
- html += "\n";
- html += "\n";
- html += " \n";
- html += " | \n";
-
html += "\n";
// Message for when a related collection is empty
diff --git a/awx/ui/static/lib/ansible/generator-helpers.js b/awx/ui/static/lib/ansible/generator-helpers.js
index 5cf6245c50..0228477751 100644
--- a/awx/ui/static/lib/ansible/generator-helpers.js
+++ b/awx/ui/static/lib/ansible/generator-helpers.js
@@ -91,7 +91,38 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
})
- .factory('Column', ['Attr', 'Icon', function(Attr, Icon) {
+
+ .factory('DropDown', ['Attr', 'Icon', function(Attr, Icon) {
+ return function(params) {
+
+ var list = params['list'];
+ var fld = params['fld'];
+ var options = params['options'];
+ var base = params['base'];
+ var field = list['fields'][fld];
+
+ html = "\n";
+ html += " \n";
+ html += "\n";
+ html += "\n";
+ html += " \n";
+ html += " | \n";
+
+ return html;
+
+ }
+ }])
+
+
+ .factory('Column', ['Attr', 'Icon', 'DropDown', function(Attr, Icon, DropDown) {
return function(params) {
var list = params['list'];
var fld = params['fld'];
@@ -101,93 +132,99 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
var field = list['fields'][fld];
var html = '';
- html += "\n";
-
- // Add ngShow
- html += (field.ngShow) ? "" : "";
-
- // Add collapse/expand icon --used on job_events page
- if (list['hasChildren'] && field.hasChildren) {
- html += " " +
- " ";
- }
-
- // Start the Link
- if ((field.key || field.link || field.linkTo || field.ngClick ) && options['mode'] != 'lookup' && options['mode'] != 'select') {
- if (field.linkTo) {
- html += "";
- }
- else if (field.ngClick) {
- html += "";
- }
- else if (field.link == undefined || field.link) {
- html += "";
- }
- }
-
- // Add icon:
- if (field.ngShowIcon) {
- html += " ";
+ if (field.type !== undefined && field.type == 'DropDown') {
+ html = DropDown(params);
}
else {
- if (field.icon) {
- html += Icon(field.icon) + " ";
- }
- }
+ html += " | \n";
- // Add data binds
- if (field.showValue == undefined || field.showValue == true) {
- if (field.ngBind) {
- html += "{{ " + field.ngBind + " }}";
- }
- else {
- html += "{{" + list.iterator + "." + fld + "}}";
- }
- }
-
- // Add additional text:
- if (field.text) {
- html += field.text;
- }
+ // Add ngShow
+ html += (field.ngShow) ? "" : "";
+
+ // Add collapse/expand icon --used on job_events page
+ if (list['hasChildren'] && field.hasChildren) {
+ html += " " +
+ " ";
+ }
- if (list['hasChildren'] && field.hasChildren) {
- html += "";
- }
-
- // close the link
- if ((field.key || field.link || field.linkTo || field.ngClick )
- && options.mode != 'lookup' && options.mode != 'select') {
- html += "";
- }
+ // Start the Link
+ if ((field.key || field.link || field.linkTo || field.ngClick ) && options['mode'] != 'lookup' && options['mode'] != 'select') {
+ if (field.linkTo) {
+ html += "";
+ }
+ else if (field.ngClick) {
+ html += "";
+ }
+ else if (field.link == undefined || field.link) {
+ html += "";
+ }
+ }
- // close ngShow
- html += (field.ngShow) ? "" : "";
-
- // Specific to Job Events page -showing event detail/results
- html += (field.appendHTML) ? "\n" : "";
-
- // Badge
- if (field.badgeIcon) {
- if (field.badgeToolTip) {
- html += "";
- html += " \n";
+ // Add icon:
+ if (field.ngShowIcon) {
+ html += " ";
}
else {
- html += " \n";
- }
+ if (field.icon) {
+ html += Icon(field.icon) + " ";
+ }
+ }
+
+ // Add data binds
+ if (field.showValue == undefined || field.showValue == true) {
+ if (field.ngBind) {
+ html += "{{ " + field.ngBind + " }}";
+ }
+ else {
+ html += "{{" + list.iterator + "." + fld + "}}";
+ }
+ }
+
+ // Add additional text:
+ if (field.text) {
+ html += field.text;
+ }
+
+ if (list['hasChildren'] && field.hasChildren) {
+ html += "";
+ }
+
+ // close the link
+ if ((field.key || field.link || field.linkTo || field.ngClick )
+ && options.mode != 'lookup' && options.mode != 'select') {
+ html += "";
+ }
+
+ // close ngShow
+ html += (field.ngShow) ? "" : "";
+
+ // Specific to Job Events page -showing event detail/results
+ html += (field.appendHTML) ? "\n" : "";
+
+ // Badge
+ if (field.badgeIcon) {
+ if (field.badgeToolTip) {
+ html += "";
+ html += " \n";
+ }
+ else {
+ html += " \n";
+ }
+ }
}
return html += " | \n";
@@ -195,6 +232,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
}])
+
.factory('SearchWidget', function() {
return function(params) {
//
diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js
index 52bac8dac6..7f3201abcf 100644
--- a/awx/ui/static/lib/ansible/list-generator.js
+++ b/awx/ui/static/lib/ansible/list-generator.js
@@ -142,6 +142,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
if (options.mode != 'lookup' && (list.well == undefined || list.well == 'true')) {
html += "\n";
}
+
if (options.mode == 'lookup' || options.id != undefined) {
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-8' });
@@ -164,6 +165,12 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
}
}
}
+
+ if (list.name == 'inventories' && options.mode !== 'select') {
+ html += "
\n";
+ }
+
//select instructions
if (options.mode == 'select' && list.selectInstructions) {
var btn = {
diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html
index 7d8972d4ae..67c179234e 100644
--- a/awx/ui/templates/ui/index.html
+++ b/awx/ui/templates/ui/index.html
@@ -104,26 +104,25 @@
-
+
-
-

-
-
-
-
+
@@ -219,7 +218,7 @@
@@ -238,7 +237,7 @@