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

Implemented WFJT copy and moved JT copy away from a viewless route

This commit is contained in:
Michael Abashian 2016-11-30 16:54:06 -05:00
parent 5cf0b8929f
commit 089f369cc4
11 changed files with 161 additions and 81 deletions

View File

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

View File

@ -99,6 +99,21 @@
color: @btn-txt-sel; 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 { .Modal-errorButton:focus {
color: @btn-txt-sel; 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']; 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 // 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 // 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]) return Rest.post(data.results[0])
.success(function(job_template_res){ .success(function(job_template_res){
// also copy any associated survey_spec // 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); return self.copySurvey(data.results[0], job_template_res).success( () => job_template_res);
} }
else{ else{
@ -54,6 +54,22 @@
buildName: function(name){ buildName: function(name){
var result = name.split('@')[0]; var result = name.split('@')[0];
return result; 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', export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Alert',
'TemplateList', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'TemplateList', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath',
'InitiatePlaybookRun', 'Wait', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'TemplatesService', 'InitiatePlaybookRun', 'Wait', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'TemplatesService',
'QuerySet', 'GetChoices', 'QuerySet', 'GetChoices', 'TemplateCopyService',
function( function(
$scope, $rootScope, $location, $stateParams, Rest, Alert, $scope, $rootScope, $location, $stateParams, Rest, Alert,
TemplateList, Prompt, ClearScope, ProcessErrors, GetBasePath, TemplateList, Prompt, ClearScope, ProcessErrors, GetBasePath,
InitiatePlaybookRun, Wait, $state, $filter, Dataset, rbacUiControlService, TemplatesService, InitiatePlaybookRun, Wait, $state, $filter, Dataset, rbacUiControlService, TemplatesService,
qs, GetChoices qs, GetChoices, TemplateCopyService
) { ) {
ClearScope(); ClearScope();
@ -192,5 +192,101 @@ export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Al
Alert('Error: Unable to schedule job', 'Template parameter is missing'); 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

@ -17,6 +17,7 @@ import workflowChart from './workflows/workflow-chart/main';
import workflowMaker from './workflows/workflow-maker/main'; import workflowMaker from './workflows/workflow-maker/main';
import templatesListRoute from './list/templates-list.route'; import templatesListRoute from './list/templates-list.route';
import workflowService from './workflows/workflow.service'; import workflowService from './workflows/workflow.service';
import templateCopyService from './copy-template/templay-copy.service';
export default export default
angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesAdd.name, angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesAdd.name,
@ -25,6 +26,7 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesA
]) ])
.service('TemplatesService', templatesService) .service('TemplatesService', templatesService)
.service('WorkflowService', workflowService) .service('WorkflowService', workflowService)
.service('TemplateCopyService', templateCopyService)
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) {
let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow, let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow,

View File

@ -185,6 +185,22 @@ export default ['Rest', 'GetBasePath', '$q', function(Rest, GetBasePath, $q){
Rest.setUrl(url); Rest.setUrl(url);
return Rest.get(); 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();
} }
}; };
}]; }];