azkaban-aplcache

New 'expand/collapse all flows' menu options on flow views

11/13/2018 3:52:43 PM

Details

diff --git a/azkaban-web-server/src/web/js/azkaban/util/flow-loader.js b/azkaban-web-server/src/web/js/azkaban/util/flow-loader.js
index b260fca..9a128bc 100644
--- a/azkaban-web-server/src/web/js/azkaban/util/flow-loader.js
+++ b/azkaban-web-server/src/web/js/azkaban/util/flow-loader.js
@@ -81,18 +81,34 @@ var nodeClickCallback = function (event, model, node) {
     var flowRequestURL = contextURL + "/manager?project=" + projectName
         + "&flow=" + node.flowId;
     if (node.expanded) {
-      menu = [{
-        title: "Collapse Flow...", callback: function () {
-          model.trigger("collapseFlow", node);
+      menu = [
+        {
+          title: "Collapse Flow...", callback: function () {
+            model.trigger("collapseFlow", node);
+          }
+        },
+        {
+          title: "Collapse All Flows...", callback: function () {
+            model.trigger("collapseAllFlows", node);
+            model.trigger("resetPanZoom");
+          }
         }
-      }];
+      ];
     }
     else {
-      menu = [{
-        title: "Expand Flow...", callback: function () {
-          model.trigger("expandFlow", node);
+      menu = [
+        {
+          title: "Expand Flow...", callback: function () {
+            model.trigger("expandFlow", node);
+          }
+        },
+        {
+          title: "Expand All Flows...", callback: function () {
+            model.trigger("expandAllFlows", node);
+            model.trigger("resetPanZoom");
+          }
         }
-      }];
+      ];
     }
 
     $.merge(menu, [
@@ -100,30 +116,30 @@ var nodeClickCallback = function (event, model, node) {
       {break: 1},
       {
         title: "Open Flow...", callback: function () {
-        window.location.href = flowRequestURL;
-      }
+          window.location.href = flowRequestURL;
+        }
       },
       {
         title: "Open Flow in New Window...", callback: function () {
-        window.open(flowRequestURL);
-      }
+          window.open(flowRequestURL);
+        }
       },
       {break: 1},
       {
         title: "Open Properties...", callback: function () {
-        window.location.href = requestURL;
-      }
+          window.location.href = requestURL;
+        }
       },
       {
         title: "Open Properties in New Window...", callback: function () {
-        window.open(requestURL);
-      }
+          window.open(requestURL);
+        }
       },
       {break: 1},
       {
         title: "Center Flow", callback: function () {
-        model.trigger("centerNode", node);
-      }
+          model.trigger("centerNode", node);
+        }
       }
     ]);
   }
@@ -133,19 +149,19 @@ var nodeClickCallback = function (event, model, node) {
       //  {break: 1},
       {
         title: "Open Job...", callback: function () {
-        window.location.href = requestURL;
-      }
+          window.location.href = requestURL;
+        }
       },
       {
         title: "Open Job in New Window...", callback: function () {
-        window.open(requestURL);
-      }
+          window.open(requestURL);
+        }
       },
       {break: 1},
       {
         title: "Center Job", callback: function () {
-        model.trigger("centerNode", node)
-      }
+          model.trigger("centerNode", node)
+        }
       }
     ];
   }
@@ -171,30 +187,30 @@ var jobClickCallback = function (event, model, node) {
       //  {break: 1},
       {
         title: "Open Flow...", callback: function () {
-        window.location.href = flowRequestURL;
-      }
+          window.location.href = flowRequestURL;
+        }
       },
       {
         title: "Open Flow in New Window...", callback: function () {
-        window.open(flowRequestURL);
-      }
+          window.open(flowRequestURL);
+        }
       },
       {break: 1},
       {
         title: "Open Properties...", callback: function () {
-        window.location.href = requestURL;
-      }
+          window.location.href = requestURL;
+        }
       },
       {
         title: "Open Properties in New Window...", callback: function () {
-        window.open(requestURL);
-      }
+          window.open(requestURL);
+        }
       },
       {break: 1},
       {
         title: "Center Flow", callback: function () {
-        model.trigger("centerNode", node)
-      }
+          model.trigger("centerNode", node)
+        }
       }
     ];
   }
@@ -204,19 +220,19 @@ var jobClickCallback = function (event, model, node) {
       //  {break: 1},
       {
         title: "Open Job...", callback: function () {
-        window.location.href = requestURL;
-      }
+          window.location.href = requestURL;
+        }
       },
       {
         title: "Open Job in New Window...", callback: function () {
-        window.open(requestURL);
-      }
+          window.open(requestURL);
+        }
       },
       {break: 1},
       {
         title: "Center Job", callback: function () {
-        graphModel.trigger("centerNode", node)
-      }
+          graphModel.trigger("centerNode", node)
+        }
       }
     ];
   }
