diff --git a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js index 85d7480957..1438f89f37 100644 --- a/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js +++ b/awx/ui/client/src/templates/job_templates/add-job-template/job-template-add.controller.js @@ -37,6 +37,8 @@ $scope.mode = "add"; $scope.parseType = 'yaml'; $scope.credentialNotPresent = false; + $scope.canChangeProject = true; + $scope.canChangeInventory = true; md5Setup({ scope: $scope, diff --git a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js index 0884a04ca2..5e38774766 100644 --- a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js +++ b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js @@ -18,13 +18,15 @@ export default 'Empty', 'Prompt', 'ToJSON', 'GetChoices', 'CallbackHelpInit', 'InitiatePlaybookRun' , 'initSurvey', '$state', 'CreateSelect2', 'ToggleNotification','$q', 'InstanceGroupsService', 'InstanceGroupsData', 'MultiCredentialService', 'availableLabels', + 'canChangeProject', 'canChangeInventory', 'jobTemplateData', 'ParseVariableString', function( $filter, $scope, $rootScope, $location, $stateParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, GetBasePath, md5Setup, ParseTypeChange, Wait, selectedLabels, i18n, Empty, Prompt, ToJSON, GetChoices, CallbackHelpInit, InitiatePlaybookRun, SurveyControllerInit, $state, - CreateSelect2, ToggleNotification, $q, InstanceGroupsService, InstanceGroupsData, MultiCredentialService, availableLabels + CreateSelect2, ToggleNotification, $q, InstanceGroupsService, InstanceGroupsData, MultiCredentialService, availableLabels, + canChangeProject, canChangeInventory, jobTemplateData, ParseVariableString ) { $scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) { @@ -47,6 +49,7 @@ export default function init() { CallbackHelpInit({ scope: $scope }); + $scope.playbook_options = null; $scope.playbook = null; $scope.mode = 'edit'; @@ -57,6 +60,8 @@ export default $scope.surveyTooltip = i18n._('Surveys allow users to be prompted at job launch with a series of questions related to the job. This allows for variables to be defined that affect the playbook run at time of launch.'); $scope.job_tag_options = []; $scope.skip_tag_options = []; + $scope.canChangeProject = canChangeProject; + $scope.canChangeInventory = canChangeInventory; SurveyControllerInit({ scope: $scope, @@ -253,7 +258,194 @@ export default $scope.rmoveLoadJobs(); } $scope.removeLoadJobs = $scope.$on('LoadJobs', function() { - $scope.fillJobTemplate(); + $scope.job_template_obj = jobTemplateData; + $scope.name = jobTemplateData.name; + var fld, i; + for (fld in form.fields) { + if (fld !== 'variables' && fld !== 'survey' && fld !== 'forks' && jobTemplateData[fld] !== null && jobTemplateData[fld] !== undefined) { + if (form.fields[fld].type === 'select') { + if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) { + for (i = 0; i < $scope[fld + '_options'].length; i++) { + if (jobTemplateData[fld] === $scope[fld + '_options'][i].value) { + $scope[fld] = $scope[fld + '_options'][i]; + } + } + } else { + $scope[fld] = jobTemplateData[fld]; + } + } else { + $scope[fld] = jobTemplateData[fld]; + if(!Empty(jobTemplateData.summary_fields.survey)) { + $scope.survey_exists = true; + } + } + master[fld] = $scope[fld]; + } + if (fld === 'forks') { + if (jobTemplateData[fld] !== 0) { + $scope[fld] = jobTemplateData[fld]; + master[fld] = $scope[fld]; + } + } + if (fld === 'variables') { + // Parse extra_vars, converting to YAML. + $scope.variables = ParseVariableString(jobTemplateData.extra_vars); + master.variables = $scope.variables; + } + if (form.fields[fld].type === 'lookup' && jobTemplateData.summary_fields[form.fields[fld].sourceModel]) { + $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = + jobTemplateData.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; + master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = + $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]; + } + if (form.fields[fld].type === 'checkbox_group') { + for(var j=0; j ({name: i, label: i, value: i})) : []; + $scope.job_tags = $scope.job_tag_options; + master.job_tags = $scope.job_tags; + + $scope.skip_tag_options = (jobTemplateData.skip_tags) ? jobTemplateData.skip_tags.split(',') + .map((i) => ({name: i, label: i, value: i})) : []; + $scope.skip_tags = $scope.skip_tag_options; + master.skip_tags = $scope.skip_tags; + + $scope.ask_job_type_on_launch = (jobTemplateData.ask_job_type_on_launch) ? true : false; + master.ask_job_type_on_launch = $scope.ask_job_type_on_launch; + + $scope.ask_inventory_on_launch = (jobTemplateData.ask_inventory_on_launch) ? true : false; + master.ask_inventory_on_launch = $scope.ask_inventory_on_launch; + + $scope.ask_credential_on_launch = (jobTemplateData.ask_credential_on_launch) ? true : false; + master.ask_credential_on_launch = $scope.ask_credential_on_launch; + + if (jobTemplateData.host_config_key) { + $scope.example_config_key = jobTemplateData.host_config_key; + } + $scope.example_template_id = id; + $scope.setCallbackHelp(); + + $scope.callback_url = $scope.callback_server_path + ((jobTemplateData.related.callback) ? jobTemplateData.related.callback : + GetBasePath('job_templates') + id + '/callback/'); + master.callback_url = $scope.callback_url; + + $scope.can_edit = jobTemplateData.summary_fields.user_capabilities.edit; + + if($scope.job_template_obj.summary_fields.user_capabilities.edit) { + MultiCredentialService.loadCredentials(jobTemplateData) + .then(([selectedCredentials, credTypes, credTypeOptions, + credTags]) => { + $scope.selectedCredentials = selectedCredentials; + $scope.credential_types = credTypes; + $scope.credentialTypeOptions = credTypeOptions; + $scope.credentialsToPost = credTags; + $scope.$emit('jobTemplateLoaded', master); + }); + } + else { + + if (jobTemplateData.summary_fields.credential) { + $scope.selectedCredentials.machine = jobTemplateData.summary_fields.credential; + } + + if (jobTemplateData.summary_fields.vault_credential) { + $scope.selectedCredentials.vault = jobTemplateData.summary_fields.vault_credential; + } + + // Extra credentials are not included in summary_fields so we have to go + // out and get them ourselves. + + let defers = [], + typesArray = [], + credTypeOptions; + + Rest.setUrl(jobTemplateData.related.extra_credentials); + defers.push(Rest.get() + .then((data) => { + $scope.selectedCredentials.extra = data.data.results; + }) + .catch(({data, status}) => { + ProcessErrors(null, data, status, null, + { + hdr: 'Error!', + msg: 'Failed to get extra credentials. ' + + 'Get returned status: ' + + status + }); + })); + + defers.push(MultiCredentialService.getCredentialTypes() + .then(({credential_types, credentialTypeOptions}) => { + typesArray = Object.keys(credential_types).map(key => credential_types[key]); + credTypeOptions = credentialTypeOptions; + }) + ); + + + return $q.all(defers).then(() => { + let machineAndVaultCreds = [], + extraCreds = []; + + if($scope.selectedCredentials.machine) { + machineAndVaultCreds.push($scope.selectedCredentials.machine); + } + if($scope.selectedCredentials.vault) { + machineAndVaultCreds.push($scope.selectedCredentials.vault); + } + + machineAndVaultCreds.map(cred => ({ + name: cred.name, + id: cred.id, + postType: cred.postType, + kind: typesArray + .filter(type => { + return cred.kind === type.kind || parseInt(cred.credential_type) === type.value; + })[0].name + ":" + })); + + extraCreds = extraCreds.concat($scope.selectedCredentials.extra).map(cred => ({ + name: cred.name, + id: cred.id, + postType: cred.postType, + kind: credTypeOptions + .filter(type => { + return parseInt(cred.credential_type) === type.value; + })[0].name + ":" + })); + + $scope.credentialsToPost = machineAndVaultCreds.concat(extraCreds); + + $scope.$emit('jobTemplateLoaded', master); + }); + + } }); if ($scope.removeChoicesReady) { diff --git a/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js b/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js index d0eada857c..e1c027a4e0 100644 --- a/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js +++ b/awx/ui/client/src/templates/job_templates/factories/callback-help-init.factory.js @@ -2,14 +2,7 @@ export default function CallbackHelpInit($q, $location, GetBasePath, Rest, JobTemplateForm, GenerateForm, $stateParams, ProcessErrors, ParseVariableString, Empty, Wait, MultiCredentialService, $rootScope) { return function(params) { - var scope = params.scope, - defaultUrl = GetBasePath('job_templates'), - // generator = GenerateForm, - form = JobTemplateForm(), - // loadingFinishedCount = 0, - // base = $location.path().replace(/^\//, '').split('/')[0], - master = {}, - id = $stateParams.job_template_id; + var scope = params.scope; // checkSCMStatus, getPlaybooks, callback, // choicesCount = 0; @@ -44,211 +37,6 @@ export default scope.example_config_key = '5a8ec154832b780b9bdef1061764ae5a'; scope.example_template_id = 'N'; scope.setCallbackHelp(); - - // this fills the job template form both on copy of the job template - // and on edit - scope.fillJobTemplate = function(){ - // id = id || $rootScope.copy.id; - // Retrieve detail record and prepopulate the form - Rest.setUrl(defaultUrl + id); - Rest.get() - .success(function (data) { - scope.job_template_obj = data; - scope.name = data.name; - var fld, i; - for (fld in form.fields) { - if (fld !== 'variables' && fld !== 'survey' && fld !== 'forks' && data[fld] !== null && data[fld] !== undefined) { - if (form.fields[fld].type === 'select') { - if (scope[fld + '_options'] && scope[fld + '_options'].length > 0) { - for (i = 0; i < scope[fld + '_options'].length; i++) { - if (data[fld] === scope[fld + '_options'][i].value) { - scope[fld] = scope[fld + '_options'][i]; - } - } - } else { - scope[fld] = data[fld]; - } - } else { - scope[fld] = data[fld]; - if(!Empty(data.summary_fields.survey)) { - scope.survey_exists = true; - } - } - master[fld] = scope[fld]; - } - if (fld === 'forks') { - if (data[fld] !== 0) { - scope[fld] = data[fld]; - master[fld] = scope[fld]; - } - } - if (fld === 'variables') { - // Parse extra_vars, converting to YAML. - scope.variables = ParseVariableString(data.extra_vars); - master.variables = scope.variables; - } - if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) { - scope[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] = - scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]; - } - if (form.fields[fld].type === 'checkbox_group') { - for(var j=0; j ({name: i, label: i, value: i})) : []; - scope.job_tags = scope.job_tag_options; - master.job_tags = scope.job_tags; - - scope.skip_tag_options = (data.skip_tags) ? data.skip_tags.split(',') - .map((i) => ({name: i, label: i, value: i})) : []; - scope.skip_tags = scope.skip_tag_options; - master.skip_tags = scope.skip_tags; - - scope.ask_job_type_on_launch = (data.ask_job_type_on_launch) ? true : false; - master.ask_job_type_on_launch = scope.ask_job_type_on_launch; - - scope.ask_inventory_on_launch = (data.ask_inventory_on_launch) ? true : false; - master.ask_inventory_on_launch = scope.ask_inventory_on_launch; - - scope.ask_credential_on_launch = (data.ask_credential_on_launch) ? true : false; - master.ask_credential_on_launch = scope.ask_credential_on_launch; - - if (data.host_config_key) { - scope.example_config_key = data.host_config_key; - } - scope.example_template_id = id; - scope.setCallbackHelp(); - - scope.callback_url = scope.callback_server_path + ((data.related.callback) ? data.related.callback : - GetBasePath('job_templates') + id + '/callback/'); - master.callback_url = scope.callback_url; - - scope.can_edit = data.summary_fields.user_capabilities.edit; - - if(scope.job_template_obj.summary_fields.user_capabilities.edit) { - MultiCredentialService.loadCredentials(data) - .then(([selectedCredentials, credTypes, credTypeOptions, - credTags]) => { - scope.selectedCredentials = selectedCredentials; - scope.credential_types = credTypes; - scope.credentialTypeOptions = credTypeOptions; - scope.credentialsToPost = credTags; - scope.$emit('jobTemplateLoaded', master); - }); - } - else { - - if (data.summary_fields.credential) { - scope.selectedCredentials.machine = data.summary_fields.credential; - } - - if (data.summary_fields.vault_credential) { - scope.selectedCredentials.vault = data.summary_fields.vault_credential; - } - - // Extra credentials are not included in summary_fields so we have to go - // out and get them ourselves. - - let defers = [], - typesArray = [], - credTypeOptions; - - Rest.setUrl(data.related.extra_credentials); - defers.push(Rest.get() - .then((data) => { - scope.selectedCredentials.extra = data.data.results; - }) - .catch(({data, status}) => { - ProcessErrors(null, data, status, null, - { - hdr: 'Error!', - msg: 'Failed to get extra credentials. ' + - 'Get returned status: ' + - status - }); - })); - - defers.push(MultiCredentialService.getCredentialTypes() - .then(({credential_types, credentialTypeOptions}) => { - typesArray = Object.keys(credential_types).map(key => credential_types[key]); - credTypeOptions = credentialTypeOptions; - }) - ); - - - return $q.all(defers).then(() => { - let machineAndVaultCreds = [], - extraCreds = []; - - if(scope.selectedCredentials.machine) { - machineAndVaultCreds.push(scope.selectedCredentials.machine); - } - if(scope.selectedCredentials.vault) { - machineAndVaultCreds.push(scope.selectedCredentials.vault); - } - - machineAndVaultCreds.map(cred => ({ - name: cred.name, - id: cred.id, - postType: cred.postType, - kind: typesArray - .filter(type => { - return cred.kind === type.kind || parseInt(cred.credential_type) === type.value; - })[0].name + ":" - })); - - extraCreds = extraCreds.concat(scope.selectedCredentials.extra).map(cred => ({ - name: cred.name, - id: cred.id, - postType: cred.postType, - kind: credTypeOptions - .filter(type => { - return parseInt(cred.credential_type) === type.value; - })[0].name + ":" - })); - - scope.credentialsToPost = machineAndVaultCreds.concat(extraCreds); - - scope.$emit('jobTemplateLoaded', master); - }); - - } - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to retrieve job template: ' + $stateParams.id + '. GET status: ' + status - }); - }); - }; }; } diff --git a/awx/ui/client/src/templates/job_templates/job-template.form.js b/awx/ui/client/src/templates/job_templates/job-template.form.js index 720bad0aad..ec7ec3a454 100644 --- a/awx/ui/client/src/templates/job_templates/job-template.form.js +++ b/awx/ui/client/src/templates/job_templates/job-template.form.js @@ -85,7 +85,7 @@ function(NotificationsList, CompletedJobsList, i18n) { ngChange: 'job_template_form.inventory_name.$validate()', text: i18n._('Prompt on launch') }, - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' + ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canChangeInventory' }, project: { label: i18n._('Project'), @@ -100,13 +100,14 @@ function(NotificationsList, CompletedJobsList, i18n) { dataTitle: i18n._('Project'), dataPlacement: 'right', dataContainer: "body", - ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' + ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canChangeProject', + awLookupWhen: 'canChangeProject' }, playbook: { label: i18n._('Playbook'), type:'select', ngOptions: 'book for book in playbook_options track by book', - ngDisabled: "!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || disablePlaybookBecausePermissionDenied", + ngDisabled: "!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !canChangeProject", id: 'playbook-select', required: true, column: 1, diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js index 4155a44d39..6b9e8ba709 100644 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js +++ b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.directive.js @@ -14,7 +14,7 @@ export default ['templateUrl', 'Rest', 'GetBasePath', 'generateList', '$compile' .then(kinds => { scope.credentialKinds = kinds; - scope.credentialKind = "" + kinds.Machine; + scope.credentialKind = scope.selectedCredentials.machine && scope.selectedCredentials.machine.readOnly ? (scope.selectedCredentials.vault && scope.selectedCredentials.vault.readOnly ? "" + kinds.Network : "" + kinds.Vault) : "" + kinds.Machine; scope.showModal = function() { $('#multi-credential-modal').modal('show'); @@ -50,6 +50,22 @@ export default ['templateUrl', 'Rest', 'GetBasePath', 'generateList', '$compile' .then(({credential_types, credentialTypeOptions}) => { scope.credential_types = credential_types; scope.credentialTypeOptions = credentialTypeOptions; + scope.allCredentialTypeOptions = _.cloneDeep(credentialTypeOptions); + + // We want to hide machine and vault dropdown options if a credential + // has already been selected for those types and the user interacting + // with the form doesn't have the ability to change them + for(let i=scope.credentialTypeOptions.length - 1; i >=0; i--) { + if((scope.selectedCredentials.machine && + scope.selectedCredentials.machine.credential_type_id === scope.credentialTypeOptions[i].value && + scope.selectedCredentials.machine.readOnly) || + (scope.selectedCredentials.vault && + scope.selectedCredentials.vault.credential_type_id === scope.credentialTypeOptions[i].value && + scope.selectedCredentials.vault.readOnly)) { + scope.credentialTypeOptions.splice(i, 1); + } + } + scope.$emit('multiCredentialModalLinked'); }); }); @@ -70,7 +86,7 @@ export default ['templateUrl', 'Rest', 'GetBasePath', 'generateList', '$compile' $scope.credTags = MultiCredentialService .updateCredentialTags($scope.selectedCredentials, - $scope.credentialTypeOptions); + $scope.allCredentialTypeOptions); }; let updateMachineCredentialList = function() { @@ -85,7 +101,7 @@ export default ['templateUrl', 'Rest', 'GetBasePath', 'generateList', '$compile' $scope.credTags = MultiCredentialService .updateCredentialTags($scope.selectedCredentials, - $scope.credentialTypeOptions); + $scope.allCredentialTypeOptions); }; let updateVaultCredentialList = function() { @@ -100,7 +116,7 @@ export default ['templateUrl', 'Rest', 'GetBasePath', 'generateList', '$compile' $scope.credTags = MultiCredentialService .updateCredentialTags($scope.selectedCredentials, - $scope.credentialTypeOptions); + $scope.allCredentialTypeOptions); }; let uncheckAllCredentials = function() { @@ -110,7 +126,7 @@ export default ['templateUrl', 'Rest', 'GetBasePath', 'generateList', '$compile' $scope.credTags = MultiCredentialService .updateCredentialTags($scope.selectedCredentials, - $scope.credentialTypeOptions); + $scope.allCredentialTypeOptions); }; let init = function() { diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html index 22fa0699f4..f14933339e 100644 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html +++ b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential-modal.partial.html @@ -27,13 +27,13 @@ class="MultiCredential-tagContainer ng-scope" ng-repeat="tag in credTags track by $index">
+ ng-click="removeCredential(tag.id)" + ng-if="!tag.readOnly">
-
+
diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less index 86db1b3fff..4f007ea2f4 100644 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less +++ b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.block.less @@ -51,6 +51,10 @@ padding-left: 15px; } +.MultiCredential-tag--disabled { + background-color: @default-icon; +} + .MultiCredential-tag--deletable { margin-right: 0px; border-top-left-radius: 0px; diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html index 6d51ae9ba1..912dc078a5 100644 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html +++ b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.partial.html @@ -23,12 +23,12 @@ ng-repeat="tag in credentialsToPost track by $index">
+ ng-hide="fieldIsDisabled || tag.readOnly">
+ ng-class="{'MultiCredential-tag--deletable': !fieldIsDisabled && !tag.readOnly, 'MultiCredential-tag--disabled': tag.readOnly}"> {{ tag.kind }} diff --git a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js index 644097b451..9cdf912956 100644 --- a/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js +++ b/awx/ui/client/src/templates/job_templates/multi-credential/multi-credential.service.js @@ -138,6 +138,7 @@ export default ['Rest', 'ProcessErrors', '$q', 'GetBasePath', function(Rest, Pro name: cred.name, id: cred.id, postType: cred.postType, + readOnly: cred.readOnly, kind: typeOpts .filter(type => { return parseInt(cred.credential_type) === type.value; @@ -190,6 +191,7 @@ export default ['Rest', 'ProcessErrors', '$q', 'GetBasePath', function(Rest, Pro /* User doesn't have read access to the machine credential, so use summary_fields */ selectedCredentials.machine = job_template_obj.summary_fields.credential; selectedCredentials.machine.credential_type = job_template_obj.summary_fields.credential.credential_type_id; + selectedCredentials.machine.readOnly = true; } else { ProcessErrors( null, data, status, null, @@ -214,6 +216,7 @@ export default ['Rest', 'ProcessErrors', '$q', 'GetBasePath', function(Rest, Pro /* User doesn't have read access to the vault credential, so use summary_fields */ selectedCredentials.vault = job_template_obj.summary_fields.vault_credential; selectedCredentials.vault.credential_type = job_template_obj.summary_fields.vault_credential.credential_type_id; + selectedCredentials.vault.readOnly = true; } else { ProcessErrors( null, data, status, null, @@ -240,6 +243,7 @@ export default ['Rest', 'ProcessErrors', '$q', 'GetBasePath', function(Rest, Pro selectedCredentials.extra = job_template_obj.summary_fields.extra_credentials; _.map(selectedCredentials.extra, (cred) => { cred.credential_type = cred.credential_type_id; + cred.readOnly = true; return cred; }); } else { diff --git a/awx/ui/client/src/templates/main.js b/awx/ui/client/src/templates/main.js index dbaf88d3e6..cd578d5d21 100644 --- a/awx/ui/client/src/templates/main.js +++ b/awx/ui/client/src/templates/main.js @@ -137,6 +137,61 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates. }, resolve: { edit: { + jobTemplateData: ['$stateParams', 'TemplatesService', 'ProcessErrors', + function($stateParams, TemplatesService, ProcessErrors) { + return TemplatesService.getJobTemplate($stateParams.job_template_id) + .then(function(res) { + return res.data; + }).catch(function(response){ + ProcessErrors(null, response.data, response.status, null, { + hdr: 'Error!', + msg: 'Failed to get job template. GET returned status: ' + + response.status + }); + }); + }], + canChangeProject: ['Rest', 'ProcessErrors', 'jobTemplateData', + function(Rest, ProcessErrors, jobTemplateData) { + Rest.setUrl(jobTemplateData.related.project); + return Rest.get() + .then(() => { + return true; + }) + .catch(({data, status}) => { + if (status === 403) { + /* User doesn't have read access to the project, no problem. */ + } else { + ProcessErrors(null, data, status, null, { + hdr: 'Error!', + msg: 'Failed to get project. GET returned ' + + 'status: ' + status + }); + } + + return false; + }); + }], + canChangeInventory: ['Rest', 'ProcessErrors', 'jobTemplateData', + function(Rest, ProcessErrors, jobTemplateData) { + Rest.setUrl(jobTemplateData.related.inventory); + return Rest.get() + .then(() => { + return true; + }) + .catch(({data, status}) => { + if (status === 403) { + /* User doesn't have read access to the project, no problem. */ + } else { + ProcessErrors(null, data, status, null, { + hdr: 'Error!', + msg: 'Failed to get project. GET returned ' + + 'status: ' + status + }); + } + + return false; + }); + }], InstanceGroupsData: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', function($stateParams, Rest, GetBasePath, ProcessErrors){ let path = `${GetBasePath('job_templates')}${$stateParams.job_template_id}/instance_groups/`; @@ -155,32 +210,32 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates. }); }); }], - availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService', - function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) { - return TemplatesService.getAllLabelOptions() - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get labels. GET returned status: ' + - response.status - }); + availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService', + function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) { + return TemplatesService.getAllLabelOptions() + .then(function(labels){ + return labels; + }).catch(function(response){ + ProcessErrors(null, response.data, response.status, null, { + hdr: 'Error!', + msg: 'Failed to get labels. GET returned status: ' + + response.status }); - }], - selectedLabels: ['Rest', '$stateParams', 'GetBasePath', 'TemplatesService', 'ProcessErrors', - function(Rest, $stateParams, GetBasePath, TemplatesService, ProcessErrors) { - return TemplatesService.getAllJobTemplateLabels($stateParams.job_template_id) - .then(function(labels){ - return labels; - }).catch(function(response){ - ProcessErrors(null, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get workflow job template labels. GET returned status: ' + - response.status - }); + }); + }], + selectedLabels: ['Rest', '$stateParams', 'GetBasePath', 'TemplatesService', 'ProcessErrors', + function(Rest, $stateParams, GetBasePath, TemplatesService, ProcessErrors) { + return TemplatesService.getAllJobTemplateLabels($stateParams.job_template_id) + .then(function(labels){ + return labels; + }).catch(function(response){ + ProcessErrors(null, response.data, response.status, null, { + hdr: 'Error!', + msg: 'Failed to get workflow job template labels. GET returned status: ' + + response.status }); - }] + }); + }] } } });