mirror of
https://github.com/ansible/awx.git
synced 2026-05-06 17:07:36 -02:30
Fixed password prompting on job submission. Prompting for passwords one at a time was causing Angular to do bad things. Now we prompt for everything in one nicely formatted dialog.
This commit is contained in:
@@ -21,8 +21,6 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea
|
|||||||
|
|
||||||
LoadBreadCrumbs();
|
LoadBreadCrumbs();
|
||||||
|
|
||||||
$scope.showJobType = true;
|
|
||||||
|
|
||||||
// Add breadcrumbs
|
// Add breadcrumbs
|
||||||
e = angular.element(document.getElementById('breadcrumbs'));
|
e = angular.element(document.getElementById('breadcrumbs'));
|
||||||
e.html(Breadcrumbs({ list: { editTitle: 'Jobs' } , mode: 'edit' }));
|
e.html(Breadcrumbs({ list: { editTitle: 'Jobs' } , mode: 'edit' }));
|
||||||
@@ -44,6 +42,7 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea
|
|||||||
QueuedJobsList.fields.type.searchOptions = $scope.type_choices;
|
QueuedJobsList.fields.type.searchOptions = $scope.type_choices;
|
||||||
}
|
}
|
||||||
completed_scope = $scope.$new(true);
|
completed_scope = $scope.$new(true);
|
||||||
|
completed_scope.showJobType = true;
|
||||||
LoadJobsScope({
|
LoadJobsScope({
|
||||||
parent_scope: $scope,
|
parent_scope: $scope,
|
||||||
scope: completed_scope,
|
scope: completed_scope,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition',
|
angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition',
|
||||||
'LookUpHelper', 'JobSubmissionHelper', 'JobTemplateFormDefinition' ])
|
'LookUpHelper', 'JobSubmissionHelper', 'JobTemplateFormDefinition', 'ModalDialog'])
|
||||||
|
|
||||||
.factory('LaunchJob', ['Rest', 'Wait', 'ProcessErrors', function(Rest, Wait, ProcessErrors) {
|
.factory('LaunchJob', ['Rest', 'Wait', 'ProcessErrors', function(Rest, Wait, ProcessErrors) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
@@ -97,103 +97,147 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('PromptForPasswords', ['$compile', 'Wait', 'Alert', 'CredentialForm',
|
.factory('PromptForPasswords', ['$compile', 'Wait', 'Alert', 'CredentialForm', 'CreateDialog',
|
||||||
function($compile, Wait, Alert, CredentialForm) {
|
function($compile, Wait, Alert, CredentialForm, CreateDialog) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var parent_scope = params.scope,
|
var parent_scope = params.scope,
|
||||||
passwords = params.passwords,
|
passwords = params.passwords,
|
||||||
callback = params.callback || 'PasswordsAccepted',
|
callback = params.callback || 'PasswordsAccepted',
|
||||||
password,
|
|
||||||
form = CredentialForm,
|
form = CredentialForm,
|
||||||
html = "",
|
|
||||||
acceptedPasswords = {},
|
acceptedPasswords = {},
|
||||||
scope = parent_scope.$new();
|
scope = parent_scope.$new(),
|
||||||
|
e, buttons;
|
||||||
|
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
|
|
||||||
function promptPassword() {
|
function buildHtml() {
|
||||||
var e, fld, field;
|
var fld, field, html;
|
||||||
password = passwords.pop();
|
|
||||||
|
|
||||||
// Prompt for password
|
|
||||||
html = "";
|
html = "";
|
||||||
|
html += "<div class=\"alert alert-info\">Launching this job requires the passwords listed below. Enter and confirm each password before continuing.</div>\n";
|
||||||
html += "<form name=\"password_form\" novalidate>\n";
|
html += "<form name=\"password_form\" novalidate>\n";
|
||||||
field = form.fields[password];
|
|
||||||
fld = password;
|
|
||||||
scope[fld] = '';
|
|
||||||
html += "<div class=\"form-group\">\n";
|
|
||||||
html += "<label for=\"" + fld + "\">* " + field.label + "</label>\n";
|
|
||||||
html += "<input type=\"password\" ";
|
|
||||||
html += "ng-model=\"" + fld + '" ';
|
|
||||||
html += 'name="' + fld + '" ';
|
|
||||||
html += "class=\"password-field form-control\" ";
|
|
||||||
html += "required ";
|
|
||||||
html += "/>";
|
|
||||||
html += "<br />\n";
|
|
||||||
// Add error messages
|
|
||||||
html += "<span class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
|
||||||
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
|
||||||
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
// Add the related confirm field
|
passwords.forEach(function(password) {
|
||||||
if (field.associated) {
|
// Prompt for password
|
||||||
fld = field.associated;
|
field = form.fields[password];
|
||||||
field = form.fields[field.associated];
|
fld = password;
|
||||||
scope[fld] = '';
|
scope[fld] = '';
|
||||||
html += "<div class=\"form-group\">\n";
|
html += "<div class=\"form-group\">\n";
|
||||||
html += "<label for=\"" + fld + "\">* " + field.label + "</label>\n";
|
html += "<label for=\"" + fld + "\">* " + field.label + "</label>\n";
|
||||||
html += "<input type=\"password\" ";
|
html += "<input type=\"password\" ";
|
||||||
html += "ng-model=\"" + fld + '" ';
|
html += "ng-model=\"" + fld + '" ';
|
||||||
html += 'name="' + fld + '" ';
|
html += 'name="' + fld + '" ';
|
||||||
html += "class=\"form-control\" ";
|
html += "class=\"password-field form-control input-sm\" ";
|
||||||
|
html += (field.associated) ? "ng-change=\"clearPWConfirm('" + field.associated + "')\" " : "";
|
||||||
html += "required ";
|
html += "required ";
|
||||||
html += (field.awPassMatch) ? "awpassmatch=\"" + field.associated + "\" " : "";
|
html += " >";
|
||||||
html += "/>";
|
|
||||||
html += "<br />\n";
|
|
||||||
// Add error messages
|
// Add error messages
|
||||||
html += "<span class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
html += "<div class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
||||||
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
"password_form." + fld + ".$error.required\">A value is required!</div>\n";
|
||||||
html += (field.awPassMatch) ? "<span class=\"error\" ng-show=\"password_form." + fld +
|
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
|
||||||
".$error.awpassmatch\">Must match Password value</span>\n" : "";
|
|
||||||
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
|
|
||||||
html += "</div>\n";
|
html += "</div>\n";
|
||||||
}
|
|
||||||
html += "</form>\n";
|
// Add the related confirm field
|
||||||
$('#password-body').html(html);
|
if (field.associated) {
|
||||||
e = angular.element(document.getElementById('password-modal'));
|
fld = field.associated;
|
||||||
$compile(e)(scope);
|
field = form.fields[field.associated];
|
||||||
$('#password-modal').modal();
|
scope[fld] = '';
|
||||||
$('#password-modal').on('shown.bs.modal', function () {
|
html += "<div class=\"form-group\">\n";
|
||||||
$('#password-body').find('input[type="password"]:first').focus();
|
html += "<label for=\"" + fld + "\">* " + field.label + "</label>\n";
|
||||||
|
html += "<input type=\"password\" ";
|
||||||
|
html += "ng-model=\"" + fld + '" ';
|
||||||
|
html += 'name="' + fld + '" ';
|
||||||
|
html += "class=\"form-control input-sm\" ";
|
||||||
|
html += "ng-change=\"checkStatus()\" ";
|
||||||
|
html += "required ";
|
||||||
|
html += (field.awPassMatch) ? "awpassmatch=\"" + field.associated + "\" " : "";
|
||||||
|
html += "/>";
|
||||||
|
// Add error messages
|
||||||
|
html += "<div class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
||||||
|
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
||||||
|
html += (field.awPassMatch) ? "<span class=\"error\" ng-show=\"password_form." + fld +
|
||||||
|
".$error.awpassmatch\">Must match Password value</div>\n" : "";
|
||||||
|
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
|
||||||
|
html += "</div>\n";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
html += "</form>\n";
|
||||||
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#password-modal').empty().html(buildHtml);
|
||||||
|
e = angular.element(document.getElementById('password-modal'));
|
||||||
|
$compile(e)(scope);
|
||||||
|
|
||||||
|
buttons = [{
|
||||||
|
label: "Cancel",
|
||||||
|
onClick: function() {
|
||||||
|
scope.passwordCancel();
|
||||||
|
},
|
||||||
|
icon: "fa-times",
|
||||||
|
"class": "btn btn-default",
|
||||||
|
"id": "password-cancel-button"
|
||||||
|
},{
|
||||||
|
label: "Continue",
|
||||||
|
onClick: function() {
|
||||||
|
scope.passwordAccept();
|
||||||
|
},
|
||||||
|
icon: "fa-check",
|
||||||
|
"class": "btn btn-primary",
|
||||||
|
"id": "password-accept-button"
|
||||||
|
}];
|
||||||
|
|
||||||
|
CreateDialog({
|
||||||
|
id: 'password-modal',
|
||||||
|
scope: scope,
|
||||||
|
buttons: buttons,
|
||||||
|
width: 600,
|
||||||
|
height: (passwords.length > 1) ? 700 : 500,
|
||||||
|
minWidth: 500,
|
||||||
|
title: 'Passwords Required',
|
||||||
|
callback: 'DialogReady'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (scope.removeDialogReady) {
|
||||||
|
scope.removeDialogReady();
|
||||||
|
}
|
||||||
|
scope.removeDialogReady = scope.$on('DialogReady', function() {
|
||||||
|
$('#password-modal').dialog('open');
|
||||||
|
$('#password-accept-button').attr({ "disabled": "disabled" });
|
||||||
|
});
|
||||||
|
|
||||||
scope.passwordAccept = function() {
|
scope.passwordAccept = function() {
|
||||||
$('#password-modal').modal('hide');
|
if (!scope.password_form.$invalid) {
|
||||||
$('#password-modal').off('shown.bs.modal');
|
passwords.forEach(function(password) {
|
||||||
$('#password-body').empty();
|
acceptedPasswords[password] = scope[password];
|
||||||
acceptedPasswords[password] = scope[password];
|
});
|
||||||
if (passwords.length > 0) {
|
$('#password-modal').dialog('close');
|
||||||
setTimeout(function() {
|
|
||||||
promptPassword();
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
parent_scope.$emit(callback, acceptedPasswords);
|
parent_scope.$emit(callback, acceptedPasswords);
|
||||||
scope.$destroy();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.passwordCancel = function() {
|
scope.passwordCancel = function() {
|
||||||
$('#password-modal').modal('hide');
|
$('#password-modal').dialog('close');
|
||||||
$('#password-modal').off('shown.bs.modal');
|
|
||||||
$('#password-body').empty();
|
|
||||||
Alert('Missing Password', 'Required password(s) not provided. Your request will not be submitted.', 'alert-info');
|
Alert('Missing Password', 'Required password(s) not provided. Your request will not be submitted.', 'alert-info');
|
||||||
parent_scope.$emit('PasswordsCanceled');
|
parent_scope.$emit('PasswordsCanceled');
|
||||||
scope.$destroy();
|
scope.$destroy();
|
||||||
};
|
};
|
||||||
promptPassword();
|
|
||||||
|
// Password change
|
||||||
|
scope.clearPWConfirm = function (fld) {
|
||||||
|
// If password value changes, make sure password_confirm must be re-entered
|
||||||
|
scope[fld] = '';
|
||||||
|
scope.password_form[fld].$setValidity('awpassmatch', false);
|
||||||
|
scope.checkStatus();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.checkStatus = function() {
|
||||||
|
if (!scope.password_form.$invalid) {
|
||||||
|
$('#password-accept-button').removeAttr('disabled');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#password-accept-button').attr({ "disabled": "disabled" });
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
@@ -238,7 +282,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
|||||||
if (scope.removePasswordsCanceled) {
|
if (scope.removePasswordsCanceled) {
|
||||||
scope.removePasswordsCanceled();
|
scope.removePasswordsCanceled();
|
||||||
}
|
}
|
||||||
scope.removePasswordCanceled = scope.$on('PasswordCanceled', function() {
|
scope.removePasswordsCanceled = scope.$on('PasswordsCanceled', function() {
|
||||||
// Delete the job
|
// Delete the job
|
||||||
Wait('start');
|
Wait('start');
|
||||||
Rest.setUrl(GetBasePath('jobs') + new_job_id + '/');
|
Rest.setUrl(GetBasePath('jobs') + new_job_id + '/');
|
||||||
|
|||||||
@@ -1079,6 +1079,11 @@ input[type="checkbox"].checkbox-no-label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#password-modal .alert-info {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Inventory job status badge */
|
/* Inventory job status badge */
|
||||||
.failures-true {
|
.failures-true {
|
||||||
background-color: @red;
|
background-color: @red;
|
||||||
|
|||||||
@@ -246,21 +246,7 @@
|
|||||||
</div><!-- modal -->
|
</div><!-- modal -->
|
||||||
|
|
||||||
<!-- Password Dialog -->
|
<!-- Password Dialog -->
|
||||||
<div id="password-modal" class="modal fade">
|
<div id="password-modal" style="display: none;"></div>
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" ng-click="cancelJob()" aria-hidden="true">×</button>
|
|
||||||
<h3>Authentication Required</h3>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body" id="password-body"></div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a href="" ng-click="passwordCancel()" class="btn btn-default" id="password_cancel_btn">Cancel</a>
|
|
||||||
<a href="" ng-click="passwordAccept()" class="btn btn-primary" id="password_continue_btn" ng-disabled="password_form.$pristine || password_form.$invalid">Continue</a>
|
|
||||||
</div>
|
|
||||||
</div><!-- modal-content -->
|
|
||||||
</div><!-- modal-dialog -->
|
|
||||||
</div><!-- modal -->
|
|
||||||
|
|
||||||
<!-- Generic Form dialog -->
|
<!-- Generic Form dialog -->
|
||||||
<div id="form-modal" class="modal fade">
|
<div id="form-modal" class="modal fade">
|
||||||
|
|||||||
Reference in New Issue
Block a user