You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/02/24 19:18:02 UTC

[04/10] ambari git commit: AMBARI-15145. Revamped Filebrowser Design - UI. (dipayanb)

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/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 1315f31..4b60ab3 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
@@ -16,201 +16,154 @@
  * limitations under the License.
  */
 
-var App = require('app');
-var bind = Ember.run.bind;
-
-App.FilesController = Ember.ArrayController.extend({
-  actions:{
-    moveFile:function (opt,fileArg) {
-      var src, title,
-          file = fileArg || this.get('selectedFiles.firstObject'),
-          moving = this.get('movingFile');
-
-      if (opt == 'cut') {
-        src = file.toJSON({includeId: true});
-        src = Em.merge(src,{name:file.get('name'),path:file.get('path')});
-        this.set('movingFile',src);
-      }
-
-      if (opt == 'move') {
-        this.store.move(moving.path,[this.get('path'),moving.name].join('/').replace('//','/'))
-          .then(bind(this,this.set,'movingFile',null),bind(this,this.throwAlert));
-      }
+import Ember from 'ember';
+import columnConfig from '../config/files-columns';
+
+export default Ember.Controller.extend({
+  fileSelectionService: Ember.inject.service('files-selection'),
+  lastSelectedFile: Ember.computed.oneWay('fileSelectionService.lastFileSelected'),
+  selectedFilesCount: Ember.computed.oneWay('fileSelectionService.filesCount'),
+  selectedFolderCount: Ember.computed.oneWay('fileSelectionService.folderCount'),
+  isSelected: Ember.computed('selectedFilesCount', 'selectedFolderCount', function() {
+    return (this.get('selectedFilesCount') + this.get('selectedFolderCount')) !== 0;
+  }),
 
-      if (opt == 'cancel') {
-        this.set('movingFile',null);
-      }
-    },
-    showRenameInput:function () {
-      this.toggleProperty('isRenaming');
-    },
-    renameDir:function (path,newName) {
-      var _this = this,
-          basedir = path.substring(0,path.lastIndexOf('/')+1);
-          newPath = basedir + newName;
-
-      if (path === newPath) {
-        return false;
-      }
-
-      this.store.listdir(basedir).then(function (listdir) {
-        var recordExists = listdir.isAny('id',newPath);
-
-        listdir.forEach(function (file) {
-          _this.store.unloadRecord(file);
-        });
+  queryParams: ['path'],
+  path: '/',
+  columns: columnConfig,
+
+  hasHomePath: false,
+  hasTrashPath: false,
+
+  currentPathIsTrash: Ember.computed('path', 'trashPath', 'hasTrashPath', function() {
+    return this.get('hasTrashPath') && (this.get('path') === this.get('trashPath'));
+  }),
+
+  // This is required as the validSearchText will be debounced and will not be
+  // called at each change of searchText. searchText is required so that sub
+  // components(file search componenet) UI can be cleared from outside.(i.e, from
+  // the afterModel of the route when the route changes)
+  searchText: '',
+  validSearchText: '',
+
+  sortProperty: [],
+  sortEnabled: Ember.computed('fileSelectionService.files.length', function() {
+    return this.get('fileSelectionService.files.length') === 0;
+  }),
+
+  allSelected: Ember.computed('fileSelectionService.files.length', function() {
+    return this.get('fileSelectionService.files.length') !== 0 && this.get('fileSelectionService.files.length') === this.get('model.length');
+  }),
+
+  parentPath: Ember.computed('path', function() {
+    var path = this.get('path');
+    var parentPath = path.substring(0, path.lastIndexOf('/'));
+    if(Ember.isBlank(parentPath)) {
+      parentPath = '/';
+    }
 
-        if (recordExists) {
-          return _this.throwAlert({message:newPath + ' already exists.'});
-        }
+    if(path === '/') {
+      parentPath = '';
+    }
+    return parentPath;
+  }),
 
-        return _this.store.move(path,newPath);
-      }).then(function (newDir) {
-        if (newDir) {
-          _this.store.unloadRecord(newDir);
-          _this.set('path',newPath);
-        }
-      }).catch(bind(this,this.throwAlert));
+  sortedContent: Ember.computed.sort('model', 'sortProperty'),
 
-    },
-    deleteFile:function (deleteForever) {
-      var self = this,
-          selected = this.get('selectedFiles'),
-          moveToTrash = !deleteForever;
-      selected.forEach(function (file) {
-        self.store.remove(file,moveToTrash).then(null,bind(self,self.deleteErrorCallback,file));
+  arrangedContent: Ember.computed('model', 'sortProperty', 'validSearchText', function() {
+    var searchText = this.get('validSearchText');
+    if(!Ember.isBlank(searchText)) {
+      return this.get('sortedContent').filter(function(entry) {
+        return !!entry.get('name').match(searchText);
       });
+    }
+    return this.get('sortedContent');
+  }),
+
+  actions: {
+    sortFiles: function(sortColumn) {
+      if (sortColumn['sortOrder'] !== 0) {
+        var sortProperty = sortColumn['key'] + ':' + this._getSortOrderString(sortColumn);
+        this.set('sortProperty', [sortProperty]);
+      } else {
+        this.set('sortProperty', []);
+      }
     },
-    download:function (option) {
-      var files = this.get('selectedFiles').filterBy('readAccess',true);
-      var content = this.get('content');
-      this.store.linkFor(content, option).then(function (link) {
-        window.location.href = link;
-      });
+
+    searchFiles: function(searchText) {
+      this.set('validSearchText', searchText);
     },
 
-    mkdir:function (newDirName) {
-      this.store.mkdir(newDirName)
-        .then(bind(this,this.mkdirSuccessCalback),bind(this,this.throwAlert));
+    /* Selects a single file. Clears previous selection */
+    selectSingle: function(file) {
+      this.get('fileSelectionService').deselectAll();
+      this.get('fileSelectionService').selectFiles([file]);
     },
-    upload:function (opt) {
-      if (opt === 'open') {
-        this.set('isUploading',true);
-      }
 
-      if (opt === 'close') {
-        this.set('isUploading',false);
+    /*
+      Selects file without clearing the previous selection. If sticky is true
+      then shiftkey was pressed while clicking and we should select all the
+      files in between
+    */
+    selectMultiple: function(file, sticky) {
+      if(!sticky) {
+        if(file.get('isSelected')) {
+          this.get('fileSelectionService').deselectFile(file);
+        } else {
+          this.get('fileSelectionService').selectFiles([file]);
+        }
+      } else {
+        var lastFileSelected = this.get('fileSelectionService.lastFileSelected');
+        var indexRange = this._getIndexRangeBetweenfiles(lastFileSelected, file);
+        if(indexRange[0] === indexRange[1]) {
+          return false;
+        }
+        var filesInRange = this._getFilesInRange(indexRange[0], indexRange[1]);
+        this.get('fileSelectionService').deselectAll();
+        this.get('fileSelectionService').selectFiles(filesInRange);
       }
     },
-    sort:function (pr) {
-      var currentProperty = this.get('sortProperties');
-      if (pr == currentProperty[0] || pr == 'toggle') {
-        this.toggleProperty('sortAscending');
-      } else{
-        this.set('sortProperties',[pr]);
-        this.set('sortAscending',true);
+
+    selectAll: function(selectStatus) {
+      this.get('fileSelectionService').deselectAll();
+      if(selectStatus === false) {
+        this.get('fileSelectionService').selectFiles(this.get('sortedContent'));
       }
     },
-    confirmChmod:function (file) {
-      this.store
-        .chmod(file)
-        .then(null,Em.run.bind(this,this.chmodErrorCallback,file));
-    },
-    confirmPreview:function (file) {
-      //this.send('download');
-      this.store.linkFor(file, "browse").then(function (link) {
-        window.location.href = link;
-      });
-    },
-    clearSearchField:function () {
-      this.set('searchString','');
-    }
-  },
-  init:function () {
-    if (App.testing) {
-      return this._super();
-    }
-    var controller = this;
-    var adapter = controller.store.adapterFor('file');
-    var url = adapter.buildURL('upload');
-    this.uploader.set('url',url);
-    this.uploader.on('didUpload', function (payload) {
-      controller.store.pushPayload('file', {'file': payload });
-    });
-    this._super();
-  },
 
-  sortProperties: ['name'],
-  sortAscending: true,
+    /* Deselects the current selections */
+    deselectAll: function() {
+      this.get('fileSelectionService').deselectAll();
+    },
 
-  needs: ["file"],
-  movingFile:null,
-  uploader:App.Uploader,
-  isRenaming:false,
-  isUploading:false,
-  queryParams: ['path'],
-  path: '/',
-  isRootDir:Ember.computed.equal('path', '/'),
-  hideMoving:function () {
-    return (this.movingFile)?[this.path,this.movingFile.name].join('/').replace('//','/')===this.movingFile.path:false;
-  }.property('movingFile','path'),
-  currentDir:function () {
-    return this.get('path').split('/').get('lastObject') || '/';
-  }.property('path'),
-  selectedOne:Ember.computed.equal('selectedFiles.length', 1),
-  isSelected:Ember.computed.gt('selectedFiles.length', 0),
-  selectedFiles:function () {
-    return this.get('content').filterBy('selected', true);
-  }.property('content.@each.selected'),
-  canConcat:function () {
-    return this.get('selectedFiles').filterProperty('isDirectory').get('length')===0;
-  }.property('selectedFiles.length'),
-
-  isSortPropertyEqualsDate: function() {
-    return this.get('sortProperties').get('firstObject') === 'date';
-  }.property('sortProperties.firstObject'),
-
-  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'));
+    //Context Menu actions
+    openFolder: function(path) {
+      this.transitionToRoute({queryParams: {path: path}});
     }
   },
 
-  clearSearch:function () {
-    this.set('searchString','');
-  }.observes('path'),
-
-  deleteErrorCallback:function (record,error) {
-    this.model.pushRecord(record);
-    this.throwAlert(error);
-  },
-
-  chmodErrorCallback:function (record,error) {
-    record.rollback();
-    this.throwAlert({message:'Permissions change failed'});
-  },
-
-  throwAlert:function (error) {
-    this.send('showAlert',error);
+  _getIndexRangeBetweenfiles: function(startFile, endFile) {
+    var startIndex = this.get('arrangedContent').indexOf(startFile);
+    var endIndex = this.get('arrangedContent').indexOf(endFile);
+    if (startIndex < endIndex) {
+      return [startIndex, endIndex];
+    } else {
+      return [endIndex, startIndex];
+    }
   },
 
-  showSpinner:function () {
-    this.set('isLoadingFiles',true);
+  _getFilesInRange: function(startIndex, endIndex) {
+    var range = Array.apply(null, Array(endIndex - startIndex + 1)).map(function (_, i) {return startIndex + i;});
+    return this.get('arrangedContent').objectsAt(range);
   },
 
-  hideSpinner:function () {
-    this.set('isLoadingFiles',false);
+  _getSortOrderString: function(column) {
+    if (column['sortOrder'] === -1) {
+      return 'desc';
+    } else if (column['sortOrder'] === 1) {
+      return 'asc';
+    } else {
+      return '';
+    }
   }
 });
-
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/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
deleted file mode 100644
index 64221e3..0000000
--- a/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * 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.
- */
-
-App.FilesAlertController = App.ErrorController.extend({
-  content:null,
-  output:function () {
-    var error = this.get('content'),
-        message = (error.responseJSON)?error.responseJSON.message:error.message,
-        output;
-
-    if (message) {
-      message = message.split('\n').objectAt(0);
-    }
-
-    return message;
-  }.property('content')
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/messages.js b/contrib/views/files/src/main/resources/ui/app/controllers/messages.js
new file mode 100644
index 0000000..52655e3
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/messages.js
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+  filesController: Ember.inject.controller('files'),
+  currentBrowserPath: Ember.computed.oneWay('filesController.path'),
+  isExpanded: true,
+  shortenLength: Ember.computed('isExpanded', function() {
+    if(this.get('isExpanded') === true) {
+      return 200;
+    } else {
+      return 100;
+    }
+  })
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js b/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js
new file mode 100644
index 0000000..d46c1f6
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+
+  showStatus: Ember.computed('model', function() {
+    return this.get('model.status') !== -1;
+  }),
+
+  displayBody: Ember.computed('model', function() {
+    return !(Ember.isBlank(this.get('model.responseMessage'))
+      && Ember.isBlank(this.get('model.trace')));
+  })
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js b/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
deleted file mode 100644
index 35973b2..0000000
--- a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * 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.PreviewModalController = Em.ObjectController.extend({
-    needs:['files', 'file'],
-    offset: 3000 ,
-    startIndex:0,
-    file:Em.computed.alias('content'),
-    filePageText:'',
-    reload: false,
-    pagecontent: Ember.computed('file', 'startIndex', 'endIndex', 'reload', function() {
-        var file = this.get('file');
-        var filepath = file.get('path');
-        var filePageText = this.get('filePageText');
-
-        var self = this,
-            defer = Ember.RSVP.defer(),
-            startIndex = this.get('startIndex'),
-            endIndex  = this.get('endIndex');
-
-        var pathName = window.location.pathname;
-        var pathNameArray = pathName.split("/");
-        var ViewVersion = pathNameArray[3];
-        var viewName = pathNameArray[4];
-        var previewServiceURL = "/api/v1/views/FILES/versions/"+ ViewVersion + "/instances/" + viewName + "/resources/files/preview/file" + '?path=' + filepath + '&start='+ startIndex +'&end='+ endIndex;
-
-        var previousText = $('.preview-content').text();
-
-        $.ajax({
-            url: previewServiceURL,
-            dataType: "json",
-            type: 'get',
-            async: false,
-            contentType: 'application/json',
-            success: function( response, textStatus, jQxhr ){
-                self.set('filePageText', previousText + response.data);
-                self.set('isFileEnd',response.isFileEnd);
-            },
-            error: function( jqXhr, textStatus, errorThrown ){
-                console.log( "Preview Fail pagecontent : " + errorThrown );
-              self.send('removePreviewModal');
-              self.send('showAlert', jqXhr);
-              self.set('reload', !self.get('reload'));
-            }
-        });
-
-        if(self.get('isFileEnd') == true){
-           this.set('showNext', false);
-        }
-        return self.get('filePageText');
-    }),
-    endIndex: Ember.computed('startIndex', 'offset', function() {
-        var startIndex = this.get('startIndex'),
-            offset  = this.get('offset');
-        return startIndex + offset;
-    }),
-    showPrev : Ember.computed('startIndex', function() {
-        var startIndex = this.get('startIndex');
-        this.set('showNext', true);
-        return ((startIndex == 0) ? false : true );
-    }),
-    showNext : true,
-    actions:{
-        next: function(){
-            console.log('Next');
-            this.set('startIndex', this.get('startIndex') + this.get('offset'));
-            return this.get('filePageText');
-        },
-        prev: function(){
-            console.log('Prev');
-            this.set('startIndex', (this.get('startIndex') - this.get('offset')) > 0 ? (this.get('startIndex') - this.get('offset')) : 0);
-        }
-    }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/.gitkeep b/contrib/views/files/src/main/resources/ui/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js
new file mode 100644
index 0000000..28a5a8d
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function alertMessageContextClass(params) {
+  let messageType = params[0];
+  let prefix = params[1];
+  return `${prefix}${messageType}`;
+}
+
+export default Ember.Helper.helper(alertMessageContextClass);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js
new file mode 100644
index 0000000..707f2d1
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export function alertMessageIconClass(params) {
+  let type = params[0];
+  switch (type) {
+    case 'success':
+      return 'check';
+    case 'info':
+      return 'info';
+    case 'warning':
+      return 'exclamation';
+    case 'danger':
+      return 'times';
+    default:
+      return 'check';
+  }
+}
+
+export default Ember.Helper.helper(alertMessageIconClass);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js b/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js
new file mode 100644
index 0000000..25601c8
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function getSortingIcon(params/*, hash*/) {
+  let sortOrder = params[0];
+  var iconClass;
+  if (sortOrder === 1) {
+    iconClass = "chevron-down";
+  } else if (sortOrder === -1) {
+    iconClass = "chevron-up";
+  } else {
+    iconClass = "chevron-right";
+  }
+  return iconClass;
+}
+
+export default Ember.Helper.helper(getSortingIcon);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js b/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js
new file mode 100644
index 0000000..7570327
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function getValueFromColumns(params) {
+  let columnsArray = params[0];
+  let key = params[1];
+  let paramKey = params[2];
+
+  var column = columnsArray.filterBy('key', key);
+
+  if(column.length > 0) {
+    return column[0][paramKey];
+  }
+  return "";
+}
+
+export default Ember.Helper.helper(getValueFromColumns);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js b/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js
new file mode 100644
index 0000000..c50b5ca
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function shortenText(params) {
+  let text = params[0];
+  let length = params[1];
+  if (text.length < length) {
+    return text;
+  } else {
+    return text.substring(0, length - 3) + '...';
+  }
+
+}
+
+export default Ember.Helper.helper(shortenText);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js b/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js
new file mode 100644
index 0000000..0f47982
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function showDate(params) {
+  let date = params[0];
+  let format = params[1];
+  return moment(date).format(format);
+}
+
+export default Ember.Helper.helper(showDate);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js b/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js
new file mode 100644
index 0000000..2855ca4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function sizeHumanize(params) {
+  let fileSizeInBytes = params[0];
+  var i = -1;
+  var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
+  do {
+      fileSizeInBytes = fileSizeInBytes / 1024;
+      i++;
+  } while (fileSizeInBytes > 1024);
+
+  return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
+}
+
+export default Ember.Helper.helper(sizeHumanize);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js b/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js
new file mode 100644
index 0000000..d24780d
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function stringCapitalize(params/*, hash*/) {
+  return params;
+}
+
+export default Ember.Helper.helper(stringCapitalize);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/index.html b/contrib/views/files/src/main/resources/ui/app/index.html
new file mode 100644
index 0000000..51d1839
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/index.html
@@ -0,0 +1,42 @@
+<!--
+ * 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.
+-->
+
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>HDFS - File Browser</title>
+    <meta name="description" content="">
+
+    {{content-for "head"}}
+
+    <link rel="stylesheet" href="assets/vendor.css">
+    <link rel="stylesheet" href="assets/files-view.css">
+
+    {{content-for "head-footer"}}
+  </head>
+  <body>
+    {{content-for "body"}}
+
+    <script src="assets/vendor.js"></script>
+    <script src="assets/files-view.js"></script>
+
+    {{content-for "body-footer"}}
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/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
deleted file mode 100644
index 7790397..0000000
--- a/contrib/views/files/src/main/resources/ui/app/initialize.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * 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.
- */
-
-//////////////////////////////////
-// Adapter
-//////////////////////////////////
-
-require('adapter');
-
-//////////////////////////////////
-// Templates
-//////////////////////////////////
-
-require('templates/application');
-require('templates/index');
-require('templates/files');
-require('templates/error');
-require('templates/modal/chmod');
-require('templates/modal/preview');
-require('templates/util/errorRow');
-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');
-
-//////////////////////////////////
-// Models
-//////////////////////////////////
-
-require('models/file');
-
-/////////////////////////////////
-// Controllers
-/////////////////////////////////
-
-require('controllers/files');
-require('controllers/file');
-require('controllers/error');
-require('controllers/filesAlert');
-require('controllers/chmodModal');
-require('controllers/previewModal');
-
-/////////////////////////////////
-// Components
-/////////////////////////////////
-
-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');
-
-/////////////////////////////////
-// Views
-/////////////////////////////////
-
-require('views/file');
-require('views/files');
-require('views/filesAlert');
-require('views/modalChmod');
-require('views/modalPreview');
-
-/////////////////////////////////
-// Routes
-/////////////////////////////////
-
-require('routes/file');
-require('routes/error');
-
-/////////////////////////////////
-// Router
-/////////////////////////////////
-
-require('router');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js b/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js
new file mode 100644
index 0000000..6f4d070
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+/*
+  Base Mixin to be used by different Services to get the common behaviors mixed
+  in to the service.
+*/
+export default Ember.Mixin.create({
+  store: Ember.inject.service('store'),
+
+  getBaseFilesURLPath: function() {
+    // TODO: This has to be changed when it is integrated inside Ambari
+    //var pathName = window.location.pathname;
+    var pathname = '/api/v1/views/FILES/versions/1.0.0/instances/Files/resources/files';
+    return pathname;
+  },
+
+  getBaseDirPath: function(path) {
+    return path.substring(0, path.lastIndexOf('/') + 1);
+  },
+
+  _getBaseURLFragments: function() {
+    var adapter = this.get('store').adapterFor('file');
+    var baseURL = adapter.buildURL('file');
+    return baseURL.split('/');
+  },
+
+  extractError: function(error) {
+    if (Ember.isArray(error.errors) && (error.errors.length >= 0)) {
+      return error.errors[0];
+    }
+    return {};
+  },
+
+  isInvalidError: function(error) {
+    // This seems to a slight hack. But from backend the response of 422 is
+    // always a hash which has success param set and value is false
+    return Ember.isPresent(error.success) && error.success === false;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js b/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js
new file mode 100644
index 0000000..543498f
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js
@@ -0,0 +1,82 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { EKMixin, keyUp, EKFirstResponderOnFocusMixin } from 'ember-keyboard';
+
+export default Ember.Mixin.create(EKMixin, EKFirstResponderOnFocusMixin, {
+  modalEventBus: Ember.inject.service('modal-event-bus'),
+  name: '',
+  closeOnEscape: false,
+  isModalOpen: false,
+
+  setupKey: Ember.on('init', function() {
+    this.set('keyboardActivated', true);
+  }),
+
+  //disableEscape:
+  closeModalOnEscape: Ember.on(keyUp('Escape'), function() {
+    if (this.get('closeOnEscape')) {
+      this.$('.modal').modal('hide');
+    }
+  }),
+
+  initModal: function() {
+    Ember.defineProperty(this, 'modalGuard', Ember.computed.alias('modalEventBus.' + this.get('name')));
+    this.addObserver('modalGuard', () => {
+      if(this.get('modalGuard')) {
+        this.set('isModalOpen', true);
+        Ember.run.later(this, () => {
+          this.$('.modal').modal({backdrop: 'static', keyboard: false});
+          this.$('.modal').on('hide.bs.modal', () => {
+            this.send('closeModal');
+          });
+          this.send('modalOpened');
+        });
+
+      }
+    });
+  }.on('didInitAttrs'),
+
+  hideModal: Ember.on('willDestroyElement', function() {
+    if (this.get('isModalOpen')) {
+      this.$('.modal').modal('hide');
+    }
+  }),
+
+  actions: {
+    /** close by action in the UI **/
+    close: function() {
+      this.$('.modal').modal('hide');
+    },
+
+    closeModal: function() {
+      this.$('.modal').off('hide.bs.modal');
+      this.set('isModalOpen', false);
+      this.get('modalEventBus').resetModal(this.get('name'));
+      this.send('didCloseModal');
+    },
+
+    modalOpened: function() {
+      this.send('didOpenModal');
+    },
+
+    didCloseModal: function() {},
+    didOpenModal: function() {}
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/models/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/models/.gitkeep b/contrib/views/files/src/main/resources/ui/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/models/alert.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/models/alert.js b/contrib/views/files/src/main/resources/ui/app/models/alert.js
new file mode 100644
index 0000000..74b07f9
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/models/alert.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+  type: DS.attr('string'),
+  message: DS.attr('string'),
+  responseMessage: DS.attr('string'),
+  status: DS.attr('number'),
+  trace: DS.attr('string')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/models/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/models/file.js b/contrib/views/files/src/main/resources/ui/app/models/file.js
index 0e31f71..a2ed1f3 100644
--- a/contrib/views/files/src/main/resources/ui/app/models/file.js
+++ b/contrib/views/files/src/main/resources/ui/app/models/file.js
@@ -16,36 +16,36 @@
  * limitations under the License.
  */
 
-var App = require('app');
+import DS from 'ember-data';
+import Ember from 'ember';
 
-var dsa = DS.attr;
+export default DS.Model.extend({
+
+  isDirectory                       : DS.attr('boolean'),
+  readAccess                        : DS.attr('boolean'),
+  writeAccess                       : DS.attr('boolean'),
+  executeAccess                     : DS.attr('boolean'),
+  len                               : DS.attr('number'),
+  owner                             : DS.attr('string'),
+  group                             : DS.attr('string'),
+  permission                        : DS.attr('string'),
+  accessTime                        : DS.attr('iso-date'),
+  modificationTime                  : DS.attr('iso-date'),
+  blockSize                         : DS.attr('number'),
+  replication                       : DS.attr('number'),
+  size                              : Ember.computed.alias('len'),
 
-App.File = DS.Model.extend({
   path: function() {
     return this.get('id');
   }.property('id'),
-  basedir:function () {
-    var path = this.get('id');
-    return path.substring(0,path.lastIndexOf('/'))||'/';
-  }.property('id'),
-  isDirectory: dsa('boolean'),
-  readAccess: dsa('boolean'),
-  writeAccess: dsa('boolean'),
-  executeAccess: dsa('boolean'),
-  len: dsa('number'),
-  owner: dsa('string'),
-  group: dsa('string'),
-  permission: dsa('string'),
-  accessTime: dsa('isodate'),
-  modificationTime: dsa('isodate'),
-  blockSize: dsa('number'),
-  replication: dsa('number'),
-  name:function () {
-    var splitpath = this.get('path').split('/');
-    return splitpath.get(splitpath.length-1);
+
+  name: function() {
+    var splitPath = this.get('path').split('/');
+    return splitPath.get(splitPath.length - 1);
   }.property('path'),
-  date:function () {
+
+  date: function() {
     return parseInt(moment(this.get('modificationTime')).format('X'));
-  }.property('modificationTime'),
-  size: Em.computed.alias('len')
+  }.property('modificationTime')
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/router.js b/contrib/views/files/src/main/resources/ui/app/router.js
index b38ac00..801e932 100644
--- a/contrib/views/files/src/main/resources/ui/app/router.js
+++ b/contrib/views/files/src/main/resources/ui/app/router.js
@@ -16,8 +16,18 @@
  * limitations under the License.
  */
 
-App = require('app');
+import Ember from 'ember';
+import config from './config/environment';
 
-App.Router.map(function() {
-  this.route('files', { queryParams:['path'],path: '/',});
+const Router = Ember.Router.extend({
+  location: config.locationType
 });
+
+Router.map(function() {
+  this.route('files');
+  this.route('messages', function() {
+    this.route('message', {path: '/:message_id'});
+  });
+});
+
+export default Router;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/.gitkeep b/contrib/views/files/src/main/resources/ui/app/routes/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/application.js b/contrib/views/files/src/main/resources/ui/app/routes/application.js
new file mode 100644
index 0000000..eca62f4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/application.js
@@ -0,0 +1,78 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+  fileOperationService: Ember.inject.service('file-operation'),
+  model: function() {
+    var promise = {
+      homeDir: this.get('fileOperationService').getHome(),
+      trashDir:  this.get('fileOperationService').getTrash()
+    };
+
+    return Ember.RSVP.hashSettled(promise).then(function(hash) {
+      var response = {
+        homeDir: {path: '', hasError: true},
+        trashDir: {path: '', hasError: true}
+      };
+
+      if(hash.homeDir.state === 'fulfilled'){
+        response.homeDir.path = hash.homeDir.value.path;
+        response.homeDir.hasError = false;
+      }
+
+      if(hash.trashDir.state === 'fulfilled'){
+        response.trashDir.path = hash.trashDir.value.path;
+        response.trashDir.hasError = false;
+      }
+
+      return response;
+    });
+  },
+  setupController: function(controller, hash) {
+    this._super(controller, hash);
+    if(hash.homeDir.hasError === false) {
+      this.controllerFor('files').set('homePath', hash.homeDir.path);
+      this.controllerFor('files').set('hasHomePath', true);
+    }
+
+    if(hash.trashDir.hasError === false) {
+      this.controllerFor('files').set('trashPath', hash.trashDir.path);
+      this.controllerFor('files').set('hasTrashPath', true);
+    }
+  },
+
+  actions: {
+    loading(transition, route) {
+      let startTime = moment();
+      let appController = this.controllerFor('application');
+      // when the application loads up we want the loading template to be
+      // rendered and not the loading spinner in the application template
+      if(appController.get('firstLoad') === false) {
+        appController.set('isLoading', true);
+      }
+      transition.promise.finally(() => {
+        console.log("Loaded in " + (moment() - startTime) + "ms");
+        appController.set('isLoading', false);
+        appController.set('firstLoad', false);
+      });
+      return appController.get('firstLoad');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/error.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/error.js b/contrib/views/files/src/main/resources/ui/app/routes/error.js
deleted file mode 100644
index 3b71cde..0000000
--- a/contrib/views/files/src/main/resources/ui/app/routes/error.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * 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.ErrorRoute = Em.Route.extend({});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/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
deleted file mode 100644
index b64a7b1..0000000
--- a/contrib/views/files/src/main/resources/ui/app/routes/file.js
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * 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.FilesRoute = Em.Route.extend({
-  queryParams: {
-    path: {
-      refreshModel: true
-    }
-  },
-  actions:{
-    refreshDir:function () {
-      this.refresh();
-    },
-    loading:function  (argument) {
-      var target = this.controllerFor('files');
-      target.showSpinner();
-      this.router.one('didTransition', target, 'hideSpinner');
-    },
-    error:function (error,transition,e) {
-      this.controllerFor('files').set('isLoadingFiles', false);
-      if (this.router._lookupActiveView('files')) {
-        this.send('showAlert',error);
-      } else {
-        return true;
-      }
-    },
-    dirUp: function () {
-      var currentPath = this.controllerFor('files').get('path');
-      var upDir = currentPath.substring(0,currentPath.lastIndexOf('/'));
-      var target = upDir || '/';
-      return this.transitionTo('files',{queryParams: {path: target}});
-    },
-    willTransition:function (argument) {
-      var hasModal = this.router._lookupActiveView('modal.chmod'),
-          hasAlert = this.router._lookupActiveView('files.alert'),
-          hasPreviewModal = this.router._lookupActiveView('modal.preview');
-
-      Em.run.next(function(){
-        if (hasAlert) this.send('removeAlert');
-        if (hasModal) this.send('removeChmodModal');
-        if (hasPreviewModal) this.send('removePreviewModal');
-      }.bind(this));
-    },
-
-    showChmodModal:function (content) {
-      this.controllerFor('chmodModal').set('content',content);
-      this.render('modal.chmod',{
-        into:'files',
-        outlet:'modal',
-        controller:'chmodModal'
-      });
-    },
-
-    showPreviewModal :function (content) {
-      var controller = this.controllerFor('previewModal');
-      controller.set('reload', true);
-      controller.set('content',content);
-      controller.set('startIndex',0);
-
-      this.render('modal.preview',{
-        into:'files',
-        outlet:'modal',
-        controller:'previewModal'
-      });
-    },
-
-    removeChmodModal:function () {
-      this.disconnectOutlet({
-        outlet: 'modal',
-        parentView: 'files'
-      });
-    },
-    removePreviewModal:function () {
-      this.disconnectOutlet({
-        outlet: 'modal',
-        parentView: 'files'
-      });
-    },
-    showAlert:function (error) {
-      this.controllerFor('filesAlert').set('content',error);
-      this.render('files.alert',{
-        into:'files',
-        outlet:'error',
-        controller:'filesAlert'
-      });
-    },
-    removeAlert:function () {
-      this.disconnectOutlet({
-        outlet: 'error',
-        parentView: 'files'
-      });
-    }
-  },
-  model:function (params) {
-    var path = (Em.isEmpty(params.path))?'/':params.path;
-    var model = this.store.listdir(path);
-    this.set('prevModel',model);
-    return model;
-  },
-  prevModel:null,
-  beforeModel:function () {
-    if (this.get('prevModel.isPending')) {
-      this.get('prevModel').then(function (files) {
-        files.forEach(function (file) {
-          file.store.unloadRecord(file);
-        });
-      });
-    }
-  },
-  afterModel: function (model) {
-    this.store.all('file').forEach(function (file) {
-      if (!model.contains(file)) {
-        file.unloadRecord();
-      }
-    });
-  }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/files.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/files.js b/contrib/views/files/src/main/resources/ui/app/routes/files.js
new file mode 100644
index 0000000..140732f
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/files.js
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Route.extend(FileOperationMixin, {
+  logger: Ember.inject.service('alert-messages'),
+  fileSelectionService: Ember.inject.service('files-selection'),
+  currentPath: '/',
+  queryParams: {
+    path: {
+      refreshModel: true
+    }
+  },
+  model: function(params) {
+    this.store.unloadAll('file');
+    return this.store.query('file', {path: params.path});
+  },
+
+  setupController: function(controller, model) {
+    this._super(controller, model);
+    controller.set('searchText', '');
+    this.get('fileSelectionService').reset();
+    this.set('currentPath', controller.get('path'));
+  },
+
+  actions: {
+    refreshCurrentRoute: function() {
+      this.refresh();
+    },
+
+    error: function(error, transition) {
+      this.get('fileSelectionService').reset();
+      let path = transition.queryParams.path;
+      var formattedError = this.extractError(error);
+      this.get('logger').danger(`Failed to transition to <strong>${path}</strong>`, formattedError);
+      // Had to do this as we are unloading all files before transitioning
+      this.transitionTo({
+        queryParams: {
+          path: this.get('currentPath')
+        }
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/index.js b/contrib/views/files/src/main/resources/ui/app/routes/index.js
new file mode 100644
index 0000000..1032334
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/index.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+  beforeModel: function(transition) {
+    this.transitionTo('files');
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/messages.js b/contrib/views/files/src/main/resources/ui/app/routes/messages.js
new file mode 100644
index 0000000..2d94782
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/messages.js
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+  logger: Ember.inject.service('alert-messages'),
+  model: function() {
+    return this.store.peekAll('alert');
+  },
+  setupController: function(controller, model) {
+    this._super(controller, model);
+    this.get('logger').clearMessages();
+    controller.set('isExpanded', true);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js b/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js
new file mode 100644
index 0000000..84be53b
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+  model: function(params) {
+    return this.store.peekRecord('alert', params.message_id);
+  },
+
+  setupController: function(controller, model) {
+    this._super(controller, model);
+    var messagesController = this.controllerFor('messages');
+    messagesController.set('isExpanded', false);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/serializers/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/serializers/file.js b/contrib/views/files/src/main/resources/ui/app/serializers/file.js
new file mode 100644
index 0000000..3edc933
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/serializers/file.js
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.RESTSerializer.extend({
+  primaryKey: 'path'
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js b/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js
new file mode 100644
index 0000000..1a9c06d
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js
@@ -0,0 +1,126 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+
+/**
+  Shows alert flash and also creates `alert` objects in store. If creation of
+  `alert` objects in store pass `options.flashOnly` as `true`. The options
+  required for creating the `alert` objects are:
+  ```
+    options.message: message field returned by the API server.
+    options.status : Status XHR request if the message is a response to XHR request. Defaults to -1.
+    options.error: Detailed error to be displayed.
+  ```
+  Options required for ember-cli-flash can also be passed in the alertOptions to override the
+  default behaviour.
+*/
+export default Ember.Service.extend({
+  flashMessages: Ember.inject.service('flash-messages'),
+  store: Ember.inject.service('store'),
+
+  success: function(message, options = {}, alertOptions = {}) {
+    this._processMessage('success', message, options, alertOptions);
+  },
+
+  warn: function(message, options = {}, alertOptions = {}) {
+    this._processMessage('warn', message, options, alertOptions);
+  },
+
+  info: function(message, options = {}, alertOptions = {}) {
+    this._processMessage('info', message, options, alertOptions);
+  },
+
+  danger: function(message, options = {}, alertOptions = {}) {
+    this._processMessage('danger', message, options, alertOptions);
+  },
+
+  clearMessages: function() {
+    this.get('flashMessages').clearMessages();
+  },
+
+  _processMessage: function(type, message, options, alertOptions) {
+    this._clearMessagesIfRequired(alertOptions);
+    let alertRecord = this._createAlert(message, type, options, alertOptions);
+    if(alertRecord) {
+      message = this._addDetailsToMessage(message, alertRecord);
+    }
+    switch (type) {
+      case 'success':
+        this.get('flashMessages').success(message, this._getOptions(alertOptions));
+        break;
+      case 'warn':
+        this.get('flashMessages').warning(message, this._getOptions(alertOptions));
+        break;
+      case 'info':
+        this.get('flashMessages').info(message, this._getOptions(alertOptions));
+        break;
+      case 'danger':
+        this.get('flashMessages').danger(message, this._getOptions(alertOptions));
+    }
+  },
+
+  _addDetailsToMessage: function(message, record) {
+    let id = record.get('id');
+    let suffix = `<a href="#/messages/${id}">(details)</a>`;
+    return message + "  " + suffix;
+  },
+
+  _createAlert: function(message, type, options, alertOptions) {
+    var data = {};
+    data.message = message;
+    data.responseMessage = options.message || '';
+    data.id = this._getNextAlertId();
+    data.type = type;
+    data.status = options.status || -1;
+    data.trace = this._getDetailedError(options.trace);
+    delete options.status;
+    delete options.error;
+
+    if(alertOptions.flashOnly === true) {
+      return;
+    }
+
+    return this.get('store').createRecord('alert', data);
+  },
+
+  _getDetailedError: function(error) {
+    return error || '';
+  },
+
+  _getOptions: function(options = {}) {
+    var defaultOptions = {
+      priority: 100,
+      showProgress: true,
+      timeout: 6000
+    };
+    return Ember.merge(defaultOptions, options);
+  },
+
+  _getNextAlertId: function() {
+    return this.get('store').peekAll('alert').get('length') + 1;
+  },
+
+  _clearMessagesIfRequired: function(options = {}) {
+    var stackMessages = options.stackMessages || false;
+    if(stackMessages !== true) {
+      this.clearMessages();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/file-copy.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/file-copy.js b/contrib/views/files/src/main/resources/ui/app/services/file-copy.js
new file mode 100644
index 0000000..7193177
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/file-copy.js
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Service.extend(FileOperationMixin, {
+  logger: Ember.inject.service('alert-messages'),
+
+  // Returns a promise for the operation. Upon sucess or error, this also
+  // appropriately sends error messages.
+
+  copy: function (srcPath, destName) {
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      var adapter = this.get('store').adapterFor('file');
+      var baseURL = adapter.buildURL('file');
+      var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/copy";
+      var data = {sourcePaths: srcPath, destinationPath: destName};
+      adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+        this.get('logger').success(`Successfully copied to ${destName}.`, {}, {flashOnly: true});
+        resolve(response);
+      }, (responseError) => {
+        var error = this.extractError(responseError);
+        this.get('logger').danger(`Failed to copy to ${destName}`, error);
+        reject(error);
+      });
+    });
+  },
+
+  _isDestinationPathExists(destinationPath) {
+    return this.get('store').peekAll('file').isAny('path', destinationPath);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/file-move.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/file-move.js b/contrib/views/files/src/main/resources/ui/app/services/file-move.js
new file mode 100644
index 0000000..859f04c
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/file-move.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.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Service.extend(FileOperationMixin, {
+  logger: Ember.inject.service('alert-messages'),
+
+  // Returns a promise for the operation. Upon sucess or error, this also
+  // appropriately sends error messages.
+  move: function(srcPath, destName ) {
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      var adapter = this.get('store').adapterFor('file');
+      var baseURL = adapter.buildURL('file');
+      var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/move";
+      var data = {sourcePaths: srcPath, destinationPath: destName};
+      adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+        this.get('logger').success(`Successfully moved to ${destName}.`, {}, {flashOnly: true});
+        resolve(response);
+      }, (responseError) => {
+        var error = this.extractError(responseError);
+        this.get('logger').danger(`Failed to move to ${destName}`, error);
+        reject(error);
+      });
+    });
+  },
+
+  _isDestinationPathExists(destinationPath) {
+    return this.get('store').peekAll('file').isAny('path', destinationPath);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/file-operation.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/file-operation.js b/contrib/views/files/src/main/resources/ui/app/services/file-operation.js
new file mode 100644
index 0000000..abb3000
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/file-operation.js
@@ -0,0 +1,199 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Service.extend(FileOperationMixin, {
+  logger: Ember.inject.service('alert-messages'),
+  chmod: function (path, permission) {
+    var adapter = this.get('store').adapterFor('file');
+    var data = {mode: permission, path: path};
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      adapter.ajax(this._getFileOperationUrl('chmod'), "POST", {data: data}).then(
+        (response) => {
+          this.get('logger').success(`Successfully changed permission of ${path}`, {}, {flashOnly: false});
+          return resolve(response);
+        }, (responseError) => {
+          var error = this.extractError(responseError);
+          this.get('logger').danger(`Failed to modify permission of ${path}`, error);
+          return reject(error);
+        });
+    });
+  },
+
+  createNewFolder: function (srcPath, folderName) {
+    var path = (srcPath === '/') ? '' : srcPath;
+
+    if (folderName.slice(0, 1) === '/') {
+      folderName = folderName.slice(0, folderName.length);
+    }
+    var adapter = this.get('store').adapterFor('file');
+    var data = {path: `${path}/${folderName}`};
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      adapter.ajax(this._getFileOperationUrl('mkdir'), "PUT", {data: data}).then(
+        (response) => {
+          this.get('logger').success(`Successfully created <strong>${path}/${folderName}`, {flashOnly: true});
+          return resolve(response);
+        }, (responseError) => {
+          var error = this.extractError(responseError);
+          this.get('logger').danger(`Failed to create ${path}/${folderName}`, error);
+          return reject(error);
+        });
+    });
+  },
+
+  deletePaths: function (paths, deletePermanently = false) {
+    var opsUrl;
+    if (deletePermanently) {
+      opsUrl = this._getFileOperationUrl('remove');
+    } else {
+      opsUrl = this._getFileOperationUrl('moveToTrash');
+    }
+    var data = {
+      paths: paths.map((path) => {
+        return {path: path, recursive: true};
+      })
+    };
+    var adapter = this.get('store').adapterFor('file');
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      adapter.ajax(opsUrl, "DELETE", {data: data}).then(
+        (response) => {
+          return resolve(response);
+        }, (rejectResponse) => {
+          var error = this.extractError(rejectResponse);
+          if (this.isInvalidError(error)) {
+            return reject(this._prepareUnprocessableErrorResponse(error));
+          } else {
+            return reject(Ember.merge({retry: false, unprocessable: false}, error));
+          }
+        });
+    });
+  },
+
+  listPath: function (queryPath, onlyDirectory = true) {
+    let baseUrl = this._getFileOperationUrl('listdir');
+    let url = `${baseUrl}?${queryPath}`;
+    var adapter = this.get('store').adapterFor('file');
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      adapter.ajax(url, "GET").then(
+        (response) => {
+          if (onlyDirectory) {
+            return resolve(response.files.filter((entry) => {
+              return entry.isDirectory;
+            }));
+          } else {
+            return resolve(response.files);
+          }
+        }, (responseError) => {
+          var error = this.extractError(responseError);
+          return reject(error);
+        });
+    });
+  },
+
+  movePaths: function (srcPath, destName) {
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      var adapter = this.get('store').adapterFor('file');
+      var baseURL = adapter.buildURL('file');
+      var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/move";
+      var data = {sourcePaths: srcPath, destinationPath: destName};
+      adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+        this.get('logger').success(`Successfully moved to ${destName}.`, {}, {flashOnly: true});
+        resolve(response);
+      }, (rejectResponse) => {
+        var error = this.extractError(rejectResponse);
+        if (this.isInvalidError(error)) {
+          return reject(this._prepareUnprocessableErrorResponse(error));
+        } else {
+          return reject(Ember.merge({retry: false, unprocessable: false}, error));
+        }
+      });
+    });
+  },
+
+  copyPaths: function (srcPath, destName) {
+    return new Ember.RSVP.Promise((resolve, reject) => {
+      var adapter = this.get('store').adapterFor('file');
+      var baseURL = adapter.buildURL('file');
+      var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/copy";
+      var data = {sourcePaths: srcPath, destinationPath: destName};
+      adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+        this.get('logger').success(`Successfully copied to ${destName}.`, {}, {flashOnly: true});
+        resolve(response);
+      }, (rejectResponse) => {
+        var error = this.extractError(rejectResponse);
+        if (this.isInvalidError(error)) {
+          return reject(this._prepareUnprocessableErrorResponse(error));
+        } else {
+          return reject(Ember.merge({retry: false, unprocessable: false}, error));
+        }
+      });
+    });
+  },
+
+  _checkIfDeleteRetryIsRequired: function (error) {
+    return error.unprocessed.length >= 1;
+  },
+
+  _prepareUnprocessableErrorResponse: function (error) {
+    var response = {};
+    response.unprocessable = true;
+    if (this._checkIfDeleteRetryIsRequired(error)) {
+      response.retry = true;
+      response.failed = error.failed[0];
+      response.message = error.message;
+      response.unprocessed = error.unprocessed;
+    } else {
+      response.retry = false;
+      response.failed = error.failed[0];
+      response.message = error.message;
+    }
+
+    return response;
+  },
+
+  getHome: function () {
+    var adapter = this.get('store').adapterFor('file');
+    return adapter.ajax(this._getMiscUrl("/help/home"), "GET");
+  },
+
+  getTrash: function () {
+    var adapter = this.get('store').adapterFor('file');
+    return adapter.ajax(this._getMiscUrl("/help/trashDir"), "GET");
+  },
+
+  _getMiscUrl: function (segment) {
+    var urlFragments = this._getBaseURLFragments();
+    return urlFragments.slice(0, urlFragments.length - 2).join('/') + segment;
+  },
+
+  getUploadUrl: function () {
+    return this._getMiscUrl("/upload");
+  },
+
+  _getFileOperationUrl: function (pathFragment) {
+    var adapter = this.get('store').adapterFor('file');
+    var baseURL = adapter.buildURL('file');
+    return baseURL.substring(0, baseURL.lastIndexOf('/')) + `/${pathFragment}`;
+  },
+
+  isExistsInCurrentPath: function (name) {
+    return this.get('store').peekAll('file').isAny('name', name);
+  }
+});