Added a lot of permissions related logic to the workflow form as well as the workflow maker. I know it's not perfect but its a step in the right direction.

This commit is contained in:
Michael Abashian
2016-11-10 16:43:23 -05:00
parent 59aeec5705
commit ca32c34036
13 changed files with 145 additions and 126 deletions

View File

@@ -33,7 +33,7 @@ export default
name: { name: {
label: i18n._('Name'), label: i18n._('Name'),
type: 'text', type: 'text',
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)', ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)',
required: true, required: true,
column: 1 column: 1
}, },
@@ -41,7 +41,7 @@ export default
label: i18n._('Description'), label: i18n._('Description'),
type: 'text', type: 'text',
column: 1, column: 1,
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
job_type: { job_type: {
label: i18n._('Job Type'), label: i18n._('Job Type'),
@@ -63,7 +63,7 @@ export default
ngShow: "!job_type.value || job_type.value !== 'scan'", ngShow: "!job_type.value || job_type.value !== 'scan'",
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
inventory: { inventory: {
label: i18n._('Inventory'), label: i18n._('Inventory'),
@@ -87,7 +87,7 @@ export default
ngShow: "!job_type.value || job_type.value !== 'scan'", ngShow: "!job_type.value || job_type.value !== 'scan'",
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
project: { project: {
label: i18n._('Project'), label: i18n._('Project'),
@@ -110,13 +110,13 @@ export default
dataTitle: i18n._('Project'), dataTitle: i18n._('Project'),
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
playbook: { playbook: {
label: i18n._('Playbook'), label: i18n._('Playbook'),
type:'select', type:'select',
ngOptions: 'book for book in playbook_options track by book', ngOptions: 'book for book in playbook_options track by book',
ngDisabled: "(job_type.value === 'scan' && project_name === 'Default') || !(job_template_obj.summary_fields.user_capabilities.edit || canAdd)", ngDisabled: "(job_type.value === 'scan' && project_name === 'Default') || !(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)",
id: 'playbook-select', id: 'playbook-select',
awRequiredWhen: { awRequiredWhen: {
reqExpression: "playbookrequired", reqExpression: "playbookrequired",
@@ -154,7 +154,7 @@ export default
variable: 'ask_credential_on_launch', variable: 'ask_credential_on_launch',
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
cloud_credential: { cloud_credential: {
label: i18n._('Cloud Credential'), label: i18n._('Cloud Credential'),
@@ -172,7 +172,7 @@ export default
dataTitle: i18n._('Cloud Credential'), dataTitle: i18n._('Cloud Credential'),
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
network_credential: { network_credential: {
label: i18n._('Network Credential'), label: i18n._('Network Credential'),
@@ -189,7 +189,7 @@ export default
dataTitle: i18n._('Network Credential'), dataTitle: i18n._('Network Credential'),
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
forks: { forks: {
label: i18n._('Forks'), label: i18n._('Forks'),
@@ -207,7 +207,7 @@ export default
dataTitle: i18n._('Forks'), dataTitle: i18n._('Forks'),
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' // TODO: get working
}, },
limit: { limit: {
label: i18n._('Limit'), label: i18n._('Limit'),
@@ -223,7 +223,7 @@ export default
variable: 'ask_limit_on_launch', variable: 'ask_limit_on_launch',
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
verbosity: { verbosity: {
label: i18n._('Verbosity'), label: i18n._('Verbosity'),
@@ -236,7 +236,7 @@ export default
dataTitle: i18n._('Verbosity'), dataTitle: i18n._('Verbosity'),
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
job_tags: { job_tags: {
label: i18n._('Job Tags'), label: i18n._('Job Tags'),
@@ -254,7 +254,7 @@ export default
variable: 'ask_tags_on_launch', variable: 'ask_tags_on_launch',
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
skip_tags: { skip_tags: {
label: i18n._('Skip Tags'), label: i18n._('Skip Tags'),
@@ -272,7 +272,7 @@ export default
variable: 'ask_skip_tags_on_launch', variable: 'ask_skip_tags_on_launch',
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
checkbox_group: { checkbox_group: {
label: i18n._('Options'), label: i18n._('Options'),
@@ -287,7 +287,7 @@ export default
dataTitle: i18n._('Become Privilege Escalation'), dataTitle: i18n._('Become Privilege Escalation'),
dataContainer: "body", dataContainer: "body",
labelClass: 'stack-inline', labelClass: 'stack-inline',
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, { }, {
name: 'allow_callbacks', name: 'allow_callbacks',
label: i18n._('Allow Provisioning Callbacks'), label: i18n._('Allow Provisioning Callbacks'),
@@ -300,7 +300,7 @@ export default
dataTitle: i18n._('Allow Provisioning Callbacks'), dataTitle: i18n._('Allow Provisioning Callbacks'),
dataContainer: "body", dataContainer: "body",
labelClass: 'stack-inline', labelClass: 'stack-inline',
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}] }]
}, },
callback_url: { callback_url: {
@@ -314,7 +314,7 @@ export default
dataPlacement: 'top', dataPlacement: 'top',
dataTitle: i18n._('Provisioning Callback URL'), dataTitle: i18n._('Provisioning Callback URL'),
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
host_config_key: { host_config_key: {
label: i18n._('Host Config Key'), label: i18n._('Host Config Key'),
@@ -328,7 +328,7 @@ export default
dataPlacement: 'right', dataPlacement: 'right',
dataTitle: i18n._("Host Config Key"), dataTitle: i18n._("Host Config Key"),
dataContainer: "body", dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
labels: { labels: {
label: i18n._('Labels'), label: i18n._('Labels'),
@@ -340,7 +340,7 @@ export default
dataPlacement: 'right', dataPlacement: 'right',
awPopOver: i18n._("<p>Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs in the Tower display.</p>"), awPopOver: i18n._("<p>Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs in the Tower display.</p>"),
dataContainer: 'body', dataContainer: 'body',
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
variables: { variables: {
label: i18n._('Extra Variables'), label: i18n._('Extra Variables'),
@@ -362,14 +362,14 @@ export default
variable: 'ask_variables_on_launch', variable: 'ask_variables_on_launch',
text: i18n._('Prompt on launch') text: i18n._('Prompt on launch')
}, },
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)' // TODO: get working
} }
}, },
buttons: { //for now always generates <button> tags buttons: { //for now always generates <button> tags
add_survey: { add_survey: {
ngClick: 'addSurvey()', ngClick: 'addSurvey()',
ngShow: 'job_type.value !== "scan" && !survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAdd)', ngShow: 'job_type.value !== "scan" && !survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)',
awFeature: 'surveys', awFeature: 'surveys',
awToolTip: '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.', awToolTip: '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.',
dataPlacement: 'top' dataPlacement: 'top'
@@ -377,25 +377,25 @@ export default
edit_survey: { edit_survey: {
ngClick: 'editSurvey()', ngClick: 'editSurvey()',
awFeature: 'surveys', awFeature: 'surveys',
ngShow: 'job_type.value !== "scan" && survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: 'job_type.value !== "scan" && survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
view_survey: { view_survey: {
ngClick: 'editSurvey()', ngClick: 'editSurvey()',
awFeature: 'surveys', awFeature: 'surveys',
ngShow: 'job_type.value !== "scan" && survey_exists && !(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: 'job_type.value !== "scan" && survey_exists && !(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
cancel: { cancel: {
ngClick: 'formCancel()', ngClick: 'formCancel()',
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
close: { close: {
ngClick: 'formCancel()', ngClick: 'formCancel()',
ngShow: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
}, },
save: { save: {
ngClick: 'formSave()', //$scope.function to call on click, optional ngClick: 'formSave()', //$scope.function to call on click, optional
ngDisabled: "job_templates_form.$invalid",//true //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons ngDisabled: "job_templates_form.$invalid",//true //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
} }
}, },
@@ -422,7 +422,7 @@ export default
awToolTip: 'Add a permission', awToolTip: 'Add a permission',
actionClass: 'btn List-buttonSubmit', actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD', buttonContent: '&#43; ADD',
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
} }
}, },

View File

@@ -28,6 +28,7 @@ export default
label: 'Type', label: 'Type',
type: 'radio_group', type: 'radio_group',
ngShow: 'selectedTemplate && showTypeOptions', ngShow: 'selectedTemplate && showTypeOptions',
ngDisabled: '!canAddWorkflowJobTemplate',
options: [ options: [
{ {
label: 'On&nbsp;Success', label: 'On&nbsp;Success',
@@ -63,6 +64,7 @@ export default
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngShow: "selectedTemplate.ask_credential_on_launch", ngShow: "selectedTemplate.ask_credential_on_launch",
ngDisabled: '!canAddWorkflowJobTemplate',
awRequiredWhen: { awRequiredWhen: {
reqExpression: 'selectedTemplate && selectedTemplate.ask_credential_on_launch' reqExpression: 'selectedTemplate && selectedTemplate.ask_credential_on_launch'
} }
@@ -82,6 +84,7 @@ export default
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngShow: "selectedTemplate.ask_inventory_on_launch", ngShow: "selectedTemplate.ask_inventory_on_launch",
ngDisabled: '!canAddWorkflowJobTemplate',
awRequiredWhen: { awRequiredWhen: {
reqExpression: 'selectedTemplate && selectedTemplate.ask_inventory_on_launch' reqExpression: 'selectedTemplate && selectedTemplate.ask_inventory_on_launch'
} }
@@ -100,6 +103,7 @@ export default
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngShow: "selectedTemplate.ask_job_type_on_launch", ngShow: "selectedTemplate.ask_job_type_on_launch",
ngDisabled: '!canAddWorkflowJobTemplate',
awRequiredWhen: { awRequiredWhen: {
reqExpression: 'selectedTemplate && selectedTemplate.ask_job_type_on_launch' reqExpression: 'selectedTemplate && selectedTemplate.ask_job_type_on_launch'
} }
@@ -114,7 +118,8 @@ export default
dataTitle: 'Limit', dataTitle: 'Limit',
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body", dataContainer: "body",
ngShow: "selectedTemplate.ask_limit_on_launch" ngShow: "selectedTemplate.ask_limit_on_launch",
ngDisabled: '!canAddWorkflowJobTemplate'
}, },
job_tags: { job_tags: {
label: 'Job Tags', label: 'Job Tags',
@@ -128,7 +133,8 @@ export default
dataTitle: "Job Tags", dataTitle: "Job Tags",
dataPlacement: "right", dataPlacement: "right",
dataContainer: "body", dataContainer: "body",
ngShow: "selectedTemplate.ask_tags_on_launch" ngShow: "selectedTemplate.ask_tags_on_launch",
ngDisabled: '!canAddWorkflowJobTemplate'
}, },
skip_tags: { skip_tags: {
label: 'Skip Tags', label: 'Skip Tags',
@@ -142,16 +148,23 @@ export default
dataTitle: "Skip Tags", dataTitle: "Skip Tags",
dataPlacement: "right", dataPlacement: "right",
dataContainer: "body", dataContainer: "body",
ngShow: "selectedTemplate.ask_skip_tags_on_launch" ngShow: "selectedTemplate.ask_skip_tags_on_launch",
ngDisabled: '!canAddWorkflowJobTemplate'
} }
}, },
buttons: { buttons: {
cancel: { cancel: {
ngClick: 'cancelNodeForm()' ngClick: 'cancelNodeForm()',
ngShow: 'canAddWorkflowJobTemplate'
},
close: {
ngClick: 'cancelNodeForm()',
ngShow: '!canAddWorkflowJobTemplate'
}, },
save: { save: {
ngClick: 'saveNodeForm()', ngClick: 'saveNodeForm()',
ngDisabled: "workflow_maker_form.$invalid || !selectedTemplate" ngDisabled: "workflow_maker_form.$invalid || !selectedTemplate",
ngShow: 'canAddWorkflowJobTemplate'
} }
} }
}) })

View File

@@ -29,14 +29,15 @@ export default
name: { name: {
label: 'Name', label: 'Name',
type: 'text', type: 'text',
addRequired: true, required: true,
editRequired: true, ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)',
column: 1 column: 1
}, },
description: { description: {
label: 'Description', label: 'Description',
type: 'text', type: 'text',
column: 1 column: 1,
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
}, },
organization: { organization: {
label: 'Organization', label: 'Organization',
@@ -48,7 +49,8 @@ export default
dataTitle: 'Organization', dataTitle: 'Organization',
dataContainer: 'body', dataContainer: 'body',
dataPlacement: 'right', dataPlacement: 'right',
column: 1 column: 1,
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
}, },
labels: { labels: {
label: 'Labels', label: 'Labels',
@@ -59,7 +61,8 @@ export default
dataTitle: 'Labels', dataTitle: 'Labels',
dataPlacement: 'right', dataPlacement: 'right',
awPopOver: "<p>Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs in the Tower display.</p>", awPopOver: "<p>Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs in the Tower display.</p>",
dataContainer: 'body' dataContainer: 'body',
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
}, },
variables: { variables: {
label: 'Extra Variables', label: 'Extra Variables',
@@ -76,17 +79,24 @@ export default
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n", "<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n",
dataTitle: 'Extra Variables', dataTitle: 'Extra Variables',
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body" dataContainer: "body",
ngDisabled: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)' // TODO: get working
} }
}, },
buttons: { //for now always generates <button> tags buttons: { //for now always generates <button> tags
cancel: { cancel: {
ngClick: 'formCancel()' ngClick: 'formCancel()',
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
},
close: {
ngClick: 'formCancel()',
ngShow: '!(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
}, },
save: { save: {
ngClick: 'formSave()', //$scope.function to call on click, optional ngClick: 'formSave()', //$scope.function to call on click, optional
ngDisabled: "workflow_form.$invalid || can_edit!==true"//true //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons ngDisabled: "workflow_form.$invalid || can_edit!==true", //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons
ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
} }
}, },
@@ -108,7 +118,7 @@ export default
awToolTip: 'Add a permission', awToolTip: 'Add a permission',
actionClass: 'btn List-buttonSubmit', actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD', buttonContent: '&#43; ADD',
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' ngShow: '(workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)'
} }
}, },

View File

@@ -31,7 +31,7 @@ export default
$scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) { $scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) {
if (val === false) { if (val === false) {
$scope.canAdd = false; $scope.canAddJobTemplate = false;
} }
}); });

View File

@@ -20,7 +20,7 @@
$scope.$watch('workflow_job_template_obj.summary_fields.user_capabilities.edit', function(val) { $scope.$watch('workflow_job_template_obj.summary_fields.user_capabilities.edit', function(val) {
if (val === false) { if (val === false) {
$scope.canAdd = false; $scope.canAddWorkflowJobTemplate = false;
} }
}); });
@@ -125,13 +125,6 @@
} }
function init() { function init() {
// // Inject the edit form
// generator.inject(form, {
// mode: 'edit' ,
// scope: $scope,
// related: false
// });
// generator.reset();
// Select2-ify the lables input // Select2-ify the lables input
CreateSelect2({ CreateSelect2({
@@ -140,24 +133,6 @@
addNew: true addNew: true
}); });
// // Make the variables textarea look nice
// ParseTypeChange({
// scope: $scope,
// field_id: 'workflow_job_template_variables',
// onChange: function() {
// $scope[form.name + '_form'].$setDirty();
// }
// });
// // Initialize the organization lookup
// LookUpInit({
// scope: $scope,
// form: form,
// list: OrganizationList,
// field: 'organization',
// input_type: 'radio'
// });
Rest.setUrl('api/v1/labels'); Rest.setUrl('api/v1/labels');
Wait("start"); Wait("start");
Rest.get() Rest.get()

View File

@@ -22,8 +22,13 @@ export default ['$scope', '$rootScope', '$location', '$stateParams', 'Rest', 'Al
$scope.canAdd = false; $scope.canAdd = false;
rbacUiControlService.canAdd("job_templates") rbacUiControlService.canAdd("job_templates")
.then(function(canAdd) { .then(function(canAddJobTemplate) {
$scope.canAdd = canAdd; $scope.canAddJobTemplate = canAddJobTemplate;
});
rbacUiControlService.canAdd("workflow_job_templates")
.then(function(canAddWorkflowJobTemplate) {
$scope.canAddWorkflowJobTemplate = canAddWorkflowJobTemplate;
}); });
// search init // search init
$scope.list = list; $scope.list = list;

View File

@@ -108,7 +108,7 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp
}, },
views: { views: {
'modal': { 'modal': {
template: ` <workflow-maker ng-if="includeWorkflowMaker" tree-data="workflowTree"></workflow-maker>` template: ` <workflow-maker ng-if="includeWorkflowMaker" tree-data="workflowTree" can-add-workflow-job-template="canAddWorkflowJobTemplate"></workflow-maker>`
}, },
'jobTemplateList@templates.editWorkflowJobTemplate.workflowMaker': { 'jobTemplateList@templates.editWorkflowJobTemplate.workflowMaker': {
templateProvider: function(WorkflowMakerJobTemplateList, generateList) { templateProvider: function(WorkflowMakerJobTemplateList, generateList) {
@@ -260,8 +260,8 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp
}); });
return html; return html;
}, },
controller: ['$scope', controller: ['$scope', '$timeout', 'CreateSelect2',
function($scope) { function($scope, $timeout, CreateSelect2) {
function resetPromptFields() { function resetPromptFields() {
$scope.credential = null; $scope.credential = null;
$scope.credential_name = null; $scope.credential_name = null;
@@ -296,6 +296,14 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp
_.forOwn(options.presetValues, function(value, key) { _.forOwn(options.presetValues, function(value, key) {
$scope[key] = value; $scope[key] = value;
}); });
// The default needs to be in place before we can select2-ify the dropdown
$timeout(function() {
CreateSelect2({
element: '#workflow_maker_job_type',
multiple: false
});
});
}); });
$scope.$on('setEdgeType', function(e, edgeType) { $scope.$on('setEdgeType', function(e, edgeType) {

View File

@@ -10,6 +10,7 @@ export default [
return { return {
scope: { scope: {
treeData: '=', treeData: '=',
canAddWorkflowJobTemplate: '=',
addNode: '&', addNode: '&',
editNode: '&', editNode: '&',
deleteNode: '&' deleteNode: '&'
@@ -17,7 +18,12 @@ export default [
restrict: 'E', restrict: 'E',
link: function(scope, element) { link: function(scope, element) {
var margin = {top: 20, right: 20, bottom: 20, left: 20}, scope.$watch('canAddWorkflowJobTemplate', function() {
// Redraw the graph if permissions change
update();
});
let margin = {top: 20, right: 20, bottom: 20, left: 20},
width = 950, width = 950,
height = 590 - margin.top - margin.bottom, height = 590 - margin.top - margin.bottom,
i = 0, i = 0,
@@ -26,21 +32,21 @@ export default [
rootW = 60, rootW = 60,
rootH = 40; rootH = 40;
var tree = d3.layout.tree() let tree = d3.layout.tree()
.size([height, width]); .size([height, width]);
var line = d3.svg.line() let line = d3.svg.line()
.x(function(d){return d.x;}) .x(function(d){return d.x;})
.y(function(d){return d.y;}); .y(function(d){return d.y;});
function lineData(d){ function lineData(d){
var sourceX = d.source.isStartNode ? d.source.y + rootW : d.source.y + rectW; let sourceX = d.source.isStartNode ? d.source.y + rootW : d.source.y + rectW;
var sourceY = d.source.isStartNode ? d.source.x + 10 + rootH / 2 : d.source.x + rectH / 2; let sourceY = d.source.isStartNode ? d.source.x + 10 + rootH / 2 : d.source.x + rectH / 2;
var targetX = d.target.y; let targetX = d.target.y;
var targetY = d.target.x + rectH / 2; let targetY = d.target.x + rectH / 2;
var points = [ let points = [
{ {
x: sourceX, x: sourceX,
y: sourceY y: sourceY
@@ -65,23 +71,23 @@ export default [
} }
} }
var svg = d3.select(element[0]).append("svg") let svg = d3.select(element[0]).append("svg")
.attr("width", width) .attr("width", width)
.attr("height", height) .attr("height", height)
.attr("class", "WorkflowChart-svg") .attr("class", "WorkflowChart-svg")
.append("g") .append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var node = svg.selectAll(".node"), let node = svg.selectAll(".node"),
link = svg.selectAll(".link"); link = svg.selectAll(".link");
function update() { function update() {
// Declare the nodes // Declare the nodes
var nodes = tree.nodes(scope.treeData); let nodes = tree.nodes(scope.treeData);
node = node.data(nodes, function(d) { d.y = d.depth * 180; return d.id || (d.id = ++i); }); node = node.data(nodes, function(d) { d.y = d.depth * 180; return d.id || (d.id = ++i); });
link = link.data(tree.links(nodes), function(d) { return d.source.id + "-" + d.target.id; }); link = link.data(tree.links(nodes), function(d) { return d.source.id + "-" + d.target.id; });
var nodeEnter = node.enter().append("g") let nodeEnter = node.enter().append("g")
.attr("class", "node") .attr("class", "node")
.attr("id", function(d){return "node-" + d.id;}) .attr("id", function(d){return "node-" + d.id;})
.attr("parent", function(d){return d.parent ? d.parent.id : null;}) .attr("parent", function(d){return d.parent ? d.parent.id : null;})
@@ -89,7 +95,7 @@ export default [
.attr("fill", "red"); .attr("fill", "red");
nodeEnter.each(function(d) { nodeEnter.each(function(d) {
var thisNode = d3.select(this); let thisNode = d3.select(this);
if(d.isStartNode) { if(d.isStartNode) {
thisNode.append("rect") thisNode.append("rect")
.attr("width", 60) .attr("width", 60)
@@ -174,7 +180,7 @@ export default [
.attr("cx", rectW) .attr("cx", rectW)
.attr("r", 10) .attr("r", 10)
.attr("class", "addCircle nodeCircle") .attr("class", "addCircle nodeCircle")
.style("display", function(d) { return d.placeholder ? "none" : null; }) .style("display", function(d) { return d.placeholder || scope.canAddWorkflowJobTemplate === false ? "none" : null; })
.call(add_node) .call(add_node)
.on("mouseover", function(d) { .on("mouseover", function(d) {
d3.select("#node-" + d.id) d3.select("#node-" + d.id)
@@ -196,7 +202,7 @@ export default [
.size(60) .size(60)
.type("cross") .type("cross")
) )
.style("display", function(d) { return d.placeholder ? "none" : null; }) .style("display", function(d) { return d.placeholder || scope.canAddWorkflowJobTemplate === false ? "none" : null; })
.call(add_node) .call(add_node)
.on("mouseover", function(d) { .on("mouseover", function(d) {
d3.select("#node-" + d.id) d3.select("#node-" + d.id)
@@ -216,7 +222,7 @@ export default [
.attr("cy", rectH) .attr("cy", rectH)
.attr("r", 10) .attr("r", 10)
.attr("class", "removeCircle") .attr("class", "removeCircle")
.style("display", function(d) { return (d.canDelete === false || d.placeholder) ? "none" : null; }) .style("display", function(d) { return (d.canDelete === false || d.placeholder || scope.canAddWorkflowJobTemplate === false) ? "none" : null; })
.call(remove_node) .call(remove_node)
.on("mouseover", function(d) { .on("mouseover", function(d) {
d3.select("#node-" + d.id) d3.select("#node-" + d.id)
@@ -238,7 +244,7 @@ export default [
.size(60) .size(60)
.type("cross") .type("cross")
) )
.style("display", function(d) { return (d.canDelete === false || d.placeholder) ? "none" : null; }) .style("display", function(d) { return (d.canDelete === false || d.placeholder || scope.canAddWorkflowJobTemplate === false) ? "none" : null; })
.call(remove_node) .call(remove_node)
.on("mouseover", function(d) { .on("mouseover", function(d) {
d3.select("#node-" + d.id) d3.select("#node-" + d.id)
@@ -257,7 +263,7 @@ export default [
node.exit().remove(); node.exit().remove();
var linkEnter = link.enter().append("g") let linkEnter = link.enter().append("g")
.attr("class", "nodeConnector") .attr("class", "nodeConnector")
.attr("id", function(d){return "link-" + d.source.id + "-" + d.target.id;}); .attr("id", function(d){return "link-" + d.source.id + "-" + d.target.id;});
@@ -294,7 +300,7 @@ export default [
}) })
.attr("r", 10) .attr("r", 10)
.attr("class", "addCircle linkCircle") .attr("class", "addCircle linkCircle")
.style("display", function(d) { return (d.source.placeholder || d.target.placeholder) ? "none" : null; }) .style("display", function(d) { return (d.source.placeholder || d.target.placeholder || scope.canAddWorkflowJobTemplate === false) ? "none" : null; })
.call(add_node_between) .call(add_node_between)
.on("mouseover", function(d) { .on("mouseover", function(d) {
d3.select("#link-" + d.source.id + "-" + d.target.id) d3.select("#link-" + d.source.id + "-" + d.target.id)
@@ -317,7 +323,7 @@ export default [
.size(60) .size(60)
.type("cross") .type("cross")
) )
.style("display", function(d) { return (d.source.placeholder || d.target.placeholder) ? "none" : null; }) .style("display", function(d) { return (d.source.placeholder || d.target.placeholder || scope.canAddWorkflowJobTemplate === false) ? "none" : null; })
.call(add_node_between) .call(add_node_between)
.on("mouseover", function(d) { .on("mouseover", function(d) {
d3.select("#link-" + d.source.id + "-" + d.target.id) d3.select("#link-" + d.source.id + "-" + d.target.id)
@@ -335,19 +341,19 @@ export default [
link.exit().remove(); link.exit().remove();
// Transition nodes and links to their new positions. // Transition nodes and links to their new positions.
var t = svg.transition(); let t = svg.transition();
t.selectAll(".nodeCircle") t.selectAll(".nodeCircle")
.style("display", function(d) { return d.placeholder ? "none" : null; }); .style("display", function(d) { return d.placeholder || scope.canAddWorkflowJobTemplate === false ? "none" : null; });
t.selectAll(".nodeAddCross") t.selectAll(".nodeAddCross")
.style("display", function(d) { return d.placeholder ? "none" : null; }); .style("display", function(d) { return d.placeholder || scope.canAddWorkflowJobTemplate === false ? "none" : null; });
t.selectAll(".removeCircle") t.selectAll(".removeCircle")
.style("display", function(d) { return (d.canDelete === false || d.placeholder) ? "none" : null; }); .style("display", function(d) { return (d.canDelete === false || d.placeholder || scope.canAddWorkflowJobTemplate === false) ? "none" : null; });
t.selectAll(".nodeRemoveCross") t.selectAll(".nodeRemoveCross")
.style("display", function(d) { return (d.canDelete === false || d.placeholder) ? "none" : null; }); .style("display", function(d) { return (d.canDelete === false || d.placeholder || scope.canAddWorkflowJobTemplate === false) ? "none" : null; });
t.selectAll(".link") t.selectAll(".link")
.attr("class", function(d) { .attr("class", function(d) {
@@ -412,27 +418,33 @@ export default [
function add_node() { function add_node() {
this.on("click", function(d) { this.on("click", function(d) {
scope.addNode({ if(scope.canAddWorkflowJobTemplate !== false) {
parent: d, scope.addNode({
betweenTwoNodes: false parent: d,
}); betweenTwoNodes: false
});
}
}); });
} }
function add_node_between() { function add_node_between() {
this.on("click", function(d) { this.on("click", function(d) {
scope.addNode({ if(scope.canAddWorkflowJobTemplate !== false) {
parent: d, scope.addNode({
betweenTwoNodes: true parent: d,
}); betweenTwoNodes: true
});
}
}); });
} }
function remove_node() { function remove_node() {
this.on("click", function(d) { this.on("click", function(d) {
scope.deleteNode({ if(scope.canAddWorkflowJobTemplate !== false) {
nodeToDelete: d scope.deleteNode({
}); nodeToDelete: d
});
}
}); });
} }

View File

@@ -7,11 +7,11 @@
export default ['$scope', 'WorkflowHelpService', 'generateList', 'JobTemplateList', 'ProjectList', export default ['$scope', 'WorkflowHelpService', 'generateList', 'JobTemplateList', 'ProjectList',
'GetBasePath', 'Wait', 'JobTemplateService', '$state', 'GetBasePath', 'Wait', 'JobTemplateService', '$state',
'ProcessErrors', 'InventorySourcesList', 'CreateSelect2', 'WorkflowMakerForm', 'ProcessErrors', 'InventorySourcesList', 'CreateSelect2', 'WorkflowMakerForm',
'GenerateForm', 'InventoryList', 'CredentialList', '$q', '$timeout', 'GenerateForm', 'InventoryList', 'CredentialList', '$q',
function($scope, WorkflowHelpService, GenerateList, JobTemplateList, ProjectList, function($scope, WorkflowHelpService, GenerateList, JobTemplateList, ProjectList,
GetBasePath, Wait, JobTemplateService, $state, GetBasePath, Wait, JobTemplateService, $state,
ProcessErrors, InventorySourcesList, CreateSelect2, WorkflowMakerForm, ProcessErrors, InventorySourcesList, CreateSelect2, WorkflowMakerForm,
GenerateForm, InventoryList, CredentialList, $q, $timeout) { GenerateForm, InventoryList, CredentialList, $q) {
let form = WorkflowMakerForm(); let form = WorkflowMakerForm();
@@ -274,13 +274,6 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'JobTemplateLis
}; };
} }
// The default needs to be in place before we can select2-ify the dropdown
$timeout(function() {
CreateSelect2({
element: '#workflow_maker_job_type',
multiple: false
});
});
} }
if ($scope.nodeBeingEdited.unifiedJobTemplate.ask_limit_on_launch) { if ($scope.nodeBeingEdited.unifiedJobTemplate.ask_limit_on_launch) {

View File

@@ -10,7 +10,8 @@ export default ['templateUrl', 'CreateDialog', 'Wait',
function(templateUrl, CreateDialog, Wait) { function(templateUrl, CreateDialog, Wait) {
return { return {
scope: { scope: {
treeData: '=' treeData: '=',
canAddWorkflowJobTemplate: '='
}, },
restrict: 'E', restrict: 'E',
templateUrl: templateUrl('job-templates/workflow-maker/workflow-maker'), templateUrl: templateUrl('job-templates/workflow-maker/workflow-maker'),

View File

@@ -60,7 +60,7 @@
<span class="badge List-titleBadge" ng-bind="treeData.data.totalNodes"></span> <span class="badge List-titleBadge" ng-bind="treeData.data.totalNodes"></span>
</div> </div>
</div> </div>
<workflow-chart tree-data="treeData.data" add-node="startAddNode(parent, betweenTwoNodes)" edit-node="startEditNode(nodeToEdit)" delete-node="startDeleteNode(nodeToDelete)" class="WorkflowMaker-chart"></workflow-chart> <workflow-chart tree-data="treeData.data" add-node="startAddNode(parent, betweenTwoNodes)" edit-node="startEditNode(nodeToEdit)" delete-node="startDeleteNode(nodeToDelete)" can-add-workflow-job-template="canAddWorkflowJobTemplate" class="WorkflowMaker-chart"></workflow-chart>
</div> </div>
<div class="WorkflowMaker-contentRight"> <div class="WorkflowMaker-contentRight">
<div class="WorkflowMaker-formTitle">{{(workflowMakerFormConfig.nodeMode === 'edit' && nodeBeingEdited && nodeBeingEdited.unifiedJobTemplate && nodeBeingEdited.unifiedJobTemplate.name) ? nodeBeingEdited.unifiedJobTemplate.name : "ADD A TEMPLATE"}}</div> <div class="WorkflowMaker-formTitle">{{(workflowMakerFormConfig.nodeMode === 'edit' && nodeBeingEdited && nodeBeingEdited.unifiedJobTemplate && nodeBeingEdited.unifiedJobTemplate.name) ? nodeBeingEdited.unifiedJobTemplate.name : "ADD A TEMPLATE"}}</div>
@@ -82,6 +82,6 @@
</div> </div>
<div class="WorkflowMaker-buttonHolder"> <div class="WorkflowMaker-buttonHolder">
<button type="button" class="btn btn-sm WorkflowMaker-cancelButton" ng-click="closeWorkflowMaker()"> Close</button> <button type="button" class="btn btn-sm WorkflowMaker-cancelButton" ng-click="closeWorkflowMaker()"> Close</button>
<button type="button" class="btn btn-sm WorkflowMaker-saveButton" ng-click="saveWorkflowMaker()"> Save</button> <button type="button" class="btn btn-sm WorkflowMaker-saveButton" ng-click="saveWorkflowMaker()" ng-show="workflow_job_template_obj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate"> Save</button>
</div> </div>
</div> </div>

View File

@@ -64,14 +64,16 @@ export default
options: [ options: [
{ {
optionContent: 'Job Template', optionContent: 'Job Template',
optionSref: 'templates.addJobTemplate' optionSref: 'templates.addJobTemplate',
ngShow: 'canAddJobTemplate'
}, },
{ {
optionContent: 'Workflow Job Template', optionContent: 'Workflow Job Template',
optionSref: 'templates.addWorkflowJobTemplate' optionSref: 'templates.addWorkflowJobTemplate',
ngShow: 'canAddWorkflowJobTemplate'
} }
], ],
ngShow: 'canAdd' ngShow: 'canAddJobTemplate || canAddWorkflowJobTemplate'
} }
}, },

View File

@@ -10,7 +10,7 @@
</button> </button>
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
<li ng-repeat="option in options.options"> <li ng-repeat="option in options.options">
<a ui-sref="{{option.optionSref}}" ng-bind-html="option.optionContent"></a> <a ui-sref="{{option.optionSref}}" ng-bind-html="option.optionContent" ng-show="{{option.ngShow}}"></a>
</li> </li>
</ul> </ul>
</div> </div>
@@ -37,7 +37,7 @@
</button> </button>
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
<li ng-repeat="option in options.options"> <li ng-repeat="option in options.options">
<a ui-sref="{{option.optionSref}}" ng-bind-html="option.optionContent"></a> <a ui-sref="{{option.optionSref}}" ng-bind-html="option.optionContent" ng-show="{{option.ngShow}}"></a>
</li> </li>
</ul> </ul>
</div> </div>