Group add and edit now mostly work. The Add Group dialog now includes tabs and supports source. The tree is refrshed on load. Moved retrieval of update status info to InventoryTree.

This commit is contained in:
Chris Houseknecht
2013-12-30 09:45:30 +00:00
parent b25c96b0dd
commit f26956d2cc
8 changed files with 399 additions and 214 deletions

View File

@@ -327,21 +327,15 @@ function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearSc
$scope.inventory_id = $routeParams.inventory_id; $scope.inventory_id = $routeParams.inventory_id;
$scope.$on('searchTreeReady', function(e, inventory_name, groups) { if ($scope.removeSearchTreeReady) {
$scope.removeSearchTreeReady();
}
$scope.removeSearchTreeReady = $scope.$on('searchTreeReady', function(e, inventory_name, groups) {
// After the tree data loads, generate the groups list // After the tree data loads, generate the groups list
generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5' }); generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5' });
$scope.groups = groups; $scope.groups = groups;
$scope.inventory_name = inventory_name; $scope.inventory_name = inventory_name;
for (var i=0; i < $scope.groups.length; i++) {
var stat = UpdateStatusMsg({ status: $scope.groups[i].status });
$scope.groups[i].status_badge_class = stat['class'];
$scope.groups[i].status_badge_tooltip = stat['tooltip'];
$scope.groups[i].status = stat['status'];
}
InjectHosts({ scope: $scope, inventory_id: $scope.inventory_id }); InjectHosts({ scope: $scope, inventory_id: $scope.inventory_id });
Wait('stop'); Wait('stop');
}); });

View File

@@ -47,7 +47,7 @@ angular.module('GroupFormDefinition', [])
rows: 10, rows: 10,
'default': '---', 'default': '---',
dataTitle: 'Group Variables', dataTitle: 'Group Variables',
dataPlacement: 'left', dataPlacement: 'right',
awPopOver: "<p>Variables defined here apply to all child groups and hosts.</p>" + awPopOver: "<p>Variables defined here apply to all child groups and hosts.</p>" +
"<p>Enter variables using either JSON or YAML syntax. Use the " + "<p>Enter variables using either JSON or YAML syntax. Use the " +
"radio button to toggle between the two.</p>" + "radio button to toggle between the two.</p>" +
@@ -96,7 +96,7 @@ angular.module('GroupFormDefinition', [])
editRequired: false, editRequired: false,
awMultiselect: 'source_region_choices', awMultiselect: 'source_region_choices',
dataTitle: 'Source Regions', dataTitle: 'Source Regions',
dataPlacement: 'left', dataPlacement: 'right',
awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " + awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " +
"or choose <em>All</em> to include all regions. AWX will only be updated with Hosts associated with the selected regions." + "or choose <em>All</em> to include all regions. AWX will only be updated with Hosts associated with the selected regions." +
"</p>", "</p>",
@@ -113,7 +113,7 @@ angular.module('GroupFormDefinition', [])
'default': '---', 'default': '---',
parseTypeName: 'envParseType', parseTypeName: 'envParseType',
dataTitle: 'Source Variables', dataTitle: 'Source Variables',
dataPlacement: 'left', dataPlacement: 'right',
awPopOver: "<p>Override variables found in ec2.ini and used by the inventory update script. For a detailed description of these variables " + awPopOver: "<p>Override variables found in ec2.ini and used by the inventory update script. For a detailed description of these variables " +
"<a href=\"https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.ini\" target=\"_blank\">" + "<a href=\"https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.ini\" target=\"_blank\">" +
"view ec2.ini in the Ansible github repo.</a></p>" + "view ec2.ini in the Ansible github repo.</a></p>" +
@@ -161,7 +161,7 @@ angular.module('GroupFormDefinition', [])
'remain untouched by the inventory update process.</p>', 'remain untouched by the inventory update process.</p>',
dataTitle: 'Overwrite', dataTitle: 'Overwrite',
dataContainer: 'body', dataContainer: 'body',
dataPlacement: 'left', dataPlacement: 'right',
labelClass: 'checkbox-options' labelClass: 'checkbox-options'
}, },
{ {
@@ -176,7 +176,7 @@ angular.module('GroupFormDefinition', [])
'those found on the external source.</p>', 'those found on the external source.</p>',
dataTitle: 'Overwrite Variables', dataTitle: 'Overwrite Variables',
dataContainer: 'body', dataContainer: 'body',
dataPlacement: 'left', dataPlacement: 'right',
labelClass: 'checkbox-options' labelClass: 'checkbox-options'
}, },
{ {
@@ -190,7 +190,7 @@ angular.module('GroupFormDefinition', [])
'executing job tasks.</p>', 'executing job tasks.</p>',
dataTitle: 'Update on Launch', dataTitle: 'Update on Launch',
dataContainer: 'body', dataContainer: 'body',
dataPlacement: 'left', dataPlacement: 'right',
labelClass: 'checkbox-options' labelClass: 'checkbox-options'
} }
] ]

