azkaban-developers
Changes
src/less/flow.less 9(+9 -0)
src/web/css/azkaban-graph.css 16(+6 -10)
src/web/js/azkaban.exflow.view.js 228(+135 -93)
src/web/js/azkaban.flow.execute.view.js 54(+40 -14)
src/web/js/azkaban.svg.graph.view.js 55(+36 -19)
Details
diff --git a/src/java/azkaban/execapp/JobRunner.java b/src/java/azkaban/execapp/JobRunner.java
index 912844e..99bd8ab 100644
--- a/src/java/azkaban/execapp/JobRunner.java
+++ b/src/java/azkaban/execapp/JobRunner.java
@@ -361,9 +361,9 @@ public class JobRunner extends EventHandler implements Runnable {
);
Arrays.sort(files, Collections.reverseOrder());
- loader.uploadLogFile(executionId, this.jobId, node.getAttempt(), files);
+ loader.uploadLogFile(executionId, this.node.getNestedId(), node.getAttempt(), files);
} catch (ExecutorManagerException e) {
- flowLogger.error("Error writing out logs for job " + this.jobId, e);
+ flowLogger.error("Error writing out logs for job " + this.node.getNestedId(), e);
}
}
else {
diff --git a/src/java/azkaban/webapp/servlet/ExecutorServlet.java b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
index 0e155c3..808ba7b 100644
--- a/src/java/azkaban/webapp/servlet/ExecutorServlet.java
+++ b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
@@ -115,9 +115,6 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
else if (ajaxName.equals("cancelFlow")) {
ajaxCancelFlow(req, resp, ret, session.getUser(), exFlow);
}
- else if (ajaxName.equals("restartFlow")) {
- ajaxRestartFlow(req, resp, ret, session.getUser(), exFlow);
- }
else if (ajaxName.equals("pauseFlow")) {
ajaxPauseFlow(req, resp, ret, session.getUser(), exFlow);
}
@@ -609,13 +606,6 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
ret.put("execIds", refs);
}
}
-
- private void ajaxRestartFlow(HttpServletRequest req, HttpServletResponse resp, HashMap<String, Object> ret, User user, ExecutableFlow exFlow) throws ServletException{
- Project project = getProjectAjaxByPermission(ret, exFlow.getProjectId(), user, Type.EXECUTE);
- if (project == null) {
- return;
- }
- }
private void ajaxPauseFlow(HttpServletRequest req, HttpServletResponse resp, HashMap<String, Object> ret, User user, ExecutableFlow exFlow) throws ServletException{
Project project = getProjectAjaxByPermission(ret, exFlow.getProjectId(), user, Type.EXECUTE);
@@ -645,19 +635,6 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
private Map<String,Object> getExecutableFlowUpdateInfo(ExecutableNode node, long lastUpdateTime) {
HashMap<String, Object> nodeObj = new HashMap<String,Object>();
- if (node.getUpdateTime() > lastUpdateTime) {
- nodeObj.put("id", node.getId());
- nodeObj.put("status", node.getStatus());
- nodeObj.put("startTime", node.getStartTime());
- nodeObj.put("endTime", node.getEndTime());
- nodeObj.put("updateTime", node.getUpdateTime());
-
- nodeObj.put("attempt", node.getAttempt());
- if (node.getAttempt() > 0) {
- nodeObj.put("pastAttempts", node.getAttemptObjects());
- }
- }
-
if (node instanceof ExecutableFlowBase) {
ExecutableFlowBase base = (ExecutableFlowBase)node;
ArrayList<Map<String, Object>> nodeList = new ArrayList<Map<String, Object>>();
@@ -672,8 +649,19 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
if (!nodeList.isEmpty()) {
nodeObj.put("flow", base.getFlowId());
nodeObj.put("nodes", nodeList);
- // We do this again, because the above update time may not have been built.
- nodeObj.put("id", node.getId());
+ }
+ }
+
+ if (node.getUpdateTime() > lastUpdateTime || !nodeObj.isEmpty()) {
+ nodeObj.put("id", node.getId());
+ nodeObj.put("status", node.getStatus());
+ nodeObj.put("startTime", node.getStartTime());
+ nodeObj.put("endTime", node.getEndTime());
+ nodeObj.put("updateTime", node.getUpdateTime());
+
+ nodeObj.put("attempt", node.getAttempt());
+ if (node.getAttempt() > 0) {
+ nodeObj.put("pastAttempts", node.getAttemptObjects());
}
}
@@ -688,6 +676,7 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
nodeObj.put("endTime", node.getEndTime());
nodeObj.put("updateTime", node.getUpdateTime());
nodeObj.put("type", node.getType());
+ nodeObj.put("nestedId", node.getNestedId());
nodeObj.put("attempt", node.getAttempt());
if (node.getAttempt() > 0) {
src/less/flow.less 9(+9 -0)
diff --git a/src/less/flow.less b/src/less/flow.less
index 452a66e..5408f07 100644
--- a/src/less/flow.less
+++ b/src/less/flow.less
@@ -63,6 +63,14 @@
}
td {
+ > .listExpand {
+ width: 16px;
+ height: 16px;
+ float:right;
+ margin-top: 5px;
+ font-size: 8pt;
+ }
+
.status {
-moz-border-radius: 2px;
border-radius: 2px;
@@ -194,6 +202,7 @@ td {
float: right;
width: 16px;
height: 16px;
+ font-size: 8pt;
}
.filterHighlight {
src/web/css/azkaban-graph.css 16(+6 -10)
diff --git a/src/web/css/azkaban-graph.css b/src/web/css/azkaban-graph.css
index 5958152..6d1112b 100644
--- a/src/web/css/azkaban-graph.css
+++ b/src/web/css/azkaban-graph.css
@@ -74,13 +74,9 @@
fill: #FFF;
}
-.KILLED {
- opacity: 0.5;
-}
-
.KILLED > g > rect {
- fill: #d2322d;
- stroke: #d2322d;
+ fill: #FF9999;
+ stroke: #FF9999;
}
.KILLED > g > text {
@@ -97,13 +93,13 @@
}
.DISABLED > g > rect {
- fill: #800000;
- stroke: #800000;
+ fill: #DDD;
+ stroke: #CCC;
}
.DISABLED > g > rect {
- fill: #800000;
- stroke: #800000;
+ fill: #DDD;
+ stroke: #CCC;
}
.nodeDisabled {
src/web/js/azkaban.exflow.view.js 228(+135 -93)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index e078112..168de67 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -218,14 +218,15 @@ azkaban.FlowTabView = Backbone.View.extend({
},
handleRestartClick: function(evt) {
- console.log("handleRestartClick");
+ console.log("handleRestartClick");
var data = graphModel.get("data");
- var nodes = data.nodes;
+
var executingData = {
project: projectName,
ajax: "executeFlow",
flow: flowId,
- execid: execId
+ execid: execId,
+ exgraph: data
};
flowExecuteDialogView.show(executingData);
},
@@ -318,73 +319,77 @@ azkaban.ExecutionListView = Backbone.View.extend({
},
updateJobRow: function(nodes) {
+ if (!nodes) {
+ return;
+ }
+
var executingBody = $("#executableBody");
nodes.sort(function(a,b) { return a.startTime - b.startTime; });
for (var i = 0; i < nodes.length; ++i) {
var node = nodes[i];
if (node.startTime < 0) {
- continue;
- }
- var nodeId = node.id.replace(".", "\\\\.");
- var row = document.getElementById(nodeId + "-row");
- if (!row) {
- this.addNodeRow(node);
- }
-
- var div = $("#" + nodeId + "-status-div");
- div.text(statusStringMap[node.status]);
- $(div).attr("class", "status " + node.status);
-
- var startdate = new Date(node.startTime);
- $("#" + nodeId + "-start").text(getDateFormat(startdate));
-
- var endTime = node.endTime;
- if (node.endTime == -1) {
- $("#" + nodeId + "-end").text("-");
- endTime = node.startTime + 1;
- }
- else {
- var enddate = new Date(node.endTime);
- $("#" + nodeId + "-end").text(getDateFormat(enddate));
- }
-
- var progressBar = $("#" + nodeId + "-progressbar");
- if (!progressBar.hasClass(node.status)) {
- for (var j = 0; j < statusList.length; ++j) {
- var status = statusList[j];
- progressBar.removeClass(status);
- }
- progressBar.addClass(node.status);
- }
-
- // Create past attempts
- if (node.pastAttempts) {
- for (var a = 0; a < node.pastAttempts.length; ++a) {
- var attemptBarId = nodeId + "-progressbar-" + a;
- var attempt = node.pastAttempts[a];
- if ($("#" + attemptBarId).length == 0) {
- var attemptBox = document.createElement("div");
- $(attemptBox).attr("id", attemptBarId);
- $(attemptBox).addClass("flow-progress-bar");
- $(attemptBox).addClass("attempt");
- $(attemptBox).addClass(attempt.status);
- $(attemptBox).css("float","left");
- $(attemptBox).bind("contextmenu", attemptRightClick);
- $(progressBar).before(attemptBox);
- attemptBox.job = nodeId;
- attemptBox.attempt = a;
- }
- }
- }
-
- if (node.endTime == -1) {
- //$("#" + node.id + "-elapse").text("0 sec");
- $("#" + nodeId + "-elapse").text(getDuration(node.startTime, (new Date()).getTime()));
- }
- else {
- $("#" + nodeId + "-elapse").text(getDuration(node.startTime, node.endTime));
+ continue;
+ }
+ var nodeId = node.id.replace(".", "\\\\.");
+ var row = document.getElementById(nodeId + "-row");
+ if (!row) {
+ this.addNodeRow(node);
+ }
+
+ var div = $("#" + nodeId + "-status-div");
+ div.text(statusStringMap[node.status]);
+ $(div).attr("class", "status " + node.status);
+
+ var startdate = new Date(node.startTime);
+ $("#" + nodeId + "-start").text(getDateFormat(startdate));
+
+ var endTime = node.endTime;
+ if (node.endTime == -1) {
+ $("#" + nodeId + "-end").text("-");
+ endTime = node.startTime + 1;
+ }
+ else {
+ var enddate = new Date(node.endTime);
+ $("#" + nodeId + "-end").text(getDateFormat(enddate));
+ }
+
+ var progressBar = $("#" + nodeId + "-progressbar");
+ if (!progressBar.hasClass(node.status)) {
+ for (var j = 0; j < statusList.length; ++j) {
+ var status = statusList[j];
+ progressBar.removeClass(status);
+ }
+ progressBar.addClass(node.status);
+ }
+
+ // Create past attempts
+ if (node.pastAttempts) {
+ for (var a = 0; a < node.pastAttempts.length; ++a) {
+ var attemptBarId = nodeId + "-progressbar-" + a;
+ var attempt = node.pastAttempts[a];
+ if ($("#" + attemptBarId).length == 0) {
+ var attemptBox = document.createElement("div");
+ $(attemptBox).attr("id", attemptBarId);
+ $(attemptBox).addClass("flow-progress-bar");
+ $(attemptBox).addClass("attempt");
+ $(attemptBox).addClass(attempt.status);
+ $(attemptBox).css("float","left");
+ $(attemptBox).bind("contextmenu", attemptRightClick);
+ $(progressBar).before(attemptBox);
+ attemptBox.job = nodeId;
+ attemptBox.attempt = a;
}
+ }
+ }
+
+ if (node.endTime == -1) {
+ //$("#" + node.id + "-elapse").text("0 sec");
+ $("#" + nodeId + "-elapse").text(getDuration(node.startTime, (new Date()).getTime()));
+ }
+ else {
+ $("#" + nodeId + "-elapse").text(getDuration(node.startTime, node.endTime));
+ }
}
},
@@ -452,8 +457,29 @@ azkaban.ExecutionListView = Backbone.View.extend({
elem.attr("title", "attempt:" + elem.attempt + " start:" + getHourMinSec(new Date(node.startTime)) + " end:" + getHourMinSec(new Date(node.endTime)));
}
},
-
+ toggleExpandFlow: function(flow) {
+ console.log("Toggle Expand");
+ var tr = flow.progressbar;
+ var expandIcon = $(tr).find("> td > .listExpand");
+ if (tr.expanded) {
+ tr.expanded = false;
+ $(expandIcon).removeClass("glyphicon-chevron-up");
+ $(expandIcon).addClass("glyphicon-chevron-down");
+ }
+ else {
+ tr.expanded = true;
+ $(expandIcon).addClass("glyphicon-chevron-up");
+ $(expandIcon).removeClass("glyphicon-chevron-down");
+ }
+ },
+ expandFlow: function(flow) {
+ for (var i = 0; i < flow.nodes.length; ++i) {
+ var node = flow.nodes[i];
+ ///@TODO Expand.
+ }
+ },
addNodeRow: function(node) {
+ var self = this;
var executingBody = $("#executableBody");
var tr = document.createElement("tr");
var tdName = document.createElement("td");
@@ -463,6 +489,8 @@ azkaban.ExecutionListView = Backbone.View.extend({
var tdElapse = document.createElement("td");
var tdStatus = document.createElement("td");
var tdDetails = document.createElement("td");
+ node.progressbar = tr;
+ tr.node = node;
$(tr).append(tdName);
$(tr).append(tdTimeline);
@@ -495,24 +523,35 @@ azkaban.ExecutionListView = Backbone.View.extend({
$(a).attr("href", requestURL);
$(a).text(node.id);
$(tdName).append(a);
+ if (node.type=="flow") {
+ var expandIcon = document.createElement("div");
+ $(expandIcon).addClass("listExpand");
+ $(tdName).append(expandIcon);
+ $(expandIcon).addClass("expandarrow glyphicon glyphicon-chevron-down");
+ $(expandIcon).click(function(evt) {
+ var parent = $(evt.currentTarget).parents("tr")[0];
+ self.toggleExpandFlow(parent.node);
+ });
+ }
var status = document.createElement("div");
$(status).addClass("status");
$(status).attr("id", node.id + "-status-div");
tdStatus.appendChild(status);
- var logURL = contextURL + "/executor?execid=" + execId + "&job=" + node.id;
+ var logURL = contextURL + "/executor?execid=" + execId + "&job=" + node.nestedId;
if (node.attempt) {
logURL += "&attempt=" + node.attempt;
}
- var a = document.createElement("a");
- $(a).attr("href", logURL);
- $(a).attr("id", node.id + "-log-link");
- $(a).text("Details");
- $(tdDetails).addClass("details");
- $(tdDetails).append(a);
-
+ if (node.type != 'flow' && node.status != 'SKIPPED') {
+ var a = document.createElement("a");
+ $(a).attr("href", logURL);
+ $(a).attr("id", node.id + "-log-link");
+ $(a).text("Details");
+ $(tdDetails).addClass("details");
+ $(tdDetails).append(a);
+ }
executingBody.append(tr);
}
});
@@ -577,6 +616,7 @@ var updateStatus = function() {
var oldData = graphModel.get("data");
var nodeMap = graphModel.get("nodeMap");
+ var updateTime = oldData.updateTime ? oldData.updateTime : 0;
var requestData = {
"execid": execId,
"ajax": "fetchexecflowupdate",
@@ -586,23 +626,8 @@ var updateStatus = function() {
var successHandler = function(data) {
console.log("data updated");
updateTime = data.updateTime;
- oldData.submitTime = data.submitTime;
- oldData.startTime = data.startTime;
- oldData.endTime = data.endTime;
- oldData.status = data.status;
- for (var i = 0; i < data.nodes.length; ++i) {
- var node = data.nodes[i];
- var oldNode = nodeMap[node.id];
- oldNode.startTime = node.startTime;
- oldNode.updateTime = node.updateTime;
- oldNode.endTime = node.endTime;
- oldNode.status = node.status;
- oldNode.attempt = node.attempt;
- if (oldNode.attempt > 0) {
- oldNode.pastAttempts = node.pastAttempts;
- }
- }
+ updateGraph(oldData, data);
graphModel.set({"update": data});
graphModel.trigger("change:update");
@@ -610,6 +635,23 @@ var updateStatus = function() {
ajaxCall(requestURL, requestData, successHandler);
}
+var updateGraph = function(data, update) {
+ var nodeMap = data.nodeMap;
+ data.startTime = update.startTime;
+ data.endTime = update.endTime;
+ data.updateTime = update.updateTime;
+ data.status = update.status;
+
+ if (update.nodes) {
+ for (var i = 0; i < update.nodes.length; ++i) {
+ var newNode = update.nodes[i];
+ var oldNode = nodeMap[newNode.id];
+
+ updateGraph(oldNode, newNode);
+ }
+ }
+}
+
var updateTime = -1;
var updaterFunction = function() {
var oldData = graphModel.get("data");
@@ -742,18 +784,18 @@ $(function() {
}
});
- jobsListView = new azkaban.JobListView({
+ jobsListView = new azkaban.JobListView({
el: $('#jobList'),
model: graphModel,
contextMenuCallback: jobClickCallback
});
- flowLogView = new azkaban.FlowLogView({
+ flowLogView = new azkaban.FlowLogView({
el: $('#flowLogView'),
model: logModel
});
- statusView = new azkaban.StatusView({
+ statusView = new azkaban.StatusView({
el: $('#flow-status'),
model: graphModel
});
@@ -819,8 +861,8 @@ $(function() {
// else {
// flowTabView.handleGraphLinkClick();
// }
-// updaterFunction();
-// logUpdaterFunction();
+ updaterFunction();
+ logUpdaterFunction();
};
ajaxCall(requestURL, requestData, successHandler);
});
src/web/js/azkaban.flow.execute.view.js 54(+40 -14)
diff --git a/src/web/js/azkaban.flow.execute.view.js b/src/web/js/azkaban.flow.execute.view.js
index 909917d..700b4eb 100644
--- a/src/web/js/azkaban.flow.execute.view.js
+++ b/src/web/js/azkaban.flow.execute.view.js
@@ -175,11 +175,12 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
// ExecId is optional
var execId = data.execid;
-
+ var exgraph = data.exgraph;
+
var loadedId = executableGraphModel.get("flowId");
- this.loadGraph(projectName, flowId);
+ this.loadGraph(projectName, flowId, exgraph);
this.loadFlowInfo(projectName, flowId, execId);
-
+
this.projectName = projectName;
this.flowId = flowId;
if (jobId) {
@@ -238,7 +239,7 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
fetchFlowInfo(this.model, projectName, flowId, execId);
},
- loadGraph: function(projectName, flowId) {
+ loadGraph: function(projectName, flowId, exgraph) {
console.log("Loading flow " + flowId);
var requestURL = contextURL + "/manager";
@@ -249,26 +250,47 @@ azkaban.FlowExecuteDialogView = Backbone.View.extend({
"ajax": "fetchflowgraph",
"flow": flowId
};
+ var self = this;
var successHandler = function(data) {
console.log("data fetched");
processFlowData(data);
- disableFinishedJobs(data);
graphModel.set({data:data});
+ if (exgraph) {
+ self.assignInitialStatus(data, exgraph);
+ }
+
+ // Auto disable jobs that are finished.
+ disableFinishedJobs(data);
executingSvgGraphView = new azkaban.SvgGraphView({
el: $('#flow-executing-graph'),
model: graphModel,
render: true,
rightClick: {
- "node": exNodeClickCallback,
- "edge": exEdgeClickCallback,
- "graph": exGraphClickCallback
- }
+ "node": expanelNodeClickCallback,
+ "edge": expanelEdgeClickCallback,
+ "graph": expanelGraphClickCallback
+ },
+ tooltipcontainer: "#svg-div-custom"
});
};
$.get(requestURL, requestData, successHandler, "json");
},
-
+ assignInitialStatus: function(data, statusData) {
+ // 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) {
+ var node = nodes[i];
+ var statusNode = statusNodeMap[node.id];
+ if (statusNode) {
+ node.status = statusNode.status;
+ if (node.type == "flow" && statusNode.type == "flow") {
+ this.assignInitialStatus(node, statusNode);
+ }
+ }
+ }
+ },
handleExecuteFlow: function(evt) {
console.log("click schedule button.");
var executeURL = contextURL + "/executor";
@@ -457,7 +479,7 @@ azkaban.GraphModel = Backbone.Model.extend({});
var disableFinishedJobs = function(data) {
for (var i=0; i < data.nodes.length; ++i) {
var node = data.nodes[i];
- node.status = status;
+
if (node.status == "DISABLED" || node.status == "SKIPPED") {
node.status = "READY";
node.disabled = true;
@@ -465,6 +487,10 @@ var disableFinishedJobs = function(data) {
else if (node.status == "SUCCEEDED" || node.status=="RUNNING") {
node.disabled = true;
}
+ else if (node.status == "KILLED") {
+ node.disabled = false;
+ node.status="READY";
+ }
else {
node.disabled = false;
if (node.flowData) {
@@ -581,7 +607,7 @@ function recurseAllDescendents(node, disable) {
}
}
-var exNodeClickCallback = function(event, model, node) {
+var expanelNodeClickCallback = function(event, model, node) {
console.log("Node clicked callback");
var jobId = node.id;
var flowId = executableGraphModel.get("flowId");
@@ -634,11 +660,11 @@ var exNodeClickCallback = function(event, model, node) {
contextMenuView.show(event, menu);
}
-var exEdgeClickCallback = function(event) {
+var expanelEdgeClickCallback = function(event) {
console.log("Edge clicked callback");
}
-var exGraphClickCallback = function(event) {
+var expanelGraphClickCallback = function(event) {
console.log("Graph clicked callback");
var flowId = executableGraphModel.get("flowId");
var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId;
diff --git a/src/web/js/azkaban.svg.flow.loader.js b/src/web/js/azkaban.svg.flow.loader.js
index 24098fa..e629758 100644
--- a/src/web/js/azkaban.svg.flow.loader.js
+++ b/src/web/js/azkaban.svg.flow.loader.js
@@ -8,7 +8,8 @@ var statusStringMap = {
"DISABLED": "Disabled",
"READY": "Ready",
"UNKNOWN": "Unknown",
- "QUEUED": "Queued"
+ "QUEUED": "Queued",
+ "SKIPPED": "Skipped"
};
var extendedViewPanels = {};
src/web/js/azkaban.svg.graph.view.js 55(+36 -19)
diff --git a/src/web/js/azkaban.svg.graph.view.js b/src/web/js/azkaban.svg.graph.view.js
index 968de08..be35b0d 100644
--- a/src/web/js/azkaban.svg.graph.view.js
+++ b/src/web/js/azkaban.svg.graph.view.js
@@ -69,6 +69,7 @@ azkaban.SvgGraphView = Backbone.View.extend({
});
}
+ this.tooltipcontainer = settings.tooltipcontainer ? settings.tooltipcontainer : "body";
if (settings.render) {
this.render();
}
@@ -161,9 +162,8 @@ azkaban.SvgGraphView = Backbone.View.extend({
};
$(".node").each(
- function(d,i){
- $(this).tooltip({container:"body", delay: {show: 500, hide: 100}});
- });
+ function(d,i){$(this).tooltip({container:self.tooltipcontainer, delay: {show: 500, hide: 100}});
+ });
return bounds;
},
@@ -174,11 +174,15 @@ azkaban.SvgGraphView = Backbone.View.extend({
for (var i =0; i < data.nodes.length; ++i) {
var node = data.nodes[i];
if (node.disabled) {
- addClass(node.gNode, "nodeDisabled");
+ if (node.gNode) {
+ addClass(node.gNode, "nodeDisabled");
+ $(node.gNode).attr("title", "DISABLED (" + node.type + ")").tooltip('fixTitle');
+ }
}
else {
if (node.gNode) {
removeClass(node.gNode, "nodeDisabled");
+ $(node.gNode).attr("title", node.status + " (" + node.type + ")").tooltip('fixTitle');
}
if (node.type=='flow') {
this.changeDisabled(node);
@@ -193,11 +197,13 @@ azkaban.SvgGraphView = Backbone.View.extend({
var initialStatus = updateNode.status ? updateNode.status : "READY";
addClass(g, initialStatus);
- $(g).attr("title", updateNode.status + " (" + updateNode.type + ")");
+ var title = updateNode.status + " (" + updateNode.type + ")";
if (updateNode.disabled) {
addClass(g, "nodeDisabled");
+ title = "DISABLED (" + updateNode.type + ")";
}
+ $(g).attr("title", title);
}
},
changeSelected: function(self) {
@@ -221,30 +227,41 @@ azkaban.SvgGraphView = Backbone.View.extend({
}
}
},
- propagateExpansion: function(node) {
+ propagateExpansion: function(node) {
if (node.parent.type) {
this.propagateExpansion(node.parent);
this.expandFlow(node.parent);
}
},
- handleStatusUpdate: function(evt) {
+ handleStatusUpdate: function(evt) {
var updateData = this.model.get("update");
- this.updateStatusChanges(updatedData);
+ var data = this.model.get("data");
+ this.updateStatusChanges(updateData, data);
},
- updateStatusChanges: function(changedData) {
+ updateStatusChanges: function(updateData, data) {
// Assumes all changes have been applied.
- if (changedData.nodes) {
- var nodeMap = previousData.nodeMap;
- for (var i = 0; i < changedData.nodes.length; ++i) {
- var node = changedData.nodes[i];
- var nodeToUpdate = nodeMap[updateNode.id];
+ if (updateData.nodes) {
+ var nodeMap = data.nodeMap;
+ for (var i = 0; i < updateData.nodes.length; ++i) {
+ var node = updateData.nodes[i];
+ var nodeToUpdate = nodeMap[node.id];
var g = nodeToUpdate.gNode;
- this.handleRemoveAllStatus(g);
- addClass(g, nodeToUpdate.status);
- $(g).attr("title", updateNode.status + " (" + updateNode.type + ")");
-
- this.updateStatusChanges(node);
+ if (g) {
+ this.handleRemoveAllStatus(g);
+ addClass(g, nodeToUpdate.status);
+
+ var title = nodeToUpdate.status + " (" + nodeToUpdate.type + ")";
+ if (nodeToUpdate.disabled) {
+ addClass(g, "nodeDisabled");
+ title = "DISABLED (" + nodeToUpdate.type + ")";
+ }
+ $(g).attr("title", title).tooltip('fixTitle');
+
+ if (node.nodes) {
+ this.updateStatusChanges(node, nodeToUpdate);
+ }
+ }
}
}
},