Przeglądaj źródła

HUE-206 [fb] Browsing a large directory slow for IE

Adding pagination
Merged bc's backend pagination and i18n'ed it.
Romain: fixed merge bug + set default items by page to 30
Enrico Berti 13 lat temu
rodzic
commit
a4f4208

+ 110 - 73
apps/filebrowser/src/filebrowser/locale/django.pot

@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PROJECT VERSION\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2012-07-11 03:53+0200\n"
+"POT-Creation-Date: 2012-07-16 23:56+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -38,7 +38,7 @@ msgid "The file to rename."
 msgstr ""
 
 #: src/filebrowser/forms.py:54
-#: src/filebrowser/templates/listdir_components.mako:160
+#: src/filebrowser/templates/listdir_components.mako:185
 msgid "New name"
 msgstr ""
 
@@ -75,7 +75,7 @@ msgid "Path in which to create the directory"
 msgstr ""
 
 #: src/filebrowser/forms.py:77
-#: src/filebrowser/templates/listdir_components.mako:202
+#: src/filebrowser/templates/listdir_components.mako:227
 msgid "Directory Name"
 msgstr ""
 
@@ -86,14 +86,14 @@ msgstr ""
 #: src/filebrowser/forms.py:84 src/filebrowser/templates/chmod.mako:40
 #: src/filebrowser/templates/chown.mako:71
 #: src/filebrowser/templates/display.mako:77
-#: src/filebrowser/templates/listdir_components.mako:63
+#: src/filebrowser/templates/listdir_components.mako:81
 msgid "User"
 msgstr ""
 
 #: src/filebrowser/forms.py:86 src/filebrowser/templates/chmod.mako:41
 #: src/filebrowser/templates/chown.mako:79
 #: src/filebrowser/templates/display.mako:79
-#: src/filebrowser/templates/listdir_components.mako:64
+#: src/filebrowser/templates/listdir_components.mako:82
 msgid "Group"
 msgstr ""
 
@@ -101,130 +101,130 @@ msgstr ""
 msgid "Path to change permissions"
 msgstr ""
 
-#: src/filebrowser/views.py:93 src/filebrowser/views.py:366
-#: src/filebrowser/views.py:394
+#: src/filebrowser/views.py:95 src/filebrowser/views.py:442
+#: src/filebrowser/views.py:470
 #, python-format
 msgid "File not found: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:95
+#: src/filebrowser/views.py:97
 #, python-format
 msgid "'%(path)s' is not a file"
 msgstr ""
 
-#: src/filebrowser/views.py:130
+#: src/filebrowser/views.py:132
 #, python-format
 msgid "Cannot access: %(path)s."
 msgstr ""
 
-#: src/filebrowser/views.py:132 src/filebrowser/views.py:674
+#: src/filebrowser/views.py:134 src/filebrowser/views.py:750
 #, python-format
 msgid ""
 " Note: you are a Hue admin but not a HDFS superuser (which is "
 "\"%(superuser)s\")."
 msgstr ""
 
-#: src/filebrowser/views.py:150
+#: src/filebrowser/views.py:152
 #, python-format
 msgid "Cannot edit a directory: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:154
+#: src/filebrowser/views.py:156
 #, python-format
 msgid "File too big to edit: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:164
+#: src/filebrowser/views.py:166
 #, python-format
 msgid "File is not encoded in %(encoding)s; cannot be edited: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:213
+#: src/filebrowser/views.py:215
 #, python-format
 msgid "Saved %(path)s."
 msgstr ""
 
-#: src/filebrowser/views.py:308
+#: src/filebrowser/views.py:310
 #, python-format
 msgid "Not a directory: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:415
+#: src/filebrowser/views.py:491
 #, python-format
 msgid "Not a file: '%(path)s'"
 msgstr ""
 
-#: src/filebrowser/views.py:437
+#: src/filebrowser/views.py:513
 msgid "First byte to display must be before last byte to display."
 msgstr ""
 
-#: src/filebrowser/views.py:447
+#: src/filebrowser/views.py:523
 msgid "Mode must be one of 'binary' or 'text'."
 msgstr ""
 
-#: src/filebrowser/views.py:449
+#: src/filebrowser/views.py:525
 msgid "Offset may not be less than zero."
 msgstr ""
 
-#: src/filebrowser/views.py:451
+#: src/filebrowser/views.py:527
 msgid "Length may not be less than zero."
 msgstr ""
 
-#: src/filebrowser/views.py:453
+#: src/filebrowser/views.py:529
 #, python-format
 msgid "Cannot request chunks greater than %(bytes)d bytes"
 msgstr ""
 
-#: src/filebrowser/views.py:564
+#: src/filebrowser/views.py:640
 msgid "Failed to read Avro file"
 msgstr ""
 
-#: src/filebrowser/views.py:573
+#: src/filebrowser/views.py:649
 msgid "We don't support offset and gzip Compression"
 msgstr ""
 
-#: src/filebrowser/views.py:580
+#: src/filebrowser/views.py:656
 msgid "Failed to decompress file"
 msgstr ""
 
-#: src/filebrowser/views.py:595
+#: src/filebrowser/views.py:671
 msgid "Failed to read file"
 msgstr ""
 
-#: src/filebrowser/views.py:623 src/filebrowser/views.py:625
+#: src/filebrowser/views.py:699 src/filebrowser/views.py:701
 #: src/filebrowser/templates/display.mako:119
 #: src/filebrowser/templates/display.mako:199
 msgid "First Block"
 msgstr ""
 
-#: src/filebrowser/views.py:623 src/filebrowser/views.py:625
+#: src/filebrowser/views.py:699 src/filebrowser/views.py:701
 #: src/filebrowser/templates/display.mako:120
 #: src/filebrowser/templates/display.mako:200
 msgid "Previous Block"
 msgstr ""
 
