소스 검색

HUE-974 [oozie] Readonly support

- Nodes are immobile
- Cannot save workflow
- Cannot edit nodes
- Node fields are disabled
abec 13 년 전
부모
커밋
e381d0b660

+ 34 - 34
apps/oozie/src/oozie/templates/editor/action_utils.mako

@@ -26,7 +26,7 @@
   <script type="text/html" id="ImportNodeTemplate">
 % endif
 
-  <div data-bind="with: context">
+  <div data-bind="with: context().node">
     <form class="form-horizontal" id="import-node-form" method="POST">
       <div class="modal-header">
         <a href="#" class="close">&times;</a>
@@ -46,7 +46,7 @@
             <tbody data-bind="visible: available_nodes().length > 0, foreach: available_nodes">
               <tr class="action-row">
                 <td class=".btn-large action-column" data-row-selector-exclude="true" style="background-color: white;">
-                  <input type="radio" name="jobsub_id" data-bind="attr: { 'value': id }, click: $parent.setJobDesignerId" />
+                  <input type="radio" name="jobsub_id" data-bind="attr: { 'value': id }, click: $parent.setJobDesignerId, disable: $root.context().read_only" />
                 </td>
                 <td data-bind="text: $data.name"></td>
                 <td data-bind="text: $data.description"></td>
@@ -63,7 +63,7 @@
 
       <div class="modal-footer">
         <a class="btn cancelButton" href="javascript:void(0);">${ _('Cancel') }</a>
-        <button class="btn btn-primary doneButton" type="button">${ _('Import') }</button>
+        <button class="btn btn-primary doneButton" type="button" data-bind="visible: !$root.context().read_only">${ _('Import') }</button>
       </div>
 
     </form>
@@ -94,7 +94,7 @@
 % if template:
   <script type="text/html" id="${node_type}EditTemplate">
 % endif
-  <div data-bind="with: context">
+  <div data-bind="with: context().node">
     <form class="form-horizontal" id="${node_type}-action-form" method="POST">
       <div class="modal-header">
         <a href="#" class="close">&times;</a>
@@ -105,7 +105,7 @@
         <fieldset class="span12">
           % for field in action_form:
             % if field.html_name in ('name', 'description'):
-              ${ utils.render_field_with_error_js(field, field.name, extra_attrs={'data-bind': 'value: %s' % field.name}) }
+              ${ utils.render_field_with_error_js(field, field.name, extra_attrs={'data-bind': 'disable: $root.context().read_only, value: %s' % field.name}) }
             % endif
           % endfor
 
@@ -141,9 +141,9 @@
           % for field in action_form:
             % if field.html_name not in ('name', 'description', 'node_type', 'job_xml'):
               % if field.html_name in ('capture_output', 'is_single', 'sub_workflow'):
-                ${ utils.render_field_with_error_js(field, field.name, extra_attrs={'data-bind': 'checked: %s' % field.name}) }
+                ${ utils.render_field_with_error_js(field, field.name, extra_attrs={'data-bind': 'disable: $root.context().read_only, checked: %s' % field.name}) }
               % else:
-                ${ utils.render_field_with_error_js(field, field.name, extra_attrs={'data-bind': 'value: %s' % field.name}) }
+                ${ utils.render_field_with_error_js(field, field.name, extra_attrs={'data-bind': 'disable: $root.context().read_only, value: %s' % field.name}) }
               % endif
             % endif
           % endfor
@@ -256,7 +256,7 @@
           % endif
 
           % if 'job_xml' in action_form.fields:
-            ${ utils.render_field_with_error_js(action_form['job_xml'], action_form['job_xml'].name, extra_attrs={'data-bind': 'value: %s' % action_form['job_xml'].name}) }
+            ${ utils.render_field_with_error_js(action_form['job_xml'], action_form['job_xml'].name, extra_attrs={'data-bind': 'disable: $root.context().read_only, value: %s' % action_form['job_xml'].name}) }
           % endif
 
           % if 'deletes' in action_form.fields:
@@ -314,7 +314,7 @@
 
       <div class="modal-footer">
         <a class="btn cancelButton" href="javascript:void(0);">Cancel</a>
-        <button class="btn btn-primary doneButton" type="button">${ _('Done')}</button>
+        <button class="btn btn-primary doneButton" type="button" data-bind="visible: !$root.context().read_only">${ _('Done')}</button>
       </div>
 
     </form>
@@ -333,11 +333,11 @@
         <tbody data-bind="foreach: ${ javascript_attrs['name'] }">
           <tr>
             <td>
-              <input type="text" class="span5 required pathChooserKo" data-bind="fileChooser: $data, value: name, uniqueName: false" />
+              <input type="text" class="span5 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: name, uniqueName: false" />
             </td>
             <td>
               % if 'remove' in javascript_attrs:
