Cleanup and changes to the way approval templates are created

This commit is contained in:
mabashian 2019-07-18 15:36:01 -04:00 committed by Ryan Petrello
parent 294d6551b9
commit 4a801c60b9
No known key found for this signature in database
GPG Key ID: F2AA5F2122351777
14 changed files with 741 additions and 933 deletions

View File

@ -110,9 +110,12 @@ function TemplatesStrings (BaseString) {
ON_SUCCESS: t.s('On Success'),
ON_FAILURE: t.s('On Failure'),
ALWAYS: t.s('Always'),
PAUSE: t.s('Wait For Approval'),
JOB_TEMPLATE: t.s('Job Template'),
PROJECT_SYNC: t.s('Project Sync'),
INVENTORY_SYNC: t.s('Inventory Sync'),
WORKFLOW: t.s('Workflow'),
TEMPLATE: t.s('Template'),
WARNING: t.s('Warning'),
TOTAL_NODES: t.s('TOTAL NODES'),
ADD_A_NODE: t.s('ADD A NODE'),
@ -145,7 +148,7 @@ function TemplatesStrings (BaseString) {
EXIT: t.s('EXIT'),
CANCEL: t.s('CANCEL'),
SAVE_AND_EXIT: t.s('SAVE & EXIT'),
PAUSE_NODE: t.s('Pause Node')
APPROVAL: t.s('Approval')
};
}

View File