-#: src/filebrowser/views.py:628 src/filebrowser/views.py:631
+#: src/filebrowser/views.py:704 src/filebrowser/views.py:707
 #: src/filebrowser/templates/display.mako:121
 #: src/filebrowser/templates/display.mako:201
 msgid "Next Block"
 msgstr ""
 
-#: src/filebrowser/views.py:628 src/filebrowser/views.py:631
+#: src/filebrowser/views.py:704 src/filebrowser/views.py:707
 #: src/filebrowser/templates/display.mako:122
 #: src/filebrowser/templates/display.mako:202
 msgid "Last Block"
 msgstr ""
 
-#: src/filebrowser/views.py:672
+#: src/filebrowser/views.py:748
 msgid "Cannot perform operation."
 msgstr ""
 
-#: src/filebrowser/views.py:818
+#: src/filebrowser/views.py:894
 #, python-format
 msgid "Failed to chown uploaded file (\"%(file)s\") as superuser %(superuser)s"
 msgstr ""
 
-#: src/filebrowser/views.py:830
+#: src/filebrowser/views.py:906
 #, python-format
 msgid ""
 "Failed to rename uploaded temporary file (\"%(file)s\") to \"%(name)s\": "
@@ -253,8 +253,8 @@ msgstr ""
 
 #: src/filebrowser/templates/chmod.mako:72
 #: src/filebrowser/templates/chown.mako:94
-#: src/filebrowser/templates/listdir_components.mako:168
-#: src/filebrowser/templates/listdir_components.mako:209
+#: src/filebrowser/templates/listdir_components.mako:193
+#: src/filebrowser/templates/listdir_components.mako:234
 #: src/filebrowser/templates/move.mako:40
 msgid "Submit"
 msgstr ""
@@ -262,9 +262,9 @@ msgstr ""
 #: src/filebrowser/templates/chmod.mako:73
 #: src/filebrowser/templates/chown.mako:95
 #: src/filebrowser/templates/edit.mako:82
-#: src/filebrowser/templates/listdir_components.mako:169
-#: src/filebrowser/templates/listdir_components.mako:210
-#: src/filebrowser/templates/listdir_components.mako:298
+#: src/filebrowser/templates/listdir_components.mako:194
+#: src/filebrowser/templates/listdir_components.mako:235
+#: src/filebrowser/templates/listdir_components.mako:323
 #: src/filebrowser/templates/move.mako:41
 #: src/filebrowser/templates/upload.mako:54
 msgid "Cancel"
@@ -283,7 +283,7 @@ msgstr ""
 
 #: src/filebrowser/templates/chown.mako:92
 #: src/filebrowser/templates/edit.mako:77
-#: src/filebrowser/templates/listdir_components.mako:164
+#: src/filebrowser/templates/listdir_components.mako:189
 #: src/filebrowser/templates/move.mako:38
 msgid "Sorry, name is required."
 msgstr ""
@@ -335,7 +335,7 @@ msgid "Stop preview"
 msgstr ""
 
 #: src/filebrowser/templates/display.mako:67
-#: src/filebrowser/templates/listdir_components.mako:118
+#: src/filebrowser/templates/listdir_components.mako:136
 msgid "Edit File"
 msgstr ""
 
@@ -360,7 +360,7 @@ msgid "Last Modified"
 msgstr ""
 
 #: src/filebrowser/templates/display.mako:81
-#: src/filebrowser/templates/listdir_components.mako:62
+#: src/filebrowser/templates/listdir_components.mako:80
 msgid "Size"
 msgstr ""
 
@@ -399,7 +399,23 @@ msgstr ""
 msgid "Please enter the location where you'd like to save the file."
 msgstr ""
 
-#: src/filebrowser/templates/fb_components.mako:24
+#: src/filebrowser/templates/fb_components.mako:30
+msgid "Upload files"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:31
+msgid "New directory"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:33
+msgid "Search for file name"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:34
+msgid "Search"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:38
 msgid "Home"
 msgstr ""
 
@@ -409,126 +425,147 @@ msgstr ""
 
 #: src/filebrowser/templates/listdir.mako:26
 #: src/filebrowser/templates/listdir.mako:28
+#: src/filebrowser/templates/listdir_paged.mako:26
+#: src/filebrowser/templates/listdir_paged.mako:28
 msgid "File Browser"
 msgstr ""
 
+#: src/filebrowser/templates/listdir_components.mako:44
+msgid "Beginning of List"
+msgstr ""
+
+#: src/filebrowser/templates/listdir_components.mako:45
+msgid "Previous Page"
+msgstr ""
+
 #: src/filebrowser/templates/listdir_components.mako:46
-msgid "Upload files"
+msgid "Next page"
+msgstr ""
+
+#: src/filebrowser/templates/listdir_components.mako:46
+msgid "Next Page"
 msgstr ""
 
 #: src/filebrowser/templates/listdir_components.mako:47
-msgid "New directory"
+msgid "End of List"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:50
-msgid "Filter: "
+#: src/filebrowser/templates/listdir_components.mako:49
+msgid "Show"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:50
-msgid "Search for file name"
+#: src/filebrowser/templates/listdir_components.mako:49
+msgid "items per page"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:58
+#: src/filebrowser/templates/listdir_components.mako:49
+#, python-format
+msgid ""
+"Showing %(start_index)s to %(end_index)s of %(total_count)s items, page "
+"%(page)s of %(num_pages)s."
+msgstr ""
+
+#: src/filebrowser/templates/listdir_components.mako:76
 msgid "Name"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:60
+#: src/filebrowser/templates/listdir_components.mako:78
 msgid "Path"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:65
+#: src/filebrowser/templates/listdir_components.mako:83
 msgid "Permissions"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:66
+#: src/filebrowser/templates/listdir_components.mako:84
 msgid "Date"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:108
