azkaban-aplcache

Adding more graph enable/disabled.

8/29/2012 3:56:52 AM

Details

diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index 90aed86..9f0ceca 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -107,11 +107,23 @@
 					</div>
 				</div>
 #end
-		<ul id="jobMenu" class="contextMenu">  
+		<ul id="jobMenu" class="contextMenu flowSubmenu">  
 			<li class="open"><a href="#open">Open...</a></li>
 			<li class="openwindow"><a href="#openwindow">Open in New Window...</a></li>
-			<li class="enable separator"><a href="#enable">Enable</a></li>
-			<li class="disable"><a href="#disable">Disable</a></li>
+			<li id="disable" class="disable separator"><a href="#disable">Disable</a><div id="disableArrow" class="context-sub-icon"></div></li>
+			<ul id="disableSub" class="subMenu">
+				<li class="parents"><a href="#disableParents">Parents</a></li>
+				<li class="ancestors"><a href="#disableAncestors">All Ancestors</a></li>
+				<li class="children"><a href="#disableChildren">Children</a></li>
+				<li class="decendents"><a href="#disableDescendents">All Descendents</a></li>
+			</ul>
+			<li id="enable" class="enable"><a href="#enable">Enable</a> <div id="enableArrow" class="context-sub-icon"></div></li>
+			<ul id="enableSub" class="subMenu">
+				<li class="parents"><a href="#enableParents">Parents</a></li>
+				<li class="ancestors"><a href="#enableAncestors">All Ancestors</a></li>
+				<li class="children"><a href="#enableChildren">Children</a></li>
+				<li class="decendents"><a href="#enableDescendents">All Descendents</a></li>
+			</ul>
 		</ul>
 
 		</div>
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index e183624..8d7096e 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -662,7 +662,31 @@ tr:hover td {
   width: 16px;
 }
 
-.collapse .state-icon {
+.flowSubmenu li {
+	clear: both;
+}
+
+.flowSubmenu a {
+	float: left;
+	width: 70%;
+}
+
+.context-sub-icon {
+  float: right;
+  background-image: url("../../js/jqueryui/themes/custom-theme/images/ui-icons_cccccc_256x240.png");
+  cursor: pointer;
+  display: block;
+  height: 16px;
+  margin-right: 5px;
+  width: 16px;
+  background-position: -32px -16px;
+}
+
+.collapse.context-sub-icon {
+  	background-position: 0 -16px;
+}
+
+.collapse.state-icon {
 	background-position: 0 -16px;
 }
 
@@ -1523,6 +1547,14 @@ h3.subhead {
 	font-weight: bold;
 }
 
+ul.subMenu {
+	margin-left: 15px;
+}
+
+ul.disableMenu {
+	margin-left: 15px;
+}
+
 /* old styles */
 
 .azkaban-charts .hitarea {
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index fe4645a..c952eda 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -10,44 +10,132 @@ var handleJobMenuClick = function(action, el, pos) {
 		window.open(requestURL);
 	}
 	else if(action == "disable") {
-		var oldDisabled = graphModel.get("disabled");
-		
-		var newDisabled = {};
-		// Copy disabled list
-		if (oldDisabled) {
-			for(var id in oldDisabled) {
-			    if(oldDisabled.hasOwnProperty(id)) {
-			    	var disabled = (oldDisabled[id]);
-			    	if (disabled) {
-			    		newDisabled[id]=true;
-			    	}
-			    }
+		var disabled = graphModel.get("disabled");
+
+		disabled[jobid] = true;
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "disableParents") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		var inNodes = nodes[jobid].inNodes;
+
+		if (inNodes) {
+			for (var key in inNodes) {
+			  disabled[key] = true;
 			}
 		}
 		
-		newDisabled[jobid] = true;
-		graphModel.set({disabled: newDisabled});
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "disableChildren") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		var outNodes = nodes[jobid].outNodes;
+
+		if (outNodes) {
+			for (var key in outNodes) {
+			  disabled[key] = true;
+			}
+		}
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "disableAncestors") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		
+		recurseAllAncestors(nodes, disabled, jobid, true);
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "disableDescendents") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		
+		recurseAllDescendents(nodes, disabled, jobid, true);
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
 	}
 	else if(action == "enable") {
-		var oldDisabled = graphModel.get("disabled");
-		// Copy disabled list
-		if (oldDisabled) {
-			var newDisabled = {};
-			for(var id in oldDisabled) {
-			    if(oldDisabled.hasOwnProperty(id)) {
-			    	var disabled = (oldDisabled[id]);
-			    	if (disabled) {
-			    		newDisabled[id]=true;
-			    	}
-			    }
+		var disabled = graphModel.get("disabled");
+
+		disabled[jobid] = false;
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "enableParents") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		var inNodes = nodes[jobid].inNodes;
+
+		if (inNodes) {
+			for (var key in inNodes) {
+			  disabled[key] = false;
 			}
-			
-			if( oldDisabled[jobid]) {
-				newDisabled[jobid] = false;
-				graphModel.set({disabled: newDisabled});
+		}
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "enableChildren") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		var outNodes = nodes[jobid].outNodes;
+
+		if (outNodes) {
+			for (var key in outNodes) {
+			  disabled[key] = false;
 			}
 		}
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "enableAncestors") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		
+		recurseAllAncestors(nodes, disabled, jobid, false);
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+	else if (action == "enableDescendents") {
+		var disabled = graphModel.get("disabled");
+		var nodes = graphModel.get("nodes");
+		
+		recurseAllDescendents(nodes, disabled, jobid, false);
+		
+		graphModel.set({disabled: disabled});
+		graphModel.trigger("change:disabled");
+	}
+}
+
+function recurseAllAncestors(nodes, disabledMap, id, disable) {
+	var node = nodes[id];
+	
+	if (node.inNodes) {
+		for (var key in node.inNodes) {
+			disabledMap[key] = disable;
+			recurseAllAncestors(nodes, disabledMap, key, disable);
+		}
+	}
+}
 