@@ -236,20 +252,33 @@ var graphClickCallback = function (event, model) {
 
   var menu = [
     {
+      title: "Expand All Flows...", callback: function () {
+        model.trigger("expandAllFlows");
+        model.trigger("resetPanZoom");
+      }
+    },
+    {
+      title: "Collapse All Flows...", callback: function () {
+        model.trigger("collapseAllFlows");
+        model.trigger("resetPanZoom");
+      }
+    },
+    {break: 1},
+    {
       title: "Open Flow...", callback: function () {
-      window.location.href = requestURL;
-    }
+        window.location.href = requestURL;
+      }
     },
     {
       title: "Open Flow in New Window...", callback: function () {
-      window.open(requestURL);
-    }
+        window.open(requestURL);
+      }
     },
     {break: 1},
     {
       title: "Center Graph", callback: function () {
-      model.trigger("resetPanZoom");
-    }
+        model.trigger("resetPanZoom");
+      }
     }
   ];
 
diff --git a/azkaban-web-server/src/web/js/azkaban/view/flow-execute-dialog.js b/azkaban-web-server/src/web/js/azkaban/view/flow-execute-dialog.js
index 1175ee5..31dd5df 100644
--- a/azkaban-web-server/src/web/js/azkaban/view/flow-execute-dialog.js
+++ b/azkaban-web-server/src/web/js/azkaban/view/flow-execute-dialog.js
@@ -374,8 +374,9 @@ azkaban.EditTableView = Backbone.View.extend({
   },
 
   handleEditColumn: function (evt) {
-    if (evt.target.tagName == "INPUT")
+    if (evt.target.tagName == "INPUT") {
       return;
+    }
     var curTarget = evt.currentTarget;
 
     var text = $(curTarget).children(".spanValue").text();
@@ -636,13 +637,19 @@ var expanelNodeClickCallback = function (event, model, node) {
       menu = [
         {
           title: "Collapse Flow...", callback: function () {
-          model.trigger("collapseFlow", node);
-        }
+            model.trigger("collapseFlow", node);
+          }
+        },
+        {
+          title: "Collapse All Flows...", callback: function () {
+            model.trigger("collapseAllFlows", node);
+            model.trigger("resetPanZoom");
+          }
         },
         {
           title: "Open Flow in New Window...", callback: function () {
-          window.open(flowRequestURL);
-        }
+            window.open(flowRequestURL);
+          }
         }
       ];
 
@@ -651,13 +658,19 @@ var expanelNodeClickCallback = function (event, model, node) {
       menu = [
         {
           title: "Expand Flow...", callback: function () {
-          model.trigger("expandFlow", node);
-        }
+            model.trigger("expandFlow", node);
+          }
+        },
+        {
+          title: "Expand All Flows...", callback: function () {
+            model.trigger("expandAllFlows", node);
+            model.trigger("resetPanZoom");
+          }
         },
         {
           title: "Open Flow in New Window...", callback: function () {
-          window.open(flowRequestURL);
-        }
+            window.open(flowRequestURL);
+          }
         }
       ];
     }
@@ -668,8 +681,8 @@ var expanelNodeClickCallback = function (event, model, node) {
     menu = [
       {
         title: "Open Job in New Window...", callback: function () {
-        window.open(requestURL);
-      }
+          window.open(requestURL);
+        }
       },
     ];
   }
@@ -678,70 +691,70 @@ var expanelNodeClickCallback = function (event, model, node) {
     {break: 1},
     {
       title: "Enable", callback: function () {
-      touchNode(node, false);
-    }, submenu: [
-      {
-        title: "Parents", callback: function () {
-        touchParents(node, false);
-      }
-      },
-      {
-        title: "Ancestors", callback: function () {
-        touchAncestors(node, false);
-      }
-      },
-      {
-        title: "Children", callback: function () {
-        touchChildren(node, false);
-      }
-      },
-      {
-        title: "Descendents", callback: function () {
-        touchDescendents(node, false);
-      }
-      },
-      {
-        title: "Enable All", callback: function () {
-        enableAll();
-      }
-      }
-    ]
+        touchNode(node, false);
+      }, submenu: [
+        {
+          title: "Parents", callback: function () {
+            touchParents(node, false);
+          }
+        },
+        {
+          title: "Ancestors", callback: function () {
+            touchAncestors(node, false);
+          }
+        },
+        {
+          title: "Children", callback: function () {
+            touchChildren(node, false);
+          }
+        },
+        {
+          title: "Descendents", callback: function () {
+            touchDescendents(node, false);
+          }
+        },
+        {
+          title: "Enable All", callback: function () {
+            enableAll();
+          }
+        }
+      ]
     },
     {
       title: "Disable", callback: function () {
-      touchNode(node, true)
-    }, submenu: [
-      {
-        title: "Parents", callback: function () {
-        touchParents(node, true);
-      }
-      },
-      {
-        title: "Ancestors", callback: function () {
-        touchAncestors(node, true);
-      }
-      },
-      {
-        title: "Children", callback: function () {
-        touchChildren(node, true);
-      }
-      },
-      {
-        title: "Descendents", callback: function () {
-        touchDescendents(node, true);
-      }
-      },
-      {
-        title: "Disable All", callback: function () {
-        disableAll();
-      }
-      }
-    ]
+        touchNode(node, true)
+      }, submenu: [
+        {
+          title: "Parents", callback: function () {
+            touchParents(node, true);
+          }
+        },
+        {
+          title: "Ancestors", callback: function () {
+            touchAncestors(node, true);
+          }
+        },
+        {
+          title: "Children", callback: function () {
+            touchChildren(node, true);
+          }
+        },
+        {
+          title: "Descendents", callback: function () {
+            touchDescendents(node, true);
+          }
+        },
+        {
+          title: "Disable All", callback: function () {
+            disableAll();
+          }
+        }
+      ]
     },
     {
       title: "Center Job", callback: function () {
-      model.trigger("centerNode", node);
-    }
+        model.trigger("centerNode", node);
+      }
     }
   ]);
 
