azkaban-aplcache
Changes
src/web/css/azkaban.css 18(+18 -0)
src/web/js/azkaban.exflow.options.view.js 101(+92 -9)
src/web/js/azkaban.exflow.view.js 18(+9 -9)
src/web/js/azkaban.flow.graph.view.js 28(+13 -15)
src/web/js/azkaban.flow.job.view.js 21(+11 -10)
src/web/js/azkaban.flow.view.js 22(+0 -22)
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>
src/web/css/azkaban.css 18(+18 -0)
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;
src/web/js/azkaban.exflow.options.view.js 101(+92 -9)
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") {
src/web/js/azkaban.exflow.view.js 18(+9 -9)
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);
src/web/js/azkaban.flow.graph.view.js 28(+13 -15)
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) {
src/web/js/azkaban.flow.job.view.js 21(+11 -10)
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) {
src/web/js/azkaban.flow.view.js 22(+0 -22)
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",