浏览代码

HUE-2786 [hbase] Show current version in the cell history and allow revert to previous version

In the full editor for a cell it now shows the current version in the cell history as well as an indicator of when the current version is edited. I've also made it possible to revert to a previous version by selecting it and pressing revert.
Johan Ahlen 10 年之前
父节点
当前提交
d5d5cac32d
共有 2 个文件被更改,包括 74 次插入16 次删除
  1. 57 4
      apps/hbase/src/hbase/static/hbase/js/utils.js
  2. 17 12
      apps/hbase/src/hbase/templates/app.mako

+ 57 - 4
apps/hbase/src/hbase/static/hbase/js/utils.js

@@ -105,6 +105,21 @@ function launchModal(modal, data) {
           lineNumbers: true,
           lineNumbers: true,
           readOnly: $(target).is(":disabled")
           readOnly: $(target).is(":disabled")
         });
         });
+        data.codeMirror = cm;
+
+        var updateTimeout = 0;
+        cm.on("change", function(cm) {
+          clearTimeout(updateTimeout);
+          updateTimeout = setTimeout(function () {
+            data.value(cm.getValue());
+          }, 100);
+        });
+
+        data.showingCurrent.subscribe(function(showingCurrent) {
+          cm.options.readOnly = ! showingCurrent;
+          cm.refresh();
+        });
+
         setTimeout(function () {
         setTimeout(function () {
           cm.refresh()
           cm.refresh()
         }, 401); //CM invis bug workaround
         }, 401); //CM invis bug workaround
@@ -124,6 +139,7 @@ function launchModal(modal, data) {
           multiple: false,
           multiple: false,
           onComplete: function (id, fileName, response) {
           onComplete: function (id, fileName, response) {
             data.content.reload();
             data.content.reload();
+            data.value(data.content.value);
           }
           }
         });
         });
       }
       }
@@ -158,12 +174,49 @@ function launchModal(modal, data) {
   logGA(modal.slice(0, modal.indexOf('_modal') != -1 ? modal.indexOf('_modal') : modal.length));
   logGA(modal.slice(0, modal.indexOf('_modal') != -1 ? modal.indexOf('_modal') : modal.length));
 }
 }
 
 
