mirror of
https://github.com/ansible/awx.git
synced 2026-03-26 05:15:02 -02:30
Merge pull request #4389 from mabashian/4165-add-edit-node-audit
Add/Edit workflow from audit items
This commit is contained in:
@@ -170,7 +170,7 @@ export default
|
|||||||
ngClick: 'cancelNodeForm()',
|
ngClick: 'cancelNodeForm()',
|
||||||
ngShow: '!canAddWorkflowJobTemplate'
|
ngShow: '!canAddWorkflowJobTemplate'
|
||||||
},
|
},
|
||||||
save: {
|
select: {
|
||||||
ngClick: 'saveNodeForm()',
|
ngClick: 'saveNodeForm()',
|
||||||
ngDisabled: "workflow_maker_form.$invalid || !selectedTemplate",
|
ngDisabled: "workflow_maker_form.$invalid || !selectedTemplate",
|
||||||
ngShow: 'canAddWorkflowJobTemplate'
|
ngShow: 'canAddWorkflowJobTemplate'
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ export default
|
|||||||
.factory('WorkflowFormObject', ['i18n', function(i18n) {
|
.factory('WorkflowFormObject', ['i18n', function(i18n) {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
addTitle: i18n._('New Workflow'),
|
addTitle: i18n._('New Workflow Job Template'),
|
||||||
editTitle: '{{ name }}',
|
editTitle: '{{ name }}',
|
||||||
name: 'workflow_job_template',
|
name: 'workflow_job_template',
|
||||||
|
breadcrumbName: i18n._('WORKFLOW'),
|
||||||
base: 'workflow',
|
base: 'workflow',
|
||||||
basePath: 'workflow_job_templates',
|
basePath: 'workflow_job_templates',
|
||||||
// the top-most node of generated state tree
|
// the top-most node of generated state tree
|
||||||
|
|||||||
@@ -1687,6 +1687,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
button.label = i18n._('Save');
|
button.label = i18n._('Save');
|
||||||
button['class'] = 'Form-saveButton';
|
button['class'] = 'Form-saveButton';
|
||||||
}
|
}
|
||||||
|
if (btn === 'select') {
|
||||||
|
button.label = i18n._('Select');
|
||||||
|
button['class'] = 'Form-saveButton';
|
||||||
|
}
|
||||||
if (btn === 'cancel') {
|
if (btn === 'cancel') {
|
||||||
button.label = i18n._('Cancel');
|
button.label = i18n._('Cancel');
|
||||||
button['class'] = 'Form-cancelButton';
|
button['class'] = 'Form-cancelButton';
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button ng-click="cancelForm()" class="Lookup-cancel btn btn-default">Cancel</button>
|
<button ng-click="cancelForm()" class="Lookup-cancel btn btn-default">Cancel</button>
|
||||||
<button ng-click="saveForm()" class="Lookup-save btn btn-primary">Save</button>
|
<button ng-click="saveForm()" class="Lookup-save btn btn-primary" ng-bind="list.lookupConfirmText ? list.lookupConfirmText : 'Save'"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -401,8 +401,10 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesA
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
ListDefinition: ['InventoryList', function(list) {
|
ListDefinition: ['InventoryList', function(InventoryList) {
|
||||||
// mutate the provided list definition here
|
// mutate the provided list definition here
|
||||||
|
let list = _.cloneDeep(InventoryList);
|
||||||
|
list.lookupConfirmText = 'SELECT';
|
||||||
return list;
|
return list;
|
||||||
}],
|
}],
|
||||||
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath',
|
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath',
|
||||||
@@ -451,8 +453,9 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesA
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
ListDefinition: ['CredentialList', function(list) {
|
ListDefinition: ['CredentialList', function(CredentialList) {
|
||||||
// mutate the provided list definition here
|
let list = _.cloneDeep(CredentialList);
|
||||||
|
list.lookupConfirmText = 'SELECT';
|
||||||
return list;
|
return list;
|
||||||
}],
|
}],
|
||||||
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath',
|
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath',
|
||||||
|
|||||||
@@ -33,10 +33,6 @@
|
|||||||
$scope.parseType = 'yaml';
|
$scope.parseType = 'yaml';
|
||||||
$scope.includeWorkflowMaker = false;
|
$scope.includeWorkflowMaker = false;
|
||||||
|
|
||||||
$scope.editRequests = [];
|
|
||||||
$scope.associateRequests = [];
|
|
||||||
$scope.disassociateRequests = [];
|
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
|
||||||
// Select2-ify the lables input
|
// Select2-ify the lables input
|
||||||
@@ -111,33 +107,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get the workflow nodes
|
|
||||||
TemplatesService.getWorkflowJobTemplateNodes(id)
|
|
||||||
.then(function(data){
|
|
||||||
|
|
||||||
$scope.workflowTree = WorkflowService.buildTree({
|
|
||||||
workflowNodes: data.data.results
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: I think that the workflow chart directive (and eventually d3) is meddling with
|
|
||||||
// this workflowTree object and removing the children object for some reason (?)
|
|
||||||
// This happens on occasion and I think is a race condition (?)
|
|
||||||
if(!$scope.workflowTree.data.children) {
|
|
||||||
$scope.workflowTree.data.children = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the partial, the workflow maker directive has an ng-if attribute which is pointed at this scope variable.
|
|
||||||
// It won't get included until this the tree has been built - I'm open to better ways of doing this.
|
|
||||||
$scope.includeWorkflowMaker = true;
|
|
||||||
|
|
||||||
}, function(error){
|
|
||||||
ProcessErrors($scope, error.data, error.status, form, {
|
|
||||||
hdr: 'Error!',
|
|
||||||
msg: 'Failed to get workflow job template nodes. GET returned ' +
|
|
||||||
'status: ' + error.status
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Go out and GET the workflow job temlate data needed to populate the form
|
// Go out and GET the workflow job temlate data needed to populate the form
|
||||||
TemplatesService.getWorkflowJobTemplate(id)
|
TemplatesService.getWorkflowJobTemplate(id)
|
||||||
.then(function(data){
|
.then(function(data){
|
||||||
@@ -180,6 +149,35 @@
|
|||||||
$scope.url = workflowJobTemplateData.url;
|
$scope.url = workflowJobTemplateData.url;
|
||||||
$scope.survey_enabled = workflowJobTemplateData.survey_enabled;
|
$scope.survey_enabled = workflowJobTemplateData.survey_enabled;
|
||||||
|
|
||||||
|
// Get the workflow nodes
|
||||||
|
TemplatesService.getWorkflowJobTemplateNodes(id)
|
||||||
|
.then(function(data){
|
||||||
|
|
||||||
|
$scope.workflowTree = WorkflowService.buildTree({
|
||||||
|
workflowNodes: data.data.results
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: I think that the workflow chart directive (and eventually d3) is meddling with
|
||||||
|
// this workflowTree object and removing the children object for some reason (?)
|
||||||
|
// This happens on occasion and I think is a race condition (?)
|
||||||
|
if(!$scope.workflowTree.data.children) {
|
||||||
|
$scope.workflowTree.data.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.workflowTree.workflow_job_template_obj = $scope.workflow_job_template_obj;
|
||||||
|
|
||||||
|
// In the partial, the workflow maker directive has an ng-if attribute which is pointed at this scope variable.
|
||||||
|
// It won't get included until this the tree has been built - I'm open to better ways of doing this.
|
||||||
|
$scope.includeWorkflowMaker = true;
|
||||||
|
|
||||||
|
}, function(error){
|
||||||
|
ProcessErrors($scope, error.data, error.status, form, {
|
||||||
|
hdr: 'Error!',
|
||||||
|
msg: 'Failed to get workflow job template nodes. GET returned ' +
|
||||||
|
'status: ' + error.status
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}, function(error){
|
}, function(error){
|
||||||
ProcessErrors($scope, error.data, error.status, form, {
|
ProcessErrors($scope, error.data, error.status, form, {
|
||||||
hdr: 'Error!',
|
hdr: 'Error!',
|
||||||
@@ -189,160 +187,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function recursiveNodeUpdates(params, completionCallback) {
|
|
||||||
// params.parentId
|
|
||||||
// params.node
|
|
||||||
|
|
||||||
let generatePostUrl = function(){
|
|
||||||
|
|
||||||
let base = (params.parentId) ? GetBasePath('workflow_job_template_nodes') + params.parentId : $scope.workflow_job_template_obj.related.workflow_nodes;
|
|
||||||
|
|
||||||
if(params.parentId) {
|
|
||||||
if(params.node.edgeType === 'success') {
|
|
||||||
base += "/success_nodes";
|
|
||||||
}
|
|
||||||
else if(params.node.edgeType === 'failure') {
|
|
||||||
base += "/failure_nodes";
|
|
||||||
}
|
|
||||||
else if(params.node.edgeType === 'always') {
|
|
||||||
base += "/always_nodes";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
let buildSendableNodeData = function() {
|
|
||||||
// Create the node
|
|
||||||
let sendableNodeData = {
|
|
||||||
unified_job_template: params.node.unifiedJobTemplate.id
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check to see if the user has provided any prompt values that are different
|
|
||||||
// from the defaults in the job template
|
|
||||||
|
|
||||||
if(params.node.unifiedJobTemplate.type === "job_template" && params.node.promptValues) {
|
|
||||||
if(params.node.unifiedJobTemplate.ask_credential_on_launch) {
|
|
||||||
sendableNodeData.credential = !params.node.promptValues.credential || params.node.unifiedJobTemplate.summary_fields.credential.id !== params.node.promptValues.credential.id ? params.node.promptValues.credential.id : null;
|
|
||||||
}
|
|
||||||
if(params.node.unifiedJobTemplate.ask_inventory_on_launch) {
|
|
||||||
sendableNodeData.inventory = !params.node.promptValues.inventory || params.node.unifiedJobTemplate.summary_fields.inventory.id !== params.node.promptValues.inventory.id ? params.node.promptValues.inventory.id : null;
|
|
||||||
}
|
|
||||||
if(params.node.unifiedJobTemplate.ask_limit_on_launch) {
|
|
||||||
sendableNodeData.limit = !params.node.promptValues.limit || params.node.unifiedJobTemplate.limit !== params.node.promptValues.limit ? params.node.promptValues.limit : null;
|
|
||||||
}
|
|
||||||
if(params.node.unifiedJobTemplate.ask_job_type_on_launch) {
|
|
||||||
sendableNodeData.job_type = !params.node.promptValues.job_type || params.node.unifiedJobTemplate.job_type !== params.node.promptValues.job_type ? params.node.promptValues.job_type : null;
|
|
||||||
}
|
|
||||||
if(params.node.unifiedJobTemplate.ask_tags_on_launch) {
|
|
||||||
sendableNodeData.job_tags = !params.node.promptValues.job_tags || params.node.unifiedJobTemplate.job_tags !== params.node.promptValues.job_tags ? params.node.promptValues.job_tags : null;
|
|
||||||
}
|
|
||||||
if(params.node.unifiedJobTemplate.ask_skip_tags_on_launch) {
|
|
||||||
sendableNodeData.skip_tags = !params.node.promptValues.skip_tags || params.node.unifiedJobTemplate.skip_tags !== params.node.promptValues.skip_tags ? params.node.promptValues.skip_tags : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sendableNodeData;
|
|
||||||
};
|
|
||||||
|
|
||||||
let continueRecursing = function(parentId) {
|
|
||||||
$scope.totalIteratedNodes++;
|
|
||||||
|
|
||||||
if($scope.totalIteratedNodes === $scope.workflowTree.data.totalNodes) {
|
|
||||||
// We're done recursing, lets move on
|
|
||||||
completionCallback();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(params.node.children && params.node.children.length > 0) {
|
|
||||||
_.forEach(params.node.children, function(child) {
|
|
||||||
if(child.edgeType === "success") {
|
|
||||||
recursiveNodeUpdates({
|
|
||||||
parentId: parentId,
|
|
||||||
node: child
|
|
||||||
}, completionCallback);
|
|
||||||
}
|
|
||||||
else if(child.edgeType === "failure") {
|
|
||||||
recursiveNodeUpdates({
|
|
||||||
parentId: parentId,
|
|
||||||
node: child
|
|
||||||
}, completionCallback);
|
|
||||||
}
|
|
||||||
else if(child.edgeType === "always") {
|
|
||||||
recursiveNodeUpdates({
|
|
||||||
parentId: parentId,
|
|
||||||
node: child
|
|
||||||
}, completionCallback);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(params.node.isNew) {
|
|
||||||
|
|
||||||
TemplatesService.addWorkflowNode({
|
|
||||||
url: generatePostUrl(),
|
|
||||||
data: buildSendableNodeData()
|
|
||||||
})
|
|
||||||
.then(function(data) {
|
|
||||||
continueRecursing(data.data.id);
|
|
||||||
}, function(error) {
|
|
||||||
ProcessErrors($scope, error.data, error.status, form, {
|
|
||||||
hdr: 'Error!',
|
|
||||||
msg: 'Failed to add workflow node. ' +
|
|
||||||
'POST returned status: ' +
|
|
||||||
error.status
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(params.node.edited || !params.node.originalParentId || (params.node.originalParentId && params.parentId !== params.node.originalParentId)) {
|
|
||||||
|
|
||||||
if(params.node.edited) {
|
|
||||||
|
|
||||||
$scope.editRequests.push({
|
|
||||||
id: params.node.nodeId,
|
|
||||||
data: buildSendableNodeData()
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if((params.node.originalParentId && params.parentId !== params.node.originalParentId) || params.node.originalEdge !== params.node.edgeType) {//beep
|
|
||||||
|
|
||||||
$scope.disassociateRequests.push({
|
|
||||||
parentId: params.node.originalParentId,
|
|
||||||
nodeId: params.node.nodeId,
|
|
||||||
edge: params.node.originalEdge
|
|
||||||
});
|
|
||||||
|
|
||||||
// Can only associate if we have a parent.
|
|
||||||
// If we don't have a parent then this is a root node
|
|
||||||
// and the act of disassociating will make it a root node
|
|
||||||
if(params.parentId) {
|
|
||||||
$scope.associateRequests.push({
|
|
||||||
parentId: params.parentId,
|
|
||||||
nodeId: params.node.nodeId,
|
|
||||||
edge: params.node.edgeType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if(!params.node.originalParentId && params.parentId) {
|
|
||||||
// This used to be a root node but is now not a root node
|
|
||||||
$scope.associateRequests.push({
|
|
||||||
parentId: params.parentId,
|
|
||||||
nodeId: params.node.nodeId,
|
|
||||||
edge: params.node.edgeType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
continueRecursing(params.node.nodeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.openWorkflowMaker = function() {
|
$scope.openWorkflowMaker = function() {
|
||||||
$state.go('.workflowMaker');
|
$state.go('.workflowMaker');
|
||||||
};
|
};
|
||||||
@@ -392,231 +236,97 @@
|
|||||||
.filter("[data-label-is-present=true]")
|
.filter("[data-label-is-present=true]")
|
||||||
.map((i, val) => ({name: $(val).text()}));
|
.map((i, val) => ({name: $(val).text()}));
|
||||||
|
|
||||||
$scope.totalIteratedNodes = 0;
|
TemplatesService.updateWorkflowJobTemplate({
|
||||||
|
id: id,
|
||||||
|
data: data
|
||||||
|
}).then(function(){
|
||||||
|
|
||||||
// TODO: this is the only way that I could figure out to get
|
var orgDefer = $q.defer();
|
||||||
// these promise arrays to play nicely. I tried to just append
|
var associationDefer = $q.defer();
|
||||||
// a single promise to deletePromises but it just wasn't working
|
var associatedLabelsDefer = $q.defer();
|
||||||
let editWorkflowJobTemplate = [id].map(function(id) {
|
|
||||||
return TemplatesService.updateWorkflowJobTemplate({
|
|
||||||
id: id,
|
|
||||||
data: data
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if($scope.workflowTree && $scope.workflowTree.data && $scope.workflowTree.data.children && $scope.workflowTree.data.children.length > 0) {
|
var getNext = function(data, arr, resolve) {
|
||||||
let completionCallback = function() {
|
Rest.setUrl(data.next);
|
||||||
|
Rest.get()
|
||||||
let disassociatePromises = $scope.disassociateRequests.map(function(request) {
|
.success(function (data) {
|
||||||
return TemplatesService.disassociateWorkflowNode({
|
if (data.next) {
|
||||||
parentId: request.parentId,
|
getNext(data, arr.concat(data.results), resolve);
|
||||||
nodeId: request.nodeId,
|
} else {
|
||||||
edge: request.edge
|
resolve.resolve(arr.concat(data.results));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let editNodePromises = $scope.editRequests.map(function(request) {
|
|
||||||
return TemplatesService.editWorkflowNode({
|
|
||||||
id: request.id,
|
|
||||||
data: request.data
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$q.all(disassociatePromises.concat(editNodePromises).concat(editWorkflowJobTemplate))
|
|
||||||
.then(function() {
|
|
||||||
|
|
||||||
let associatePromises = $scope.associateRequests.map(function(request) {
|
|
||||||
return TemplatesService.associateWorkflowNode({
|
|
||||||
parentId: request.parentId,
|
|
||||||
nodeId: request.nodeId,
|
|
||||||
edge: request.edge
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let deletePromises = $scope.workflowTree.data.deletedNodes.map(function(nodeId) {
|
|
||||||
return TemplatesService.deleteWorkflowJobTemplateNode(nodeId);
|
|
||||||
});
|
|
||||||
|
|
||||||
$q.all(associatePromises.concat(deletePromises))
|
|
||||||
.then(function() {
|
|
||||||
|
|
||||||
var orgDefer = $q.defer();
|
|
||||||
var associationDefer = $q.defer();
|
|
||||||
var associatedLabelsDefer = $q.defer();
|
|
||||||
|
|
||||||
var getNext = function(data, arr, resolve) {
|
|
||||||
Rest.setUrl(data.next);
|
|
||||||
Rest.get()
|
|
||||||
.success(function (data) {
|
|
||||||
if (data.next) {
|
|
||||||
getNext(data, arr.concat(data.results), resolve);
|
|
||||||
} else {
|
|
||||||
resolve.resolve(arr.concat(data.results));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Rest.setUrl($scope.workflow_job_template_obj.related.labels);
|
|
||||||
|
|
||||||
Rest.get()
|
|
||||||
.success(function(data) {
|
|
||||||
if (data.next) {
|
|
||||||
getNext(data, data.results, associatedLabelsDefer);
|
|
||||||
} else {
|
|
||||||
associatedLabelsDefer.resolve(data.results);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
associatedLabelsDefer.promise.then(function (current) {
|
|
||||||
current = current.map(data => data.id);
|
|
||||||
var labelsToAdd = $scope.labels
|
|
||||||
.map(val => val.value);
|
|
||||||
var labelsToDisassociate = current
|
|
||||||
.filter(val => labelsToAdd
|
|
||||||
.indexOf(val) === -1)
|
|
||||||
.map(val => ({id: val, disassociate: true}));
|
|
||||||
var labelsToAssociate = labelsToAdd
|
|
||||||
.filter(val => current
|
|
||||||
.indexOf(val) === -1)
|
|
||||||
.map(val => ({id: val, associate: true}));
|
|
||||||
var pass = labelsToDisassociate
|
|
||||||
.concat(labelsToAssociate);
|
|
||||||
associationDefer.resolve(pass);
|
|
||||||
});
|
|
||||||
|
|
||||||
Rest.setUrl(GetBasePath("organizations"));
|
|
||||||
Rest.get()
|
|
||||||
.success(function(data) {
|
|
||||||
orgDefer.resolve(data.results[0].id);
|
|
||||||
});
|
|
||||||
|
|
||||||
orgDefer.promise.then(function(orgId) {
|
|
||||||
var toPost = [];
|
|
||||||
$scope.newLabels = $scope.newLabels
|
|
||||||
.map(function(i, val) {
|
|
||||||
val.organization = orgId;
|
|
||||||
return val;
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.newLabels.each(function(i, val) {
|
|
||||||
toPost.push(val);
|
|
||||||
});
|
|
||||||
|
|
||||||
associationDefer.promise.then(function(arr) {
|
|
||||||
toPost = toPost
|
|
||||||
.concat(arr);
|
|
||||||
|
|
||||||
Rest.setUrl($scope.workflow_job_template_obj.related.labels);
|
|
||||||
|
|
||||||
var defers = [];
|
|
||||||
for (var i = 0; i < toPost.length; i++) {
|
|
||||||
defers.push(Rest.post(toPost[i]));
|
|
||||||
}
|
|
||||||
$q.all(defers)
|
|
||||||
.then(function() {
|
|
||||||
$state.go('templates.editWorkflowJobTemplate', {id: id}, {reload: true});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_.forEach($scope.workflowTree.data.children, function(child) {
|
Rest.setUrl($scope.workflow_job_template_obj.related.labels);
|
||||||
recursiveNodeUpdates({
|
|
||||||
node: child
|
|
||||||
}, completionCallback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
let deletePromises = $scope.workflowTree.data.deletedNodes.map(function(nodeId) {
|
Rest.get()
|
||||||
return TemplatesService.deleteWorkflowJobTemplateNode(nodeId);
|
.success(function(data) {
|
||||||
});
|
if (data.next) {
|
||||||
|
getNext(data, data.results, associatedLabelsDefer);
|
||||||
$q.all(deletePromises.concat(editWorkflowJobTemplate))
|
} else {
|
||||||
.then(function() {
|
associatedLabelsDefer.resolve(data.results);
|
||||||
var orgDefer = $q.defer();
|
}
|
||||||
var associationDefer = $q.defer();
|
|
||||||
var associatedLabelsDefer = $q.defer();
|
|
||||||
|
|
||||||
var getNext = function(data, arr, resolve) {
|
|
||||||
Rest.setUrl(data.next);
|
|
||||||
Rest.get()
|
|
||||||
.success(function (data) {
|
|
||||||
if (data.next) {
|
|
||||||
getNext(data, arr.concat(data.results), resolve);
|
|
||||||
} else {
|
|
||||||
resolve.resolve(arr.concat(data.results));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Rest.setUrl($scope.workflow_job_template_obj.related.labels);
|
|
||||||
|
|
||||||
Rest.get()
|
|
||||||
.success(function(data) {
|
|
||||||
if (data.next) {
|
|
||||||
getNext(data, data.results, associatedLabelsDefer);
|
|
||||||
} else {
|
|
||||||
associatedLabelsDefer.resolve(data.results);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
associatedLabelsDefer.promise.then(function (current) {
|
|
||||||
current = current.map(data => data.id);
|
|
||||||
var labelsToAdd = $scope.labels
|
|
||||||
.map(val => val.value);
|
|
||||||
var labelsToDisassociate = current
|
|
||||||
.filter(val => labelsToAdd
|
|
||||||
.indexOf(val) === -1)
|
|
||||||
.map(val => ({id: val, disassociate: true}));
|
|
||||||
var labelsToAssociate = labelsToAdd
|
|
||||||
.filter(val => current
|
|
||||||
.indexOf(val) === -1)
|
|
||||||
.map(val => ({id: val, associate: true}));
|
|
||||||
var pass = labelsToDisassociate
|
|
||||||
.concat(labelsToAssociate);
|
|
||||||
associationDefer.resolve(pass);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Rest.setUrl(GetBasePath("organizations"));
|
associatedLabelsDefer.promise.then(function (current) {
|
||||||
Rest.get()
|
current = current.map(data => data.id);
|
||||||
.success(function(data) {
|
var labelsToAdd = $scope.labels
|
||||||
orgDefer.resolve(data.results[0].id);
|
.map(val => val.value);
|
||||||
|
var labelsToDisassociate = current
|
||||||
|
.filter(val => labelsToAdd
|
||||||
|
.indexOf(val) === -1)
|
||||||
|
.map(val => ({id: val, disassociate: true}));
|
||||||
|
var labelsToAssociate = labelsToAdd
|
||||||
|
.filter(val => current
|
||||||
|
.indexOf(val) === -1)
|
||||||
|
.map(val => ({id: val, associate: true}));
|
||||||
|
var pass = labelsToDisassociate
|
||||||
|
.concat(labelsToAssociate);
|
||||||
|
associationDefer.resolve(pass);
|
||||||
|
});
|
||||||
|
|
||||||
|
Rest.setUrl(GetBasePath("organizations"));
|
||||||
|
Rest.get()
|
||||||
|
.success(function(data) {
|
||||||
|
orgDefer.resolve(data.results[0].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
orgDefer.promise.then(function(orgId) {
|
||||||
|
var toPost = [];
|
||||||
|
$scope.newLabels = $scope.newLabels
|
||||||
|
.map(function(i, val) {
|
||||||
|
val.organization = orgId;
|
||||||
|
return val;
|
||||||
});
|
});
|
||||||
|
|
||||||
orgDefer.promise.then(function(orgId) {
|
$scope.newLabels.each(function(i, val) {
|
||||||
var toPost = [];
|
toPost.push(val);
|
||||||
$scope.newLabels = $scope.newLabels
|
});
|
||||||
.map(function(i, val) {
|
|
||||||
val.organization = orgId;
|
associationDefer.promise.then(function(arr) {
|
||||||
return val;
|
toPost = toPost
|
||||||
|
.concat(arr);
|
||||||
|
|
||||||
|
Rest.setUrl($scope.workflow_job_template_obj.related.labels);
|
||||||
|
|
||||||
|
var defers = [];
|
||||||
|
for (var i = 0; i < toPost.length; i++) {
|
||||||
|
defers.push(Rest.post(toPost[i]));
|
||||||
|
}
|
||||||
|
$q.all(defers)
|
||||||
|
.then(function() {
|
||||||
|
$state.go('templates.editWorkflowJobTemplate', {id: id}, {reload: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.newLabels.each(function(i, val) {
|
|
||||||
toPost.push(val);
|
|
||||||
});
|
|
||||||
|
|
||||||
associationDefer.promise.then(function(arr) {
|
|
||||||
toPost = toPost
|
|
||||||
.concat(arr);
|
|
||||||
|
|
||||||
Rest.setUrl($scope.workflow_job_template_obj.related.labels);
|
|
||||||
|
|
||||||
var defers = [];
|
|
||||||
for (var i = 0; i < toPost.length; i++) {
|
|
||||||
defers.push(Rest.post(toPost[i]));
|
|
||||||
}
|
|
||||||
$q.all(defers)
|
|
||||||
.then(function() {
|
|
||||||
$state.go('templates.editWorkflowJobTemplate', {id: id}, {reload: true});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
}, function(error){
|
||||||
|
ProcessErrors($scope, error.data, error.status, form, {
|
||||||
|
hdr: 'Error!',
|
||||||
|
msg: 'Failed to update workflow job template. PUT returned ' +
|
||||||
|
'status: ' + error.status
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
|
|||||||
@@ -29,6 +29,11 @@
|
|||||||
fill: @default-interface-txt;
|
fill: @default-interface-txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.WorkflowChart-startText {
|
||||||
|
fill: @default-bg;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.node .rect {
|
.node .rect {
|
||||||
fill: @default-secondary-bg;
|
fill: @default-secondary-bg;
|
||||||
}
|
}
|
||||||
@@ -97,3 +102,6 @@
|
|||||||
width: 90px;
|
width: 90px;
|
||||||
color: @default-interface-txt;
|
color: @default-interface-txt;
|
||||||
}
|
}
|
||||||
|
.WorkflowChart-activeNode {
|
||||||
|
fill: @default-link;
|
||||||
|
}
|
||||||
|
|||||||
@@ -84,6 +84,25 @@ export default [ '$state',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rounded_rect(x, y, w, h, r, tl, tr, bl, br) {
|
||||||
|
var retval;
|
||||||
|
retval = "M" + (x + r) + "," + y;
|
||||||
|
retval += "h" + (w - 2*r);
|
||||||
|
if (tr) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + r; }
|
||||||
|
else { retval += "h" + r; retval += "v" + r; }
|
||||||
|
retval += "v" + (h - 2*r);
|
||||||
|
if (br) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + r; }
|
||||||
|
else { retval += "v" + r; retval += "h" + -r; }
|
||||||
|
retval += "h" + (2*r - w);
|
||||||
|
if (bl) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + -r; }
|
||||||
|
else { retval += "h" + -r; retval += "v" + -r; }
|
||||||
|
retval += "v" + (2*r - h);
|
||||||
|
if (tl) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + -r; }
|
||||||
|
else { retval += "v" + -r; retval += "h" + r; }
|
||||||
|
retval += "z";
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
// This is the zoom function called by using the mousewheel/click and drag
|
// This is the zoom function called by using the mousewheel/click and drag
|
||||||
function naturalZoom() {
|
function naturalZoom() {
|
||||||
let scale = d3.event.scale,
|
let scale = d3.event.scale,
|
||||||
@@ -163,20 +182,13 @@ export default [ '$state',
|
|||||||
.attr("fill", "#5cb85c")
|
.attr("fill", "#5cb85c")
|
||||||
.attr("class", "WorkflowChart-rootNode")
|
.attr("class", "WorkflowChart-rootNode")
|
||||||
.call(add_node);
|
.call(add_node);
|
||||||
thisNode.append("path")
|
|
||||||
.style("fill", "white")
|
|
||||||
.attr("transform", function() { return "translate(" + 30 + "," + 30 + ")"; })
|
|
||||||
.attr("d", d3.svg.symbol()
|
|
||||||
.size(120)
|
|
||||||
.type("cross")
|
|
||||||
)
|
|
||||||
.call(add_node);
|
|
||||||
thisNode.append("text")
|
thisNode.append("text")
|
||||||
.attr("x", 14)
|
.attr("x", 13)
|
||||||
.attr("y", 0)
|
.attr("y", 30)
|
||||||
.attr("dy", ".35em")
|
.attr("dy", ".35em")
|
||||||
.attr("class", "WorkflowChart-defaultText")
|
.attr("class", "WorkflowChart-startText")
|
||||||
.text(function () { return "START"; });
|
.text(function () { return "START"; })
|
||||||
|
.call(add_node);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
thisNode.append("rect")
|
thisNode.append("rect")
|
||||||
@@ -184,12 +196,32 @@ export default [ '$state',
|
|||||||
.attr("height", rectH)
|
.attr("height", rectH)
|
||||||
.attr("rx", 5)
|
.attr("rx", 5)
|
||||||
.attr("ry", 5)
|
.attr("ry", 5)
|
||||||
.attr('stroke', function(d) { return d.isActiveEdit ? "#337ab7" : "#D7D7D7"; })
|
.attr('stroke', function(d) {
|
||||||
.attr('stroke-width', function(d){ return d.isActiveEdit ? "2px" : "1px"; })
|
if(d.edgeType) {
|
||||||
|
if(d.edgeType === "failure") {
|
||||||
|
return "#d9534f";
|
||||||
|
}
|
||||||
|
else if(d.edgeType === "success") {
|
||||||
|
return "#5cb85c";
|
||||||
|
}
|
||||||
|
else if(d.edgeType === "always"){
|
||||||
|
return "#337ab7";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "#D7D7D7";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.attr('stroke-width', "2px")
|
||||||
.attr("class", function(d) {
|
.attr("class", function(d) {
|
||||||
return d.placeholder ? "rect placeholder" : "rect";
|
return d.placeholder ? "rect placeholder" : "rect";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
thisNode.append("path")
|
||||||
|
.attr("d", rounded_rect(1, 0, 5, rectH, 5, 1, 0, 1, 0))
|
||||||
|
.attr("class", "WorkflowChart-activeNode")
|
||||||
|
.style("display", function(d) { return d.isActiveEdit ? null : "none"; });
|
||||||
|
|
||||||
thisNode.append("text")
|
thisNode.append("text")
|
||||||
.attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 20 : rectW / 2; })
|
.attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 20 : rectW / 2; })
|
||||||
.attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 10 : rectH / 2; })
|
.attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 10 : rectH / 2; })
|
||||||
@@ -517,8 +549,22 @@ export default [ '$state',
|
|||||||
.attr("transform", function(d) { return "translate(" + (d.target.y + d.source.y + rectW) / 2 + "," + (d.target.x + d.source.x + rectH) / 2 + ")"; });
|
.attr("transform", function(d) { return "translate(" + (d.target.y + d.source.y + rectW) / 2 + "," + (d.target.x + d.source.x + rectH) / 2 + ")"; });
|
||||||
|
|
||||||
t.selectAll(".rect")
|
t.selectAll(".rect")
|
||||||
.attr('stroke', function(d) { return d.isActiveEdit ? "#337ab7" : "#D7D7D7"; })
|
.attr('stroke', function(d) {
|
||||||
.attr('stroke-width', function(d){ return d.isActiveEdit ? "2px" : "1px"; })
|
if(d.edgeType) {
|
||||||
|
if(d.edgeType === "failure") {
|
||||||
|
return "#d9534f";
|
||||||
|
}
|
||||||
|
else if(d.edgeType === "success") {
|
||||||
|
return "#5cb85c";
|
||||||
|
}
|
||||||
|
else if(d.edgeType === "always"){
|
||||||
|
return "#337ab7";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "#D7D7D7";
|
||||||
|
}
|
||||||
|
})
|
||||||
.attr("class", function(d) {
|
.attr("class", function(d) {
|
||||||
return d.placeholder ? "rect placeholder" : "rect";
|
return d.placeholder ? "rect placeholder" : "rect";
|
||||||
});
|
});
|
||||||
@@ -601,6 +647,9 @@ export default [ '$state',
|
|||||||
t.selectAll(".WorkflowChart-conflictText")
|
t.selectAll(".WorkflowChart-conflictText")
|
||||||
.style("display", function(d) { return (d.edgeConflict && !d.placeholder) ? null : "none"; });
|
.style("display", function(d) { return (d.edgeConflict && !d.placeholder) ? null : "none"; });
|
||||||
|
|
||||||
|
t.selectAll(".WorkflowChart-activeNode")
|
||||||
|
.style("display", function(d) { return d.isActiveEdit ? null : "none"; });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_node() {
|
function add_node() {
|
||||||
|
|||||||
@@ -154,7 +154,7 @@
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-maker--right {
|
.WorkflowLegend-maker--right {
|
||||||
flex: 0 0 182px;
|
flex: 0 0 206px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -226,7 +226,7 @@
|
|||||||
}
|
}
|
||||||
.WorkflowMaker-manualControls {
|
.WorkflowMaker-manualControls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -122px;
|
left: -86px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
width: 293px;
|
width: 293px;
|
||||||
background-color: @default-bg;
|
background-color: @default-bg;
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'Pr
|
|||||||
showTypeOptions: false
|
showTypeOptions: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.editRequests = [];
|
||||||
|
$scope.associateRequests = [];
|
||||||
|
$scope.disassociateRequests = [];
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
$scope.treeDataMaster = angular.copy($scope.treeData.data);
|
$scope.treeDataMaster = angular.copy($scope.treeData.data);
|
||||||
$scope.showManualControls = false;
|
$scope.showManualControls = false;
|
||||||
@@ -55,6 +59,160 @@ export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'Pr
|
|||||||
$scope.workflowMakerFormConfig.activeTab = "jobs";
|
$scope.workflowMakerFormConfig.activeTab = "jobs";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function recursiveNodeUpdates(params, completionCallback) {
|
||||||
|
// params.parentId
|
||||||
|
// params.node
|
||||||
|
|
||||||
|
let generatePostUrl = function(){
|
||||||
|
|
||||||
|
let base = (params.parentId) ? GetBasePath('workflow_job_template_nodes') + params.parentId : $scope.treeData.workflow_job_template_obj.related.workflow_nodes;
|
||||||
|
|
||||||
|
if(params.parentId) {
|
||||||
|
if(params.node.edgeType === 'success') {
|
||||||
|
base += "/success_nodes";
|
||||||
|
}
|
||||||
|
else if(params.node.edgeType === 'failure') {
|
||||||
|
base += "/failure_nodes";
|
||||||
|
}
|
||||||
|
else if(params.node.edgeType === 'always') {
|
||||||
|
base += "/always_nodes";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
let buildSendableNodeData = function() {
|
||||||
|
// Create the node
|
||||||
|
let sendableNodeData = {
|
||||||
|
unified_job_template: params.node.unifiedJobTemplate.id
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check to see if the user has provided any prompt values that are different
|
||||||
|
// from the defaults in the job template
|
||||||
|
|
||||||
|
if(params.node.unifiedJobTemplate.type === "job_template" && params.node.promptValues) {
|
||||||
|
if(params.node.unifiedJobTemplate.ask_credential_on_launch) {
|
||||||
|
sendableNodeData.credential = !params.node.promptValues.credential || params.node.unifiedJobTemplate.summary_fields.credential.id !== params.node.promptValues.credential.id ? params.node.promptValues.credential.id : null;
|
||||||
|
}
|
||||||
|
if(params.node.unifiedJobTemplate.ask_inventory_on_launch) {
|
||||||
|
sendableNodeData.inventory = !params.node.promptValues.inventory || params.node.unifiedJobTemplate.summary_fields.inventory.id !== params.node.promptValues.inventory.id ? params.node.promptValues.inventory.id : null;
|
||||||
|
}
|
||||||
|
if(params.node.unifiedJobTemplate.ask_limit_on_launch) {
|
||||||
|
sendableNodeData.limit = !params.node.promptValues.limit || params.node.unifiedJobTemplate.limit !== params.node.promptValues.limit ? params.node.promptValues.limit : null;
|
||||||
|
}
|
||||||
|
if(params.node.unifiedJobTemplate.ask_job_type_on_launch) {
|
||||||
|
sendableNodeData.job_type = !params.node.promptValues.job_type || params.node.unifiedJobTemplate.job_type !== params.node.promptValues.job_type ? params.node.promptValues.job_type : null;
|
||||||
|
}
|
||||||
|
if(params.node.unifiedJobTemplate.ask_tags_on_launch) {
|
||||||
|
sendableNodeData.job_tags = !params.node.promptValues.job_tags || params.node.unifiedJobTemplate.job_tags !== params.node.promptValues.job_tags ? params.node.promptValues.job_tags : null;
|
||||||
|
}
|
||||||
|
if(params.node.unifiedJobTemplate.ask_skip_tags_on_launch) {
|
||||||
|
sendableNodeData.skip_tags = !params.node.promptValues.skip_tags || params.node.unifiedJobTemplate.skip_tags !== params.node.promptValues.skip_tags ? params.node.promptValues.skip_tags : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendableNodeData;
|
||||||
|
};
|
||||||
|
|
||||||
|
let continueRecursing = function(parentId) {
|
||||||
|
$scope.totalIteratedNodes++;
|
||||||
|
|
||||||
|
if($scope.totalIteratedNodes === $scope.treeData.data.totalNodes) {
|
||||||
|
// We're done recursing, lets move on
|
||||||
|
completionCallback();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(params.node.children && params.node.children.length > 0) {
|
||||||
|
_.forEach(params.node.children, function(child) {
|
||||||
|
if(child.edgeType === "success") {
|
||||||
|
recursiveNodeUpdates({
|
||||||
|
parentId: parentId,
|
||||||
|
node: child
|
||||||
|
}, completionCallback);
|
||||||
|
}
|
||||||
|
else if(child.edgeType === "failure") {
|
||||||
|
recursiveNodeUpdates({
|
||||||
|
parentId: parentId,
|
||||||
|
node: child
|
||||||
|
}, completionCallback);
|
||||||
|
}
|
||||||
|
else if(child.edgeType === "always") {
|
||||||
|
recursiveNodeUpdates({
|
||||||
|
parentId: parentId,
|
||||||
|
node: child
|
||||||
|
}, completionCallback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(params.node.isNew) {
|
||||||
|
|
||||||
|
TemplatesService.addWorkflowNode({
|
||||||
|
url: generatePostUrl(),
|
||||||
|
data: buildSendableNodeData()
|
||||||
|
})
|
||||||
|
.then(function(data) {
|
||||||
|
continueRecursing(data.data.id);
|
||||||
|
}, function(error) {
|
||||||
|
ProcessErrors($scope, error.data, error.status, form, {
|
||||||
|
hdr: 'Error!',
|
||||||
|
msg: 'Failed to add workflow node. ' +
|
||||||
|
'POST returned status: ' +
|
||||||
|
error.status
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(params.node.edited || !params.node.originalParentId || (params.node.originalParentId && params.parentId !== params.node.originalParentId)) {
|
||||||
|
|
||||||
|
if(params.node.edited) {
|
||||||
|
|
||||||
|
$scope.editRequests.push({
|
||||||
|
id: params.node.nodeId,
|
||||||
|
data: buildSendableNodeData()
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if((params.node.originalParentId && params.parentId !== params.node.originalParentId) || params.node.originalEdge !== params.node.edgeType) {//beep
|
||||||
|
|
||||||
|
$scope.disassociateRequests.push({
|
||||||
|
parentId: params.node.originalParentId,
|
||||||
|
nodeId: params.node.nodeId,
|
||||||
|
edge: params.node.originalEdge
|
||||||
|
});
|
||||||
|
|
||||||
|
// Can only associate if we have a parent.
|
||||||
|
// If we don't have a parent then this is a root node
|
||||||
|
// and the act of disassociating will make it a root node
|
||||||
|
if(params.parentId) {
|
||||||
|
$scope.associateRequests.push({
|
||||||
|
parentId: params.parentId,
|
||||||
|
nodeId: params.node.nodeId,
|
||||||
|
edge: params.node.edgeType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(!params.node.originalParentId && params.parentId) {
|
||||||
|
// This used to be a root node but is now not a root node
|
||||||
|
$scope.associateRequests.push({
|
||||||
|
parentId: params.parentId,
|
||||||
|
nodeId: params.node.nodeId,
|
||||||
|
edge: params.node.edgeType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
continueRecursing(params.node.nodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.lookUpInventory = function(){
|
$scope.lookUpInventory = function(){
|
||||||
$state.go('.inventory');
|
$state.go('.inventory');
|
||||||
};
|
};
|
||||||
@@ -70,7 +228,66 @@ export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'Pr
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.saveWorkflowMaker = function() {
|
$scope.saveWorkflowMaker = function() {
|
||||||
$scope.closeDialog();
|
|
||||||
|
$scope.totalIteratedNodes = 0;
|
||||||
|
|
||||||
|
if($scope.treeData && $scope.treeData.data && $scope.treeData.data.children && $scope.treeData.data.children.length > 0) {
|
||||||
|
let completionCallback = function() {
|
||||||
|
|
||||||
|
let disassociatePromises = $scope.disassociateRequests.map(function(request) {
|
||||||
|
return TemplatesService.disassociateWorkflowNode({
|
||||||
|
parentId: request.parentId,
|
||||||
|
nodeId: request.nodeId,
|
||||||
|
edge: request.edge
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let editNodePromises = $scope.editRequests.map(function(request) {
|
||||||
|
return TemplatesService.editWorkflowNode({
|
||||||
|
id: request.id,
|
||||||
|
data: request.data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$q.all(disassociatePromises.concat(editNodePromises))
|
||||||
|
.then(function() {
|
||||||
|
|
||||||
|
let associatePromises = $scope.associateRequests.map(function(request) {
|
||||||
|
return TemplatesService.associateWorkflowNode({
|
||||||
|
parentId: request.parentId,
|
||||||
|
nodeId: request.nodeId,
|
||||||
|
edge: request.edge
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let deletePromises = $scope.treeData.data.deletedNodes.map(function(nodeId) {
|
||||||
|
return TemplatesService.deleteWorkflowJobTemplateNode(nodeId);
|
||||||
|
});
|
||||||
|
|
||||||
|
$q.all(associatePromises.concat(deletePromises))
|
||||||
|
.then(function() {
|
||||||
|
$scope.closeDialog();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_.forEach($scope.treeData.data.children, function(child) {
|
||||||
|
recursiveNodeUpdates({
|
||||||
|
node: child
|
||||||
|
}, completionCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
let deletePromises = $scope.treeData.data.deletedNodes.map(function(nodeId) {
|
||||||
|
return TemplatesService.deleteWorkflowJobTemplateNode(nodeId);
|
||||||
|
});
|
||||||
|
|
||||||
|
$q.all(deletePromises)
|
||||||
|
.then(function() {
|
||||||
|
$scope.closeDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ADD NODE FUNCTIONS */
|
/* ADD NODE FUNCTIONS */
|
||||||
@@ -575,7 +792,7 @@ export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'Pr
|
|||||||
edgeFlags: $scope.edgeFlags
|
edgeFlags: $scope.edgeFlags
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.toggleManualControls = function() {
|
$scope.toggleManualControls = function() {
|
||||||
$scope.showManualControls = !$scope.showManualControls;
|
$scope.showManualControls = !$scope.showManualControls;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ describe('Controller: WorkflowMaker', () => {
|
|||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('scope.saveWorkflowMaker()', () => {
|
describe('scope.closeWorkflowMaker()', () => {
|
||||||
|
|
||||||
it('should close the dialog', ()=>{
|
it('should close the dialog', ()=>{
|
||||||
scope.saveWorkflowMaker();
|
scope.closeWorkflowMaker();
|
||||||
expect(scope.closeDialog).toHaveBeenCalled();
|
expect(scope.closeDialog).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user