+#: src/filebrowser/templates/listdir_components.mako:126
 msgid "Options"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:113
-#: src/filebrowser/templates/listdir_components.mako:116
+#: src/filebrowser/templates/listdir_components.mako:131
+#: src/filebrowser/templates/listdir_components.mako:134
 msgid "Delete"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:114
+#: src/filebrowser/templates/listdir_components.mako:132
 msgid "Delete Recursively"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:117
+#: src/filebrowser/templates/listdir_components.mako:135
 msgid "View File"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:119
+#: src/filebrowser/templates/listdir_components.mako:137
 msgid "Download File"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:121
+#: src/filebrowser/templates/listdir_components.mako:139
 msgid "Rename"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:122
+#: src/filebrowser/templates/listdir_components.mako:140
 msgid "Change Owner / Group"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:123
+#: src/filebrowser/templates/listdir_components.mako:141
 msgid "Change Permissions"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:124
+#: src/filebrowser/templates/listdir_components.mako:142
 msgid "Move"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:138
+#: src/filebrowser/templates/listdir_components.mako:163
 msgid "Please Confirm"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:141
+#: src/filebrowser/templates/listdir_components.mako:166
 msgid "Are you sure you want to delete this file?"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:145
+#: src/filebrowser/templates/listdir_components.mako:170
 msgid "Yes"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:146
+#: src/filebrowser/templates/listdir_components.mako:171
 msgid "No"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:157
+#: src/filebrowser/templates/listdir_components.mako:182
 msgid "Renaming:"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:179
+#: src/filebrowser/templates/listdir_components.mako:204
 msgid "Uploading to:"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:185
+#: src/filebrowser/templates/listdir_components.mako:210
 #: src/filebrowser/templates/upload.mako:31
 msgid "Please enable JavaScript to use file uploader."
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:199
+#: src/filebrowser/templates/listdir_components.mako:224
 msgid "Create Directory"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:207
+#: src/filebrowser/templates/listdir_components.mako:232
 msgid "Sorry, directory name is required."
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:290
+#: src/filebrowser/templates/listdir_components.mako:315
 #: src/filebrowser/templates/upload.mako:46
 msgid "Drop files here to upload"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:291
+#: src/filebrowser/templates/listdir_components.mako:316
 #: src/filebrowser/templates/upload.mako:47
 msgid "Upload a file"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:299
+#: src/filebrowser/templates/listdir_components.mako:324
 #: src/filebrowser/templates/upload.mako:55
 msgid "Failed"
 msgstr ""

+ 110 - 73
apps/filebrowser/src/filebrowser/locale/en_US/LC_MESSAGES/django.po

@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PROJECT VERSION\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2012-07-11 03:53+0200\n"
+"POT-Creation-Date: 2012-07-16 23:56+0200\n"
 "PO-Revision-Date: 2012-07-02 23:32+0200\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: en_US <LL@li.org>\n"
@@ -38,7 +38,7 @@ msgid "The file to rename."
 msgstr ""
 
 #: src/filebrowser/forms.py:54
-#: src/filebrowser/templates/listdir_components.mako:160
+#: src/filebrowser/templates/listdir_components.mako:185
 msgid "New name"
 msgstr ""
 
@@ -75,7 +75,7 @@ msgid "Path in which to create the directory"
 msgstr ""
 
 #: src/filebrowser/forms.py:77
-#: src/filebrowser/templates/listdir_components.mako:202
+#: src/filebrowser/templates/listdir_components.mako:227
 msgid "Directory Name"
 msgstr ""
 
@@ -86,14 +86,14 @@ msgstr ""
 #: src/filebrowser/forms.py:84 src/filebrowser/templates/chmod.mako:40
 #: src/filebrowser/templates/chown.mako:71
 #: src/filebrowser/templates/display.mako:77
-#: src/filebrowser/templates/listdir_components.mako:63
+#: src/filebrowser/templates/listdir_components.mako:81
 msgid "User"
 msgstr ""
 
 #: src/filebrowser/forms.py:86 src/filebrowser/templates/chmod.mako:41
 #: src/filebrowser/templates/chown.mako:79
 #: src/filebrowser/templates/display.mako:79
-#: src/filebrowser/templates/listdir_components.mako:64
+#: src/filebrowser/templates/listdir_components.mako:82
 msgid "Group"
 msgstr ""
 
@@ -101,130 +101,130 @@ msgstr ""
 msgid "Path to change permissions"
 msgstr ""
 
-#: src/filebrowser/views.py:93 src/filebrowser/views.py:366
-#: src/filebrowser/views.py:394
+#: src/filebrowser/views.py:95 src/filebrowser/views.py:442
+#: src/filebrowser/views.py:470
 #, python-format
 msgid "File not found: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:95
+#: src/filebrowser/views.py:97
 #, python-format
 msgid "'%(path)s' is not a file"
 msgstr ""
 
-#: src/filebrowser/views.py:130
+#: src/filebrowser/views.py:132
 #, python-format
 msgid "Cannot access: %(path)s."
 msgstr ""
 
-#: src/filebrowser/views.py:132 src/filebrowser/views.py:674
+#: src/filebrowser/views.py:134 src/filebrowser/views.py:750
 #, python-format
 msgid ""
 " Note: you are a Hue admin but not a HDFS superuser (which is "
 "\"%(superuser)s\")."
 msgstr ""
 
-#: src/filebrowser/views.py:150
+#: src/filebrowser/views.py:152
 #, python-format
 msgid "Cannot edit a directory: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:154
+#: src/filebrowser/views.py:156
 #, python-format
 msgid "File too big to edit: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:164
+#: src/filebrowser/views.py:166
 #, python-format
 msgid "File is not encoded in %(encoding)s; cannot be edited: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:213
+#: src/filebrowser/views.py:215
 #, python-format
 msgid "Saved %(path)s."
 msgstr ""
 
