azkaban-aplcache

Adding restart feature.

10/1/2012 5:58:28 PM

Details

diff --git a/src/java/azkaban/executor/ExecutableFlow.java b/src/java/azkaban/executor/ExecutableFlow.java
index 102213b..e2191ec 100644
--- a/src/java/azkaban/executor/ExecutableFlow.java
+++ b/src/java/azkaban/executor/ExecutableFlow.java
@@ -25,8 +25,8 @@ public class ExecutableFlow {
 	private ArrayList<String> startNodes;
 	private ArrayList<String> endNodes;
 	
-	private ArrayList<String> failureEmails;
-	private ArrayList<String> successEmails;
+	private ArrayList<String> failureEmails = new ArrayList<String>();
+	private ArrayList<String> successEmails = new ArrayList<String>();
 	
 	private long submitTime = -1;
 	private long startTime = -1;
@@ -220,10 +220,18 @@ public class ExecutableFlow {
 		this.failureEmails = emails == null ? new ArrayList<String>() : new ArrayList<String>(emails);
 	}
 	
+	public List<String> getFailureEmails() {
+		return this.failureEmails;
+	}
+	
 	public void setSuccessEmails(List<String> emails) {
 		this.successEmails = emails == null ? new ArrayList<String>() : new ArrayList<String>(emails);
 	}
 	
+	public List<String> getSuccessEmails() {
+		return this.successEmails;
+	}
+	
 	public Map<String,Object> toObject() {
 		HashMap<String, Object> flowObj = new HashMap<String, Object>();
 		flowObj.put("type", "executableflow");
@@ -271,6 +279,10 @@ public class ExecutableFlow {
 		failureAction = action;
 	}
 	
+	public FailureAction getFailureAction() {
+		return failureAction;
+	}
+	
 	@SuppressWarnings("unchecked")
 	public static ExecutableFlow createExecutableFlowFromObject(Object obj) {
 		ExecutableFlow exFlow = new ExecutableFlow();
@@ -396,6 +408,14 @@ public class ExecutableFlow {
 		this.notifyOnLastFailure = notify;
 	}
 	
+	public boolean getNotifyOnFirstFailure() {
+		return this.notifyOnFirstFailure;
+	}
+	
+	public boolean getNotifyOnLastFailure() {
+		return this.notifyOnLastFailure;
+	}
+	
 	public static class ExecutableNode {
 		private String id;
 
diff --git a/src/java/azkaban/utils/DirectoryFlowLoader.java b/src/java/azkaban/utils/DirectoryFlowLoader.java
index 7c80368..1f675f4 100644
--- a/src/java/azkaban/utils/DirectoryFlowLoader.java
+++ b/src/java/azkaban/utils/DirectoryFlowLoader.java
@@ -209,9 +209,27 @@ public class DirectoryFlowLoader {
 				
 				// Dedup with sets
 				@SuppressWarnings("unchecked")
-				Set<String> successEmail = new HashSet<String>(jobProp.getStringList("success.emails", Collections.EMPTY_LIST));
+				List<String> successEmailList = jobProp.getStringList("success.emails", Collections.EMPTY_LIST);
+				Set<String> successEmail = new HashSet<String>();
+				for (String email: successEmailList) {
+					successEmail.add(email.toLowerCase());
+				}
+	
 				@SuppressWarnings("unchecked")
-				Set<String> failureEmail = new HashSet<String>(jobProp.getStringList("failure.emails", Collections.EMPTY_LIST));
+				List<String> failureEmailList = jobProp.getStringList("failure.emails", Collections.EMPTY_LIST);
+				Set<String> failureEmail = new HashSet<String>();
+				for (String email: failureEmailList) {
+					failureEmail.add(email.toLowerCase());
+				}
+				
+				@SuppressWarnings("unchecked")
+				List<String> notifyEmailList = jobProp.getStringList("notify.emails", Collections.EMPTY_LIST);
+				for (String email: notifyEmailList) {
+					email = email.toLowerCase();
+					successEmail.add(email);
+					failureEmail.add(email);
+				}
+				
 				flow.addFailureEmails(failureEmail);
 				flow.addSuccessEmails(successEmail);
 				
diff --git a/src/java/azkaban/webapp/servlet/ExecutorServlet.java b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
index 68de060..86ec0ba 100644
--- a/src/java/azkaban/webapp/servlet/ExecutorServlet.java
+++ b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
@@ -226,6 +226,11 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
 					ajaxFetchJobLogs(req, resp, ret, session.getUser(), exFlow);
 					ret = null;
 				}
+				else if (ajaxName.equals("flowInfo")) {
+					String projectName = getParam(req, "project");
+					String flowName = getParam(req, "flow");
+					ajaxFetchExecutableFlowInfo(req, resp, ret, session.getUser(), projectName, flowName, exFlow);
+				}
 			}
 		}
 		else if (ajaxName.equals("isRunning")) {
@@ -236,6 +241,7 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
 		else if (ajaxName.equals("flowInfo")) {
 			String projectName = getParam(req, "project");
 			String flowName = getParam(req, "flow");
+			
 			ajaxFetchFlowInfo(req, resp, ret, session.getUser(), projectName, flowName);
 		}
 		else {
@@ -354,6 +360,53 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
 			ret.put("scheduled", sflow.getNextExecTime().getMillis());
 		}
 	}
+
+	private void ajaxFetchExecutableFlowInfo(HttpServletRequest req, HttpServletResponse resp, HashMap<String, Object> ret, User user, String projectId, String flowId, ExecutableFlow exflow) throws ServletException {
+		Project project = getProjectAjaxByPermission(ret, projectId, user, Type.READ);
+		if (project == null) {
+			return;
+		}
+		
+		Flow flow = project.getFlow(flowId);
+		if (flow == null) {
+			ret.put("error", "Error loading flow. Flow " + flowId + " doesn't exist in " + projectId);
+			return;
+		}
+		
+		ret.put("successEmails", exflow.getSuccessEmails());
+		ret.put("failureEmails", flow.getFailureEmails());
+		ret.put("flowParam", exflow.getFlowParameters());
+		
+		FailureAction action = exflow.getFailureAction();
+		String failureAction = null;
+		switch (action) {
+			case FINISH_CURRENTLY_RUNNING:
+				failureAction = "finishCurrent";
+				break;
+			case CANCEL_ALL:
+				failureAction = "cancelImmediately";
+				break;
+			case FINISH_ALL_POSSIBLE:
+				failureAction = "finishPossible";
+				break;
+		}
+		ret.put("failureAction", failureAction);
+		ret.put("notifyFailureFirst", exflow.getNotifyOnFirstFailure());
+		ret.put("notifyFailureLast", exflow.getNotifyOnLastFailure());
+		ret.put("running", executorManager.getFlowRunningFlows(projectId, flowId));
+		
+		ScheduledFlow sflow = null;
+		for (ScheduledFlow schedFlow: scheduleManager.getSchedule()) {
+			if (schedFlow.getProjectId().equals(projectId) && schedFlow.getFlowId().equals(flowId)) {
+				sflow = schedFlow;
+				break;
+			}
+		}
+		
+		if (sflow != null) {
+			ret.put("scheduled", sflow.getNextExecTime().getMillis());
+		}
+	}
 	
 	private void ajaxCancelFlow(HttpServletRequest req, HttpServletResponse resp, HashMap<String, Object> ret, User user, ExecutableFlow exFlow) throws ServletException{
 		Project project = getProjectAjaxByPermission(ret, exFlow.getProjectId(), user, Type.EXECUTE);
@@ -533,10 +586,9 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
 			String option = getParam(req, "jobOption");
 			// Not set yet
 		}
-		if (hasParam(req, "flowOverride")) {
-			Map<String, String> paramGroup = this.getParamGroup(req, "flowOverride");
-			exflow.addFlowParameters(paramGroup);
-		}
+		
+		Map<String, String> flowParamGroup = this.getParamGroup(req, "flowOverride");
+		exflow.addFlowParameters(flowParamGroup);
 		
 		// Setup disabled
 		Map<String, String> paramGroup = this.getParamGroup(req, "disable");
diff --git a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
index ebc33f5..f29d398 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
@@ -17,6 +17,7 @@
 		<script type="text/javascript" src="${context}/js/azkaban.flow.job.view.js"></script>
 		<script type="text/javascript" src="${context}/js/azkaban.flow.graph.view.js"></script>
 		<script type="text/javascript" src="${context}/js/azkaban.exflow.view.js"></script>
+		<script type="text/javascript" src="${context}/js/azkaban.exflow.options.view.js"></script>
 		<script type="text/javascript" src="${context}/js/svgNavigate.js"></script>
 		<script type="text/javascript">
 			var contextURL = "${context}";
@@ -67,7 +68,7 @@
 							<li><div id="pausebtn" class="btn2">Pause</div></li>
 							<li><div id="resumebtn" class="btn2">Resume</div></li>
 							<li><div id="cancelbtn" class="btn6">Cancel</div></li>
-							<li><div id="restartbtn" class="btn1">Retry...</div></li>
+							<li><div id="executebtn" class="btn1">Execute</div></li>
 						</ul>
 					</div>
 					<div id="graphView">
@@ -80,8 +81,8 @@
 								</div>
 								<div id="resetPanZoomBtn" class="btn5 resetPanZoomBtn" >Reset Pan Zoom</div>
 							</div>
-							<div id="svgDiv" >
-								<svg id="svgGraph" xmlns="http://www.w3.org/2000/svg" version="1.1" shape-rendering="optimize-speed" text-rendering="optimize-speed" >
+							<div id="svgDiv" class="svgDiv">
+								<svg id="svgGraph" class="svgGraph" xmlns="http://www.w3.org/2000/svg" version="1.1" shape-rendering="optimize-speed" text-rendering="optimize-speed" >
 								</svg>
 							</div>
 						</div>
@@ -110,23 +111,126 @@
 						</div>
 					</div>
 				</div>
+				
+				<div id="flow-status">
+					<table class="status">
+						<tr><td class="first">Status</td><td id="flowStatus">-</td></tr>
+						<tr><td class="first">Submit User</td><td id="submitUser">-</td></tr>
+					</table>
+					<table class="time">
+						<tr><td class="first">Start Time</td><td id="startTime">-</td></tr>
+						<tr><td class="first">End Time</td><td id="endTime">-</td></tr>
+						<tr><td class="first">Duration</td><td id="duration">-</td></tr>
+					</table>
+				</div>
+						
+	            <div id="modalBackground" class="modalBackground2">
+	                <div id="executing-options" class="modal modalContainer2">
+	                	<a href='#' title='Close' class='modal-close'>x</a>
+	                		<h3>Executing Flow Options</h3>
+	                		<div>
+	                			<ul class="optionsPicker">
+	                				<li id="generalOptions">General Options</li>
+	                				<li id="flowOptions">Flow Options</li>
+	                			</ul>
+	                		</div>
+	                		<div class="optionsPane">
+	                			<div id="generalPanel" class="generalPanel panel">
+	                				<div id="completeActions">
+	                					<h4>Completion Actions</h4>
+		                				<dl>
+		                					<dt class="disabled">Failure Action</dt>
+		                					<dd>
+		                						<select id="failureAction" name="failureAction" disabled="disabled">
+		                							<option value="finishCurrent">Finish Current Running</option>
+		                							<option value="cancelImmediately">Cancel All</option>
+		                							<option value="finishPossible">Finish All Possible</option>
+		                						</select>
+											</dd>
+		                					<dt>Failure Email</dt>
+		                					<dd>
+		                						<textarea id="failureEmails"></textarea>
+		                					</dd>
+		                					<dt class="disabled">Notify on Failure</dt>
+		                					<dd>
+		                						<input id="notifyFailureFirst" class="checkbox" type="checkbox" name="notify" value="first" disabled="disabled" checked >First Failure</input>
+		                						<input id="notifyFailureLast" class="checkbox" type="checkbox" name="notify" disabled="disabled" value="last">Flow Stop</input>
+		                					</dd>
+		                					<dt>Success Email</dt>
+		                					<dd>
+		                						<textarea id="successEmails"></textarea>
+		                					</dd>
+		                					<dt>Concurrent Execution</dt>
+		                					<dd id="executingJob" class="disabled">
+		                						<input id="ignore" class="radio" type="radio" name="concurrent" value="ignore" checked /><label class="radioLabel" for="ignore">Run Concurrently</label>
+		                						<input id="pipeline" class="radio" type="radio" name="concurrent" value="pipeline" /><label class="radioLabel" for="pipeline">Pipeline</label>
+		                						<input id="queue" class="radio" type="radio" name="concurrent" value="queue" /><label class="radioLabel" for="queue">Queue Job</label>
+		                					</dd>
+		                				</dl>
+	                				</div>
+	                				<div id="flowPropertyOverride">
+	                					<h4>Flow Property Override</h4>
+	                					<div class="tableDiv">
+		                					<table>
+		                						<thead>
+		                							<tr>
+			                							<th>Name</th>
+			                							<th>Value</th>
+			                						</tr>
+		                						</thead>
+		                						<tbody>
+		                							<tr id="addRow"><td id="addRow-col" colspan="2"><span class="addIcon"></span><a href="#">Add Row</a></td></tr>
+		                						</tbody>
+		                					</table>
+	                					</div>
+	                				</div>
+	                			</div>
+								<div id="graphPanel" class="graphPanel panel">
+									<div id="jobListCustom" class="jobList">
+										<div class="filterList">
+											<input class="filter" placeholder="  Job Filter" />
+										</div>
+										<div class="list">
+										</div>
+										<div class="btn5 resetPanZoomBtn" >Reset Pan Zoom</div>
+									</div>
+								    <div id="svgDivCustom" class="svgDiv" >
+								    	<svg class="svgGraph" xmlns="http://www.w3.org/2000/svg" version="1.1" shape-rendering="optimize-speed" text-rendering="optimize-speed" >
+										</svg>
+									</div>
+		                        </div>
+	                        </div>
+                    		<div class="actions">
+	                                <a class="yes btn1" id="execute-btn" href="#">Execute Now</a>
+	                                <a class="no simplemodal-close btn3" id="cancel-btn" href="#">Cancel</a>
+	                        </div>
+	                </div>
+                </div>
 #end
 		<ul id="jobMenu" class="contextMenu">  
 			<li class="open"><a href="#open">Open...</a></li>
 			<li class="openwindow"><a href="#openwindow">Open in New Window...</a></li>
 		</ul>
 
-		</div>
-		<div id="flow-status">
-			<table class="status">
-				<tr><td class="first">Status</td><td id="flowStatus">-</td></tr>
-				<tr><td class="first">Submit User</td><td id="submitUser">-</td></tr>
-			</table>
-			<table class="time">
-				<tr><td class="first">Start Time</td><td id="startTime">-</td></tr>
-				<tr><td class="first">End Time</td><td id="endTime">-</td></tr>
-				<tr><td class="first">Duration</td><td id="duration">-</td></tr>
-			</table>
+		<ul id="disableJobMenu" class="contextMenu flowSubmenu">  
+			<li class="openwindow"><a href="#openwindow">Open in New Window...</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="disableAll"><a href="#disableAll">All</a></li>
+				<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="enableAll"><a href="#enableAll">All</a></li>
+				<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>
 		
 		<div id="messageDialog" class="modal">
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index ac2879d..914ad59 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -28,6 +28,7 @@
 			
 			var projectName = "${project.name}";
 			var flowName = "${flowid}";
+			var execId = null;
 		</script>
 		<script>
 			$(function() {
@@ -204,9 +205,9 @@
 	                				<div id="completeActions">
 	                					<h4>Completion Actions</h4>
 		                				<dl>
-		                					<dt>Failure Action</dt>
+		                					<dt class="disabled">Failure Action</dt>
 		                					<dd>
-		                						<select id="failureAction" name="failureAction">
+		                						<select id="failureAction" name="failureAction" disabled="disabled">
 		                							<option value="finishCurrent">Finish Current Running</option>
 		                							<option value="cancelImmediately">Cancel All</option>
 		                							<option value="finishPossible">Finish All Possible</option>
@@ -216,17 +217,17 @@
 		                					<dd>
 		                						<textarea id="failureEmails"></textarea>
 		                					</dd>
-		                					<dt>Notify on Failure</dt>
+		                					<dt class="disabled">Notify on Failure</dt>
 		                					<dd>
-		                						<input id="notifyFailureFirst" class="checkbox" type="checkbox" name="notify" value="first" checked >First Failure</input>
-		                						<input id="notifyFailureLast" class="checkbox" type="checkbox" name="notify" value="last">Flow Stop</input>
+		                						<input id="notifyFailureFirst" class="checkbox" type="checkbox" name="notify" value="first" disabled="disabled" checked >First Failure</input>
+		                						<input id="notifyFailureLast" class="checkbox" type="checkbox" name="notify" disabled="disabled" value="last">Flow Stop</input>
 		                					</dd>
 		                					<dt>Success Email</dt>
 		                					<dd>
 		                						<textarea id="successEmails"></textarea>
 		                					</dd>
-		                					<dt>Concurrent Execution</dt>
-		                					<dd id="executingJob">
+		                					<dt class="disabled" >Concurrent Execution</dt>
+		                					<dd id="executingJob" class="disabled">
 		                						<input id="ignore" class="radio" type="radio" name="concurrent" value="ignore" checked /><label class="radioLabel" for="ignore">Run Concurrently</label>
 		                						<input id="pipeline" class="radio" type="radio" name="concurrent" value="pipeline" /><label class="radioLabel" for="pipeline">Pipeline</label>
 		                						<input id="queue" class="radio" type="radio" name="concurrent" value="queue" /><label class="radioLabel" for="queue">Queue Job</label>
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index 20d62f8..19a399e 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -21,6 +21,13 @@ textarea {
 	border: 2px inset;
 }
 
+dt.disabled {
+	color: #CCC;
+}
+label.disabled {
+	color: #CCC;
+}
+
 .header {
   background-image: -o-linear-gradient(bottom, rgb(56,56,56) 33%, rgb(73,73,73) 66%);
   background-image: -moz-linear-gradient(bottom, rgb(56,56,56) 33%, rgb(73,73,73) 66%);
@@ -1209,6 +1216,17 @@ tr:hover td {
 	background: #E0E0E0;
 }
 
+#jobListView {
+	position: absolute;
+	top: 210px;
+	bottom: 5px;
+	left: 50px;
+	right: 50px;
+	padding: 0px;
+	background: #E0E0E0;
+	overflow-y: auto;
+}
+
 .logView {
 	position: absolute;
 	top: 210px;
diff --git a/src/web/js/azkaban.exflow.options.view.js b/src/web/js/azkaban.exflow.options.view.js
index 6120c2c..f18211f 100644
--- a/src/web/js/azkaban.exflow.options.view.js
+++ b/src/web/js/azkaban.exflow.options.view.js
@@ -3,6 +3,28 @@ var customSvgGraphView;
 var customJobListView;
 var cloneModel;
 
+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);
+		}
+	}
+}
+
 azkaban.ContextMenu = Backbone.View.extend({
 	events : {
 		"click #disableArrow" : "handleDisabledClick",
@@ -68,20 +90,70 @@ azkaban.ExecuteFlowView = Backbone.View.extend({
 	  	this.handleGeneralOptionsSelect();
 	  	$('#modalBackground').show();
 	  	$('#executing-options').show();
+	  	this.cloneModel = this.model.clone();
 	  	
+	  	var fetchData = {"project": projectName, "ajax":"flowInfo", "flow":flowName};
+	  	if (execId) {
+	  		fetchData.execid = execId;
+	  	}
 	  	var executeURL = contextURL + "/executor";
+	  	var handleAddRow = this.handleAddRow;
+	  	
+	  	var data = this.cloneModel.get("data");
+	  	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;
+      	}
+	    this.cloneModel.set({nodes: nodes});
+	  	
 	  	$.get(
 			executeURL,
-			{"project": projectName, "ajax":"flowInfo", "flow":flowName},
+			fetchData,
 			function(data) {
 				if (data.error) {
 					alert(data.error);
 				}
 				else {
-					$('#successEmails').val(data.successEmails);
-					$('#failureEmails').val(data.failureEmails);
+					$('#successEmails').val(data.successEmails.join());
+					$('#failureEmails').val(data.failureEmails.join());
 					
-					if (data.running.length == 0) {
+					if (data.failureAction) {
+						$('#failureAction').val(data.failureAction);
+					}
+					if (data.notifyFailureFirst) {
+						$('#notifyFailureFirst').attr('checked', true);
+					}
+					if (data.notifyFailureLast) {
+						$('#notifyFailureLast').attr('checked', true);	
+					}
+					if (data.flowParam) {
+						var flowParam = data.flowParam;
+						for (var key in flowParam) {
+							var row = handleAddRow();
+							var td = $(row).find('td');
+							$(td[0]).text(key);
+							$(td[1]).text(flowParam[key]);
+						}
+					}
+
+					if (!data.running || data.running.length == 0) {
 						$(".radio").attr("disabled", "disabled");
 						$(".radioLabel").addClass("disabled", "disabled");
 					}
@@ -113,12 +185,22 @@ azkaban.ExecuteFlowView = Backbone.View.extend({
 	  		return;
 	  	}
 	  	
- 	  	this.cloneModel = this.model.clone();
  	  	cloneModel = this.cloneModel;
+
+		var disabled = {};
+		var data = this.cloneModel.get("data");
+		for (var i = 0; i < data.nodes.length; ++i) {
+			var updateNode = data.nodes[i];
+			if (updateNode.status == "DISABLED" || updateNode.status == "SUCCEEDED" || updateNode.status == "SKIPPED") {
+				disabled[updateNode.id] = true;
+			}
+		}
+ 	  	cloneModel.set({disabled: disabled});
+ 	  	
 	  	customSvgGraphView = new azkaban.SvgGraphView({el:$('#svgDivCustom'), model: this.cloneModel, rightClick: {id: 'disableJobMenu', callback: this.handleDisableMenuClick}});
 		customJobsListView = new azkaban.JobListView({el:$('#jobListCustom'), model: this.cloneModel, rightClick: {id: 'disableJobMenu', callback: this.handleDisableMenuClick}});
 		this.cloneModel.trigger("change:graph");
-
+		
 		this.flowSetup = true;
 	  },
 	  handleExecuteFlow: function(evt) {
@@ -198,6 +280,7 @@ azkaban.ExecuteFlowView = Backbone.View.extend({
 	  	$(tr).append(tdValue);
 	   
 	  	$(tr).insertBefore("#addRow");
+	  	return tr;
 	  },
 	  handleEditColumn : function(evt) {
 	  	var curTarget = evt.currentTarget;
@@ -287,17 +370,17 @@ azkaban.ExecuteFlowView = Backbone.View.extend({
 				cloneModel.trigger("change:disabled");
 			}
 			else if (action == "disableChildren") {
-				var disabled = cloneModel.get("disabled");
+				var disabledMap = cloneModel.get("disabled");
 				var nodes = cloneModel.get("nodes");
 				var outNodes = nodes[jobid].outNodes;
 		
 				if (outNodes) {
 					for (var key in outNodes) {
-					  disabled[key] = true;
+					  disabledMap[key] = true;
 					}
 				}
 				
-				cloneModel.set({disabled: disabled});
+				cloneModel.set({disabled: disabledMap});
 				cloneModel.trigger("change:disabled");
 			}
 			else if (action == "disableAncestors") {
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index 318e514..207b6c1 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -73,13 +73,13 @@ azkaban.FlowTabView= Backbone.View.extend({
   	"click #jobslistViewLink" : "handleJobslistLinkClick",
   	"click #flowLogViewLink" : "handleLogLinkClick",
   	"click #cancelbtn" : "handleCancelClick",
-  	"click #restartbtn" : "handleRestartClick",
+  	"click #executebtn" : "handleRestartClick",
   	"click #pausebtn" : "handlePauseClick",
   	"click #resumebtn" : "handleResumeClick",
   },
   initialize : function(settings) {
   	$("#cancelbtn").hide();
-  	$("#restartbtn").hide();
+  	$("#executebtn").hide();
   	$("#pausebtn").hide();
   	$("#resumebtn").hide();
   
@@ -127,15 +127,15 @@ azkaban.FlowTabView= Backbone.View.extend({
   handleFlowStatusChange: function() {
   	var data = this.model.get("data");
   	$("#cancelbtn").hide();
-  	$("#restartbtn").hide();
+  	$("#executebtn").hide();
   	$("#pausebtn").hide();
   	$("#resumebtn").hide();
 
   	if(data.status=="SUCCEEDED") {
-  	  	$("#restartbtn").show();
+  	  	$("#executebtn").show();
   	}
   	else if (data.status=="FAILED") {
-  		$("#restartbtn").show();
+  		$("#executebtn").show();
   	}
   	else if (data.status=="FAILED_FINISHING") {
   		$("#cancelbtn").show();
@@ -152,7 +152,7 @@ azkaban.FlowTabView= Backbone.View.extend({
   		$("#cancelbtn").show();
   	}
   	else if (data.status=="KILLED") {
-  		$("#restartbtn").show();
+  		$("#executebtn").show();
   	}
   },
   handleCancelClick : function(evt) {
@@ -174,6 +174,7 @@ azkaban.FlowTabView= Backbone.View.extend({
       );
   },
   handleRestartClick : function(evt) {
+  	  	executeFlowView.show();
   },
   handlePauseClick : function(evt) {
   	  var requestURL = contextURL + "/executor";
@@ -512,18 +513,17 @@ $(function() {
 	jobsListView = new azkaban.JobListView({el:$('#jobList'), model: graphModel, rightClick: {id: 'jobMenu', callback: handleJobMenuClick}});
 	statusView = new azkaban.StatusView({el:$('#flow-status'), model: graphModel});
 	flowLogView = new azkaban.FlowLogView({el:$('#flowLogView'), model: logModel});
+	executeFlowView = new azkaban.ExecuteFlowView({el:$('#executing-options'), model: graphModel});
 	executionListView = new azkaban.ExecutionListView({el: $('#jobListView'), model:graphModel});
 	var requestURL = contextURL + "/executor";
 
-	// This is to set up the execution flow
-	
-
 	ajaxCall(
 	      requestURL,
 	      {"execid": execId, "ajax":"fetchexecflow"},
 	      function(data) {
 	          console.log("data fetched");
 	          graphModel.set({data: data});
+	          graphModel.set({disabled: {}});
 	          graphModel.trigger("change:graph");
 	          
 	          updateTime = Math.max(updateTime, data.submitTime);
diff --git a/src/web/js/azkaban.flow.graph.view.js b/src/web/js/azkaban.flow.graph.view.js
index 33db1ec..e01c161 100644
--- a/src/web/js/azkaban.flow.graph.view.js
+++ b/src/web/js/azkaban.flow.graph.view.js
@@ -83,25 +83,23 @@ azkaban.SvgGraphView = Backbone.View.extend({
 		bounds.maxY = bounds.maxY ? bounds.maxY + 200 : 200;
 		
 		this.assignInitialStatus(self);
+		this.handleDisabledChange(self);
 		this.graphBounds = bounds;
 		this.resetPanZoom(0);
 	},
 	handleDisabledChange: function(evt) {
 		var disabledMap = this.model.get("disabled");
-		for(var id in disabledMap) {
-		    if(disabledMap.hasOwnProperty(id)) {
-		    	var disabled = disabledMap[id];
-		    	this.nodes[id].disabled = disabled;
-		    	var g = this.gNodes[id];
-		    	
-		    	if (disabled) {
-		    		this.nodes[id].disabled = disabled;
-					addClass(g, "disabled");
-		    	}
-		    	else {
-		    		removeClass(g, "disabled");
-		    	}
-		    }
+
+		for(var id in this.nodes) {
+			 var g = this.gNodes[id];
+			if (disabledMap[id]) {
+				this.nodes[id].disabled = true;
+				addClass(g, "disabled");
+			}
+		    else {
+		    	this.nodes[id].disabled = false;
+		    	removeClass(g, "disabled");
+			}
 		}
 	},
 	assignInitialStatus: function(evt) {
@@ -151,7 +149,7 @@ azkaban.SvgGraphView = Backbone.View.extend({
 	handleRemoveAllStatus: function(gNode) {
 		for (var j = 0; j < statusList.length; ++j) {
 			var status = statusList[j];
-			removeClass(g, status);
+			removeClass(gNode, status);
 		}
 	},
 	clickGraph: function(self) {
diff --git a/src/web/js/azkaban.flow.job.view.js b/src/web/js/azkaban.flow.job.view.js
index b165e28..50de61d 100644
--- a/src/web/js/azkaban.flow.job.view.js
+++ b/src/web/js/azkaban.flow.job.view.js
@@ -13,6 +13,7 @@ azkaban.JobListView = Backbone.View.extend({
 		this.filterInput = $(this.el).find(".filter");
 		this.list = $(this.el).find(".list");
 		this.contextMenu = settings.rightClick;
+		this.listNodes = {};
 	},
 	filterJobs: function(self) {
 		var filter = this.filterInput.val();
@@ -134,6 +135,7 @@ azkaban.JobListView = Backbone.View.extend({
 		
 		this.list.append(ul);
 		this.assignInitialStatus(self);
+		this.handleDisabledChange(self);
 	},
 	handleJobClick : function(evt) {
 		var jobid = evt.currentTarget.jobid;
@@ -156,16 +158,15 @@ azkaban.JobListView = Backbone.View.extend({
 	},
 	handleDisabledChange: function(evt) {
 		var disabledMap = this.model.get("disabled");
-		for(var id in disabledMap) {
-		    if(disabledMap.hasOwnProperty(id)) {
-		    	var disabled = (disabledMap[id]);
-		    	if (disabled) {
-		    		$(this.listNodes[id]).addClass("nodedisabled");
-		    	}
-		    	else {
-		    		$(this.listNodes[id]).removeClass("nodedisabled");
-		    	}
-		    }
+		var nodes = this.model.get("nodes");
+		
+		for(var id in nodes) {
+			if (disabledMap[id]) {
+				$(this.listNodes[id]).addClass("nodedisabled");
+			}
+			else {
+				$(this.listNodes[id]).removeClass("nodedisabled");
+			}
 		}
 	},
 	handleSelectionChange: function(evt) {
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index ad6dec9..9548d98 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -23,28 +23,6 @@ var handleJobMenuClick = function(action, el, pos) {
 	}
 }
 
-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);
-		}
-	}
-}
-
 function hasClass(el, name) 
 {
 	var classes = el.getAttribute("class");
diff --git a/src/web/js/azkaban.job.status.utils.js b/src/web/js/azkaban.job.status.utils.js
index 271af58..848a351 100644
--- a/src/web/js/azkaban.job.status.utils.js
+++ b/src/web/js/azkaban.job.status.utils.js
@@ -1,4 +1,4 @@
-var statusList = ["FAILED", "FAILED_FINISHING", "SUCCEEDED", "RUNNING", "WAITING", "KILLED", "DISABLED", "READY", "UNKNOWN", "PAUSED"];
+var statusList = ["FAILED", "FAILED_FINISHING", "SUCCEEDED", "RUNNING", "WAITING", "KILLED", "DISABLED", "READY", "UNKNOWN", "PAUSED", "SKIPPED"];
 var statusStringMap = {
 	"FAILED": "Failed",
 	"SUCCEEDED": "Success",