azkaban-aplcache

Merge pull request #193 from davidzchen/flow-execution-dialog-fix Correctly

2/24/2014 10:30:27 PM

Details

diff --git a/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm b/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm
index c849910..44a3f16 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm
@@ -1,12 +1,12 @@
 #*
  * Copyright 2012 LinkedIn Corp.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -61,13 +61,15 @@
 									<div id="notification-panel" class="side-panel">
 										<h4>Notify on failure</h4>
 										<p>On a job failure, notify on either the first failure, and/or when the failed flow finishes.</p>
-										<hr>
-										<label class="checkbox-inline">
-											<input id="notify-failure-first" type="checkbox" name="notify" value="first">First failure
-										</label>
-										<label class="checkbox-inline">
-											<input id="notify-failure-last" type="checkbox" name="notify" value="last">Flow finished
-										</label>
+                    <hr>
+                    <div class="btn-group" data-toggle="buttons">
+                      <label class="btn btn-default">
+                        <input id="notify-failure-first" type="radio" name="notify" value="first">First failure
+                      </label>
+                      <label class="btn btn-default">
+                        <input id="notify-failure-last" type="radio" name="notify" value="last">Flow finished
+                      </label>
+                    </div>
 
 										<h4>Failure Emails</h4>
 										<div class="checkbox">
@@ -82,7 +84,7 @@
 										<h4>Success Emails</h4>
 										<div class="checkbox">
 											<label>
-												<input type="checkbox" name="overrideSuccessEmails" value="overrideSuccessEmails">
+												<input type="checkbox" id="override-success-emails" name="overrideSuccessEmails" value="overrideSuccessEmails">
 												Override flow email settings.
 											</label>
 										</div>
@@ -101,7 +103,7 @@
 											<li><strong>Cancel All</strong> immediately kills all jobs and fails the flow.</li>
 											<li><strong>Finish All Possible</strong> will keep executing jobs as long as its dependencies are met.</li>
 										</ul>
-										<select id="failure-action" name="failureAction">
+										<select id="failure-action" name="failureAction" class="form-control form-control-auto">
 											<option value="finishCurrent">Finish Current Running</option>
 											<option value="cancelImmediately">Cancel All</option>
 											<option value="finishPossible">Finish All Possible</option>
@@ -135,7 +137,7 @@
 												<input type="radio" id="pipeline" name="concurrent" value="pipeline">
 												Pipeline
 											</label>
-											<select id="pipelineLevel" name="pipelineLevel">
+											<select id="pipeline-level" name="pipelineLevel" class="form-control form-control-auto input-sm">
 												<option value="1">Level 1</option>
 												<option value="2">Level 2</option>
 											</select>
@@ -178,7 +180,7 @@
 						</div><!-- /modal-body -->
 
 						<div class="modal-footer">
-#if (!$show_schedule || $show_schedule == 'true') 
+#if (!$show_schedule || $show_schedule == 'true')
               <div class="pull-left">
                 <button type="button" class="btn btn-success" id="schedule-btn">Schedule</button>
               </div>
@@ -198,7 +200,7 @@
 				</div><!-- /modal-dialog -->
 			</div><!-- /modal -->
 
-#if (!$show_schedule || $show_schedule == 'true') 
+#if (!$show_schedule || $show_schedule == 'true')
 	#parse ("azkaban/webapp/servlet/velocity/schedulepanel.vm")
 #end
 
diff --git a/src/less/base.less b/src/less/base.less
index 4c7445d..62861ca 100644
--- a/src/less/base.less
+++ b/src/less/base.less
@@ -154,3 +154,7 @@
     margin-bottom: 0;
   }
 }
