AC-570 Added host enabled flag on Hosts page, allowing one-click editing for manually managed hosts. Fixed one more bug with prepending '*' to labels of required fileds.

This commit is contained in:
Chris Houseknecht 2013-11-06 08:09:02 +00:00
parent 1497d128f3
commit 49a8de4efe
7 changed files with 130 additions and 53 deletions

View File

@ -13,7 +13,7 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt,
GetBasePath, HostsList, HostsAdd, HostsEdit, HostsDelete,
HostsReload, BuildTree, EditHostGroups, InventoryHostsHelp, HelpDialog)
HostsReload, BuildTree, EditHostGroups, InventoryHostsHelp, HelpDialog, Wait)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -33,11 +33,11 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
// buildAllGroups emits from TreeSelector.js after the inventory object is ready
if (scope.loadBreadCrumbsRemove) {
scope.loadBreadCrumbsRemove();
scope.loadBreadCrumbsRemove();
}
scope.loadBreadCrumbsRemove = scope.$on('buildAllGroups', function(e, inventory_name) {
LoadBreadCrumbs({ path: '/inventories/' + id, title: inventory_name });
});
LoadBreadCrumbs({ path: '/inventories/' + id, title: inventory_name });
});
scope.filterHosts = function() {
HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
@ -75,6 +75,39 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
scope.allJobs = function(id) {
$location.url('/jobs/?job_host_summaries__host=' + id);
}
scope.toggle_host_enabled = function(id, sources) {
var host;
var i;
if (!sources) {
// Host is not managed by an external source
Wait('start');
for (i=0; i < scope.hosts.length; i++) {
if (scope.hosts[i].id == id) {
scope.hosts[i].enabled = (scope.hosts[i].enabled) ? false : true;
scope.hosts[i].enabled_flag = scope.hosts[i].enabled;
host = scope.hosts[i];
break;
}
}
Rest.setUrl(GetBasePath('hosts') + id + '/');
Rest.put(host)
.success( function(data, status, headers, config) {
Wait('stop');
})
.error( function(data, status, headers, config) {
scope.hosts[i].enabled = (scope.hosts[i].enabled) ? false : true;
scope.hosts[i].enabled_flag = scope.hosts[i].enabled;
Wait('stop');
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to update host. PUT returned status: ' + status });
});
}
else {
Alert('External Host', 'This host is part of an external inventory. It can only be enabled or disabled by the ' +
'inventory sync process.', 'alert-info');
}
}
scope.allHostSummaries = function(id, name, inventory_id) {
LoadBreadCrumbs({ path: '/hosts/' + id, title: name, altPath: '/inventories/' + inventory_id + '/hosts',
@ -118,15 +151,15 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
scope.group_id = group;
scope.helpCount++;
if (scope.group_id == null) {
scope.groupTitle = 'All Hosts';
scope.hostAddHide = true;
scope.hostCreateHide = true;
scope.hostDeleteHide = true;
scope.groupTitle = 'All Hosts';
scope.hostAddHide = true;
scope.hostCreateHide = true;
scope.hostDeleteHide = true;
}
else {
scope.hostAddHide = false;
scope.hostCreateHide = false;
scope.hostDeleteHide = false;
scope.hostAddHide = false;
scope.hostCreateHide = false;
scope.hostDeleteHide = false;
}
scope['hostDeleteDisabled'] = true;
scope['hostDeleteDisabledClass'] = 'disabled';
@ -135,11 +168,11 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
// Load the tree. See TreeSelector.js
BuildTree({
scope: scope,
inventory_id: id,
emit_on_select: 'refreshHost',
target_id: 'search-tree-container'
});
scope: scope,
inventory_id: id,
emit_on_select: 'refreshHost',
target_id: 'search-tree-container'
});
}
@ -147,6 +180,6 @@ InventoryHosts.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$lo
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt',
'GetBasePath', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete',
'HostsReload', 'BuildTree', 'EditHostGroups', 'InventoryHostsHelp', 'HelpDialog'
'HostsReload', 'BuildTree', 'EditHostGroups', 'InventoryHostsHelp', 'HelpDialog', 'Wait'
];

View File