-#: src/filebrowser/views.py:308
+#: src/filebrowser/views.py:310
 #, python-format
 msgid "Not a directory: %(path)s"
 msgstr ""
 
-#: src/filebrowser/views.py:415
+#: src/filebrowser/views.py:491
 #, python-format
 msgid "Not a file: '%(path)s'"
 msgstr ""
 
-#: src/filebrowser/views.py:437
+#: src/filebrowser/views.py:513
 msgid "First byte to display must be before last byte to display."
 msgstr ""
 
-#: src/filebrowser/views.py:447
+#: src/filebrowser/views.py:523
 msgid "Mode must be one of 'binary' or 'text'."
 msgstr ""
 
-#: src/filebrowser/views.py:449
+#: src/filebrowser/views.py:525
 msgid "Offset may not be less than zero."
 msgstr ""
 
-#: src/filebrowser/views.py:451
+#: src/filebrowser/views.py:527
 msgid "Length may not be less than zero."
 msgstr ""
 
-#: src/filebrowser/views.py:453
+#: src/filebrowser/views.py:529
 #, python-format
 msgid "Cannot request chunks greater than %(bytes)d bytes"
 msgstr ""
 
-#: src/filebrowser/views.py:564
+#: src/filebrowser/views.py:640
 msgid "Failed to read Avro file"
 msgstr ""
 
-#: src/filebrowser/views.py:573
+#: src/filebrowser/views.py:649
 msgid "We don't support offset and gzip Compression"
 msgstr ""
 
-#: src/filebrowser/views.py:580
+#: src/filebrowser/views.py:656
 msgid "Failed to decompress file"
 msgstr ""
 
-#: src/filebrowser/views.py:595
+#: src/filebrowser/views.py:671
 msgid "Failed to read file"
 msgstr ""
 
-#: src/filebrowser/views.py:623 src/filebrowser/views.py:625
+#: src/filebrowser/views.py:699 src/filebrowser/views.py:701
 #: src/filebrowser/templates/display.mako:119
 #: src/filebrowser/templates/display.mako:199
 msgid "First Block"
 msgstr ""
 
-#: src/filebrowser/views.py:623 src/filebrowser/views.py:625
+#: src/filebrowser/views.py:699 src/filebrowser/views.py:701
 #: src/filebrowser/templates/display.mako:120
 #: src/filebrowser/templates/display.mako:200
 msgid "Previous Block"
 msgstr ""
 
-#: src/filebrowser/views.py:628 src/filebrowser/views.py:631
+#: src/filebrowser/views.py:704 src/filebrowser/views.py:707
 #: src/filebrowser/templates/display.mako:121
 #: src/filebrowser/templates/display.mako:201
 msgid "Next Block"
 msgstr ""
 
-#: src/filebrowser/views.py:628 src/filebrowser/views.py:631
+#: src/filebrowser/views.py:704 src/filebrowser/views.py:707
 #: src/filebrowser/templates/display.mako:122
 #: src/filebrowser/templates/display.mako:202
 msgid "Last Block"
 msgstr ""
 
-#: src/filebrowser/views.py:672
+#: src/filebrowser/views.py:748
 msgid "Cannot perform operation."
 msgstr ""
 
-#: src/filebrowser/views.py:818
+#: src/filebrowser/views.py:894
 #, python-format
 msgid "Failed to chown uploaded file (\"%(file)s\") as superuser %(superuser)s"
 msgstr ""
 
-#: src/filebrowser/views.py:830
+#: src/filebrowser/views.py:906
 #, python-format
 msgid ""
 "Failed to rename uploaded temporary file (\"%(file)s\") to \"%(name)s\": "
@@ -253,8 +253,8 @@ msgstr ""
 
 #: src/filebrowser/templates/chmod.mako:72
 #: src/filebrowser/templates/chown.mako:94
-#: src/filebrowser/templates/listdir_components.mako:168
-#: src/filebrowser/templates/listdir_components.mako:209
+#: src/filebrowser/templates/listdir_components.mako:193
+#: src/filebrowser/templates/listdir_components.mako:234
 #: src/filebrowser/templates/move.mako:40
 msgid "Submit"
 msgstr ""
@@ -262,9 +262,9 @@ msgstr ""
 #: src/filebrowser/templates/chmod.mako:73
 #: src/filebrowser/templates/chown.mako:95
 #: src/filebrowser/templates/edit.mako:82
-#: src/filebrowser/templates/listdir_components.mako:169
-#: src/filebrowser/templates/listdir_components.mako:210
-#: src/filebrowser/templates/listdir_components.mako:298
+#: src/filebrowser/templates/listdir_components.mako:194
+#: src/filebrowser/templates/listdir_components.mako:235
+#: src/filebrowser/templates/listdir_components.mako:323
 #: src/filebrowser/templates/move.mako:41
 #: src/filebrowser/templates/upload.mako:54
 msgid "Cancel"
@@ -283,7 +283,7 @@ msgstr ""
 
 #: src/filebrowser/templates/chown.mako:92
 #: src/filebrowser/templates/edit.mako:77
-#: src/filebrowser/templates/listdir_components.mako:164
+#: src/filebrowser/templates/listdir_components.mako:189
 #: src/filebrowser/templates/move.mako:38
 msgid "Sorry, name is required."
 msgstr ""
@@ -335,7 +335,7 @@ msgid "Stop preview"
 msgstr ""
 
 #: src/filebrowser/templates/display.mako:67
-#: src/filebrowser/templates/listdir_components.mako:118
+#: src/filebrowser/templates/listdir_components.mako:136
 msgid "Edit File"
 msgstr ""
 
@@ -360,7 +360,7 @@ msgid "Last Modified"
 msgstr ""
 
 #: src/filebrowser/templates/display.mako:81
