瀏覽代碼

HUE-1330 [oozie] Make kill action target configurable

- Appending a node triggered computed to update. Moved cleanNode statement higher.
- Used wrong methods for adding kill node.
- Added a couple of js tests.
- Made detach API aware of errors.
Abraham Elmahrek 12 年之前
父節點
當前提交
4820ab3

+ 9 - 78
apps/oozie/src/oozie/templates/editor/edit_workflow.mako

@@ -611,76 +611,6 @@ import_workflow_action.fetchWorkflows({ success: import_workflow_load_success })
 /**
  * Modals
  */
-// open a modal window for editing a node
-function edit_node_modal(node, save, cancel, template) {
-  var backup = ko.mapping.toJS(node);
-  normalize_model_fields(backup);
-
-  modal.hide();
-  modal.setTemplate(template || node.edit_template);
-  // Provide node, readonly mode, and error link updater.
-  // Kill node is manually added to list of nodes that users can select from.
-  // Kill node is placed at the front of the list so that it is automatically selected.
-  var context = {
-    node: node,
-    read_only: workflow.read_only(),
-    nodes: ko.computed({
-      read: function() {
-        var arr = ko.utils.arrayFilter(workflow.nodes(), function(value) {
-          return value.id() && value.id() != node.id();
-        });
-        arr.unshift(workflow.kill);
-        return arr;
-      }
-    }),
-    error_node: ko.computed({
-      read: function() {
-        var error_child  = node.getErrorChild();
-        return (error_child) ? error_child.id() : null;
-      },
-      write: function(node_id) {
-        var error_child = workflow.registry.get(node_id);
-        if (error_child) {
-          node.putErrorChild(error_child);
-        }
-      }
-    })
-  };
-  modal.show(context);
-  modal.recenter(280, 250);
-  modal.addDecorations();
-
-  var cancel_edit = cancel || function() {
-    ko.mapping.fromJS(backup, node);
-    modal.hide();
-
-    // Prevent event propagation
-    return false;
-  };
-
-  var try_save = save || function() {
-    if (node.validate()) {
-      workflow.is_dirty( true );
-      modal.hide();
-    }
-  };
-
-  $('.modal-backdrop').on('click', cancel_edit);
-  modal.el.on('click', '.close', cancel_edit);
-  modal.el.on('click', '.cancelButton', cancel_edit);
-  modal.el.on('click', '.doneButton', try_save);
-
-  modal.el.on('click', '.edit-node-link', function() {
-    var link = ko.contextFor(this).$data;
-    var parent = ko.contextFor(this).$parent;
-    var node = parent.registry.get(link.child());
-
-    cancel_edit();
-
-    edit_node_modal(node);
-  });
-}
-
 // Drag a new node onto the canvas
 workflow.el.on('mousedown', '.new-node-link', function(e) {
   e.preventDefault();
@@ -722,9 +652,8 @@ workflow.el.on('mousedown', '.new-node-link', function(e) {
       workflow.is_dirty( true );
       modal.hide();
       if (!node.getErrorChild()) {
-        node.addChild(workflow.kill);
+        node.putErrorChild(workflow.kill);
       }
-      ko.cleanNode(modal.el[0]);
       workflow.el.trigger('workflow:rebuild');
     }
   };
@@ -734,7 +663,7 @@ workflow.el.on('mousedown', '.new-node-link', function(e) {
     workflow.new_node(null);
     el.offset(old_position);
     if (node.findChildren().length > 0 || node.findParents().length > 1) {
-      edit_node_modal(node, try_save, cancel_edit);
+      edit_node_modal(modal, workflow, node, try_save, cancel_edit);
     } else {
       node.erase();
     }
@@ -744,13 +673,13 @@ workflow.el.on('mousedown', '.new-node-link', function(e) {
 // Modal for editing a node
 workflow.el.on('click', '.edit-node-link', function(e) {
   var node = ko.contextFor(this).$data;
-  edit_node_modal(node);
+  edit_node_modal(modal, workflow, node);
 });
 
 // Modal for converting to a decision node
 workflow.el.on('click', '.convert-node-link', function(e) {
   var node = ko.contextFor(this).$data;
-  edit_node_modal(node, null, null, 'forkConvertTemplate');
+  edit_node_modal(modal, workflow, node, null, null, 'forkConvertTemplate');
 });
 
 // Modal for cloning a node
@@ -761,6 +690,7 @@ workflow.el.on('click', '.clone-node-btn', function(e) {
   model.name += '-copy';
   model.child_links = [];
   var new_node = new Node(workflow, model, workflow.registry);
+  new_node.child_links.removeAll();
   workflow.registry.add(new_node.id(), new_node);
 
   var cancel_edit = function(e) {
@@ -773,14 +703,15 @@ workflow.el.on('click', '.clone-node-btn', function(e) {
     if (node.validate()) {
       workflow.is_dirty( true );
       modal.hide();
-      // save, add kill, add node to workflow.
-      new_node.addChild(workflow.kill);
       node.append(new_node);
+      if (!new_node.getErrorChild()) {
+        new_node.putErrorChild(workflow.kill);
+      }
       workflow.el.trigger('workflow:rebuild');
     }
   };
 
-  edit_node_modal(new_node, try_save, cancel_edit);
+  edit_node_modal(modal, workflow, new_node, try_save, cancel_edit);
 });
 
 // Modal for deleting a node

+ 6 - 0
apps/oozie/src/oozie/templates/editor/jasmine.mako

@@ -21,4 +21,10 @@
     <h1>Buongiorno, world!</h1>
     <div id="graph"></div>
   </div>
+
+  <div id="modal-window" class="modal hide fade">
+    <a class="doneButton"></a>
+    <a class="cancelButton"></a>
+    <a class="closeButton"></a>
+  </div>
 </%block>

+ 27 - 36
apps/oozie/static/jasmine/workflow.js

@@ -16,6 +16,10 @@
  limitations under the License.
 */
 
+
+function getFileBrowseButton() {}
+
+
 describe("WorkflowModel", function(){
 
   function create_three_step_workflow(workflow_id) {
@@ -246,43 +250,30 @@ describe("WorkflowModel", function(){
     });
   });
 
-  // describe("Node movement", function(){
-  //   it("Should be able to move a node up", function() {
-
-  //   });
-
-  //   it("Should be able to move a node down", function() {
-
-  //   });
-
-  //   it("Should be able to create a fork", function() {
-
-  //   });
-
-  //   it("Should be able to create a decision", function() {
-
-  //   });
-  // });
-
-  // describe("Node operations", function(){
-  //   it("Should be able to edit a node", function() {
-  //     $('.edit-node-link')[0].click();
-  //     expect($("#node-modal").length).toBeGreaterThan(0);
-  //   });
+  describe("Workflow node modal", function(){
+    var node = null;
+    var viewModel = create_three_step_workflow(2);
+    var modal = new Modal($('#node-modal'));
+    viewModel.rebuild();
 
-  //   it("Should be able to create a node", function() {
-  //     $('.new-node-link[data-node-type=mapreduce]')[0].click();
-  //     expect($("#node-modal").length).toBeGreaterThan(0);
-  //   });
+    it("Ensure can open and close modal", function() {
+      edit_node_modal(modal, viewModel, viewModel.nodes()[1]);
+      expect(modal.el.is(":visible"));
+      $('.doneButton').click();
+      expect(!modal.el.is(":visible"));
 
-  //   it("Should be able to clone a node", function() {
-  //     $('.clone-node-link')[0].click();
-  //     expect($("#node-modal").length).toBeGreaterThan(0);
-  //   });
+      edit_node_modal(modal, viewModel, viewModel.nodes()[1]);
+      expect(modal.el.is(":visible"));
+      $('.cancelButton').click();
+      expect(!modal.el.is(":visible"));
+    });
 
-  //   it("Should be able to remove a node", function() {
-  //     $('.delete-node-btn')[0].click();
-  //     expect($("#node-modal").length).toBeGreaterThan(0);
-  //   });
-  // });
+    it("Ensure can change kill node of existing node", function() {
+      edit_node_modal(modal, viewModel, viewModel.nodes()[1]);
+      modal.context().error_node(viewModel.nodes()[0].id());
+      expect(viewModel.nodes()[1].getErrorChild().id()).toEqual(viewModel.nodes()[0].id());
+      $('.done').click();
+      expect(viewModel.nodes()[1].getErrorChild().id()).toEqual(viewModel.nodes()[0].id());
+    });
+  });
 });

+ 1 - 1
apps/oozie/static/js/workflow.js

@@ -32,7 +32,7 @@ $.extend(StartNode.prototype, Node.prototype, {
     var self = this;
     var index = -1;
 
-    $.each(self.child_links(), function(i, link) {
+    $.each(self.non_error_links(), function(i, link) {
       if (link.child() == child.id()) {
         index = i;
       }

+ 7 - 2
apps/oozie/static/js/workflow.modal.js

@@ -51,13 +51,18 @@ var ModalModule = function($, ko) {
   module.prototype.hide = function() {
     var self = this;
 
-    self.el.modal('hide');
+    self.modal.modal('hide');
+    if (self.modal.length > 0 && !!ko.dataFor(self.modal[0])) {
+      ko.cleanNode(self.modal[0]);
+    }
   };
 
   module.prototype.setTemplate = function(template) {
     var self = this;
 
-    ko.cleanNode(self.modal[0]);
+    if (self.modal.length > 0 && !!ko.dataFor(self.modal[0])) {
+      ko.cleanNode(self.modal[0]);
+    }
     self.template( template );
   };
 

+ 27 - 1
apps/oozie/static/js/workflow.node.js

@@ -61,6 +61,13 @@ var NodeModule = function($, IdGeneratorTable, NodeFields) {
       return links;
     });
 
+    self.non_error_links = ko.computed(function() {
+      var links = self.child_links().filter(function(element, index, arr) {
+        return element.name() != 'error';
+      });
+      return links;
+    });
+
     self._workflow = workflow;
 
     self.registry = registry;
@@ -285,6 +292,20 @@ var NodeModule = function($, IdGeneratorTable, NodeFields) {
       return parents;
     },
 
+    findErrorParents: function() {
+      var self = this;
+
+      var parents = [];
+      $.each(self.registry.nodes, function(id, node) {
+        $.each(node.meta_links(), function(index, link) {
+          if (link.child() == self.id()) {
+            parents.push(node);
+          }
+        });
+      });
+      return parents;
+    },
+
     /**
      * Find all children of current node
      */
@@ -315,6 +336,11 @@ var NodeModule = function($, IdGeneratorTable, NodeFields) {
         });
       });
 
+      // Error links of parents reset to kill node.
+      $.each(self.findErrorParents(), function(index, parent) {
+        parent.putErrorChild(self._workflow.kill);
+      });
+
       $(self).trigger('detached');
 
       self.removeAllChildren();
@@ -416,7 +442,7 @@ var NodeModule = function($, IdGeneratorTable, NodeFields) {
       var self = this;
       var index = -1;
 
-      $.each(self.child_links(), function(i, link) {
+      $.each(self.non_error_links(), function(i, link) {
         if (link.child() == child.id()) {
           index = i;
         }

+ 9 - 0
apps/oozie/static/js/workflow.registry.js

@@ -64,6 +64,15 @@ var RegistryModule = function($) {
 
       delete self.nodes;
       self.nodes = {};
+    },
+
+    allNodes: function() {
+      var self = this;
+      var nodes = [];
+      $.each(self.nodes, function(key, node) {
+        nodes.push(node);
+      });
+      return nodes;
     }
   });
 

+ 69 - 0
apps/oozie/static/js/workflow.utils.js

@@ -23,4 +23,73 @@ if (!('filter' in Array.prototype)) {
         other.push(v);
     return other;
   };
+}
+
+// open a modal window for editing a node
+function edit_node_modal(modal, workflow, node, save, cancel, template) {
+  var backup = ko.mapping.toJS(node);
+  normalize_model_fields(backup);
+
+  modal.hide();
+  modal.setTemplate(template || node.edit_template);
+  // Provide node, readonly mode, and error link updater.
+  // Kill node is manually added to list of nodes that users can select from.
+  // Kill node is placed at the front of the list so that it is automatically selected.
+  var context = {
+    node: node,
+    read_only: workflow.read_only(),
+    nodes: ko.computed({
+      read: function() {
+        var arr = ko.utils.arrayFilter(workflow.registry.allNodes(), function(_node) {
+          return _node.id() && _node.id() != node.id() && $.inArray(_node.node_type(), ['fork', 'join', 'decision']) == -1;
+        });
+        return arr;
+      }
+    }),
+    error_node: ko.computed({
+      read: function() {
+        var error_child  = node.getErrorChild();
+        return (error_child) ? error_child.id() : null;
+      },
+      write: function(node_id) {
+        var error_child = workflow.registry.get(node_id);
+        if (error_child) {
+          node.putErrorChild(error_child);
+        }
+      }
+    })
+  };
+  modal.show(context);
+  modal.recenter(280, 250);
+  modal.addDecorations();
+
+  var cancel_edit = cancel || function() {
+    ko.mapping.fromJS(backup, node);
+    modal.hide();
+
+    // Prevent event propagation
+    return false;
+  };
+
+  var try_save = save || function() {
+    if (node.validate()) {
+      workflow.is_dirty( true );
+      modal.hide();
+    }
+  };
+
+  $('.modal-backdrop').on('click', cancel_edit);
+  modal.el.on('click', '.close', cancel_edit);
+  modal.el.on('click', '.cancelButton', cancel_edit);
+  modal.el.on('click', '.doneButton', try_save);
+
+  modal.el.on('click', '.edit-node-link', function() {
+    var link = ko.contextFor(this).$data;
+    var parent = ko.contextFor(this).$parent;
+    var node = parent.registry.get(link.child());
+
+    cancel_edit();
+
+    edit_node_modal(node);
+  });
 }