@ -39,10 +39,22 @@ angular.module('HostFormDefinition', [])
addRequired: false,
editRequired: false
},
inventory: {
type: 'hidden',
includeOnEdit: true,
includeOnAdd: true
enabled: {
label: 'Enabled?',
type: 'radio',
addRequired: false,
editRequired: false,
options: [
{ label: 'Yes', value: 'true'},
{ label: 'No', value: 'false' }
],
"default": "true",
awPopOver: "<p>Indicates if a host is available and should be included in running jobs.</p><p>For hosts that " +
"are part of an external inventory, this flag cannot be changed. It will be set by the inventory sync process.</p>",
dataTitle: 'Host Enabled',
dataPlacement: 'right',
dataContainer: '#form-modal .modal-content',
ngDisabled: 'has_inventory_sources == true'
},
variables: {
label: 'Variables',
@ -62,6 +74,11 @@ angular.module('HostFormDefinition', [])
dataTitle: 'Host Variables',
dataPlacement: 'right',
dataContainer: '#form-modal .modal-content'
},
inventory: {
type: 'hidden',
includeOnEdit: true,
includeOnAdd: true
}
},

View File

@ -34,19 +34,16 @@ angular.module('InventoryHostsFormDefinition', [])
searchable: false,
nosort: true
},
/*inventory_sources: {
label: 'External<br>Source?',
ngHref: "\{\{ host.has_inv_source_link \}\}",
badgeNgHref: "\{\{ host.has_inv_source_link \}\}",
badgeIcon: "\{\{ 'icon-cloud-' + host.has_inventory_sources \}\}",
enabled_flag: {
label: 'Enabled',
badgeIcon: "\{\{ 'icon-enabled-' + host.enabled \}\}",
badgePlacement: 'left',
badgeToolTip: "\{\{ host.has_inv_source_tip \}\}",
awToolTip: "\{\{ host.has_inv_source_tip \}\}",
dataPlacement: 'top',
badgeTipPlacement: 'top',
badgeToolTip: "\{\{ host.enabledToolTip \}\}",
badgeTipPlacement: "top",
ngClick: "toggle_host_enabled(\{\{ host.id \}\}, \{\{ host.has_inventory_sources \}\})",
searchable: false,
nosort: true
},*/
showValue: false
},
groups: {
label: 'Groups',
searchable: true,
@ -54,6 +51,13 @@ angular.module('InventoryHostsFormDefinition', [])
sourceField: 'name',
nosort: true
},
enabled: {
label: 'Disabled?',
searchSingleValue: true,
searchType: 'boolean',
searchValue: 'false',
searchOnly: true
},
has_active_failures: {
label: 'Has failed jobs?',
searchSingleValue: true,
@ -108,7 +112,7 @@ angular.module('InventoryHostsFormDefinition', [])
type: 'DropDown',
label: 'Jobs',
icon: 'icon-zoom-in',
"class": "btn-default btn-sm",
"class": "btn-default btn-xs",
options: [
{ ngClick: "allJobs(\{\{ host.id \}\})", label: 'All', ngShow: 'host.last_job' },
{ ngClick: "allHostSummaries(\{\{ host.id \}\},'\{\{ host.name \}\}', \{\{ inventory_id \}\})", label: 'All summaries',
@ -125,7 +129,7 @@ angular.module('InventoryHostsFormDefinition', [])
"delete": {
ngClick: "deleteHost(\{\{ host.id \}\},'\{\{ host.name \}\}')",
icon: 'icon-trash',
"class": 'btn-sm btn-danger',
"class": 'btn-xs btn-danger',
awToolTip: 'Delete host'
}
}

View File

@ -155,6 +155,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
data['variables'] = JSON.stringify(json_data, undefined, '\t');
}
data['enabled'] = (scope['enabled'] == "true") ? true : false;
Rest.setUrl(defaultUrl);
Rest.post(data)
.success( function(data, status, headers, config) {
@ -261,6 +263,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
relatedSets[set] = { url: related[set], iterator: form.related[set].iterator };
}
}
scope['enabled'] = (data['enabled']) ? "true" : "false";
master['enabled'] = scope['enabled'];
scope.variable_url = data.related.variable_data;
scope.$emit('hostLoaded');
})
@ -309,6 +313,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
data['variables'] = JSON.stringify(json_data, undefined, '\t');
}
data['enabled'] = (scope['enabled'] == "true") ? true : false;
Rest.setUrl(defaultUrl);
Rest.put(data)
.success( function(data, status, headers, config) {
@ -430,22 +436,10 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
}
}
scope.hosts[i].groups = scope.hosts[i].groups.replace(/\, $/,'');
if (scope.hosts[i].has_inventory_sources) {
scope.hosts[i].inventory_sources = 'yes';
scope.hosts[i].has_inv_source_link = '/#/inventories/' + scope['inventory_id'] + '/groups/?has_external_source=true';
scope.hosts[i].has_inv_source_tip = 'Has an external source. Click to view inventory source details.';
}
else {
scope.hosts[i].inventory_sources = 'no';
scope.hosts[i].has_inv_source_link = '/#/inventories/' + scope['inventory_id'] + '/groups';
scope.hosts[i].has_inv_source_tip = 'Has no external source.';
}
}
// Add the value displayed in Job Status column
for (var i=0; i < scope.hosts.length; i++) {
// Add the value displayed in Job Status column
scope.hosts[i].activeFailuresLink = '/#/hosts/' + scope.hosts[i].id + '/job_host_summaries/?inventory=' + scope['inventory_id'] +
'&host_name=' + escape(scope.hosts[i].name);
if (scope.hosts[i].has_active_failures == true) {
@ -460,7 +454,19 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
else if (scope.hosts[i].has_active_failures == false && scope.hosts[i].last_job !== null) {
scope.hosts[i].badgeToolTip = "Most recent job successful. Click to view jobs.";
scope.hosts[i].active_failures = 'success';
}
}
scope.hosts[i].enabled_flag = scope.hosts[i].enabled;
if (scope.hosts[i].has_inventory_sources) {
// Inventory sync managed, so not clickable
scope.hosts[i].enabledToolTip = (scope.hosts[i].enabled) ? 'Ready! Availabe to running jobs.' :
'Out to lunch! This host is not available to running jobs.';
}
else {
// Clickable
scope.hosts[i].enabledToolTip = (scope.hosts[i].enabled) ? 'Ready! Available to running jobs. Click to toggle.' :
'Out to lunch! Host not available to running jobs. Click to toggle.';
}
}
if (group_id == null || group_id == undefined) {

View File

@ -814,6 +814,22 @@ input[type="checkbox"].checkbox-no-label {
color: @red;
}
.icon-enabled-true:before {
content: "\f046";
}
.icon-enabled-true {
color: @green;
}
.icon-enabled-false:before {
content: "\f096";
}
.icon-enabled-false{
color: @red;
}
/* Inventory cloud sourced? indicator */
.icon-cloud-true:before {
content: "\f111";

View File

@ -104,16 +104,16 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
// Prepend an asterisk to required field label
$('.form-control[required], input[type="radio"][required]').each(function() {
if ( Empty($(this).attr('aw-required-when')) ) {
var label = $(this).parent().parent().find('label');
var label = $(this).parent().parent().find('label').first();
if ($(this).attr('type') == 'radio') {
label = $(this).parent().parent().parent().find('label');
label = $(this).parent().parent().parent().find('label').first();
}
if (label.length > 0) {
var span = label.children('span');
if (span.length > 0 && !span.first().hasClass('prepend-asterisk')) {
span.first().addClass('prepend-asterisk');
}
else if (!label.first().hasClass('prepend-asterisk')) {
else if (span.length <= 0 && !label.first().hasClass('prepend-asterisk')) {
label.first().addClass('prepend-asterisk');
}
}
@ -817,6 +817,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
html += (field.readonly) ? "disabled " : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.ngDisabled) ? this.attr(field,'ngDisabled') : "";
html += " > " + field.options[i].label + "\n";
html += "</label>\n";
}

View File

@ -373,7 +373,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
if (options.mode == 'select' && (options.selectButton == undefined || options.selectButton == true)) {
html += "<div class=\"navigation-buttons\">\n";
html += " <button class=\"btn btn-small btn-primary pull-right\" aw-tool-tip=\"Complete your selection\" " +
html += " <button class=\"btn btn-sm btn-primary pull-right\" aw-tool-tip=\"Complete your selection\" " +
"ng-click=\"finishSelection()\" ng-disabled=\"selected.length == 0\"><i class=\"icon-check\"></i> Select</button>\n";
html += "</div>\n";
}