-#: src/filebrowser/templates/listdir_components.mako:62
+#: src/filebrowser/templates/listdir_components.mako:80
 msgid "Size"
 msgstr ""
 
@@ -399,7 +399,23 @@ msgstr ""
 msgid "Please enter the location where you'd like to save the file."
 msgstr ""
 
-#: src/filebrowser/templates/fb_components.mako:24
+#: src/filebrowser/templates/fb_components.mako:30
+msgid "Upload files"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:31
+msgid "New directory"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:33
+msgid "Search for file name"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:34
+msgid "Search"
+msgstr ""
+
+#: src/filebrowser/templates/fb_components.mako:38
 msgid "Home"
 msgstr ""
 
@@ -409,126 +425,147 @@ msgstr ""
 
 #: src/filebrowser/templates/listdir.mako:26
 #: src/filebrowser/templates/listdir.mako:28
+#: src/filebrowser/templates/listdir_paged.mako:26
+#: src/filebrowser/templates/listdir_paged.mako:28
 msgid "File Browser"
 msgstr ""
 
+#: src/filebrowser/templates/listdir_components.mako:44
+msgid "Beginning of List"
+msgstr ""
+
+#: src/filebrowser/templates/listdir_components.mako:45
+msgid "Previous Page"
+msgstr ""
+
 #: src/filebrowser/templates/listdir_components.mako:46
-msgid "Upload files"
+msgid "Next page"
+msgstr ""
+
+#: src/filebrowser/templates/listdir_components.mako:46
+msgid "Next Page"
 msgstr ""
 
 #: src/filebrowser/templates/listdir_components.mako:47
-msgid "New directory"
+msgid "End of List"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:50
-msgid "Filter: "
+#: src/filebrowser/templates/listdir_components.mako:49
+msgid "Show"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:50
-msgid "Search for file name"
+#: src/filebrowser/templates/listdir_components.mako:49
+msgid "items per page"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:58
+#: src/filebrowser/templates/listdir_components.mako:49
+#, python-format
+msgid ""
+"Showing %(start_index)s to %(end_index)s of %(total_count)s items, page "
+"%(page)s of %(num_pages)s."
+msgstr ""
+
+#: src/filebrowser/templates/listdir_components.mako:76
 msgid "Name"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:60
+#: src/filebrowser/templates/listdir_components.mako:78
 msgid "Path"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:65
+#: src/filebrowser/templates/listdir_components.mako:83
 msgid "Permissions"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:66
+#: src/filebrowser/templates/listdir_components.mako:84
 msgid "Date"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:108
+#: src/filebrowser/templates/listdir_components.mako:126
 msgid "Options"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:113
-#: src/filebrowser/templates/listdir_components.mako:116
+#: src/filebrowser/templates/listdir_components.mako:131
+#: src/filebrowser/templates/listdir_components.mako:134
 msgid "Delete"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:114
+#: src/filebrowser/templates/listdir_components.mako:132
 msgid "Delete Recursively"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:117
+#: src/filebrowser/templates/listdir_components.mako:135
 msgid "View File"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:119
+#: src/filebrowser/templates/listdir_components.mako:137
 msgid "Download File"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:121
+#: src/filebrowser/templates/listdir_components.mako:139
 msgid "Rename"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:122
+#: src/filebrowser/templates/listdir_components.mako:140
 msgid "Change Owner / Group"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:123
+#: src/filebrowser/templates/listdir_components.mako:141
 msgid "Change Permissions"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:124
+#: src/filebrowser/templates/listdir_components.mako:142
 msgid "Move"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:138
+#: src/filebrowser/templates/listdir_components.mako:163
 msgid "Please Confirm"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:141
+#: src/filebrowser/templates/listdir_components.mako:166
 msgid "Are you sure you want to delete this file?"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:145
+#: src/filebrowser/templates/listdir_components.mako:170
 msgid "Yes"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:146
+#: src/filebrowser/templates/listdir_components.mako:171
 msgid "No"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:157
+#: src/filebrowser/templates/listdir_components.mako:182
 msgid "Renaming:"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:179
+#: src/filebrowser/templates/listdir_components.mako:204
 msgid "Uploading to:"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:185
+#: src/filebrowser/templates/listdir_components.mako:210
 #: src/filebrowser/templates/upload.mako:31
 msgid "Please enable JavaScript to use file uploader."
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:199
+#: src/filebrowser/templates/listdir_components.mako:224
 msgid "Create Directory"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:207
+#: src/filebrowser/templates/listdir_components.mako:232
 msgid "Sorry, directory name is required."
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:290
+#: src/filebrowser/templates/listdir_components.mako:315
 #: src/filebrowser/templates/upload.mako:46
 msgid "Drop files here to upload"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:291
+#: src/filebrowser/templates/listdir_components.mako:316
 #: src/filebrowser/templates/upload.mako:47
 msgid "Upload a file"
 msgstr ""
 
-#: src/filebrowser/templates/listdir_components.mako:299
+#: src/filebrowser/templates/listdir_components.mako:324
 #: src/filebrowser/templates/upload.mako:55
 msgid "Failed"
 msgstr ""

+ 15 - 1
apps/filebrowser/src/filebrowser/templates/fb_components.mako

@@ -18,8 +18,22 @@ from django.template.defaultfilters import urlencode
 from django.utils.translation import ugettext as _
 %>
 
-<%def name="breadcrumbs(path, breadcrumbs)">
+<%def name="breadcrumbs(path, breadcrumbs, from_listdir=False)">
+    <%
+    current_filter = ""
+    if filter_str is not None:
+        current_filter = filter_str
+    %>
     <div class="subnav">
