AMBARI-7623. View: Files cleanup, enhancements and bugs. (jaimin)

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

Branch: refs/heads/branch-alerts-dev
Commit: d5b9af74587ad918e82fc418aa9c77716bb6f299
Parents: ac70302
Author: Jaimin Jetly <[email protected]>
Authored: Fri Oct 3 09:54:34 2014 -0700
Committer: Jaimin Jetly <[email protected]>
Committed: Fri Oct 3 09:54:34 2014 -0700

----------------------------------------------------------------------
 .../view/filebrowser/FileOperationService.java  |  37 +++
 .../apache/ambari/view/filebrowser/HdfsApi.java |  21 ++
 .../files/src/main/resources/ui/app/adapter.js  |  59 +++--
 .../resources/ui/app/components/breadCrumbs.js  |  47 ++++
 .../resources/ui/app/components/bsPopover.js    |  21 ++
 .../resources/ui/app/components/bulkCheckbox.js |  40 ++++
 .../resources/ui/app/components/chmodInput.js   |  79 +++++++
 .../ui/app/components/confirmDelete.js          |  59 +++++
 .../resources/ui/app/components/contextMenu.js  |  36 +--
 .../resources/ui/app/components/mkdirInput.js   |  45 ++++
 .../ui/app/components/popoverDelete.js          |  50 ++++
 .../resources/ui/app/components/renameInput.js  |   7 +-
 .../resources/ui/app/components/sortArrow.js    |  39 ++++
 .../ui/app/components/toggleContext.js          |  56 +++++
 .../resources/ui/app/components/uploader.js     |  13 +-
 .../main/resources/ui/app/controllers/error.js  |   5 +-
 .../main/resources/ui/app/controllers/file.js   | 104 +++++----
 .../main/resources/ui/app/controllers/files.js  | 103 ++++-----
 .../resources/ui/app/controllers/filesAlert.js  |  10 +
 .../src/main/resources/ui/app/initialize.js     |  24 +-
 .../src/main/resources/ui/app/routes/file.js    |   3 +
 .../resources/ui/app/styles/application.less    |  67 +++++-
 .../ui/app/templates/components/chmodInput.hbs  | 100 ++++++++
 .../ui/app/templates/components/contextMenu.hbs |  43 ++++
 .../ui/app/templates/components/deleteBulk.hbs  |  46 ++++
 .../app/templates/components/deletePopover.hbs  |  38 +++
 .../ui/app/templates/components/mkdirInput.hbs  |  37 +++
 .../ui/app/templates/components/renameInput.hbs |  38 +++
 .../ui/app/templates/components/uploader.hbs    |  35 +++
 .../main/resources/ui/app/templates/files.hbs   | 229 ++++++-------------
 .../ui/app/templates/util/contextMenu.hbs       |  56 -----
 .../ui/app/templates/util/deleteBulk.hbs        |  38 ---
 .../ui/app/templates/util/deletePopover.hbs     |  38 ---
 .../resources/ui/app/templates/util/fileRow.hbs |  84 +++++++
 .../ui/app/templates/util/renameInput.hbs       |  38 ---
 .../ui/app/templates/util/uploader.hbs          |  35 ---
 .../src/main/resources/ui/app/views/file.js     | 182 +--------------
 .../main/resources/ui/app/views/filesAlert.js   |  23 ++
 .../files/src/main/resources/ui/bower.json      |  10 +-
 .../main/resources/ui/vendor/js/bsPopover.js    | 190 +++++++++++++++
 contrib/views/files/src/main/resources/view.xml |   2 +-
 41 files changed, 1478 insertions(+), 709 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileOperationService.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileOperationService.java
 
b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileOperationService.java
index 7b6a5fa..d043917 100644
--- 
a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileOperationService.java
+++ 
b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileOperationService.java
@@ -96,6 +96,33 @@ public class FileOperationService extends HdfsService {
   }
 
   /**
+   * Chmod
+   * @param request chmod request
+   * @return response with success
+   */
+  @POST
+  @Path("/chmod")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response chmod(final ChmodRequest request) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      if (api.chmod(request.path, request.mode)) {
+        result = Response.ok(HdfsApi.fileStatusToJSON(api
+            .getFileStatus(request.path)));
+      } else {
+        result = Response.ok(new BoolResult(false)).status(422);
+      }
+      return result.build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
    * Copy file
    * @param request source and destination request
    * @return response with success
@@ -229,6 +256,16 @@ public class FileOperationService extends HdfsService {
     public String path;
   }
 
