diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index a83c19ddba..8babf34c42 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -21,8 +21,6 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea LoadBreadCrumbs(); - $scope.showJobType = true; - // Add breadcrumbs e = angular.element(document.getElementById('breadcrumbs')); 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; } completed_scope = $scope.$new(true); + completed_scope.showJobType = true; LoadJobsScope({ parent_scope: $scope, scope: completed_scope, diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 176a9ba531..5ca4bcfd33 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -8,7 +8,7 @@ 'use strict'; angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition', - 'LookUpHelper', 'JobSubmissionHelper', 'JobTemplateFormDefinition' ]) + 'LookUpHelper', 'JobSubmissionHelper', 'JobTemplateFormDefinition', 'ModalDialog']) .factory('LaunchJob', ['Rest', 'Wait', 'ProcessErrors', function(Rest, Wait, ProcessErrors) { return function(params) { @@ -97,103 +97,147 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi }; }]) -.factory('PromptForPasswords', ['$compile', 'Wait', 'Alert', 'CredentialForm', - function($compile, Wait, Alert, CredentialForm) { +.factory('PromptForPasswords', ['$compile', 'Wait', 'Alert', 'CredentialForm', 'CreateDialog', + function($compile, Wait, Alert, CredentialForm, CreateDialog) { return function(params) { var parent_scope = params.scope, passwords = params.passwords, callback = params.callback || 'PasswordsAccepted', - password, form = CredentialForm, - html = "", acceptedPasswords = {}, - scope = parent_scope.$new(); - + scope = parent_scope.$new(), + e, buttons; + Wait('stop'); - function promptPassword() { - var e, fld, field; - password = passwords.pop(); - - // Prompt for password + function buildHtml() { + var fld, field, html; html = ""; + html += "
Launching this job requires the passwords listed below. Enter and confirm each password before continuing.
\n"; html += "
\n"; - field = form.fields[password]; - fld = password; - scope[fld] = ''; - html += "
\n"; - html += "\n"; - html += "A value is required!\n"; - html += "\n"; - html += "
\n"; - - // Add the related confirm field - if (field.associated) { - fld = field.associated; - field = form.fields[field.associated]; + + passwords.forEach(function(password) { + // Prompt for password + field = form.fields[password]; + fld = password; scope[fld] = ''; html += "
\n"; html += "\n"; html += "A value is required!\n"; - html += (field.awPassMatch) ? "Must match Password value\n" : ""; - html += "\n"; + html += "
A value is required!
\n"; + html += "
\n"; html += "
\n"; - } - html += "
\n"; - $('#password-body').html(html); - e = angular.element(document.getElementById('password-modal')); - $compile(e)(scope); - $('#password-modal').modal(); - $('#password-modal').on('shown.bs.modal', function () { - $('#password-body').find('input[type="password"]:first').focus(); + + // Add the related confirm field + if (field.associated) { + fld = field.associated; + field = form.fields[field.associated]; + scope[fld] = ''; + html += "
\n"; + html += "\n"; + html += "A value is required!\n"; + html += (field.awPassMatch) ? "Must match Password value
\n" : ""; + html += "
\n"; + html += "\n"; + } }); + html += "\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() { - $('#password-modal').modal('hide'); - $('#password-modal').off('shown.bs.modal'); - $('#password-body').empty(); - acceptedPasswords[password] = scope[password]; - if (passwords.length > 0) { - setTimeout(function() { - promptPassword(); - }, 500); - } - else { + if (!scope.password_form.$invalid) { + passwords.forEach(function(password) { + acceptedPasswords[password] = scope[password]; + }); + $('#password-modal').dialog('close'); parent_scope.$emit(callback, acceptedPasswords); - scope.$destroy(); } }; scope.passwordCancel = function() { - $('#password-modal').modal('hide'); - $('#password-modal').off('shown.bs.modal'); - $('#password-body').empty(); + $('#password-modal').dialog('close'); Alert('Missing Password', 'Required password(s) not provided. Your request will not be submitted.', 'alert-info'); parent_scope.$emit('PasswordsCanceled'); 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) { scope.removePasswordsCanceled(); } - scope.removePasswordCanceled = scope.$on('PasswordCanceled', function() { + scope.removePasswordsCanceled = scope.$on('PasswordsCanceled', function() { // Delete the job Wait('start'); Rest.setUrl(GetBasePath('jobs') + new_job_id + '/'); diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 536446f05b..fb17e9d192 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -1078,6 +1078,11 @@ input[type="checkbox"].checkbox-no-label { resize: vertical; } } + + #password-modal .alert-info { + margin-top: 0; + margin-bottom: 25px; + } /* Inventory job status badge */ .failures-true { diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 0e0312d52e..2617a56bd8 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -246,21 +246,7 @@ - +