+        % if from_listdir:
+        <p class="pull-right">
+            <a href="#" class="btn upload-link">${_('Upload files')}</a>
+            <a href="#" class="btn create-directory-link">${_('New directory')}</a>
+            &nbsp;&nbsp;&nbsp;&nbsp;
+            <input type="text" value="${current_filter}" class="input-medium search-query" placeholder="${_('Search for file name')}">
+            <a href="#" class="btn filter">${_('Search')}</a>
+        </p>
+        % endif
         <ul class="nav nav-pills">
           <li><a href="${url('filebrowser.views.view', path=urlencode(path))}?default_to_home"><i class="icon-home"></i>${_('Home')}</a></li>
           <li>

+ 5 - 5
apps/filebrowser/src/filebrowser/templates/listdir.mako

@@ -25,12 +25,12 @@ from django.utils.translation import ugettext as _
 
 ${commonheader(_('File Browser'), 'filebrowser')}
 <div class="container-fluid">
-	<h1>${_('File Browser')}</h1>
-	% if breadcrumbs:
-        ${fb_components.breadcrumbs(path, breadcrumbs)}
-	%endif
+    <h1>${_('File Browser')}</h1>
+    % if breadcrumbs:
+        ${fb_components.breadcrumbs(path, breadcrumbs, True)}
+    %endif
     <div id="dirlist" class="view">
-    ${dir.list_table_browser(files, path_enc, current_request_path, cwd_set)}
+        ${dir.list_table_browser(files, path_enc, current_request_path, cwd_set)}
     </div>
 </div>
 ${commonfooter()}

+ 102 - 33
apps/filebrowser/src/filebrowser/templates/listdir_components.mako

@@ -23,6 +23,33 @@ from django.utils.translation import ugettext as _
 %>
 
 
+<%def name="pageref(num)">
+    href="?pagenum=${num}&pagesize=${pagesize}"
+</%def>
+<%def name="prevpage(page)">
+  ${pageref(page.previous_page_number())}
+</%def>
+<%def name="nextpage(page)">
+  ${pageref(page.next_page_number())}
+</%def>
+<%def name="toppage(page)">
+  ${pageref(1)}
+</%def>
+<%def name="bottompage(page)">
+  ${pageref(page.num_pages())}
+</%def>
+<%def name="pagination(page)">
+    <div class="pagination">
+        <ul class="pull-right">
+            <li class="prev"><a title="${_('Beginning of List')}" ${toppage(page)}>&larr; ${_('Beginning of List')}</a></li>
+            <li><a title="${_('Previous Page')}" ${prevpage(page)}>${_('Previous Page')}</a></li>
+            <li><a title="${_('Next page')}" ${nextpage(page)}>${_('Next Page')}</a></li>
+            <li class="next"><a title="${_('End of List')}" ${bottompage(page)}>${_('End of List')} &rarr;</a></li>
+        </ul>
+        <p>${_('Show')} <select id="pagesize" class="input-mini"><option>15</option><option selected>30</option><option>45</option><option>60</option><option>100</option><option>200</option></select> ${_('items per page')}. ${_('Showing %(start_index)s to %(end_index)s of %(total_count)s items, page %(page)s of %(num_pages)s.') % dict(start_index=page.start_index(), end_index=page.end_index(), total_count=page.total_count(), page=page.number, num_pages=page.num_pages())}</p>
+    </div>
+</%def>
+
 <%def name="list_table_chooser(files, path, current_request_path)">
   ${_table(files, path, current_request_path, 'chooser')}
 </%def>
@@ -41,29 +68,20 @@ from django.utils.translation import ugettext as _
             cursor: pointer;
         }
     </style>
-    <div class="well hueWell">
-        <p class="pull-right">
-            <a href="#" class="btn upload-link">${_('Upload files')}</a>
-            <a href="#" class="btn create-directory-link">${_('New directory')}</a>
-        </p>
-        <form class="form-search">
-            ${_('Filter: ')}<input id="filterInput" class="input-xlarge search-query" placeholder="${_('Search for file name')}">
-        </form>
-    </div>
-
+    %if len(files)>0 :
     <table class="table table-condensed table-striped datatables">
         <thead>
             <tr>
             % if cwd_set:
-                <th>${_('Name')}</th>
+                <th class="sortable sorting" data-sort="name">${_('Name')}</th>
             % else:
-                <th>${_('Path')}</th>
+                <th class="sortable sorting" data-sort="name">${_('Path')}</th>
             % endif
-                <th>${_('Size')}</th>
-                <th>${_('User')}</th>
-                <th>${_('Group')}</th>
+                <th class="sortable sorting" data-sort="size">${_('Size')}</th>
+                <th class="sortable sorting" data-sort="user">${_('User')}</th>
+                <th class="sortable sorting" data-sort="group">${_('Group')}</th>
                 <th>${_('Permissions')}</th>
-                <th>${_('Date')}</th>
+                <th class="sortable sorting" data-sort="mtime">${_('Date')}</th>
                 <th>&nbsp;</th>
             </tr>
         </thead>
@@ -131,6 +149,13 @@ from django.utils.translation import ugettext as _
         </tbody>
     </table>
 
+    ${pagination(page)}
+    %else:
+        <div class="alert">
+            There are no files matching the search criteria.
+        </div>
+    %endif
+
 <!-- delete modal -->
 <div id="deleteModal" class="modal hide fade">
     <div class="modal-header">
@@ -319,26 +344,58 @@ from django.utils.translation import ugettext as _
     // don"t wait for the window to load
     window.onload = createUploader;
 
