azkaban-uncached
Changes
src/web/css/azkaban-graph.css 49(+49 -0)
src/web/js/azkaban.context.menu.js 1(+1 -0)
src/web/js/azkaban.flow.extended.view.js 67(+67 -0)
src/web/js/azkaban.flow.view.js 79(+3 -76)
src/web/js/azkaban.svg.graph.helper.js 152(+152 -0)
src/web/js/azkaban.svg.graph.view.js 22(+17 -5)
Details
diff --git a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index ea5b901..4abde57 100644
--- a/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/src/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -64,6 +64,7 @@ import azkaban.user.User;
import azkaban.utils.JSONUtils;
import azkaban.utils.Pair;
import azkaban.utils.Props;
+import azkaban.utils.PropsUtils;
import azkaban.utils.Utils;
import azkaban.webapp.AzkabanWebServer;
import azkaban.webapp.session.Session;
@@ -204,6 +205,11 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
ajaxFetchFlowGraph(project, ret, req);
}
}
+ else if (ajaxName.equals("fetchflownodedata")) {
+ if (handleAjaxPermission(project, user, Type.READ, ret)) {
+ ajaxFetchFlowNodeData(project, ret, req);
+ }
+ }
else if (ajaxName.equals("fetchprojectflows")) {
if (handleAjaxPermission(project, user, Type.READ, ret)) {
ajaxFetchProjectFlows(project, ret, req);
@@ -413,7 +419,6 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
}
private void ajaxFetchJobInfo(Project project, HashMap<String, Object> ret, HttpServletRequest req) throws ServletException {
-
String flowName = getParam(req, "flowName");
String jobName = getParam(req, "jobName");
@@ -505,6 +510,11 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
private void ajaxFetchFlowGraph(Project project, HashMap<String, Object> ret, HttpServletRequest req) throws ServletException {
String flowId = getParam(req, "flow");
+
+ fillFlowInfo(project, flowId, ret);
+ }
+
+ private void fillFlowInfo(Project project, String flowId, HashMap<String, Object> ret) {
Flow flow = project.getFlow(flowId);
//Collections.sort(flowNodes, NODE_LEVEL_COMPARATOR);
@@ -539,6 +549,47 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
ret.put("edges", edgeList);
}
+ private void ajaxFetchFlowNodeData(Project project, HashMap<String, Object> ret, HttpServletRequest req) throws ServletException {
+ String flowId = getParam(req, "flow");
+ Flow flow = project.getFlow(flowId);
+
+ String nodeId = getParam(req, "node");
+ Node node = flow.getNode(nodeId);
+
+ if (node == null) {
+ ret.put("error", "Job " + nodeId + " doesn't exist.");
+ return;
+ }
+
+ ret.put("id", nodeId);
+ ret.put("flow", flowId);
+ ret.put("type", node.getType());
+
+ Props props;
+ try {
+ props = projectManager.getProperties(project, node.getJobSource());
+ } catch (ProjectManagerException e) {
+ ret.put("error", "Failed to upload job override property for " + nodeId);
+ return;
+ }
+
+ if (props == null) {
+ ret.put("error", "Properties for " + nodeId + " isn't found.");
+ return;
+ }
+
+ Map<String,String> properties = PropsUtils.toStringMap(props, true);
+ ret.put("props", properties);
+
+ if (node.getType().equals("flow")) {
+ if (node.getEmbeddedFlowId() != null) {
+ HashMap<String, Object> flowMap = new HashMap<String, Object>();
+ fillFlowInfo(project, node.getEmbeddedFlowId(), flowMap);
+ ret.put("flowData", flowMap);
+ }
+ }
+ }
+
private void ajaxFetchFlow(Project project, HashMap<String, Object> ret, HttpServletRequest req, HttpServletResponse resp) throws ServletException {
String flowId = getParam(req, "flow");
Flow flow = project.getFlow(flowId);
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm b/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm
index aab0e61..32619e0 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowexecutionpanel.vm
@@ -1,7 +1,6 @@
<script type="text/javascript" src="${context}/js/azkaban.layout.js"></script>
<script type="text/javascript" src="${context}/js/svgNavigate.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.context.menu.js"></script>
-<script type="text/javascript" src="${context}/js/azkaban.svg.graph.view.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.flow.execute.view.js"></script>
<link rel="stylesheet" type="text/css" href="${context}/css/azkaban-graph.css" />
@@ -147,6 +146,3 @@
#parse( "azkaban/webapp/servlet/velocity/schedulepanel.vm" )
#end
-<div id="contextMenu">
-
-</div>
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowextendedpanel.vm b/src/java/azkaban/webapp/servlet/velocity/flowextendedpanel.vm
new file mode 100644
index 0000000..557d09c
--- /dev/null
+++ b/src/java/azkaban/webapp/servlet/velocity/flowextendedpanel.vm
@@ -0,0 +1,22 @@
+<div id="flowInfoBase" class="flowExtendedView" style="display:none">
+ <div class="flowExtendedViewHeader">
+ <h3 class="flowInfoTitle"><span class="nodeId"></span><span class="nodeType"></span></h3>
+ <a title="Close" class="modal-close closeInfoPanel">x</a>
+ </div>
+ <div class="dataContent">
+ <div class="dataFlow">
+ </div>
+ <div class="dataJobProperties">
+ <table class="dataPropertiesTable">
+ <thead class="dataPropertiesHead">
+ <tr>
+ <th>Name</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody class="dataPropertiesBody">
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index 1bec383..82101cb 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -30,9 +30,13 @@
<script type="text/javascript" src="${context}/js/azkaban.ajax.utils.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.nav.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.layout.js"></script>
+ <script type="text/javascript" src="${context}/js/svgNavigate.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.svg.graph.helper.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.svg.graph.view.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.flow.extended.view.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.flow.job.view.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.flow.view.js"></script>
- <script type="text/javascript" src="${context}/js/svgNavigate.js"></script>
+
<script type="text/javascript">
var contextURL = "${context}";
var currentTime = ${currentTime};
@@ -147,6 +151,7 @@
#end
</div>
+ #parse( "azkaban/webapp/servlet/velocity/flowextendedpanel.vm" )
<div id="contextMenu">
</div>
#parse( "azkaban/webapp/servlet/velocity/messagedialog.vm" )
diff --git a/src/java/azkaban/webapp/servlet/velocity/projectpage.vm b/src/java/azkaban/webapp/servlet/velocity/projectpage.vm
index 6c82bfb..8a608f6 100644
--- a/src/java/azkaban/webapp/servlet/velocity/projectpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/projectpage.vm
@@ -180,6 +180,8 @@
</div>
</div>
#parse( "azkaban/webapp/servlet/velocity/flowexecutionpanel.vm" )
+ <div id="contextMenu">
+ </div>
#parse( "azkaban/webapp/servlet/velocity/messagedialog.vm" )
</body>
src/web/css/azkaban-graph.css 49(+49 -0)
diff --git a/src/web/css/azkaban-graph.css b/src/web/css/azkaban-graph.css
index c20e6d9..b5b6b57 100644
--- a/src/web/css/azkaban-graph.css
+++ b/src/web/css/azkaban-graph.css
@@ -196,3 +196,52 @@ svg circle.SKIPPED {
stroke-width: 2px;
fill: #FFF;
}
+
+.flowExtendedView {
+ position: absolute;
+ background-color: rgba(255, 255, 255, 0.95);
+ -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
+ -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
+ box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
+
+ min-width: 200px;
+ min-height: 150px;
+}
+
+.dataJobProperties {
+
+}
+
+.flowInfoTitle {
+ padding-top: 8px;
+ padding-left: 8px;
+ padding-bottom: 5px;
+ cursor: pointer;
+}
+
+.flowInfoTitle:hover {
+ background-color: #CCC;
+}
+
+.nodeId {
+ font-size: 16px;
+ font-weight: bold;
+ margin: 20px 20px;
+}
+
+.nodeType {
+ font-style: italic;
+}
+
+.dataContent {
+ margin: 5px;
+}
+
+.dataFlow {
+ width: 100%;
+}
+
+.svgTiny {
+ width: 100%;
+ height: 100%;
+}
\ No newline at end of file
src/web/js/azkaban.context.menu.js 1(+1 -0)
diff --git a/src/web/js/azkaban.context.menu.js b/src/web/js/azkaban.context.menu.js
index 9bf1ef0..7bca798 100644
--- a/src/web/js/azkaban.context.menu.js
+++ b/src/web/js/azkaban.context.menu.js
@@ -18,6 +18,7 @@ azkaban.ContextMenuView = Backbone.View.extend({
var contextMenu = this.setupMenu(menu);
$(contextMenu).css({top: y, left: x});
+
$(this.el).after(contextMenu);
},
hide : function(evt) {
diff --git a/src/web/js/azkaban.flow.execute.view.js b/src/web/js/azkaban.flow.execute.view.js
index 90319c6..c4de9f4 100644
--- a/src/web/js/azkaban.flow.execute.view.js
+++ b/src/web/js/azkaban.flow.execute.view.js
@@ -525,7 +525,7 @@ var touchDescendents = function(jobid, disable) {
executableGraphModel.trigger("change:disabled");
}
-var nodeClickCallback = function(event) {
+var exNodeClickCallback = function(event) {
console.log("Node clicked callback");
var jobId = event.currentTarget.jobid;
var flowId = executableGraphModel.get("flowId");
@@ -556,11 +556,11 @@ var nodeClickCallback = function(event) {
contextMenuView.show(event, menu);
}
-var edgeClickCallback = function(event) {
+var exEdgeClickCallback = function(event) {
console.log("Edge clicked callback");
}
-var graphClickCallback = function(event) {
+var exGraphClickCallback = function(event) {
console.log("Graph clicked callback");
var flowId = executableGraphModel.get("flowId");
var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId;
@@ -580,7 +580,7 @@ var contextMenuView;
$(function() {
executableGraphModel = new azkaban.GraphModel();
flowExecuteDialogView = new azkaban.FlowExecuteDialogView({el:$('#execute-flow-panel'), model: executableGraphModel});
- svgGraphView = new azkaban.SvgGraphView({el:$('#svgDivCustom'), model: executableGraphModel, topGId:"topG", graphMargin: 10, rightClick: { "node": nodeClickCallback, "edge": edgeClickCallback, "graph": graphClickCallback }});
+ svgGraphView = new azkaban.SvgGraphView({el:$('#svgDivCustom'), model: executableGraphModel, topGId:"topG", graphMargin: 10, rightClick: { "node": exNodeClickCallback, "edge": exEdgeClickCallback, "graph": exGraphClickCallback }});
sideMenuDialogView = new azkaban.SideMenuDialogView({el:$('#graphOptions')});
editTableView = new azkaban.EditTableView({el:$('#editTable')});
src/web/js/azkaban.flow.extended.view.js 67(+67 -0)
diff --git a/src/web/js/azkaban.flow.extended.view.js b/src/web/js/azkaban.flow.extended.view.js
new file mode 100644
index 0000000..21985b3
--- /dev/null
+++ b/src/web/js/azkaban.flow.extended.view.js
@@ -0,0 +1,67 @@
+azkaban.FlowExtendedViewPanel = Backbone.View.extend({
+ events: {
+ "click .closeInfoPanel" : "handleClosePanel"
+ },
+ initialize: function(settings) {
+ //this.model.bind('change:flowinfo', this.changeFlowInfo, this);
+ $(this.el).show();
+ $(this.el).draggable({cancel: ".dataContent", containment: "document"});
+
+ this.extendedViewPanels = {};
+ this.extendedDataModels = {};
+ this.render();
+ $(this.el).hide();
+ },
+ showExtendedView: function(evt) {
+ var event = evt;
+
+ $(this.el).css({top: evt.pageY, left: evt.pageX});
+ $(this.el).show();
+ },
+ render: function(self) {
+ console.log("Changing title");
+ $(this.el).find(".nodeId").text(this.model.get("id"));
+ $(this.el).find(".nodeType").text(this.model.get("type"));
+
+ var props = this.model.get("props");
+ var tableBody = $(this.el).find(".dataPropertiesBody");
+
+ for (var key in props) {
+ var tr = document.createElement("tr");
+ var tdKey = document.createElement("td");
+ var tdValue = document.createElement("td");
+
+ $(tdKey).text(key);
+ $(tdValue).text(props[key]);
+
+ $(tr).append(tdKey);
+ $(tr).append(tdValue);
+
+ $(tableBody).append(tr);
+
+ var propsTable = $(this.el).find(".dataJobProperties");
+ $(propsTable).resizable({handler: "s"});
+ }
+
+ if (this.model.get("type") == "flow") {
+ var svgns = "http://www.w3.org/2000/svg";
+ var svgDataFlow = $(this.el).find(".dataFlow");
+
+ var svgGraph = document.createElementNS(svgns, "svg");
+ $(svgGraph).attr("class", "svgTiny");
+ $(svgDataFlow).append(svgGraph);
+ $(svgDataFlow).resizable();
+
+ this.innerGraphModel = new azkaban.GraphModel();
+ this.innerGraphModel.set({"data": this.model.get("flow")});
+
+ this.graphView = new azkaban.SvgGraphView({el: svgDataFlow, model: this.innerGraphModel, render: true, rightClick: { "node": nodeClickCallback, "graph": graphClickCallback }})
+ }
+ else {
+ $(this.el).find(".dataFlow").hide();
+ }
+ },
+ handleClosePanel: function(self) {
+ $(this.el).hide();
+ }
+});
\ No newline at end of file
src/web/js/azkaban.flow.view.js 79(+3 -76)
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index 46a336f..73945f0 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -275,54 +275,6 @@ azkaban.ExecutionsView = Backbone.View.extend({
}
});
-var exNodeClickCallback = function(event) {
- console.log("Node clicked callback");
- var jobId = event.currentTarget.jobid;
- var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId + "&job=" + jobId;
-
- var menu = [
- {title: "Open Job...", callback: function() {window.location.href=requestURL;}},
- {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
- {break: 1},
- {title: "Center Job", callback: function() {graphModel.trigger("centerNode", jobId)}}
- ];
-
- contextMenuView.show(event, menu);
-}
-
-var exJobClickCallback = function(event) {
- console.log("Node clicked callback");
- var jobId = event.currentTarget.jobid;
- var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId + "&job=" + jobId;
-
- var menu = [
- {title: "Open Job...", callback: function() {window.location.href=requestURL;}},
- {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
- {break: 1},
- {title: "Center Job", callback: function() {graphModel.trigger("centerNode", jobId)}}
- ];
-
- contextMenuView.show(event, menu);
-}
-
-var exEdgeClickCallback = function(event) {
- console.log("Edge clicked callback");
-}
-
-var exGraphClickCallback = function(event) {
- console.log("Graph clicked callback");
- var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId;
-
- var menu = [
- {title: "Open Flow...", callback: function() {window.location.href=requestURL;}},
- {title: "Open Flow in New Window...", callback: function() {window.open(requestURL);}},
- {break: 1},
- {title: "Center Graph", callback: function() {graphModel.trigger("resetPanZoom");}}
- ];
-
- contextMenuView.show(event, menu);
-}
-
var graphModel;
azkaban.GraphModel = Backbone.Model.extend({});
@@ -339,8 +291,8 @@ $(function() {
flowTabView = new azkaban.FlowTabView({el:$( '#headertabs'), selectedView: selected });
graphModel = new azkaban.GraphModel();
- mainSvgGraphView = new azkaban.SvgGraphView({el:$('#svgDiv'), model: graphModel, rightClick: { "node": exNodeClickCallback, "edge": exEdgeClickCallback, "graph": exGraphClickCallback }});
- jobsListView = new azkaban.JobListView({el:$('#jobList'), model: graphModel, contextMenuCallback: exJobClickCallback});
+ mainSvgGraphView = new azkaban.SvgGraphView({el:$('#svgDiv'), model: graphModel, rightClick: { "node": nodeClickCallback, "edge": edgeClickCallback, "graph": graphClickCallback }});
+ jobsListView = new azkaban.JobListView({el:$('#jobList'), model: graphModel, contextMenuCallback: jobClickCallback});
var requestURL = contextURL + "/manager";
@@ -362,32 +314,7 @@ $(function() {
requestURL,
{"project": projectName, "ajax":"fetchflowgraph", "flow":flowId},
function(data) {
- // Create the nodes
- var nodes = {};
- for (var i=0; i < data.nodes.length; ++i) {
- var node = data.nodes[i];
- nodes[node.id] = node;
- }
- for (var i=0; i < data.edges.length; ++i) {
- var edge = data.edges[i];
- var fromNode = nodes[edge.from];
- var toNode = nodes[edge.target];
-
- if (!fromNode.outNodes) {
- fromNode.outNodes = {};
- }
- fromNode.outNodes[toNode.id] = toNode;
-
- if (!toNode.inNodes) {
- toNode.inNodes = {};
- }
- toNode.inNodes[fromNode.id] = fromNode;
- }
-
- console.log("data fetched");
- graphModel.set({data: data});
- graphModel.set({nodes: nodes});
- graphModel.set({disabled: {}});
+ createModelFromAjaxCall(data, graphModel);
graphModel.trigger("change:graph");
// Handle the hash changes here so the graph finishes rendering first.
src/web/js/azkaban.svg.graph.helper.js 152(+152 -0)
diff --git a/src/web/js/azkaban.svg.graph.helper.js b/src/web/js/azkaban.svg.graph.helper.js
new file mode 100644
index 0000000..67ee1f7
--- /dev/null
+++ b/src/web/js/azkaban.svg.graph.helper.js
@@ -0,0 +1,152 @@
+var extendedViewPanels = {};
+var extendedDataModels = {};
+var openJobDisplayCallback = function(nodeId, flowId, evt) {
+ console.log("Open up data");
+
+ var nodeInfoPanelID = flowId + ":" + nodeId + "-info";
+ if ($("#" + nodeInfoPanelID).length) {
+ $("#flowInfoBase").before(cloneStuff);
+ extendedViewPanels[nodeInfoPanelID].showExtendedView(evt);
+ return;
+ }
+
+ var cloneStuff = $("#flowInfoBase").clone();
+ $(cloneStuff).attr("id", nodeInfoPanelID);
+
+ $("#flowInfoBase").before(cloneStuff);
+ var requestURL = contextURL + "/manager";
+
+ $.get(
+ requestURL,
+ {"project": projectName, "ajax":"fetchflownodedata", "flow":flowId, "node": nodeId},
+ function(data) {
+ var graphModel = new azkaban.GraphModel();
+ graphModel.set({id: data.id, flow: data.flowData, type: data.type, props: data.props});
+
+ var flowData = data.flowData;
+ if (flowData) {
+ createModelFromAjaxCall(flowData, graphModel);
+ }
+
+ var backboneView = new azkaban.FlowExtendedViewPanel({el:cloneStuff, model: graphModel});
+ extendedViewPanels[nodeInfoPanelID] = backboneView;
+ extendedDataModels[nodeInfoPanelID] = graphModel;
+ backboneView.showExtendedView(evt);
+ },
+ "json"
+ );
+}
+
+var createModelFromAjaxCall = function(data, model) {
+ var nodes = {};
+ for (var i=0; i < data.nodes.length; ++i) {
+ var node = data.nodes[i];
+ nodes[node.id] = node;
+ }
+ for (var i=0; i < data.edges.length; ++i) {
+ var edge = data.edges[i];
+ var fromNode = nodes[edge.from];
+ var toNode = nodes[edge.target];
+
+ if (!fromNode.outNodes) {
+ fromNode.outNodes = {};
+ }
+ fromNode.outNodes[toNode.id] = toNode;
+
+ if (!toNode.inNodes) {
+ toNode.inNodes = {};
+ }
+ toNode.inNodes[fromNode.id] = fromNode;
+ }
+
+ console.log("data fetched");
+ model.set({data: data});
+ model.set({nodes: nodes});
+ model.set({disabled: {}});
+}
+
+var nodeClickCallback = function(event, model, type) {
+ console.log("Node clicked callback");
+ var jobId = event.currentTarget.jobid;
+ var flowId = model.get("flowId");
+ var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId + "&job=" + jobId;
+
+ if (event.currentTarget.jobtype == "flow") {
+ var flowRequestURL = contextURL + "/manager?project=" + projectName + "&flow=" + event.currentTarget.flowId;
+ menu = [
+ {title: "View Flow...", callback: function() {openJobDisplayCallback(jobId, flowId, event)}},
+ {break: 1},
+ {title: "Open Flow...", callback: function() {window.location.href=flowRequestURL;}},
+ {title: "Open Flow in New Window...", callback: function() {window.open(flowRequestURL);}},
+ {break: 1},
+ {title: "Open Properties...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Properties in New Window...", callback: function() {window.open(requestURL);}},
+ {break: 1},
+ {title: "Center Flow", callback: function() {model.trigger("centerNode", jobId)}}
+ ];
+ }
+ else {
+ menu = [
+ {title: "View Job...", callback: function() {openJobDisplayCallback(jobId, flowId, event)}},
+ {break: 1},
+ {title: "Open Job...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
+ {break: 1},
+ {title: "Center Job", callback: function() {model.trigger("centerNode", jobId)}}
+ ];
+ }
+ contextMenuView.show(event, menu);
+}
+
+var jobClickCallback = function(event, model) {
+ console.log("Node clicked callback");
+ var jobId = event.currentTarget.jobid;
+ var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId + "&job=" + jobId;
+
+ var menu;
+ if (event.currentTarget.jobtype == "flow") {
+ var flowRequestURL = contextURL + "/manager?project=" + projectName + "&flow=" + event.currentTarget.flowId;
+ menu = [
+ {title: "View Flow...", callback: function() {openJobDisplayCallback(jobId, flowId, event)}},
+ {break: 1},
+ {title: "Open Flow...", callback: function() {window.location.href=flowRequestURL;}},
+ {title: "Open Flow in New Window...", callback: function() {window.open(flowRequestURL);}},
+ {break: 1},
+ {title: "Open Properties...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Properties in New Window...", callback: function() {window.open(requestURL);}},
+ {break: 1},
+ {title: "Center Flow", callback: function() {model.trigger("centerNode", jobId)}}
+ ];
+ }
+ else {
+ menu = [
+ {title: "View Job...", callback: function() {openJobDisplayCallback(jobId, flowId, event)}},
+ {break: 1},
+ {title: "Open Job...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
+ {break: 1},
+ {title: "Center Job", callback: function() {graphModel.trigger("centerNode", jobId)}}
+ ];
+ }
+ contextMenuView.show(event, menu);
+}
+
+var edgeClickCallback = function(event, model) {
+ console.log("Edge clicked callback");
+}
+
+var graphClickCallback = function(event, model) {
+ console.log("Graph clicked callback");
+ var jobId = event.currentTarget.jobid;
+ var flowId = model.get("flowId");
+ var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowId;
+
+ var menu = [
+ {title: "Open Flow...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Flow in New Window...", callback: function() {window.open(requestURL);}},
+ {break: 1},
+ {title: "Center Graph", callback: function() {model.trigger("resetPanZoom");}}
+ ];
+
+ contextMenuView.show(event, menu);
+}
src/web/js/azkaban.svg.graph.view.js 22(+17 -5)
diff --git a/src/web/js/azkaban.svg.graph.view.js b/src/web/js/azkaban.svg.graph.view.js
index 3703e27..1e0f443 100644
--- a/src/web/js/azkaban.svg.graph.view.js
+++ b/src/web/js/azkaban.svg.graph.view.js
@@ -57,6 +57,10 @@ azkaban.SvgGraphView = Backbone.View.extend({
}
$(svg).svgNavigate();
+
+ if (settings.render) {
+ this.render();
+ }
},
initializeDefs: function(self) {
var def = document.createElementNS(svgns, 'defs');
@@ -133,7 +137,7 @@ azkaban.SvgGraphView = Backbone.View.extend({
this.drawEdge(this, edges[i]);
}
- this.model.set({"nodes": this.nodes, "edges": edges});
+ this.model.set({"flowId":data.flowId, "nodes": this.nodes, "edges": edges});
var margin = this.graphMargin;
bounds.minX = bounds.minX ? bounds.minX - margin : -margin;
@@ -142,7 +146,13 @@ azkaban.SvgGraphView = Backbone.View.extend({
bounds.maxY = bounds.maxY ? bounds.maxY + margin : margin;
this.assignInitialStatus(self);
- this.handleDisabledChange(self);
+
+ if (this.model.get("disabled")) {
+ this.handleDisabledChange(self);
+ }
+ else {
+ this.model.set({"disabled":[]})
+ }
this.graphBounds = bounds;
this.resetPanZoom(0);
},
@@ -232,13 +242,13 @@ azkaban.SvgGraphView = Backbone.View.extend({
var callbacks = this.rightClick;
var currentTarget = self.currentTarget;
if (callbacks.node && currentTarget.jobid) {
- callbacks.node(self);
+ callbacks.node(self, this.model);
}
else if (callbacks.edge && (currentTarget.nodeName == "polyline" || currentTarget.nodeName == "line")) {
- callbacks.edge(self);
+ callbacks.edge(self, this.model);
}
else if (callbacks.graph) {
- callbacks.graph(self);
+ callbacks.graph(self, this.model);
}
return false;
}
@@ -350,6 +360,8 @@ azkaban.SvgGraphView = Backbone.View.extend({
innerG.appendChild(flowIdText);
innerG.appendChild(iconNode);
innerG.jobid = node.id;
+ innerG.jobtype = "flow";
+ innerG.flowId = node.flowId;
nodeG.appendChild(innerG);
self.mainG.appendChild(nodeG);