فهرست منبع

[oozie] Unified and extracted change tracker, made common submit modal code

Enrico Berti 10 سال پیش
والد
کامیت
365fec6079

+ 2 - 9
apps/oozie/src/oozie/templates/editor2/bundle_editor.mako

@@ -193,7 +193,7 @@ ${ commonheader(_("Bundle Editor"), "Oozie", user) | n,unicode }
 </div>
 
 
-<div id="submit-modal" class="modal hide"></div>
+<div class="submit-modal modal hide"></div>
 
 
 </div>
@@ -218,7 +218,7 @@ ${ commonshare() | n,unicode }
 ${ dashboard.import_bindings() }
 
 <script src="/oozie/static/js/bundle-editor.ko.js" type="text/javascript" charset="utf-8"></script>
-
+<script src="/oozie/static/js/editor2-utils.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript">
   var viewModel = new BundleEditorViewModel(${ bundle_json | n,unicode }, ${ coordinators_json | n,unicode }, ${ can_edit_json | n,unicode });
@@ -248,13 +248,6 @@ ${ dashboard.import_bindings() }
     $("#chooseCoordinatorDemiModal").modal("hide");
   }
 
-  $(document).on("showSubmitPopup", function(event, data){
-    if (! viewModel.bundle.isDirty()){
-      $('#submit-modal').html(data);
-      $('#submit-modal').modal('show');
-    }
-  });
-
   $(document).ready(function() {
     $("#chooseCoordinatorDemiModal").modal({
       show: false

+ 2 - 8
apps/oozie/src/oozie/templates/editor2/coordinator_editor.mako

@@ -465,7 +465,7 @@ ${ commonheader(_("Coordinator Editor"), "Oozie", user) | n,unicode }
 </div>
 
 
-<div id="submit-coord-modal" class="modal hide"></div>
+<div class="submit-modal modal hide"></div>
 
 <div id="chooseFile" class="modal hide fade">
   <div class="modal-header">
@@ -510,6 +510,7 @@ ${ commonshare() | n,unicode }
 ${ dashboard.import_bindings() }
 
 <script src="/oozie/static/js/coordinator-editor.ko.js" type="text/javascript" charset="utf-8"></script>
+<script src="/oozie/static/js/editor2-utils.js" type="text/javascript" charset="utf-8"></script>
 
 
 <script type="text/javascript">
@@ -571,13 +572,6 @@ ${ dashboard.import_bindings() }
     $("#chooseWorkflowDemiModal").modal("hide");
   }
 
-  $(document).on("showSubmitPopup", function(event, data){
-    if (! viewModel.coordinator.isDirty()){
-      $('#submit-coord-modal').html(data);
-      $('#submit-coord-modal').modal('show');
-    }
-  });
-
   var firstToggled = true;
   $(document).on("editingToggled", function(){
     if (firstToggled){

+ 2 - 6
apps/oozie/src/oozie/templates/editor2/list_editor_bundles.mako

@@ -108,7 +108,7 @@ ${ layout.menubar(section='bundles', is_editor=True) }
   <!-- <![endif]-->
 </div>
 
-<div id="submit-wf-modal" class="modal hide"></div>
+<div class="submit-modal modal hide"></div>
 
 <div id="deleteWf" class="modal hide fade">
   <form id="deleteWfForm" method="POST" data-bind="submit: delete2">
@@ -135,6 +135,7 @@ ${ commonshare() | n,unicode }
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/js/share.vm.js"></script>
+<script src="/oozie/static/js/editor2-utils.js" type="text/javascript" charset="utf-8"></script>
 
 
 <script type="text/javascript" charset="utf-8">
@@ -220,11 +221,6 @@ ${ commonshare() | n,unicode }
     shareViewModel = initSharing("#documentShareModal");
     shareViewModel.setDocId(-1);
 
-    $(document).on("showSubmitPopup", function(event, data){
-      $('#submit-wf-modal').html(data);
-      $('#submit-wf-modal').modal('show');
-    });
-
     var oTable = $("#workflowTable").dataTable({
       "sPaginationType":"bootstrap",
       'iDisplayLength':50,

+ 2 - 7
apps/oozie/src/oozie/templates/editor2/list_editor_coordinators.mako

@@ -108,7 +108,7 @@ ${ layout.menubar(section='coordinators', is_editor=True) }
   <!-- <![endif]-->
 </div>
 
-<div id="submit-wf-modal" class="modal hide"></div>
+<div class="submit-modal modal hide"></div>
 
 <div id="deleteWf" class="modal hide fade">
   <form id="deleteWfForm" method="POST" data-bind="submit: delete2">
@@ -135,7 +135,7 @@ ${ commonshare() | n,unicode }
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/js/share.vm.js"></script>
-
+<script src="/oozie/static/js/editor2-utils.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript" charset="utf-8">
   var Editor = function () {
@@ -219,11 +219,6 @@ ${ commonshare() | n,unicode }
     shareViewModel = initSharing("#documentShareModal");
     shareViewModel.setDocId(-1);
 
-    $(document).on("showSubmitPopup", function(event, data){
-      $('#submit-wf-modal').html(data);
-      $('#submit-wf-modal').modal('show');
-    });
-
     var oTable = $("#workflowTable").dataTable({
       "sPaginationType":"bootstrap",
       'iDisplayLength':50,

+ 2 - 7
apps/oozie/src/oozie/templates/editor2/list_editor_workflows.mako

@@ -109,7 +109,7 @@ ${ layout.menubar(section='workflows', is_editor=True) }
   <!-- <![endif]-->
 </div>
 
-<div id="submit-wf-modal" class="modal hide"></div>
+<div class="submit-modal modal hide"></div>
 
 <div id="deleteWf" class="modal hide fade">
   <form id="deleteWfForm" method="POST" data-bind="submit: delete2">
@@ -136,7 +136,7 @@ ${ commonshare() | n,unicode }
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/js/share.vm.js"></script>
-
+<script src="/oozie/static/js/editor2-utils.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript" charset="utf-8">
   var Editor = function () {
@@ -221,11 +221,6 @@ ${ commonshare() | n,unicode }
     shareViewModel = initSharing("#documentShareModal");
     shareViewModel.setDocId(-1);
 
-    $(document).on("showSubmitPopup", function(event, data){
-      $('#submit-wf-modal').html(data);
-      $('#submit-wf-modal').modal('show');
-    });
-
     var oTable = $("#workflowTable").dataTable({
       "sPaginationType":"bootstrap",
       'iDisplayLength':50,

+ 5 - 7
apps/oozie/src/oozie/templates/editor2/submit_job_popup.mako

@@ -29,7 +29,7 @@
     <h3>${ _('Submit %(job)s?') % {'job': name} }</h3>
   </div>
   <div class="modal-body">
-    
+
       <div id="param-container">
 
        ${ params_form.management_form | n,unicode }
@@ -43,7 +43,7 @@
             % if form['name'].form.initial.get('name') == 'oozie.use.system.libpath':
                 style="display: none"
             % endif
-          ">
+          >
             <label class="control-label">${ form['name'].form.initial.get('name') }</label>
             <div class="controls">
               ${ utils.render_field(form['value'], show_label=False, extra_attrs={'class': 'filechooser-input input-xlarge'}) }
@@ -68,7 +68,7 @@
 
          % endfor
       </div>
-
+      <div class="clearfix"></div>
   </div>
   <div class="modal-footer">
     <a href="#" class="btn" data-dismiss="modal">${ _('Cancel') }</a>
@@ -99,7 +99,7 @@
     z-index: 4999;
   }
   #param-container input[type="text"].filechooser-input.input-xlarge {
-    width: 450px;
+    width: 430px;
   }
   #param-container .control-group {
     float: left;
@@ -107,7 +107,6 @@
   #param-container .btn-group {
     margin-left: 10px;
   }
-}
 </style>
 
 <script src="/static/ext/js/moment-with-locales.min.js" type="text/javascript" charset="utf-8"></script>
@@ -133,6 +132,5 @@
       _el.val(_el.val() + "T00:00Z");
     });
    _el.datepicker('show');
-  }); 
+  });
 </script>
-

+ 18 - 26
apps/oozie/src/oozie/templates/editor2/workflow_editor.mako

@@ -153,7 +153,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
     </a>
 
     &nbsp;&nbsp;&nbsp;
-    
+
     <a title="${ _('Edit') }" rel="tooltip" data-placement="bottom" data-bind="click: toggleEditing, css: {'btn': true, 'btn-inverse': isEditing}, visible: canEdit">
       <i class="fa fa-fw fa-pencil"></i>
     </a>
@@ -462,7 +462,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
     <div class="big-icon" data-bind="visible: ! $root.isEditing()"><i class="fa fa-magic"></i></div>
 
     <div data-bind="visible: $root.isEditing" style="padding: 10px">
-      <a class="custom-popover pull-right" href="javascript:void(0)" target="_blank" data-trigger="click" data-toggle="popover" data-placement="right" rel="popover" 
+      <a class="custom-popover pull-right" href="javascript:void(0)" target="_blank" data-trigger="click" data-toggle="popover" data-placement="right" rel="popover"
         data-html="true" data-content="<strong>${ _('Examples of predicates:') }</strong><br/>
                 <br/>${'${'} fs:fileSize(secondjobOutputDir) gt 10 * GB }
                 <br/>
@@ -470,7 +470,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
                 <br/>
                 <a href='http://oozie.apache.org/docs/4.1.0/WorkflowFunctionalSpec.html#a4.2_Expression_Language_Functions'>${ _('Click for more') }</a>">
           <i class="fa fa-question-circle" title="${ _('Click for more info') }"></i>
-      </a>    
+      </a>
       <ul data-bind="foreach: children" class="unstyled">
         <li>
           ${ _('If') } <input type="text" data-bind="value: $data['condition']" />
@@ -733,7 +733,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
 
         &nbsp;&nbsp;
 
-        <span data-bind="text: $root.workflow_properties.hive_xml.label"></span>      
+        <span data-bind="text: $root.workflow_properties.hive_xml.label"></span>
         <input type="text" style="width:25%" class="input-large filechooser-input" data-bind="filechooser: properties.hive_xml, filechooserOptions: globalFilechooserOptions, attr: { placeholder: $root.workflow_properties.hive_xml.help_text }"/>
 
         <div class="row-fluid">
@@ -1039,7 +1039,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
             </a>
           </li>
         </ul>
-        
+
         <div class="span12" data-bind="template: { name: 'common-properties-files' }"></div>
       </div>
     </div>
@@ -1075,12 +1075,12 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
 		    <a class="pointer" data-bind="click: function(){ properties.prepares.push({'type': 'delete', 'value': ''}); $(document).trigger('drawArrows') }">
 		      ${ _('Delete') } <i class="fa fa-plus"></i>
 		    </a>
-		
+
 		    <!-- ko if: properties.job_xml -->
 		      <h6>${ _('Job XML') }</h6>
 		      <input type="text" class="input-xlarge filechooser-input" data-bind="filechooser: properties.job_xml, filechooserOptions: globalFilechooserOptions, attr: { placeholder: $root.workflow_properties.job_xml.help_text }"/>
 		    <!-- /ko -->
-		
+
 		    <h6>
 		      <a class="pointer" data-bind="click: function(){ properties.archives.push(ko.mapping.fromJS({'name': ''})); $(document).trigger('drawArrows') }">
 		        ${ _('Archives') } <i class="fa fa-plus"></i>
@@ -1581,7 +1581,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
         <span data-bind="text: $root.workflow_properties.reducer.label"></span
         <input type="text" data-bind="value: properties.reducer" />
         <span data-bind='template: { name: "common-fs-link", data: {path: properties.reducer(), with_label: false} }'></span>
-        
+
         <div data-bind="template: { name: 'common-properties-files' }"></div>
       </div>
     </div>
@@ -1647,7 +1647,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
 
       </div>
     </div>
-    
+
     <div data-bind="visible: ! $root.isEditing()">
       ${ _('Parameters') }
       <ul data-bind="foreach: properties.distcp_parameters" class="unstyled">
@@ -1684,7 +1684,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
 		   <a class="pointer" data-bind="click: function(){ properties.prepares.push({'type': 'delete', 'value': ''}); $(document).trigger('drawArrows') }">
 		     ${ _('Delete') } <i class="fa fa-plus"></i>
 		   </a>
-		
+
 		   <h6>
 		     <a class="pointer" data-bind="click: function(){ properties.job_properties.push({'name': '', 'value': ''}); $(document).trigger('drawArrows') }">
 		       ${ _('Properties') } <i class="fa fa-plus"></i>
@@ -1701,8 +1701,8 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
            </ul>
            <em data-bind="visible: properties.job_properties().length == 0">${ _('No properties defined.') }</em>
 
-           <h6>             
-             <span data-bind="text: $root.workflow_properties.java_opts.label"></span>             
+           <h6>
+             <span data-bind="text: $root.workflow_properties.java_opts.label"></span>
            </h6>
            <input type="text" class="input-xlarge" data-bind="value: properties.java_opts, attr: { placeholder: $root.workflow_properties.java_opts.help_text }" />
         </div>
@@ -1813,7 +1813,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
         <i class="fa fa-plus"></i> ${ _('Add property') }
       </a>
 
-      <h4>${ _("Show graph arrows") }</h4>      
+      <h4>${ _("Show graph arrows") }</h4>
       <input type="checkbox" data-bind="checked: $root.workflow.properties.show_arrows" title="${ _('Toggle arrow showing') }" rel="tooltip" data-placement="bottom" />
 
       <h4>${ _("Version") }</h4>
@@ -1831,7 +1831,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
 </div>
 
 
-<div id="submit-wf-modal" class="modal hide"></div>
+<div class="submit-modal modal hide"></div>
 
 <div id="chooseFile" class="modal hide fade">
   <div class="modal-header">
@@ -1873,18 +1873,19 @@ ${ dashboard.import_bindings() }
 
 <script src="/oozie/static/js/workflow-editor.ko.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/jquery/plugins/jquery.curvedarrow.js" type="text/javascript" charset="utf-8"></script>
-
+<script src="/oozie/static/js/editor2-utils.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript">
   ${ utils.slaGlobal() }
 
-  var viewModel = new WorkflowEditorViewModel(${ layout_json | n,unicode }, ${ workflow_json | n,unicode }, ${ credentials_json | n,unicode }, ${ workflow_properties_json | n,unicode }, ${ subworkflows_json | n,unicode }, ${ can_edit_json | n,unicode }); 
+  var viewModel = new WorkflowEditorViewModel(${ layout_json | n,unicode }, ${ workflow_json | n,unicode }, ${ credentials_json | n,unicode }, ${ workflow_properties_json | n,unicode }, ${ subworkflows_json | n,unicode }, ${ can_edit_json | n,unicode });
   ko.applyBindings(viewModel, $("#editor")[0]);
 
   var shareViewModel = initSharing("#documentShareModal");
   shareViewModel.setDocId(${ doc1_id });
 
   viewModel.init();
+  viewModel.workflow.tracker().markCurrentStateAsClean();
   fullLayout(viewModel);
 
   var globalFilechooserOptions = {
@@ -1921,15 +1922,6 @@ ${ dashboard.import_bindings() }
     }
   }
 
-
-  $(document).on("showSubmitPopup", function(event, data){
-    if (! viewModel.workflow.isDirty()){
-      $('#submit-wf-modal').html(data);
-      $('#submit-wf-modal').modal('show');
-    }
-  });
-
-
   function showAddActionDemiModal(widget) {
     viewModel.newAction(widget);
     $("#exposeOverlay").fadeIn(300);
@@ -2084,7 +2076,7 @@ ${ dashboard.import_bindings() }
           "width": _width
         });
         _el.width(500);
-        $("#exposeOverlay").fadeIn(300);  
+        $("#exposeOverlay").fadeIn(300);
         widget.oozieExpanded(true);
       }
       else {

+ 3 - 1
apps/oozie/static/css/common-editor.css

@@ -162,4 +162,6 @@ ul.with-margin li {
   margin-bottom: 4px;
 }
 
-
+.submit-modal .dropdown-menu {
+  box-shadow: 0 5px 10px rgba(0,0,0,0.2) !important;
+}

+ 0 - 4
apps/oozie/static/css/coordinator-editor.css

@@ -28,10 +28,6 @@
   display: inline-block;
 }
 