-                <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+                <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
               % endif
             </td>
           </tr>
@@ -345,7 +345,7 @@
       </table>
 
       % if 'add' in javascript_attrs:
-        <button class="btn" data-bind="click: ${ javascript_attrs['add'] }">${ _('Add Path') }</button>
+        <button class="btn" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['add'] }">${ _('Add Path') }</button>
       % endif
     % endif
   </div>
@@ -361,11 +361,11 @@
         <tbody data-bind="foreach: ${ javascript_attrs['name'] }">
           <tr>
             <td>
-              <input type="text" class="span5 required pathChooserKo" data-bind="fileChooser: $data, value: name, uniqueName: false" />
+              <input type="text" class="span5 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: name, uniqueName: false" />
             </td>
             <td>
               % if 'remove' in javascript_attrs:
-                <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+                <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
               % endif
             </td>
           </tr>
@@ -373,7 +373,7 @@
       </table>
 
       % if 'add' in javascript_attrs:
-        <button class="btn" data-bind="click: ${ javascript_attrs['add'] }">${ _('Add Archive') }</button>
+        <button class="btn" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['add'] }">${ _('Add Archive') }</button>
       % endif
     % endif
   </div>
@@ -395,11 +395,11 @@
         </thead>
         <tbody data-bind="foreach: ${ javascript_attrs['name'] }">
           <tr>
-            <td><input type="text" class="span4 required propKey" data-bind="value: name, uniqueName: false" /></td>
-            <td><input type="text" class="span4 required pathChooserKo" data-bind="fileChooser: $data, value: value, uniqueName: false" /></td>
+            <td><input type="text" class="span4 required propKey" data-bind="disable: $root.context().read_only, value: name, uniqueName: false" /></td>
+            <td><input type="text" class="span4 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: value, uniqueName: false" /></td>
             <td>
             % if 'remove' in javascript_attrs:
-              <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+              <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
             % endif
             </td>
           </tr>
@@ -407,7 +407,7 @@
       </table>
 
       % if 'add' in javascript_attrs:
-        <button class="btn" data-bind="click: ${ javascript_attrs['add'] }">${ _('Add Property') }</button>
+        <button class="btn" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['add'] }">${ _('Add Property') }</button>
       % endif
     % endif
   </div>
@@ -429,11 +429,11 @@
         </thead>
         <tbody data-bind="foreach: ${ javascript_attrs['name'] }">
           <tr>
-            <td><input type="text" class="span4 required propKey" data-bind="fileChooser: $data, value: source, uniqueName: false" /></td>
-            <td><input type="text" class="span4 required pathChooserKo" data-bind="fileChooser: $data, value: destination, uniqueName: false" /></td>
+            <td><input type="text" class="span4 required propKey" data-bind="disable: $root.context().read_only, fileChooser: $data, value: source, uniqueName: false" /></td>
+            <td><input type="text" class="span4 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: destination, uniqueName: false" /></td>
             <td>
             % if 'remove' in javascript_attrs:
-              <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+              <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
             % endif
             </td>
           </tr>
@@ -441,7 +441,7 @@
       </table>
 
       % if 'add' in javascript_attrs:
-        <button class="btn" data-bind="click: ${ javascript_attrs['add'] }">${ _('Add move') }</button>
+        <button class="btn" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['add'] }">${ _('Add move') }</button>
       % endif
     % endif
   </div>
@@ -464,12 +464,12 @@
         </thead>
         <tbody data-bind="foreach: ${ javascript_attrs['name'] }">
           <tr>
-            <td><input type="text" class="span4 required pathChooserKo" data-bind="fileChooser: $data, value: path, uniqueName: false" /></td>
-            <td><input type="text" class="span2 required propKey" data-bind="value: permissions, uniqueName: false" /></td>
-            <td><input type="checkbox" class="span1 required" data-bind="checked: recursive, uniqueName: false" /></td>
+            <td><input type="text" class="span4 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: path, uniqueName: false" /></td>
+            <td><input type="text" class="span2 required propKey" data-bind="disable: $root.context().read_only, value: permissions, uniqueName: false" /></td>
+            <td><input type="checkbox" class="span1 required" data-bind="disable: $root.context().read_only, checked: recursive, uniqueName: false" /></td>
             <td>
             % if 'remove' in javascript_attrs:
-              <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+              <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
             % endif
             </td>
           </tr>
@@ -477,7 +477,7 @@
       </table>
 
       % if 'add' in javascript_attrs:
-        <button class="btn" data-bind="click: ${ javascript_attrs['add'] }">${ _('Add chmod') }</button>
+        <button class="btn" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['add'] }">${ _('Add chmod') }</button>
       % endif
     % endif
   </div>