@@ -760,26 +773,38 @@ var expanelGraphClickCallback = function (event) {
 
   var menu = [
     {
+      title: "Expand All Flows...", callback: function () {
+        executableGraphModel.trigger("expandAllFlows");
+        executableGraphModel.trigger("resetPanZoom");
+      }
+    },
+    {
+      title: "Collapse All Flows...", callback: function () {
+        executableGraphModel.trigger("collapseAllFlows");
+        executableGraphModel.trigger("resetPanZoom");
+      }
+    },
+    {
       title: "Open Flow in New Window...", callback: function () {
-      window.open(requestURL);
-    }
+        window.open(requestURL);
+      }
     },
     {break: 1},
     {
       title: "Enable All", callback: function () {
-      enableAll();
-    }
+        enableAll();
+      }
     },
     {
       title: "Disable All", callback: function () {
-      disableAll();
-    }
+        disableAll();
+      }
     },
     {break: 1},
     {
       title: "Center Graph", callback: function () {
-      executableGraphModel.trigger("resetPanZoom");
-    }
+        executableGraphModel.trigger("resetPanZoom");
+      }
     }
   ];
 
diff --git a/azkaban-web-server/src/web/js/azkaban/view/svg-graph.js b/azkaban-web-server/src/web/js/azkaban/view/svg-graph.js
index 12d7c50..250b134 100644
--- a/azkaban-web-server/src/web/js/azkaban/view/svg-graph.js
+++ b/azkaban-web-server/src/web/js/azkaban/view/svg-graph.js
@@ -33,6 +33,8 @@ azkaban.SvgGraphView = Backbone.View.extend({
     this.model.bind('change:updateAll', this.handleUpdateAllStatus, this);
     this.model.bind('expandFlow', this.expandFlow, this);
     this.model.bind('collapseFlow', this.collapseFlow, this);
+    this.model.bind('expandAllFlows', this.expandAllFlows, this);
+    this.model.bind('collapseAllFlows', this.collapseAllFlows, this);
 
     this.graphMargin = settings.graphMargin ? settings.graphMargin : 25;
     this.svgns = "http://www.w3.org/2000/svg";
@@ -81,7 +83,6 @@ azkaban.SvgGraphView = Backbone.View.extend({
   },
 
   render: function () {
-    console.log("graph render");
     $(this.mainG).empty();
 
     this.graphBounds = this.renderGraph(this.model.get("data"), this.mainG);
@@ -439,6 +440,46 @@ azkaban.SvgGraphView = Backbone.View.extend({
     this.graphBounds = bounds;
   },
 
+  expandAllFlows: function (node) {
+    if (node) {
+      // expands all embedded flows inside given node
+      if (node.type == 'flow') {
+        this.expandFlow(node);
+
+        for (var i = 0; i < node.nodes.length; ++i) {
+          this.expandAllFlows(node.nodes[i]);
+        }
+      }
+    } else {
+      // expands all embedded flows in the graph
+      var nodes = this.model.get("data").nodes;
+      for (var i = 0; i < nodes.length; ++i) {
+        this.expandAllFlows(nodes[i]);
+      }
+    }
+  },
+
+  collapseAllFlows: function (node) {
+    if (node) {
+      // collapse all embedded flows inside given node
+
+      // collapse already rendered nodes of type flow
+      if (node.type == 'flow' && node.gNode) {
+        this.collapseFlow(node);
+
+        for (var i = 0; i < node.nodes.length; ++i) {
+          this.collapseAllFlows(node.nodes[i]);
+        }
+      }
+    } else {
+      // collapse all embedded flows in the graph
+      var nodes = this.model.get("data").nodes;
+      for (var i = 0; i < nodes.length; ++i) {
+        this.collapseAllFlows(nodes[i]);
+      }
+    }
+  },
+
   relayoutFlow: function (node) {
     if (node.expanded) {
       this.layoutExpandedFlowNode(node);