diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js index eca1f5b546..e5bfcc2251 100644 --- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js +++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js @@ -9,7 +9,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge return { scope: { - treeState: '=', + graphState: '=', readOnly: '<', addNodeWithoutChild: '&', addNodeWithChild: '&', @@ -55,6 +55,11 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function init() { force = d3.layout.force() + // .gravity(0) + // .linkStrength(2) + // .friction(0.4) + // .charge(-4000) + // .linkDistance(300) .gravity(0) .charge(-300) .linkDistance(300) @@ -206,7 +211,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function update() { if(scope.dimensionsSet) { let links = svgGroup.selectAll(".WorkflowChart-link") - .data(scope.treeState.arrayOfLinksForChart, function(d) { return `${d.source.id}-${d.target.id}`; }); + .data(scope.graphState.arrayOfLinksForChart, function(d) { return `${d.source.id}-${d.target.id}`; }); // Remove any stale links links.exit().remove(); @@ -217,7 +222,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge baseSvg.selectAll(".WorkflowChart-linkPath") .attr("class", function(d) { - return (d.source.isNodeBeingAdded || d.target.isNodeBeingAdded) ? "WorkflowChart-linkPath WorkflowChart-isNodeBeingAdded" : "WorkflowChart-linkPath"; + return (d.source.id === scope.graphState.nodeBeingAdded || d.target.id === scope.graphState.nodeBeingAdded) ? "WorkflowChart-linkPath WorkflowChart-isNodeBeingAdded" : "WorkflowChart-linkPath"; }) .attr('stroke', function(d) { let edgeType = d.edgeType; @@ -241,7 +246,11 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("id", function(d){return "link-" + d.source.id + "-" + d.target.id + "-overlay";}) .attr("class", function(d) { let linkClasses = ["WorkflowChart-linkOverlay"]; - if (d.isLinkBeingEdited) { + if ( + scope.graphState.linkBeingEdited && + d.source.id === scope.graphState.linkBeingEdited.source && + d.target.id === scope.graphState.linkBeingEdited.target + ) { linkClasses.push("WorkflowChart-link--active"); } return linkClasses.join(' '); @@ -249,10 +258,10 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge baseSvg.selectAll(".WorkflowChart-circleBetweenNodes") .attr("id", function(d){return "link-" + d.source.id + "-" + d.target.id + "-add";}) - .style("display", function(d) { return (scope.treeState.isLinkMode || d.source.isNodeBeingAdded || d.target.isNodeBeingAdded || scope.readOnly) ? "none" : null; }); + .style("display", function(d) { return (scope.graphState.isLinkMode || d.source.id === scope.graphState.nodeBeingAdded || d.target.id === scope.graphState.nodeBeingAdded || scope.readOnly) ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-betweenNodesIcon") - .style("display", function(d) { return (scope.treeState.isLinkMode || d.source.isNodeBeingAdded || d.target.isNodeBeingAdded || scope.readOnly) ? "none" : null; }); + .style("display", function(d) { return (scope.graphState.isLinkMode || d.source.id === scope.graphState.nodeBeingAdded || d.target.id === scope.graphState.nodeBeingAdded || scope.readOnly) ? "none" : null; }); // Add any new links @@ -263,7 +272,11 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge linkEnter.append("polygon", "g") .attr("class", function(d) { let linkClasses = ["WorkflowChart-linkOverlay"]; - if (d.isLinkBeingEdited) { + if ( + scope.graphState.linkBeingEdited && + d.source.id === scope.graphState.linkBeingEdited.source && + d.target.id === scope.graphState.linkBeingEdited.target + ) { linkClasses.push("WorkflowChart-link--active"); } return linkClasses.join(' '); @@ -271,8 +284,9 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("id", function(d){return "link-" + d.source.id + "-" + d.target.id + "-overlay";}) .call(edit_link) .on("mouseover", function(d) { - if(!scope.treeState.isLinkMode && !d.source.isStartNode && !d.source.isNodeBeingAdded && !d.target.isNodeBeingAdded && scope.mode !== 'details') { - d3.select("#link-" + d.source.id + "-" + d.target.id) + if(!scope.graphState.isLinkMode && !d.source.isStartNode && d.source.id !== scope.graphState.nodeBeingAdded && d.target.id !== scope.graphState.nodeBeingAdded && scope.mode !== 'details') { + $(`#link-${d.source.id}-${d.target.id}`).appendTo(`#aw-workflow-chart-g`); + d3.select(`#link-${d.source.id}-${d.target.id}`) .classed("WorkflowChart-linkHovering", true); let xPos, yPos, arrowClass; @@ -314,7 +328,8 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge }) .on("mouseout", function(d){ - if(!d.source.isStartNode && !d.target.isNodeBeingAdded && scope.mode !== 'details') { + if(!d.source.isStartNode && d.target.id !== scope.graphState.nodeBeingAdded && scope.mode !== 'details') { + $(`#aw-workflow-chart-g`).prepend($(`#link-${d.source.id}-${d.target.id}`)); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-linkHovering", false); } @@ -324,11 +339,12 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge // Add entering links in the parent’s old position. linkEnter.append("line") .attr("class", function(d) { - return (d.source.isNodeBeingAdded || d.target.isNodeBeingAdded) ? "WorkflowChart-linkPath WorkflowChart-isNodeBeingAdded" : "WorkflowChart-linkPath"; + return (d.source.id === scope.graphState.nodeBeingAdded || d.target.id === scope.graphState.nodeBeingAdded) ? "WorkflowChart-linkPath WorkflowChart-isNodeBeingAdded" : "WorkflowChart-linkPath"; }) .call(edit_link) .on("mouseenter", function(d) { - if(!scope.treeState.isLinkMode && !d.source.isStartNode && !d.source.isNodeBeingAdded && !d.target.isNodeBeingAdded && scope.mode !== 'details') { + if(!scope.graphState.isLinkMode && !d.source.isStartNode && d.source.id !== scope.graphState.nodeBeingAdded && d.target.id !== scope.graphState.nodeBeingAdded && scope.mode !== 'details') { + $(`#link-${d.source.id}-${d.target.id}`).appendTo(`#aw-workflow-chart-g`); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-linkHovering", true); @@ -370,7 +386,8 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge } }) .on("mouseleave", function(d){ - if(!d.source.isStartNode && !d.target.isNodeBeingAdded && scope.mode !== 'details') { + if(!d.source.isStartNode && d.target.id !== scope.graphState.nodeBeingAdded && scope.mode !== 'details') { + $(`#aw-workflow-chart-g`).prepend($(`#link-${d.source.id}-${d.target.id}`)); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-linkHovering", false); } @@ -398,13 +415,15 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("id", function(d){return "link-" + d.source.id + "-" + d.target.id + "-add";}) .attr("r", 10) .attr("class", "WorkflowChart-addCircle WorkflowChart-circleBetweenNodes") - .style("display", function(d) { return (scope.treeState.isLinkMode || d.source.isNodeBeingAdded || d.target.isNodeBeingAdded || scope.readOnly) ? "none" : null; }) + .style("display", function(d) { return (scope.graphState.isLinkMode || d.source.id === scope.graphState.nodeBeingAdded || d.target.id === scope.graphState.nodeBeingAdded || scope.readOnly) ? "none" : null; }) .call(add_node_with_child) .on("mouseover", function(d) { + $(`#link-${d.source.id}-${d.target.id}`).appendTo(`#aw-workflow-chart-g`); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-addHovering", true); }) .on("mouseout", function(d){ + $(`#aw-workflow-chart-g`).prepend($(`#link-${d.source.id}-${d.target.id}`)); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-addHovering", false); }); @@ -416,13 +435,15 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .size(60) .type("cross") ) - .style("display", function(d) { return (scope.treeState.isLinkMode || d.source.isNodeBeingAdded || d.target.isNodeBeingAdded || scope.readOnly) ? "none" : null; }) + .style("display", function(d) { return (scope.graphState.isLinkMode || d.source.id === scope.graphState.nodeBeingAdded || d.target.id === scope.graphState.nodeBeingAdded || scope.readOnly) ? "none" : null; }) .call(add_node_with_child) .on("mouseover", function(d) { + $(`#link-${d.source.id}-${d.target.id}`).appendTo(`#aw-workflow-chart-g`); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-addHovering", true); }) .on("mouseout", function(d){ + $(`#aw-workflow-chart-g`).prepend($(`#link-${d.source.id}-${d.target.id}`)); d3.select("#link-" + d.source.id + "-" + d.target.id) .classed("WorkflowChart-addHovering", false); }); @@ -435,29 +456,29 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge let linkAddBetweenIcon = svgGroup.selectAll(".WorkflowChart-betweenNodesIcon"); let nodes = svgGroup.selectAll('.WorkflowChart-node') - .data(scope.treeState.arrayOfNodesForChart, function(d) { return d.id; }); + .data(scope.graphState.arrayOfNodesForChart, function(d) { return d.id; }); // Remove any stale nodes nodes.exit().remove(); // Update existing nodes baseSvg.selectAll(".WorkflowChart-nodeAddCircle") - .style("display", function(d) { return scope.treeState.isLinkMode || d.isNodeBeingAdded || scope.readOnly ? "none" : null; }); + .style("display", function(d) { return scope.graphState.isLinkMode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-nodeAddIcon") - .style("display", function(d) { return scope.treeState.isLinkMode || d.isNodeBeingAdded || scope.readOnly ? "none" : null; }); + .style("display", function(d) { return scope.graphState.isLinkMode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-linkCircle") - .style("display", function(d) { return scope.treeState.isLinkMode || d.isNodeBeingAdded || scope.readOnly ? "none" : null; }); + .style("display", function(d) { return scope.graphState.isLinkMode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-nodeLinkIcon") - .style("display", function(d) { return scope.treeState.isLinkMode || d.isNodeBeingAdded || scope.readOnly ? "none" : null; }); + .style("display", function(d) { return scope.graphState.isLinkMode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-nodeRemoveCircle") - .style("display", function(d) { return scope.treeState.isLinkMode || d.isNodeBeingAdded || scope.readOnly ? "none" : null; }); + .style("display", function(d) { return scope.graphState.isLinkMode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-nodeRemoveIcon") - .style("display", function(d) { return scope.treeState.isLinkMode || d.isNodeBeingAdded || scope.readOnly ? "none" : null; }); + .style("display", function(d) { return scope.graphState.isLinkMode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-rect") .attr('stroke', function(d) { @@ -477,7 +498,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge } }) .attr("class", function(d) { - let classString = d.isNodeBeingAdded ? "WorkflowChart-rect WorkflowChart-isNodeBeingAdded" : "WorkflowChart-rect"; + let classString = d.id === scope.graphState.nodeBeingAdded ? "WorkflowChart-rect WorkflowChart-isNodeBeingAdded" : "WorkflowChart-rect"; classString += !d.unifiedJobTemplate ? " WorkflowChart-dashedNode" : ""; return classString; }); @@ -561,17 +582,17 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .style("display", function(d){ return d.job && d.job.status && d.job.id ? null : "none"; }); baseSvg.selectAll(".WorkflowChart-deletedText") - .style("display", function(d){ return d.unifiedJobTemplate || d.isNodeBeingAdded ? "none" : null; }); + .style("display", function(d){ return d.unifiedJobTemplate || d.id === scope.graphState.nodeBeingAdded ? "none" : null; }); baseSvg.selectAll(".WorkflowChart-activeNode") - .style("display", function(d) { return d.isNodeBeingEdited ? null : "none"; }); + .style("display", function(d) { return d.id === scope.graphState.nodeBeingEdited ? null : "none"; }); baseSvg.selectAll(".WorkflowChart-elapsed") .style("display", function(d) { return (d.job && d.job.elapsed) ? null : "none"; }); baseSvg.selectAll(".WorkflowChart-addLinkCircle") - .attr("fill", function(d) { return scope.treeState.addLinkSource === d.id ? "#337AB7" : "#D7D7D7"; }) - .style("display", function(d) { return scope.treeState.isLinkMode && !d.isInvalidLinkTarget ? null : "none"; }); + .attr("fill", function(d) { return scope.graphState.addLinkSource === d.id ? "#337AB7" : "#D7D7D7"; }) + .style("display", function(d) { return scope.graphState.isLinkMode && !d.isInvalidLinkTarget ? null : "none"; }); // Add new nodes const nodeEnter = nodes @@ -619,7 +640,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("cx", nodeW) .attr("r", 8) .attr("class", "WorkflowChart-addLinkCircle") - .style("display", function() { return scope.treeState.isLinkMode ? null : "none"; }); + .style("display", function() { return scope.graphState.isLinkMode ? null : "none"; }); thisNode.append("rect") .attr("width", nodeW) .attr("height", nodeH) @@ -643,7 +664,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge }) .attr('stroke-width', "2px") .attr("class", function(d) { - let classString = d.isNodeBeingAdded ? "WorkflowChart-rect WorkflowChart-isNodeBeingAdded" : "WorkflowChart-rect"; + let classString = d.id === scope.graphState.nodeBeingAdded ? "WorkflowChart-rect WorkflowChart-isNodeBeingAdded" : "WorkflowChart-rect"; classString += !_.get(d, 'unifiedJobTemplate.name') ? " WorkflowChart-dashedNode" : ""; return classString; }); @@ -651,7 +672,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge thisNode.append("path") .attr("d", rounded_rect(1, 0, 5, nodeH, 5, 1, 0, 1, 0)) .attr("class", "WorkflowChart-activeNode") - .style("display", function(d) { return d.isNodeBeingEdited ? null : "none"; }); + .style("display", function(d) { return d.id === scope.graphState.nodeBeingEdited ? null : "none"; }); thisNode.append("text") .attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 20 : nodeW / 2; }) @@ -673,7 +694,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .html(function () { return `${TemplatesStrings.get('workflow_maker.DELETED')}`; }) - .style("display", function(d) { return d.unifiedJobTemplate || d.isNodeBeingAdded ? "none" : null; }); + .style("display", function(d) { return d.unifiedJobTemplate || d.id === scope.graphState.nodeBeingAdded ? "none" : null; }); thisNode.append("circle") .attr("cy", nodeH) @@ -738,6 +759,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .call(node_click) .on("mouseover", function(d) { if(!d.isStartNode) { + $(`#node-${d.id}`).appendTo(`#aw-workflow-chart-g`); let resourceName = (d.unifiedJobTemplate && d.unifiedJobTemplate.name) ? d.unifiedJobTemplate.name : ""; if(resourceName && resourceName.length > maxNodeTextLength) { // When the graph is initially rendered all the links come after the nodes (when you look at the dom). @@ -773,8 +795,8 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge }); } - if (scope.treeState.isLinkMode && !d.isInvalidLinkTarget && scope.treeState.addLinkSource !== d.id) { - let sourceNode = d3.select(`#node-${scope.treeState.addLinkSource}`); + if (scope.graphState.isLinkMode && !d.isInvalidLinkTarget && scope.graphState.addLinkSource !== d.id) { + let sourceNode = d3.select(`#node-${scope.graphState.addLinkSource}`); const sourceNodeX = d3.transform(sourceNode.attr("transform")).translate[0]; const sourceNodeY = d3.transform(sourceNode.attr("transform")).translate[1]; @@ -821,7 +843,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("cx", nodeW) .attr("r", 10) .attr("class", "WorkflowChart-addCircle WorkflowChart-nodeAddCircle") - .style("display", function(d) { return d.isNodeBeingAdded || scope.readOnly ? "none" : null; }) + .style("display", function(d) { return d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }) .call(add_node_without_child) .on("mouseover", function(d) { d3.select("#node-" + d.id) @@ -843,7 +865,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .size(60) .type("cross") ) - .style("display", function(d) { return d.isNodeBeingAdded || scope.readOnly ? "none" : null; }) + .style("display", function(d) { return d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }) .call(add_node_without_child) .on("mouseover", function(d) { d3.select("#node-" + d.id) @@ -863,7 +885,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("cy", nodeH/2) .attr("r", 10) .attr("class", "WorkflowChart-linkCircle") - .style("display", function(d) { return d.isNodeBeingAdded || scope.readOnly ? "none" : null; }) + .style("display", function(d) { return d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }) .call(add_link) .on("mouseover", function(d) { d3.select("#node-" + d.id) @@ -877,8 +899,6 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge d3.select("#node-" + d.id + "-link") .classed("WorkflowChart-linkButtonHovering", false); }); - // TODO: clean up the placement of this icon... this works but it's not - // clean thisNode.append("foreignObject") .attr("x", nodeW - 6) .attr("y", nodeH/2 - 9) @@ -887,7 +907,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge return ``; }) .attr("class", "WorkflowChart-nodeLinkIcon") - .style("display", function(d) { return d.isNodeBeingAdded || scope.readOnly ? "none" : null; }) + .style("display", function(d) { return d.id === scope.graphState.nodeBeingAdded || scope.readOnly ? "none" : null; }) .call(add_link) .on("mouseover", function(d) { d3.select("#node-" + d.id) @@ -907,7 +927,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .attr("cy", nodeH) .attr("r", 10) .attr("class", "WorkflowChart-nodeRemoveCircle") - .style("display", function(d) { return (d.isStartNode || d.isNodeBeingAdded || scope.readOnly) ? "none" : null; }) + .style("display", function(d) { return (d.isStartNode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly) ? "none" : null; }) .call(remove_node) .on("mouseover", function(d) { d3.select("#node-" + d.id) @@ -929,7 +949,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge .size(60) .type("cross") ) - .style("display", function(d) { return (d.isStartNode || d.isNodeBeingAdded || scope.readOnly) ? "none" : null; }) + .style("display", function(d) { return (d.isStartNode || d.id === scope.graphState.nodeBeingAdded || scope.readOnly) ? "none" : null; }) .call(remove_node) .on("mouseover", function(d) { d3.select("#node-" + d.id) @@ -1004,7 +1024,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge }); // TODO: this - // if(scope.treeState.arrayOfNodesForChart && scope.treeState.arrayOfNodesForChart > 1 && !graphLoaded) { + // if(scope.graphState.arrayOfNodesForChart && scope.graphState.arrayOfNodesForChart > 1 && !graphLoaded) { // zoomToFitChart(); // } @@ -1017,7 +1037,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge let tick = () => { linkLines .each(function(d) { - d.target.y = scope.treeState.depthMap[d.target.id] * 300; + d.target.y = scope.graphState.depthMap[d.target.id] * 300; }) .attr("x1", function(d) { return d.target.y; }) .attr("y1", function(d) { return d.target.x + (nodeH/2); }) @@ -1068,8 +1088,8 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge }; force - .nodes(scope.treeState.arrayOfNodesForChart) - .links(scope.treeState.arrayOfLinksForChart) + .nodes(scope.graphState.arrayOfNodesForChart) + .links(scope.graphState.arrayOfLinksForChart) .on("tick", tick) .start(); } @@ -1086,7 +1106,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function add_node_without_child() { this.on("click", function(d) { - if(!scope.readOnly && !scope.treeState.isLinkMode) { + if(!scope.readOnly && !scope.graphState.isLinkMode) { scope.addNodeWithoutChild({ parent: d }); @@ -1096,7 +1116,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function add_node_with_child() { this.on("click", function(d) { - if(!scope.readOnly && !scope.treeState.isLinkMode) { + if(!scope.readOnly && !scope.graphState.isLinkMode) { scope.addNodeWithChild({ link: d }); @@ -1106,7 +1126,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function remove_node() { this.on("click", function(d) { - if(!d.isStartNode && !scope.readOnly && !scope.treeState.isLinkMode) { + if(!d.isStartNode && !scope.readOnly && !scope.graphState.isLinkMode) { scope.deleteNode({ nodeToDelete: d }); @@ -1116,13 +1136,13 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function node_click() { this.on("click", function(d) { - if(!d.isStartNode && !scope.readOnly){ - if(scope.treeState.isLinkMode && !d.isInvalidLinkTarget) { + if(d.id !== scope.graphState.nodeBeingAdded && !scope.readOnly){ + if(scope.graphState.isLinkMode && !d.isInvalidLinkTarget) { $('.WorkflowChart-potentialLink').remove(); scope.selectNodeForLinking({ nodeToStartLink: d }); - } else if(!scope.treeState.isLinkMode) { + } else if(!scope.graphState.isLinkMode) { scope.editNode({ nodeToEdit: d }); @@ -1134,7 +1154,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function edit_link() { this.on("click", function(d) { - if(!scope.treeState.isLinkMode && !d.source.isStartNode && !d.source.isNodeBeingAdded && !d.target.isNodeBeingAdded && scope.mode !== 'details'){ + if(!scope.graphState.isLinkMode && !d.source.isStartNode && d.source.id !== scope.graphState.nodeBeingAdded && d.target.id !== scope.graphState.nodeBeingAdded && scope.mode !== 'details'){ scope.editLink({ linkToEdit: d }); @@ -1144,7 +1164,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function add_link() { this.on("click", function(d) { - if (!scope.readOnly && !scope.treeState.isLinkMode) { + if (!scope.readOnly && !scope.graphState.isLinkMode) { scope.selectNodeForLinking({ nodeToStartLink: d }); @@ -1198,7 +1218,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge } scope.$on('refreshWorkflowChart', function(){ - if(scope.treeState) { + if(scope.graphState) { update(); } }); @@ -1219,12 +1239,12 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge zoomToFitChart(); }); - let clearWatchTreeState = scope.$watch('treeState.arrayOfNodesForChart', function(newVal) { + let clearWatchgraphState = scope.$watch('graphState.arrayOfNodesForChart', function(newVal) { if(newVal) { - // scope.treeState.arrayOfNodesForChart + // scope.graphState.arrayOfNodesForChart update(); - clearWatchTreeState(); + clearWatchgraphState(); } }); diff --git a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.controller.js b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.controller.js index 0bb164ea95..824527bcbb 100644 --- a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.controller.js +++ b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.controller.js @@ -12,11 +12,8 @@ export default ['$scope', 'TemplatesService', Empty, PromptService, Rest, TemplatesStrings, WorkflowChartService) { $scope.strings = TemplatesStrings; - // TODO: I don't think this needs to be on scope but changing it will require changes to - // all the prompt places $scope.preventCredsWithPasswords = true; - let credentialRequests = []; let deletedNodeIds = []; let workflowMakerNodeIdCounter = 1; let nodeIdToChartNodeIdMapping = {}; @@ -87,15 +84,16 @@ export default ['$scope', 'TemplatesService', $scope.closeWorkflowMaker = function() { // Revert the data to the master which was created when the dialog was opened - $scope.treeState.nodeTree = angular.copy($scope.treeStateMaster); + $scope.graphState.nodeTree = angular.copy($scope.graphStateMaster); $scope.closeDialog(); }; $scope.saveWorkflowMaker = function () { - if ($scope.treeState.arrayOfNodesForChart.length > 1) { + if ($scope.graphState.arrayOfNodesForChart.length > 1) { let addPromises = []; let editPromises = []; + let credentialsToPost = []; Object.keys(nodeRef).map((workflowMakerNodeId) => { if (nodeRef[workflowMakerNodeId].isNew) { @@ -104,27 +102,26 @@ export default ['$scope', 'TemplatesService', data: buildSendableNodeData(nodeRef[workflowMakerNodeId]) }).then(({data}) => { nodeRef[workflowMakerNodeId].originalNodeObject = data; - // TODO: do we need this? nodeIdToChartNodeIdMapping[data.id] = parseInt(workflowMakerNodeId); - // if (_.get(params, 'node.promptData.launchConf.ask_credential_on_launch')) { - // // This finds the credentials that were selected in the prompt but don't occur - // // in the template defaults - // let credentialsToPost = params.node.promptData.prompts.credentials.value.filter(function (credFromPrompt) { - // let defaultCreds = _.get(params, 'node.promptData.launchConf.defaults.credentials', []); - // return !defaultCreds.some(function (defaultCred) { - // return credFromPrompt.id === defaultCred.id; - // }); - // }); - // - // credentialsToPost.forEach((credentialToPost) => { - // credentialRequests.push({ - // id: data.data.id, - // data: { - // id: credentialToPost.id - // } - // }); - // }); - // } + if (_.get(nodeRef[workflowMakerNodeId], 'promptData.launchConf.ask_credential_on_launch')) { + // This finds the credentials that were selected in the prompt but don't occur + // in the template defaults + let credentialIdsToPost = nodeRef[workflowMakerNodeId].promptData.prompts.credentials.value.filter(function (credFromPrompt) { + let defaultCreds = _.get(nodeRef[workflowMakerNodeId], 'promptData.launchConf.defaults.credentials', []); + return !defaultCreds.some(function (defaultCred) { + return credFromPrompt.id === defaultCred.id; + }); + }); + + credentialIdsToPost.forEach((credentialToPost) => { + credentialsToPost.push({ + id: data.id, + data: { + id: credentialToPost.id + } + }); + }); + } })); } else if (nodeRef[workflowMakerNodeId].isEdited) { editPromises.push(TemplatesService.editWorkflowNode({ @@ -146,9 +143,9 @@ export default ['$scope', 'TemplatesService', let linkMap = {}; // Build a link map for easy access - $scope.treeState.arrayOfLinksForChart.forEach(link => { - // link.source.index of 0 is our artificial start node - if (link.source.index !== 0) { + $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]) { @@ -219,13 +216,13 @@ export default ['$scope', 'TemplatesService', Object.keys(linkMap).map((sourceNodeId) => { Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => { - const foo = nodeIdToChartNodeIdMapping[sourceNodeId]; - const bar = nodeIdToChartNodeIdMapping[targetNodeId]; + const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId]; + const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId]; switch(linkMap[sourceNodeId][targetNodeId]) { case "success": if ( - !nodeRef[foo].originalNodeObject.success_nodes || - !nodeRef[foo].originalNodeObject.success_nodes.includes(nodeRef[bar].id) + !nodeRef[sourceChartNodeId].originalNodeObject.success_nodes || + !nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].id) ) { associatePromises.push( TemplatesService.associateWorkflowNode({ @@ -238,8 +235,8 @@ export default ['$scope', 'TemplatesService', break; case "failure": if ( - !nodeRef[foo].originalNodeObject.failure_nodes || - !nodeRef[foo].originalNodeObject.failure_nodes.includes(nodeRef[bar].id) + !nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes || + !nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].id) ) { associatePromises.push( TemplatesService.associateWorkflowNode({ @@ -252,8 +249,8 @@ export default ['$scope', 'TemplatesService', break; case "always": if ( - !nodeRef[foo].originalNodeObject.always_nodes || - !nodeRef[foo].originalNodeObject.always_nodes.includes(nodeRef[bar].id) + !nodeRef[sourceChartNodeId].originalNodeObject.always_nodes || + !nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].id) ) { associatePromises.push( TemplatesService.associateWorkflowNode({ @@ -270,9 +267,7 @@ export default ['$scope', 'TemplatesService', $q.all(disassociatePromises) .then(function () { - - // TODO: don't forget about this.... - let credentialPromises = credentialRequests.map(function (request) { + let credentialPromises = credentialsToPost.map(function (request) { return TemplatesService.postWorkflowNodeCredential({ id: request.id, data: request.data @@ -291,8 +286,6 @@ export default ['$scope', 'TemplatesService', }); }); - // TODO: handle the case where the user deletes all the nodes - } else { let deletePromises = deletedNodeIds.map(function (nodeId) { @@ -314,18 +307,19 @@ export default ['$scope', 'TemplatesService', $scope.cancelNodeForm(); } - $scope.treeState.arrayOfNodesForChart.push({ - index: $scope.treeState.arrayOfNodesForChart.length, + $scope.graphState.arrayOfNodesForChart.push({ + index: $scope.graphState.arrayOfNodesForChart.length, id: workflowMakerNodeIdCounter, - isNodeBeingAdded: true, unifiedJobTemplate: null }); - chartNodeIdToIndexMapping[workflowMakerNodeIdCounter] = $scope.treeState.arrayOfNodesForChart.length - 1; + $scope.graphState.nodeBeingAdded = workflowMakerNodeIdCounter; - $scope.treeState.arrayOfLinksForChart.push({ - source: $scope.treeState.arrayOfNodesForChart[parent.index], - target: $scope.treeState.arrayOfNodesForChart[chartNodeIdToIndexMapping[workflowMakerNodeIdCounter]], + chartNodeIdToIndexMapping[workflowMakerNodeIdCounter] = $scope.graphState.arrayOfNodesForChart.length - 1; + + $scope.graphState.arrayOfLinksForChart.push({ + source: $scope.graphState.arrayOfNodesForChart[parent.index], + target: $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[workflowMakerNodeIdCounter]], edgeType: "placeholder" }); @@ -337,7 +331,7 @@ export default ['$scope', 'TemplatesService', workflowMakerNodeIdCounter++; - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); $scope.$broadcast("refreshWorkflowChart"); @@ -349,38 +343,39 @@ export default ['$scope', 'TemplatesService', $scope.cancelNodeForm(); } - $scope.treeState.arrayOfNodesForChart.push({ - index: $scope.treeState.arrayOfNodesForChart.length, + $scope.graphState.arrayOfNodesForChart.push({ + index: $scope.graphState.arrayOfNodesForChart.length, id: workflowMakerNodeIdCounter, - isNodeBeingAdded: true, unifiedJobTemplate: null }); - chartNodeIdToIndexMapping[workflowMakerNodeIdCounter] = $scope.treeState.arrayOfNodesForChart.length - 1; + $scope.graphState.nodeBeingAdded = workflowMakerNodeIdCounter; - $scope.treeState.arrayOfLinksForChart.push({ - source: $scope.treeState.arrayOfNodesForChart[link.source.index], - target: $scope.treeState.arrayOfNodesForChart[chartNodeIdToIndexMapping[workflowMakerNodeIdCounter]], + chartNodeIdToIndexMapping[workflowMakerNodeIdCounter] = $scope.graphState.arrayOfNodesForChart.length - 1; + + $scope.graphState.arrayOfLinksForChart.push({ + source: $scope.graphState.arrayOfNodesForChart[link.source.index], + target: $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[workflowMakerNodeIdCounter]], edgeType: "placeholder" }); $scope.nodeConfig = { mode: "add", nodeId: workflowMakerNodeIdCounter, - newNodeIsRoot: link.source.index === 0 + newNodeIsRoot: link.source.id === 1 }; // Search for the link that used to exist between source and target and shift it to // go from our new node to the target - $scope.treeState.arrayOfLinksForChart.forEach((foo) => { + $scope.graphState.arrayOfLinksForChart.forEach((foo) => { if (foo.source.id === link.source.id && foo.target.id === link.target.id) { - foo.source = $scope.treeState.arrayOfNodesForChart[chartNodeIdToIndexMapping[workflowMakerNodeIdCounter]]; + foo.source = $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[workflowMakerNodeIdCounter]]; } }); workflowMakerNodeIdCounter++; - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); $scope.$broadcast("refreshWorkflowChart"); @@ -391,17 +386,16 @@ export default ['$scope', 'TemplatesService', const nodeIndex = chartNodeIdToIndexMapping[$scope.nodeConfig.nodeId]; if ($scope.nodeConfig.mode === "add") { if (selectedTemplate && edgeType && edgeType.value) { - // TODO: do we need to clone prompt data? nodeRef[$scope.nodeConfig.nodeId] = { fullUnifiedJobTemplateObject: selectedTemplate, - promptData: _.cloneDeep(promptData), + promptData, isNew: true }; - $scope.treeState.arrayOfNodesForChart[nodeIndex].unifiedJobTemplate = selectedTemplate; - $scope.treeState.arrayOfNodesForChart[nodeIndex].isNodeBeingAdded = false; + $scope.graphState.arrayOfNodesForChart[nodeIndex].unifiedJobTemplate = selectedTemplate; + $scope.graphState.nodeBeingAdded = null; - $scope.treeState.arrayOfLinksForChart.map( (link) => { + $scope.graphState.arrayOfLinksForChart.map( (link) => { if (link.target.index === nodeIndex) { link.edgeType = edgeType.value; } @@ -412,8 +406,8 @@ export default ['$scope', 'TemplatesService', nodeRef[$scope.nodeConfig.nodeId].fullUnifiedJobTemplateObject = selectedTemplate; nodeRef[$scope.nodeConfig.nodeId].promptData = _.cloneDeep(promptData); nodeRef[$scope.nodeConfig.nodeId].isEdited = true; - $scope.treeState.arrayOfNodesForChart[nodeIndex].unifiedJobTemplate = selectedTemplate; - $scope.treeState.arrayOfNodesForChart[nodeIndex].isNodeBeingEdited = false; + $scope.graphState.arrayOfNodesForChart[nodeIndex].unifiedJobTemplate = selectedTemplate; + $scope.graphState.nodeBeingEdited = null; } } @@ -427,15 +421,15 @@ export default ['$scope', 'TemplatesService', const nodeIndex = chartNodeIdToIndexMapping[$scope.nodeConfig.nodeId]; if ($scope.nodeConfig.mode === "add") { // Remove the placeholder node from the array - $scope.treeState.arrayOfNodesForChart.splice(nodeIndex, 1); + $scope.graphState.arrayOfNodesForChart.splice(nodeIndex, 1); // Update the links let parents = []; let children = []; // Remove any links that reference this node - for( let i = $scope.treeState.arrayOfLinksForChart.length; i--; ){ - const link = $scope.treeState.arrayOfLinksForChart[i]; + for( let i = $scope.graphState.arrayOfLinksForChart.length; i--; ){ + const link = $scope.graphState.arrayOfLinksForChart[i]; if (link.source.index === nodeIndex || link.target.index === nodeIndex) { if (link.source.index === nodeIndex) { @@ -445,7 +439,7 @@ export default ['$scope', 'TemplatesService', const sourceIndex = link.source.index < nodeIndex ? link.source.index : link.source.index - 1; parents.push(sourceIndex); } - $scope.treeState.arrayOfLinksForChart.splice(i, 1); + $scope.graphState.arrayOfLinksForChart.splice(i, 1); } else { if (link.source.index > nodeIndex) { link.source.index--; @@ -462,9 +456,9 @@ export default ['$scope', 'TemplatesService', if (parentIndex === 0) { child.edgeType = "always"; } - $scope.treeState.arrayOfLinksForChart.push({ - source: $scope.treeState.arrayOfNodesForChart[parentIndex], - target: $scope.treeState.arrayOfNodesForChart[child.index], + $scope.graphState.arrayOfLinksForChart.push({ + source: $scope.graphState.arrayOfNodesForChart[parentIndex], + target: $scope.graphState.arrayOfNodesForChart[child.index], edgeType: child.edgeType }); }); @@ -478,13 +472,9 @@ export default ['$scope', 'TemplatesService', } } - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); } else if ($scope.nodeConfig.mode === "edit") { - $scope.treeState.arrayOfNodesForChart.map( (node) => { - if (node.index === $scope.nodeConfig.nodeId) { - node.isNodeBeingEdited = false; - } - }); + $scope.graphState.nodeBeingEdited = null; } $scope.formState.showNodeForm = false; $scope.nodeConfig = null; @@ -509,11 +499,7 @@ export default ['$scope', 'TemplatesService', node: nodeRef[nodeToEdit.id] }; - $scope.treeState.arrayOfNodesForChart.map( (node) => { - if (node.index === nodeToEdit.index) { - node.isNodeBeingEdited = true; - } - }); + $scope.graphState.nodeBeingEdited = nodeToEdit.id; $scope.formState.showNodeForm = true; } @@ -526,18 +512,19 @@ export default ['$scope', 'TemplatesService', $scope.startEditLink = (linkToEdit) => { const setupLinkEdit = () => { - linkToEdit.isLinkBeingEdited = true; - // Determine whether or not this link can be removed - // TODO: we already (potentially) loop across this array below - // and we should combine let numberOfParents = 0; - $scope.treeState.arrayOfLinksForChart.forEach((link) => { + $scope.graphState.arrayOfLinksForChart.forEach((link) => { if (link.target.id === linkToEdit.target.id) { numberOfParents++; } }); + $scope.graphState.linkBeingEdited = { + source: linkToEdit.source.id, + target: linkToEdit.target.id + }; + $scope.linkConfig = { mode: "edit", parent: { @@ -564,12 +551,9 @@ export default ['$scope', 'TemplatesService', if ($scope.linkConfig.parent.id !== linkToEdit.source.id || $scope.linkConfig.child.id !== linkToEdit.target.id) { // User is going from editing one link to editing another if ($scope.linkConfig.mode === "add") { - $scope.treeState.arrayOfLinksForChart.splice($scope.treeState.arrayOfLinksForChart.length-1, 1); - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.arrayOfLinksForChart.splice($scope.graphState.arrayOfLinksForChart.length-1, 1); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); } - $scope.treeState.arrayOfLinksForChart.forEach((link) => { - link.isLinkBeingEdited = false; - }); setupLinkEdit(); } } else { @@ -587,29 +571,33 @@ export default ['$scope', 'TemplatesService', }; $scope.linkConfig.edgeType = "success"; - $scope.treeState.arrayOfNodesForChart.forEach((node) => { + $scope.graphState.arrayOfNodesForChart.forEach((node) => { node.isInvalidLinkTarget = false; }); - $scope.treeState.arrayOfLinksForChart.push({ - target: $scope.treeState.arrayOfNodesForChart[node.index], - source: $scope.treeState.arrayOfNodesForChart[chartNodeIdToIndexMapping[$scope.linkConfig.parent.id]], - edgeType: "placeholder", - isLinkBeingEdited: true + $scope.graphState.arrayOfLinksForChart.push({ + target: $scope.graphState.arrayOfNodesForChart[node.index], + source: $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[$scope.linkConfig.parent.id]], + edgeType: "placeholder" }); - $scope.treeState.arrayOfLinksForChart.forEach((link, index) => { + $scope.graphState.linkBeingEdited = { + source: $scope.graphState.arrayOfNodesForChart[node.index].id, + target: $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[$scope.linkConfig.parent.id]].id + }; + + $scope.graphState.arrayOfLinksForChart.forEach((link, index) => { if (link.source.id === 1 && link.target.id === node.id) { - $scope.treeState.arrayOfLinksForChart.splice(index, 1); + $scope.graphState.arrayOfLinksForChart.splice(index, 1); } }); - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); - $scope.treeState.isLinkMode = false; + $scope.graphState.isLinkMode = false; } else { // This is the first node selected - $scope.treeState.addLinkSource = node.id; + $scope.graphState.addLinkSource = node.id; $scope.linkConfig = { mode: "add", parent: { @@ -622,7 +610,7 @@ export default ['$scope', 'TemplatesService', let invalidLinkTargetIds = []; // Find and mark any ancestors as disabled to prevent cycles - $scope.treeState.arrayOfLinksForChart.forEach((link) => { + $scope.graphState.arrayOfLinksForChart.forEach((link) => { // id=1 is our artificial root node so we don't care about that if (link.source.id !== 1) { if (link.source.id === node.id) { @@ -649,10 +637,10 @@ export default ['$scope', 'TemplatesService', // Filter out the duplicates invalidLinkTargetIds.filter((element, index, array) => index === array.indexOf(element)).forEach((ancestorId) => { - $scope.treeState.arrayOfNodesForChart[chartNodeIdToIndexMapping[ancestorId]].isInvalidLinkTarget = true; + $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[ancestorId]].isInvalidLinkTarget = true; }); - $scope.treeState.isLinkMode = true; + $scope.graphState.isLinkMode = true; $scope.formState.showLinkForm = true; } @@ -661,22 +649,20 @@ export default ['$scope', 'TemplatesService', }; $scope.confirmLinkForm = (newEdgeType) => { - $scope.treeState.arrayOfLinksForChart.forEach((link) => { + $scope.graphState.arrayOfLinksForChart.forEach((link) => { if (link.source.id === $scope.linkConfig.parent.id && link.target.id === $scope.linkConfig.child.id) { - link.source.isLinkEditParent = false; - link.target.isLinkEditChild = false; link.edgeType = newEdgeType; - link.isLinkBeingEdited = false; } }); if ($scope.linkConfig.mode === "add") { - $scope.treeState.arrayOfNodesForChart.forEach((node) => { + $scope.graphState.arrayOfNodesForChart.forEach((node) => { node.isInvalidLinkTarget = false; }); } - $scope.treeState.addLinkSource = null; + $scope.graphState.linkBeingEdited = null; + $scope.graphState.addLinkSource = null; $scope.formState.showLinkForm = false; $scope.linkConfig = null; $scope.$broadcast("refreshWorkflowChart"); @@ -684,15 +670,15 @@ export default ['$scope', 'TemplatesService', $scope.unlink = () => { // Remove the link - for( let i = $scope.treeState.arrayOfLinksForChart.length; i--; ){ - const link = $scope.treeState.arrayOfLinksForChart[i]; + for( let i = $scope.graphState.arrayOfLinksForChart.length; i--; ){ + const link = $scope.graphState.arrayOfLinksForChart[i]; if (link.source.id === $scope.linkConfig.parent.id && link.target.id === $scope.linkConfig.child.id) { - $scope.treeState.arrayOfLinksForChart.splice(i, 1); + $scope.graphState.arrayOfLinksForChart.splice(i, 1); } } - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); $scope.formState.showLinkForm = false; $scope.linkConfig = null; @@ -701,32 +687,30 @@ export default ['$scope', 'TemplatesService', $scope.cancelLinkForm = () => { if ($scope.linkConfig.mode === "add" && $scope.linkConfig.child) { - $scope.treeState.arrayOfLinksForChart.splice($scope.treeState.arrayOfLinksForChart.length-1, 1); + $scope.graphState.arrayOfLinksForChart.splice($scope.graphState.arrayOfLinksForChart.length-1, 1); let targetIsOrphaned = true; - $scope.treeState.arrayOfLinksForChart.forEach((link) => { + $scope.graphState.arrayOfLinksForChart.forEach((link) => { if (link.target.id === $scope.linkConfig.child.id) { targetIsOrphaned = false; } }); if (targetIsOrphaned) { // Link it to the start node - $scope.treeState.arrayOfLinksForChart.push({ - source: $scope.treeState.arrayOfNodesForChart[0], - target: $scope.treeState.arrayOfNodesForChart[chartNodeIdToIndexMapping[$scope.linkConfig.child.id]], + $scope.graphState.arrayOfLinksForChart.push({ + source: $scope.graphState.arrayOfNodesForChart[0], + target: $scope.graphState.arrayOfNodesForChart[chartNodeIdToIndexMapping[$scope.linkConfig.child.id]], edgeType: "always" }); } - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); } - $scope.treeState.addLinkSource = null; - $scope.treeState.isLinkMode = false; - $scope.formState.showLinkForm = false; - $scope.treeState.arrayOfNodesForChart.forEach((node) => { + $scope.graphState.linkBeingEdited = null; + $scope.graphState.addLinkSource = null; + $scope.graphState.isLinkMode = false; + $scope.graphState.arrayOfNodesForChart.forEach((node) => { node.isInvalidLinkTarget = false; }); - $scope.treeState.arrayOfLinksForChart.forEach((link) => { - link.isLinkBeingEdited = false; - }); + $scope.formState.showLinkForm = false; $scope.linkConfig = null; $scope.$broadcast("refreshWorkflowChart"); }; @@ -752,15 +736,15 @@ export default ['$scope', 'TemplatesService', } // Remove the node from the array - $scope.treeState.arrayOfNodesForChart.splice(nodeIndex, 1); + $scope.graphState.arrayOfNodesForChart.splice(nodeIndex, 1); // Update the links let parents = []; let children = []; // Remove any links that reference this node - for( let i = $scope.treeState.arrayOfLinksForChart.length; i--; ){ - const link = $scope.treeState.arrayOfLinksForChart[i]; + for( let i = $scope.graphState.arrayOfLinksForChart.length; i--; ){ + const link = $scope.graphState.arrayOfLinksForChart[i]; if (link.source.index === nodeIndex || link.target.index === nodeIndex) { if (link.source.index === nodeIndex) { @@ -770,14 +754,14 @@ export default ['$scope', 'TemplatesService', const sourceIndex = link.source.index < nodeIndex ? link.source.index : link.source.index - 1; parents.push(sourceIndex); } - $scope.treeState.arrayOfLinksForChart.splice(i, 1); + $scope.graphState.arrayOfLinksForChart.splice(i, 1); } else { - if (link.source.index > nodeIndex) { - link.source = link.source.index - 1; - } - if (link.target.index > nodeIndex) { - link.target = link.target.index - 1; - } + // if (link.source.index > nodeIndex) { + // link.source.index = link.source.index - 1; + // } + // if (link.target.index > nodeIndex) { + // link.target.index = link.target.index - 1; + // } } } @@ -787,9 +771,9 @@ export default ['$scope', 'TemplatesService', if (parentIndex === 0) { child.edgeType = "always"; } - $scope.treeState.arrayOfLinksForChart.push({ - source: $scope.treeState.arrayOfNodesForChart[parentIndex], - target: $scope.treeState.arrayOfNodesForChart[child.index], + $scope.graphState.arrayOfLinksForChart.push({ + source: $scope.graphState.arrayOfNodesForChart[parentIndex], + target: $scope.graphState.arrayOfNodesForChart[child.index], edgeType: child.edgeType }); }); @@ -807,7 +791,9 @@ export default ['$scope', 'TemplatesService', } } - $scope.treeState.depthMap = WorkflowChartService.generateDepthMap($scope.treeState.arrayOfLinksForChart); + $scope.deleteOverlayVisible = false; + + $scope.graphState.depthMap = WorkflowChartService.generateDepthMap($scope.graphState.arrayOfLinksForChart); $scope.nodeToBeDeleted = null; $scope.deleteOverlayVisible = false; @@ -869,7 +855,7 @@ export default ['$scope', 'TemplatesService', let depthMap = WorkflowChartService.generateDepthMap(arrayOfLinksForChart); - $scope.treeState = { arrayOfNodesForChart, arrayOfLinksForChart, depthMap }; + $scope.graphState = { arrayOfNodesForChart, arrayOfLinksForChart, depthMap }; } }, function ({ data, status, config }) { ProcessErrors($scope, data, status, null, { diff --git a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html index 107b97baab..52c09a3f28 100644 --- a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html +++ b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html @@ -74,7 +74,7 @@
{{strings.get('workflow_maker.TOTAL_TEMPLATES')}} - +
@@ -83,7 +83,7 @@