-#submit-coord-modal .modal-body {
-  overflow: visible;
-}
-
 .datepicker {
   z-index: 1300;
 }

+ 32 - 47
apps/oozie/static/js/bundle-editor.ko.js

@@ -16,21 +16,6 @@
 
 
 var Bundle = function (vm, bundle) {
-  function changeTracker(objectToTrack, hashFunction) {    
-      hashFunction = hashFunction || ko.toJSON;
-      var lastCleanState = ko.observable(hashFunction(objectToTrack));
-      
-      var result = {
-          somethingHasChanged : ko.dependentObservable(function() {
-              return hashFunction(objectToTrack) != lastCleanState()
-          }),
-          markCurrentStateAsClean : function() {
-              lastCleanState(hashFunction(objectToTrack));   
-          }
-      };
-      
-      return function() { return result }
-  }
 
   var self = this;
 
@@ -41,27 +26,27 @@ var Bundle = function (vm, bundle) {
   self.coordinators = ko.mapping.fromJS(typeof bundle.coordinators != "undefined" && bundle.coordinators != null ? bundle.coordinators : []);
   self.properties = ko.mapping.fromJS(typeof bundle.properties != "undefined" && bundle.properties != null ? bundle.properties : {});
 
-  self.tracker = new changeTracker(self);
-  
+  self.tracker = new ChangeTracker(self);  // from ko.common-dashboard.js
+
   self.isDirty = ko.computed(function () {
     return self.tracker().somethingHasChanged();
   });
-  
-  self.addCoordinator = function(coordinator_uuid) {
-    self.getCoordinatorParameters(coordinator_uuid);	  
+
+  self.addCoordinator = function (coordinator_uuid) {
+    self.getCoordinatorParameters(coordinator_uuid);
   };
-  
-  self.getCoordinatorParameters = function(uuid) {
-	$.get("/oozie/editor/coordinator/parameters/", {
-	  "uuid": uuid,
-	}, function (data) {
-	   var _var = {       
-           'coordinator': uuid,
-		   'properties': data.parameters
-	   };
+
+  self.getCoordinatorParameters = function (uuid) {
+    $.get("/oozie/editor/coordinator/parameters/", {
+      "uuid": uuid,
+    }, function (data) {
+      var _var = {
+        'coordinator': uuid,
+        'properties': data.parameters
+      };
 
       self.coordinators.push(ko.mapping.fromJS(_var));
-	}).fail(function (xhr, textStatus, errorThrown) {
+    }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);
     });
   };
@@ -73,35 +58,35 @@ var BundleEditorViewModel = function (bundle_json, coordinators_json, can_edit_j
 
   self.canEdit = ko.mapping.fromJS(can_edit_json);
   self.isEditing = ko.observable(bundle_json.id == null);
-  self.isEditing.subscribe(function(newVal){
+  self.isEditing.subscribe(function (newVal) {
     $(document).trigger("editingToggled");
   });
   self.toggleEditing = function () {
-    self.isEditing(! self.isEditing());
+    self.isEditing(!self.isEditing());
   };
 
   self.bundle = new Bundle(self, bundle_json);
-  
+
   self.coordinators = ko.mapping.fromJS(coordinators_json);
 
   self.coordinatorModalFilter = ko.observable("");
-  self.filteredModalCoordinators = ko.computed(function() {
+  self.filteredModalCoordinators = ko.computed(function () {
     var _filter = self.coordinatorModalFilter().toLowerCase();
     if (!_filter) {
       return self.coordinators();
     }
     else {
-      return ko.utils.arrayFilter(self.coordinators(), function(coord) {
+      return ko.utils.arrayFilter(self.coordinators(), function (coord) {
         return coord.name().toLowerCase().indexOf(_filter.toLowerCase()) > -1;
       });
     }
   }, self);
 
   self.getCoordinatorById = function (uuid) {
-    var _coords = ko.utils.arrayFilter(self.coordinators(), function(coord) {
+    var _coords = ko.utils.arrayFilter(self.coordinators(), function (coord) {
       return coord.uuid() == uuid;
     });
-    if (_coords.length > 0){
+    if (_coords.length > 0) {
       return _coords[0];
     }
     return null;
@@ -111,10 +96,10 @@ var BundleEditorViewModel = function (bundle_json, coordinators_json, can_edit_j
     self.bundle.addCoordinator(uuid);
   };
 
-  
+
   self.save = function () {
     $.post("/oozie/editor/bundle/save/", {
-        "bundle": ko.mapping.toJSON(self.bundle)
+      "bundle": ko.mapping.toJSON(self.bundle)
     }, function (data) {
       if (data.status == 0) {
         self.bundle.id(data.id);
@@ -126,22 +111,22 @@ var BundleEditorViewModel = function (bundle_json, coordinators_json, can_edit_j
       }
       else {
         $(document).trigger("error", data.message);
-     }
-   }).fail(function (xhr, textStatus, errorThrown) {
+      }
+    }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);
     });
   };
-  
+
   self.showSubmitPopup = function () {
     // If self.bundle.id() == null, need to save wf for now
-	  $(".jHueNotify").hide();
-    if (! self.bundle.isDirty()){
+    $(".jHueNotify").hide();
+    if (!self.bundle.isDirty()) {
       logGA('submit');
       $.get("/oozie/editor/bundle/submit/" + self.bundle.id(), {
-        }, function (data) {
-          $(document).trigger("showSubmitPopup", data);
+      }, function (data) {
+        $(document).trigger("showSubmitPopup", data);
       }).fail(function (xhr, textStatus, errorThrown) {
-          $(document).trigger("error", xhr.responseText);
+        $(document).trigger("error", xhr.responseText);
       });
     }
   };

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 63 - 78
apps/oozie/static/js/coordinator-editor.ko.js


+ 27 - 0
apps/oozie/static/js/editor2-utils.js

@@ -0,0 +1,27 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+$(document).ready(function () {
+  $(document).on("showSubmitPopup", function (event, data) {
+    $('.submit-modal').html(data);
+    $('.submit-modal').modal('show');
+    var _sel = $('.submit-form .control-group[rel!="popover"]:visible');
+    console.log(_sel.length)
+    if (_sel.length > 0) {
+      $('.submit-modal .modal-body').height(_sel.length * 65 + 100);
+    }
+  });
+});

+ 66 - 91
apps/oozie/static/js/workflow-editor.ko.js

@@ -85,19 +85,21 @@ var Node = function (node) {
   self.children = ko.mapping.fromJS(typeof node.children != "undefined" && node.children != null ? node.children : []);
 
   self.actionParameters = ko.observableArray([]);
-  self.actionParametersUI = ko.computed(function() {
-	if (typeof self.properties.parameters != "undefined") {
-      var _vars = $.map(self.properties.parameters(), function(p, i) { return p.value().split('=', 1)[0]; });
-      if (typeof self.actionParameters() == "undefined"){
+  self.actionParametersUI = ko.computed(function () {
+    if (typeof self.properties.parameters != "undefined") {
+      var _vars = $.map(self.properties.parameters(), function (p, i) {
+        return p.value().split('=', 1)[0];
+      });
+      if (typeof self.actionParameters() == "undefined") {
         return _vars;
       }
-      return $.grep(self.actionParameters(), function(param) {
+      return $.grep(self.actionParameters(), function (param) {
         return _vars.indexOf(param) == -1;
       });
-	}
+    }
   });
   self.actionParametersFetched = ko.observable(false);
-  
+
   self.get_link = function (name) {
     var _link = null;
     $.each(self.children(), function (index, link) {
@@ -133,33 +135,33 @@ var Node = function (node) {
       self.children.remove(_link);
     }
   };
-  
-  self.fetch_parameters = function() {
-    if (typeof self.properties.parameters != "undefined" && ! self.actionParametersFetched()) { // Fetch once the possible variable when they exist 
+
+  self.fetch_parameters = function () {
+    if (typeof self.properties.parameters != "undefined" && !self.actionParametersFetched()) { // Fetch once the possible variable when they exist
       $.post("/oozie/editor/workflow/action/parameters/", {
-         "node": ko.mapping.toJSON(self),
-	  }, function (data) {
-	    self.actionParametersFetched(true);
-	    self.actionParameters(data.parameters);
-	    if (data.parameters && data.parameters.length > 0 && self.properties.parameters().length == 0) { // If new node with variables, give a hint by adding a parameter
-	      self.properties.parameters.push(ko.mapping.fromJS({'value': ''}));
-	    }
-	  }).fail(function (xhr, textStatus, errorThrown) {
-	    $(document).trigger("error", xhr.responseText);
+        "node": ko.mapping.toJSON(self),
+      }, function (data) {
+        self.actionParametersFetched(true);
+        self.actionParameters(data.parameters);
+        if (data.parameters && data.parameters.length > 0 && self.properties.parameters().length == 0) { // If new node with variables, give a hint by adding a parameter
+          self.properties.parameters.push(ko.mapping.fromJS({'value': ''}));
+        }
+      }).fail(function (xhr, textStatus, errorThrown) {
+        $(document).trigger("error", xhr.responseText);
       });
     }
-  };  
-  
-  if (typeof self.properties.parameters != "undefined") { 
-    self.properties.parameters.subscribe(function(newVal) {
+  };
+
+  if (typeof self.properties.parameters != "undefined") {
+    self.properties.parameters.subscribe(function (newVal) {
       if (newVal) {
-	    self.fetch_parameters();
-	  }
-    });  
+        self.fetch_parameters();
+      }
+    });
   }
-  
+
   if (typeof self.properties.script_path != "undefined") {
-    self.properties.script_path.subscribe(function() {
+    self.properties.script_path.subscribe(function () {
       self.actionParametersFetched(false);
     });
   }
@@ -167,13 +169,18 @@ var Node = function (node) {
 
 
 var Workflow = function (vm, workflow) {
+
   var self = this;
 
   self.id = ko.observable(typeof workflow.id != "undefined" && workflow.id != null ? workflow.id : null);
   self.uuid = ko.observable(typeof workflow.uuid != "undefined" && workflow.uuid != null ? workflow.uuid : UUID());
   self.name = ko.observable(typeof workflow.name != "undefined" && workflow.name != null ? workflow.name : "");
 
-  self.isDirty = ko.observable(false);
+  self.tracker = new ChangeTracker(self); // from ko.common-dashboard.js
+
+  self.isDirty = ko.computed(function () {
+    return self.tracker().somethingHasChanged();
+  });
 
   self.properties = ko.mapping.fromJS(typeof workflow.properties != "undefined" && workflow.properties != null ? workflow.properties : {});
   self.nodes = ko.observableArray([]);
@@ -181,7 +188,7 @@ var Workflow = function (vm, workflow) {
   self.versions = ko.mapping.fromJS(['uri:oozie:workflow:0.4', 'uri:oozie:workflow:0.4.5', 'uri:oozie:workflow:0.5']);
   self.movedNode = null;
   self.properties.show_arrows.subscribe(function (newVal) {
-    if (newVal){
+    if (newVal) {
       $(document).trigger("drawArrows");
     }
     else {
@@ -189,35 +196,6 @@ var Workflow = function (vm, workflow) {
     }
   });
 
-  self.nodesProperties = ko.computed(function () {
-    var isDirtyContainer = [];
-    $.each(self.nodes(), function (index, node) {
-      for(var property in node.properties) {
-        if (typeof node.properties[property] == "function"){
-          var _obs = node.properties[property]();
-           isDirtyContainer.push(_obs);
-           if ($.isArray(_obs)){
-             _obs.forEach(function(item){
-               isDirtyContainer.push(typeof item.value == "function" ? item.value() : item.value);
-             });
-           }
-        }
-      }
-    });
-    return isDirtyContainer;
-  });
-
-  self.oldNodesPropertiesHash = "";
-  self.nodesProperties.subscribe(function(newVal){
-    if (self.oldNodesPropertiesHash == ""){
-      self.oldNodesPropertiesHash = JSON.stringify(newVal);
-    }
-    if (JSON.stringify(newVal) !== self.oldNodesPropertiesHash){
-      self.oldNodesPropertiesHash = JSON.stringify(newVal);
-      self.isDirty(true);
-    }
-  });
-
   self.nodeIds = ko.computed(function () {
     var mapping = [];
 
@@ -275,10 +253,10 @@ var Workflow = function (vm, workflow) {
       success: function (data) {
         if (data.status == 0) {
           viewModel.addActionProperties.removeAll();
-          $.each(data.properties, function(i, prop) {
-        	viewModel.addActionProperties.push(ko.mapping.fromJS(prop));  
+          $.each(data.properties, function (i, prop) {
+            viewModel.addActionProperties.push(ko.mapping.fromJS(prop));
           });
-          
+
           if (data.workflows.length > 0) {
             viewModel.subworfklows(data.workflows);
           }
@@ -286,7 +264,6 @@ var Workflow = function (vm, workflow) {
           if (callback) {
             callback(widget, sourceNode);
           }
-          self.isDirty(true);
         }
       },
       async: false
@@ -333,10 +310,10 @@ var Workflow = function (vm, workflow) {
             var forkParent = self.getNodeById(vm.getWidgetPredecessor(parentWidget.id()).id());
 
             // In case of Fork of Fork, we need to pick the link of the neighbor of new node instead of just the first forkParent.get_link('to')
-            var newParentLink = $.grep(forkParent.children(), function(link) {
+            var newParentLink = $.grep(forkParent.children(), function (link) {
               return vm.getWidgetPredecessor(ko.mapping.toJS(link)['to']).id() == fork.id();
-            })[0];  
- 
+            })[0];
+
             var afterParentId = ko.mapping.toJS(newParentLink).to;
             var afterParent = self.getNodeById(afterParentId);
             fork.children.push({'to': afterParentId, 'condition': '${ 1 gt 0 }'});
@@ -377,7 +354,7 @@ var Workflow = function (vm, workflow) {
             node.set_link('to', child.id());
             node.set_link('error', '17c9c895-5a16-7443-bb81-f34b30b21548');
           } else {
-            // Parent is regular node        	
+            // Parent is regular node
             node.set_link('to', parent.get_link('to')['to']);
             node.set_link('error', '17c9c895-5a16-7443-bb81-f34b30b21548');
 
@@ -386,8 +363,6 @@ var Workflow = function (vm, workflow) {
         }
 
         vm.currentlyCreatingFork = false;
-        self.isDirty(true);
-
       } else {
         $(document).trigger("error", data.message);
       }
@@ -443,7 +418,6 @@ var Workflow = function (vm, workflow) {
       } else if (parent.type() == 'decision-widget') {
         parent.remove_link('to', childId);
       }
-      self.isDirty(true);
     }
     else {
       self.nodes.remove(node);
@@ -494,7 +468,7 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
     $(document).trigger("editingToggled");
   });
   self.toggleEditing = function () {
-    self.isEditing(! self.isEditing());
+    self.isEditing(!self.isEditing());
   };
 
   self.isRunning = ko.observable(false);
@@ -516,11 +490,11 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
   };
 
   self.addActionProperties = ko.observableArray([]);
-  self.addActionPropertiesFilledOut = ko.computed(function (){
+  self.addActionPropertiesFilledOut = ko.computed(function () {
     var _filledInternalValues = function (val) {
       var _iAllFilled = true;
-      val.forEach(function(iVal){
-        if (iVal.value() == ''){
+      val.forEach(function (iVal) {
+        if (iVal.value() == '') {
           _iAllFilled = false;
         }
       });
@@ -529,16 +503,16 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
     var _allFilled = true;
     ko.utils.arrayForEach(self.addActionProperties(), function (property) {
       var _val = property.value();
-      if (($.isArray(_val) && !_filledInternalValues(_val) ) || _val == ''){
+      if (($.isArray(_val) && !_filledInternalValues(_val) ) || _val == '') {
         _allFilled = false;
       }
     });
     return _allFilled;
   });
   self.subworfklows = ko.observableArray(subworkflows_json);
-  self.getSubWorkflow = function(uuid) {
-    var wf = $.grep(self.subworfklows(), function(wf, i) {
-        return wf.value == uuid;
+  self.getSubWorkflow = function (uuid) {
+    var wf = $.grep(self.subworfklows(), function (wf, i) {
+      return wf.value == uuid;
     });
     if (wf[0]) {
       return ko.mapping.fromJS(wf[0]);
@@ -558,13 +532,14 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
 
   self.enableSideDrop = function (widget) {
     toggleSideDrop(widget, true);
-    sideDropsTouched.forEach(function(row) {
+    sideDropsTouched.forEach(function (row) {
       row.enableOozieDropOnSide(true);
     });
     sideDropsTouched = [];
   }
 
   var sideDropsTouched = [];
+
   function toggleSideDrop(widget, enable) {
     if (widget != null && widget.id() != "" && self.currentlyDraggedOp() == "move") {
       var _row = self.getWidgetParentRow(widget.id());
@@ -1051,24 +1026,24 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
   }
 
   self.save = function () {
-	$(".jHueNotify").hide();
+    $(".jHueNotify").hide();
     $.post("/oozie/editor/workflow/save/", {
       "layout": ko.mapping.toJSON(self.oozieColumns),
       "workflow": ko.mapping.toJSON(self.workflow)
     }, function (data) {
       if (data.status == 0) {
-    	if (data.url) { 
+        if (data.url) {
           window.location.replace(data.url);
-    	}
-    	if (self.workflow.id() == null) {
-    	  shareViewModel.setDocId(data.doc1_id);
-    	}
+        }
+        if (self.workflow.id() == null) {
+          shareViewModel.setDocId(data.doc1_id);
+        }
         self.workflow.id(data.id);
         $(document).trigger("info", data.message);
         if (window.location.search.indexOf("workflow") == -1) {
           window.location.hash = '#workflow=' + data.id;
         }
-        self.workflow.isDirty(false);
+        self.workflow.tracker().markCurrentStateAsClean();
       }
       else {
         $(document).trigger("error", data.message);
@@ -1095,7 +1070,7 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
   };
 
   self.showSubmitPopup = function () {
-	$(".jHueNotify").hide();
+    $(".jHueNotify").hide();
     $.get("/oozie/editor/workflow/submit/" + self.workflow.id(), {
     }, function (data) {
       $(document).trigger("showSubmitPopup", data);
@@ -1103,7 +1078,7 @@ var WorkflowEditorViewModel = function (layout_json, workflow_json, credentials_
       $(document).trigger("error", xhr.responseText);
     });
   };
-  
+
   self.schedule = function () {
     window.location.replace('/oozie/editor/coordinator/new/?workflow=' + self.workflow.uuid());
   };
@@ -1194,7 +1169,7 @@ var ExtendedColumn = function (size, rows) {
 var ExtendedRow = function (widgets, vm, columns) {
   var self = new Row(widgets, vm, columns);
   self.columnPrototype = ExtendedColumn;
-  self.enableOozieDrop = ko.computed(function(){
+  self.enableOozieDrop = ko.computed(function () {
     return vm.isEditing && vm.isEditing() && self.widgets && self.widgets().length < 1
   });
 
@@ -1206,8 +1181,8 @@ var ExtendedRow = function (widgets, vm, columns) {
 
 var ExtendedWidget = function (params) {
   var self = new Widget(params);
-  self.oozieMovable = ko.computed(function() {
-    return ["end-widget", "start-widget", "fork-widget", "decision-widget", "join-widget"].indexOf(self.widgetType()) == - 1
+  self.oozieMovable = ko.computed(function () {
+    return ["end-widget", "start-widget", "fork-widget", "decision-widget", "join-widget"].indexOf(self.widgetType()) == -1
   });
 
   self.oozieExpanded = ko.observable(false);

+ 27 - 9
desktop/core/static/js/ko.common-dashboard.js

@@ -67,8 +67,8 @@ var Row = function (widgets, vm, columns) {
   self.id = ko.observable(UUID());
   self.widgets = ko.observableArray(widgets);
   self.columns = ko.observableArray(columns ? columns : []);
-  self.columns.subscribe(function(val){
-    self.columns().forEach(function(col){
+  self.columns.subscribe(function (val) {
+    self.columns().forEach(function (col) {
       col.percWidth((100 - self.columns().length * 0.5) / self.columns().length);
     });
   });
@@ -78,11 +78,11 @@ var Row = function (widgets, vm, columns) {
   };
 
   self.addEmptyColumn = function (atBeginning) {
-    if (self.columns().length == 0){
+    if (self.columns().length == 0) {
       var _col = self.addColumn(null, atBeginning);
-      if (self.widgets().length > 0){
+      if (self.widgets().length > 0) {
         var _row = _col.addEmptyRow();
-        self.widgets().forEach(function(widget){
+        self.widgets().forEach(function (widget) {
           _row.addWidget(widget);
         });
         self.widgets([]);
@@ -95,11 +95,11 @@ var Row = function (widgets, vm, columns) {
     if (typeof column == "undefined" || column == null) {
       var _size = Math.max(1, Math.floor(12 / (self.columns().length + 1)));
       column = new self.columnPrototype(_size, []); // Hacky but needed when a new row is deleted
-      self.columns().forEach(function(col){
+      self.columns().forEach(function (col) {
         col.size(_size);
       });
     }
-    if (typeof atBeginning == "undefined" || atBeginning == null || ! atBeginning) {
+    if (typeof atBeginning == "undefined" || atBeginning == null || !atBeginning) {
       self.columns.push(column);
     }
     else {
@@ -160,7 +160,7 @@ var Row = function (widgets, vm, columns) {
 var Widget = function (params) {
   var self = this;
 
-  self.extend = function() {
+  self.extend = function () {
     return self;
   }
 
@@ -283,4 +283,22 @@ function setLayout(colSizes, vm) {
   vm.columns(_cols);
 
   $(document).trigger("setLayout");
-}
+}
+
+function ChangeTracker(objectToTrack, hashFunction) {
+  hashFunction = hashFunction || ko.toJSON;
+  var lastCleanState = ko.observable(hashFunction(objectToTrack));
+
+  var result = {
+    somethingHasChanged: ko.dependentObservable(function () {
+      return hashFunction(objectToTrack) != lastCleanState()
+    }),
+    markCurrentStateAsClean: function () {
+      lastCleanState(hashFunction(objectToTrack));
+    }
+  };
+
+  return function () {
+    return result
+  }
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است