You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by vs...@apache.org on 2017/06/22 04:05:39 UTC

ambari git commit: AMBARI-21264.Integrate new hdfs-file browser in WFD(Venkata Sairam)

Repository: ambari
Updated Branches:
  refs/heads/trunk 7335bf7e2 -> b53cf918f


AMBARI-21264.Integrate new hdfs-file browser in WFD(Venkata Sairam)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b53cf918
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b53cf918
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b53cf918

Branch: refs/heads/trunk
Commit: b53cf918fc27d55a11fae25af9c4eba6dcee26fb
Parents: 7335bf7
Author: Venkata Sairam <ve...@gmail.com>
Authored: Thu Jun 22 09:35:30 2017 +0530
Committer: Venkata Sairam <ve...@gmail.com>
Committed: Thu Jun 22 09:35:30 2017 +0530

----------------------------------------------------------------------
 .../resources/ui/app/components/hdfs-browser.js |   8 +-
 .../ui/app/services/workspace-manager.js        |   5 +
 .../src/main/resources/ui/app/styles/app.less   |   3 +-
 .../app/templates/components/hdfs-browser.hbs   |  16 +-
 .../main/resources/ui/app/utils/hdfsviewer.js   |   3 +
 .../wfmanager/src/main/resources/ui/bower.json  |   1 -
 .../addon/components/directory-viewer.js        | 325 +++++++++++++------
 .../hdfs-directory-viewer/addon/styles/app.css  | 189 +++++++++++
 .../templates/components/directory-viewer.hbs   | 146 +++++++++
 .../addon/utils/viewer-config.js                |   3 +
 .../hdfs-directory-viewer/bower.json            |   1 -
 .../hdfs-directory-viewer/index.js              |   3 -
 .../hdfs-directory-viewer/package.json          |   5 +-
 .../src/main/resources/ui/package.json          |   3 +-
 14 files changed, 582 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
