Browse Source

HUE-2916 [fb] Change URL-routing

Filebrowser routing `r'^view(?P<path>/.*)$'` is unsuitable for absolute
URI.
* Changes filebrowser routing rules to `r'^view=(?P<path>.*)$'`
  this new pattern will allow path like:
  - /user/romain/public (default to hdfs)
  - s3://bucket/key
* Makes related changes on other applications
Ivan Orlov 11 năm trước cách đây
mục cha
commit
cde6a6a3cc
26 tập tin đã thay đổi với 116 bổ sung và 109 xóa
  1. 2 2
      apps/beeswax/src/beeswax/api.py
  2. 2 2
      apps/filebrowser/src/filebrowser/templates/fb_components.mako
  3. 2 2
      apps/filebrowser/src/filebrowser/templates/listdir_components.mako
  4. 8 8
      apps/filebrowser/src/filebrowser/urls.py
  5. 7 1
      apps/filebrowser/src/filebrowser/views.py
  6. 53 51
      apps/filebrowser/src/filebrowser/views_test.py
  7. 8 8
      apps/jobbrowser/src/jobbrowser/tests.py
  8. 0 1
      apps/metastore/src/metastore/templates/describe_partitions.mako
  9. 1 1
      apps/oozie/src/oozie/templates/editor/edit_workflow.mako
  10. 3 3
      apps/oozie/src/oozie/templates/editor2/common_workflow.mako
  11. 1 1
      apps/oozie/src/oozie/templates/editor2/coordinator_editor.mako
  12. 1 1
      apps/oozie/src/oozie/templates/editor2/workflow_editor.mako
  13. 5 5
      apps/oozie/src/oozie/templates/utils.inc.mako
  14. 2 2
      apps/pig/src/pig/models.py
  15. 3 3
      apps/pig/src/pig/templates/app.mako
  16. 3 3
      apps/search/src/search/static/search/js/search.utils.js
  17. 1 1
      apps/security/src/security/static/security/js/hdfs.ko.js
  18. 1 1
      apps/security/src/security/static/security/js/hive.ko.js
  19. 5 5
      apps/security/src/security/templates/hdfs.mako
  20. 1 1
      apps/security/src/security/templates/hive.mako
  21. 2 2
      apps/sqoop/src/sqoop/static/sqoop/js/sqoop.jobs.js
  22. 1 1
      desktop/core/src/desktop/models.py
  23. 1 1
      desktop/core/src/desktop/static/desktop/js/jquery.filechooser.js
  24. 1 1
      desktop/core/src/desktop/static/desktop/js/jquery.hdfsautocomplete.js
  25. 1 1
      desktop/core/src/desktop/static/desktop/js/jquery.hdfstree.js
  26. 1 1
      desktop/core/src/desktop/tests.py

+ 2 - 2
apps/beeswax/src/beeswax/api.py

@@ -448,7 +448,7 @@ def save_results_hdfs_directory(request, query_history_id):
         response['id'] = query_history.id
         response['query'] = query_history.query
         response['path'] = target_dir
-        response['success_url'] = '/filebrowser/view%s' % target_dir
+        response['success_url'] = '/filebrowser/view=%s' % target_dir
         query_history = db.insert_query_into_directory(query_history, target_dir)
         response['watch_url'] = reverse(get_app_name(request) + ':api_watch_query_refresh_json', kwargs={'id': query_history.id})
       except Exception, ex:
@@ -515,7 +515,7 @@ def save_results_hdfs_file(request, query_history_id):
         response['id'] = query_history.id
         response['query'] = query_history.query
         response['path'] = target_file
-        response['success_url'] = '/filebrowser/view%s' % target_file
+        response['success_url'] = '/filebrowser/view=%s' % target_file
         response['watch_url'] = reverse(get_app_name(request) + ':api_watch_query_refresh_json', kwargs={'id': query_history.id})
       except Exception, ex:
         error_msg, log = expand_exception(ex, db)

+ 2 - 2
apps/filebrowser/src/filebrowser/templates/fb_components.mako

@@ -50,10 +50,10 @@ from django.utils.translation import ugettext as _
                     % for breadcrumb_item in breadcrumbs:
                     <% label = breadcrumb_item['label'] %>
                     %if label == '/':
-                            <li><a href="/filebrowser/view${breadcrumb_item['url']}"><span
+                            <li><a href="/filebrowser/view=${breadcrumb_item['url']}"><span
                                     class="divider">${label}</span></a></li>
                     %else:
-                            <li><a href="/filebrowser/view${breadcrumb_item['url']}">${label}</a><span class="divider">/</span></li>
+                            <li><a href="/filebrowser/view=${breadcrumb_item['url']}">${label}</a><span class="divider">/</span></li>
                     %endif
                     % endfor
             </ul>

+ 2 - 2
apps/filebrowser/src/filebrowser/templates/listdir_components.mako