+function recurseAllDescendents(nodes, disabledMap, id, disable) {
+	var node = nodes[id];
+	
+	if (node.outNodes) {
+		for (var key in node.outNodes) {
+			disabledMap[key] = disable;
+			recurseAllDescendents(nodes, disabledMap, key, disable);
+		}
 	}
 }
 
@@ -699,6 +787,52 @@ azkaban.ExecutionsView = Backbone.View.extend({
 	}
 });
 
+var contextMenu;
+azkaban.ContextMenu = Backbone.View.extend({
+	events : {
+		"click #disableArrow" : "handleDisabledClick",
+		"click #enableArrow" : "handleEnabledClick"
+	},
+	initialize: function(settings) {
+		$('#disableSub').hide();
+		$('#enableSub').hide();
+	},
+	handleEnabledClick: function(evt) {
+		if(evt.stopPropagation) {
+			evt.stopPropagation();
+		}
+		evt.cancelBubble=true;
+		
+		if (evt.currentTarget.expanded) {
+			evt.currentTarget.expanded=false;
+			$('#enableArrow').removeClass('collapse');
+			$('#enableSub').hide();
+		}
+		else {
+			evt.currentTarget.expanded=true;
+			$('#enableArrow').addClass('collapse');
+			$('#enableSub').show();
+		}
+	},
+	handleDisabledClick: function(evt) {
+		if(evt.stopPropagation) {
+			evt.stopPropagation();
+		}
+		evt.cancelBubble=true;
+		
+		if (evt.currentTarget.expanded) {
+			evt.currentTarget.expanded=false;
+			$('#disableArrow').removeClass('collapse');
+			$('#disableSub').hide();
+		}
+		else {
+			evt.currentTarget.expanded=true;
+			$('#disableArrow').addClass('collapse');
+			$('#disableSub').show();
+		}
+	}
+});
+
 var graphModel;
 azkaban.GraphModel = Backbone.Model.extend({});
 
@@ -716,6 +850,7 @@ $(function() {
 	graphModel = new azkaban.GraphModel();
 	svgGraphView = new azkaban.SvgGraphView({el:$('#svgDiv'), model: graphModel});
 	jobsListView = new azkaban.JobListView({el:$('#jobList'), model: graphModel});
+	contextMenu = new azkaban.ContextMenu({el:$('#jobMenu')});
 	
 	var requestURL = contextURL + "/manager";
 
@@ -723,8 +858,32 @@ $(function() {
 	      requestURL,
 	      {"project": projectName, "ajax":"fetchflowgraph", "flow":flowName},
 	      function(data) {
+	      	  // Create the nodes
+	      	  var nodes = {};
+	      	  for (var i=0; i < data.nodes.length; ++i) {
+	      	  	var node = data.nodes[i];
+	      	  	nodes[node.id] = node;
+	      	  }
+	      	  for (var i=0; i < data.edges.length; ++i) {
+	      	  	var edge = data.edges[i];
+	      	  	var fromNode = nodes[edge.from];
+	      	  	var toNode = nodes[edge.target];
+	      	  	
+	      	  	if (!fromNode.outNodes) {
+	      	  		fromNode.outNodes = {};
+	      	  	}
+	      	  	fromNode.outNodes[toNode.id] = toNode;
+	      	  	
+	      	  	if (!toNode.inNodes) {
+	      	  		toNode.inNodes = {};
+	      	  	}
+	      	  	toNode.inNodes[fromNode.id] = fromNode;
+	      	  }
+	      
 	          console.log("data fetched");
 	          graphModel.set({data: data});
+	          graphModel.set({nodes: nodes});
+	          graphModel.set({disabled: {}});
 	          graphModel.trigger("change:graph");
 	          
 	          // Handle the hash changes here so the graph finishes rendering first.
@@ -772,5 +931,4 @@ $(function() {
 		);
 		
 	});
-
 });