Fixed form validation issues on Projects detail for manual projects. When editing an existing project, local_path value was not being set, even though it diplayed properly. Changed local_path from array of strings to array of objects. Now local_path values are sorted and the correct object in the list is selected.

This commit is contained in:
Chris Houseknecht 2013-11-04 07:14:21 +00:00 committed by Chris Church
parent bac22205a8
commit a5c44a391c
6 changed files with 99 additions and 126 deletions

View File

@ -231,7 +231,7 @@ ProjectsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routePar
function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, ProjectsForm,
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope,
GetBasePath, ReturnToCaller, GetProjectPath, LookUpInit, OrganizationList,
CredentialList, GetChoices)
CredentialList, GetChoices, DebugForm)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -247,6 +247,7 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
generator.reset();
LoadBreadCrumbs();
GetProjectPath({ scope: scope, master: master });
if (scope.removeChoicesReady) {
@ -259,6 +260,8 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
break;
}
}
scope.scmRequired = false;
master['scm_type'] = scope['scm_type'];
});
// Load the list of options for Kind
@ -301,10 +304,11 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
}
}
}
if (scope.scm_type) {
data.scm_type = scope.scm_type.value;
data.scm_type = scope.scm_type.value;
if (data.scm_type.value !== '') {
delete data.local_path;
}
var url = (base == 'teams') ? GetBasePath('teams') + $routeParams.team_id + '/projects/' : defaultUrl;
Rest.setUrl(url);
Rest.post(data)
@ -331,20 +335,9 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
scope.scmChange = function() {
// When an scm_type is set, path is not required
scope.pathRequired = (scope.scm_type) ? false : true;
scope.scmBranchLabel = (scope.scm_type && scope.scm_type.value && scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
}
scope.authChange = function() {
if (!scope.auth_required) {
scope.scm_username = null;
scope.scm_password = null;
scope.scm_password_confirm = null;
scope.scm_key_data = null;
scope.scm_key_unlock = null;
scope.scm_key_unlock_confirm = null;
scope.scm_password_ask = false;
}
scope.pathRequired = (scope.scm_type.value == '') ? true : false;
scope.scmRequired = (scope.scm_type.value !== '') ? true : false;
scope.scmBranchLabel = (scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
}
// Cancel
@ -354,19 +347,21 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
for (var fld in master) {
scope[fld] = master[fld];
}
scope.scmChange();
};
}
ProjectsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'ProjectsForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath',
'ReturnToCaller', 'GetProjectPath', 'LookUpInit', 'OrganizationList', 'CredentialList', 'GetChoices'
'ReturnToCaller', 'GetProjectPath', 'LookUpInit', 'OrganizationList', 'CredentialList', 'GetChoices',
'DebugForm'
];
function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, ProjectsForm,
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
RelatedPaginateInit, Prompt, ClearScope, GetBasePath, ReturnToCaller, GetProjectPath,
Authorization, CredentialList, LookUpInit, GetChoices)
Authorization, CredentialList, LookUpInit, GetChoices, Empty, DebugForm)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -386,21 +381,6 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
scope.project_local_paths = [];
scope.base_dir = '';
function setAskCheckboxes() {
for (var fld in form.fields) {
if (form.fields[fld].type == 'password' && form.fields[fld].ask && scope[fld] == 'ASK') {
// turn on 'ask' checkbox for password fields with value of 'ASK'
$("#" + fld + "-clear-btn").attr("disabled","disabled");
scope[fld + '_ask'] = true;
}
else {
scope[fld + '_ask'] = false;
$("#" + fld + "-clear-btn").removeAttr("disabled");
}
master[fld + '_ask'] = scope[fld + '_ask'];
}
}
// After the project is loaded, retrieve each related set
if (scope.projectLoadedRemove) {
scope.projectLoadedRemove();
@ -409,25 +389,29 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
for (var set in relatedSets) {
scope.search(relatedSets[set].iterator);
}
if (Authorization.getUserInfo('is_superuser') == true) {
GetProjectPath({ scope: scope, master: master });
}
else {
var opts = [];
opts.push(scope['local_path']);
opts.push({ label: scope['local_path'], value: scope['local_path'] });
scope.project_local_paths = opts;
scope.local_path = scope['project_local_paths'][0];
scope.base_dir = 'You do not have access to view this property';
}
LookUpInit({
url: GetBasePath('credentials') + '?kind=scm',
scope: scope,
form: form,
list: CredentialList,
field: 'credential'
field: 'credential'
});
scope.auth_required = (scope.scm_type && (scope.scm_username || scope.scm_password || scope.scm_key_data)) ? true : false;
master.auth_required = scope.auth_required;
scope.pathRequired = (scope.scm_type.value == '') ? true : false;
scope.scmRequired = (scope.scm_type.value !== '') ? true : false;
scope.scmBranchLabel = (scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
});
if (scope.removeChoicesReady) {
@ -466,26 +450,28 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
relatedSets[set] = { url: related[set], iterator: form.related[set].iterator };
}
}
if (data.scm_type !== "") {
for (var i=0; i < scope.scm_type_options.length; i++) {
if (scope.scm_type_options[i].value == data.scm_type) {
scope.scm_type = scope.scm_type_options[i];
break;
}
}
data.scm_type = (Empty(data.scm_type)) ? '' : data.scm_type;
for (var i=0; i < scope.scm_type_options.length; i++) {
if (scope.scm_type_options[i].value == data.scm_type) {
scope.scm_type = scope.scm_type_options[i];
break;
}
}
if (scope.scm_type.value !== '') {
scope.pathRequired = false;
scope.scmRequired = true;
}
else {
scope.pathRequired = true;
scope.scmRequired = false;
}
master['scm_type'] = scope['scm_type'];
master['auth_required'] = scope['auth_required'];
scope.scmBranchLabel = (scope.scm_type && scope.scm_type.value && scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
setAskCheckboxes();
scope.scmBranchLabel = (scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
// Initialize related search functions. Doing it here to make sure relatedSets object is populated.
RelatedSearchInit({ scope: scope, form: form, relatedSets: relatedSets });
RelatedPaginateInit({ scope: scope, relatedSets: relatedSets });
@ -499,7 +485,7 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
// Load the list of options for Kind
GetChoices({
url: GetBasePath('credentials') + '?kind=scm',
url: GetBasePath('projects'),
scope: scope,
field: 'scm_type',
variable: 'scm_type_options',
@ -524,10 +510,12 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
}
}
}
if (scope.scm_type) {
params.scm_type = scope.scm_type.value;
params.scm_type = scope.scm_type.value;
if (scope.scm_type.value !== '') {
delete params.local_path;
}
Rest.setUrl(defaultUrl);
Rest.put(params)
.success( function(data, status, headers, config) {
@ -539,27 +527,6 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
});
};
// Reset the form
scope.formReset = function() {
$rootScope.flashMessage = null;
generator.reset();
for (var fld in master) {
scope[fld] = master[fld];
}
};
scope.authChange = function() {
if (!scope.auth_required) {
scope.scm_username = null;
scope.scm_password = null;
scope.scm_password_confirm = null;
scope.scm_key_data = null;
scope.scm_key_unlock = null;
scope.scm_key_unlock_confirm = null;
scope.scm_password_ask = false;
}
}
// Related set: Add button
scope.add = function(set) {
$rootScope.flashMessage = null;
@ -595,46 +562,28 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
action: action
});
}
// Password change
scope.clearPWConfirm = function(fld) {
// If password value changes, make sure password_confirm must be re-entered
scope[fld] = '';
scope[form.name + '_form'][fld].$setValidity('awpassmatch', false);
}
// Respond to 'Ask at runtime?' checkbox
scope.ask = function(fld, associated) {
if (scope[fld + '_ask']) {
$("#" + fld + "-clear-btn").attr("disabled","disabled");
scope[fld] = 'ASK';
scope[associated] = '';
scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
}
else {
$("#" + fld + "-clear-btn").removeAttr("disabled");
scope[fld] = '';
scope[associated] = '';
scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
}
}
scope.clear = function(fld, associated) {
scope[fld] = '';
scope[associated] = '';
scope[form.name + '_form'][associated].$setValidity('awpassmatch', true);
scope[form.name + '_form'].$setDirty();
}
scope.scmChange = function() {
// When an scm_type is set, path is not required
scope.pathRequired = (scope.scm_type) ? false : true;
scope.scmBranchLabel = (scope.scm_type && scope.scm_type.value && scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
scope.pathRequired = (scope.scm_type.value == '') ? true : false;
scope.scmRequired = (scope.scm_type.value !== '') ? true : false;
scope.scmBranchLabel = (scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
}
// Reset the form
scope.formReset = function() {
$rootScope.flashMessage = null;
generator.reset();
for (var fld in master) {
scope[fld] = master[fld];
}
scope.scmChange();
//DebugForm({ scope: scope, form: form });
};
}
ProjectsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'ProjectsForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
'RelatedPaginateInit', 'Prompt', 'ClearScope', 'GetBasePath', 'ReturnToCaller',
'GetProjectPath', 'Authorization', 'CredentialList', 'LookUpInit', 'GetChoices'
'GetProjectPath', 'Authorization', 'CredentialList', 'LookUpInit', 'GetChoices', 'Empty',
'DebugForm'
];