@@ -503,11 +503,11 @@
               <span class="span4 required" data-bind="text: type" />
             </td>
             <td>
-              <input type="text" class="input span4 required pathChooserKo" data-bind="fileChooser: $data, value: value, uniqueName: false" />
+              <input type="text" class="input span4 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: value, uniqueName: false" />
             </td>
             <td>
             % if 'remove' in javascript_attrs:
-              <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+              <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
             % endif
             </td>
           </tr>
@@ -516,7 +516,7 @@
 
       % if 'add' in javascript_attrs:
         % for method in javascript_attrs['add']:
-          <button class="btn" data-bind="click: ${ method['method'] }">${ _(method['label']) }</button>
+          <button class="btn" data-bind="disable: $root.context().read_only, click: ${ method['method'] }">${ _(method['label']) }</button>
         % endfor
       % endif
     % endif
@@ -543,11 +543,11 @@
               <span class="span4 required" data-bind="text: type" />
             </td>
             <td>
-              <input type="text" class="input span4 required pathChooserKo" data-bind="fileChooser: $data, value: value, uniqueName: false" />
+              <input type="text" class="input span4 required pathChooserKo" data-bind="disable: $root.context().read_only, fileChooser: $data, value: value, uniqueName: false" />
             </td>
             <td>
               % if 'remove' in javascript_attrs:
-                <a class="btn" href="#" data-bind="click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
+                <a class="btn" href="#" data-bind="disable: $root.context().read_only, click: ${ javascript_attrs['remove'] }">${ _('Delete') }</a>
               % endif
             </td>
           </tr>
@@ -556,7 +556,7 @@
 
       % if 'add' in javascript_attrs:
         % for method in javascript_attrs['add']:
-          <button class="btn" data-bind="click: ${ method['method'] }">${ _(method['label']) }</button>
+          <button class="btn" data-bind="disable: $root.context().read_only, click: ${ method['method'] }">${ _(method['label']) }</button>
         % endfor
       % endif
     % endif

+ 2 - 2
apps/oozie/src/oozie/templates/editor/control_utils.mako

@@ -27,7 +27,7 @@
 % if template:
   <script type="text/html" id="${node_type}EditTemplate">
 % endif
-  <div data-bind="with: context">
+  <div data-bind="with: context().node">
     <form class="form-horizontal" id="${node_type}-action-form" method="POST">
       <div class="modal-header">
         <a href="#" class="close" data-dismiss="modal">&times;</a>
@@ -43,7 +43,7 @@
       <div class="modal-footer">
         <button data-dismiss="modal" class="btn">${ _('No')}</button>
         % if 'convert' in javascript_attrs:
-          <button data-dismiss="modal" class="btn btn-primary" data-bind="click: ${ javascript_attrs['convert'] }">${ _('Yes') }</button>
+          <button data-dismiss="modal" class="btn btn-primary" data-bind="visible: !$root.context().read_only, click: ${ javascript_attrs['convert'] }">${ _('Yes') }</button>
         % endif
       </div>
 

+ 6 - 5
apps/oozie/src/oozie/templates/editor/edit_workflow.mako

@@ -182,7 +182,7 @@ ${ layout.menubar(section='workflows') }
           </div>
         </div>
         <div class="form-actions center">
-          <a data-bind="click: function() { save() }" href="javascript:void(0);" class="btn btn-primary">${ _('Save') }</a>
+          <a data-bind="disable: workflow.read_only, visible: !workflow.read_only(), click: function() { save() }" href="javascript:void(0);" class="btn btn-primary">${ _('Save') }</a>
           <a href="${ url('oozie:list_workflows') }" class="btn">${ _('Back') }</a>
         </div>
       </div>
@@ -235,7 +235,7 @@ ${ layout.menubar(section='workflows') }
         </div>
         <div class="form-actions center">
           % if user_can_edit_job:
-            <button data-bind="click: function() { save() }" class="btn btn-primary">${ _('Save') }</button>
+            <button data-bind="disable: workflow.read_only, visible: !workflow.read_only(), click: function() { save() }" class="btn btn-primary">${ _('Save') }</button>
           % endif
           <a href="${ url('oozie:list_workflows') }" class="btn">${ _('Back') }</a>
         </div>