+
+.form-control-auto {
+  width: auto;
+}
diff --git a/src/web/js/azkaban/view/flow-execute-dialog.js b/src/web/js/azkaban/view/flow-execute-dialog.js
index ce590ca..ad39ac4 100644
--- a/src/web/js/azkaban/view/flow-execute-dialog.js
+++ b/src/web/js/azkaban/view/flow-execute-dialog.js
@@ -1,12 +1,12 @@
 /*
  * Copyright 2012 LinkedIn Corp.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -23,40 +23,40 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 		"click #schedule-btn": "scheduleClick",
 		"click #execute-btn": "handleExecuteFlow"
 	},
-	
+
 	initialize: function(settings) {
 		this.model.bind('change:flowinfo', this.changeFlowInfo, this);
-		$("#overrideSuccessEmails").click(function(evt) {
+		$("#override-success-emails").click(function(evt) {
 			if ($(this).is(':checked')) {
-				$('#successEmails').attr('disabled', null);
+				$('#success-emails').attr('disabled', null);
 			}
 			else {
-				$('#successEmails').attr('disabled', "disabled");
+				$('#success-emails').attr('disabled', "disabled");
 			}
 		});
-				
-		$("#overrideFailureEmails").click(function(evt) {
+
+		$("#override-failure-emails").click(function(evt) {
 			if ($(this).is(':checked')) {
-				$('#failureEmails').attr('disabled', null);
+				$('#failure-emails').attr('disabled', null);
 			}
 			else {
-				$('#failureEmails').attr('disabled', "disabled");
+				$('#failure-emails').attr('disabled', "disabled");
 			}
 		});
 	},
-	
+
 	render: function() {
 	},
-	
+
 	getExecutionOptionData: function() {
-		var failureAction = $('#failureAction').val();
-		var failureEmails = $('#failureEmails').val();
-		var successEmails = $('#successEmails').val();
-		var notifyFailureFirst = $('#notifyFailureFirst').is(':checked');
-		var notifyFailureLast = $('#notifyFailureLast').is(':checked');
-		var failureEmailsOverride = $("#overrideFailureEmails").is(':checked');
-		var successEmailsOverride = $("#overrideSuccessEmails").is(':checked');
-		
+		var failureAction = $('#failure-action').val();
+		var failureEmails = $('#failure-emails').val();
+		var successEmails = $('#success-emails').val();
+		var notifyFailureFirst = $('#notify-failure-first').is(':checked');
+		var notifyFailureLast = $('#notify-failure-last').is(':checked');
+		var failureEmailsOverride = $("#override-failure-emails").is(':checked');
+		var successEmailsOverride = $("#override-success-emails").is(':checked');
+
 		var flowOverride = {};
 		var editRows = $(".editRow");
 		for (var i = 0; i < editRows.length; ++i) {
@@ -69,18 +69,18 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 				flowOverride[key] = val;
 			}
 		}
-		
+
 		var data = this.model.get("data");
 		var disabledList = gatherDisabledNodes(data);
-		
+
 		var executingData = {
 			projectId: projectId,
 			project: this.projectName,
 			ajax: "executeFlow",
 			flow: this.flowId,
 			disabled: JSON.stringify(disabledList),
-			failureEmailsOverride:failureEmailsOverride,
-			successEmailsOverride:successEmailsOverride,
+			failureEmailsOverride: failureEmailsOverride,
+			successEmailsOverride: successEmailsOverride,
 			failureAction: failureAction,
 			failureEmails: failureEmails,
 			successEmails: successEmails,
@@ -88,19 +88,19 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 			notifyFailureLast: notifyFailureLast,
 			flowOverride: flowOverride
 		};
-		
+
 		// Set concurrency option, default is skip
 
 		var concurrentOption = $('input[name=concurrent]:checked').val();
 		executingData.concurrentOption = concurrentOption;
 		if (concurrentOption == "pipeline") {
-			var pipelineLevel = $("#pipelineLevel").val();
+			var pipelineLevel = $("#pipeline-level").val();
 			executingData.pipelineLevel = pipelineLevel;
 		}
 		else if (concurrentOption == "queue") {
 			executingData.queueLevel = $("#queueLevel").val();
 		}
-		
+
 		return executingData;
 	},
 
@@ -116,44 +116,46 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 		var pipelineExecutionId = this.model.get("pipelineExecution");
 		var queueLevel = this.model.get("queueLevel");
 		var nodeStatus = this.model.get("nodeStatus");
-		var overrideSuccessEmails = this.model.get("overrideSuccessEmails");
-		var overrideFailureEmails = this.model.get("overrideFailureEmails");
-		
+		var overrideSuccessEmails = this.model.get("failureEmailsOverride");
+		var overrideFailureEmails = this.model.get("successEmailsOverride");
+
 		if (overrideSuccessEmails) {
-			$('#overrideSuccessEmails').attr('checked', true);
+			$('#override-success-emails').attr('checked', true);
 		}
 		else {
-			$('#successEmails').attr('disabled','disabled');
+			$('#success-emails').attr('disabled','disabled');
 		}
 		if (overrideFailureEmails) {
-			$('#overrideFailureEmails').attr('checked', true);
+			$('#override-failure-emails').attr('checked', true);
 		}
 		else {
-			$('#failureEmails').attr('disabled','disabled');
+			$('#failure-emails').attr('disabled','disabled');
 		}
-		
+
 		if (successEmails) {
-			$('#successEmails').val(successEmails.join());
+			$('#success-emails').val(successEmails.join());
 		}
 		if (failureEmails) {
-			$('#failureEmails').val(failureEmails.join());
+			$('#failure-emails').val(failureEmails.join());
 		}
 		if (failureActions) {
-		$('#failureAction').val(failureActions);
+			$('#failure-action').val(failureActions);
 		}
-		
+
 		if (notifyFailure.first) {
-		$('#notifyFailureFirst').attr('checked', true);
+			$('#notify-failure-first').attr('checked', true);
+			$('#notify-failure-first').parent('.btn').addClass('active');
 		}
 		if (notifyFailure.last) {
-			$('#notifyFailureLast').attr('checked', true);
+			$('#notify-failure-last').attr('checked', true);
+			$('#notify-failure-last').parent('.btn').addClass('active');
 		}
-		
+
 		if (concurrentOption) {
 			$('input[value='+concurrentOption+'][name="concurrent"]').attr('checked', true);
 		}
 		if (pipelineLevel) {
-			$('#pipelineLevel').val(pipelineLevel);
+			$('#pipeline-level').val(pipelineLevel);
 		}
 		if (queueLevel) {
 			$('#queueLevel').val(queueLevel);
@@ -162,25 +164,25 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 		if (flowParams) {
 			for (var key in flowParams) {
 				editTableView.handleAddRow({
-					paramkey: key, 
+					paramkey: key,
 					paramvalue: flowParams[key]
 				});
 			}
 		}
 	},
-	
+
 	show: function(data) {
 		var projectName = data.project;
 		var flowId = data.flow;
 		var jobId = data.job;
-		
+
 		// ExecId is optional
 		var execId = data.execid;
 		var exgraph = data.exgraph;
-		
+
 		this.projectName = projectName;
 		this.flowId = flowId;
-		
+
 		var self = this;
 		var loadCallback = function() {
 			if (jobId) {
@@ -190,13 +192,12 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 				self.showExecuteFlow(projectName, flowId);
 			}
 		}
-		
+
 		var loadedId = executableGraphModel.get("flowId");
 		this.loadGraph(projectName, flowId, exgraph, loadCallback);
 		this.loadFlowInfo(projectName, flowId, execId);
-
 	},
-	
+
 	showExecuteFlow: function(projectName, flowId) {
 		$("#execute-flow-panel-title").text("Execute Flow " + flowId);
 		this.showExecutionOptionPanel();
@@ -204,20 +205,20 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 		// Triggers a render
 		this.model.trigger("change:graph");
 	},
-	
+
 	showExecuteJob: function(projectName, flowId, jobId, withDep) {
 		sideMenuDialogView.menuSelect($("#flow-option"));
 		$("#execute-flow-panel-title").text("Execute Flow " + flowId);
-		
+
 		var data = this.model.get("data");
 		var disabled = this.model.get("disabled");
-		
+
 		// Disable all, then re-enable those you want.
 		disableAll();
-		
+
 		var jobNode = data.nodeMap[jobId];
 		touchNode(jobNode, false);
-		
+
 		if (withDep) {
 			recurseAllAncestors(jobNode, false);
 		}
@@ -225,61 +226,61 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 		this.showExecutionOptionPanel();
 		this.model.trigger("change:graph");
 	},
-	
+
 	showExecutionOptionPanel: function() {
 		sideMenuDialogView.menuSelect($("#flow-option"));
 		$('#execute-flow-panel').modal();
 	},
-	
+
 	hideExecutionOptionPanel: function() {
 		$('#execute-flow-panel').modal("hide");
 	},
-	
+
 	scheduleClick: function() {
 		console.log("click schedule button.");
 		this.hideExecutionOptionPanel();
 		schedulePanelView.showSchedulePanel();
 	},
-	
+
 	loadFlowInfo: function(projectName, flowId, execId) {
 		console.log("Loading flow " + flowId);
 		fetchFlowInfo(this.model, projectName, flowId, execId);
 	},
-	
+
 	loadGraph: function(projectName, flowId, exgraph, callback) {
 		console.log("Loading flow " + flowId);
 		var requestURL = contextURL + "/manager";
-		
+
 		var graphModel = executableGraphModel;
 		// fetchFlow(this.model, projectName, flowId, true);
 		var requestData = {
-				"project": projectName, 
-				"ajax": "fetchflowgraph", 
+				"project": projectName,
+				"ajax": "fetchflowgraph",
 				"flow": flowId
 			};
 		var self = this;
 		var successHandler = function(data) {
 			console.log("data fetched");
 			graphModel.addFlow(data);
-			
+
 			if (exgraph) {
 				self.assignInitialStatus(data, exgraph);
 			}
-			
+
 			// Auto disable jobs that are finished.
 			disableFinishedJobs(data);
 			executingSvgGraphView = new azkaban.SvgGraphView({
-				el: $('#flow-executing-graph'), 
+				el: $('#flow-executing-graph'),
 				model: graphModel,
 				render: false,
-				rightClick: { 
+				rightClick: {
 					"node": expanelNodeClickCallback,
-					"edge": expanelEdgeClickCallback, 
-					"graph": expanelGraphClickCallback 
+					"edge": expanelEdgeClickCallback,
+					"graph": expanelGraphClickCallback
 				},
 				tooltipcontainer: "#svg-div-custom"
 			});
-			
+
 			if (callback) {
 				callback.call(this);
 			}
@@ -291,7 +292,7 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
 		// Copies statuses over from the previous execution if it exists.
 		var statusNodeMap = statusData.nodeMap;
 		var nodes = data.nodes;
-		for(var i=0; i<nodes.length; ++i) {
+		for (var i = 0; i<nodes.length; ++i) {
 			var node = nodes[i];
 			var statusNode = statusNodeMap[node.id];
 			if (statusNode) {
@@ -321,23 +322,23 @@ azkaban.EditTableView = Backbone.View.extend({
 
 	initialize: function(setting) {
 	},
-	
+
 	handleAddRow: function(data) {
 		var name = "";
 		if (data.paramkey) {
 			name = data.paramkey;
 		}
-		
+
 		var value = "";
 		if (data.paramvalue) {
 			value = data.paramvalue;
 		}
-	
+
 		var tr = document.createElement("tr");
 		var tdName = document.createElement("td");
 		$(tdName).addClass('property-key');
 		var tdValue = document.createElement("td");
-		
+
 		var remove = document.createElement("div");
 		$(remove).addClass("pull-right").addClass('remove-btn');
 		var removeBtn = document.createElement("button");
@@ -352,28 +353,28 @@ azkaban.EditTableView = Backbone.View.extend({
 		var valueData = document.createElement("span");
 		$(valueData).addClass("spanValue");
 		$(valueData).text(value);
-						
+
 		$(tdName).append(nameData);
 		$(tdName).addClass("editable");
-		
+
 		$(tdValue).append(valueData);
 		$(tdValue).append(remove);
 		$(tdValue).addClass("editable").addClass('value');
-		
+
 		$(tr).addClass("editRow");
 		$(tr).append(tdName);
 		$(tr).append(tdValue);
-	 
+
 		$(tr).insertBefore(".addRow");
 		return tr;
 	},
-	
+
 	handleEditColumn: function(evt) {
 		var curTarget = evt.currentTarget;
-	
+
 		var text = $(curTarget).children(".spanValue").text();
 		$(curTarget).empty();
-					
+
 		var input = document.createElement("input");
 		$(input).attr("type", "text");
 		$(input).addClass('form-control').addClass('input-sm');
@@ -382,12 +383,12 @@ azkaban.EditTableView = Backbone.View.extend({
 		$(curTarget).addClass("editing");
 		$(curTarget).append(input);
 		$(input).focus();
-		
+
 		var obj = this;
 		$(input).focusout(function(evt) {
 			obj.closeEditingTarget(evt);
 		});
-		
+
 		$(input).keypress(function(evt) {
 			if (evt.which == 13) {
 				obj.closeEditingTarget(evt);
@@ -401,7 +402,7 @@ azkaban.EditTableView = Backbone.View.extend({
 		var row = curTarget.parentElement.parentElement;
 		$(row).remove();
 	},
-	
+
 	closeEditingTarget: function(evt) {
 		var input = evt.currentTarget;
 		var text = $(input).val();
@@ -422,7 +423,7 @@ azkaban.EditTableView = Backbone.View.extend({
 			$(remove).append(removeBtn);
 			$(parent).append(remove);
 		}
-		
+
 		$(parent).removeClass("editing");
 		$(parent).append(valueData);
 	}
@@ -433,7 +434,7 @@ azkaban.SideMenuDialogView = Backbone.View.extend({
 	events: {
 		"click .menu-header": "menuClick"
 	},
-	
+
 	initialize: function(settings) {
 		var children = $(this.el).children();
 		for (var i = 0; i < children.length; ++i ) {
@@ -444,25 +445,25 @@ azkaban.SideMenuDialogView = Backbone.View.extend({
 		}
 		this.menuSelect($("#flow-option"));
 	},
-	
+
 	menuClick: function(evt) {
 		this.menuSelect(evt.currentTarget);
 	},
-	
+
 	menuSelect: function(target) {
 		if ($(target).hasClass("active")) {
 			return;
 		}
-		
+
 		$(".side-panel").each(function() {
 			$(this).hide();
 		});
-		
+
 		$(".menu-header").each(function() {
 			$(this).find(".menu-caption").slideUp("fast");
 			$(this).removeClass("active");
 		});
-		
+
 		$(target).addClass("active");
 		$(target).find(".menu-caption").slideDown("fast");
 		var panelName = $(target).attr("viewpanel");
@@ -472,7 +473,7 @@ azkaban.SideMenuDialogView = Backbone.View.extend({
 
 var handleJobMenuClick = function(action, el, pos) {
 	var jobid = el[0].jobid;
-	
+
 	var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowName + "&job=" + jobid;
 	if (action == "open") {
 		window.location.href = requestURL;
@@ -490,7 +491,7 @@ var executableGraphModel;
 var disableFinishedJobs = function(data) {
 	for (var i = 0; i < data.nodes.length; ++i) {
 		var node = data.nodes[i];
-		
+
 		if (node.status == "DISABLED" || node.status == "SKIPPED") {
 			node.status = "READY";
 			node.disabled = true;
@@ -528,7 +529,7 @@ var recurseTree = function(data, disabled, recurse) {
 	for (var i = 0; i < data.nodes.length; ++i) {
 		var node = data.nodes[i];
 		node.disabled = disabled;
-		
+
 		if (node.type == "flow" && recurse) {
 			recurseTree(node, disabled);
 		}
@@ -560,26 +561,26 @@ var touchChildren = function(node, disable) {
 			outNodes[key].disabled = disable;
 		}
 	}
-	
+
 	executableGraphModel.trigger("change:disabled");
 }
 
 var touchAncestors = function(node, disable) {
 	recurseAllAncestors(node, disable);
-	
+
 	executableGraphModel.trigger("change:disabled");
 }
 
 var touchDescendents = function(node, disable) {
 	recurseAllDescendents(node, disable);
-	
+
 	executableGraphModel.trigger("change:disabled");
 }
 
 var gatherDisabledNodes = function(data) {
 	var nodes = data.nodes;
 	var disabled = [];
-	
+
 	for (var i = 0; i < nodes.length; ++i) {
 		var node = nodes[i];
 		if (node.disabled) {
@@ -594,7 +595,7 @@ var gatherDisabledNodes = function(data) {
 			}
 		}
 	}
-	
+
 	return disabled;
 }
 
@@ -623,7 +624,7 @@ var expanelNodeClickCallback = function(event, model, node) {
 	var jobId = node.id;
 	var flowId = executableGraphModel.get("flowId");
 	var type = node.type;
-	
+
 	var menu;
 	if (type == "flow") {
 		var flowRequestURL = contextURL + "/manager?project=" + projectName + "&flow=" + node.flowId;
@@ -632,7 +633,7 @@ var expanelNodeClickCallback = function(event, model, node) {
 				{title: "Collapse Flow...", callback: function() {model.trigger("collapseFlow", node);}},
 				{title: "Open Flow in New Window...", callback: function() {window.open(flowRequestURL);}}
 			];
-	
+
 		}
 		else {
 			menu = [
@@ -679,7 +680,7 @@ var expanelGraphClickCallback = function(event) {
 	console.log("Graph clicked callback");
 	var flowId = executableGraphModel.get("flowId");
 	var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId;
-	
+
 	var menu = [
 		{title: "Open Flow in New Window...", callback: function() {window.open(requestURL);}},
 		{break: 1},
@@ -688,7 +689,7 @@ var expanelGraphClickCallback = function(event) {
 		{break: 1},
 		{title: "Center Graph", callback: function() {executableGraphModel.trigger("resetPanZoom");}}
 	];
-	
+
 	contextMenuView.show(event, menu);
 }
 
@@ -696,10 +697,10 @@ var contextMenuView;
 $(function() {
 	executableGraphModel = new azkaban.GraphModel();
 	flowExecuteDialogView = new azkaban.FlowExecuteDialogView({
-		el: $('#execute-flow-panel'), 
+		el: $('#execute-flow-panel'),
 		model: executableGraphModel
 	});
-	
+
 	sideMenuDialogView = new azkaban.SideMenuDialogView({
 		el: $('#graph-options')
 	});