View File

@ -82,8 +82,8 @@ angular.module('ProjectFormDefinition', [])
label: 'Playbook Directory',
type: 'select',
id: 'local-path-select',
ngOptions: 'path for path in project_local_paths',
awRequiredWhen: { variable: "pathRequired", init: "true" },
ngOptions: 'path.label for path in project_local_paths',
awRequiredWhen: { variable: "pathRequired", init: false },
ngShow: "scm_type.value == ''",
awPopOver: '<p>Select from the list of directories found in the base path.' +
'Together the base path and the playbook directory provide the full path used to locate playbooks.</p>' +
@ -96,7 +96,7 @@ angular.module('ProjectFormDefinition', [])
label: 'SCM URL',
type: 'text',
ngShow: "scm_type.value !== ''",
awRequiredWhen: { variable: "scm_type", init: "true" },
awRequiredWhen: { variable: "scmRequired", init: false },
helpCollapse: [
{ hdr: 'GIT URLs',
content: '<p>Example URLs for GIT SCM include:</p><ul class=\"no-bullets\"><li>https://github.com/ansible/ansible.git</li>' +
@ -140,14 +140,12 @@ angular.module('ProjectFormDefinition', [])
checkbox_group: {
label: 'SCM Options',
type: 'checkbox_group',
ngShow: "scm_type !== '' && scm_type !== null",
ngShow: "scm_type && scm_type.value !== ''",
fields: [
{
name: 'scm_clean',
label: 'Clean',
type: 'checkbox',
ngShow: "scm_type.value !== ''",
addRequired: false,
editRequired: false,
awPopOver: '<p>Remove any local modifications prior to performing an update.</p>',
@ -160,7 +158,6 @@ angular.module('ProjectFormDefinition', [])
name: 'scm_delete_on_update',
label: 'Delete on Update',
type: 'checkbox',
ngShow: "scm_type.value !== ''",
addRequired: false,
editRequired: false,
awPopOver: '<p>Delete the local repository in its entirety prior to performing an update.</p><p>Depending on the size of the ' +
@ -174,7 +171,6 @@ angular.module('ProjectFormDefinition', [])
name: 'scm_update_on_launch',
label: 'Update on Launch',
type: 'checkbox',
ngShow: "scm_type.value !== ''",
addRequired: false,
editRequired: false,
awPopOver: '<p>Each time a job runs using this project, perform an update to the local repository prior to starting the job.</p>',

View File

@ -611,7 +611,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
var data = {
name: scope['name'],
description: scope['description'],
description: scope['description']
};
if (inventory_id) {

View File

@ -316,7 +316,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function(e, action) {
// Refresh the project list after update request submitted
Alert('Update Started', 'The request to start the SCM update process was submitted. ' +
'The Projects page will refresh every 10 seconds, or refresh manually by clicking the <em>Refresh</em> button.', 'alert-info');
'To monitor the update status, refresh the page by clicking the <em>Refresh</em> button.', 'alert-info');
scope.refresh();
});
@ -402,8 +402,8 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function(e, action) {
if (action == 'started') {
// Refresh the project list after update request submitted
Alert('Update Started', 'The request to start the inventory update process was submitted. Monitor progress from the inventory summary screen. ' +
'The screen will refresh every 10 seconds, or refresh manually by clicking the <em>Refresh</em> button.', 'alert-info');
Alert('Update Started', 'The request to start the inventory update process was submitted. Monitor progress of the update process ' +
'by clicking the <em>Refresh</em> button.', 'alert-info');
//var node = $('#inventory-node')
//var selected = $('#tree-view').jstree('get_selected');
//scope['inventorySummaryGroup'] = null;

View File

@ -17,6 +17,24 @@ angular.module('ProjectPathHelper', ['RestServices', 'Utilities'])
var scope = params.scope;
var master = params.master;
function arraySort(data) {
//Sort nodes by name
var names = [];
var newData = [];
for (var i=0; i < data.length; i++) {
names.push(data[i].value);
}
names.sort();
for (var j=0; j < names.length; j++) {
for (i=0; i < data.length; i++) {
if (data[i].value == names[j]) {
newData.push(data[i]);
}
}
}
return newData;
}
scope.showMissingPlaybooksAlert = false;
Rest.setUrl( GetBasePath('config') );
@ -24,12 +42,22 @@ angular.module('ProjectPathHelper', ['RestServices', 'Utilities'])
.success( function(data, status, headers, config) {
var opts = [];
for (var i=0; i < data.project_local_paths.length; i++) {
opts.push(data.project_local_paths[i]);
opts.push({ label: data.project_local_paths[i], value: data.project_local_paths[i] });
}
if (scope.local_path) {
opts.push(scope.local_path);
// List only includes paths not assigned to projects, so add the
// path assigned to the current project.
opts.push({ label: scope.local_path, value: scope.local_path });
}
scope.project_local_paths = arraySort(opts);
if (scope.local_path) {
for (var i=0; scope.project_local_paths.length; i++) {
if (scope.project_local_paths[i].value == scope.local_path) {
scope.local_path = scope.project_local_paths[i];
break;
}
}
}
scope.project_local_paths = opts;
scope.base_dir = data.project_base_dir;
master.base_dir = scope.base_dir; // Keep in master object so that it doesn't get
// wiped out on form reset.

View File

@ -107,7 +107,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
function checkIt () {
var viewValue = elm.val();
var txt, label, p, l, s;
var txt, label;
validity = true;
if ( scope[attrs.awRequiredWhen] && (elm.attr('required') == null || elm.attr('required') == undefined) ) {
$(elm).attr('required','required');