diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js
index f227c26925..7eaab2a2f6 100644
--- a/awx/ui/static/js/controllers/Inventories.js
+++ b/awx/ui/static/js/controllers/Inventories.js
@@ -184,7 +184,8 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt,
OrganizationList, TreeInit, GetBasePath, GroupsList, GroupsAdd, GroupsEdit, LoadInventory,
- GroupsDelete, HostsList, HostsAdd, HostsEdit, HostsDelete, RefreshGroupName, ParseTypeChange)
+ GroupsDelete, HostsList, HostsAdd, HostsEdit, HostsDelete, RefreshGroupName, ParseTypeChange,
+ HostsReload)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@@ -247,6 +248,10 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
RefreshTree({ scope: scope });
}
+ scope.filterHosts = function() {
+ HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
+ }
+
function PostSave() {
// Make sure the inventory name in the tree is correct
RefreshGroupName($('#inventory-node'), scope['inventory_name'], scope['inventory_description']);
@@ -450,13 +455,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope.groupTitle = '
All Hosts
';
scope.group_id = null;
}
- scope.relatedSets['hosts'] = { url: url, iterator: 'host' };
- RelatedSearchInit({ scope: scope, form: form, relatedSets: scope.relatedSets });
- RelatedPaginateInit({ scope: scope, relatedSets: scope.relatedSets });
- scope.search('host');
- if (!scope.$$phase) {
- scope.$digest();
- }
+ HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
});
scope.addGroup = function() {
@@ -513,6 +512,6 @@ InventoriesEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$l
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt',
'OrganizationList', 'TreeInit', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory',
'GroupsDelete', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete', 'RefreshGroupName',
- 'ParseTypeChange'
+ 'ParseTypeChange', 'HostsReload'
];
diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js
index f05af922a2..31ad6b04f4 100644
--- a/awx/ui/static/js/helpers/Hosts.js
+++ b/awx/ui/static/js/helpers/Hosts.js
@@ -406,6 +406,20 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
var relatedSets = { hosts: { url: url, iterator: 'host' } };
RelatedSearchInit({ scope: params.scope, form: InventoryForm, relatedSets: relatedSets });
RelatedPaginateInit({ scope: params.scope, relatedSets: relatedSets });
+
+ if (scope['hostFailureFilter']) {
+ // If the user checked 'show only hosts with failures', filter for hosts with failed jobs
+ scope['hostSearchFieldLabel'] = 'Failed jobs?';
+ scope['hostSearchField'] = 'has_active_failures';
+ scope['hostSelectShow'] = true;
+ scope.setSearchField('host','has_active_failures','Failed jobs?');
+ for (var i=0; i < scope['hostSearchSelectOpts'].length; i++) {
+ if (scope['hostSearchSelectOpts'][i].value == 1) {
+ scope['hostSearchSelectValue'] = scope['hostSearchSelectOpts'][i];
+ }
+ }
+ }
+
params.scope.search('host');
if (!params.scope.$$phase) {
params.scope.$digest();
diff --git a/awx/ui/static/js/helpers/related-search.js b/awx/ui/static/js/helpers/related-search.js
index 3e2744ffbf..b17322caaf 100644
--- a/awx/ui/static/js/helpers/related-search.js
+++ b/awx/ui/static/js/helpers/related-search.js
@@ -70,7 +70,7 @@ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelat
scope[iterator + 'SelectShow'] = false;
scope[iterator + 'HideSearchType'] = false;
scope[iterator + 'InputHide'] = false;
-
+
if (f.searchType !== undefined && f.searchType == 'gtzero') {
scope[iterator + "InputHide"] = true;
}
@@ -83,6 +83,15 @@ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelat
scope[iterator + 'HideSearchType'] = true;
}
+ if (iterator == 'host') {
+ if (fld == 'has_active_failures') {
+ scope['hostFailureFilter'] = true;
+ }
+ else {
+ scope['hostFailureFilter'] = false;
+ }
+ }
+
scope.search(iterator);
}
@@ -96,7 +105,18 @@ angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelat
scope.search = function(iterator) {
scope[iterator + 'SearchSpin'] = true;
scope[iterator + 'Loading'] = true;
-
+
+ if (iterator == 'host') {
+ if (scope['hostSearchField'] == 'has_active_failures') {
+ if (scope['hostSearchSelectValue'] && scope['hostSearchSelectValue'].value == 1) {
+ scope['hostFailureFilter'] = true;
+ }
+ else {
+ scope['hostFailureFilter'] = false;
+ }
+ }
+ }
+
var set, url, iterator, sort_order;
for (var key in relatedSets) {
if (relatedSets[key].iterator == iterator) {
diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js
index 0462b14eb4..632468ae05 100644
--- a/awx/ui/static/lib/ansible/form-generator.js
+++ b/awx/ui/static/lib/ansible/form-generator.js
@@ -965,6 +965,15 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
// End List
html += "\n";
html += "\n";
+
+ // Failure filter checkbox
+ html += "\n";
+ html += "";
+ html += "\n"
+ html += "
\n";
+
html += "\n"; // close well
html += "\n"; // close group-view