+  /**
+   * Wrapper for json mapping of chmod request
+   */
+  @XmlRootElement
+  public static class ChmodRequest {
+    @XmlElement(nillable = false, required = true)
+    public String path;
+    @XmlElement(nillable = false, required = true)
+    public String mode;
+  }
 
   /**
    * Wrapper for json mapping of request with

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsApi.java
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsApi.java
 
b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsApi.java
index 79ea0d9..cd88c54 100644
--- 
a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsApi.java
+++ 
b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsApi.java
@@ -250,6 +250,27 @@ public class HdfsApi {
   }
 
   /**
+   * Change permissions
+   * @param path path
+   * @param permissions permissions in format rwxrwxrwx
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  public boolean chmod(final String path, final String permissions) throws 
IOException,
+      InterruptedException {
+    return ugi.doAs(new PrivilegedExceptionAction<Boolean>() {
+      public Boolean run() throws Exception {
+        try {
+          fs.setPermission(new Path(path), new FsPermission(permissions));
+        } catch (Exception ex) {
+          return false;
+        }
+        return true;
+      }
+    });
+  }
+
+  /**
    * Copy file
    * @param src source path
    * @param dest destination path

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/adapter.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/adapter.js 
b/contrib/views/files/src/main/resources/ui/app/adapter.js
index b8e127b..a6e471f 100644
--- a/contrib/views/files/src/main/resources/ui/app/adapter.js
+++ b/contrib/views/files/src/main/resources/ui/app/adapter.js
@@ -87,11 +87,6 @@ function _move(adapter, store, record, query) {
 
     return store.push('file', payload);
   }, function(reason) {
-    if (reason instanceof DS.InvalidError) {
-      store.recordWasInvalid(record, reason.errors);
-    } else {
-      store.recordWasError(record, reason);
-    }
 
     throw reason;
   }, label);
@@ -113,19 +108,14 @@ function _mkdir(adapter, store, type, query) {
 
     return store.push('file', payload);
   }, function(reason) {
-    if (reason instanceof DS.InvalidError) {
-      store.recordWasInvalid(record, reason.errors);
-    } else {
-      store.recordWasError(record, reason);
-    }
-
     throw reason;
   }, label);
 }
 
-function _remove(adapter, store, record, query) {
+function _remove(adapter, store, record, query, toTrash) {
   var type = record.constructor;
-  var promise = adapter.remove(store, type, query),
+  var method = (toTrash)?'moveToTrash':'remove';
+  var promise = adapter[method](store, type, query),
       serializer = serializerForAdapter(adapter, type),
       label = "";
 
@@ -136,7 +126,8 @@ function _remove(adapter, store, record, query) {
     if (reason instanceof DS.InvalidError) {
       store.recordWasInvalid(record, reason.errors);
     } else {
-      store.recordWasError(record, reason);
+      record.rollback();
+      //store.recordWasError(record, reason);
     }
 
     throw reason;
@@ -172,12 +163,22 @@ App.Store = DS.Store.extend({
     move:function (store, type, record, query) {
       return this.ajax(this.buildURL('fileops','rename'), 'POST', { data: 
query });
     },
+    updateRecord:function (store, type, record) {
+      var query = {
+        "path":record.get('path'),
+        "mode":record.get('permission')
+      };
+      return this.ajax(this.buildURL('fileops','chmod'), 'POST', { data: query 
});
+    },
     mkdir:function (store, type, query) {
       return this.ajax(this.buildURL('fileops','mkdir'), 'PUT', { data: query 
});
     },
     remove:function (store, type, query) {
       return this.ajax(this.buildURL('fileops','remove'), 'DELETE', { data: 
query });
     },
+    moveToTrash:function (store, type, query) {
+      return this.ajax(this.buildURL('fileops','moveToTrash'), 'DELETE', { 
data: query });
+    },
     downloadUrl:function (option, query) {
       return [this.buildURL('download',option),Em.$.param(query)].join('?');
     },
@@ -218,6 +219,9 @@ App.Store = DS.Store.extend({
 
     return DS.PromiseObject.create({ promise: resolver.promise });
   },
+  chmod:function (record, path) {
+    return record.save();
+  },
   mkdir:function (path) {
     var query = {
       "path":path
@@ -231,7 +235,7 @@ App.Store = DS.Store.extend({
 
     return DS.PromiseObject.create({ promise: resolver.promise });
   },
-  remove:function (record) {
+  remove:function (record, toTrash) {
     var query = {
       "path":record.get('path'),
       "recursive":true
@@ -242,7 +246,7 @@ App.Store = DS.Store.extend({
     var adapter = this.adapterFor(type);
     
     record.deleteRecord();
-    resolver.resolve(_remove(adapter, this, record, query));
+    resolver.resolve(_remove(adapter, this, record, query, toTrash));
 
     return DS.PromiseObject.create({ promise: resolver.promise });
   },
@@ -279,7 +283,7 @@ App.Store = DS.Store.extend({
     return resolver.promise.then(function(response) {
       return adapter.downloadUrl(option,response);
     }, function(reason) {
-      //TODO reject
+      throw reason;
     });
   }
 })
@@ -293,7 +297,10 @@ App.FileSerializer = DS.RESTSerializer.extend({
   extractSingle: function(store, type, payload, id, requestType) {
     payload = {'files': payload};
     return this._super(store, type, payload, id, requestType);
-  }
+  },
+  extractChmod:function(store, type, payload, id, requestType) {
+    return this.extractSingle(store, type, payload, id, requestType);
+  },
 });
 
 App.Uploader = Ember.Uploader.create({
@@ -307,11 +314,19 @@ App.Uploader = Ember.Uploader.create({
 
     this.set('isUploading', true);
     
-    return this.ajax(url, data, type).then(function(respData) {
-      self.didUpload(respData);
-      return respData;
-    });
+    return this.ajax(url, data, type)
+      
.then(Em.run.bind(this,this.uploadSuccess),Em.run.bind(this,this.uploadFailed));
+  },
+  uploadSuccess:function(respData) {
+    this.didUpload(respData);
+    return respData;
+  },
+  uploadFailed:function (error) {
+    this.set('isUploading', false);
+    this.sendAlert(error);
+    return error;
   },
+  sendAlert: Em.K,
   ajax: function(url, params, method) {
     var self = this;
     var settings = {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/breadCrumbs.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/breadCrumbs.js 
b/contrib/views/files/src/main/resources/ui/app/components/breadCrumbs.js
new file mode 100644
index 0000000..8448f05
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/breadCrumbs.js
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.BreadCrumbsComponent = Ember.CollectionView.extend({
+  classNames: ['breadcrumb pull-left'],
+  tagName: 'ul',
+  path:'',
+  content: function (argument) {
+    var crumbs = [];
+    var currentPath = this.get('path').match(/((?!\/)\S)+/g)||[];
+    currentPath.forEach(function (cur,i,array) {
+      return crumbs.push({name:cur,path:'/'+array.slice(0,i+1).join('/')});
+    });
+    crumbs.unshift({name:'/',path:'/'});
+    crumbs.get('lastObject').last = 'true';
+    return crumbs;
+  }.property('path'),
+  itemViewClass: Ember.View.extend({
+    classNameBindings: ['isActive:active'],
+    template: Ember.Handlebars.compile("{{#link-to 'files' (query-params 
path=view.content.path)}}{{view.content.name}}{{/link-to}}"),
+    isActive: function () {
+      return this.get('content.last');
+    }.property('content'),
+    click:function () {
+      if (this.get('isActive')) {
+        this.get('controller').send('refreshDir');
+      }
+    }
+  })
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/bsPopover.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/bsPopover.js 
b/contrib/views/files/src/main/resources/ui/app/components/bsPopover.js
new file mode 100644
index 0000000..dbc9785
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/bsPopover.js
@@ -0,0 +1,21 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.BsPopoverComponent = Ember.BsPopoverComponent.extend({});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/bulkCheckbox.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/bulkCheckbox.js 
b/contrib/views/files/src/main/resources/ui/app/components/bulkCheckbox.js
new file mode 100644
index 0000000..34c9a1f
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/bulkCheckbox.js
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.BulkCheckboxComponent = Em.Checkbox.extend({
+  changeBinding:'selectAll',
+  checkedBinding:'selectedAll',
+  selectedAll:false,
+  selectAll:function () {
+    var checked = this.get('checked');
+    var items = this.get('content');
+    return items.forEach(function (item) {
+      item.set('selected',checked);
+    });
+  },
+  selection:function () {
+    var selected = this.get('content').filterBy('selected',true);
+    if (selected.length == this.get('content.length') && selected.length > 0) {
+      this.set('selectedAll',true);
+    } else {
+      this.set('selectedAll',false);
+    }
+  }.observes('[email protected]'),
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/chmodInput.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/chmodInput.js 
b/contrib/views/files/src/main/resources/ui/app/components/chmodInput.js
new file mode 100644
index 0000000..151b681
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/chmodInput.js
@@ -0,0 +1,79 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+var _permissionsProp = function(n, l) {
+  return function (arg,val) {
+    if (arguments.length > 1) {
+      this.set('permissions', this.replaceAt(n,(val)?l:'-'));
+      return val;
+    };
+    return this.get('permissions')[n]===l;
+  }
+}
+
+App.ChmodInputComponent = Em.Component.extend({
+  layoutName:'components/chmodInput',
+  tagName:'tr',
+  classNames:"chmod-row",
+  file:null,
+  permissions:Em.computed.alias('file.permission'),
+  usrR:_permissionsProp(1, 'r').property('permissions'),
+  usrW:_permissionsProp(2, 'w').property('permissions'),
+  usrE:_permissionsProp(3, 'x').property('permissions'),
+  grpR:_permissionsProp(4, 'r').property('permissions'),
+  grpW:_permissionsProp(5, 'w').property('permissions'),
+  grpE:_permissionsProp(6, 'x').property('permissions'),
+  otrR:_permissionsProp(7, 'r').property('permissions'),
+  otrW:_permissionsProp(8, 'w').property('permissions'),
+  otrE:_permissionsProp(9, 'x').property('permissions'),
+  replaceAt:function (index,p) {
+    var perm = this.get('permissions');
+    var newPerm = perm.substr(0, index) + p + perm.substr(index + p.length);
+    return newPerm;
+  },
+  markActive:function () {
+    if (this.get('isVisible')) {
+      this.$('.btn-chmod').each(function () {
+        if ($(this).children('input').is(':checked')) {
+          $(this).addClass('active');
+        } else {
+          $(this).removeClass('active');
+        }
+      });
+    }
+  }.observes('chVisible'),
+  showModal:function () {
+    this.$('.chmodal').modal('toggle');
+  }.observes('chVisible'),
+  actions:{
+    confirm:function (r) {
+      this.sendAction('confirm',r);
+      this.set('chVisible',false);
+    },
+    close:function () {
+      var file = this.get('file');
+      var diff = file.changedAttributes();
+      if (diff.permission) {
+        file.set('permission',diff.permission[0]);
+      };
+      this.set('chVisible',false);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/confirmDelete.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/confirmDelete.js 
b/contrib/views/files/src/main/resources/ui/app/components/confirmDelete.js
new file mode 100644
index 0000000..e0122bf
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/confirmDelete.js
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.DropdownWrapComponent = Em.Component.extend({
+  onResetConfirm:function () {
+    var childs = this.get('childViews').filter(function (view) {
+      return view instanceof App.ConfirmDeleteComponent;
+    });
+    childs.setEach('isRemoving',false);
+  }.on('resetConfirm'),
+  didInsertElement:function(){
+    this.$().on('hidden.bs.dropdown',Em.run.bind(this,this.onResetConfirm));
+  },
+});
+
+App.ConfirmDeleteComponent = Em.Component.extend({
+  layoutName:'components/deleteBulk',
+  tagName:'li',
+  deleteForever:false,
+  isRemoving:false,
+  cancelRemoving:function () {
+    this.set('isRemoving',false);
+  },
+  click:function  (e) {
+    if (!$(e.target).hasClass('delete')) {
+      e.stopPropagation();
+    };
+  },
+  actions:{
+    ask:function () {
+      this.get('parentView').trigger('resetConfirm');
+      this.set('isRemoving',true);
+      return false; 
+    },
+    cancel:function () {
+      this.cancelRemoving();
+    },
+    confirm:function () {
+      this.sendAction('confirm',this.get('deleteForever'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/contextMenu.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/contextMenu.js 
b/contrib/views/files/src/main/resources/ui/app/components/contextMenu.js
index 9807e0c..c35b485 100644
--- a/contrib/views/files/src/main/resources/ui/app/components/contextMenu.js
+++ b/contrib/views/files/src/main/resources/ui/app/components/contextMenu.js
@@ -18,21 +18,25 @@
 
 var App = require('app');
 
-App.ContextMenu = Em.Component.extend({
-  layoutName:'util/contextMenu',
-  waitConfirm: null,
-  startWaitConfirm:function (v,observer) {
-    var self = this,
-        action = this.get(observer);
-    if (!action) {
-      $(this.get('element')).off('hidden.bs.context');
-      return false;
-    };
-    $(this.get('element')).on('hidden.bs.context',function(){
-      self.get('target').send(self.get(observer),'cancel');
-      self.set('waitConfirm', null)
-    })
-    this.get('target').send(action,'ask');
-  }.observes('waitConfirm')
+App.ContextMenuComponent = Em.Component.extend({
+  layoutName:'components/contextMenu',
+
+  onTargetChange:function () {
+    this.$().off('hidden.bs.context');
+    this.$().on('hidden.bs.context', Em.run.bind(this, 
this.resetConfirmations));
+  }.observes('target'),
+
+  resetConfirmations:function () {
+    this.triggerRecursively('resetConfirm');
+  },
+
+  actions:{
+    removeFile:function () {
+      this.get('target').send('deleteFile',true);
+    },
+    moveToTrash:function () {
+      this.get('target').send('deleteFile');
+    },
+  }
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/mkdirInput.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/mkdirInput.js 
b/contrib/views/files/src/main/resources/ui/app/components/mkdirInput.js
new file mode 100644
index 0000000..c97f8d4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/mkdirInput.js
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.MkdirInputComponent = Em.Component.extend({
+  layoutName:'components/mkdirInput',
+  newDirName:'',
+  isMkdir:false,
+  path:'',
+  actions:{
+    create:function () {
+      var name = this.get('newDirName');
+
+      if (Em.isEmpty(name)) {
+        return false;
+      }
+      newDir = [this.get('path'),name].join('/').replace('//','/');
+
+      this.sendAction('create',newDir);
+      this.setProperties({'newDirName':'','isMkdir':false});
+    },
+    edit:function () {
+      this.set('isMkdir',true);
+    },
+    cancel:function () {
+      this.setProperties({'newDirName':'','isMkdir':false});
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/popoverDelete.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/popoverDelete.js 
b/contrib/views/files/src/main/resources/ui/app/components/popoverDelete.js
new file mode 100644
index 0000000..bd398df
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/popoverDelete.js
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.PopoverDeleteComponent = Em.Component.extend({
+  popover:Em.computed.alias('childViews.firstObject'),
+  layoutName:'components/deletePopover',
+  deleteForever:false,
+  actions:{
+    confirm:function (deleteForever) {
+      this.sendAction('confirm',this.get('deleteForever'));
+    },
+    close:function () {
+      this.set('popover.isVisible',false);
+    }
+  },
+  didInsertElement:function () {
+    $('body').on('click.popover', Em.run.bind(this,this.hideMultiply));
+  },
+  hideMultiply:function (e) {
+    if (!this.$()) {
+      return;
+    }
+    if (!this.$().is(e.target)
+        && this.$().has(e.target).length === 0
+        && $('.popover').has(e.target).length === 0) {
+          this.set('popover.isVisible',false);
+    }
+  },
+  willClearRender:function () {
+    this.get('popover').$element.off('click');
+    $('body').off('click.popover');
+  },
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/renameInput.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/renameInput.js 
b/contrib/views/files/src/main/resources/ui/app/components/renameInput.js
index 9a826a4..cd311e9 100644
--- a/contrib/views/files/src/main/resources/ui/app/components/renameInput.js
+++ b/contrib/views/files/src/main/resources/ui/app/components/renameInput.js
@@ -21,10 +21,10 @@ var App = require('app');
 
 App.RenameInputComponent = Ember.Component.extend({
   tagName:'span',
-  layoutName:'util/renameInput',
+  layoutName:'components/renameInput',
   actions:{
     rename:function (opt) {
-      var target, tmpName;
+      var tmpName;
 
       switch (opt) {
         case 'edit': this.set('isRenaming',true); break;
@@ -34,8 +34,7 @@ App.RenameInputComponent = Ember.Component.extend({
           if (tmpName.length==0) {
             break;
           };
-          target = this.get('targetObject');
-          target.send(this.get('actionName'),this.get('filePath'),tmpName);
+          this.sendAction('confirm',this.get('filePath'),tmpName);
           this.set('isRenaming',false);
           break;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/sortArrow.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/sortArrow.js 
b/contrib/views/files/src/main/resources/ui/app/components/sortArrow.js
new file mode 100644
index 0000000..7c4a4e4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/sortArrow.js
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.SortArrowComponent = Em.Component.extend({
+  layout:Ember.Handlebars.compile('<i {{bind-attr class=":fa 
view.asc:fa-chevron-down:fa-chevron-up view.cur::fa-gr view.cur::fa-rotate-270" 
}} ></i>'),
+  classNames:['pull-right'],
+  tagName:'span',
+  sPs:[],
+  sA:false,
+  sP:null,
+  asc:true,
+  cur:false,
+  sorting:function () {
+    if (this.get('sPs.firstObject') == this.get('sP')) {
+      this.set('asc',this.get('sA'));
+      this.set('cur',true);
+    } else{
+      this.set('asc',true);
+      this.set('cur',false);
+    };
+  }.observes('sPs','sA').on('init'),
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/toggleContext.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/toggleContext.js 
b/contrib/views/files/src/main/resources/ui/app/components/toggleContext.js
new file mode 100644
index 0000000..326fa64
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/components/toggleContext.js
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.ToggleContextComponent = Em.Component.extend({
+  didInsertElement:function () {
+    var fileRow = this.$().parents('.file-row'),
+        beforeHandler = Ember.run.bind(this, this.setContext),
+        itemHandler = Ember.run.bind(this, this.itemHandler);
+
+    fileRow.on('click',Ember.run.bind(this, this.openOnClick));
+
+    fileRow.contextmenu({
+      target:'#context-menu',
+      before:beforeHandler,
+      onItem:itemHandler
+    });
+  },
+  setContext:function(e) {
+    if (this.get('targetObject.isMoving')) {
+      return false;
+    };
+    
this.set('targetObject.parentController.targetContextMenu',this.get('targetObject'));
+    return true;
+  },
+  itemHandler:function (t,e) {
+    if (e.target.dataset.disabled) {
+      return false;
+    };
+  },
+  openOnClick:function (e) {
+    if($(e.target).is('td') || $(e.target).hasClass('allow-open')){
+      this.get('targetObject').send('open');
+    }
+  },
+  willClearRender:function () {
+    this.$().parents('.file-row').off('click');
+    
this.$().parents('.file-row').off('.context.data-api').removeData('context');
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/components/uploader.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/components/uploader.js 
b/contrib/views/files/src/main/resources/ui/app/components/uploader.js
index 05efd58..5837c36 100644
--- a/contrib/views/files/src/main/resources/ui/app/components/uploader.js
+++ b/contrib/views/files/src/main/resources/ui/app/components/uploader.js
@@ -21,6 +21,12 @@ var App = require('app');
 
 App.FileUploaderComponent = Ember.Component.extend({
   didInsertElement:function () {
+    var _this = this;
+    this.uploader.reopen({
+      sendAlert:function (e) {
+        _this.sendAction('alert',e);
+      }
+    });
     this.fileInput.reopen({
       filesDidChange: function() {
         var files = this.get('files');
@@ -42,12 +48,11 @@ App.FileUploaderComponent = Ember.Component.extend({
   },
   actions:{
     upload:function (files) {
-      var self = this;
       var uploader = this.get('uploader');
       var uploadBtn = Ladda.create(this.uploadButton.get('element'));
       var reset = function () {
         uploadBtn.stop();
-        self.send('clear');
+        this.send('clear');
       };
       if (!uploader.get('isUploading')) {
         var path = this.get('path');
@@ -57,7 +62,7 @@ App.FileUploaderComponent = Ember.Component.extend({
           uploader.on('progress',function (e) {
             uploadBtn.setProgress(e.percent/100);
           })
-          uploader.upload(file,{path:path}).then(reset,reset);
+          uploader.upload(file,{path:path}).finally(Em.run.bind(this,reset));
         }
       };
     },
@@ -66,7 +71,7 @@ App.FileUploaderComponent = Ember.Component.extend({
     }
   },
   uploader: null,
-  layoutName:'util/uploader',
+  layoutName:'components/uploader',
   path:'',
   info:'',
   files:null,

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/controllers/error.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/error.js 
b/contrib/views/files/src/main/resources/ui/app/controllers/error.js
index 69b4777..ecf7749 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/error.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/error.js
@@ -17,9 +17,6 @@
  */
 
 App.ErrorController = Ember.ObjectController.extend({
-  init:function () {
-    this._super();
-  },
   actions: {
     toggleStackTrace:function () {
       var value = this.get('isExpanded');
@@ -35,6 +32,8 @@ App.ErrorController = Ember.ObjectController.extend({
     if (content && content.responseText) {
       var json = JSON.parse(content.responseText);
       text = json.message;
+    } else if (content && content.message) {
+      text = content.message;
     }
     return text;
   }.property('content'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/controllers/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/file.js 
b/contrib/views/files/src/main/resources/ui/app/controllers/file.js
index 4c2cccd..f8b7046 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/file.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/file.js
@@ -16,6 +16,8 @@
  * limitations under the License.
  */
 
+var App = require('app');
+
 App.FileController = Ember.ObjectController.extend({
   init:function () {
     this.set('content.selected', false);
@@ -25,41 +27,33 @@ App.FileController = Ember.ObjectController.extend({
     download:function (option) {
       this.store.linkFor([this.get('content')],option).then(function (link) {
         window.location.href = link;
-      });
+      },Em.run.bind(this,this.sendAlert));
+    },
+    showChmod:function () {
+      this.toggleProperty('chmodVisible',true);
     },
-    rename:function (opt,file) {
+    rename:function (opt,name) {
       var file = this.get('content'),
-          self,path,name,newPath;
-      if (opt === 'edit') {
-        this.set('tmpName',file.get('name'));
-        this.set('isRenaming',true);
-      };
-
-      if (opt === 'cancel') {
-        this.set('tmpName','');
-        this.set('isRenaming',false);
-      };
-
-      if (opt === 'confirm') {
-        self = this;
-        path = file.get('path');
-        name = this.get('tmpName');
+          path = file.get('path'),
+          newPath;
 
-        if (Em.isEmpty(name)) {
-          return false;
-        }
-
-        if (name === file.get('name')) {
-          return self.set('isRenaming',false);
-        }
+      if (name === file.get('name') || Em.isEmpty(name)) {
+        return this.set('isRenaming',!Em.isEmpty(name));
+      }
 
-        newPath = path.substring(0,path.lastIndexOf('/')+1)+name;
+      newPath = path.substring(0,path.lastIndexOf('/')+1)+name;
 
-        this.store.move(file,newPath).then(function () {
-          self.set('tmpName','');
-          self.set('isRenaming',false);
-        });
-      };
+      this.store.move(file,newPath)
+        
.then(Em.run.bind(this,this.set,'isRenaming',false),Em.run.bind(this,this.sendAlert));
+    },
+    editName:function () {
+      this.set('isRenaming',true);
+    },
+    chmod:function (r) {
+      var record = this.get('content');
+      this.store
+        .chmod(record)
+        .then(null,Em.run.bind(this,this.chmodErrorCallback,record));
     },
     open:function (file) {
       if (this.get('content.isDirectory')) {
@@ -68,32 +62,22 @@ App.FileController = Ember.ObjectController.extend({
         return this.send('download');
       };
     },
-    removeFile:function (opt) {
-      if (opt=='ask') {
-        this.toggleProperty('isRemoving');
-        console.log('ask removeFile')
-        return false;
-      };
-
-      if (opt == 'cancel'  && !this.isDestroyed) {
-        this.set('isRemoving',false);
-        console.log('cancel removeFile')
-      }
-
-      if (opt == 'confirm') {
-        this.set('isRemoving',false);
-        this.store.remove(this.get('content'));
-      }
-    },
-    deleteFile:function () {
-      var file = this.get('content');
-      this.store.remove(file);
+    deleteFile:function (deleteForever) {
+      this.store
+        .remove(this.get('content'),!deleteForever)
+        .then(null,Em.run.bind(this,this.sendAlert));
     },
   },
-  tmpName:'',
   selected:false,
   isRenaming:false,
-  isRemoving:false,
+  isMovingToTrash:false,
+  chmodVisible:false,
+  targetContextMenu:null,
+  isPermissionsDirty:function () {
+    var file = this.get('content');
+    var diff = file.changedAttributes();
+    return !!diff.permission;
+  }.property('content.permission'),
   isMoving:function () {
     var movingFile = this.get('parentController.movingFile.path');
     var thisFile = this.get('content.id');
@@ -102,5 +86,19 @@ App.FileController = Ember.ObjectController.extend({
   
   setSelected:function (controller,observer) {
     this.set('selected',this.get(observer))
-  }.observes('content.selected')
+  }.observes('content.selected'),
+
+  renameSuccessCallback:function (record,error) {
+    record.rollback();
+    this.sendAlert(error);
+  },
+
+  chmodErrorCallback:function (record,error) {
+    record.rollback();
+    this.sendAlert(error);
+  },
+
+  sendAlert:function (error) {
+    this.send('showAlert',error);
+  },
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/controllers/files.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/files.js 
b/contrib/views/files/src/main/resources/ui/app/controllers/files.js
index 11b7c0c..a9d98e8 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/files.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/files.js
@@ -17,11 +17,12 @@
  */
 
 var App = require('app');
+var bind = Ember.run.bind;
 
 App.FilesController = Ember.ArrayController.extend({
   actions:{
     moveFile:function (opt,file) {
-      var src, title, self,
+      var src, title,
           file = file || this.get('selectedFiles.firstObject'),
           moving = this.get('movingFile');
 
@@ -32,11 +33,8 @@ App.FilesController = Ember.ArrayController.extend({
       };
 
       if (opt == 'move') {
-        self = this;
         
this.store.move(moving.path,[this.get('path'),moving.name].join('/').replace('//','/'))
-          .then(function () {
-            self.set('movingFile',null);
-          });
+          
.then(bind(this,this.set,'movingFile',null),bind(this,this.throwAlert));
       };
 
       if (opt == 'cancel') {
@@ -47,7 +45,7 @@ App.FilesController = Ember.ArrayController.extend({
       this.toggleProperty('isRenaming');
     },
     renameDir:function (path,newName) {
-      var self = this,
+      var _this = this,
           basedir = path.substring(0,path.lastIndexOf('/')+1);
           newPath = basedir + newName;
 
@@ -59,25 +57,28 @@ App.FilesController = Ember.ArrayController.extend({
         var recordExists = listdir.isAny('id',newPath);
 
         listdir.forEach(function (file) {
-          self.store.unloadRecord(file);
+          _this.store.unloadRecord(file);
         });
 
         if (recordExists) {
-          return self.send('showAlert',{message:newPath + ' already exists.'});
+          return _this.throwAlert({message:newPath + ' already exists.'});
         };
 
-        self.store.move(path,newPath).then(function (newDir) {
-          self.store.unloadRecord(newDir);
-          self.set('path',newPath);
-        });
-      });
+        return _this.store.move(path,newPath);
+      }).then(function (newDir) {
+        if (newDir) {
+          _this.store.unloadRecord(newDir);
+          _this.set('path',newPath);
+        };
+      }).catch(bind(this,this.throwAlert));
 
     },
-    deleteFile:function () {
+    deleteFile:function (deleteForever) {
       var self = this;
       var selected = this.get('selectedFiles');
+      var moveToTrash = !deleteForever;
       selected.forEach(function (file) {
-        self.store.remove(file);
+        
self.store.remove(file,moveToTrash).then(null,bind(self,self.throwAlert));
       });
     },
     download:function (option) {
@@ -86,31 +87,9 @@ App.FilesController = Ember.ArrayController.extend({
         window.location.href = link;
       });
     },
-    mkdir:function (opt) {
-      var name,self,newDir;
-      if (opt === 'edit') {
-        this.set('isMkdir',true);
-      };
-
-      if (opt === 'cancel') {
-        this.set('newDirName','');
-        this.set('isMkdir',false);
-      };
-
-      if (opt === 'confirm') {
-        self = this;
-        name = this.get('newDirName');
-
-        if (Em.isEmpty(name)) {
-          return false;
-        }
-        newDir = [this.get('path'),name].join('/').replace('//','/');
-
-        this.store.mkdir(newDir).then(function () {
-          self.set('newDirName','');
-          self.set('isMkdir',false);
-        });
-      };
+    mkdir:function (newDirName) {
+      this.store.mkdir(newDirName)
+        .then(bind(this,this.mkdirSuccessCalback),bind(this,this.throwAlert));
     },
     upload:function (opt) {
       if (opt === 'open') {
@@ -129,6 +108,9 @@ App.FilesController = Ember.ArrayController.extend({
         this.set('sortProperties',[pr]);
         this.set('sortAscending',true);
       };
+    },
+    clearSearchField:function () {
+      this.set('searchString','');
     }
   },
   init:function () {
@@ -140,6 +122,7 @@ App.FilesController = Ember.ArrayController.extend({
 
       controller.store.pushPayload('file',{file:e});
     });
+    this._super();
   },
 
   sortProperties: ['name'],
@@ -149,10 +132,7 @@ App.FilesController = Ember.ArrayController.extend({
   movingFile:null,
   uploader:App.Uploader,
   isRenaming:false,
-  isRemoving:false,
-  isMkdir:false,
   isUploading:false,
-  newDirName:'',
   queryParams: ['path'],
   path: '/',
   isRootDir:Ember.computed.equal('path', '/'),
@@ -165,23 +145,32 @@ App.FilesController = Ember.ArrayController.extend({
   }.property('path'),
   selectedOne:Ember.computed.equal('selectedFiles.length', 1),
   isSelected:Ember.computed.gt('selectedFiles.length', 0),
-  selectedFiles:Ember.computed.filterBy('content', 'selected', true),
+  selectedFiles:function () {
+    return this.get('content').filterBy('selected', true);
+  }.property('[email protected]'),
   canConcat:function () {
     return 
this.get('selectedFiles').filterProperty('isDirectory').get('length')==0;
   }.property('selectedFiles.length'),
 
-  fileList: Ember.computed.alias('arrangedContent')
-});
+  searchString:'',
+  fileList: function () {
+    var fileList = this.get('arrangedContent');
+    var search = this.get('searchString');
+    return (search)?fileList.filter(function (file) {
+      return !!file.get('name').match(search);
+    }):fileList;
+  }.property('arrangedContent','searchString'),
+
+  mkdirSuccessCalback:function (newDir) {
+    if (newDir.get('path') != [this.get('path'),newDir.get('name')].join('/')){
+      newDir.unloadRecord();
+      newDir.store.listdir(this.get('path'));
+    }
+  },
 
-App.FilesAlertController = Em.ObjectController.extend({
-  content:null,
-  output:function () {
-    var error = this.get('content'),output;
-    if (error instanceof Em.Error) {
-      output = error;
-    } else {
-      output = {status:error.status, message:error.statusText||error.message};
-    };
-    return output;
-  }.property('content')
+  throwAlert:function (error) {
+    this.send('showAlert',error);
+  }
 });
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js 
b/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
index c2be8c2..f2ef6b6 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
@@ -17,4 +17,14 @@
  */
 
 App.FilesAlertController = App.ErrorController.extend({
+  content:null,
+  output:function () {
+    var error = this.get('content'),output;
+    if (error instanceof Em.Error) {
+      output = error;
+    } else {
+      output = {status:error.status, message:error.statusText||error.message};
+    };
+    return output;
+  }.property('content')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/initialize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/initialize.js 
b/contrib/views/files/src/main/resources/ui/app/initialize.js
index 564bdfe..8b79492 100644
--- a/contrib/views/files/src/main/resources/ui/app/initialize.js
+++ b/contrib/views/files/src/main/resources/ui/app/initialize.js
@@ -30,12 +30,16 @@ require('templates/application');
 require('templates/index');
 require('templates/files');
 require('templates/error');
-require('templates/util/deletePopover');
-require('templates/util/uploader');
-require('templates/util/contextMenu');
-require('templates/util/deleteBulk');
 require('templates/util/errorRow');
-require('templates/util/renameInput');
+require('templates/util/fileRow');
+
+require('templates/components/uploader');
+require('templates/components/renameInput');
+require('templates/components/deletePopover');
+require('templates/components/mkdirInput');
+require('templates/components/contextMenu');
+require('templates/components/deleteBulk');
+require('templates/components/chmodInput');
 
 //////////////////////////////////
 // Models
@@ -59,12 +63,22 @@ require('controllers/filesAlert');
 require('components/uploader');
 require('components/contextMenu');
 require('components/renameInput');
+require('components/bsPopover');
+require('components/confirmDelete');
+require('components/sortArrow');
+require('components/breadCrumbs');
+require('components/popoverDelete');
+require('components/bulkCheckbox');
+require('components/mkdirInput');
+require('components/toggleContext');
+require('components/chmodInput');
 
 /////////////////////////////////
 // Views
 /////////////////////////////////
 
 require('views/file');
+require('views/filesAlert');
 
 /////////////////////////////////
 // Routes

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/routes/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/file.js 
b/contrib/views/files/src/main/resources/ui/app/routes/file.js
index afe98a8..5df1c0b 100644
--- a/contrib/views/files/src/main/resources/ui/app/routes/file.js
+++ b/contrib/views/files/src/main/resources/ui/app/routes/file.js
@@ -25,6 +25,9 @@ App.FilesRoute = Em.Route.extend({
     }
   },
   actions:{
+    refreshDir:function () {
+      this.refresh();
+    },
     error:function (error,transition,e) {
       if (this.router._lookupActiveView('files')) {
         this.send('showAlert',error);

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/styles/application.less
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/styles/application.less 
b/contrib/views/files/src/main/resources/ui/app/styles/application.less
index 6242bc5..c44923e 100644
--- a/contrib/views/files/src/main/resources/ui/app/styles/application.less
+++ b/contrib/views/files/src/main/resources/ui/app/styles/application.less
@@ -68,6 +68,22 @@
     .i-am-in {
       margin: 0;
       width: 80%;
+      .dir-name {
+        color: black;
+      }
+    }
+    .input-group-search {
+      .input-search {
+        padding-right: 25px;
+      }
+      .form-control-feedback {
+        position: absolute;
+        z-index: 2;
+        top: 8px;
+        right: 39px;
+        cursor: pointer;
+        opacity: 0.5;
+      }
     }
   }
 
@@ -139,6 +155,24 @@
           }
         }
       }
+      .chmod-row {
+        &:hover > td {
+          background-color: #fff;
+          cursor: default;
+        }
+        & > td {
+          border-top: 0;
+          padding: 0;
+        }
+/*         .chmod-wrap {
+  transition: all 0.3s ease;
+  opacity: 1;
+  margin-right: 0px;
+  height: 32px;
+  overflow: hidden;
+  padding-top: 5px;
+} */
+      }
       .btn-delete {
         .popover-content{
           width: 80px;
@@ -161,8 +195,8 @@
           width: 130px;
           margin-bottom: 0;
           .delete-forever {
-            display: inline-block;
-            margin: 5px;
+            float: right;
+            margin: 0px 0px 0 10px;
           }
         }
         .mod-time{
@@ -249,6 +283,27 @@
   }
 }
 
+#bulkDropdown {
+  .sub-label{
+    display: inline-block;
+    width: 55%;
+  }
+}
+
+#context-menu {
+  .sub-label{
+    display: inline-block;
+    width: 55%;
+  }
+  .dropdown-confirm {
+    margin: -4px 8px;
+  }
+}
+
+.dropdown-confirm {
+  margin: -4px 0;
+}
+
 
 .fa-right {
   top: 3px;
@@ -293,10 +348,6 @@
   }
 }
 
-.dropdown-confirm {
-  margin: -4px 0;
-}
-
 .renameable {
   display: inline-block;
   &.half {
@@ -321,3 +372,7 @@
     margin-left: -1px;
   }
 }
+.modal-backdrop.in {
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/chmodInput.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/chmodInput.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/chmodInput.hbs
new file mode 100644
index 0000000..4805e65
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/chmodInput.hbs
@@ -0,0 +1,100 @@
+{{!
+   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.
+}}
+
+<td colspan="8" class="">
+
+<div class="modal chmodal" tabindex="-1" role="dialog" aria-hidden="true" 
data-backdrop="static">
+  <div class="modal-dialog modal-sm">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal"><span 
aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
+        <h4 class="modal-title">Edit permission</h4>
+      </div>
+      <div class="modal-body">
+
+        <form class="form-horizontal" role="form">
+          <div class="form-group">
+            <label class="col-sm-2 control-label">User</label>
+            <div class="col-sm-10">
+              <div class="btn-group" data-toggle="buttons">
+                <label {{bind-attr class=":btn :btn-sm 
usrR:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=usrR}} <span>Read</span>
+                </label>
+                <label {{bind-attr class=":btn :btn-sm 
usrW:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=usrW}} <span>Write</span>
+                </label>
+                <label {{bind-attr class=":btn :btn-sm 
usrE:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=usrE}} <span>Execute</span>
+                </label>
+              </div>
+            </div>
+          </div>
+          <div class="form-group">
+            <label class="col-sm-2 control-label">Group</label>
+            <div class="col-sm-10">
+              <div class="btn-group" data-toggle="buttons">
+                <label {{bind-attr class=":btn :btn-sm 
grpR:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=grpR}} <span>Read</span>
+                </label>
+                <label {{bind-attr class=":btn :btn-sm 
grpW:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=grpW}} <span>Write</span>
+                </label>
+                <label {{bind-attr class=":btn :btn-sm 
grpE:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=grpE}} <span>Execute</span>
+                </label>
+              </div>
+            </div>
+          </div>
+          <div class="form-group">
+            <label class="col-sm-2 control-label">Other</label>
+            <div class="col-sm-10">
+              <div class="btn-group" data-toggle="buttons">
+                <label {{bind-attr class=":btn :btn-sm 
otrR:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=otrR}} <span>Read</span>
+                </label>
+                <label {{bind-attr class=":btn :btn-sm 
otrW:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=otrW}} <span>Write</span>
+                </label>
+                <label {{bind-attr class=":btn :btn-sm 
otrE:btn-primary:btn-default :btn-chmod" }} >
+                  {{input type="checkbox" checked=otrE}} <span>Execute</span>
+                </label>
+              </div>
+            </div>
+          </div>
+
+          <div class="form-group">
+            <div class="col-sm-offset-2 col-sm-10">
+              <div class="checkbox">
+                <label>
+                  {{input type="checkbox"}} <span> Modify recursively</span>
+                </label>
+              </div>
+            </div>
+          </div>
+        </form>
+
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" {{action 
'close'}}>Close</button>
+        <button type="button" class="btn btn-primary" {{action 
'confirm'}}>Save changes</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+</td>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/contextMenu.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/contextMenu.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/contextMenu.hbs
new file mode 100644
index 0000000..844363c
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/contextMenu.hbs
@@ -0,0 +1,43 @@
+{{!
+   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.
+}}
+
+{{#dropdown-wrap}}
+<div id="context-menu">
+  <ul class="dropdown-menu dropdown-context compressed-context" role="menu">
+    {{#if view.target.content.isDirectory}} 
+    <li><a tabindex="-1" href="#" {{action 'open'}}>Open folder</a></li>
+    {{else}}
+    <li><a tabindex="-1" href="#" {{action 'download'}}>Download</a></li>
+    {{/if}}
+    <li><a tabindex="-1" href="#" {{action 'moveFile' 'cut' 
view.target.content}}>Move</a></li>
+    <li><a tabindex="-1" href="#" {{action 'showChmod'}} >Permissions</a></li>
+    <li><a tabindex="-1" href="#" {{action 'editName'}} >Rename</a></li>
+    <li class="divider"></li>
+    <li class="dropdown-submenu">
+      <a href="#" data-disabled="disabled">
+      <span> Delete </span>
+        <i class="fa fa-chevron-right pull-right fa-right"></i>
+      </a>
+      <ul class="dropdown-menu">
+        {{confirm-delete confirm="removeFile" deleteForever=true }}
+        {{confirm-delete confirm="moveToTrash" deleteForever=false }}
+      </ul>
+    </li>
+  </ul>
+</div>
+{{/dropdown-wrap}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/deleteBulk.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/deleteBulk.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/deleteBulk.hbs
new file mode 100644
index 0000000..e7e6c69
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/deleteBulk.hbs
@@ -0,0 +1,46 @@
+{{!
+   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.
+}}
+
+{{#if isRemoving}}
+<a  tabindex="-1">
+  {{#if deleteForever}}
+    <i class="fa fa-fw fa-exclamation-triangle"></i>
+    <span class="sub-label" > Delete forever </span>
+  {{else}}
+    <i class="fa fa-fw fa-trash-o"></i>
+    <span class="sub-label" >Move To Trash</span>
+  {{/if}}
+  <div class="btn-group text-center dropdown-confirm">
+    <button {{action 'cancel'}} type="button" class="btn btn-xs btn-danger">
+      <span class="glyphicon glyphicon-remove"></span>
+    </button>
+    <button {{action 'confirm'}} type="button" class="btn btn-xs btn-success 
delete">
+      <span class="glyphicon glyphicon-ok delete"></span>
+    </button>
+  </div>
+</a>
+{{else}}
+<a {{action 'ask'}} tabindex="-1" href="#">
+  {{#if deleteForever}}
+    <i class="fa fa-fw fa-exclamation-triangle"></i> <span class="sub-label" > 
Delete forever </span>
+  {{else}}
+    <i class="fa fa-fw fa-trash-o"></i> <span class="sub-label" >Move To 
Trash</span>
+  {{/if}}
+</a>
+{{/if}}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/deletePopover.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/deletePopover.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/deletePopover.hbs
new file mode 100644
index 0000000..e5f3b9a
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/deletePopover.hbs
@@ -0,0 +1,38 @@
+{{!
+   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.
+}}
+
+<a data-toggle="tooltip" data-placement="bottom" title="Delete"> <i class="fa 
fa-trash-o fa-lg"></i> </a>
+
+{{#bs-popover triggers='click' placement='left'}}
+  <div class="input-group" >
+    <div class="btn-group ">
+      <button {{action 'close'}} type="button" class="btn btn-xs btn-danger">
+        <i class="fa fa-times fa-fw"></i>
+      </button>
+      <button {{action 'confirm'}} type="button" class="btn btn-xs 
btn-success">
+        <i class="fa fa-check fa-fw"></i>
+      </button>
+    </div>
+    <div class="checkbox delete-forever">
+      <label>
+      {{input type="checkbox" checkedBinding='deleteForever' }} Delete forever
+      </label>
+    </div>
+  </div>
+{{/bs-popover}}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/mkdirInput.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/mkdirInput.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/mkdirInput.hbs
new file mode 100644
index 0000000..0db9240
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/mkdirInput.hbs
@@ -0,0 +1,37 @@
+{{!
+   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.
+}}
+
+{{#unless isMkdir}} 
+  <button type="button" {{action 'edit'}} {{bind-attr class=":btn :btn-default 
:btn-sm :pull-right :mkdirwrap"}}>
+    <i class="fa fa-plus"></i> New directory
+  </button>
+{{else}}
+  <div class="input-group input-group-sm pull-right mkdir-area">
+    {{input class="form-control mkdir-input" valueBinding='newDirName' 
placeholder="Enter Directory Name"}}
+    <div class="input-group-btn">
+      <button  type="button" {{action 'cancel'}} {{bind-attr class=":btn 
:btn-danger :btn-sm :btn-mkdir-cancel"}} >
+        <i class="fa fa-times"></i> Cancel
+      </button>
+    </div>
+    <div class="input-group-btn">
+      <button  type="button" {{action 'create'}} {{bind-attr 
class="newDirName::disabled :btn :btn-success :btn-sm :btn-mkdir"}} >
+        <i class="fa fa-check"></i> Create
+      </button>
+    </div>
+  </div>
+{{/unless}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/renameInput.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/renameInput.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/renameInput.hbs
new file mode 100644
index 0000000..57a7b7c
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/renameInput.hbs
@@ -0,0 +1,38 @@
+{{!
+   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.
+}}
+{{#if isRenaming}}
+
+<div class="input-group input-group-sm rename-area">
+  {{view view.renameInputView class="form-control rename-input" 
valueBinding='tmpName'}}
+  <div class="input-group-btn">
+    <button  type="button" {{action 'rename' 'cancel'}} {{bind-attr 
class=":btn :btn-danger :btn-xs :btn-rename-cancel isRenaming:show"}} >
+      <i class="fa fa-times"></i> Cancel
+    </button>
+  </div>
+  <div class="input-group-btn">
+    <button  type="button" {{action 'rename' 'confirm'}} {{bind-attr 
class=":btn :btn-success :btn-xs :btn-rename isRenaming:show"}} >
+      <i class="fa fa-check"></i> Rename
+    </button>
+  </div>
+</div>
+
+{{else}}
+
+  {{yield}}
+
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/components/uploader.hbs
----------------------------------------------------------------------
diff --git 
a/contrib/views/files/src/main/resources/ui/app/templates/components/uploader.hbs
 
b/contrib/views/files/src/main/resources/ui/app/templates/components/uploader.hbs
new file mode 100644
index 0000000..cefc9f8
--- /dev/null
+++ 
b/contrib/views/files/src/main/resources/ui/app/templates/components/uploader.hbs
@@ -0,0 +1,35 @@
+{{!
+   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.
+}}
+
+<div class="input-group input-group-sm">
+  <span class="input-group-btn">
+    <span class="btn btn-primary btn-file">
+      Browse… {{view fileInput}}
+    </span>
+    <span  {{bind-attr class=":btn :btn-danger isFiles:hide"}} {{action 
'clear'}}  >
+      Clear
+    </span>
+  </span>
+  <span {{bind-attr class=":input-group-btn :btn-upload isFiles:hide"}}>
+    {{#view uploadButton data-style="expand-right" data-size="xs"}}
+      <span class="ladda-label">Upload</span>
+    {{/view}}
+  </span>
+  {{view controlInput placeholder='Select files to upload.'}}
+</div>
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5b9af74/contrib/views/files/src/main/resources/ui/app/templates/files.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/templates/files.hbs 
b/contrib/views/files/src/main/resources/ui/app/templates/files.hbs
index 8b4cff0..6f65e91 100644
--- a/contrib/views/files/src/main/resources/ui/app/templates/files.hbs
+++ b/contrib/views/files/src/main/resources/ui/app/templates/files.hbs
@@ -19,13 +19,13 @@
 <div class="panel-default panel-files">
   <div class="panel-heading">
     {{!-- BREADCRUMBS --}}  
-    {{view view.breadcrumbsView}}
+    {{bread-crumbs path=path}}
       
     <div class="um-section">
     {{!-- UPLOADER --}}  
     <div {{bind-attr class="isUploading::hide :pull-right" }}>
       <button {{action 'upload' 'close'}} type="button" class="close" 
aria-hidden="true">&times;</button>
-      {{file-uploader path=path uploader=uploader class=" upload-area 
pull-right"}}
+      {{file-uploader path=path uploader=uploader class=" upload-area 
pull-right" alert='showAlert'}}
     </div>
 
     <div {{bind-attr class="isUploading:hide: :pull-right :uploadwrap" }}>
@@ -34,57 +34,26 @@
       </button>
     </div>
 
-    {{!-- MKDIR --}}  
-    {{#unless isMkdir}} 
-      <button type="button" {{action 'mkdir' 'edit'}} {{bind-attr class=":btn 
:btn-default :btn-sm :pull-right :mkdirwrap"}}>
-        <i class="fa fa-plus"></i> New directory
-      </button>
-    {{else}}
-      <div class="input-group input-group-sm pull-right mkdir-area">
-        {{input class="form-control mkdir-input" valueBinding='newDirName'}}
-        <div class="input-group-btn">
-          <button  type="button" {{action 'mkdir' 'cancel'}} {{bind-attr 
class=":btn :btn-danger :btn-sm :btn-mkdir-cancel"}} >
-            <i class="fa fa-times"></i> Cancel
-          </button>
-        </div>
-        <div class="input-group-btn">
-          <button  type="button" {{action 'mkdir' 'confirm'}} {{bind-attr 
class=":btn :btn-success :btn-sm :btn-mkdir"}} >
-            <i class="fa fa-check"></i> Create
-          </button>
-        </div>
-      </div>
-    {{/unless}}
-
+    {{!-- MKDIR --}} 
+    {{mkdir-input create="mkdir" path=path}}
 
     </div>
   </div>
 
   <div class="panel-body">
     <h4 class="i-am-in pull-left"> <i class="fa fa-folder fa-lg"></i>
-    {{#rename-input file=path actionName='renameDir' isRenaming=isRenaming 
class='renameable stocked half'}}
-      {{currentDir}} <a href="#" {{bind-attr class="isRootDir:hide"}} {{action 
showRenameInput}}><i class="fa fa-edit"></i></a>
+    {{#rename-input file=path confirm='renameDir' isRenaming=isRenaming 
class='renameable stocked half'}}
+      <a href="#" class="dir-name" {{action refreshDir}}>{{currentDir}}</a>
+      <a href="#" {{bind-attr class="isRootDir:hide"}} {{action 
showRenameInput}}><i class="fa fa-edit"></i></a>
     {{/rename-input}}
     </h4>
 
-    <div class="btn-group btn-sort pull-right" data-toggle="tooltip" 
data-placement="left" title="Sort by:">
-      <button type="button" class="btn btn-xs btn-default" {{action sort 
'toggle'}}>
-      {{#if sortAscending}} Asc {{else}} Desc {{/if}}
-      </button>
-
-      <button type="button" class="btn btn-xs btn-default dropdown-toggle" 
data-toggle="dropdown">
-        <span>
-        {{capitalize sortProperties.firstObject}}
-        </span>
-        <span class="caret"></span>
-      </button>
-      <ul class="dropdown-menu" role="menu">
-        <li><a href="#" {{action 'sort' 'name'}} >Name</a></li>
-        <li><a href="#" {{action 'sort' 'size'}} >Size</a></li>
-        <li><a href="#" {{action 'sort' 'owner'}} >Owner</a></li>
-        <li><a href="#" {{action 'sort' 'group'}} >Group</a></li>
-        <li><a href="#" {{action 'sort' 'permission'}} >Permission</a></li>
-        <li><a href="#" {{action 'sort' 'date'}} >Date</a></li>
-      </ul>
+    <div class="input-group input-group-sm input-group-search">
+      {{input valueBinding='searchString' class="form-control input-search" 
placeholder="Search File Names" }}
+      {{#if searchString}}
+        <i {{action 'clearSearchField'}} class="fa fa-times 
form-control-feedback"></i>
+      {{/if}}
+      <div class="input-group-addon"><i class="fa fa-search"></i></div>
     </div>
   </div>
 
@@ -92,44 +61,66 @@
     <thead>
       <tr>
         <th class="icon"></th>
-        <th class="path" {{action 'sort' 'name'}}> Name {{view view.sortArrow 
sortProperty='name'}} </th>
-        <th class="size" {{action 'sort' 'size'}}>Size {{view view.sortArrow 
sortProperty='size'}}</th>
-        <th class="owner" {{action 'sort' 'owner'}}>Owner {{view 
view.sortArrow sortProperty='owner'}}</th>
-        <th class="grp" {{action 'sort' 'group'}} >Group {{view view.sortArrow 
sortProperty='group'}}</th>
-        <th class="perm" {{action 'sort' 'permission'}} >Permission {{view 
view.sortArrow sortProperty='permission'}}</th>
+        <th class="path" {{action 'sort' 'name'}}> Name {{sort-arrow 
sPs=sortProperties sA=sortAscending sP='name'}} </th>
+        <th class="size" {{action 'sort' 'size'}}>Size {{sort-arrow 
sPs=sortProperties sA=sortAscending sP='size'}}</th>
+        <th class="owner" {{action 'sort' 'owner'}}>Owner {{sort-arrow 
sPs=sortProperties sA=sortAscending sP='owner'}}</th>
+        <th class="grp" {{action 'sort' 'group'}} >Group {{sort-arrow 
sPs=sortProperties sA=sortAscending sP='group'}}</th>
+        <th class="perm" {{action 'sort' 'permission'}} >Permission 
{{sort-arrow sPs=sortProperties sA=sortAscending sP='permission'}}</th>
         <th class="download">
+          <div class="btn-group btn-sort pull-right" data-toggle="tooltip" 
data-placement="left" title="Sort by:">
+            <button type="button" class="btn btn-xs btn-default" {{action sort 
'toggle'}}>
+            {{#if sortAscending}} Asc {{else}} Desc {{/if}}
+            </button>
+
+            <button type="button" class="btn btn-xs btn-default 
dropdown-toggle" data-toggle="dropdown">
+              <span>
+              {{capitalize sortProperties.firstObject}}
+              </span>
+              <span class="caret"></span>
+            </button>
+            <ul class="dropdown-menu" role="menu">
+              <li><a href="#" {{action 'sort' 'name'}} >Name</a></li>
+              <li><a href="#" {{action 'sort' 'size'}} >Size</a></li>
+              <li><a href="#" {{action 'sort' 'owner'}} >Owner</a></li>
+              <li><a href="#" {{action 'sort' 'group'}} >Group</a></li>
+              <li><a href="#" {{action 'sort' 'permission'}} 
>Permission</a></li>
+              <li><a href="#" {{action 'sort' 'date'}} >Date</a></li>
+            </ul>
+          </div>
         </th>
         <th class="check"> 
+        {{#dropdown-wrap}}
           <div id="bulkDropdown" class="btn-group">
-              <span class="input-group-addon">
-                <div class="checkbox">
-                    {{view view.checkboxAll contentBinding='fileList'}}
-                </div>
-              </span>
-          <button  type="button" data-toggle="dropdown" {{bind-attr 
class=":btn :btn-xs :btn-default :dropdown-toggle isSelected::disabled"}} >
-            <span class="caret"></span>
-          </button>
-          <ul class="dropdown-menu pull-right" role="menu">
-            <li><a href="#"  {{action 'download' 'zip'}} ><i class="fa 
fa-archive fa-fw"></i> Download zip</a></li>
-            {{#if canConcat}}
-            <li><a href="#"  {{action 'download' 'concat'}} ><i class="fa 
fa-th fa-fw"></i> Concat</a></li>
-            {{/if}}
-            <li class="divider"></li>
-            <li class="dropdown-submenu">
-              <a href="#" disabled="disabled">
-                <i class="fa fa-chevron-left fa-gr fa-fw"></i> Delete
-              </a>
-              <ul class="dropdown-menu left-submenu">
-                {{view view.deleteBulkView}}
-              </ul>
-            </li>
-          </ul>
-        </div>
+            <span class="input-group-addon">
+              <div class="checkbox">
+                {{bulk-checkbox content=fileList}}
+              </div>
+            </span>
+            <button  type="button" data-toggle="dropdown" {{bind-attr 
class=":btn :btn-xs :btn-default :dropdown-toggle isSelected::disabled"}} >
+              <span class="caret"></span>
+            </button>
+            <ul class="dropdown-menu pull-right" role="menu">
+              <li><a href="#"  {{action 'download' 'zip'}} ><i class="fa 
fa-archive fa-fw"></i> Download zip</a></li>
+              {{#if canConcat}}
+              <li><a href="#"  {{action 'download' 'concat'}} ><i class="fa 
fa-th fa-fw"></i> Concat</a></li>
+              {{/if}}
+              <li class="divider"></li>
+              <li class="dropdown-submenu">
+                <a href="#" disabled="disabled">
+                  <i class="fa fa-chevron-left fa-gr fa-fw"></i> Delete
+                </a>
+                <ul class="dropdown-menu left-submenu">
+                  {{confirm-delete confirm="deleteFile" deleteForever=true 
selector='bulkDropdown'}}
+                  {{confirm-delete confirm="deleteFile" deleteForever=false 
selector='bulkDropdown'}}
+                </ul>
+              </li>
+            </ul>
+          </div>
+        {{/dropdown-wrap}}
       </th>
       </tr>
     </thead>
     <tbody>
-    <div>
       <tr>
         <td><i class="fa fa-folder"></i></td>
         <td  {{action 'dirUp'}} colspan="7">
@@ -167,7 +158,7 @@
           </td>
           <td>
             {{#unless content.isDirectory}}
-              {{humanSize movingFile.size}}
+              {{humanSize movingFile.len}}
             {{/unless}}
           </td>
           <td >{{movingFile.owner}}</td>
@@ -186,87 +177,17 @@
         </tr>
       {{/if}}
       {{/unless}}
-    </div>
       {{#each fileList itemController="file"}}
-        <tr {{bind-attr class=":file-row isMoving:isMoving"}}>
-          <td>
-            {{#if content.isDirectory}}
-            <i class="fa fa-folder"></i>
-            {{else}}
-            <i class="fa fa-file"></i>
-            {{/if}}
-          </td>
-          <td>
-            {{#unless isRenaming}}
-              <div class="file-name allow-open">
-                <span>
-                  <a {{action 'open'}}>
-                    <strong>
-                      {{content.name}}
-                    </strong>
-                  </a>
-                </span>
-                <span class="help-block mod-time allow-open">
-                  <small class='allow-open'>
-                    Updated {{showDate modificationTime 'YYYY-MM-DD HH:mm'}}
-                  </small>
-                </span>
-              </div>
-            {{else}}
-              <div class="input-group input-group-sm rename-area">
-                {{view view.renameInputView class="form-control rename-input" 
valueBinding='tmpName'}}
-                <div class="input-group-btn">
-                  <button  type="button" {{action 'rename' 'cancel'}} 
{{bind-attr class=":btn :btn-danger :btn-xs :btn-rename-cancel 
isRenaming:show"}} >
-                    <i class="fa fa-times"></i> Cancel
-                  </button>
-                </div>
-                <div class="input-group-btn">
-                  <button  type="button" {{action 'rename' 'confirm'}} 
{{bind-attr class=":btn :btn-success :btn-xs :btn-rename isRenaming:show"}} >
-                    <i class="fa fa-check"></i> Rename
-                  </button>
-                </div>
-              </div>
-            {{/unless}}
-          </td>
-          <td>
-            {{#unless content.isDirectory}}
-              {{humanSize content.size}}
-            {{/unless}}
-          </td>
-          <td >{{content.owner}}</td>
-          <td>{{content.group}}</td>
-          <td>{{content.permission}}</td>
-          <td>
-            {{#unless isMoving}}
-              <ul class="list-inline file-actions text-right">
-                <li>
-                {{#if content.isDirectory}}
-                  <a href="#" {{action 'download' 'zip'}} 
data-toggle="tooltip" data-placement="bottom" title="Download zip"><i class="fa 
fa-archive fa-fw fa-lg"></i></a>  
-                {{else}}
-                  <a href="#" {{action 'download' 'browse'}} 
data-toggle="tooltip" data-placement="bottom" title="Download"><i class="fa 
fa-download fa-fw fa-lg"></i></a>  
-                {{/if}}
-                </li>
-                <li>
-                  <a href="#" {{action 'moveFile' 'cut' this.content}} 
data-toggle="tooltip" data-placement="bottom" title="Move"><i class="fa 
fa-level-down fa-rotate-270 fa-fw fa-lg"></i></span></a>  
-                </li>
-                <li>
-                  <a {{action 'rename' 'edit'}} data-toggle="tooltip" 
data-placement="bottom" title="Rename"><i class="fa fa-edit fa-lg"></i></a>
-                </li>
-                <li>{{view view.deleteSingleView}}</li>
-              </ul>
-            {{/unless}}
-            </td>
-          <td>
-          {{#if isMoving}}
-            <a href="#" {{action 'moveFile' 'cancel' target="parentController" 
}} data-toggle="tooltip" data-placement="bottom" title="Cancel moving"> <i 
class="fa fa-times fa-lg"></i></a>
-          {{else}}
-            {{input type="checkbox" checkedBinding='content.selected'}}
-          {{/if}}
-          {{view view.togglecontext}}
-          </td>
-        </tr>
+        {{partial 'util/fileRow'}}
       {{/each}}
+      {{#unless fileList}}
+      <tr>
+        <td colspan="8">
+          No files
+        </td>
+      </tr>
+      {{/unless}}
     </tbody>
   </table>
-  {{view view.contextMenu }}
+  {{context-menu target=targetContextMenu}}
 </div>

Reply via email to