index 0194f13..b1fb29a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
@@ -20,6 +20,7 @@ import HdfsViewerConfig from '../utils/hdfsviewer';
 export default Ember.Component.extend({
   config: HdfsViewerConfig.create(),
   uploaderService : Ember.inject.service('hdfs-file-uploader'),
+  userInfo : Ember.inject.service('workspace-manager'),
   initialize:function(){
     var self=this;
     self.$("#filediv").modal("show");
@@ -27,8 +28,12 @@ export default Ember.Component.extend({
       self.sendAction('closeWorkflowSubmitConfigs');
       self.sendAction("closeFileBrowser");
     });
-
   }.on('didInsertElement'),
+  setUserData : function() {
+    this.set("homeDirectory", "/user/"+this.get("userInfo").getUserName());
+    this.set("selectedPath", "/user/"+this.get("userInfo").getUserName());
+    this.set("filePath", "/user/"+this.get("userInfo").getUserName());
+  }.on("init"),
   selectFileType: "all",//can be all/file/folder
   selectedPath:"",
   isDirectory:false,
@@ -81,6 +86,7 @@ export default Ember.Component.extend({
     },
     viewerSelectedPath(data) {
       this.set("selectedPath",data.path);
+      this.set("filePath",data.path);
       this.set("isDirectory",data.isDirectory);
       this.set("alertMessage",null);
     },

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
index 8636fd5..4ac5ae1 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
@@ -21,6 +21,7 @@ export default Ember.Service.extend({
   tabsInfo : {},
   workInProgress : {},
   userInfo : Ember.inject.service('user-info'),
+  userName : null,
   setLastActiveTab(tabId){
     this.get("userInfo").getUserData().then(function(data){
        localStorage.setItem(data+"-lastActiveTab", tabId);
@@ -38,6 +39,7 @@ export default Ember.Service.extend({
   restoreTabs(){
       var deferred = Ember.RSVP.defer();
       this.get("userInfo").getUserData().then(function(data){
+        this.set("userName", data);
         var tabs = localStorage.getItem(data+'-tabsInfo');
         deferred.resolve(JSON.parse(tabs));
       }.bind(this)).catch(function(e){
@@ -87,5 +89,8 @@ export default Ember.Service.extend({
     }.bind(this)).catch(function(e){
       console.error(e);
     });
+  },
+  getUserName(){
+   return this.get("userName");
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
index 0603b57..597e2e8 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
@@ -1060,6 +1060,7 @@ input:invalid {
   width: 100%;
 }
 .hdfs-browse{
+  height: 500px;
   max-height: 500px;
   overflow: scroll;
 }
@@ -1369,7 +1370,7 @@ input:invalid {
 }
 
 #cyRenderer input:invalid {
-  border: 1px solid @defaultRed;
+  border: 2px solid @defaultRed;
 }
 
 .cy-panzoom-panner{

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
index 5779e36..cbd2a1f 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
@@ -53,26 +53,14 @@
         {{/unless}}
         <div class="panel-body">
           <div>
-            {{#if showUploadSuccess}}
-              <div id="success-alert"class="alert alert-success alert-dismissible fade in" role="alert">
-                <span>File uploaded</span>
-              </div>
-            {{/if}}
-            {{#if alertMessage}}
-              <div class="alert alert-{{alertType}} col-xs-24">
-                {{alertMessage}}
-                {{#if alertDetails}}
-                -{{alertDetails}}
-                {{/if}}
-              </div>
-
-            {{/if}}
           <div class="directory-viewer-wrap hdfs-browse">
             {{#directory-viewer
               config=config
               errorAction="viewerError"
               pathSelectAction="viewerSelectedPath"
               uploaderService=uploaderService
+              width=850
+              homeDirectory = homeDirectory
             }}{{/directory-viewer}}
           </div>
         </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/app/utils/hdfsviewer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/utils/hdfsviewer.js b/contrib/views/wfmanager/src/main/resources/ui/app/utils/hdfsviewer.js
index 080409b..5e30c60 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/utils/hdfsviewer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/utils/hdfsviewer.js
@@ -25,5 +25,8 @@ export default ViewerConfig.extend({
 
   listDirectoryUrl(pathParams) {
     return   Ember.ENV.FILE_API_URL+`/fileops/listdir?${pathParams}`;
+  },
+  createDirectoryUrl() {
+    return Ember.ENV.FILE_API_URL+`/fileops/mkdir`;
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/bower.json b/contrib/views/wfmanager/src/main/resources/ui/bower.json
index 75ac7a7..06fc3e3 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/bower.json
+++ b/contrib/views/wfmanager/src/main/resources/ui/bower.json
@@ -19,7 +19,6 @@
     "eonasdan-bootstrap-datetimepicker": "~4.17.37",
     "code-prettify": "*",
     "abdmob/x2js": "~1.2.0",
-    "bootstrap-treeview": "~1.2.0",
     "datatables": "~1.10.11",
     "vkBeautify": "https://github.com/vkiryukhin/vkBeautify.git",
     "cytoscape": "~2.7.7",

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/components/directory-viewer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/components/directory-viewer.js b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/components/directory-viewer.js
index 65746e8..2f2b547 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/components/directory-viewer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/components/directory-viewer.js
@@ -21,30 +21,81 @@ import layout from '../templates/components/directory-viewer';
 
 export default Ember.Component.extend({
   layout,
+  counter: 0,
   config: Ember.Object.create({}),
   classNames: ['directory-viewer'],
   startPath: '/',
-  treeData: Ember.A(),
+  folderName:'',
+  isDirectory: true,
+  isFile: true,
+  fileBrowserHeight: '850',
+  fileBrowserWidth: '650',
+  maxBreadCrumbsCount: 3,
+  elipsisLength: 8,
+  isFolderCreationSuccess: null,
+  isFolderCreationFailure: null,
+  isFolderCreationprogress:false,
+  // homeDirectory: '/app-logs/cstm-hdfs/logs',
+  fileSystem: Ember.A(),
   currentPath: Ember.computed.oneWay('startPath'),
-  currentQueryParam: Ember.computed('currentPath', function() {
+  currentPathArray: [{'path':'/'}],
+  breadCrumbs: {},
+  isCreateFolder : false,
+  folderAccessError: {},
+  createFolderError: {},
+  filteredFileSytemInfo: Ember.computed('fileSystem', 'isDirectory', 'isFile', function() {
+    return this.get('fileSystem').filter( (record) => {
+      if(record.traverse) {
+         return true;
+      }
+      if(this.get('isDirectory') && this.get('isFile')) {
+         return record.isDirectory || !record.isDirectory;
+      }
+      if(this.get('isDirectory')) {
+         return record.isDirectory;
+      }
+      if(this.get('isFile')) {
+         return !record.isDirectory;
+      }
+      return;
+  });
+  }),
+  currentQueryParam: Ember.computed('currentPath', 'homeDirectory', function() {
+    if(this.get('counter') === 1 && this.get('homeDirectory')){
+      this.set('currentPath', this.get('homeDirectory'));
+    }
     return Ember.$.param({path: this.get('currentPath')});
   }),
-
+  createFolderQueryParam: Ember.computed('currentPath', 'homeDirectory', 'folderName', function() {
+    return {path: this.get('currentPath')+"/"+this.get('folderName')};
+  }),
+  isDataLoading: true,
   startFetch: Ember.on('didInitAttrs', function() {
-    this.get('uploaderService').on('uploadSuccess', function(){
-      this.fetchData();
-    }.bind(this));
+    if(this.get('width')) {
+      this.set('fileBrowserWidth', this.get('width'));
+    }
+    if(this.get('height')) {
+      this.set('fileBrowserHeight', this.get('height'));
+    }
     this.fetchData();
   }),
-
-
+  setFileBroswerHeightAndWidth: Ember.on('didInsertElement', function() {
+    Ember.$('.top-header, #file-view-unix').css('width', this.get('fileBrowserWidth'));
+  }),
   fetchData: function() {
+    this.incrementProperty('counter');
+    this.startFileSystemFetchProgress();
+    this.set('folderAccessError', {});
     this.listPath(this.get('currentQueryParam')).then(
       (response) => {
         let list = this.filterDirectoriesIfRequired(response.files);
-        this.modifyTreeViewData(list);
+        this.stopFileSystemFetchProgress();
+        this.modifyFileSystemData(list);
       }, (error) => {
+        this.set('folderAccessError', error.responseJSON);
         this.sendAction('errorAction', error);
+        this.set('errorMsg', 'Error while accessing.Please try again.');
+        this.stopFileSystemFetchProgress();
       }
     );
   },
@@ -60,7 +111,29 @@ export default Ember.Component.extend({
       headers: headers
     });
   },
-
+  createFolder() {
+    let deferred = Ember.RSVP.defer();
+    let config = this.get('config');
+    let listUrl = config.createDirectoryUrl();
+    let headers = config.getHeaders();
+    headers = this.setHeadersForMkdir(headers);
+    Ember.$.ajax(listUrl, {
+      headers: headers,
+      method:'PUT',
+      data:JSON.stringify(this.get('createFolderQueryParam'))
+    }).done(function(data){
+        deferred.resolve(data);
+    }).fail(function(data){
+        deferred.reject(data);
+    });
+    return deferred.promise;
+  },
+  setHeadersForMkdir(headers) {
+    headers['Accept'] = 'application/json';
+    headers.dataType = 'json';
+    headers['Content-Type'] = 'application/json; charset=UTF-8';
+    return headers;
+  },
   filterDirectoriesIfRequired: function(files) {
     let showOnlyDirectories = this.get('config.showOnlyDirectories');
     return files.filter((entry) => {
@@ -68,7 +141,7 @@ export default Ember.Component.extend({
     });
   },
 
-  modifyTreeViewData: function(response) {
+  modifyFileSystemData: function(response) {
     let paths = response.map((entry) => {
       let isDirectory = entry.isDirectory;
       let icon = isDirectory ? this.get('config.folderIcon') : this.get('config.fileIcon');
@@ -77,120 +150,160 @@ export default Ember.Component.extend({
         pathSegment: this.getNameForPath(entry.path),
         isDirectory: isDirectory,
         icon: icon,
-        text: this.getNameForPath(entry.path)
+        permission: entry.permission,
+        text: this.getNameForPath(entry.path),
+        selectedClass: ''
       };
       if(isDirectory) {
         data.nodes = Ember.A();
       }
       return data;
     });
-
-    var currentPath = this.get('currentPath');
-    var newTreeData = Ember.copy(this.get('treeData'), true);
-    if(currentPath === '/') {
-      newTreeData = paths;
-    } else {
-      this.insertPathToTreeData(newTreeData, paths, currentPath.substring(1));
+    this.setCurrentPathAsList();
+    paths = this.insertRootAsFirstPath(paths, this.get('currentPath'));
+    this.setBreadCrumbsAndListMenu();
+    this.set('fileSystem', paths);
+    this.set('errorMsg', null);
+    this.stopFileSystemFetchProgress();
+  },
+  insertRootAsFirstPath(paths, currentPath) {
+    if(currentPath !== '/') {
+       paths.unshift({traverse:true, path: this.get('currentPathArray')[this.get('currentPathArray').length-2 >=0 ?this.get('currentPathArray').length-2:this.get('currentPathArray').length-1].path});
     }
-
-    this.set('treeData', newTreeData);
-    this.send('refreshTreeView');
+    return paths;
   },
-
-  insertPathToTreeData(treeData, paths, pathSegment) {
-    let isFinalSegment = pathSegment.indexOf('/') === -1? true: false;
-    let firstPathSegment = isFinalSegment? pathSegment: pathSegment.substring(0, pathSegment.indexOf('/'));
-    if(treeData.length === 0) {
-      treeData.pushObjects(paths);
+  setBreadCrumbsAndListMenu() {
+    let currentPathArray = this.get('currentPathArray');
+    if(currentPathArray.length > this.get('maxBreadCrumbsCount')){
+       this.set("breadCrumbs", {'dropDownMenu': currentPathArray.splice(0, currentPathArray.length - this.get('maxBreadCrumbsCount')), 'breadCrumbsMenu': currentPathArray.splice(0, currentPathArray.length)});
     } else {
-      treeData.forEach((entry) => {
-        entry.state = {};
-        if (entry.pathSegment === firstPathSegment) {
-          let nodesLength = entry.nodes.length;
-          entry.state.expanded = true;
-          if(nodesLength === 0) {
-            paths.forEach((pathEntry) => {
-              entry.nodes.push(pathEntry);
-            });
-          } else if(nodesLength > 0 && nodesLength !== paths.length && isFinalSegment){
-            entry.nodes = paths;
-          } else {
-            this.insertPathToTreeData(entry.nodes, paths, pathSegment.substring(pathSegment.indexOf('/') + 1));
-          }
-        } else {
-          this.collapseAll(entry);
-        }
-      });
+       this.set("breadCrumbs", {'breadCrumbsMenu': currentPathArray});
     }
   },
-
-  collapseAll: function(node) {
-    if (Ember.isNone(node.state)) {
-      node.state = {};
-    }
-    node.state.expanded = false;
-    if(!Ember.isNone(node.nodes)) {
-      node.nodes.forEach((entry) => {
-        this.collapseAll(entry);
-      });
+  shortenName(name) {
+    return name.length > this.get('elipsisLength') ? name.substring(0, this.get('elipsisLength'))+'...':name;
+  },
+  setCurrentPathAsList() {
+    let currentPath = this.get('currentPath'), relPath = "", currentPathArr = currentPath.split('/');
+    if(currentPath === "/") {
+      currentPathArr = [""];
     }
+    this.set('currentPathArray', []);
+    currentPathArr.forEach(function(item, i) {
+        if(i !== 1) {
+         relPath = relPath + "/"+ item;
+        } else if(i === 1){
+         relPath = relPath + currentPathArr[i];
+        }
+        console.log(relPath+" is relPath");
+        if(i === currentPathArr.length-1){
+           if(0 === currentPathArr.length-1) {
+             this.get('currentPathArray').push({'path':relPath, 'fullFileName' : item, 'name':item?this.shortenName(item):'root', isCurrentFolder: true, isRoot:true});
+           } else{
+             this.get('currentPathArray').push({'path':relPath, 'fullFileName' : item, 'name':item?this.shortenName(item):'root', isCurrentFolder: true});
+           }
+        } else if(i === 0){
+           this.get('currentPathArray').push({'path':relPath, 'fullFileName' : item, 'name':item?this.shortenName(item):'root', isRoot:true});
+        } else {
+           this.get('currentPathArray').push({'path':relPath ,'fullFileName' : item,  'name':item?this.shortenName(item):'root'});
+        }
+    }.bind(this));
   },
-
   getNameForPath: function(path) {
     return path.substring(path.lastIndexOf("/") + 1);
   },
-
-  collapseAllExceptPath: function(pathSegment) {
-    let collapseAll = function(nodes, pathSegment) {
-      var firstPathSegment;
-      if (pathSegment.indexOf('/') !== -1) {
-        firstPathSegment = pathSegment.substring(0, pathSegment.indexOf('/'));
-      } else {
-        firstPathSegment = pathSegment;
-      }
-
-      nodes.forEach((entry) => {
-        if (Ember.isNone(entry.state)) {
-          entry.state = {};
-        }
-        if(firstPathSegment !== entry.pathSegment) {
-          entry.state.expanded = false;
-        } else {
-          entry.state.expanded = true;
-          collapseAll(entry.nodes, pathSegment.substring(pathSegment.indexOf('/') + 1));
-        }
-      });
-    };
-    var newTreeData = this.get('treeData');
-    collapseAll(newTreeData, pathSegment);
-    this.set('treeData', newTreeData);
-    this.send('refreshTreeView');
+  stopFolderCreationProgress() {
+    this.set('isFolderCreationprogress', false);
+  },
+  startFolderCreationProgress() {
+    this.set('isFolderCreationprogress', true);
+  },
+  stopFileSystemFetchProgress() {
+    this.set('isDataLoading', false);
+  },
+  startFileSystemFetchProgress() {
+    this.set('isDataLoading', true);
+  },
+  resetFolderCreationMenuValidation() {
+    this.set('isFolderCreationSuccess', false);
+    this.set('isFolderCreationFailure', false);
+  },
+  folderCreationSuccess() {
+    this.set('createFolderError', {});
+    this.set('isFolderCreationSuccess', true);
+    this.set('isFolderCreationFailure', false);
+  },
+  folderCreationFailure() {
+    this.set('isFolderCreationSuccess', false);
+    this.set('isFolderCreationFailure', true);
+  },
+  resetGoToPathMenuValidation() {
+    this.set('isGoToFolderSuccess', false);
+    this.set('isGoToFolderFailure', false);
+  },
+  hideGoToPathMenu() {
+    this.set('isGoToFolder', false);
+  },
+  hideCreateFolderMenu() {
+    this.set('isCreateFolder', false);
   },
-
   actions: {
-    refreshTreeView() {
-      Ember.run.later(() => {
-        this.$().treeview({
-          data: this.get('treeData'),
-          expandIcon: this.get('config.expandIcon'),
-          collapseIcon: this.get('config.collapseIcon'),
-          //emptyIcon: "fa",
-          showBorder: false,
-          onNodeSelected: (event, data) => {
-            this.set('currentPath', data.path);
-            this.sendAction('pathSelectAction', {path: data.path, isDirectory: data.isDirectory});
-          },
-          onNodeExpanded: (event, data) => {
-            this.set('currentPath', data.path);
-            if (!Ember.isNone(data.nodes) && data.nodes.length === 0) {
-              var node = this.$().treeview('getNode', data.nodeId);
-              node.icon = "fa fa-refresh fa-spin";
-              this.fetchData();
-            } else {
-              this.collapseAllExceptPath(data.path.substring(1));
-            }
+    toggleCreateFolderMenu() {
+      if(this.get('isGoToFolder')) {
+        this.hideGoToPathMenu();
+      }
+      this.toggleProperty('isCreateFolder');
+      this.resetFolderCreationMenuValidation();
+    },
+    toggleGoToFolderMenu() {
+      if(this.get('isCreateFolder')) {
+        this.hideCreateFolderMenu();
+      }
+      this.toggleProperty('isGoToFolder');
+      this.resetGoToPathMenuValidation();
+    },
+    createFolder() {
+      if(Ember.isBlank(this.get('currentPath'))) {
+        return true;
+      }
+      this.startFolderCreationProgress();
+      this.set('createFolderError', {});
+      this.createFolder().then(function() {
+         this.send('drillToPath', this.get('currentPath'));
+         this.folderCreationSuccess();
+         this.stopFolderCreationProgress();
+      }.bind(this)).catch(function(e) {
+         this.set('createFolderError', e.responseJSON);
+         this.folderCreationFailure();
+         this.stopFolderCreationProgress();
+         console.error(e);
+      }.bind(this));
+    },
+    goToFolder() {
+      if(Ember.isBlank(this.get('currentPath'))) {
+        return true;
+      }
+      this.send('drillToPath', this.get('currentPath'));
+    },
+    drillToPath(path, fileItem) {
+       if(fileItem) {
+        this.sendAction('pathSelectAction', fileItem);
+       }
+       if(path.indexOf('/') !== 0){
+         this.set('errorMsg', 'Invalid path.');
+         return;
+       }
+       this.set('currentPath', path);
+       this.fetchData();
+    },
+    selectRow(index, fileItem) {
+       this.sendAction('pathSelectAction', fileItem);
+       this.get('fileSystem').forEach(function(item, i) {
+          if(index === i && !item.traverse){
+            Ember.set(item, "selectedClass", "row-selected");
+          } else {
+            Ember.set(item, "selectedClass", "");
           }
-        });
       });
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/styles/app.css
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/styles/app.css b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/styles/app.css
new file mode 100644
index 0000000..b46fa34
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/styles/app.css
@@ -0,0 +1,189 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+.directory-viewer{
+  width: 500px;
+}
+.directory-viewer-wrap {
+  height: 500px;
+  border: 1px solid #e2e2e2;
+}
+
+.directory-viewer .container-wrap {
+	position:relative;
+	height:400px;
+}
+.directory-viewer .top-header {
+	position: relative;
+	padding-left: 0px;
+	padding-right: 0px;
+	padding-bottom: 5px;
+	width: 500px;
+	border-bottom:1px solid #e2e2e2;
+}
+.directory-viewer .row-selected {
+	background-color:#c7ddef!important
+}
+.directory-viewer .file-row {
+	padding-top: 10px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #e2e2e2;
+}
+.directory-viewer .dropdown-menu>li>a {
+    display: block;
+    padding: 3px 20px;
+    clear: both;
+    font-weight: 400;
+    line-height: 1.42857143;
+    color: #337ab7;
+    white-space: nowrap;
+}
+.directory-viewer .file-row:hover {
+    background-color: #f5f5f5;
+}
+.directory-viewer .mod-icon {
+	font-size:1.5em
+}
+.directory-viewer .elipsisClass{
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -o-text-overflow: ellipsis;
+    white-space: nowrap;
+    width: 50%;
+}
+.directory-viewer .elipsis-link{
+    overflow: initial;
+    text-overflow: ellipsis;
+    -o-text-overflow: ellipsis;
+    white-space: nowrap;
+    width: 50px;
+}
+.directory-viewer .pointer {
+    cursor: pointer;
+}
+.directory-viewer .breadcrumbs-label {
+	display: inline-block;
+	padding: 8px;
+}
+.directory-viewer #file-view-unix {
+	width:500px;
+	position:relative;
+	overflow:auto;
+}
+.directory-viewer .padding-left-10px {
+	padding-left: 10px;
+}
+.directory-viewer .padding-right-10px {
+	padding-right: 10px;
+}
+.directory-viewer .home-icon {
+	top:3px;
+	font-size:1.5em;
+	position:relative;
+}
+.directory-viewer .breadcrumb {
+	background-color:white;
+	margin-bottom:0px;
+	padding: 0px;
+}
+.directory-viewer .container-fluid {
+	position:relative;
+	height:400px;
+}
+.directory-viewer .folder-name {
+	width:100% !important;
+}
+.directory-viewer .add-folder {
+    padding: 10px;
+    height: auto;
+    padding-top:0px;
+    padding-left:10px;
+    padding-bottom:4px;
+    margin-top:3px;
+    left:16px;
+}
+.directory-viewer .go-to-folder {
+    height: auto;
+    padding-right: 0px;
+    padding-left: 10px;
+    padding-bottom: 4px;
+    margin-top:3px;
+    left: 8px;
+}
+.directory-viewer .btn-action {
+	padding: 5px 10px;
+}
+.directory-viewer #folderPath, .directory-viewer #folderName {
+	height: 32px;
+	top: 2px;
+	position: relative;
+}
+.directory-viewer .margin-right-5 {
+	margin-right: 5px !important;
+}
+.directory-viewer a, .directory-viewer .file-system-count  {
+  color: #337ab7;
+}
+.directory-viewer .top-header button.btn{
+  color: #fff !important;
+}
+
+.directory-viewer .form-group{
+  padding-left:0px;
+  width:90%;
+}
+
+.directory-viewer button{
+  position:relative;
+  top:2px;
+  left:5px;
+}
+
+.directory-viewer .file-creation-status {
+  margin-top:10px;
+  margin-bottom:0px;
+}
+
+.directory-viewer .file-creation-success {
+  color:green;
+}
+
+.directory-viewer .file-creation-failure {
+  color:red;
+}
+
+.directory-viewer .inline {
+  display:inline-block;
+}
+
+.directory-viewer .file-viewer-settings {
+  position:relative;
+  top:5px;
+}
+
+.directory-viewer .no-padding {
+  padding:0px;
+}
+
+.directory-viewer .file-system-status {
+  margin-top:10px;
+  padding-left:20px;
+}
+
+.directory-viewer .file-system-count {
+  text-align:center;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
index 4083ad6..64a747f 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/templates/components/directory-viewer.hbs
@@ -15,3 +15,149 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
+<div class="pull-left col-sm-6 top-header">
+{{#if isGoToFolder}}
+        <div class="container-fluid go-to-folder">
+            <div class="form-inline">
+                <div class="form-group">
+                    {{input class="form-control col-sm-4 folder-name" id="folderPath" placeholder="Enter folder path" name="folderPath" value=currentPath}}
+                </div>
+                <button type="button" class="btn btn-sm btn-default btn-primary btn-action" {{action "goToFolder"}}><i aria-hidden="true" class="fa fa-arrow-circle-right"></i></button>
+                <button type="button" class="btn btn-sm btn-default btn-danger btn-action" {{action "toggleGoToFolderMenu"}}>
+                    <i class="fa fa-times" aria-hidden="true"></i>
+                </button>
+            </div>
+        </div>
+{{else if isCreateFolder}}
+        <div class="container-fluid add-folder">
+            <div class="form-inline">
+                <div class="form-group">
+                    {{input class="form-control col-sm-4 folder-name" id="folderName" placeholder="Enter folder name" name="folderName" value=currentPath}}
+                </div>
+                <button type="button" class="btn btn-sm btn-default btn-primary" {{action "createFolder"}}><i class="fa fa-plus-circle" aria-hidden="true"></i></button>
+                <button type="button" class="btn btn-sm btn-default btn-danger" {{action "toggleCreateFolderMenu"}}><i class="fa fa-times" aria-hidden="true"></i></button>
+                {{#if isFolderCreationSuccess}}
+                    <div class="file-creation-status">
+                        <strong class="file-creation-success">Folder have been created.</strong>
+                    </div>
+                {{/if}}
+                {{#if isFolderCreationFailure}}
+                    <div class="file-creation-status">
+                        <strong class="file-creation-failure">Folder creation failed.</strong>
+                        <div class="file-creation-failure">
+                            {{createFolderError.message}}
+                        </div>
+                    </div>
+                {{/if}}
+                {{#if isFolderCreationprogress}}
+                    <div class="loading-data" class="file-creation-status">
+                        <i class="fa fa-spinner fa-pulse fa-1x fa-fw"></i>Creating the folder...
+                    </div>
+                {{/if}}
+            </div>
+        </div>
+
+{{else}}
+
+    {{#if breadCrumbs.dropDownMenu}}
+        <li class="inline">
+        <div class="dropdown">
+            <a class="dropdown-toggle" d="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+	        <span class="fa-stack">
+	          <i class="fa fa-folder-o fa-stack-1x mod-icon" aria-hidden="true"></i>
+	          <i class="fa fa-caret-down fa-stack-1x" aria-hidden="true"></i>
+	        </span>
+            </a>
+        <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
+        {{#each breadCrumbs.dropDownMenu as |crumb index|}}
+                <li><a {{action "drillToPath" crumb.path crumb}}> <div title={{crumb.fullFileName}} class="elipsis-link pointer inline">{{crumb.name}}</div></a></li>
+        {{/each}}
+            </ul>
+        </div>
+        </li>&nbsp;/
+    {{/if}}
+    <div class="bs-example breadcrumbs-label">
+        <ul class="breadcrumb">
+            <li>
+                {{#each breadCrumbs.breadCrumbsMenu as |pathItem|}}
+                    {{#if pathItem.isRoot}}
+                        <a {{action "drillToPath" pathItem.path pathItem}}><i class="fa fa-folder-o home-icon" aria-hidden="true"></i></a>&nbsp;>
+                    {{else if pathItem.isCurrentFolder}}
+                        <span  title={{pathItem.fullFileName}}>{{pathItem.name}}</span>&nbsp;
+                    {{else}}
+                        <a {{action "drillToPath" pathItem.path pathItem}}><div class="pointer inline" title={{pathItem.fullFileName}}>{{pathItem.name}}</div></a>&nbsp;>
+                    {{/if}}
+                {{/each}}
+            </li>
+        </ul>
+    </div>
+
+    <div class="pull-right file-viewer-settings">
+        <li class="breadcrumbs-label no-padding">
+            <div class="dropdown">
+                <a class="dropdown-toggle" d="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
+		  <span class="btn btn-sm btn-default">
+		    <i class="fa fa-cog" aria-hidden="true"></i>
+		    <i class="fa fa-caret-down" aria-hidden="true"></i>
+		  </span>
+                </a>
+                <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
+                    <li><a>{{input type="checkbox" class="margin-right-5" name="dir" checked=isDirectory}}Directories</a></li>
+                    <li><a>{{input type="checkbox" class="margin-right-5" name="file" checked=isFile}}Files</a></li>
+                </ul>
+            </div>
+        </li>
+        <span {{ action "drillToPath" currentPath}} class="btn btn-sm btn-default">
+		    <i class="fa fa-refresh" aria-hidden="true"></i>
+		</span>
+        <button type="button" class="btn btn-sm btn-primary" {{action "toggleCreateFolderMenu"}}>
+            <i class="fa fa-plus-circle" aria-hidden="true"></i>{{!--  New Folder --}}
+        </button>
+        <button type="button" class="btn btn-sm btn-primary" {{action "toggleGoToFolderMenu"}}>
+            <i aria-hidden="true" class="fa fa-arrow-circle-o-right"></i> {{!-- Go To --}}
+        </button>
+    </div>
+{{/if}}
+</div>
+<div id="file-view-unix">
+    {{#if isDataLoading}}
+        <div class="loading-data file-system-status">
+            <i class="fa fa-spinner fa-pulse fa-1x fa-fw"></i>Fetching data...
+        </div>
+    {{else if errorMsg}}
+        <div class="file-system-status">
+            <strong class="file-creation-failure">{{errorMsg}}</strong>
+            <div class="file-creation-failure">
+                {{folderAccessError.message}}
+            </div>
+        </div>
+    {{else}}
+        {{#if filteredFileSytemInfo}}
+            <div class="container-fluid">
+                {{#ember-collection items=filteredFileSytemInfo cell-layout=(fixed-grid-layout fileBrowserWidth 41) as |item index|}}
+                    <div class="row file-row {{item.selectedClass}}" {{action 'selectRow' index item}}>
+                        {{#if item.traverse}}
+                            <div class="col-sm-8">
+                                <a class="padding-left-10px pointer" {{action "drillToPath" item.path item}}>
+                                    <i class="fa fa-reply padding-right-10px" aria-hidden="true"></i>
+                                </a>
+                            </div>
+                        {{else if item.isDirectory }}
+                            <div class="col-sm-6 elipsisClass">
+                                <a title={{item.text}} class="padding-left-10px pointer" {{action "drillToPath" item.path item}}>
+                                <i class="fa fa-folder-o padding-right-10px" aria-hidden="true"></i>{{ item.text }}
+                                </a>
+                            </div>
+                        {{else}}
+                            <div class="col-sm-6 elipsisClass" title={{item.text}}>
+                                <i class="fa fa-file padding-left-10px padding-right-10px" aria-hidden="true"></i>{{ item.text }}
+                            </div>
+                        {{/if}}
+                    </div>
+                {{/ember-collection}}
+            </div>
+        {{else}}
+            No files or folders.
+        {{/if}}
+    {{/if}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/utils/viewer-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/utils/viewer-config.js b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/utils/viewer-config.js
index 64773c6..c97c7c0 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/utils/viewer-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/utils/viewer-config.js
@@ -54,6 +54,9 @@ export default Ember.Object.extend({
    */
   listDirectoryUrl(pathParams) {
     return `/listdir?${pathParams}`;
+  },
+  createDirectoryUrl() {
+    return `/mkdir`;
   }
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/bower.json b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/bower.json
index f016904..206b8bd 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/bower.json
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/bower.json
@@ -10,7 +10,6 @@
     "loader.js": "^3.5.0",
     "qunit": "~1.20.0",
     "bootstrap": "~3.3.6",
-    "bootstrap-treeview": "~1.2.0",
     "font-awesome": "~4.5.0"
   },
   "resolutions": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/index.js b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/index.js
index dc074d7..762c281 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/index.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/index.js
@@ -23,10 +23,7 @@ module.exports = {
   name: 'hdfs-directory-viewer',
   included: function(app) {
     this._super.included(app);
-
     app.import(app.bowerDirectory + '/bootstrap/dist/css/bootstrap.css');
     app.import(app.bowerDirectory + '/bootstrap/dist/js/bootstrap.js');
-    app.import(app.bowerDirectory + '/bootstrap-treeview/src/js/bootstrap-treeview.js');
-    app.import(app.bowerDirectory + '/bootstrap-treeview/dist/bootstrap-treeview.min.css');
   }
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/package.json b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/package.json
index 66a7b20..90e4357 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/package.json
+++ b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/package.json
@@ -36,7 +36,10 @@
     "ember-disable-proxy-controllers": "^1.0.1",
     "ember-export-application-global": "^1.0.4",
     "ember-resolver": "^2.0.3",
-    "ember-try": "~0.0.8"
+    "ember-try": "~0.0.8",
+    "ember-truth-helpers": "1.2.0",
+    "ember-collection": "git://github.com/emberjs/ember-collection.git#4dbe10b7498886e277fc21b28139924f908d1926"
+
   },
   "keywords": [
     "ember-addon"

http://git-wip-us.apache.org/repos/asf/ambari/blob/b53cf918/contrib/views/wfmanager/src/main/resources/ui/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/package.json b/contrib/views/wfmanager/src/main/resources/ui/package.json
index b5973c1..25ed6c1 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/package.json
+++ b/contrib/views/wfmanager/src/main/resources/ui/package.json
@@ -49,7 +49,8 @@
     "ember-uuid": "1.0.0",
     "ember-validations": "~ 2.0.0-alpha.4",
     "ivy-codemirror": "2.0.3",
-    "loader.js": "^4.0.0"
+    "loader.js": "^4.0.0",
+    "ember-collection": "git://github.com/emberjs/ember-collection.git#4dbe10b7498886e277fc21b28139924f908d1926"
   },
   "ember-addon": {
     "paths": [