Moved a significant amount of the tree generation logic out to the workflow service

This commit is contained in:
Michael Abashian
2016-11-15 09:51:51 -05:00
parent bcf768e7fc
commit 17b4b1e7a2
7 changed files with 333 additions and 423 deletions

View File

@@ -12,7 +12,7 @@ export default
return { return {
restrict: 'E', restrict: 'E',
scope: false, scope: false,
templateUrl: templateUrl('job-templates/labels/labelsList'), templateUrl: templateUrl('templates/labels/labelsList'),
link: function(scope, element, attrs) { link: function(scope, element, attrs) {
scope.showDelete = attrs.showDelete === 'true'; scope.showDelete = attrs.showDelete === 'true';
scope.seeMoreInactive = true; scope.seeMoreInactive = true;

View File

@@ -24,7 +24,7 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesA
workflowChart.name, workflowMaker.name workflowChart.name, workflowMaker.name
]) ])
.service('TemplatesService', templatesService) .service('TemplatesService', templatesService)
.service('WorkflowHelpService', workflowService) .service('WorkflowService', workflowService)
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) {
let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow, let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow,

View File

@@ -8,13 +8,13 @@
[ '$scope', '$stateParams', 'WorkflowForm', 'GenerateForm', 'Alert', 'ProcessErrors', [ '$scope', '$stateParams', 'WorkflowForm', 'GenerateForm', 'Alert', 'ProcessErrors',
'ClearScope', 'GetBasePath', '$q', 'ParseTypeChange', 'Wait', 'Empty', 'ClearScope', 'GetBasePath', '$q', 'ParseTypeChange', 'Wait', 'Empty',
'ToJSON', 'initSurvey', '$state', 'CreateSelect2', 'ParseVariableString', 'ToJSON', 'initSurvey', '$state', 'CreateSelect2', 'ParseVariableString',
'TemplatesService', 'OrganizationList', 'Rest', 'TemplatesService', 'OrganizationList', 'Rest', 'WorkflowService',
function( function(
$scope, $stateParams, WorkflowForm, GenerateForm, Alert, ProcessErrors, $scope, $stateParams, WorkflowForm, GenerateForm, Alert, ProcessErrors,
ClearScope, GetBasePath, $q, ParseTypeChange, Wait, Empty, ClearScope, GetBasePath, $q, ParseTypeChange, Wait, Empty,
ToJSON, SurveyControllerInit, $state, CreateSelect2, ParseVariableString, ToJSON, SurveyControllerInit, $state, CreateSelect2, ParseVariableString,
TemplatesService, OrganizationList, Rest TemplatesService, OrganizationList, Rest, WorkflowService
) {window.state = $state; ) {
ClearScope(); ClearScope();
@@ -40,90 +40,6 @@
$scope.associateRequests = []; $scope.associateRequests = [];
$scope.disassociateRequests = []; $scope.disassociateRequests = [];
$scope.workflowTree = {
data: {
id: 1,
canDelete: false,
canEdit: false,
canAddTo: true,
isStartNode: true,
unifiedJobTemplate: {
name: "Workflow Launch"
},
children: [],
deletedNodes: [],
totalNodes: 0
},
nextIndex: 2
};
function buildBranch(params) {
// params.nodeId
// params.parentId
// params.edgeType
// params.nodesObj
// params.isRoot
let treeNode = {
children: [],
c: "#D7D7D7",
id: $scope.workflowTree.nextIndex,
nodeId: params.nodeId,
canDelete: true,
canEdit: true,
canAddTo: true,
placeholder: false,
edgeType: params.edgeType,
unifiedJobTemplate: _.clone(params.nodesObj[params.nodeId].summary_fields.unified_job_template),
isNew: false,
edited: false,
originalEdge: params.edgeType,
originalNodeObj: _.clone(params.nodesObj[params.nodeId]),
promptValues: {},
isRoot: params.isRoot ? params.isRoot : false
};
$scope.workflowTree.data.totalNodes++;
$scope.workflowTree.nextIndex++;
if(params.parentId) {
treeNode.originalParentId = params.parentId;
}
// Loop across the success nodes and add them recursively
_.forEach(params.nodesObj[params.nodeId].success_nodes, function(successNodeId) {
treeNode.children.push(buildBranch({
nodeId: successNodeId,
parentId: params.nodeId,
edgeType: "success",
nodesObj: params.nodesObj
}));
});
// failure nodes
_.forEach(params.nodesObj[params.nodeId].failure_nodes, function(failureNodesId) {
treeNode.children.push(buildBranch({
nodeId: failureNodesId,
parentId: params.nodeId,
edgeType: "failure",
nodesObj: params.nodesObj
}));
});
// always nodes
_.forEach(params.nodesObj[params.nodeId].always_nodes, function(alwaysNodesId) {
treeNode.children.push(buildBranch({
nodeId: alwaysNodesId,
parentId: params.nodeId,
edgeType: "always",
nodesObj: params.nodesObj
}));
});
return treeNode;
}
function init() { function init() {
// Select2-ify the lables input // Select2-ify the lables input
@@ -195,40 +111,8 @@
TemplatesService.getWorkflowJobTemplateNodes(id) TemplatesService.getWorkflowJobTemplateNodes(id)
.then(function(data){ .then(function(data){
let nodesArray = data.data.results; $scope.workflowTree = WorkflowService.buildTree({
let nodesObj = {}; workflowNodes: data.data.results
let nonRootNodeIds = [];
let allNodeIds = [];
// Determine which nodes are root nodes
_.forEach(nodesArray, function(node) {
nodesObj[node.id] = _.clone(node);
allNodeIds.push(node.id);
_.forEach(node.success_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
_.forEach(node.failure_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
_.forEach(node.always_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
});
let rootNodes = _.difference(allNodeIds, nonRootNodeIds);
// Loop across the root nodes and re-build the tree
_.forEach(rootNodes, function(rootNodeId) {
let branch = buildBranch({
nodeId: rootNodeId,
edgeType: "always",
nodesObj: nodesObj,
isRoot: true
});
$scope.workflowTree.data.children.push(branch);
}); });
// TODO: I think that the workflow chart directive (and eventually d3) is meddling with // TODO: I think that the workflow chart directive (and eventually d3) is meddling with

View File

@@ -4,11 +4,11 @@
* All Rights Reserved * All Rights Reserved
*************************************************/ *************************************************/
export default ['$scope', 'WorkflowHelpService', 'generateList', 'TemplateList', 'ProjectList', export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'ProjectList',
'GetBasePath', 'Wait', 'TemplatesService', '$state', 'GetBasePath', 'Wait', 'TemplatesService', '$state',
'ProcessErrors', 'InventorySourcesList', 'CreateSelect2', 'WorkflowMakerForm', 'ProcessErrors', 'InventorySourcesList', 'CreateSelect2', 'WorkflowMakerForm',
'GenerateForm', 'InventoryList', 'CredentialList', '$q', 'GenerateForm', 'InventoryList', 'CredentialList', '$q',
function($scope, WorkflowHelpService, GenerateList, TemplateList, ProjectList, function($scope, WorkflowService, GenerateList, TemplateList, ProjectList,
GetBasePath, Wait, TemplatesService, $state, GetBasePath, Wait, TemplatesService, $state,
ProcessErrors, InventorySourcesList, CreateSelect2, WorkflowMakerForm, ProcessErrors, InventorySourcesList, CreateSelect2, WorkflowMakerForm,
GenerateForm, InventoryList, CredentialList, $q) { GenerateForm, InventoryList, CredentialList, $q) {
@@ -78,7 +78,7 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'TemplateList',
$scope.addParent = parent; $scope.addParent = parent;
$scope.betweenTwoNodes = betweenTwoNodes; $scope.betweenTwoNodes = betweenTwoNodes;
$scope.placeholderNode = WorkflowHelpService.addPlaceholderNode({ $scope.placeholderNode = WorkflowService.addPlaceholderNode({
parent: parent, parent: parent,
betweenTwoNodes: betweenTwoNodes, betweenTwoNodes: betweenTwoNodes,
tree: $scope.treeData.data, tree: $scope.treeData.data,
@@ -87,7 +87,7 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'TemplateList',
$scope.treeData.nextIndex++; $scope.treeData.nextIndex++;
let siblingConnectionTypes = WorkflowHelpService.getSiblingConnectionTypes({ let siblingConnectionTypes = WorkflowService.getSiblingConnectionTypes({
tree: $scope.treeData.data, tree: $scope.treeData.data,
parentId: betweenTwoNodes ? parent.source.id : parent.id parentId: betweenTwoNodes ? parent.source.id : parent.id
}); });
@@ -187,7 +187,7 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'TemplateList',
$scope.cancelNodeForm = function() { $scope.cancelNodeForm = function() {
if ($scope.workflowMakerFormConfig.nodeMode === "add") { if ($scope.workflowMakerFormConfig.nodeMode === "add") {
// Remove the placeholder node from the tree // Remove the placeholder node from the tree
WorkflowHelpService.removeNodeFromTree({ WorkflowService.removeNodeFromTree({
tree: $scope.treeData.data, tree: $scope.treeData.data,
nodeToBeDeleted: $scope.placeholderNode nodeToBeDeleted: $scope.placeholderNode
}); });
@@ -212,12 +212,12 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'TemplateList',
$scope.workflowMakerFormConfig.nodeMode = "edit"; $scope.workflowMakerFormConfig.nodeMode = "edit";
let parent = WorkflowHelpService.searchTree({ let parent = WorkflowService.searchTree({
element: $scope.treeData.data, element: $scope.treeData.data,
matchingId: nodeToEdit.parent.id matchingId: nodeToEdit.parent.id
}); });
$scope.nodeBeingEdited = WorkflowHelpService.searchTree({ $scope.nodeBeingEdited = WorkflowService.searchTree({
element: parent, element: parent,
matchingId: nodeToEdit.id matchingId: nodeToEdit.id
}); });
@@ -427,7 +427,7 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'TemplateList',
// TODO: turn this into a promise so that we can handle errors // TODO: turn this into a promise so that we can handle errors
WorkflowHelpService.removeNodeFromTree({ WorkflowService.removeNodeFromTree({
tree: $scope.treeData.data, tree: $scope.treeData.data,
nodeToBeDeleted: $scope.nodeToBeDeleted nodeToBeDeleted: $scope.nodeToBeDeleted
}); });

View File

@@ -14,7 +14,7 @@ export default ['templateUrl', 'CreateDialog', 'Wait', '$state',
canAddWorkflowJobTemplate: '=' canAddWorkflowJobTemplate: '='
}, },
restrict: 'E', restrict: 'E',
templateUrl: templateUrl('job-templates/workflow-maker/workflow-maker'), templateUrl: templateUrl('templates/workflows/workflow-maker/workflow-maker'),
controller: workflowMakerController, controller: workflowMakerController,
link: function(scope) { link: function(scope) {
CreateDialog({ CreateDialog({

View File

@@ -117,6 +117,139 @@ export default [function(){
} }
return Object.keys(siblingConnectionTypes); return Object.keys(siblingConnectionTypes);
},
buildTree: function(params) {
//params.workflowNodes
let _this = this;
let treeData = {
data: {
id: 1,
canDelete: false,
canEdit: false,
canAddTo: true,
isStartNode: true,
unifiedJobTemplate: {
name: "Workflow Launch"
},
children: [],
deletedNodes: [],
totalNodes: 0
},
nextIndex: 2
};
let nodesArray = params.workflowNodes;
let nodesObj = {};
let nonRootNodeIds = [];
let allNodeIds = [];
// Determine which nodes are root nodes
_.forEach(nodesArray, function(node) {
nodesObj[node.id] = _.clone(node);
allNodeIds.push(node.id);
_.forEach(node.success_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
_.forEach(node.failure_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
_.forEach(node.always_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
});
let rootNodes = _.difference(allNodeIds, nonRootNodeIds);
// Loop across the root nodes and re-build the tree
_.forEach(rootNodes, function(rootNodeId) {
let branch = _this.buildBranch({
nodeId: rootNodeId,
edgeType: "always",
nodesObj: nodesObj,
isRoot: true,
treeData: treeData
});
treeData.data.children.push(branch);
});
return treeData;
},
buildBranch: function(params) {
// params.nodeId
// params.parentId
// params.edgeType
// params.nodesObj
// params.isRoot
// params.treeData
let _this = this;
let treeNode = {
children: [],
c: "#D7D7D7",
id: params.treeData.nextIndex,
nodeId: params.nodeId,
canDelete: true,
canEdit: true,
canAddTo: true,
placeholder: false,
edgeType: params.edgeType,
unifiedJobTemplate: _.clone(params.nodesObj[params.nodeId].summary_fields.unified_job_template),
isNew: false,
edited: false,
originalEdge: params.edgeType,
originalNodeObj: _.clone(params.nodesObj[params.nodeId]),
promptValues: {},
isRoot: params.isRoot ? params.isRoot : false
};
params.treeData.data.totalNodes++;
params.treeData.nextIndex++;
if(params.parentId) {
treeNode.originalParentId = params.parentId;
}
// Loop across the success nodes and add them recursively
_.forEach(params.nodesObj[params.nodeId].success_nodes, function(successNodeId) {
treeNode.children.push(_this.buildBranch({
nodeId: successNodeId,
parentId: params.nodeId,
edgeType: "success",
nodesObj: params.nodesObj,
treeData: params.treeData
}));
});
// failure nodes
_.forEach(params.nodesObj[params.nodeId].failure_nodes, function(failureNodesId) {
treeNode.children.push(_this.buildBranch({
nodeId: failureNodesId,
parentId: params.nodeId,
edgeType: "failure",
nodesObj: params.nodesObj,
treeData: params.treeData
}));
});
// always nodes
_.forEach(params.nodesObj[params.nodeId].always_nodes, function(alwaysNodesId) {
treeNode.children.push(_this.buildBranch({
nodeId: alwaysNodesId,
parentId: params.nodeId,
edgeType: "always",
nodesObj: params.nodesObj,
treeData: params.treeData
}));
});
return treeNode;
} }
}; };
}]; }];

View File

@@ -6,6 +6,7 @@ export default ['workflowData',
'$scope', '$scope',
'ParseTypeChange', 'ParseTypeChange',
'ParseVariableString', 'ParseVariableString',
'WorkflowService',
function(workflowData, function(workflowData,
workflowResultsService, workflowResultsService,
workflowDataOptions, workflowDataOptions,
@@ -13,306 +14,198 @@ export default ['workflowData',
workflowNodes, workflowNodes,
$scope, $scope,
ParseTypeChange, ParseTypeChange,
ParseVariableString ParseVariableString,
WorkflowService
) { ) {
var getTowerLinks = function() {
var getTowerLink = function(key) { var getTowerLinks = function() {
if ($scope.workflow.related[key]) { var getTowerLink = function(key) {
return '/#/' + $scope.workflow.related[key] if ($scope.workflow.related[key]) {
.split('api/v1/')[1]; return '/#/' + $scope.workflow.related[key]
} .split('api/v1/')[1];
else { }
return null; else {
} return null;
}
};
$scope.workflow_template_link = '/#/templates/workflow_job_template/'+$scope.workflow.workflow_job_template;
$scope.created_by_link = getTowerLink('created_by');
$scope.cloud_credential_link = getTowerLink('cloud_credential');
$scope.network_credential_link = getTowerLink('network_credential');
}; };
$scope.workflow_template_link = '/#/templates/workflow_job_template/'+$scope.workflow.workflow_job_template; var getTowerLabels = function() {
$scope.created_by_link = getTowerLink('created_by'); var getTowerLabel = function(key) {
$scope.cloud_credential_link = getTowerLink('cloud_credential'); if ($scope.workflowOptions && $scope.workflowOptions[key]) {
$scope.network_credential_link = getTowerLink('network_credential'); return $scope.workflowOptions[key].choices
}; .filter(val => val[0] === $scope.workflow[key])
.map(val => val[1])[0];
} else {
return null;
}
};
var getTowerLabels = function() { $scope.status_label = getTowerLabel('status');
var getTowerLabel = function(key) { $scope.type_label = getTowerLabel('job_type');
if ($scope.workflowOptions && $scope.workflowOptions[key]) { $scope.verbosity_label = getTowerLabel('verbosity');
return $scope.workflowOptions[key].choices };
.filter(val => val[0] === $scope.workflow[key])
.map(val => val[1])[0]; function init() {
} else { // put initially resolved request data on scope
return null; $scope.workflow = workflowData;
$scope.workflow_nodes = workflowNodes;
$scope.workflowOptions = workflowDataOptions.actions.GET;
$scope.labels = jobLabels;
// turn related api browser routes into tower routes
getTowerLinks();
// use options labels to manipulate display of details
getTowerLabels();
// set up a read only code mirror for extra vars
$scope.variables = ParseVariableString($scope.workflow.extra_vars);
$scope.parseType = 'yaml';
ParseTypeChange({ scope: $scope,
field_id: 'pre-formatted-variables',
readOnly: true });
// Click binding for the expand/collapse button on the standard out log
$scope.stdoutFullScreen = false;
$scope.stdoutArr = [];
$scope.treeData = WorkflowService.buildTree({
workflowNodes: workflowNodes
});
// TODO: I think that the workflow chart directive (and eventually d3) is meddling with
// this treeData object and removing the children object for some reason (?)
// This happens on occasion and I think is a race condition (?)
if(!$scope.treeData.data.children) {
$scope.treeData.data.children = [];
} }
};
$scope.status_label = getTowerLabel('status'); $scope.canAddWorkflowJobTemplate = false;
$scope.type_label = getTowerLabel('job_type');
$scope.verbosity_label = getTowerLabel('verbosity');
};
// var getTotalHostCount = function(count) {
// return Object
// .keys(count).reduce((acc, i) => acc += count[i], 0);
// };
// put initially resolved request data on scope
$scope.workflow = workflowData;
$scope.workflow_nodes = workflowNodes;
$scope.workflowOptions = workflowDataOptions.actions.GET;
$scope.labels = jobLabels;
// turn related api browser routes into tower routes
getTowerLinks();
// use options labels to manipulate display of details
getTowerLabels();
// set up a read only code mirror for extra vars
$scope.variables = ParseVariableString($scope.workflow.extra_vars);
$scope.parseType = 'yaml';
ParseTypeChange({ scope: $scope,
field_id: 'pre-formatted-variables',
readOnly: true });
// Click binding for the expand/collapse button on the standard out log
$scope.stdoutFullScreen = false;
$scope.toggleStdoutFullscreen = function() {
$scope.stdoutFullScreen = !$scope.stdoutFullScreen;
};
$scope.deleteJob = function() {
workflowResultsService.deleteJob($scope.workflow);
};
$scope.cancelJob = function() {
workflowResultsService.cancelJob($scope.workflow);
};
$scope.relaunchJob = function() {
workflowResultsService.relaunchJob($scope);
};
$scope.stdoutArr = [];
$scope.treeData = {
data: {
id: 1,
canDelete: false,
canEdit: false,
canAddTo: true,
isStartNode: true,
unifiedJobTemplate: {
name: "Workflow Launch"
},
children: [],
deletedNodes: [],
totalNodes: 0
},
nextIndex: 2
};
function buildBranch(params) {
// params.nodeId
// params.parentId
// params.edgeType
// params.nodesObj
// params.isRoot
let treeNode = {
children: [],
c: "#D7D7D7",
id: $scope.treeData.nextIndex,
nodeId: params.nodeId,
canDelete: true,
canEdit: true,
canAddTo: true,
placeholder: false,
edgeType: params.edgeType,
unifiedJobTemplate: _.clone(params.nodesObj[params.nodeId].summary_fields.unified_job_template),
isNew: false,
edited: false,
originalEdge: params.edgeType,
originalNodeObj: _.clone(params.nodesObj[params.nodeId]),
promptValues: {},
isRoot: params.isRoot ? params.isRoot : false
};
$scope.treeData.data.totalNodes++;
$scope.treeData.nextIndex++;
if(params.parentId) {
treeNode.originalParentId = params.parentId;
} }
// Loop across the success nodes and add them recursively // var getTotalHostCount = function(count) {
_.forEach(params.nodesObj[params.nodeId].success_nodes, function(successNodeId) { // return Object
treeNode.children.push(buildBranch({ // .keys(count).reduce((acc, i) => acc += count[i], 0);
nodeId: successNodeId, // };
parentId: params.nodeId,
edgeType: "success",
nodesObj: params.nodesObj $scope.toggleStdoutFullscreen = function() {
})); $scope.stdoutFullScreen = !$scope.stdoutFullScreen;
};
$scope.deleteJob = function() {
workflowResultsService.deleteJob($scope.workflow);
};
$scope.cancelJob = function() {
workflowResultsService.cancelJob($scope.workflow);
};
$scope.relaunchJob = function() {
workflowResultsService.relaunchJob($scope);
};
// EVENT STUFF BELOW
// just putting the event queue on scope so it can be inspected in the
// console
// $scope.event_queue = eventQueue.queue;
// $scope.defersArr = eventQueue.populateDefers;
// This is where the async updates to the UI actually happen.
// Flow is event queue munging in the service -> $scope setting in here
// var processEvent = function(event) {
// // put the event in the queue
// eventQueue.populate(event).then(mungedEvent => {
// // make changes to ui based on the event returned from the queue
// if (mungedEvent.changes) {
// mungedEvent.changes.forEach(change => {
// // we've got a change we need to make to the UI!
// // update the necessary scope and make the change
// if (change === 'startTime' && !$scope.workflow.start) {
// $scope.workflow.start = mungedEvent.startTime;
// }
//
// if (change === 'count' && !$scope.countFinished) {
// // for all events that affect the host count,
// // update the status bar as well as the host
// // count badge
// $scope.count = mungedEvent.count;
// $scope.hostCount = getTotalHostCount(mungedEvent
// .count);
// }
//
// if (change === 'playCount') {
// $scope.playCount = mungedEvent.playCount;
// }
//
// if (change === 'taskCount') {
// $scope.taskCount = mungedEvent.taskCount;
// }
//
// if (change === 'finishedTime' && !$scope.workflow.finished) {
// $scope.workflow.finished = mungedEvent.finishedTime;
// }
//
// if (change === 'countFinished') {
// // the playbook_on_stats event actually lets
// // us know that we don't need to iteratively
// // look at event to update the host counts
// // any more.
// $scope.countFinished = true;
// }
//
// if(change === 'stdout'){
// angular
// .element(".JobResultsStdOut-stdoutContainer")
// .append($compile(mungedEvent
// .stdout)($scope));
// }
// });
// }
//
// // the changes have been processed in the ui, mark it in the queue
// eventQueue.markProcessed(event);
// });
// };
// PULL! grab completed event data and process each event
// TODO: implement retry logic in case one of these requests fails
// var getEvents = function(url) {
// workflowResultsService.getEvents(url)
// .then(events => {
// events.results.forEach(event => {
// // get the name in the same format as the data
// // coming over the websocket
// event.event_name = event.event;
// processEvent(event);
// });
// if (events.next) {
// getEvents(events.next);
// }
// });
// };
// getEvents($scope.job.related.job_events);
// // Processing of job_events messages from the websocket
// $scope.$on(`ws-job_events-${$scope.workflow.id}`, function(e, data) {
// processEvent(data);
// });
// Processing of job-status messages from the websocket
$scope.$on(`ws-jobs`, function(e, data) {
if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
$scope.workflow.status = data.status;
}
}); });
// failure nodes init();
_.forEach(params.nodesObj[params.nodeId].failure_nodes, function(failureNodesId) {
treeNode.children.push(buildBranch({
nodeId: failureNodesId,
parentId: params.nodeId,
edgeType: "failure",
nodesObj: params.nodesObj
}));
});
// always nodes
_.forEach(params.nodesObj[params.nodeId].always_nodes, function(alwaysNodesId) {
treeNode.children.push(buildBranch({
nodeId: alwaysNodesId,
parentId: params.nodeId,
edgeType: "always",
nodesObj: params.nodesObj
}));
});
return treeNode;
}
let nodesArray = $scope.workflow_nodes;
let nodesObj = {};
let nonRootNodeIds = [];
let allNodeIds = [];
// Determine which nodes are root nodes
_.forEach(nodesArray, function(node) {
nodesObj[node.id] = _.clone(node);
allNodeIds.push(node.id);
_.forEach(node.success_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
_.forEach(node.failure_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
_.forEach(node.always_nodes, function(nodeId){
nonRootNodeIds.push(nodeId);
});
});
let rootNodes = _.difference(allNodeIds, nonRootNodeIds);
// Loop across the root nodes and re-build the tree
_.forEach(rootNodes, function(rootNodeId) {
let branch = buildBranch({
nodeId: rootNodeId,
edgeType: "always",
nodesObj: nodesObj,
isRoot: true
});
$scope.treeData.data.children.push(branch);
});
// TODO: I think that the workflow chart directive (and eventually d3) is meddling with
// this treeData object and removing the children object for some reason (?)
// This happens on occasion and I think is a race condition (?)
if(!$scope.treeData.data.children) {
$scope.treeData.data.children = [];
}
$scope.canAddWorkflowJobTemplate = false;
// EVENT STUFF BELOW
// just putting the event queue on scope so it can be inspected in the
// console
// $scope.event_queue = eventQueue.queue;
// $scope.defersArr = eventQueue.populateDefers;
// This is where the async updates to the UI actually happen.
// Flow is event queue munging in the service -> $scope setting in here
// var processEvent = function(event) {
// // put the event in the queue
// eventQueue.populate(event).then(mungedEvent => {
// // make changes to ui based on the event returned from the queue
// if (mungedEvent.changes) {
// mungedEvent.changes.forEach(change => {
// // we've got a change we need to make to the UI!
// // update the necessary scope and make the change
// if (change === 'startTime' && !$scope.workflow.start) {
// $scope.workflow.start = mungedEvent.startTime;
// }
//
// if (change === 'count' && !$scope.countFinished) {
// // for all events that affect the host count,
// // update the status bar as well as the host
// // count badge
// $scope.count = mungedEvent.count;
// $scope.hostCount = getTotalHostCount(mungedEvent
// .count);
// }
//
// if (change === 'playCount') {
// $scope.playCount = mungedEvent.playCount;
// }
//
// if (change === 'taskCount') {
// $scope.taskCount = mungedEvent.taskCount;
// }
//
// if (change === 'finishedTime' && !$scope.workflow.finished) {
// $scope.workflow.finished = mungedEvent.finishedTime;
// }
//
// if (change === 'countFinished') {
// // the playbook_on_stats event actually lets
// // us know that we don't need to iteratively
// // look at event to update the host counts
// // any more.
// $scope.countFinished = true;
// }
//
// if(change === 'stdout'){
// angular
// .element(".JobResultsStdOut-stdoutContainer")
// .append($compile(mungedEvent
// .stdout)($scope));
// }
// });
// }
//
// // the changes have been processed in the ui, mark it in the queue
// eventQueue.markProcessed(event);
// });
// };
// PULL! grab completed event data and process each event
// TODO: implement retry logic in case one of these requests fails
// var getEvents = function(url) {
// workflowResultsService.getEvents(url)
// .then(events => {
// events.results.forEach(event => {
// // get the name in the same format as the data
// // coming over the websocket
// event.event_name = event.event;
// processEvent(event);
// });
// if (events.next) {
// getEvents(events.next);
// }
// });
// };
// getEvents($scope.job.related.job_events);
// // Processing of job_events messages from the websocket
// $scope.$on(`ws-job_events-${$scope.workflow.id}`, function(e, data) {
// processEvent(data);
// });
// Processing of job-status messages from the websocket
$scope.$on(`ws-jobs`, function(e, data) {
if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
$scope.workflow.status = data.status;
}
});
}]; }];