@@ -498,7 +498,8 @@ var workflow_model = new WorkflowModel({
 var registry = new Registry();
 var workflow = new Workflow({
   model: workflow_model,
-  registry: registry
+  registry: registry,
+  read_only: ${ str(not user_can_edit_job).lower() }
 });
 workflow.load();
 
@@ -514,7 +515,7 @@ function edit_node_modal(node, save, cancel) {
 
   modal.hide();
   modal.setTemplate(node.edit_template);
-  modal.show(node);
+  modal.show({node: node, read_only: workflow.read_only()});
   modal.recenter(280, 250);
   modal.addDecorations();
 
@@ -651,7 +652,7 @@ $('#workflow').on('click', '.import-jobsub-node-link', function(e) {
 
   modal.hide();
   modal.setTemplate('ImportNodeTemplate');
-  modal.show(tempModelView);
+  modal.show({node: tempModelView, read_only: workflow.read_only()});
   modal.recenter(280, 250);
   modal.addDecorations();
 

+ 36 - 8
apps/oozie/static/js/workflow.js

@@ -552,7 +552,7 @@ var ImportNodeModule = function($) {
         if (data.status == 0) {
           self.initialize(data.data);
         } else {
-          $.jHueNotify.error("${ _('Received invalid response from server: ') }" + JSON.stringify(data));
+          $.jHueNotify.error("Received invalid response from server: " + JSON.stringify(data));
         }
       });
     },
@@ -1761,6 +1761,7 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
     self.nodes = ko.observableArray([]);
     self.kill = null;
     self.is_dirty = ko.observable( false );
+    self.read_only = ko.observable( options.read_only || false );
 
     self.url = ko.computed(function() {
       return '/oozie/workflows/' + self.id()
@@ -1793,13 +1794,16 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
     initialize: function(options) {
       var self = this;
 
-      if ('data' in options) {
+      $.extend(self.options, options);
+
+      if ('model' in options) {
+        self.model = options.model;
 
         // Initialize nodes
-        if (options.data.nodes) {
+        if (self.model.nodes) {
           self.registry.clear();
 
-          $.each(options.data.nodes, function(index, node) {
+          $.each(self.model.nodes, function(index, node) {
             var NodeModel = NodeModelChooser(node.node_type);
             var model = new NodeModel(node);
             var temp = null;
@@ -1826,7 +1830,7 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
         }
 
         // Update data
-        $.each(options.data, function (key, value) {
+        $.each(self.model, function (key, value) {
           if (key in self) {
             switch(key) {
               case 'job_properties':
@@ -1874,6 +1878,10 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
         self.kill = new Node(self, model, self.registry);
         self.registry.add(self.kill.id(), self.kill);
       }
+
+      if ('read_only' in options) {
+        self.read_only(options['read_only']);
+      }
     },
 
     toString: function() {
@@ -1915,12 +1923,12 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
         if (data.status == 0) {
           self.reload(data.data);
         } else {
-          $.jHueNotify.error("${ _('Received invalid response from server: ') }" + JSON.stringify(data));
+          $.jHueNotify.error("Received invalid response from server: " + JSON.stringify(data));
         }
       });
     },
 
-    reload: function(data) {
+    reload: function(model) {
       var self = this;
 
       // Clear all children
@@ -1929,7 +1937,7 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
       });
       self.nodes.removeAll();
 
-      self.initialize({data: data});
+      self.initialize({model: model});
       self.rebuild();
       self.el.trigger('workflow:loaded');
     },
@@ -2164,6 +2172,11 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
       // Build event delegations.
       // Drop on node link
       self.el.on('drop', '.node-link', function(e, ui) {
+        if (self.read_only()) {
+          $.jHueNotify.error("Workflow is in read only mode.");
+          return false;
+        }
+
         // draggable should be a node.
         // droppable should be a link.
         var draggable = ko.contextFor(ui.draggable[0]).$data;
@@ -2215,6 +2228,11 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
 
       // Drop on fork
       self.el.on('drop', '.node-fork', function(e, ui) {
+        if (self.read_only()) {
+          $.jHueNotify.error("Workflow is in read only mode.");
+          return false;
+        }
+
         // draggable should be a node.
         // droppable should be a fork.
         var draggable = ko.contextFor(ui.draggable[0]).$data;
@@ -2233,6 +2251,11 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
 
       // Drop on decision
       self.el.on('drop', '.node-decision', function(e, ui) {
+        if (self.read_only()) {
+          $.jHueNotify.error("Workflow is in read only mode.");
+          return false;
+        }
+
         // draggable should be a node.
         // droppable should be a fork.
         var draggable = ko.contextFor(ui.draggable[0]).$data;
@@ -2251,6 +2274,11 @@ var WorkflowModule = function($, NodeModelChooser, Node, ForkNode, DecisionNode,
 
       // Drop on action
       self.el.on('drop', '.node-action', function(e, ui) {
+        if (self.read_only()) {
+          $.jHueNotify.error("Workflow is in read only mode.");
+          return false;
+        }
+
         // draggable should be a node.
         // droppable should be a node.
         var draggable = ko.contextFor(ui.draggable[0]).$data;