From cfba11f8d799b3fd5e2ce1954cc233b3b0a75db4 Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Sun, 3 Dec 2017 23:26:58 -0500 Subject: [PATCH] slight cleanup of templates list controller lint / fix all of the indentation issues smaller functions use a variable for any string a user sees --- .../templates/list-templates.controller.js | 723 ++++++++++-------- 1 file changed, 406 insertions(+), 317 deletions(-) diff --git a/awx/ui/client/features/templates/list-templates.controller.js b/awx/ui/client/features/templates/list-templates.controller.js index 1f6e156e4a..9e5d2b18ef 100644 --- a/awx/ui/client/features/templates/list-templates.controller.js +++ b/awx/ui/client/features/templates/list-templates.controller.js @@ -1,91 +1,403 @@ -function ListTemplatesController (model, JobTemplate, WorkflowJobTemplate, strings, $state, $scope, rbacUiControlService, Dataset, $filter, Alert, InitiatePlaybookRun, Prompt, Wait, ProcessErrors, TemplateCopyService, $q, Empty, i18n, PromptService) { - const vm = this || {}, - unifiedJobTemplate = model, - jobTemplate = new JobTemplate(), - workflowJobTemplate = new WorkflowJobTemplate(); +/** *********************************************** + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + ************************************************ */ - vm.strings = strings; +const ALERT_MISSING = 'Template parameter is missing'; +const ALERT_NO_PERMISSION = 'You do not have permission to perform this action.'; +const ALERT_UNKNOWN = 'We were unable to determine this template\'s type'; +const ALERT_UNKNOWN_COPY = `${ALERT_UNKNOWN} while copying.`; +const ALERT_UNKNOWN_DELETE = `${ALERT_UNKNOWN} while deleting.`; +const ALERT_UNKNOWN_EDIT = `${ALERT_UNKNOWN} while routing to edit.`; +const ALERT_UNKNOWN_LAUNCH = `${ALERT_UNKNOWN} while launching.`; +const ALERT_UNKNOWN_SCHEDULE = `${ALERT_UNKNOWN} while routing to schedule.`; +const ERROR_EDIT = 'Error: Unable to edit template'; +const ERROR_DELETE = 'Error: Unable to delete template'; +const ERROR_LAUNCH = 'Error: Unable to launch template'; +const ERROR_UNKNOWN = 'Error: Unable to determine template type'; +const ERROR_JOB_SCHEDULE = 'Error: Unable to schedule job'; +const ERROR_TEMPLATE_COPY = 'Error: Unable to copy job template'; +const ERROR_WORKFLOW_COPY = 'Error: Unable to copy workflow job template'; - // TODO: add the permission based functionality to the base model - $scope.canAdd = false; - rbacUiControlService.canAdd("job_templates") - .then(function(params) { - $scope.canAddJobTemplate = params.canAdd; - }); - rbacUiControlService.canAdd("workflow_job_templates") - .then(function(params) { +const JOB_TEMPLATE_ALIASES = ['job_template', 'Job Template']; +const WORKFLOW_TEMPLATE_ALIASES = ['workflow_job_template', 'Workflow Job Template']; + +const isJobTemplate = obj => _.includes(JOB_TEMPLATE_ALIASES, _.get(obj, 'type')); +const isWorkflowTemplate = obj => _.includes(WORKFLOW_TEMPLATE_ALIASES, _.get(obj, 'type')); + +function TemplatesListController ( + $scope, + $rootScope, + Alert, + TemplateList, + Prompt, + ProcessErrors, + GetBasePath, + InitiatePlaybookRun, + Wait, + $state, + $filter, + Dataset, + rbacUiControlService, + TemplatesService, + qs, + i18n, + JobTemplate, + WorkflowJobTemplate, + TemplatesStrings, + $q, + Empty, + i18n, + PromptService, +) { + const jobTemplate = new JobTemplate(); + const list = TemplateList; + + init(); + + function init () { + $scope.canAdd = false; + + rbacUiControlService.canAdd('job_templates').then(params => { + $scope.canAddJobTemplate = params.canAdd; + }); + + rbacUiControlService.canAdd('workflow_job_templates').then(params => { $scope.canAddWorkflowJobTemplate = params.canAdd; }); - $scope.$watchGroup(["canAddJobTemplate", "canAddWorkflowJobTemplate"], function() { - if ($scope.canAddJobTemplate || $scope.canAddWorkflowJobTemplate) { - $scope.canAdd = true; + + // search init + $scope.list = list; + $scope[`${list.iterator}_dataset`] = Dataset.data; + $scope[list.name] = $scope[`${list.iterator}_dataset`].results; + $scope.options = {}; + + $rootScope.flashMessage = null; + } + + $scope.$on(`${list.iterator}_options`, (event, data) => { + $scope.options = data.data.actions.GET; + optionsRequestDataProcessing(); + }); + + $scope.$watchCollection('templates', () => { + optionsRequestDataProcessing(); + }); + + $scope.$on('ws-jobs', () => { + const path = GetBasePath(list.basePath) || GetBasePath(list.name); + qs.search(path, $state.params[`${list.iterator}_search`]) + .then(searchResponse => { + $scope[`${list.iterator}_dataset`] = searchResponse.data; + $scope[list.name] = $scope[`${list.iterator}_dataset`].results; + }); + }); + + // iterate over the list and add fields like type label, after the + // OPTIONS request returns, or the list is sorted/paginated/searched + function optionsRequestDataProcessing () { + $scope[list.name].forEach((item, idx) => { + const itm = $scope[list.name][idx]; + // Set the item type label + if (list.fields.type && _.has($scope.options, 'type.choices')) { + $scope.options.type.choices.forEach(choice => { + if (choice[0] === item.type) { + [itm.type_label] = choice; + } + }); + } + }); + } + + $scope.editJobTemplate = template => { + if (!template) { + Alert(ERROR_EDIT, ALERT_MISSING); + return; + } + + if (isJobTemplate(template)) { + $state.transitionTo('templates.editJobTemplate', { job_template_id: template.id }); + } else if (isWorkflowTemplate(template)) { + $state.transitionTo('templates.editWorkflowJobTemplate', { workflow_job_template_id: template.id }); } else { - $scope.canAdd = false; + Alert(ERROR_UNKNOWN, ALERT_UNKNOWN_EDIT); } - }); - - $scope.list = { - iterator: 'template', - name: 'templates' - }; - $scope.collection = { - basePath: 'unified_job_templates', - iterator: 'template' - }; - $scope[`${$scope.list.iterator}_dataset`] = Dataset.data; - $scope[$scope.list.name] = $scope[`${$scope.list.iterator}_dataset`].results; - $scope.$on('updateDataset', function(e, dataset) { - $scope[`${$scope.list.iterator}_dataset`] = dataset; - $scope[$scope.list.name] = dataset.results; - }); - - // get modified date and user who modified it - vm.getModified = function(template) { - let val = ""; - if (template.modified) { - val += $filter('longDate')(template.modified); - } - if (_.has(template, 'summary_fields.modified_by.username')) { - val += ` by ${template.summary_fields.modified_by.username}`; - } - if (val === "") { - val = undefined; - } - return val; }; - // get last ran date and user who ran it - vm.getRan = function(template) { - let val = ""; - if (template.last_job_run) { - val += $filter('longDate')(template.last_job_run); + $scope.submitJob = template => { + if (!template) { + Alert(ERROR_LAUNCH, ALERT_MISSING); + return; } - // TODO: when API gives back a user who last ran the job in summary fields, uncomment and - // update this code - // if (template && template.summary_fields && template.summary_fields.modified_by && - // template.summary_fields.modified_by.username) { - // val += ` by ${template.summary_fields.modified_by.username}`; - // } - - if (val === "") { - val = undefined; + if (isJobTemplate(template)) { + submitJobTemplate(template) + } else if (isWorkflowTemplate(template)) { + InitiatePlaybookRun({ scope: $scope, id: template.id, job_type: 'workflow_job_template' }); + } else { + Alert(ERROR_UNKNOWN, ALERT_UNKNOWN_LAUNCH); } - return val; }; - // get pretified template type names from options - vm.templateTypes = unifiedJobTemplate.options('actions.GET.type.choices') - .reduce((acc, i) => { - acc[i[0]] = i[1]; - return acc; - }, {}); + $scope.scheduleJob = template => { + if (!template) { + Alert(ERROR_JOB_SCHEDULE, ALERT_MISSING); + return; + } - // get if you should show the active indicator for the row or not - // TODO: edit indicator doesn't update when you enter edit route after initial load right now - vm.activeId = parseInt($state.params.job_template_id || $state.params.workflow_template_id); + if (isJobTemplate(template)) { + $state.go('jobTemplateSchedules', { id: template.id }); + } else if (isWorkflowTemplate(template)) { + $state.go('workflowJobTemplateSchedules', { id: template.id }); + } else { + Alert(ERROR_UNKNOWN, ALERT_UNKNOWN_SCHEDULE); + } + }; - vm.submitJob = function(template) { + $scope.deleteJobTemplate = template => { + if (!template) { + Alert(ERROR_DELETE, ALERT_MISSING); + return; + } + + if (isWorkflowTemplate(template)) { + const body = TemplatesStrings.get('deleteResource.CONFIRM', 'workflow job template'); + $scope.displayTemplateDeletePrompt(template, body); + } else if (isJobTemplate(template)) { + jobTemplate.getDependentResourceCounts(template.id) + .then(counts => { + const body = buildTemplateDeletePromptHTML(counts); + $scope.displayTemplateDeletePrompt(template, body); + }); + } else { + Alert(ERROR_UNKNOWN, ALERT_UNKNOWN_DELETE); + } + }; + + $scope.copyTemplate = template => { + if (!template) { + Alert(ERROR_TEMPLATE_COPY, ALERT_MISSING); + return; + } + + if (isJobTemplate(template)) { + $scope.copyJobTemplate(template); + } else if (isWorkflowTemplate(template)) { + $scope.copyWorkflowJobTemplate(template); + } else { + Alert(ERROR_UNKNOWN, ALERT_UNKNOWN_COPY); + } + }; + + $scope.copyJobTemplate = template => { + Wait('start'); + new JobTemplate('get', template.id) + .then(model => model.copy()) + .then(({ id }) => { + const params = { job_template_id: id }; + $state.go('templates.editJobTemplate', params, { reload: true }); + }) + .catch(({ data, status }) => { + const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; + ProcessErrors($scope, data, status, null, params); + }) + .finally(() => Wait('stop')); + }; + + $scope.copyWorkflowJobTemplate = template => { + Wait('start'); + new WorkflowJobTemplate('get', template.id) + .then(model => model.extend('GET', 'copy')) + .then(model => { + const action = () => { + model.copy() + .then(({ id }) => { + const params = { workflow_job_template_id: id }; + $state.go('templates.editWorkflowJobTemplate', params, { reload: true }); + }) + .catch(({ data, status }) => { + const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; + ProcessErrors($scope, data, status, null, params); + }); + }; + if (model.get('related.copy.can_copy_without_user_input')) { + action(); + } else if (model.get('related.copy.can_copy')) { + Prompt({ + hdr: 'Copy Workflow', + action, + actionText: 'COPY', + class: 'Modal-primaryButton', + body: buildWorkflowCopyPromptHTML(model.get('related.copy')) + }); + } else { + Alert(ERROR_WORKFLOW_COPY, ALERT_NO_PERMISSION); + } + }) + .catch(({ data, status }) => { + const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; + ProcessErrors($scope, data, status, null, params); + }) + .finally(() => Wait('stop')); + }; + + $scope.displayTemplateDeletePrompt = (template, body) => { + const action = () => { + function handleSuccessfulDelete (isWorkflow) { + let reloadListStateParams = null; + let stateParamID; + + if (isWorkflow) { + stateParamID = $state.params.workflow_job_template_id; + } else { + stateParamID = $state.params.job_template_id; + } + + const templateSearch = _.get($state.params, 'template_search'); + const { page } = templateSearch; + + if ($scope.templates.length === 1 && !_.isEmpty(page) && page !== '1') { + reloadListStateParams = _.cloneDeep($state.params); + + const pageNum = (parseInt(reloadListStateParams.template_search.page, 0) - 1); + reloadListStateParams.template_search.page = pageNum.toString(); + } + + if (parseInt(stateParamID, 0) === template.id) { + $state.go('templates', reloadListStateParams, { reload: true }); + } else { + $state.go('.', reloadListStateParams, { reload: true }); + } + + Wait('stop'); + } // end handler + + let deleteServiceMethod; + let failMsg; + + if (isWorkflowTemplate(template)) { + deleteServiceMethod = TemplatesService.deleteWorkflowJobTemplate; + failMsg = 'Call to delete workflow job template failed. DELETE returned status: '; + } else if (isJobTemplate(template)) { + deleteServiceMethod = TemplatesService.deleteJobTemplate; + failMsg = 'Call to delete job template failed. DELETE returned status: '; + } else { + Alert(ERROR_UNKNOWN, ALERT_UNKNOWN_DELETE); + return; + } + + $('#prompt-modal').modal('hide'); + Wait('start'); + + deleteServiceMethod(template.id) + .then(() => handleSuccessfulDelete(isWorkflowTemplate(template))) + .catch(res => { + ProcessErrors($scope, res.data, res.status, null, { + hdr: 'Error!', + msg: `${failMsg} ${res.status}.` + }); + }); + }; // end action + + Prompt({ + action, + actionText: 'DELETE', + body, + hdr: i18n._('Delete'), + resourceName: $filter('sanitize')(template.name) + }); + }; + + function buildTemplateDeletePromptHTML (dependentResourceCounts) { + const invalidateRelatedLines = []; + + let bodyHTML = ` +
+ ${TemplatesStrings.get('deleteResource.CONFIRM', 'job template')} +
`; + + dependentResourceCounts.forEach(countObj => { + if (countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
+ + ${countObj.label} + + + ${countObj.count} + +
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + bodyHTML = ` +
+ ${TemplatesStrings.get('deleteResource.USED_BY', 'job template')} + ${TemplatesStrings.get('deleteResource.CONFIRM', 'job template')} +
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + bodyHTML += invalidateRelatedLine; + }); + } + + return bodyHTML; + } + + function buildWorkflowCopyPromptHTML (data) { + const { + credentials_unable_to_copy, + inventories_unable_to_copy, + job_templates_unable_to_copy + } = data; + + let itemsHTML = ''; + + if (job_templates_unable_to_copy.length > 0) { + itemsHTML += '
Unified Job Templates that cannot be copied
'; + } + + if (inventories_unable_to_copy.length > 0) { + itemsHTML += '
Node prompted inventories that cannot be copied
'; + } + + if (credentials_unable_to_copy.length > 0) { + itemsHTML += '
Node prompted credentials that cannot be copied
'; + } + + const bodyHTML = ` +
+ You do not have access to all resources used by this workflow. + Resources that you don't have access to will not be copied + and will result in an incomplete workflow. +
+
+ ${itemsHTML} +
+ `; + + return bodyHTML; + } + + function submitJobTemplate(template) { if(template) { if(template.type && (template.type === 'Job Template' || template.type === 'job_template')) { let jobTemplate = new JobTemplate(); @@ -149,7 +461,7 @@ function ListTemplatesController (model, JobTemplate, WorkflowJobTemplate, strin else { Alert('Error: Unable to launch template', 'Template parameter is missing'); } - }; + } $scope.launchJob = () => { @@ -219,255 +531,32 @@ function ListTemplatesController (model, JobTemplate, WorkflowJobTemplate, strin msg: i18n.sprintf(i18n._('Failed to launch job template. POST returned: %d'), $scope.promptData.template, status) }); }); }; - - vm.scheduleJob = (template) => { - if(template) { - if(template.type && (template.type === 'Job Template' || template.type === 'job_template')) { - $state.go('jobTemplateSchedules', {id: template.id}); - } - else if(template.type && (template.type === 'Workflow Job Template' || template.type === 'workflow_job_template')) { - $state.go('workflowJobTemplateSchedules', {id: template.id}); - } - else { - // Something went wrong Let the user know that we're unable to redirect to schedule because we don't know - // what type of job template this is - Alert('Error: Unable to determine template type', 'We were unable to determine this template\'s type while routing to schedule.'); - } - } - else { - Alert('Error: Unable to schedule job', 'Template parameter is missing'); - } - }; - - vm.scheduleJob = (template) => { - if(template) { - if(template.type && (template.type === 'Job Template' || template.type === 'job_template')) { - $state.go('jobTemplateSchedules', {id: template.id}); - } - else if(template.type && (template.type === 'Workflow Job Template' || template.type === 'workflow_job_template')) { - $state.go('workflowJobTemplateSchedules', {id: template.id}); - } - else { - // Something went wrong Let the user know that we're unable to redirect to schedule because we don't know - // what type of job template this is - Alert('Error: Unable to determine template type', 'We were unable to determine this template\'s type while routing to schedule.'); - } - } - else { - Alert('Error: Unable to schedule job', 'Template parameter is missing'); - } - }; - - vm.copyTemplate = function(template) { - - if(template) { - if(template.type && template.type === 'job_template') { - Wait('start'); - TemplateCopyService.get(template.id) - .then(function(response){ - TemplateCopyService.set(response.data.results) - .then(function(results){ - Wait('stop'); - if(results.type && results.type === 'job_template') { - $state.go('templates.editJobTemplate', {job_template_id: results.id}, {reload: true}); - } - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: 'Error!', - msg: 'Call failed. Return status: ' + status - }); - }); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, {hdr: 'Error!', - msg: 'Call failed. Return status: '+ status}); - }); - } - else if(template.type && template.type === 'workflow_job_template') { - TemplateCopyService.getWorkflowCopy(template.id) - .then(function(result) { - - if(result.data.can_copy) { - if(result.data.can_copy_without_user_input) { - // Go ahead and copy the workflow - the user has full priveleges on all the resources - TemplateCopyService.copyWorkflow(template.id) - .then(function(result) { - $state.go('templates.editWorkflowJobTemplate', {workflow_job_template_id: result.data.id}, {reload: true}); - }) - .catch(function (response) { - Wait('stop'); - ProcessErrors($scope, response.data, response.status, null, { hdr: 'Error!', - msg: 'Call to copy workflow job template failed. Return status: ' + response.status + '.'}); - }); - } - else { - - let bodyHtml = ` -
- You do not have access to all resources used by this workflow. Resources that you don\'t have access to will not be copied and will result in an incomplete workflow. -
-
`; - - // List the unified job templates user can not access - if (result.data.templates_unable_to_copy.length > 0) { - bodyHtml += '
Unified Job Templates that can not be copied
    '; - _.forOwn(result.data.templates_unable_to_copy, function(ujt) { - if(ujt) { - bodyHtml += '
  • ' + ujt + '
  • '; - } - }); - bodyHtml += '
'; - } - // List the prompted inventories user can not access - if (result.data.inventories_unable_to_copy.length > 0) { - bodyHtml += '
Node prompted inventories that can not be copied
    '; - _.forOwn(result.data.inventories_unable_to_copy, function(inv) { - if(inv) { - bodyHtml += '
  • ' + inv + '
  • '; - } - }); - bodyHtml += '
'; - } - // List the prompted credentials user can not access - if (result.data.credentials_unable_to_copy.length > 0) { - bodyHtml += '
Node prompted credentials that can not be copied
    '; - _.forOwn(result.data.credentials_unable_to_copy, function(cred) { - if(cred) { - bodyHtml += '
  • ' + cred + '
  • '; - } - }); - bodyHtml += '
'; - } - - bodyHtml += '
'; - - - Prompt({ - hdr: 'Copy Workflow', - body: bodyHtml, - action: function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - TemplateCopyService.copyWorkflow(template.id) - .then(function(result) { - Wait('stop'); - $state.go('templates.editWorkflowJobTemplate', {workflow_job_template_id: result.data.id}, {reload: true}); - }, function (data) { - Wait('stop'); - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Call to copy template failed. POST returned status: ' + status }); - }); - }, - actionText: 'COPY', - class: 'Modal-primaryButton' - }); - } - } - else { - Alert('Error: Unable to copy workflow job template', 'You do not have permission to perform this action.'); - } - }, function (data) { - Wait('stop'); - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Call to copy template failed. GET returned status: ' + status }); - }); - } - else { - // Something went wrong - Let the user know that we're unable to copy because we don't know - // what type of job template this is - Alert('Error: Unable to determine template type', 'We were unable to determine this template\'s type while copying.'); - } - } - else { - Alert('Error: Unable to copy job', 'Template parameter is missing'); - } - }; - - vm.deleteTemplate = function(template) { - var action = function() { - $('#prompt-modal').modal('hide'); - Wait('start'); - - let deleteComplete = () => { - let reloadListStateParams = null; - - if($scope.templates.length === 1 && $state.params.template_search && !_.isEmpty($state.params.template_search.page) && $state.params.template_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.template_search.page = (parseInt(reloadListStateParams.template_search.page)-1).toString(); - } - - if (parseInt($state.params.template_id) === template.id) { - $state.go("^", reloadListStateParams, { reload: true }); - } else { - $state.go('.', reloadListStateParams, {reload: true}); - } - }; - - if(template.type === "job_template") { - jobTemplate.request('delete', template.id) - .then(() => { - deleteComplete(); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', {path: "" + unifiedJobTemplate.path + template.id, status}) - }); - }) - .finally(function() { - Wait('stop'); - }); - } else if(template.type === "workflow_job_template") { - workflowJobTemplate.request('delete', template.id) - .then(() => { - deleteComplete(); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: strings.get('error.HEADER'), - msg: strings.get('error.CALL', {path: "" + unifiedJobTemplate.path + template.id, status}) - }); - }) - .finally(function() { - Wait('stop'); - }); - } - - }; - - let deleteModalBody = `
${strings.get('deleteResource.CONFIRM', 'template')}
`; - - Prompt({ - hdr: strings.get('deleteResource.HEADER'), - resourceName: $filter('sanitize')(template.name), - body: deleteModalBody, - action: action, - actionText: 'DELETE' - }); - }; } -ListTemplatesController.$inject = [ - 'resolvedModels', +TemplatesListController.$inject = [ + '$scope', + '$rootScope', + 'Alert', + 'TemplateList', + 'Prompt', + 'ProcessErrors', + 'GetBasePath', + 'InitiatePlaybookRun', + 'Wait', + '$state', + '$filter', + 'Dataset', + 'rbacUiControlService', + 'TemplatesService', + 'QuerySet', + 'i18n', 'JobTemplateModel', 'WorkflowJobTemplateModel', 'TemplatesStrings', - '$state', - '$scope', - 'rbacUiControlService', - 'Dataset', - '$filter', - 'Alert', - 'InitiatePlaybookRun', - 'Prompt', - 'Wait', - 'ProcessErrors', - 'TemplateCopyService', - '$q', + '$q,' 'Empty', 'i18n', - 'PromptService' + 'PromptService', ]; -export default ListTemplatesController; +export default TemplatesListController; \ No newline at end of file