@ -12,6 +12,7 @@ import workflowEdit from './workflows/edit-workflow/main';
import labels from './labels/main';
import prompt from './prompt/main';
import workflowChart from './workflows/workflow-chart/main';
import workflowKey from './workflows/workflow-key/main';
import workflowMaker from './workflows/workflow-maker/main';
import workflowControls from './workflows/workflow-controls/main';
import WorkflowForm from './workflows.form';
@ -31,7 +32,7 @@ import {
export default
angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, prompt.name, workflowAdd.name, workflowEdit.name,
workflowChart.name, workflowMaker.name, workflowControls.name
workflowChart.name, workflowKey.name, workflowMaker.name, workflowControls.name
])
.service('TemplatesService', templatesService)
.factory('WorkflowForm', WorkflowForm)
@ -499,320 +500,7 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
views: {
'modal': {
template: `<workflow-maker ng-if="includeWorkflowMaker" workflow-job-template-obj="workflow_job_template_obj" can-add-or-edit="canAddOrEdit"></workflow-maker>`
},
'jobTemplateList@templates.editWorkflowJobTemplate.workflowMaker': {
templateProvider: function(WorkflowMakerJobTemplateList, generateList) {
let html = generateList.build({
list: WorkflowMakerJobTemplateList,
input_type: 'radio',
mode: 'lookup'
});
return html;
},
// $scope encapsulated in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy
controller: ['$scope', 'WorkflowMakerJobTemplateList', 'JobTemplateDataset',
function($scope, list, Dataset) {
init();
function init() {
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
$scope.$watch('wf_maker_templates', function(){
if($scope.selectedTemplate){
$scope.wf_maker_templates.forEach(function(row, i) {
if(row.id === $scope.selectedTemplate.id) {
$scope.wf_maker_templates[i].checked = 1;
}
else {
$scope.wf_maker_templates[i].checked = 0;
}
});
}
});
}
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.wf_maker_templates.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.wf_maker_templates[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.templateManuallySelected(row);
}
});
}
};
$scope.$watch('selectedTemplate', () => {
$scope.wf_maker_templates.forEach(function(row, i) {
if(_.has($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) {
$scope.wf_maker_templates[i].checked = 1;
}
else {
$scope.wf_maker_templates[i].checked = 0;
}
});
});
$scope.$watch('activeTab', () => {
if(!$scope.activeTab || $scope.activeTab !== "jobs") {
$scope.wf_maker_templates.forEach(function(row, i) {
$scope.wf_maker_templates[i].checked = 0;
});
}
});
$scope.$on('clearWorkflowLists', function() {
$scope.wf_maker_templates.forEach(function(row, i) {
$scope.wf_maker_templates[i].checked = 0;
});
});
}
]
},
'inventorySyncList@templates.editWorkflowJobTemplate.workflowMaker': {
templateProvider: function(WorkflowInventorySourcesList, generateList) {
let html = generateList.build({
list: WorkflowInventorySourcesList,
input_type: 'radio',
mode: 'lookup'
});
return html;
},
// encapsulated $scope in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy
controller: ['$scope', 'WorkflowInventorySourcesList', 'InventorySourcesDataset',
function($scope, list, Dataset) {
init();
function init() {
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
$scope.$watch('wf_maker_inventory_sources', function(){
if($scope.selectedTemplate){
$scope.wf_maker_inventory_sources.forEach(function(row, i) {
if(row.id === $scope.selectedTemplate.id) {
$scope.wf_maker_inventory_sources[i].checked = 1;
}
else {
$scope.wf_maker_inventory_sources[i].checked = 0;
}
});
}
});
}
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.wf_maker_inventory_sources.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.wf_maker_inventory_sources[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.templateManuallySelected(row);
}
});
}
};
$scope.$watch('selectedTemplate', () => {
$scope.wf_maker_inventory_sources.forEach(function(row, i) {
if(_.hasIn($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) {
$scope.wf_maker_inventory_sources[i].checked = 1;
}
else {
$scope.wf_maker_inventory_sources[i].checked = 0;
}
});
});
$scope.$watch('activeTab', () => {
if(!$scope.activeTab || $scope.activeTab !== "inventory_sync") {
$scope.wf_maker_inventory_sources.forEach(function(row, i) {
$scope.wf_maker_inventory_sources[i].checked = 0;
});
}
});
$scope.$on('clearWorkflowLists', function() {
$scope.wf_maker_inventory_sources.forEach(function(row, i) {
$scope.wf_maker_inventory_sources[i].checked = 0;
});
});
}
]
},
'projectSyncList@templates.editWorkflowJobTemplate.workflowMaker': {
templateProvider: function(WorkflowProjectList, generateList) {
let html = generateList.build({
list: WorkflowProjectList,
input_type: 'radio',
mode: 'lookup'
});
return html;
},
// encapsulated $scope in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy
controller: ['$scope', 'WorkflowProjectList', 'ProjectDataset',
function($scope, list, Dataset) {
init();
function init() {
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
$scope.$watch('wf_maker_projects', function(){
if($scope.selectedTemplate){
$scope.wf_maker_projects.forEach(function(row, i) {
if(row.id === $scope.selectedTemplate.id) {
$scope.wf_maker_projects[i].checked = 1;
}
else {
$scope.wf_maker_projects[i].checked = 0;
}
});
}
});
}
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.wf_maker_projects.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.wf_maker_projects[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.templateManuallySelected(row);
}
});
}
};
$scope.$watch('selectedTemplate', () => {
$scope.wf_maker_projects.forEach(function(row, i) {
if(_.hasIn($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) {
$scope.wf_maker_projects[i].checked = 1;
}
else {
$scope.wf_maker_projects[i].checked = 0;
}
});
});
$scope.$watch('activeTab', () => {
if(!$scope.activeTab || $scope.activeTab !== "project_sync") {
$scope.wf_maker_projects.forEach(function(row, i) {
$scope.wf_maker_projects[i].checked = 0;
});
}
});
$scope.$on('clearWorkflowLists', function() {
$scope.wf_maker_projects.forEach(function(row, i) {
$scope.wf_maker_projects[i].checked = 0;
});
});
}
]
}
},
resolve: {
JobTemplateDataset: ['WorkflowMakerJobTemplateList', 'QuerySet', '$stateParams', 'GetBasePath',
(list, qs, $stateParams, GetBasePath) => {
let path = GetBasePath(list.basePath);
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
ProjectDataset: ['WorkflowProjectList', 'QuerySet', '$stateParams', 'GetBasePath',
(list, qs, $stateParams, GetBasePath) => {
let path = GetBasePath(list.basePath);
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
InventorySourcesDataset: ['InventorySourcesList', 'QuerySet', '$stateParams', 'GetBasePath',
(list, qs, $stateParams, GetBasePath) => {
let path = GetBasePath(list.basePath);
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
WorkflowMakerJobTemplateList: ['TemplateList', 'i18n',
(TemplateList, i18n) => {
let list = _.cloneDeep(TemplateList);
delete list.actions;
delete list.fields.type;
delete list.fields.description;
delete list.fields.smart_status;
delete list.fields.labels;
delete list.fieldActions;
list.name = 'wf_maker_templates';
list.iterator = 'wf_maker_template';
list.fields.name.columnClass = "col-md-8";
list.fields.name.tag = i18n._('WORKFLOW');
list.fields.name.showTag = "{{wf_maker_template.type === 'workflow_job_template'}}";
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
list.basePath = 'unified_job_templates';
list.fields.info = {
ngInclude: "'/static/partials/job-template-details.html'",
type: 'template',
columnClass: 'col-md-3',
infoHeaderClass: 'col-md-3',
label: '',
nosort: true
};
list.maxVisiblePages = 5;
list.searchBarFullWidth = true;
return list;
}
],
WorkflowProjectList: ['ProjectList',
(ProjectList) => {
let list = _.cloneDeep(ProjectList);
delete list.fields.status;
delete list.fields.scm_type;
delete list.fields.last_updated;
list.name = 'wf_maker_projects';
list.iterator = 'wf_maker_project';
list.fields.name.columnClass = "col-md-11";
list.maxVisiblePages = 5;
list.searchBarFullWidth = true;
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
return list;
}
],
WorkflowInventorySourcesList: ['InventorySourcesList',
(InventorySourcesList) => {
let list = _.cloneDeep(InventorySourcesList);
list.name = 'wf_maker_inventory_sources';
list.iterator = 'wf_maker_inventory_source';
list.maxVisiblePages = 5;
list.searchBarFullWidth = true;
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
return list;
}
]
}
};

View File

@ -291,13 +291,13 @@ export default ['Rest', 'GetBasePath', '$q', 'NextPage', function(Rest, GetBaseP
Rest.setUrl(url);
return Rest.post(params.data);
},
createApprovalTemplate: (params) => {
params = params || {};
Rest.setUrl(GetBasePath('workflow_approval_templates'));
return Rest.post(params);
createApprovalTemplate: ({url, data}) => {
data = data || {};
Rest.setUrl(url);
return Rest.post(data);
},
patchApprovalTemplate: ({id, data}) => {
Rest.setUrl(`${GetBasePath('workflow_approval_templates')}/${id}`);
Rest.setUrl(`/api/v2/workflow_approval_templates/${id}`);
return Rest.patch(data);
}
};

View File

@ -117,6 +117,7 @@
.WorkflowChart-nodeTypeLetter {
fill: @default-bg;
font-size: 10px;
}
.WorkflowChart-nodeStatus--running {

View File

@ -0,0 +1,11 @@
/*************************************************
* Copyright (c) 2019 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import workflowKey from './workflow-key.directive';
export default
angular.module('workflowKey', [])
.directive('workflowKey', workflowKey);

View File

@ -0,0 +1,18 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default ['templateUrl', 'TemplatesStrings',
function(templateUrl, TemplatesStrings) {
return {
scope: {},
templateUrl: templateUrl('templates/workflows/workflow-key/workflow-key'),
restrict: 'E',
link: function(scope) {
scope.strings = TemplatesStrings;
}
};
}
];

View File

@ -0,0 +1,43 @@
<ul class="Key-list noselect">
<li class="Key-listItem">
<p class="Key-heading">{{:: strings.get('workflow_maker.KEY')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--success"></div>
<p class="Key-listItemContent">{{:: strings.get('workflow_maker.ON_SUCCESS')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--fail"></div>
<p class="Key-listItemContent">{{:: strings.get('workflow_maker.ON_FAILURE')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--always"></div>
<p class="Key-listItemContent">{{:: strings.get('workflow_maker.ALWAYS')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">JT</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{:: strings.get('workflow_maker.JOB_TEMPLATE')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">P</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{:: strings.get('workflow_maker.PROJECT_SYNC')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">I</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{:: strings.get('workflow_maker.INVENTORY_SYNC')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">W</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{:: strings.get('workflow_maker.WORKFLOW')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">
<span class="fa fa-pause"></span>
</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{:: strings.get('workflow_maker.PAUSE')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--warning">!</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{:: strings.get('workflow_maker.WARNING')}}</p>
</li>
</ul>

View File

@ -1,7 +1,9 @@
import workflowLinkForm from './workflow-link-form.directive';
import workflowNodeForm from './workflow-node-form.directive';
import workflowNodeFormService from './workflow-node-form.service';
export default
angular.module('templates.workflowMaker.forms', [])
.directive('workflowLinkForm', workflowLinkForm)
.directive('workflowNodeForm', workflowNodeForm);
.directive('workflowNodeForm', workflowNodeForm)
.service('WorkflowNodeFormService', workflowNodeFormService);

View File

@ -0,0 +1,67 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default ['TemplateList', 'ProjectList', 'InventorySourcesList', 'i18n',
function(TemplateList, ProjectList, InventorySourcesList, i18n){
return {
inventorySourceListDefinition: function() {
const inventorySourceList = _.cloneDeep(InventorySourcesList);
inventorySourceList.name = 'wf_maker_inventory_sources';
inventorySourceList.iterator = 'wf_maker_inventory_source';
inventorySourceList.maxVisiblePages = 5;
inventorySourceList.searchBarFullWidth = true;
inventorySourceList.disableRow = "{{ readOnly }}";
inventorySourceList.disableRowValue = 'readOnly';
return inventorySourceList;
},
projectListDefinition: function(){
const projectList = _.cloneDeep(ProjectList);
delete projectList.fields.status;
delete projectList.fields.scm_type;
delete projectList.fields.last_updated;
projectList.name = 'wf_maker_projects';
projectList.iterator = 'wf_maker_project';
projectList.fields.name.columnClass = "col-md-11";
projectList.maxVisiblePages = 5;
projectList.searchBarFullWidth = true;
projectList.disableRow = "{{ readOnly }}";
projectList.disableRowValue = 'readOnly';
return projectList;
},
templateListDefinition: function(){
const templateList = _.cloneDeep(TemplateList);
delete templateList.actions;
delete templateList.fields.type;
delete templateList.fields.description;
delete templateList.fields.smart_status;
delete templateList.fields.labels;
delete templateList.fieldActions;
templateList.name = 'wf_maker_templates';
templateList.iterator = 'wf_maker_template';
templateList.fields.name.columnClass = "col-md-8";
templateList.fields.name.tag = i18n._('WORKFLOW');
templateList.fields.name.showTag = "{{wf_maker_template.type === 'workflow_job_template'}}";
templateList.disableRow = "{{ readOnly }}";
templateList.disableRowValue = 'readOnly';
templateList.basePath = 'unified_job_templates';
templateList.fields.info = {
ngInclude: "'/static/partials/job-template-details.html'",
type: 'template',
columnClass: 'col-md-3',
infoHeaderClass: 'col-md-3',
label: '',
nosort: true
};
templateList.maxVisiblePages = 5;
templateList.searchBarFullWidth = true;
return templateList;
}
};
}
];

View File

@ -7,6 +7,15 @@
.ui-dialog-buttonpane, .ui-dialog-titlebar {
display:none;
}
input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] {
-moz-appearance: textfield;
}
}
.WorkflowMaker-header {
@ -380,11 +389,11 @@
.Key-icon--circle {
border-radius: 50%;
width: 20px;
height: 20px;
width: 24px;
height: 24px;
color: @default-bg;
text-align: center;
line-height: 20px;
line-height: 24px;
margin: 4px 5px 5px 0px;
}

View File

@ -145,21 +145,24 @@ export default ['$scope', 'TemplatesService',
let editPromises = [];
let credentialRequests = [];
// TODO: clean up data generation of approval template requests
Object.keys(nodeRef).map((workflowMakerNodeId) => {
const node = nodeRef[workflowMakerNodeId];
if (node.isNew) {
if (node.unifiedJobTemplate && node.unifiedJobTemplate.unified_job_type === "workflow_approval") {
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
name: node.unifiedJobTemplate.name
}).then(({data: approvalTemplateData}) => {
addPromises.push(TemplatesService.addWorkflowNode({
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
addPromises.push(TemplatesService.addWorkflowNode({
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
data: {}
}).then(({data}) => {
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
url: data.related.create_approval_template,
data: {
unified_job_template: approvalTemplateData.id
name: node.unifiedJobTemplate.name,
description: node.unifiedJobTemplate.description
}
}).then(({data: nodeData}) => {
node.originalNodeObject = nodeData;
nodeIdToChartNodeIdMapping[nodeData.id] = parseInt(workflowMakerNodeId);
}).then(() => {
node.originalNodeObject = data;
nodeIdToChartNodeIdMapping[data.id] = parseInt(workflowMakerNodeId);
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
@ -222,20 +225,11 @@ export default ['$scope', 'TemplatesService',
}));
} else {
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
name: node.unifiedJobTemplate.name
}).then(({data: approvalTemplateData}) => {
// Make sure that this isn't overwriting everything on the node...
editPromises.push(TemplatesService.editWorkflowNode({
id: node.originalNodeObject.id,
data: {
unified_job_template: approvalTemplateData.id
}
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
});
}));
url: node.originalNodeObject.related.create_approval_template,
data: {
name: node.unifiedJobTemplate.name,
description: node.unifiedJobTemplate.description
}
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
@ -302,176 +296,173 @@ export default ['$scope', 'TemplatesService',
return TemplatesService.deleteWorkflowJobTemplateNode(nodeId);
});
$q.all(approvalTemplatePromises)
$q.all(addPromises.concat(editPromises, deletePromises))
.then(() => {
$q.all(addPromises.concat(editPromises, deletePromises))
.then(() => {
let disassociatePromises = [];
let associatePromises = [];
let linkMap = {};
$q.all(approvalTemplatePromises)
.then(() => {
let disassociatePromises = [];
let associatePromises = [];
let linkMap = {};
// Build a link map for easy access
$scope.graphState.arrayOfLinksForChart.forEach(link => {
// link.source.id of 1 is our artificial start node
if (link.source.id !== 1) {
const sourceNodeId = nodeRef[link.source.id].originalNodeObject.id;
const targetNodeId = nodeRef[link.target.id].originalNodeObject.id;
if (!linkMap[sourceNodeId]) {
linkMap[sourceNodeId] = {};
// Build a link map for easy access
$scope.graphState.arrayOfLinksForChart.forEach(link => {
// link.source.id of 1 is our artificial start node
if (link.source.id !== 1) {
const sourceNodeId = nodeRef[link.source.id].originalNodeObject.id;
const targetNodeId = nodeRef[link.target.id].originalNodeObject.id;
if (!linkMap[sourceNodeId]) {
linkMap[sourceNodeId] = {};
}
linkMap[sourceNodeId][targetNodeId] = link.edgeType;
}
});
linkMap[sourceNodeId][targetNodeId] = link.edgeType;
}
});
Object.keys(nodeRef).map((workflowNodeId) => {
let nodeId = nodeRef[workflowNodeId].originalNodeObject.id;
if (nodeRef[workflowNodeId].originalNodeObject.success_nodes) {
nodeRef[workflowNodeId].originalNodeObject.success_nodes.forEach((successNodeId) => {
if (
!deletedNodeIds.includes(successNodeId) &&
(!linkMap[nodeId] ||
!linkMap[nodeId][successNodeId] ||
linkMap[nodeId][successNodeId] !== "success")
) {
disassociatePromises.push(
TemplatesService.disassociateWorkflowNode({
parentId: nodeId,
nodeId: successNodeId,
edge: "success"
})
);
}
});
}
if (nodeRef[workflowNodeId].originalNodeObject.failure_nodes) {
nodeRef[workflowNodeId].originalNodeObject.failure_nodes.forEach((failureNodeId) => {
if (
!deletedNodeIds.includes(failureNodeId) &&
(!linkMap[nodeId] ||
!linkMap[nodeId][failureNodeId] ||
linkMap[nodeId][failureNodeId] !== "failure")
) {
disassociatePromises.push(
TemplatesService.disassociateWorkflowNode({
parentId: nodeId,
nodeId: failureNodeId,
edge: "failure"
})
);
}
});
}
if (nodeRef[workflowNodeId].originalNodeObject.always_nodes) {
nodeRef[workflowNodeId].originalNodeObject.always_nodes.forEach((alwaysNodeId) => {
if (
!deletedNodeIds.includes(alwaysNodeId) &&
(!linkMap[nodeId] ||
!linkMap[nodeId][alwaysNodeId] ||
linkMap[nodeId][alwaysNodeId] !== "always")
) {
disassociatePromises.push(
TemplatesService.disassociateWorkflowNode({
parentId: nodeId,
nodeId: alwaysNodeId,
edge: "always"
})
);
}
});
}
});
Object.keys(linkMap).map((sourceNodeId) => {
Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => {
const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId];
const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId];
switch(linkMap[sourceNodeId][targetNodeId]) {
case "success":
Object.keys(nodeRef).map((workflowNodeId) => {
let nodeId = nodeRef[workflowNodeId].originalNodeObject.id;
if (nodeRef[workflowNodeId].originalNodeObject.success_nodes) {
nodeRef[workflowNodeId].originalNodeObject.success_nodes.forEach((successNodeId) => {
if (
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes ||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
!deletedNodeIds.includes(successNodeId) &&
(!linkMap[nodeId] ||
!linkMap[nodeId][successNodeId] ||
linkMap[nodeId][successNodeId] !== "success")
) {
associatePromises.push(
TemplatesService.associateWorkflowNode({
parentId: parseInt(sourceNodeId),
nodeId: parseInt(targetNodeId),
disassociatePromises.push(
TemplatesService.disassociateWorkflowNode({
parentId: nodeId,
nodeId: successNodeId,
edge: "success"
})
);
}
break;
case "failure":
});
}
if (nodeRef[workflowNodeId].originalNodeObject.failure_nodes) {
nodeRef[workflowNodeId].originalNodeObject.failure_nodes.forEach((failureNodeId) => {
if (
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes ||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
!deletedNodeIds.includes(failureNodeId) &&
(!linkMap[nodeId] ||
!linkMap[nodeId][failureNodeId] ||
linkMap[nodeId][failureNodeId] !== "failure")
) {
associatePromises.push(
TemplatesService.associateWorkflowNode({
parentId: parseInt(sourceNodeId),
nodeId: parseInt(targetNodeId),
disassociatePromises.push(
TemplatesService.disassociateWorkflowNode({
parentId: nodeId,
nodeId: failureNodeId,
edge: "failure"
})
);
}
break;
case "always":
});
}
if (nodeRef[workflowNodeId].originalNodeObject.always_nodes) {
nodeRef[workflowNodeId].originalNodeObject.always_nodes.forEach((alwaysNodeId) => {
if (
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes ||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
!deletedNodeIds.includes(alwaysNodeId) &&
(!linkMap[nodeId] ||
!linkMap[nodeId][alwaysNodeId] ||
linkMap[nodeId][alwaysNodeId] !== "always")
) {
associatePromises.push(
TemplatesService.associateWorkflowNode({
parentId: parseInt(sourceNodeId),
nodeId: parseInt(targetNodeId),
disassociatePromises.push(
TemplatesService.disassociateWorkflowNode({
parentId: nodeId,
nodeId: alwaysNodeId,
edge: "always"
})
);
}
break;
});
}
});
});
$q.all(disassociatePromises)
.then(() => {
let credentialPromises = credentialRequests.map((request) => {
return TemplatesService.postWorkflowNodeCredential({
id: request.id,
data: request.data
});
});
return $q.all(associatePromises.concat(credentialPromises))
.then(() => {
Wait('stop');
$scope.workflowChangesUnsaved = false;
$scope.workflowChangesStarted = false;
$scope.closeDialog();
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
});
});
}).catch(({
data,
status
}) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
Object.keys(linkMap).map((sourceNodeId) => {
Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => {
const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId];
const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId];
switch(linkMap[sourceNodeId][targetNodeId]) {
case "success":
if (
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes ||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
) {
associatePromises.push(
TemplatesService.associateWorkflowNode({
parentId: parseInt(sourceNodeId),
nodeId: parseInt(targetNodeId),
edge: "success"
})
);
}
break;
case "failure":
if (
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes ||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
) {
associatePromises.push(
TemplatesService.associateWorkflowNode({
parentId: parseInt(sourceNodeId),
nodeId: parseInt(targetNodeId),
edge: "failure"
})
);
}
break;
case "always":
if (
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes ||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
) {
associatePromises.push(
TemplatesService.associateWorkflowNode({
parentId: parseInt(sourceNodeId),
nodeId: parseInt(targetNodeId),
edge: "always"
})
);
}
break;
}
});
});
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
$q.all(disassociatePromises)
.then(() => {
let credentialPromises = credentialRequests.map((request) => {
return TemplatesService.postWorkflowNodeCredential({
id: request.id,
data: request.data
});
});
return $q.all(associatePromises.concat(credentialPromises))
.then(() => {
Wait('stop');
$scope.workflowChangesUnsaved = false;
$scope.workflowChangesStarted = false;
$scope.closeDialog();
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
});
});
}).catch(({
data,
status
}) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
});
});
});
}).catch(({ data, status }) => {
Wait('stop');
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER')
});
})
.catch(() => {
// TODO: handle
});
} else {

View File

@ -68,39 +68,7 @@
<div class="WorkflowLegend-maker">
<div class="WorkflowLegend-maker--left">
<i ng-class="{{ keyClassList }}" class="fa fa-compass Key-menuIcon" ng-click="toggleKey()"></i>
<ul ng-show="showKey" class="Key-list noselect">
<li class="Key-listItem">
<p class="Key-heading">{{strings.get('workflow_maker.KEY')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--success"></div>
<p class="Key-listItemContent">{{strings.get('workflow_maker.ON_SUCCESS')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--fail"></div>
<p class="Key-listItemContent">{{strings.get('workflow_maker.ON_FAILURE')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--always"></div>
<p class="Key-listItemContent">{{strings.get('workflow_maker.ALWAYS')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">P</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.PROJECT_SYNC')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">I</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.INVENTORY_SYNC')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">W</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.WORKFLOW')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--warning">!</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.WARNING')}}</p>
</li>
</ul>
<workflow-key ng-show="showKey"></workflow-key>
</div>
<div class="WorkflowLegend-maker--right">
<span class="WorkflowMaker-totalJobs">{{strings.get('workflow_maker.TOTAL_NODES')}}</span>

View File

@ -327,35 +327,7 @@
<div class="WorkflowLegend-details">
<div class="WorkflowLegend-details--left">
<i ng-class="{{ keyClassList }}" class="fa fa-compass Key-menuIcon" ng-click="toggleKey()"></i>
<ul ng-show="showKey" class="Key-list noselect">
<li class="Key-listItem">
<p class="Key-heading">{{strings.legend.KEY}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--success"></div>
<p class="Key-listItemContent">{{strings.legend.ON_SUCCESS}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--fail"></div>
<p class="Key-listItemContent">{{strings.legend.ON_FAILURE}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--always"></div>
<p class="Key-listItemContent">{{strings.legend.ALWAYS}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">P</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.legend.PROJECT_SYNC}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">I</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.legend.INVENTORY_SYNC}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">W</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.legend.WORKFLOW}}</p>
</li>
</ul>
<workflow-key ng-show="showKey"></workflow-key>
</div>
<div class="WorkflowLegend-details--right">
<i ng-class="{'WorkflowMaker-manualControlsIcon--active': showManualControls}" class="fa fa-cog WorkflowMaker-manualControlsIcon" aria-hidden="true" alt="Controls" ng-click="toggleManualControls()"></i>