View File

@@ -12,7 +12,8 @@
angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition',
'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper',
'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper', 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper',
'PromptDialog', 'InventorySummaryHelpDefinition', 'CredentialsListDefinition' 'PromptDialog', 'InventorySummaryHelpDefinition', 'CredentialsListDefinition',
'InventoryTree'
]) ])
.factory('GetSourceTypeOptions', [ 'Rest', 'ProcessErrors', 'GetBasePath', function(Rest, ProcessErrors, GetBasePath) { .factory('GetSourceTypeOptions', [ 'Rest', 'ProcessErrors', 'GetBasePath', function(Rest, ProcessErrors, GetBasePath) {
@@ -586,13 +587,16 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
}]) }])
.factory('GroupsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', .factory('GroupsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'GroupsEdit', 'ClickNode', 'Wait', 'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'GroupsEdit', 'ClickNode', 'Wait', 'GetChoices',
'GetSourceTypeOptions', 'CredentialList', 'LookUpInit', 'BuildTree',
function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
GetBasePath, ParseTypeChange, GroupsEdit, ClickNode, Wait) { GetBasePath, ParseTypeChange, GroupsEdit, ClickNode, Wait, GetChoices, GetSourceTypeOptions, CredentialList,
LookUpInit, BuildTree) {
return function(params) { return function(params) {
var inventory_id = params.inventory_id; var inventory_id = params.inventory_id;
var group_id = (params.group_id !== undefined) ? params.group_id : null; var group_id = (params.group_id !== undefined) ? params.group_id : null;
var inventory_scope = params.scope;
// Inject dynamic view // Inject dynamic view
var defaultUrl = (group_id !== null) ? GetBasePath('groups') + group_id + '/children/' : var defaultUrl = (group_id !== null) ? GetBasePath('groups') + group_id + '/children/' :
@@ -610,84 +614,192 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
$('#form-modal').on('hidden.bs.modal', function () { $('#form-modal').on('hidden.bs.modal', function () {
if (!groupCreated) { //if (!groupCreated) {
ClickNode({ selector: '#' + scope['selectedNode'].attr('id') }); // ClickNode({ selector: '#' + scope['selectedNode'].attr('id') });
} //}
}); });
generator.reset(); generator.reset();
var master={}; var master={};
if (!scope.$$phase) { if (scope.removeSearchTreeReady) {
scope.$digest(); scope.removeSearchTreeReady();
} }
scope.removeSearchTreeReady = scope.$on('searchTreeReady', function(e) {
Wait('stop');
$('#form-modal').modal('hide');
});
if (scope.removeSaveComplete) {
scope.removeSaveComplete();
}
scope.removeSaveComplete = scope.$on('SaveComplete', function(e, error) {
if (!error) {
scope.formModalActionDisabled = false;
scope.showGroupHelp = false; //get rid of the Hint
BuildTree({ scope: inventory_scope, inventory_id: inventory_id });
}
});
if (scope.removeFormSaveSuccess) {
scope.removeFormSaveSuccess();
}
scope.removeFormSaveSuccess = scope.$on('formSaveSuccess', function(e, group_id, url) {
// Source data gets stored separately from the group. Validate and store Source
// related fields, then call SaveComplete to wrap things up.
var parseError = false;
var saveError = false;
// Update the selector tree with new group name, descr
//SetNodeName({ scope: scope['selectedNode'], group_id: group_id,
// name: scope.name, description: scope.description });
if (scope.source.value !== null && scope.source.value !== '') {
var data = {
group: group_id,
source: scope['source'].value,
source_path: scope['source_path'],
credential: scope['credential'],
overwrite: scope['overwrite'],
overwrite_vars: scope['overwrite_vars'],
update_on_launch: scope['update_on_launch']
//update_interval: scope['update_interval'].value
};
// Create a string out of selected list of regions
var regions = $('#s2id_group_source_regions').select2("data");
var r = [];
for (var i=0; i < regions.length; i++) {
r.push(regions[i].id);
}
data['source_regions'] = r.join();
if (scope['source'].value == 'ec2') {
// for ec2, validate variable data
try {
if (scope.envParseType == 'json') {
var json_data = JSON.parse(scope.source_vars); //make sure JSON parses
}
else {
var json_data = jsyaml.load(scope.source_vars); //parse yaml
}
// Make sure our JSON is actually an object
if (typeof json_data !== 'object') {
throw "failed to return an object!";
}
// Send JSON as a string
if ($.isEmptyObject(json_data)) {
data.source_vars = "";
}
else {
data.source_vars = JSON.stringify(json_data, undefined, '\t');
}
}
catch(err) {
parseError = true;
scope.$emit('SaveComplete', true);
Alert("Error", "Error parsing extra variables. Parser returned: " + err);
}
}
if (!parseError) {
Rest.setUrl(url)
Rest.put(data)
.success( function(data, status, headers, config) {
scope.$emit('SaveComplete', false);
})
.error( function(data, status, headers, config) {
scope.$emit('SaveComplete', true);
ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to update group inventory source. PUT status: ' + status });
});
}
}
else {
// No source value
scope.$emit('SaveComplete', false);
}
});
// Save // Save
scope.formModalAction = function() { scope.formModalAction = function() {
Wait('start'); Wait('start');
try { try {
scope.formModalActionDisabled = true; scope.formModalActionDisabled = true;
// Make sure we have valid variable data // Make sure we have valid variable data
if (scope.parseType == 'json') { if (scope.parseType == 'json') {
var json_data = JSON.parse(scope.variables); //make sure JSON parses var json_data = JSON.parse(scope.variables); //make sure JSON parses
} }
else { else {
var json_data = jsyaml.load(scope.variables); //parse yaml var json_data = jsyaml.load(scope.variables); //parse yaml
} }
// Make sure our JSON is actually an object // Make sure our JSON is actually an object
if (typeof json_data !== 'object') { if (typeof json_data !== 'object') {
throw "failed to return an object!"; throw "failed to return an object!";
} }
var data = { var data = {
name: scope['name'], name: scope['name'],
description: scope['description'] description: scope['description']
}; };
if (inventory_id) { if (inventory_id) {
data['inventory'] = inventory_id; data['inventory'] = inventory_id;
} }
if ($.isEmptyObject(json_data)) { if ($.isEmptyObject(json_data)) {
data['variables'] = ""; data['variables'] = "";
} }
else { else {
data['variables'] = JSON.stringify(json_data, undefined, '\t'); data['variables'] = JSON.stringify(json_data, undefined, '\t');
} }
Rest.setUrl(defaultUrl); Rest.setUrl(defaultUrl);
Rest.post(data) Rest.post(data)
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
Wait('stop'); scope.$emit('formSaveSuccess', data.id, GetBasePath('inventory_sources') + data.id + '/');
groupCreated = true; })
scope.formModalActionDisabled = false; .error( function(data, status, headers, config) {
scope.showGroupHelp = false; //get rid of the Hint Wait('stop');
$('#form-modal').modal('hide'); scope.formModalActionDisabled = false;
/*BuildTree({ ProcessErrors(scope, data, status, form,
scope: scope, { hdr: 'Error!', msg: 'Failed to add new group. POST returned status: ' + status });
inventory_id: scope['inventory_id'], });
emit_on_select: 'NodeSelect', }
target_id: 'search-tree-container', catch(err) {
refresh: true, Wait('stop');
moveable: true, scope.formModalActionDisabled = false;
group_id: data.id Alert("Error", "Error parsing group variables. Parser returned: " + err);
});*/ }
}) }
.error( function(data, status, headers, config) {
Wait('stop'); scope.sourceChange = function() {
scope.formModalActionDisabled = false; if (scope['source'].value == 'rax') {
ProcessErrors(scope, data, status, form, scope['source_region_choices'] = scope['rax_regions'];
{ hdr: 'Error!', msg: 'Failed to add new group. POST returned status: ' + status }); //$('#s2id_group_source_regions').select2('data', []);
}); $('#s2id_group_source_regions').select2('data', [{ id: 'all', text: 'All' }]);
} }
catch(err) { else if (scope['source'].value == 'ec2') {
Wait('stop'); scope['source_region_choices'] = scope['ec2_regions'];
scope.formModalActionDisabled = false; //$('#s2id_group_source_regions').select2('data', []);
Alert("Error", "Error parsing group variables. Parser returned: " + err); $('#s2id_group_source_regions').select2('data', [{ id: 'all', text: 'All' }]);
} }
} LookUpInit({
url: GetBasePath('credentials') +
'?cloud=true&kind=' + [ (scope.source.value == 'rax') ? 'rax' : 'aws' ],
scope: scope,
form: form,
list: CredentialList,
field: 'credential'
});
}
// Cancel // Cancel
scope.formReset = function() { scope.formReset = function() {
@@ -695,15 +807,50 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
generator.reset(); generator.reset();
}; };
var choicesReady = 0;
if (scope.removeChoicesReady) {
scope.removeChoicesReady();
}
scope.removeChoicesReady = scope.$on('choicesReadyGroup', function() {
choicesReady++;
if (choicesReady == 2) {
Wait('stop');
}
});
// Load options for source regions
GetChoices({
scope: scope,
url: GetBasePath('inventory_sources'),
field: 'source_regions',
variable: 'rax_regions',
choice_name: 'rax_region_choices',
callback: 'choicesReadyGroup'
});
GetChoices({
scope: scope,
url: GetBasePath('inventory_sources'),
field: 'source_regions',
variable: 'ec2_regions',
choice_name: 'ec2_region_choices',
callback: 'choicesReadyGroup'
});
GetSourceTypeOptions({ scope: scope, variable: 'source_type_options' });
Wait('start');
} }
}]) }])
.factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', .factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate', 'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate',
'GetUpdateIntervalOptions', 'ClickNode', 'LookUpInit', 'CredentialList', 'Empty', 'Wait', 'GetChoices', 'GetUpdateIntervalOptions', 'ClickNode', 'LookUpInit', 'CredentialList', 'Empty', 'Wait', 'GetChoices', 'UpdateGroup',
function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, GetUpdateIntervalOptions, ClickNode, GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, GetUpdateIntervalOptions, ClickNode,
LookUpInit, CredentialList, Empty, Wait, GetChoices) { LookUpInit, CredentialList, Empty, Wait, GetChoices, UpdateGroup) {
return function(params) { return function(params) {
var group_id = params.group_id; var group_id = params.group_id;
@@ -711,7 +858,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
var generator = GenerateForm; var generator = GenerateForm;
var form = GroupForm; var form = GroupForm;
var defaultUrl = GetBasePath('groups') + group_id + '/'; var defaultUrl = GetBasePath('groups') + group_id + '/';
var groups_scope = params.scope;
//var scope =
var scope = generator.inject(form, { mode: 'edit', modal: true, related: false }); var scope = generator.inject(form, { mode: 'edit', modal: true, related: false });
generator.reset(); generator.reset();
@@ -741,136 +890,138 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
} }
if (scope.variable_url) { if (scope.variable_url) {
// get group variables // get group variables
Rest.setUrl(scope.variable_url); Rest.setUrl(scope.variable_url);
Rest.get() Rest.get()
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
if ($.isEmptyObject(data)) { if ($.isEmptyObject(data)) {
scope.variables = "---"; scope.variables = "---";
} }
else { else {
scope.variables = jsyaml.safeDump(data); scope.variables = jsyaml.safeDump(data);
} }
Wait('stop');
}) })
.error( function(data, status, headers, config) { .error( function(data, status, headers, config) {
scope.variables = null; scope.variables = null;
Wait('stop');
ProcessErrors(scope, data, status, form, ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to retrieve group variables. GET returned status: ' + status }); { hdr: 'Error!', msg: 'Failed to retrieve group variables. GET returned status: ' + status });
}); });
} }
else { else {
scope.variables = "---"; scope.variables = "---";
} }
master.variables = scope.variables; master.variables = scope.variables;
if (scope.source_url) { if (scope.source_url) {
// get source data // get source data
Rest.setUrl(scope.source_url); Rest.setUrl(scope.source_url);
Rest.get() Rest.get()
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
for (var fld in form.fields) { for (var fld in form.fields) {
if (fld == 'checkbox_group') { if (fld == 'checkbox_group') {
for (var i = 0; i < form.fields[fld].fields.length; i++) { for (var i = 0; i < form.fields[fld].fields.length; i++) {
var flag = form.fields[fld].fields[i]; var flag = form.fields[fld].fields[i];
if (data[flag.name] !== undefined) { if (data[flag.name] !== undefined) {
scope[flag.name] = data[flag.name]; scope[flag.name] = data[flag.name];
master[flag.name] = scope[flag.name]; master[flag.name] = scope[flag.name];
} }
} }
} }
if (fld == 'source') { if (fld == 'source') {
var found = false; var found = false;
for (var i=0; i < scope.source_type_options.length; i++) { for (var i=0; i < scope.source_type_options.length; i++) {
if (scope.source_type_options[i].value == data['source']) { if (scope.source_type_options[i].value == data['source']) {
scope['source'] = scope.source_type_options[i]; scope['source'] = scope.source_type_options[i];
found = true; found = true;
} }
} }
if (!found || scope['source'].value == "") { if (!found || scope['source'].value == "") {
scope['groupUpdateHide'] = true; scope['groupUpdateHide'] = true;
} }
else { else {
scope['groupUpdateHide'] = false; scope['groupUpdateHide'] = false;
} }
master['source'] = scope['source']; master['source'] = scope['source'];
} }
else if (fld == 'update_interval') { else if (fld == 'update_interval') {
if (data[fld] == '' || data[fld] == null || data[fld] == undefined) { if (data[fld] == '' || data[fld] == null || data[fld] == undefined) {
data[fld] = 0; data[fld] = 0;
} }
for (var i=0; i < scope.update_interval_options.length; i++) { for (var i=0; i < scope.update_interval_options.length; i++) {
if (scope.update_interval_options[i].value == if (scope.update_interval_options[i].value ==
data[fld]) { data[fld]) {
scope[fld] = scope.update_interval_options[i]; scope[fld] = scope.update_interval_options[i];
} }
} }
} }
else if (fld == 'source_vars') { else if (fld == 'source_vars') {
// Parse source_vars, converting to YAML. // Parse source_vars, converting to YAML.
if ($.isEmptyObject(data.source_vars) || data.source_vars == "\{\}" || if ($.isEmptyObject(data.source_vars) || data.source_vars == "\{\}" ||
data.source_vars == "null" || data.source_vars == "") { data.source_vars == "null" || data.source_vars == "") {
scope.source_vars = "---"; scope.source_vars = "---";
} }
else { else {
var json_obj = JSON.parse(data.extra_vars); var json_obj = JSON.parse(data.extra_vars);
scope.source_vars = jsyaml.safeDump(json_obj); scope.source_vars = jsyaml.safeDump(json_obj);
} }
master.source_vars = scope.variables; master.source_vars = scope.variables;
} }
else if (data[fld]) { else if (data[fld]) {
scope[fld] = data[fld]; scope[fld] = data[fld];
master[fld] = scope[fld]; master[fld] = scope[fld];
} }
if (form.fields[fld].sourceModel && data.summary_fields && if (form.fields[fld].sourceModel && data.summary_fields &&
data.summary_fields[form.fields[fld].sourceModel]) { data.summary_fields[form.fields[fld].sourceModel]) {
scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
} }
} }
LookUpInit({ LookUpInit({
url: GetBasePath('credentials') + url: GetBasePath('credentials') +
'?cloud=true&kind=' + [(scope.source.value == 'rax') ? 'rax' : 'aws'], '?cloud=true&kind=' + (scope.source.value == 'rax') ? 'rax' : 'aws',
scope: scope, scope: scope,
form: form, form: form,
list: CredentialList, list: CredentialList,
field: 'credential' field: 'credential'
}); });
scope.sourceChange(); //set defaults that rely on source value scope.sourceChange(); //set defaults that rely on source value
if (data['source_regions']) { if (data['source_regions']) {
if (data['source'] == 'ec2' || data['source'] == 'rax') { if (data['source'] == 'ec2' || data['source'] == 'rax') {
var set = (data['source'] == 'ec2') ? scope['ec2_regions'] : scope['rax_regions']; var set = (data['source'] == 'ec2') ? scope['ec2_regions'] : scope['rax_regions'];
var opts = []; var opts = [];
var list = data['source_regions'].split(','); var list = data['source_regions'].split(',');
for (var i=0; i < list.length; i++) { for (var i=0; i < list.length; i++) {
for (var j=0; j < set.length; j++) { for (var j=0; j < set.length; j++) {
if (list[i] == set[j].value) { if (list[i] == set[j].value) {
opts.push({ id: set[j].value, text: set[j].label }); opts.push({ id: set[j].value, text: set[j].label });
} }
} }
} }
master['source_regions'] = opts; master['source_regions'] = opts;
$('#s2id_group_source_regions').select2('data', opts); $('#s2id_group_source_regions').select2('data', opts);
} }
} }
else { else {
// If empty, default to all // If empty, default to all
master['source_regions'] = [{ id: 'all', text: 'All' }]; master['source_regions'] = [{ id: 'all', text: 'All' }];
} }
scope['group_update_url'] = data.related['update'];
scope['group_update_url'] = data.related['update']; Wait('stop');
})
}) .error( function(data, status, headers, config) {
.error( function(data, status, headers, config) { scope.source = "";
scope.source = ""; Wait('stop');
ProcessErrors(scope, data, status, form, ProcessErrors(scope, data, status, form,
{ hdr: 'Error!', msg: 'Failed to retrieve inventory source. GET status: ' + status }); { hdr: 'Error!', msg: 'Failed to retrieve inventory source. GET status: ' + status });
}); });
} }
}); });
@@ -885,14 +1036,14 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
for (var fld in form.fields) { for (var fld in form.fields) {
if (data[fld]) { if (data[fld]) {
scope[fld] = data[fld]; scope[fld] = data[fld];
master[fld] = scope[fld]; master[fld] = scope[fld];
} }
} }
var related = data.related; var related = data.related;
for (var set in form.related) { for (var set in form.related) {
if (related[set]) { if (related[set]) {
relatedSets[set] = { url: related[set], iterator: form.related[set].iterator }; relatedSets[set] = { url: related[set], iterator: form.related[set].iterator };
} }
} }
scope.variable_url = data.related.variable_data; scope.variable_url = data.related.variable_data;
@@ -936,19 +1087,29 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
callback: 'choicesReadyGroup' callback: 'choicesReadyGroup'
}); });
if (!scope.$$phase) { Wait('start');
scope.$digest();
} //if (!scope.$$phase) {
// scope.$digest();
//}
if (scope.removeSaveComplete) { if (scope.removeSaveComplete) {
scope.removeSaveComplete(); scope.removeSaveComplete();
} }
scope.removeSaveComplete = scope.$on('SaveComplete', function(e, error) { scope.removeSaveComplete = scope.$on('SaveComplete', function(e, error) {
if (!error) { if (!error) {
//scope['flashMessage'] = 'Your changes to ' + scope['name'] + ' were saved.'; UpdateGroup({
//ClickNode({ selector: '#inventory-root-node' }); scope: groups_scope,
group_id: group_id,
properties: {
name: scope.name,
description: scope.description,
has_inventory_sources: (scope.source) ? true : false
}
});
scope.formModalActionDisabled = false; scope.formModalActionDisabled = false;
scope.showGroupHelp = false; //get rid of the Hint scope.showGroupHelp = false; //get rid of the Hint
Wait('stop');
$('#form-modal').modal('hide'); $('#form-modal').modal('hide');
} }
}); });
@@ -981,7 +1142,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
// Create a string out of selected list of regions // Create a string out of selected list of regions
var regions = $('#s2id_group_source_regions').select2("data"); var regions = $('#s2id_group_source_regions').select2("data");
data['source_regions'] = regions.join(); var r = [];
for (var i=0; i < regions.length; i++) {
r.push(regions[i].id);
}
data['source_regions'] = r.join();
if (scope['source'].value == 'ec2') { if (scope['source'].value == 'ec2') {
// for ec2, validate variable data // for ec2, validate variable data
@@ -1055,12 +1220,12 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
for (var fld in form.fields) { for (var fld in form.fields) {
data[fld] = scope[fld]; data[fld] = scope[fld];
} }
data['inventory'] = inventory_id; data['inventory'] = inventory_id;
Rest.setUrl(defaultUrl); Rest.setUrl(defaultUrl);
Rest.put(data) Rest.put(data)
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
Wait('stop');
if (scope.variables) { if (scope.variables) {
//update group variables //update group variables
Rest.setUrl(scope.variable_url); Rest.setUrl(scope.variable_url);
@@ -1106,7 +1271,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
} }
LookUpInit({ LookUpInit({
url: GetBasePath('credentials') + url: GetBasePath('credentials') +
'?cloud=true&kind=' + [(scope.source.value == 'rax') ? 'rax' : 'aws'], '?cloud=true&kind=' + (scope.source.value == 'rax') ? 'rax' : 'aws',
scope: scope, scope: scope,
form: form, form: form,
list: CredentialList, list: CredentialList,

View File

@@ -882,7 +882,7 @@ input[type="checkbox"].checkbox-no-label {
} }
.field-badge { .field-badge {
font-size: 14px; font-size: 12px;
} }
.license-warning, .license-warning,

View File

@@ -9,7 +9,7 @@
* *
*/ */
angular.module('InventoryTree', ['Utilities', 'RestServices']) angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper'])
.factory('SortNodes', [ function() { .factory('SortNodes', [ function() {
return function(data) { return function(data) {
@@ -171,8 +171,8 @@ angular.module('InventoryTree', ['Utilities', 'RestServices'])
} }
}]) }])
.factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', .factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'UpdateStatusMsg',
function(Rest, GetBasePath, ProcessErrors, SortNodes, Wait) { function(Rest, GetBasePath, ProcessErrors, SortNodes, Wait, UpdateStatusMsg) {
return function(params) { return function(params) {
var inventory_id = params.inventory_id; var inventory_id = params.inventory_id;
@@ -185,6 +185,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices'])
var sorted = SortNodes(tree_data); var sorted = SortNodes(tree_data);
for (var i=0; i < sorted.length; i++) { for (var i=0; i < sorted.length; i++) {
var currentId= id; var currentId= id;
var stat = UpdateStatusMsg({ status: sorted[i].status });
var group = { var group = {
name: sorted[i].name, name: sorted[i].name,
has_active_failures: sorted[i].has_active_failures, has_active_failures: sorted[i].has_active_failures,
@@ -194,12 +195,15 @@ angular.module('InventoryTree', ['Utilities', 'RestServices'])
groups_with_active_failures: sorted[i].groups_with_active_failures, groups_with_active_failures: sorted[i].groups_with_active_failures,
parent: parent, parent: parent,
has_children: (sorted[i].children.length > 0) ? true : false, has_children: (sorted[i].children.length > 0) ? true : false,
has_inventory_sources: sorted[i].has_inventory_sources,
id: id, id: id,
group_id: sorted[i].id, group_id: sorted[i].id,
event_level: level, event_level: level,
ngicon: (sorted[i].children.length > 0) ? 'icon-collapse-alt' : null, ngicon: (sorted[i].children.length > 0) ? 'icon-collapse-alt' : null,
related: { children: (sorted[i].children.length > 0) ? sorted[i].related.children : '' }, related: { children: (sorted[i].children.length > 0) ? sorted[i].related.children : '' },
status: sorted[i].summary_fields.inventory_source.status status: sorted[i].summary_fields.inventory_source.status,
status_badge_class: stat['class'],
status_badge_tooltip: stat['tooltip']
} }
groups.push(group); groups.push(group);
id++; id++;
@@ -244,10 +248,29 @@ angular.module('InventoryTree', ['Utilities', 'RestServices'])
} }
loadTreeData(); loadTreeData();
} }
}]) }])
// Update a group with a set of properties
.factory('UpdateGroup', [ function() {
return function(params) {
var scope = params.scope;
var group_id = params.group_id;
var properties = params.properties; // object of key:value pairs to update
for (var i=0; i < scope.groups.length; i++) {
if (scope.groups[i].group_id == group_id) {
var grp = scope.groups[i];
for (var p in properties) {
scope.groups[i][p] = properties[p];
}
}
}
}
}])
// Set node name and description after an update to Group properties. // Set node name and description after an update to Group properties.
.factory('SetNodeName', [ function() { .factory('SetNodeName', [ function() {
return function(params) { return function(params) {

View File

@@ -129,6 +129,10 @@ angular.module('Utilities',['RestServices', 'Utilities'])
else if (form) { else if (form) {
var fieldErrors = false; var fieldErrors = false;
for (var field in form.fields ) { for (var field in form.fields ) {
if (data[field] && form.fields[field].tab) {
// If the form is part of a tab group, activate the tab
$('#' + form.name + "_tabs a[href=\"#" + form.fields[field].tab + '"]').tab('show');
}
if (form.fields[field].realName) { if (form.fields[field].realName) {
if (data[form.fields[field].realName]) { if (data[form.fields[field].realName]) {
scope[field + '_api_error'] = data[form.fields[field]][0]; scope[field + '_api_error'] = data[form.fields[field]][0];

View File

@@ -1240,7 +1240,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
html += "</div>\n"; html += "</div>\n";
} }
else if (this.form.tabs) { else if (this.form.tabs) {
html += "<ul class=\"nav nav-tabs\">\n"; html += "<ul id=\"" + this.form.name + "_tabs\" class=\"nav nav-tabs\">\n";
for (var i=0; i < this.form.tabs.length; i++) { for (var i=0; i < this.form.tabs.length; i++) {
var tab = this.form.tabs[i]; var tab = this.form.tabs[i];
html += "<li"; html += "<li";

View File

@@ -72,7 +72,6 @@
<script src="{{ STATIC_URL }}js/forms/ProjectStatus.js"></script> <script src="{{ STATIC_URL }}js/forms/ProjectStatus.js"></script>
<script src="{{ STATIC_URL }}js/forms/Permissions.js"></script> <script src="{{ STATIC_URL }}js/forms/Permissions.js"></script>
<script src="{{ STATIC_URL }}js/forms/JobEventData.js"></script> <script src="{{ STATIC_URL }}js/forms/JobEventData.js"></script>
<script src="{{ STATIC_URL }}js/forms/License.js"></script>
<script src="{{ STATIC_URL }}js/forms/HostGroups.js"></script> <script src="{{ STATIC_URL }}js/forms/HostGroups.js"></script>
<script src="{{ STATIC_URL }}js/forms/InventoryStatus.js"></script> <script src="{{ STATIC_URL }}js/forms/InventoryStatus.js"></script>
<script src="{{ STATIC_URL }}js/forms/ActivityDetail.js"></script> <script src="{{ STATIC_URL }}js/forms/ActivityDetail.js"></script>