+    function getQueryString(){
+        var queryString = {};
+        if (window.location.href.indexOf("?") > -1) {
+            window.location.href.split("?").pop().split("&").forEach(function (prop) {
+                var item = prop.split("=");
+                queryString[item.shift()] = item.shift();
+            });
+        }
+        return queryString;
+    }
+
+    function setQueryString(queryString){
+        var qs = "?"
+        for (var key in queryString) {
+            qs += key + "=" + queryString[key] + "&";
+        }
+        return qs.substring(0, qs.length - 1);
+    }
+
     $(document).ready(function(){
-        //filter handlers
-        var oTable = $('.datatables').dataTable( {
-          "sPaginationType": "bootstrap",
-          "bLengthChange": false,
-          "iDisplayLength": 15,
-          "sDom": "<'row'r>t<'row'<'span8'i><''p>>",
-          "aoColumns": [
-                null,
-                null,
-                null,
-                null,
-                null,
-                { "sType": "date" },
-                null
-            ]
+        var qs = getQueryString();
+
+        if (qs["sortby"] == null){
+            qs["sortby"] = "name";
+        }
+
+        var el = $(".sortable[data-sort=" + qs["sortby"] + "]");
+        el.removeClass("sorting");
+        if (qs["descending"] != null && qs["descending"] == "true") {
+            el.addClass("sorting_desc");
+        }
+        else {
+            el.addClass("sorting_asc");
+        }
+
+
+        $(".sortable").click(function(){
+            qs["sortby"] = $(this).data("sort");
+            if ($(this).hasClass("sorting_asc")) {
+                qs["descending"] = "true";
+            }
+            else {
+                delete qs["descending"];
+            }
+            location.href = setQueryString(qs);
         });
 
-        $("#filterInput").keyup(function() {
-            oTable.fnFilter($(this).val(), 0 /* Column Idx */);
+        $("#pagesize").val("${pagesize}");
+        $("#pagesize").change(function(){
+            qs["pagenum"] = "1";
+            qs["pagesize"] = $("#pagesize").val();
+            location.href = setQueryString(qs);
         });
 
         //delete handlers
@@ -417,6 +474,18 @@ from django.utils.translation import ugettext as _
             });
         });
 
+        // handle search
+        $(".search-query").keydown(function(e){
+            if (e.keyCode == 13){
+                $(".filter").click();
+            }
+        });
+        $(".filter").click(function(){
+            qs["filter"] = $(".search-query").val();
+            qs["pagenum"] = "1";
+            location.href = setQueryString(qs);
+        });
+
         $("#cancelCreateDirectoryBtn").click(function(){
             $("#createDirectoryModal").modal("hide");
         });

+ 1 - 1
apps/filebrowser/src/filebrowser/urls.py

@@ -29,7 +29,7 @@ urlpatterns = patterns('filebrowser.views',
   url(r'status', 'status', name='status'),
   # Catch-all for viewing a file (display) or a directory (listdir)
   url(r'view(?P<path>/.*)', 'view', name='view'),
-  url(r'chooser(?P<path>/.*)', 'chooser', name='view'),
+  url(r'chooser(?P<path>/.*)', 'chooser', name='choose'),
   url(r'edit(?P<path>/.*)', 'edit', name='edit'),
   url(r'save', 'save_file'),
 

+ 80 - 3
apps/filebrowser/src/filebrowser/views.py

@@ -23,6 +23,7 @@
 import errno
 import logging
 import mimetypes
+import operator
 import posixpath
 import stat as stat_module
 import os
@@ -37,7 +38,8 @@ from cStringIO import StringIO
 from gzip import GzipFile
 from avro import datafile, io
 
-from desktop.lib import i18n
+from desktop.lib import i18n, paginator
+from desktop.lib.conf import coerce_bool
 from desktop.lib.django_util import make_absolute, render, render_json
 from desktop.lib.django_util import PopupException, format_preserving_redirect
 from filebrowser.lib.rwx import filetype, rwx
@@ -123,7 +125,7 @@ def view(request, path):
     try:
         stats = request.fs.stats(path)
         if stats.isDir:
-            return listdir(request, path, False)
+            return listdir_paged(request, path)
         else:
             return display(request, path)
     except (IOError, WebHdfsException), e:
@@ -346,6 +348,81 @@ def listdir(request, path, chooser):
     else:
         return render('listdir.mako', request, data)
 
+def listdir_paged(request, path):
+    """
+    A paginated version of listdir.
+
+    Query parameters:
+      pagenum           - The page number to show. Defaults to 1.
+      pagesize          - How many to show on a page. Defaults to 15.
+      sortby=?          - Specify attribute to sort by. Accepts:
+                            (name, atime, mtime, size, user, group)
+                          Defaults to name.
+      descending        - Specify a descending sort order.
+                          Default to false.
+      filter=?          - Specify a substring filter to search for in
+                          the filename field.
+    """
+    if not request.fs.isdir(path):
+        raise PopupException("Not a directory: %s" % (path,))
+
+    pagenum = int(request.GET.get('pagenum', 1))
+    pagesize = int(request.GET.get('pagesize', 30))
+
+    home_dir_path = request.user.get_home_directory()
+    breadcrumbs = parse_breadcrumbs(path)
+
+    all_stats = request.fs.listdir_stats(path)
+
+    # Include parent dir, unless at filesystem root.
+    if Hdfs.normpath(path) != posixpath.sep:
+        parent_path = request.fs.join(path, "..")
+        parent_stat = request.fs.stats(parent_path)
+        # The 'path' field would be absolute, but we want its basename to be
+        # actually '..' for display purposes. Encode it since _massage_stats expects byte strings.
+        parent_stat['path'] = parent_path
+        parent_stat['name'] = ".."
+        all_stats.insert(0, parent_stat)
+
+    # Filter first
+    filter_str = request.GET.get('filter', None)
+    if filter_str:
+        filtered_stats = filter(lambda sb: filter_str in sb['name'], all_stats)
+        all_stats = filtered_stats
+
+    # Sort next
+    sortby = request.GET.get('sortby', None)
+    if sortby is not None:
+        if sortby not in ('name', 'atime', 'mtime', 'user', 'group', 'size'):
+            logger.info("Invalid sort attribute '%s' for listdir." %
+                        (sortby,))
+        else:
+            descending_param = request.GET.get('descending', None)
+            all_stats = sorted(all_stats,
+                               key=operator.attrgetter(sortby),
+                               reverse=coerce_bool(descending_param))
+
+    # Do pagination
+    page = paginator.Paginator(all_stats, pagesize).page(pagenum)
+    shown_stats = page.object_list
+    page.object_list = [ _massage_stats(request, s) for s in shown_stats ]
+
+    data = {
+        'path': path,
+        'breadcrumbs': breadcrumbs,
+        'current_request_path': request.path,
+        'files': page.object_list,
+        'page': page,
+        'pagesize': pagesize,
+        'home_directory': request.fs.isdir(home_dir_path) and home_dir_path or None,
+        'filter_str': filter_str,
+        # The following should probably be deprecated
+        'cwd_set': True,
+        'file_filter': 'any',
+        'current_dir_path': path,
+    }
+    return render('listdir.mako', request, data)
+
 
 def chooser(request, path):
     """
@@ -375,7 +452,7 @@ def _massage_stats(request, stats):
     normalized = Hdfs.normpath(path)
     return {
         'path': normalized,
-        'name': posixpath.basename(path),
+        'name': stats['name'],
         'stats': stats.to_json_dict(),
         'type': filetype(stats['mode']),
         'rwx': rwx(stats['mode']),

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

@@ -128,6 +128,80 @@ def test_listdir():
     except:
       pass      # Don't let cleanup errors mask earlier failures
 
+
+@attr('requires_hadoop')
+def test_listdir_sort_and_filter():
+  cluster = pseudo_hdfs4.shared_cluster()
+  c = make_logged_in_client(cluster.superuser)
+  cluster.fs.setuser(cluster.superuser)
+
+  BASE = '/test_sort_and_filter'
+  FUNNY_NAME = u'greek-Ελληνικά'
+  try:
+    cluster.fs.mkdir(BASE)
+    # Create 10 files
+    for i in range(1, 11):
+      cluster.fs.create(cluster.fs.join(BASE, str(i)), data="foo" * i)
+
+    # Create 1 funny name directory
+    cluster.fs.mkdir(cluster.fs.join(BASE, FUNNY_NAME))
+
+    # All 12 of the entries
+    expect = [ '..', FUNNY_NAME] + [ str(i) for i in range(1, 11) ]
+
+    # Check pagination
+    listing = c.get('/filebrowser/view' + BASE + '?pagesize=20').context['files']
+    assert_equal(len(expect), len(listing))
+
+    listing = c.get('/filebrowser/view' + BASE + '?pagesize=10').context['files']
+    assert_equal(10, len(listing))
+
+    listing = c.get('/filebrowser/view' + BASE + '?pagesize=10&pagenum=1').context['files']
+    assert_equal(10, len(listing))
+
+    listing = c.get('/filebrowser/view' + BASE + '?pagesize=10&pagenum=2').context['files']
+    assert_equal(2, len(listing))
+
+    # Check sorting (name)
+    listing = c.get('/filebrowser/view' + BASE + '?sortby=name').context['files']
+    assert_equal(sorted(expect), [ f['name'] for f in listing ])
+
+    listing = c.get('/filebrowser/view' + BASE + '?sortby=name&descending=false').context['files']
+    assert_equal(sorted(expect), [ f['name'] for f in listing ])
+
+    listing = c.get('/filebrowser/view' + BASE + '?sortby=name&descending=true').context['files']
+    assert_equal(sorted(expect, reverse=True), [ f['name'] for f in listing ])
+    
+    # Check sorting (size)
+    listing = c.get('/filebrowser/view' + BASE + '?sortby=size').context['files']
+    assert_equal(expect, [ f['name'] for f in listing ])
+
+    # Check sorting (mtime)
+    listing = c.get('/filebrowser/view' + BASE + '?sortby=mtime').context['files']
+    assert_equal("..", listing[0]['name'])
+    assert_equal(FUNNY_NAME, listing[-1]['name'])
+
+    # Check filter
+    listing = c.get('/filebrowser/view' + BASE + '?filter=1').context['files']
+    assert_equal(['1', '10'], [ f['name'] for f in listing ])
+
+    listing = c.get('/filebrowser/view' + BASE + '?filter=' + FUNNY_NAME).context['files']
+    assert_equal([FUNNY_NAME], [ f['name'] for f in listing ])
+
+    # Check filter + sorting
+    listing = c.get('/filebrowser/view' + BASE + '?filter=1&sortby=name&descending=true').context['files']
+    assert_equal(['10', '1'], [ f['name'] for f in listing ])
+
+    # Check filter + sorting + pagination
+    listing = c.get('/filebrowser/view' + BASE + '?filter=1&sortby=name&descending=true&pagesize=1&pagenum=2').context['files']
+    assert_equal(['1'], [ f['name'] for f in listing ])
+  finally:
+    try:
+      cluster.fs.rmtree(BASE)
+    except:
+      pass      # Don't let cleanup errors mask earlier failures
+
+
 @attr('requires_hadoop')
 def test_chooser():
   cluster = pseudo_hdfs4.shared_cluster()

+ 2 - 1
desktop/libs/hadoop/src/hadoop/fs/webhdfs_types.py

@@ -32,7 +32,8 @@ class WebHdfsStat(object):
   """
 
   def __init__(self, file_status, parent_path):
-    self.path = Hdfs.join(parent_path, decode_fs_path(file_status['pathSuffix']))
+    self.name = decode_fs_path(file_status['pathSuffix'])
+    self.path = Hdfs.join(parent_path, self.name)
     self.isDir = file_status['type'] == 'DIRECTORY'
     self.atime = file_status['accessTime'] / 1000
     self.mtime = file_status['modificationTime'] / 1000