Procházet zdrojové kódy

HUE-1311 [fb] Editing a file corrupt it in some way

Removing CRLF line terminators when saving a file
Added some icon in view file
Added popup in save as a new file
Romain Rigaux před 12 roky
rodič
revize
e2b4073

+ 3 - 0
apps/filebrowser/src/filebrowser/forms.py

@@ -63,6 +63,9 @@ class EditorForm(forms.Form):
   contents = CharField(widget=Textarea, label=_("Contents"), required=False)
   contents = CharField(widget=Textarea, label=_("Contents"), required=False)
   encoding = CharField(label=_('Encoding'), required=False)
   encoding = CharField(label=_('Encoding'), required=False)
 
 
+  def clean_contents(self):
+    return self.cleaned_data.get('contents', '').replace('\r\n', '\n')
+
   def clean_encoding(self):
   def clean_encoding(self):
     encoding = self.cleaned_data.get('encoding', '').strip()
     encoding = self.cleaned_data.get('encoding', '').strip()
     if not encoding:
     if not encoding:

+ 10 - 9
apps/filebrowser/src/filebrowser/templates/display.mako

@@ -45,32 +45,33 @@ ${ commonheader(_('%(filename)s - File Viewer') % dict(filename=truncate(filenam
         <ul class="nav nav-list">
         <ul class="nav nav-list">
           <li class="nav-header">${_('Actions')}</li>
           <li class="nav-header">${_('Actions')}</li>
           % if view['mode'] == "binary":
           % if view['mode'] == "binary":
-            <li><a href="${base_url}?offset=${view['offset']}&length=${view['length']}&mode=text&compression=${view['compression']}">${_('View as text')}</a></li>
+            <li><a href="${base_url}?offset=${view['offset']}&length=${view['length']}&mode=text&compression=${view['compression']}"><i class="icon-icon-font"></i> ${_('View as text')}</a></li>
           % endif
           % endif
 
 
           % if view['mode'] == "text":
           % if view['mode'] == "text":
-            <li><a href="${base_url}?offset=${view['offset']}&length=${view['length']}&mode=binary&compression=${view['compression']}">${_('View as binary')}</a></li>
+            <li><a href="${base_url}?offset=${view['offset']}&length=${view['length']}&mode=binary&compression=${view['compression']}"><i class="icon-barcode"></i> ${_('View as binary')}</a></li>
           % endif
           % endif
 
 
           % if view['compression'] != "gzip" and path.endswith('.gz'):
           % if view['compression'] != "gzip" and path.endswith('.gz'):
-            <li><a href="${base_url}?offset=0&length=2000&mode=${view['mode']}&compression=gzip">${_('Preview as Gzip')}</a></li>
+            <li><a href="${base_url}?offset=0&length=2000&mode=${view['mode']}&compression=gzip"><i class="icon-youtube-play"></i> ${_('Preview as Gzip')}</a></li>
           % endif
           % endif
 
 
           % if view['compression'] != "avro" and view['compression'] != "snappy_avro" and path.endswith('.avro'):
           % if view['compression'] != "avro" and view['compression'] != "snappy_avro" and path.endswith('.avro'):
-            <li><a href="${base_url}?offset=0&length=2000&mode=${view['mode']}&compression=avro">${_('Preview as Avro')}</a></li>
+            <li><a href="${base_url}?offset=0&length=2000&mode=${view['mode']}&compression=avro"><i class="icon-youtube-play"></i> ${_('Preview as Avro')}</a></li>
           % endif
           % endif
 
 
           % if view['compression'] and view['compression'] != "none":
           % if view['compression'] and view['compression'] != "none":
-            <li><a href="${base_url}?offset=0&length=2000&mode=${view['mode']}&compression=none">${_('Stop preview')}</a></li>
+            <li><a href="${base_url}?offset=0&length=2000&mode=${view['mode']}&compression=none"><i class="icon-remove-circle"></i> ${_('Stop preview')}</a></li>
           % endif
           % endif
 
 
           % if editable and view['compression'] == "none":
           % if editable and view['compression'] == "none":
-            <li><a href="${url('filebrowser.views.edit', path=path_enc)}">${_('Edit file')}</a></li>
+            <li><a href="${url('filebrowser.views.edit', path=path_enc)}"><i class="icon-pencil"></i> ${_('Edit file')}</a></li>
           % endif
           % endif
 
 
-           <li><a href="${url('filebrowser.views.download', path=path_enc)}">${_('Download')}</a></li>
-           <li><a href="${url('filebrowser.views.view', path=dirname_enc)}">${_('View file location')}</a></li>
-           <li><a id="refreshBtn">${_('Refresh')}</a></li>
+           <li><a href="${url('filebrowser.views.download', path=path_enc)}"><i class="icon-download-alt"></i> ${_('Download')}</a></li>
+           <li><a href="${url('filebrowser.views.view', path=dirname_enc)}"><i class="icon-file-text"></i> ${_('View file location')}</a></li>
+           <li><a id="refreshBtn"><i class="icon-refresh"></i> ${_('Refresh')}</a></li>
+
           <li class="nav-header">${_('Info')}</li>
           <li class="nav-header">${_('Info')}</li>
           <li>
           <li>
             <dl>
             <dl>

+ 32 - 12
apps/filebrowser/src/filebrowser/templates/edit.mako

@@ -13,34 +13,38 @@
 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ## See the License for the specific language governing permissions and
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ## limitations under the License.
-<%namespace name="edit" file="editor_components.mako" />
+
 <%!
 <%!
   from django.template.defaultfilters import urlencode
   from django.template.defaultfilters import urlencode
   from filebrowser.views import truncate
   from filebrowser.views import truncate
   from desktop.views import commonheader, commonfooter
   from desktop.views import commonheader, commonfooter
   from django.utils.translation import ugettext as _
   from django.utils.translation import ugettext as _
 %>
 %>
+
 <%
 <%
   path_enc = urlencode(path)
   path_enc = urlencode(path)
   dirname_enc = urlencode(dirname)
   dirname_enc = urlencode(dirname)
 %>
 %>
+
+<%namespace name="edit" file="editor_components.mako" />
 <%namespace name="fb_components" file="fb_components.mako" />
 <%namespace name="fb_components" file="fb_components.mako" />
 
 
 ${ commonheader(_('%(filename)s - File Viewer') % dict(filename=truncate(filename)), 'filebrowser', user) | n,unicode }
 ${ commonheader(_('%(filename)s - File Viewer') % dict(filename=truncate(filename)), 'filebrowser', user) | n,unicode }
 
 
+
 <div class="container-fluid">
 <div class="container-fluid">
-	% if breadcrumbs:
+    % if breadcrumbs:
         ${fb_components.breadcrumbs(path, breadcrumbs)}
         ${fb_components.breadcrumbs(path, breadcrumbs)}
-	%endif
+    %endif
 </div>
 </div>
 
 
 <div class="container-fluid">
 <div class="container-fluid">
 <div class="well" >
 <div class="well" >
     <form class="form-stacked" method="post" action="${url('filebrowser.views.save_file')}">
     <form class="form-stacked" method="post" action="${url('filebrowser.views.save_file')}">
     <div class="toolbar">
     <div class="toolbar">
-		<a class="btn" href="${url('filebrowser.views.view', path=dirname_enc)}">${_('Browse location')}</a>
-	</div>
-	<br/>
+        <a class="btn" href="${url('filebrowser.views.view', path=dirname_enc)}"><i class="icon-file-text"></i> ${_('Browse location')}</a>
+    </div>
+    <br/>
 
 
 % if form.errors:
 % if form.errors:
   <div class="alert-message">
   <div class="alert-message">
@@ -69,15 +73,17 @@ ${ commonheader(_('%(filename)s - File Viewer') % dict(filename=truncate(filenam
         <h3>${_('Save as')}</h3>
         <h3>${_('Save as')}</h3>
     </div>
     </div>
     <div class="modal-body">
     <div class="modal-body">
-		${edit.render_field(form["path"], notitle=True, klass="xlarge")}
-		<span class="help-block">${_("Enter the location where you'd like to save the file.")}</span>
+        <span class="help-block">${_("Enter the location where you would like to save the file.")}</span>
+        ${ edit.render_field(form["path"], notitle=True, nolabel=True, klass="pathChooser input-xxlarge") }
+        <br/>
+        <div id="fileChooserSaveModal" class="hide"></div>
     </div>
     </div>
     <div class="modal-footer">
     <div class="modal-footer">
         <div id="saveAsNameRequiredAlert" class="alert-message error hide" style="position: absolute; left: 10;">
         <div id="saveAsNameRequiredAlert" class="alert-message error hide" style="position: absolute; left: 10;">
             <p><strong>${_('Name is required.')}</strong>
             <p><strong>${_('Name is required.')}</strong>
         </div>
         </div>
-		${edit.render_field(form["contents"], hidden=True)}
-		${edit.render_field(form["encoding"], hidden=True)}
+        ${edit.render_field(form["contents"], hidden=True)}
+        ${edit.render_field(form["encoding"], hidden=True)}
         <a id="cancelSaveAsBtn" class="btn">${_('Cancel')}</a>
         <a id="cancelSaveAsBtn" class="btn">${_('Cancel')}</a>
         <input type="submit" value="${_('Save')}" class="btn btn-primary" />
         <input type="submit" value="${_('Save')}" class="btn btn-primary" />
     </div>
     </div>
@@ -112,9 +118,23 @@ ${ commonheader(_('%(filename)s - File Viewer') % dict(filename=truncate(filenam
         $(this).removeClass("fieldError");
         $(this).removeClass("fieldError");
         $("#saveAsNameRequiredAlert").hide();
         $("#saveAsNameRequiredAlert").hide();
       });
       });
+
+      $(".pathChooser").click(function() {
+        var self = this;
+        $("#fileChooserSaveModal").jHueFileChooser({
+          initialPath:$(self).val(),
+          onFileChoose:function (filePath) {
+            $(self).val(filePath);
+          },
+          onFolderChange:function (folderPath) {
+            $(self).val(folderPath);
+          },
+          createFolder:false,
+          uploadFile:false
+        });
+        $("#fileChooserSaveModal").slideDown();
+      });
     });
     });
   </script>
   </script>
 
 
 ${ commonfooter(messages) | n,unicode }
 ${ commonfooter(messages) | n,unicode }
-
-

+ 4 - 2
apps/filebrowser/src/filebrowser/templates/saveas.mako

@@ -13,9 +13,11 @@
 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ## See the License for the specific language governing permissions and
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ## limitations under the License.
+
 <%namespace name="edit" file="editor_components.mako" />
 <%namespace name="edit" file="editor_components.mako" />
+
 <html>
 <html>
-  <head><title>Save File As...</title></head>
+  <head><title>${ _('Save File As...') }</title></head>
   <body>
   <body>
     % if form.errors:
     % if form.errors:
       <div class="alert_popup">
       <div class="alert_popup">
@@ -28,7 +30,7 @@
     % endif
     % endif
     <div class="saveAsPrompt_popup">
     <div class="saveAsPrompt_popup">
       <form method="post" action="${url('filebrowser.views.save_file')}">
       <form method="post" action="${url('filebrowser.views.save_file')}">
-          Please enter the location where you'd like to save the file.
+          ${ _('Please enter the location where you'd like to save the file.') }
           ${edit.render_field(form["path"], notitle=True)}
           ${edit.render_field(form["path"], notitle=True)}
           <div>${edit.render_field(form["contents"], hidden=True)}</div>
           <div>${edit.render_field(form["contents"], hidden=True)}</div>
           <div>${edit.render_field(form["encoding"], hidden=True)}</div>
           <div>${edit.render_field(form["encoding"], hidden=True)}</div>

+ 2 - 4
apps/filebrowser/src/filebrowser/views.py

@@ -232,11 +232,10 @@ def save_file(request):
         if not is_valid:
         if not is_valid:
             return edit(request, path, form=form)
             return edit(request, path, form=form)
         else:
         else:
-            data = dict(form=form)
-            return render("saveas.mako", request, data)
+            return render("saveas.mako", request, {'form': form})
 
 
     if not path:
     if not path:
-        raise PopupException("No path specified")
+        raise PopupException(_("No path specified"))
     if not is_valid:
     if not is_valid:
         return edit(request, path, form=form)
         return edit(request, path, form=form)
 
 
@@ -250,7 +249,6 @@ def save_file(request):
                          form.cleaned_data['encoding'])
                          form.cleaned_data['encoding'])
 
 
     messages.info(request, _('Saved %(path)s.') % {'path': os.path.basename(path)})
     messages.info(request, _('Saved %(path)s.') % {'path': os.path.basename(path)})
-    """ Changing path to reflect the request path of the JFrame that will actually be returned."""
     request.path = urlresolvers.reverse("filebrowser.views.edit", kwargs=dict(path=path))
     request.path = urlresolvers.reverse("filebrowser.views.edit", kwargs=dict(path=path))
     return edit(request, path, form)
     return edit(request, path, form)
 
 

+ 2 - 0
apps/filebrowser/src/filebrowser/views_test.py

@@ -941,6 +941,7 @@ def edit_helper(cluster, encoding, contents_pass_1, contents_pass_2):
     # And its contents should be what we expect
     # And its contents should be what we expect
     f = cluster.fs.open(filename)
     f = cluster.fs.open(filename)
     assert_equal(f.read(), contents_pass_1.encode(encoding))
     assert_equal(f.read(), contents_pass_1.encode(encoding))
+    assert_false('\r\n' in f.read()) # No CRLF line terminators
     f.close()
     f.close()
 
 
     # We should be able to overwrite the file with another save
     # We should be able to overwrite the file with another save
@@ -952,6 +953,7 @@ def edit_helper(cluster, encoding, contents_pass_1, contents_pass_2):
     assert_equal(response.context['form'].data['contents'], contents_pass_2)
     assert_equal(response.context['form'].data['contents'], contents_pass_2)
     f = cluster.fs.open(filename)
     f = cluster.fs.open(filename)
     assert_equal(f.read(), contents_pass_2.encode(encoding))
     assert_equal(f.read(), contents_pass_2.encode(encoding))
+    assert_false('\r\n' in f.read()) # No CRLF line terminators
     f.close()
     f.close()
 
 
     # TODO(todd) add test for maintaining ownership/permissions
     # TODO(todd) add test for maintaining ownership/permissions