+function showFullEditor(cellContent) {
+  var currentValue = ko.isObservable(cellContent.value) ? cellContent.value() : cellContent.value;
+  launchModal('cell_edit_modal', {
+    originalValue: currentValue,
+    currentValue: ko.observable(currentValue),
+    value: ko.observable(currentValue),
+    showingCurrent: ko.observable(true),
+    readOnly: ko.observable(false),
+    timestamp: ko.observable(cellContent.timestamp),
+    content: cellContent,
+    mime: detectMimeType(currentValue),
+
+    updateCodeMirror: function() {
+      if (this.codeMirror) {
+        this.codeMirror.setValue(this.value());
+        this.codeMirror.refresh()
+      }
+    },
+
+    switchToHistorical: function(item) {
+      if (this.showingCurrent()) {
+        this.currentValue(this.value());
+      }
+      this.value(item.value);
+      this.updateCodeMirror();
+      this.showingCurrent(false);
+      this.timestamp(item.timestamp)
+    },
+
+    switchToCurrent: function() {
+      if (!this.showingCurrent()) {
+        this.value(this.currentValue());
+        this.showingCurrent(true);
+        this.timestamp(this.content.timestamp);
+        this.updateCodeMirror();
+      }
+    }
+  });
+}
+
 function editCell($data) {
 function editCell($data) {
   if ($data.value().length > 146) {
   if ($data.value().length > 146) {
-    launchModal('cell_edit_modal', {
-      content: $data,
-      mime: detectMimeType($data.value())
-    });
+    showFullEditor($data);
   } else {
   } else {
     $data.editing(true);
     $data.editing(true);
   }
   }

+ 17 - 12
apps/hbase/src/hbase/templates/app.mako

@@ -95,7 +95,7 @@ ${ commonheader(None, "hbase", user) | n,unicode }
             % if can_write:
             % if can_write:
               <a class="corner-btn btn" data-bind="click: $data.drop, clickBubble: false"><i class="fa fa-trash-o"></i></a>
               <a class="corner-btn btn" data-bind="click: $data.drop, clickBubble: false"><i class="fa fa-trash-o"></i></a>
             % endif
             % endif
-            <a class="corner-btn btn" data-bind="event: { mousedown: function(){launchModal('cell_edit_modal', {content:$data, mime: detectMimeType($data.value())})} }"><i class="fa fa-pencil"></i> ${_('Full Editor')}</a>
+            <a class="corner-btn btn" data-bind="event: { mousedown: function(){ showFullEditor($data) } }"><i class="fa fa-pencil"></i> ${_('Full Editor')}</a>
             <pre data-bind="text: ($data.value().length > 146 ? $data.value().substring(0, 144) + '...' : $data.value()).replace(/(\r\n|\n|\r)/gm,''), click: editCell.bind(null, $data), clickBubble: false, visible: ! $data.isLoading() && ! $data.editing()"></pre>
             <pre data-bind="text: ($data.value().length > 146 ? $data.value().substring(0, 144) + '...' : $data.value()).replace(/(\r\n|\n|\r)/gm,''), click: editCell.bind(null, $data), clickBubble: false, visible: ! $data.isLoading() && ! $data.editing()"></pre>
             <textarea data-bind="visible: !$data.isLoading() && $data.editing(), disable: ! app.views.tabledata.canWrite(), hasfocus: $data.editing, value: $data.value, click:function(){}, clickBubble: false"></textarea>
             <textarea data-bind="visible: !$data.isLoading() && $data.editing(), disable: ! app.views.tabledata.canWrite(), hasfocus: $data.editing, value: $data.value, click:function(){}, clickBubble: false"></textarea>
             <img src="${ static('desktop/art/spinner.gif') }" data-bind="visible: $data.isLoading() " />
             <img src="${ static('desktop/art/spinner.gif') }" data-bind="visible: $data.isLoading() " />
@@ -365,7 +365,7 @@ ${ commonheader(None, "hbase", user) | n,unicode }
     <script id="cell_edit_modal_template" type="text/html">
     <script id="cell_edit_modal_template" type="text/html">
       <div class="modal-header">
       <div class="modal-header">
         <a class="close pointer" data-dismiss="modal" aria-hidden="true">&times;</a>
         <a class="close pointer" data-dismiss="modal" aria-hidden="true">&times;</a>
-        <h3>${_('Edit Cell')} - <span data-bind="text: content.name || formatTimestamp(content.timestamp)"></span> <code data-bind="text: mime, visible: mime !== 'type/null'"></code> <small><i class="fa fa-clock-o"></i> <span data-bind="text: formatTimestamp($data.content.timestamp)"></span></small></h3>
+        <h3>${_('Edit Cell')} - <span data-bind="text: content.name || formatTimestamp(timestamp())"></span> <code data-bind="text: mime, visible: mime !== 'type/null'"></code> <small><i class="fa fa-clock-o"></i> <span data-bind="text: formatTimestamp(timestamp())"></span></small></h3>
       </div>
       </div>
       <div class="modal-body container-fluid">
       <div class="modal-body container-fluid">
           <div class="row-fluid">
           <div class="row-fluid">
@@ -382,8 +382,9 @@ ${ commonheader(None, "hbase", user) | n,unicode }
             <div class="span3">
             <div class="span3">
               <ul class="nav nav-list cell-history">
               <ul class="nav nav-list cell-history">
                 <li class="nav-header">${_('Cell History:')}</li>
                 <li class="nav-header">${_('Cell History:')}</li>
+                <li data-bind="css: { 'active': showingCurrent }"><a data-bind="click: switchToCurrent()" class="pointer">${_('Current Version')}<span data-bind="if: (originalValue !== value() && showingCurrent()) || (originalValue !== currentValue() && !showingCurrent())"> (${_('Edited')})</span></a></li>
                 <!-- ko foreach: $data.content.history.items() -->
                 <!-- ko foreach: $data.content.history.items() -->
-                  <li data-bind="css: { 'active': $data.timestamp == $parent.content.timestamp }"><a data-bind="click: $parent.content.history.pickHistory.bind(null, $data), text: formatTimestamp($data.timestamp)" class="pointer"></a></li>
+                  <li data-bind="css: { 'active': $data.timestamp == $parent.timestamp() }"><a data-bind="click: function() { $root.switchToHistorical($data) }, text: formatTimestamp($data.timestamp)" class="pointer"></a></li>
                 <!-- /ko -->
                 <!-- /ko -->
                 <li data-bind="visible: $data.content.history.loading()"><img src="${ static('desktop/art/spinner.gif') }" /></li>
                 <li data-bind="visible: $data.content.history.loading()"><img src="${ static('desktop/art/spinner.gif') }" /></li>
               </ul>
               </ul>
@@ -391,31 +392,35 @@ ${ commonheader(None, "hbase", user) | n,unicode }
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
-      <div class="modal-footer" data-bind="if: ! $data.readonly">
-        % if can_write:
+      <div class="modal-footer">
+        <!-- ko if: showingCurrent -->
           <button class="btn" data-dismiss="modal" aria-hidden="true">${_('Cancel')}</button>
           <button class="btn" data-dismiss="modal" aria-hidden="true">${_('Cancel')}</button>
           <a id="file-upload-btn" class="btn fileChooserBtn" aria-hidden="true"><i class="fa fa-upload"></i> ${_('Upload')}</a>
           <a id="file-upload-btn" class="btn fileChooserBtn" aria-hidden="true"><i class="fa fa-upload"></i> ${_('Upload')}</a>
           <input data-bind="visible: mime.split('/')[0].toLowerCase() != 'application' && mime.split('/')[0].toLowerCase() != 'image'" type="submit" class="btn btn-primary" value="${_('Save')}">
           <input data-bind="visible: mime.split('/')[0].toLowerCase() != 'application' && mime.split('/')[0].toLowerCase() != 'image'" type="submit" class="btn btn-primary" value="${_('Save')}">
-        % else:
-          <button class="btn" data-dismiss="modal" aria-hidden="true">${_('OK')}</button>
-        % endif
+        <!-- /ko -->
+        <!-- ko ifnot: showingCurrent -->
+          <button class="btn" data-dismiss="modal" aria-hidden="true">${_('Cancel')}</button>
+          <input type="submit" class="btn btn-primary" value="${_('Revert')}">
+        <!-- /ko -->
       </div>
       </div>
     </script>
     </script>
 
 
     <script id="cell_image_template" type="text/html">
     <script id="cell_image_template" type="text/html">
-      <img data-bind="attr: {src: 'data:image/' + $data.mime + ';base64,' + $data.content.value()}"/>
+      <img data-bind="attr: {src: 'data:image/' + $data.mime + ';base64,' + value()}"/>
+      <input type="hidden" data-bind="value: value"/>
     </script>
     </script>
 
 
     <script id="cell_text_template" type="text/html">
     <script id="cell_text_template" type="text/html">
-      <textarea id="codemirror_target" data-bind="text: $data.content.value, disable: ! app.views.tabledata.canWrite()" data-use-post="true"></textarea>
+      <textarea id="codemirror_target" data-bind="text: value, disable: !showingCurrent()" data-use-post="true"></textarea>
     </script>
     </script>
 
 
     <script id="cell_application_template" type="text/html">
     <script id="cell_application_template" type="text/html">
-      <iframe width="100%" height="100%" data-bind="attr: {src: 'data:' + $data.mime + ';base64,' + $data.content.value()}"></iframe>
+      <iframe width="100%" height="100%" data-bind="attr: {src: 'data:' + $data.mime + ';base64,' + value()}"></iframe>
+      <input type="hidden" data-bind="value: value"/>
     </script>
     </script>
 
 
     <script id="cell_type_template" type="text/html">
     <script id="cell_type_template" type="text/html">
-      <textarea style="width:100%; height: 450px;" data-bind="text: $data.content.value, disable: ! app.views.tabledata.canWrite()" data-use-post="true"></textarea>
+      <textarea style="width:100%; height: 450px;" data-bind="textInput: value, disable: !showingCurrent()" data-use-post="true"></textarea>
     </script>
     </script>
   </div>
   </div>