1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Merge pull request #4178 from mabashian/3583-copy-workflow

Implemented WFJT copy and moved JT copy away from a viewless route
This commit is contained in:
Michael Abashian 2016-12-01 09:20:54 -05:00 committed by GitHub
commit 3d56c2b50f
11 changed files with 162 additions and 83 deletions

View File

@ -27,21 +27,21 @@ export default
first_name: {
label: i18n._('First Name'),
type: 'text',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)',
required: true,
capitalize: true
},
last_name: {
label: i18n._('Last Name'),
type: 'text',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)',
required: true,
capitalize: true
},
email: {
label: i18n._('Email'),
type: 'email',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)',
required: true,
autocomplete: false
},
@ -53,7 +53,7 @@ export default
init: true
},
autocomplete: false,
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
organization: {
label: i18n._('Organization'),
@ -64,7 +64,7 @@ export default
sourceField: 'name',
required: true,
excludeMode: 'edit',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
password: {
label: i18n._('Password'),
@ -76,7 +76,7 @@ export default
ngChange: "clearPWConfirm('password_confirm')",
autocomplete: false,
chkPass: true,
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
password_confirm: {
label: i18n._('Confirm Password'),
@ -88,7 +88,7 @@ export default
awPassMatch: true,
associated: 'password',
autocomplete: false,
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
user_type: {
label: i18n._('User Type'),
@ -97,23 +97,23 @@ export default
disableChooseOption: true,
ngModel: 'user_type',
ngShow: 'current_user["is_superuser"]',
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
},
buttons: {
cancel: {
ngClick: 'formCancel()',
ngShow: '(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngShow: '(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
close: {
ngClick: 'formCancel()',
ngShow: '!(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngShow: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
},
save: {
ngClick: 'formSave()',
ngDisabled: true,
ngShow: '(user_obj.summary_fields.user_capabilities.edit || !canAdd)'
ngShow: '(user_obj.summary_fields.user_capabilities.edit || canAdd)'
}
},

View File

@ -98,7 +98,7 @@ export default
},
copy: {
label: i18n._('Copy'),
'ui-sref': 'templates.copy({id: template.id})',
ngClick: 'copyTemplate(template)',
"class": 'btn-danger btn-xs',
awToolTip: i18n._('Copy template'),
dataPlacement: 'top',

View File

@ -99,6 +99,21 @@
color: @btn-txt-sel;
}
.Modal-primaryButton {
background-color: @default-link;
color: @default-bg;
text-transform: uppercase;
border-radius: 5px;
transition: background-color 0.2s;
padding-left:15px;
padding-right: 15px;
}
.Modal-primaryButton:hover {
background-color: @default-link-hov;
color: @default-bg;
}
.Modal-errorButton:focus {
color: @btn-txt-sel;
}

View File

@ -47,7 +47,7 @@ angular.module('PromptDialog', ['Utilities', 'sanitizeFilter'])
cls = (params['class'] === null || params['class'] === undefined) ? 'Modal-errorButton' : params['class'];
$('#prompt_action_btn').removeClass(cls).addClass(cls);
$('#prompt_action_btn').removeClass('Modal-errorButton Modal-primaryButton').addClass(cls);
// bootstrap modal's have an open defect with disallowing tab index's of the background of the modal
// This will keep the tab indexing on the modal's focus. This is to fix an issue with tabbing working when

View File

@ -39,7 +39,7 @@
return Rest.post(data.results[0])
.success(function(job_template_res){
// also copy any associated survey_spec
if (data.results[0].related.survey_spec){
if (data.results[0].summary_fields.survey){
return self.copySurvey(data.results[0], job_template_res).success( () => job_template_res);
}
else{
@ -54,6 +54,22 @@
buildName: function(name){
var result = name.split('@')[0];
return result;
},
getWorkflowCopy: function(id) {
let url = GetBasePath('workflow_job_templates');
url = url + id + '/copy';
Rest.setUrl(url);
return Rest.get();
},
copyWorkflow: function(id) {
let url = GetBasePath('workflow_job_templates');
url = url + id + '/copy';
Rest.setUrl(url);
return Rest.post();
}
};
}

View File

@ -1,36 +0,0 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default
[ 'Wait', '$state', '$scope', 'jobTemplateCopyService',
'ProcessErrors', '$rootScope',
function(Wait, $state, $scope, jobTemplateCopyService,
ProcessErrors, $rootScope){
// GETs the job_template to copy
// POSTs a new job_template
// routes to JobTemplates.edit when finished
var init = function(){
Wait('start');
jobTemplateCopyService.get($state.params.id)
.success(function(res){
jobTemplateCopyService.set(res)
.success(function(res){
Wait('stop');
if(res.type && res.type === 'job_template') {
$state.go('templates.editJobTemplate', {id: res.id}, {reload: true});
}
// Workflow edit to be implemented post 3.1 but we'll need to handle the
// state transition for that here
});
})
.error(function(res, status){
ProcessErrors($rootScope, res, status, null, {hdr: 'Error!',
msg: 'Call failed. Return status: '+ status});
});
};
init();
}
];

View File

@ -1,12 +0,0 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default {
name: 'templates.copy',
route: '/:id/copy',
controller: 'jobTemplateCopyController'
};

View File

@ -1,17 +0,0 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import controller from './job-templates-copy.controller';
import route from './job-templates-copy.route';
import service from './job-templates-copy.service';
export default
angular.module('templates.copy', [])
.service('jobTemplateCopyService', service)
.controller('jobTemplateCopyController', controller)
.run(['$stateExtender', function($stateExtender) {
$stateExtender.addState(route);
}]);

View File

@ -7,12 +7,12 @@
export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Alert',
'TemplateList', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath',
'InitiatePlaybookRun', 'Wait', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'TemplatesService',
'QuerySet', 'GetChoices',
'QuerySet', 'GetChoices', 'TemplateCopyService',
function(
$scope, $rootScope, $location, $stateParams, Rest, Alert,
TemplateList, Prompt, ClearScope, ProcessErrors, GetBasePath,
InitiatePlaybookRun, Wait, $state, $filter, Dataset, rbacUiControlService, TemplatesService,
qs, GetChoices
qs, GetChoices, TemplateCopyService
) {
ClearScope();
@ -192,5 +192,101 @@ export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Al
Alert('Error: Unable to schedule job', 'Template parameter is missing');
}
};
$scope.copyTemplate = function(template) {
if(template) {
if(template.type && template.type === 'job_template') {
Wait('start');
TemplateCopyService.get(template.id)
.success(function(res){
TemplateCopyService.set(res)
.success(function(res){
Wait('stop');
if(res.type && res.type === 'job_template') {
$state.go('templates.editJobTemplate', {job_template_id: res.id}, {reload: true});
}
});
})
.error(function(res, status){
ProcessErrors($rootScope, res, 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.warnings || _.isEmpty(result.data.warnings)) {
// 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});
}, function (data) {
Wait('stop');
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Call to copy template failed. POST returned status: ' + status });
});
}
else {
let bodyHtml = `
<div class="Prompt-bodyQuery">
You may not have access to all resources used by this workflow. Resources that you don\'t have access to will not be copied and may result in an incomplete workflow.
</div>
<div class="Prompt-bodyTarget">`;
// Go and grab all of the warning strings
_.forOwn(result.data.warnings, function(warning) {
if(warning) {
_.forOwn(warning, function(warningString) {
bodyHtml += '<div>' + warningString + '</div>';
});
}
} );
bodyHtml += '</div>';
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');
}
};
}
];

View File

@ -9,7 +9,6 @@ import surveyMaker from './survey-maker/main';
import templatesList from './list/main';
import jobTemplatesAdd from './job_templates/add-job-template/main';
import jobTemplatesEdit from './job_templates/edit-job-template/main';
import jobTemplatesCopy from './job_templates/copy-job-template/main';
import workflowAdd from './workflows/add-workflow/main';
import workflowEdit from './workflows/edit-workflow/main';
import labels from './labels/main';
@ -17,14 +16,16 @@ import workflowChart from './workflows/workflow-chart/main';
import workflowMaker from './workflows/workflow-maker/main';
import templatesListRoute from './list/templates-list.route';
import workflowService from './workflows/workflow.service';
import templateCopyService from './copy-template/template-copy.service';
export default
angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesAdd.name,
jobTemplatesEdit.name, jobTemplatesCopy.name, labels.name, workflowAdd.name, workflowEdit.name,
jobTemplatesEdit.name, labels.name, workflowAdd.name, workflowEdit.name,
workflowChart.name, workflowMaker.name
])
.service('TemplatesService', templatesService)
.service('WorkflowService', workflowService)
.service('TemplateCopyService', templateCopyService)
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) {
let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow,

View File

@ -185,6 +185,22 @@ export default ['Rest', 'GetBasePath', '$q', function(Rest, GetBasePath, $q){
Rest.setUrl(url);
return Rest.get();
},
getWorkflowCopy: function(id) {
let url = GetBasePath('workflow_job_templates');
url = url + id + '/copy';
Rest.setUrl(url);
return Rest.get();
},
copyWorkflow: function(id) {
let url = GetBasePath('workflow_job_templates');
url = url + id + '/copy';
Rest.setUrl(url);
return Rest.post();
}
};
}];