@@ -1292,7 +1292,7 @@ from django.utils.translation import ugettext as _
             if (response.status != 0) {
               $(document).trigger("error", "${ _('Error: ') }" + response['data']);
             } else if (num_of_pending_uploads == 0) {
-              location = "/filebrowser/view" + self.currentPath();
+              location = "/filebrowser/view=" + self.currentPath();
             }
           },
           onSubmit:function (id, fileName, responseJSON) {
@@ -1340,7 +1340,7 @@ from django.utils.translation import ugettext as _
           onComplete:function (id, fileName, responseJSON) {
             num_of_pending_uploads--;
             if (num_of_pending_uploads == 0) {
-              location = "/filebrowser/view" + self.currentPath();
+              location = "/filebrowser/view=" + self.currentPath();
             }
           },
           onSubmit:function (id, fileName, responseJSON) {

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

@@ -23,16 +23,16 @@ urlpatterns = patterns('filebrowser.views',
   url(r'^$', 'index', name='index'),
 
   # Catch-all for viewing a file (display) or a directory (listdir)
-  url(r'^view(?P<path>/.*)$', 'view', name='view'),
+  url(r'^view=(?P<path>.*)$', 'view', name='view'),
 
-  url(r'^listdir(?P<path>/.*)$', 'listdir', name='listdir'),
-  url(r'^display(?P<path>/.*)$', 'display', name='display'),
-  url(r'^stat(?P<path>/.*)$', 'stat', name='stat'),
-  url(r'^download(?P<path>/.*)$', 'download', name='download'),
+  url(r'^listdir=(?P<path>.*)$', 'listdir', name='listdir'),
+  url(r'^display=(?P<path>.*)$', 'display', name='display'),
+  url(r'^stat=(?P<path>.*)$', 'stat', name='stat'),
+  url(r'^download=(?P<path>.*)$', 'download', name='download'),
   url(r'^status$', 'status', name='status'),
-  url(r'^home_relative_view(?P<path>/.*)$', 'home_relative_view', name='home_relative_view'),
-  url(r'^chooser(?P<path>/.*)$', 'chooser', name='choose'),
-  url(r'^edit(?P<path>/.*)$', 'edit', name='edit'),
+  url(r'^home_relative_view=(?P<path>.*)$', 'home_relative_view', name='home_relative_view'),
+  url(r'^chooser=(?P<path>.*)$', 'chooser', name='choose'),
+  url(r'^edit=(?P<path>.*)$', 'edit', name='edit'),
 
   # POST operations
   url(r'^save$', 'save_file'),

+ 7 - 1
apps/filebrowser/src/filebrowser/views.py

@@ -1304,6 +1304,7 @@ def status(request):
 def location_to_url(location, strict=True):
     """
     If possible, returns a file browser URL to the location.
+    Prunes HDFS URI to path.
     Location is a URI, if strict is True.
 
     Python doesn't seem to have a readily-available URI-comparison
@@ -1315,7 +1316,11 @@ def location_to_url(location, strict=True):
     if strict and not split_path[1] or not split_path[2]:
       # No netloc not full url or no URL
       return None
-    return reverse("filebrowser.views.view", kwargs=dict(path=split_path[2]))
+    path = location
+    if split_path[0] == 'hdfs':
+      path = split_path[2]
+    return reverse("filebrowser.views.view", kwargs=dict(path=path))
+
 
 def truncate(toTruncate, charsToKeep=50):
     """
@@ -1327,5 +1332,6 @@ def truncate(toTruncate, charsToKeep=50):
     else:
         return toTruncate
 
+
 def _is_hdfs_superuser(request):
   return request.user.username == request.fs.superuser or request.user.groups.filter(name__exact=request.fs.supergroup).exists()

+ 53 - 51
apps/filebrowser/src/filebrowser/views_test.py

@@ -204,7 +204,7 @@ class TestFileBrowserWithHadoop(object):
     self.c.post('/filebrowser/mkdir', dict(path=prefix, name=success_path))
 
     # Read the parent dir and make sure we created 'success_path' only.
-    response = self.c.get('/filebrowser/view' + prefix)
+    response = self.c.get('/filebrowser/view=' + prefix)
     dir_listing = response.context['files']
     assert_equal(3, len(dir_listing))
     assert_equal(dir_listing[2]['name'], success_path)
@@ -227,7 +227,7 @@ class TestFileBrowserWithHadoop(object):
     assert_equal(200, resp.status_code)
 
     # Read the parent dir and make sure we created 'success_path' only.
-    response = self.c.get('/filebrowser/view' + prefix)
+    response = self.c.get('/filebrowser/view=' + prefix)
     file_listing = response.context['files']
     assert_equal(3, len(file_listing))
     assert_equal(file_listing[2]['name'], success_path)
@@ -397,7 +397,7 @@ class TestFileBrowserWithHadoop(object):
       self.c.post('/filebrowser/mkdir', dict(path=prefix, name=path))
 
     # Read the parent dir
-    response = self.c.get('/filebrowser/view' + prefix)
+    response = self.c.get('/filebrowser/view=' + prefix)
 
     dir_listing = response.context['files']
     assert_equal(len(orig_paths) + 2, len(dir_listing))
@@ -418,21 +418,21 @@ class TestFileBrowserWithHadoop(object):
       assert_equal('..', resp.context['files'][0]['name'])
 
     # Test's home directory now exists. Should be returned.
-    response = self.c.get('/filebrowser/view' + prefix)
+    response = self.c.get('/filebrowser/view=' + prefix)
     assert_equal(response.context['home_directory'], home)
 
     # Test URL conflicts with filenames
     stat_dir = '%sstat/dir' % prefix
     self.cluster.fs.do_as_user('test', self.cluster.fs.mkdir, stat_dir)
-    response = self.c.get('/filebrowser/view%s' % stat_dir)
+    response = self.c.get('/filebrowser/view=%s' % stat_dir)
     assert_equal(stat_dir, response.context['path'])
 
-    response = self.c.get('/filebrowser/view/test-filebrowser/?default_to_home')
+    response = self.c.get('/filebrowser/view=/test-filebrowser/?default_to_home')
     assert_true(re.search('%s$' % home, response['Location']))
 
     # Test path relative to home directory
     self.cluster.fs.do_as_user('test', self.cluster.fs.mkdir, '%s/test_dir' % home)
-    response = self.c.get('/filebrowser/home_relative_view/test_dir')
+    response = self.c.get('/filebrowser/home_relative_view=/test_dir')
     assert_equal('%s/test_dir' % home, response.context['path'])
 
 
@@ -455,53 +455,53 @@ class TestFileBrowserWithHadoop(object):
     expect = [ '..', '.', FUNNY_NAME] + [ str(i) for i in range(1, 11) ]
 
     # Check pagination
-    listing = self.c.get('/filebrowser/view' + BASE + '?pagesize=20').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?pagesize=20').context['files']
     assert_equal(len(expect), len(listing))
 
-    listing = self.c.get('/filebrowser/view' + BASE + '?pagesize=10').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?pagesize=10').context['files']
     assert_equal(12, len(listing))
 
-    listing = self.c.get('/filebrowser/view' + BASE + '?pagesize=10&pagenum=1').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?pagesize=10&pagenum=1').context['files']
     assert_equal(12, len(listing))
 
-    listing = self.c.get('/filebrowser/view' + BASE + '?pagesize=10&pagenum=2').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?pagesize=10&pagenum=2').context['files']
     assert_equal(3, len(listing))
 
     # Check sorting (name)
-    listing = self.c.get('/filebrowser/view' + BASE + '?sortby=name').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?sortby=name').context['files']
     assert_equal(sorted(expect[2:]), [ f['name'] for f in listing ][2:])
 
-    listing = self.c.get('/filebrowser/view' + BASE + '?sortby=name&descending=false').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?sortby=name&descending=false').context['files']
     assert_equal(sorted(expect[2:]), [ f['name'] for f in listing ][2:])
 
-    listing = self.c.get('/filebrowser/view' + BASE + '?sortby=name&descending=true').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?sortby=name&descending=true').context['files']
     assert_equal(".", listing[1]['name'])
     assert_equal("..", listing[0]['name'])
     assert_equal(FUNNY_NAME, listing[2]['name'])
 
     # Check sorting (size)
-    listing = self.c.get('/filebrowser/view' + BASE + '?sortby=size').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?sortby=size').context['files']
     assert_equal(expect, [ f['name'] for f in listing ])
 
     # Check sorting (mtime)
-    listing = self.c.get('/filebrowser/view' + BASE + '?sortby=mtime').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?sortby=mtime').context['files']
     assert_equal(".", listing[1]['name'])
     assert_equal("..", listing[0]['name'])
     assert_equal(FUNNY_NAME, listing[-1]['name'])
 
     # Check filter
-    listing = self.c.get('/filebrowser/view' + BASE + '?filter=1').context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?filter=1').context['files']
     assert_equal(['..', '.', '1', '10'], [ f['name'] for f in listing ])
 
-    listing = self.c.get('/filebrowser/view' + BASE + '?filter=' + FUNNY_NAME).context['files']
+    listing = self.c.get('/filebrowser/view=' + BASE + '?filter=' + FUNNY_NAME).context['files']
     assert_equal(['..', '.', FUNNY_NAME], [ f['name'] for f in listing ])
 
     # Check filter + sorting
-    listing = self.c.get('/filebrowser/view' + BASE + '?filter=1&sortby=name&descending=true').context['files']
+    listing = self.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 = self.c.get('/filebrowser/view' + BASE + '?filter=1&sortby=name&descending=true&pagesize=1&pagenum=2').context['files']
+    listing = self.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 ])
 
 
@@ -510,7 +510,7 @@ class TestFileBrowserWithHadoop(object):
     self.cluster.fs.mkdir(prefix)
 
     # Note that the trailing slash is important. We ask for the root dir.
-    resp = self.c.get('/filebrowser/chooser/?format=json')
+    resp = self.c.get('/filebrowser/chooser=/?format=json')
     # We should get a json response
     dic = json.loads(resp.content)
     assert_equal('/', dic['current_dir_path'])
@@ -541,22 +541,22 @@ class TestFileBrowserWithHadoop(object):
       f.close()
 
       # Snappy compressed fail
-      response = c.get('/filebrowser/view%s/test-view.notsnappy?compression=snappy' % prefix)
+      response = c.get('/filebrowser/view=%s/test-view.notsnappy?compression=snappy' % prefix)
       assert_true('Failed to decompress' in response.context['message'], response)
 
       # Snappy compressed succeed
-      response = c.get('/filebrowser/view%s/test-view.snappy' % prefix)
+      response = c.get('/filebrowser/view=%s/test-view.snappy' % prefix)
       assert_equal('snappy', response.context['view']['compression'])
       assert_equal(response.context['view']['contents'], 'This is a test of the emergency broadcasting system.', response)
 
       # Snappy compressed succeed
-      response = c.get('/filebrowser/view%s/test-view.stillsnappy' % prefix)
+      response = c.get('/filebrowser/view=%s/test-view.stillsnappy' % prefix)
       assert_equal('snappy', response.context['view']['compression'])
       assert_equal(response.context['view']['contents'], 'The broadcasters of your area in voluntary cooperation with the FCC and other authorities.', response)
 
       # Largest snappy compressed file
       finish.append( MAX_SNAPPY_DECOMPRESSION_SIZE.set_for_testing(1) )
-      response = c.get('/filebrowser/view%s/test-view.stillsnappy?compression=snappy' % prefix)
+      response = c.get('/filebrowser/view=%s/test-view.stillsnappy?compression=snappy' % prefix)
       assert_true('File size is greater than allowed max snappy decompression size of 1' in response.context['message'], response)
 
     finally:
@@ -604,7 +604,7 @@ class TestFileBrowserWithHadoop(object):
       f.close()
 
       # Snappy compressed succeed
-      response = self.c.get('/filebrowser/view%s/test-view.compressed.avro' % prefix)
+      response = self.c.get('/filebrowser/view=%s/test-view.compressed.avro' % prefix)
       assert_equal('avro', response.context['view']['compression'])
       assert_equal(eval(response.context['view']['contents']), dummy_datum, response)
 
@@ -640,13 +640,13 @@ class TestFileBrowserWithHadoop(object):
     data_file_writer.close()
 
     # autodetect
-    response = self.c.get('/filebrowser/view%s/test-view.avro' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view.avro' % prefix)
     # (Note: we use eval here cause of an incompatibility issue between
     # the representation string of JSON dicts in simplejson vs. json)
     assert_equal(eval(response.context['view']['contents']), dummy_datum)
 
     # offsetting should work as well
-    response = self.c.get('/filebrowser/view%s/test-view.avro?offset=1' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view.avro?offset=1' % prefix)
     assert_equal('avro', response.context['view']['compression'])
 
     f = self.cluster.fs.open(prefix + '/test-view2.avro', "w")
@@ -654,11 +654,11 @@ class TestFileBrowserWithHadoop(object):
     f.close()
 
     # we shouldn't autodetect non avro files
-    response = self.c.get('/filebrowser/view%s/test-view2.avro' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view2.avro' % prefix)
     assert_equal(response.context['view']['contents'], "hello")
 
     # we should fail to do a bad thing if they specify compression when it's not set.
-    response = self.c.get('/filebrowser/view%s/test-view2.avro?compression=gzip' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view2.avro?compression=gzip' % prefix)
     assert_true('Failed to decompress' in response.context['message'])
 
 
@@ -673,7 +673,7 @@ class TestFileBrowserWithHadoop(object):
     f.write(test_data.decode('hex'))
 
     # autodetect
-    response = self.c.get('/filebrowser/view%s/test-parquet.parquet' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-parquet.parquet' % prefix)
 
     assert_true('FRANCE' in response.context['view']['contents'])
 
@@ -687,11 +687,11 @@ class TestFileBrowserWithHadoop(object):
     f.write(sdf_string)
     f.close()
 
-    response = self.c.get('/filebrowser/view%s/test-view.gz?compression=gzip' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view.gz?compression=gzip' % prefix)
     assert_equal(response.context['view']['contents'], "sdf\n")
 
     # autodetect
-    response = self.c.get('/filebrowser/view%s/test-view.gz' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view.gz' % prefix)
     assert_equal(response.context['view']['contents'], "sdf\n")
 
     # ensure compression note is rendered
@@ -699,7 +699,7 @@ class TestFileBrowserWithHadoop(object):
     assert_true('Output rendered from compressed' in response.content, response.content)
 
     # offset should do nothing
-    response = self.c.get('/filebrowser/view%s/test-view.gz?compression=gzip&offset=1' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view.gz?compression=gzip&offset=1' % prefix)
     assert_true("Offsets are not supported" in response.context['message'], response.context['message'])
 
     f = self.cluster.fs.open(prefix + '/test-view2.gz', "w")
@@ -707,11 +707,11 @@ class TestFileBrowserWithHadoop(object):
     f.close()
 
     # we shouldn't autodetect non gzip files
-    response = self.c.get('/filebrowser/view%s/test-view2.gz' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view2.gz' % prefix)
     assert_equal(response.context['view']['contents'], "hello")
 
     # we should fail to do a bad thing if they specify compression when it's not set.
-    response = self.c.get('/filebrowser/view%s/test-view2.gz?compression=gzip' % prefix)
+    response = self.c.get('/filebrowser/view=%s/test-view2.gz?compression=gzip' % prefix)
     assert_true("Failed to decompress" in response.context['message'])
 
 
@@ -731,10 +731,10 @@ class TestFileBrowserWithHadoop(object):
     view_i18n_helper(self.c, self.cluster, 'johab', content)
 
     # Test that the default view is home
-    response = self.c.get('/filebrowser/view/')
+    response = self.c.get('/filebrowser/view=/')
     assert_equal(response.context['path'], '/')
-    response = self.c.get('/filebrowser/view/?default_to_home=1')
-    assert_equal("http://testserver/filebrowser/view/user/test", response["location"])
+    response = self.c.get('/filebrowser/view=/?default_to_home=1')
+    assert_equal("http://testserver/filebrowser/view=/user/test", response["location"])
 
 
   def test_view_access(self):
@@ -744,10 +744,10 @@ class TestFileBrowserWithHadoop(object):
     self.cluster.fs.mkdir(NO_PERM_DIR, mode='700')
 
     c_no_perm = make_logged_in_client(username='no_home')
-    response = c_no_perm.get('/filebrowser/view%s' % NO_PERM_DIR)
+    response = c_no_perm.get('/filebrowser/view=%s' % NO_PERM_DIR)
     assert_true('Cannot access' in response.context['message'])
 
-    response = self.c.get('/filebrowser/view/test-does-not-exist')
+    response = self.c.get('/filebrowser/view=/test-does-not-exist')
     assert_true('Cannot access' in response.context['message'])
 
 
@@ -962,20 +962,20 @@ class TestFileBrowserWithHadoop(object):
     self.c.post('/filebrowser/rmtree?skip_trash=true', dict(path=[HOME_TRASH_DIR2]))
 
     # No trash folder
-    response = self.c.get('/filebrowser/view/user/test?default_to_trash', follow=True)
+    response = self.c.get('/filebrowser/view=/user/test?default_to_trash', follow=True)
 
     assert_equal([], response.redirect_chain)
 
     self.c.post('/filebrowser/rmtree', dict(path=[PATH_1]))
 
     # We have a trash folder so a redirect (Current not always there)
-    response = self.c.get('/filebrowser/view/user/test?default_to_trash', follow=True)
+    response = self.c.get('/filebrowser/view=/user/test?default_to_trash', follow=True)
     assert_true(any(['.Trash' in page for page, code in response.redirect_chain]), response.redirect_chain)
 
     self.c.post('/filebrowser/rmtree?skip_trash=true', dict(path=[HOME_TRASH_DIR]))
 
     # No home trash, just regular root trash
-    response = self.c.get('/filebrowser/view/user/test?default_to_trash', follow=True)
+    response = self.c.get('/filebrowser/view=/user/test?default_to_trash', follow=True)
     assert_true(any(['.Trash' in page for page, code in response.redirect_chain]), response.redirect_chain)
 
 def view_i18n_helper(c, cluster, encoding, content):
@@ -992,10 +992,10 @@ def view_i18n_helper(c, cluster, encoding, content):
     f.write(bytestring)
     f.close()
 
-    response = c.get('/filebrowser/view%s?encoding=%s' % (filename, encoding))
+    response = c.get('/filebrowser/view=%s?encoding=%s' % (filename, encoding))
     assert_equal(response.context['view']['contents'], content)
 
-    response = c.get('/filebrowser/view%s?encoding=%s&end=8&begin=1' % (filename, encoding))
+    response = c.get('/filebrowser/view=%s?encoding=%s&end=8&begin=1' % (filename, encoding))
     assert_equal(response.context['view']['contents'],
                  unicode(bytestring[0:8], encoding, errors='replace'))
   finally:
@@ -1010,7 +1010,7 @@ def edit_i18n_helper(c, cluster, encoding, contents_pass_1, contents_pass_2):
   filename = prefix + u'//test-filebrowser//./test-edit-carácter-internacional with space and () en-hello pt-Olá ch-你好 ko-안녕 ru-Здравствуйте'
 
   # File doesn't exist - should be empty
-  edit_url = '/filebrowser/edit' + filename
+  edit_url = '/filebrowser/edit=' + filename
   response = c.get(edit_url)
   assert_equal(response.context['form'].data['path'], filename)
   assert_equal(response.context['form'].data['contents'], "")
@@ -1052,8 +1052,10 @@ def edit_i18n_helper(c, cluster, encoding, contents_pass_1, contents_pass_2):
   finally:
     cleanup_file(cluster, filename)
 
+
 def test_location_to_url():
-  assert_equal('/filebrowser/view/var/lib/hadoop-hdfs', location_to_url('/var/lib/hadoop-hdfs', False))
-  assert_equal('/filebrowser/view/var/lib/hadoop-hdfs', location_to_url('hdfs://localhost:8020/var/lib/hadoop-hdfs'))
-  assert_equal('/filebrowser/view/', location_to_url('hdfs://localhost:8020'))
-  assert_equal(None, location_to_url('thrift://10.0.0.1:9083'))
+  prefix = '/filebrowser/view='
+  assert_equal(prefix + '/var/lib/hadoop-hdfs', location_to_url('/var/lib/hadoop-hdfs', False))
+  assert_equal(prefix + '/var/lib/hadoop-hdfs', location_to_url('hdfs://localhost:8020/var/lib/hadoop-hdfs'))
+  assert_equal(prefix + '/', location_to_url('hdfs://localhost:8020'))
+  assert_equal(prefix + 's3%3A//bucket/key', location_to_url('s3://bucket/key'))

+ 8 - 8
apps/jobbrowser/src/jobbrowser/tests.py

@@ -782,35 +782,35 @@ def test_make_log_links():
 
   # FileBrowser
   assert_equal(
-      """<a href="/filebrowser/view/user/romain/tmp" target="_blank">hdfs://localhost:8020/user/romain/tmp</a>  &lt;dir&gt;""",
+      """<a href="/filebrowser/view=/user/romain/tmp" target="_blank">hdfs://localhost:8020/user/romain/tmp</a>  &lt;dir&gt;""",
       LinkJobLogs._make_links('hdfs://localhost:8020/user/romain/tmp  <dir>')
   )
   assert_equal(
-      """<a href="/filebrowser/view/user/romain/tmp" target="_blank">hdfs://localhost:8020/user/romain/tmp</a>&lt;dir&gt;""",
+      """<a href="/filebrowser/view=/user/romain/tmp" target="_blank">hdfs://localhost:8020/user/romain/tmp</a>&lt;dir&gt;""",
       LinkJobLogs._make_links('hdfs://localhost:8020/user/romain/tmp<dir>')
   )
   assert_equal(
-      """output: <a href="/filebrowser/view/user/romain/tmp" target="_blank">/user/romain/tmp</a>  &lt;dir&gt;""",
+      """output: <a href="/filebrowser/view=/user/romain/tmp" target="_blank">/user/romain/tmp</a>  &lt;dir&gt;""",
       LinkJobLogs._make_links('output: /user/romain/tmp  <dir>')
   )
   assert_equal(
-      'Successfully read 3760 records (112648 bytes) from: &quot;<a href="/filebrowser/view/user/hue/pig/examples/data/midsummer.txt" target="_blank">/user/hue/pig/examples/data/midsummer.txt</a>&quot;',
+      'Successfully read 3760 records (112648 bytes) from: &quot;<a href="/filebrowser/view=/user/hue/pig/examples/data/midsummer.txt" target="_blank">/user/hue/pig/examples/data/midsummer.txt</a>&quot;',
       LinkJobLogs._make_links('Successfully read 3760 records (112648 bytes) from: "/user/hue/pig/examples/data/midsummer.txt"')
   )
   assert_equal(
-      'data,upper_case  MAP_ONLY  <a href="/filebrowser/view/user/romain/out/fffff" target="_blank">hdfs://localhost:8020/user/romain/out/fffff</a>,',
+      'data,upper_case  MAP_ONLY  <a href="/filebrowser/view=/user/romain/out/fffff" target="_blank">hdfs://localhost:8020/user/romain/out/fffff</a>,',
       LinkJobLogs._make_links('data,upper_case  MAP_ONLY  hdfs://localhost:8020/user/romain/out/fffff,')
   )
   assert_equal(
-      'MAP_ONLY  <a href="/filebrowser/view/user/romain/out/fffff" target="_blank">hdfs://localhost:8020/user/romain/out/fffff</a>\n2013',
+      'MAP_ONLY  <a href="/filebrowser/view=/user/romain/out/fffff" target="_blank">hdfs://localhost:8020/user/romain/out/fffff</a>\n2013',
       LinkJobLogs._make_links('MAP_ONLY  hdfs://localhost:8020/user/romain/out/fffff\n2013')
   )
   assert_equal(
-      ' <a href="/filebrowser/view/jobs.tsv" target="_blank">/jobs.tsv</a> ',
+      ' <a href="/filebrowser/view=/jobs.tsv" target="_blank">/jobs.tsv</a> ',
       LinkJobLogs._make_links(' /jobs.tsv ')
   )
   assert_equal(
-      '<a href="/filebrowser/view/user/romain/job_pos_2012.tsv" target="_blank">hdfs://localhost:8020/user/romain/job_pos_2012.tsv</a>',
+      '<a href="/filebrowser/view=/user/romain/job_pos_2012.tsv" target="_blank">hdfs://localhost:8020/user/romain/job_pos_2012.tsv</a>',
       LinkJobLogs._make_links('hdfs://localhost:8020/user/romain/job_pos_2012.tsv')
   )
 

+ 0 - 1
apps/metastore/src/metastore/templates/describe_partitions.mako

@@ -14,7 +14,6 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 <%!
-  from filebrowser.views import location_to_url
   from desktop.views import commonheader, commonfooter
   from django.utils.translation import ugettext as _
 %>

+ 1 - 1
apps/oozie/src/oozie/templates/editor/edit_workflow.mako

@@ -45,7 +45,7 @@ ${ layout.menubar(section='workflows') }
         <li><a href="#properties"><i class="fa fa-cog"></i> ${ _('Properties') }</a></li>
         % if user_can_edit_job:
           <li>
-            <a data-bind="attr: {href: '/filebrowser/view' + fixLeadingSlash(deployment_dir()) }" target="_blank" title="${ _('Go upload additional files and libraries to the deployment directory on HDFS') }" rel="tooltip" data-placement="right"><i class="fa fa-folder-open"></i> ${ _('Workspace') }</a>
+            <a data-bind="attr: {href: '/filebrowser/view=' + fixLeadingSlash(deployment_dir()) }" target="_blank" title="${ _('Go upload additional files and libraries to the deployment directory on HDFS') }" rel="tooltip" data-placement="right"><i class="fa fa-folder-open"></i> ${ _('Workspace') }</a>
           </li>
         % endif
 

+ 3 - 3
apps/oozie/src/oozie/templates/editor2/common_workflow.mako

@@ -549,13 +549,13 @@
 <script type="text/html" id="common-fs-link">
 <!-- ko if: $data.path.length > 0 -->
   <!-- ko if: with_label -->
-    <a data-bind="attr: {href: '/filebrowser/view' + ($data.path[0] != '/' ? $root.workflow.properties.deployment_dir() + '/' : '') + $data.path , title: '${ _('Open') } '+ $data.path }" target="_blank">
+    <a data-bind="attr: {href: '/filebrowser/view=' + ($data.path[0] != '/' ? $root.workflow.properties.deployment_dir() + '/' : '') + $data.path , title: '${ _('Open') } '+ $data.path }" target="_blank">
       <span data-bind="text: $data.path.lastIndexOf('/') == $data.path.length - 1 ? $data.path : $data.path.split('/').pop()"></span>
     </a>
   <!-- /ko -->
 
    <!-- ko if: ! with_label -->
-     <a data-bind="attr: {href: '/filebrowser/view' + ($data.path[0] != '/' ? $root.workflow.properties.deployment_dir() + '/' : '') + $data.path }" target="_blank" title="${ _('Open') }">
+     <a data-bind="attr: {href: '/filebrowser/view=' + ($data.path[0] != '/' ? $root.workflow.properties.deployment_dir() + '/' : '') + $data.path }" target="_blank" title="${ _('Open') }">
        <i class="fa fa-external-link-square"></i>
      </a>
    <!-- /ko -->
@@ -565,7 +565,7 @@
 
 <script type="text/html" id="param-fs-link">
   <!-- ko if: path.split('=', 2)[1] && path.split('=', 2)[1].charAt(0) == '/' -->
-    <a data-bind="attr: {href: '/filebrowser/view' + $data.path.split('=', 2)[1] }" target="_blank" title="${ _('Open') }">
+    <a data-bind="attr: {href: '/filebrowser/view=' + $data.path.split('=', 2)[1] }" target="_blank" title="${ _('Open') }">
       <i class="fa fa-external-link-square"></i>
     </a>
   <!-- /ko -->

+ 1 - 1
apps/oozie/src/oozie/templates/editor2/coordinator_editor.mako

@@ -299,7 +299,7 @@ ${ layout.menubar(section='coordinators', is_editor=True, pullright=buttons) }
                   </span>
                   <span data-bind="visible: dataset_variable().length > 0 && instance_choice() != 'range'">
                     ${ _('Will convert to') }
-                    <a target="_blank" data-bind="text: convertDatasetVariables(dataset_variable(), same_start(), start(), same_frequency(), frequency_unit(), start_instance(), instance_choice()), attr: {'href': '/filebrowser/view' + convertDatasetVariables(dataset_variable(), same_start(), start(), same_frequency(), frequency_unit(), start_instance(), instance_choice())}"></a>
+                    <a target="_blank" data-bind="text: convertDatasetVariables(dataset_variable(), same_start(), start(), same_frequency(), frequency_unit(), start_instance(), instance_choice()), attr: {'href': '/filebrowser/view=' + convertDatasetVariables(dataset_variable(), same_start(), start(), same_frequency(), frequency_unit(), start_instance(), instance_choice())}"></a>
                   </span>
                   </a>
                 </span>

+ 1 - 1
apps/oozie/src/oozie/templates/editor2/workflow_editor.mako

@@ -55,7 +55,7 @@ ${ commonheader(_("Workflow Editor"), "Oozie", user, "40px") | n,unicode }
 
     <a title="${ _('Workspace') }" target="_blank" rel="tooltip" data-placement="right"
         data-original-title="${ _('Go upload additional files and libraries to the deployment directory on HDFS') }"
-        data-bind="css: {'btn': true}, attr: { href: '/filebrowser/view' + $root.workflow.properties.deployment_dir() }">
+        data-bind="css: {'btn': true}, attr: { href: '/filebrowser/view=' + $root.workflow.properties.deployment_dir() }">
       <i class="fa fa-fw fa-folder-open"></i>
     </a>
 

+ 5 - 5
apps/oozie/src/oozie/templates/utils.inc.mako

@@ -94,9 +94,9 @@
     <% path = Hdfs.urlsplit(url)[2] %>
     % if path:
       % if path.startswith(posixpath.sep):
-        <a href="/filebrowser/view${path}">${ url }</a>
+        <a href="/filebrowser/view=${path}">${ url }</a>
       % else:
-        <a href="/filebrowser/home_relative_view/${path}">${ url }</a>
+        <a href="/filebrowser/home_relative_view=/${path}">${ url }</a>
       % endif
     % else:
       ${ url }
@@ -111,9 +111,9 @@
     <% path = Hdfs.urlsplit(url)[2] %>
     % if path:
       % if path.startswith(posixpath.sep):
-        /filebrowser/view${path}
+        /filebrowser/view=${path}
       % else:
-        /filebrowser/home_relative_view/${path}
+        /filebrowser/home_relative_view=/${path}
       % endif
     % else:
       javascript:void(0)
@@ -360,7 +360,7 @@
         // check if it's a relative path
         var pathAddition = "";
         if ($.trim(inputElement.val()) != "") {
-          var checkPath = "/filebrowser/chooser${ workflow.deployment_dir }" + "/" + inputElement.val();
+          var checkPath = "/filebrowser/chooser=${ workflow.deployment_dir }" + "/" + inputElement.val();
           $.getJSON(checkPath, function (data) {
             pathAddition = "${ workflow.deployment_dir }/";
             callFileChooser();

+ 2 - 2
apps/pig/src/pig/models.py

@@ -160,9 +160,9 @@ def hdfs_link(url):
     path = Hdfs.urlsplit(url)[2]
     if path:
       if path.startswith(posixpath.sep):
-        return "/filebrowser/view" + path
+        return "/filebrowser/view=" + path
       else:
-        return "/filebrowser/home_relative_view/" + path
+        return "/filebrowser/home_relative_view=/" + path
     else:
       return url
   else:

+ 3 - 3
apps/pig/src/pig/templates/app.mako

@@ -927,7 +927,7 @@ ${ commonshare() | n,unicode }
         CodeMirror.isTable = false;
         if (_partial.toLowerCase().indexOf("load") > -1 || _partial.toLowerCase().indexOf("into") > -1) {
           var _path = _partial.substring(_partial.lastIndexOf("'") + 1);
-          var _autocompleteUrl = "/filebrowser/view";
+          var _autocompleteUrl = "/filebrowser/view=";
           if (_path.indexOf("/") == 0) {
             _autocompleteUrl += _path.substr(0, _path.lastIndexOf("/"));
           }
@@ -1000,11 +1000,11 @@ ${ commonshare() | n,unicode }
             var _path = _partial.substring(_partial.lastIndexOf("'") + 1);
             if (_path[0] == "/") {
               if (_path.lastIndexOf("/") != 0) {
-                showHdfsAutocomplete("/filebrowser/view" + _partial.substring(_partial.lastIndexOf("'") + 1) + "?format=json", false);
+                showHdfsAutocomplete("/filebrowser/view=" + _partial.substring(_partial.lastIndexOf("'") + 1) + "?format=json", false);
               }
             }
             else {
-              showHdfsAutocomplete("/filebrowser/view" + USER_HOME + _partial.substring(_partial.lastIndexOf("'") + 1) + "?format=json", false);
+              showHdfsAutocomplete("/filebrowser/view=" + USER_HOME + _partial.substring(_partial.lastIndexOf("'") + 1) + "?format=json", false);
             }
           }
         }

+ 3 - 3
apps/search/src/search/static/search/js/search.utils.js

@@ -49,17 +49,17 @@ function addTemplateFunctions(item) {
 
   item.hue_fn_preview = function () {
     return function (val) {
-      return '<a href="/filebrowser/view/' + $.trim(Mustache.render(val, item)) + '">' + $.trim(Mustache.render(val, item)) + '</a>';
+      return '<a href="/filebrowser/view=/' + $.trim(Mustache.render(val, item)) + '">' + $.trim(Mustache.render(val, item)) + '</a>';
     }
   };
   item.hue_fn_embeddeddownload = function () {
     return function (val) {
-      return '<a href="/filebrowser/download/' + $.trim(Mustache.render(val, item)) + '?disposition=inline">' + $.trim(Mustache.render(val, item)) + '</a>';
+      return '<a href="/filebrowser/download=/' + $.trim(Mustache.render(val, item)) + '?disposition=inline">' + $.trim(Mustache.render(val, item)) + '</a>';
     }
   };
   item.hue_fn_download = function () {
     return function (val) {
-      return '<a href="/filebrowser/download/' + $.trim(Mustache.render(val, item)) + '>' + $.trim(Mustache.render(val, item)) + '</a>';
+      return '<a href="/filebrowser/download=/' + $.trim(Mustache.render(val, item)) + '>' + $.trim(Mustache.render(val, item)) + '</a>';
     }
   };
   item.hue_fn_date = function () {

+ 1 - 1
apps/security/src/security/static/security/js/hdfs.ko.js

@@ -376,7 +376,7 @@ var Assist = function (vm, assist) {
   }
 
   self.openPath = function (obj) {
-    window.open("/filebrowser/view" + obj.path(), '_blank');
+    window.open("/filebrowser/view=" + obj.path(), '_blank');
   }
 
   self.loadParents = function (breadcrumbs) {

+ 1 - 1
apps/security/src/security/static/security/js/hive.ko.js

@@ -647,7 +647,7 @@ var Assist = function (vm, initial) {
     e.stopPropagation();
     e.stopImmediatePropagation();
     self.fetchHivePath(obj.path(), function(data){
-      location.href = "/security/hdfs#" + data.hdfs_link.substring("/filebrowser/view".length);
+      location.href = "/security/hdfs#" + data.hdfs_link.substring("/filebrowser/view=".length);
     });
   }
 

+ 5 - 5
apps/security/src/security/templates/hdfs.mako

@@ -97,7 +97,7 @@ ${ layout.menubar(section='hdfs') }
               <div class="path-container">
                 <div class="input-append span12">
                   <input id="path" class="path" type="text" data-bind="value: $root.assist.path" autocomplete="off" />
-                  <a data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }" target="_blank" title="${ _('Open in File Browser') }" class="btn btn-inverse">
+                  <a data-bind="attr: { href: '/filebrowser/view=' + $root.assist.path() }" target="_blank" title="${ _('Open in File Browser') }" class="btn btn-inverse">
                     <i class="fa fa-external-link"></i>
                   </a>
                 </div>
@@ -145,7 +145,7 @@ ${ layout.menubar(section='hdfs') }
 
                   <div class="acl-panel-content">
                     <span class="fake-pre" data-bind="visible: $root.assist.showAclsAsText">
-                      # file: <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }, text: $root.assist.path()" target="_blank"></a><br/>
+                      # file: <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view=' + $root.assist.path() }, text: $root.assist.path()" target="_blank"></a><br/>
                       # owner: <span data-bind="text: $root.assist.owner"></span><br/>
                       # group: <span data-bind="text: $root.assist.group"></span><br/>
                       <div data-bind="foreach: $root.assist.regularAcls">
@@ -158,7 +158,7 @@ ${ layout.menubar(section='hdfs') }
 
                     <span data-bind="visible: ! $root.assist.showAclsAsText()">
                       <h4>${ _('Path') }</h4>
-                      <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }, text: $root.assist.path()" target="_blank" title="${ _('Open in File Browser') }" rel="tooltip"></a>
+                      <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view=' + $root.assist.path() }, text: $root.assist.path()" target="_blank" title="${ _('Open in File Browser') }" rel="tooltip"></a>
 
                       <h4>${ _('User/Group') }</h4>
                       <i class="fa fa-user" style="color: #999999" title="${_('User')}"></i> <span title="${_('User')}" data-bind="text: $root.assist.owner"></span>&nbsp;
@@ -231,7 +231,7 @@ ${ layout.menubar(section='hdfs') }
       <div class="span4">
         <h4>${ _('to apply to the selection') }</h4>
         <ul class="unstyled modal-panel" data-bind="foreach: $root.assist.checkedItems">
-          <li><a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + path }, text: path" target="_blank" title="${ _('Open in File Browser') }" rel="tooltip"></a></li>
+          <li><a class="force-word-break" data-bind="attr: { href: '/filebrowser/view=' + path }, text: path" target="_blank" title="${ _('Open in File Browser') }" rel="tooltip"></a></li>
         </ul>
       </div>
     </div>
@@ -242,7 +242,7 @@ ${ layout.menubar(section='hdfs') }
         <h4>${ _('ACLs to apply') }</h4>
 
         <span class="fake-pre modal-panel">
-          # file: <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }, text: $root.assist.path()" target="_blank"></a><br/>
+          # file: <a class="force-word-break" data-bind="attr: { href: '/filebrowser/view=' + $root.assist.path() }, text: $root.assist.path()" target="_blank"></a><br/>
           # owner: <span data-bind="text: $root.assist.owner"></span><br/>
           # group: <span data-bind="text: $root.assist.group"></span><br/>
           <div data-bind="foreach: $root.assist.regularAcls">

+ 1 - 1
apps/security/src/security/templates/hive.mako

@@ -114,7 +114,7 @@ ${ layout.menubar(section='hive') }
     <!-- /ko -->
 
     <!-- ko if: privilegeType() == 'uri' -->
-      <i class="fa fa-long-arrow-right"></i> <i class="fa fa-file-o"></i> <i class="fa fa-long-arrow-right"></i> <a data-bind="attr: { href: '/filebrowser/view/' + URI().split('/')[3] }" target="_blank"><span data-bind="text: URI"></span></a>
+      <i class="fa fa-long-arrow-right"></i> <i class="fa fa-file-o"></i> <i class="fa fa-long-arrow-right"></i> <a data-bind="attr: { href: '/filebrowser/view=/' + URI().split('/')[3] }" target="_blank"><span data-bind="text: URI"></span></a>
     <!-- /ko -->
 
     <i class="fa fa-long-arrow-right"></i> action=<span data-bind="text: action"></span>

+ 2 - 2
apps/sqoop/src/sqoop/static/sqoop/js/sqoop.jobs.js

@@ -127,7 +127,7 @@ var jobs = (function($) {
             });
           }
         });
-        return (output_directory) ? '/filebrowser/view' + output_directory : null;
+        return (output_directory) ? '/filebrowser/view=' + output_directory : null;
       });
       self.inputDirectoryFilebrowserURL = ko.computed(function() {
         var input_directory = null;
@@ -140,7 +140,7 @@ var jobs = (function($) {
             });
           }
         });
-        return (input_directory) ? '/filebrowser/view' + input_directory : null;
+        return (input_directory) ? '/filebrowser/view=' + input_directory : null;
       });
       self.storageType = ko.computed(function() {
         var storage_type = null;

+ 1 - 1
desktop/core/src/desktop/models.py

@@ -820,7 +820,7 @@ def get_data_link(meta):
     elif 'fam' in meta:
       link += '[%(fam)s]' % meta
   elif meta['type'] == 'hdfs':
-    link = '/filebrowser/view%(path)s' % meta # Could add a byte #
+    link = '/filebrowser/view=%(path)s' % meta # Could add a byte #
   elif meta['type'] == 'link':
     link = meta['link']
   elif meta['type'] == 'hive':

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/jquery.filechooser.js

@@ -106,7 +106,7 @@
         else {
           $(_parent.element).html("<i style=\"font-size: 24px; color: #DDD\" class=\"fa fa-spinner fa-spin\"></i>");
         }
-        $.getJSON("/filebrowser/chooser" + path, function (data) {
+        $.getJSON("/filebrowser/chooser=" + path, function (data) {
             $(_parent.element).empty();
             path = data.current_dir_path; // use real path.
             var _flist = $("<ul>").addClass("unstyled").css("margin-left", "2px");

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/jquery.hdfsautocomplete.js

@@ -208,7 +208,7 @@
       }
     });
 
-    var BASE_PATH = "/filebrowser/view";
+    var BASE_PATH = "/filebrowser/view=";
     var _currentFiles = [];
 
     function showHdfsAutocomplete(callback) {

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/jquery.hdfstree.js

@@ -125,7 +125,7 @@
     var _root = $("<ul>").addClass("content unstyled").attr("data-path", "__JHUEHDFSTREE__ROOT__").attr("data-loaded", "true");
     _root.appendTo(_tree.find("li"));
 
-    var BASE_PATH = "/filebrowser/view";
+    var BASE_PATH = "/filebrowser/view=";
     var _currentFiles = [];
     
     function escapeSingleQuote(path) {

+ 1 - 1
desktop/core/src/desktop/tests.py

@@ -944,5 +944,5 @@ def test_get_data_link():
   assert_equal('/hbase/#Cluster/document_demo/query/20150527[f1]', get_data_link({'type': 'hbase', 'table': 'document_demo', 'row_key': '20150527', 'fam': 'f1'}))
   assert_equal('/hbase/#Cluster/document_demo/query/20150527[f1:c1]', get_data_link({'type': 'hbase', 'table': 'document_demo', 'row_key': '20150527', 'fam': 'f1', 'col': 'c1'}))
 
-  assert_equal('/filebrowser/view/data/hue/1', get_data_link({'type': 'hdfs', 'path': '/data/hue/1'}))
+  assert_equal('/filebrowser/view=/data/hue/1', get_data_link({'type': 'hdfs', 'path': '/data/hue/1'}))
   assert_equal('/metastore/table/default/sample_07', get_data_link({'type': 'hive', 'database': 'default', 'table': 'sample_07'}))