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:08 UTC

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

AMBARI-15145. Revamped Filebrowser Design - UI. (dipayanb)


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

Branch: refs/heads/trunk
Commit: b988562aa75531aef5f77ec5ee02d22bbb13fe07
Parents: db999ae
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Wed Feb 24 23:47:02 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Wed Feb 24 23:47:02 2016 +0530

----------------------------------------------------------------------
 contrib/views/files/pom.xml                     |   72 +-
 .../view/filebrowser/FileOperationService.java  |  250 +-
 .../ambari/view/filebrowser/HdfsService.java    |   23 +-
 .../ambari/view/filebrowser/HelpService.java    |    2 +-
 .../views/files/src/main/resources/ui/.bowerrc  |    4 +
 .../files/src/main/resources/ui/.editorconfig   |   34 +
 .../files/src/main/resources/ui/.ember-cli      |   27 +
 .../files/src/main/resources/ui/.gitignore      |   35 +-
 .../views/files/src/main/resources/ui/.jshintrc |   33 +
 .../files/src/main/resources/ui/.travis.yml     |   39 +
 .../files/src/main/resources/ui/.watchmanconfig |   20 +
 .../views/files/src/main/resources/ui/README.md |   68 +
 .../files/src/main/resources/ui/app/adapter.js  |  419 ---
 .../resources/ui/app/adapters/application.js    |   38 +
 .../src/main/resources/ui/app/adapters/file.js  |   66 +
 .../files/src/main/resources/ui/app/app.js      |   19 +-
 .../ui/app/assets/fonts/fontawesome-webfont.eot |  Bin 38205 -> 0 bytes
 .../ui/app/assets/fonts/fontawesome-webfont.svg |  414 ---
 .../ui/app/assets/fonts/fontawesome-webfont.ttf |  Bin 80652 -> 0 bytes
 .../app/assets/fonts/fontawesome-webfont.woff   |  Bin 44432 -> 0 bytes
 .../fonts/glyphicons-halflings-regular.eot      |  Bin 20290 -> 0 bytes
 .../fonts/glyphicons-halflings-regular.svg      |  229 --
 .../fonts/glyphicons-halflings-regular.ttf      |  Bin 41236 -> 0 bytes
 .../fonts/glyphicons-halflings-regular.woff     |  Bin 23292 -> 0 bytes
 .../src/main/resources/ui/app/assets/index.html |   34 -
 .../ui/app/assets/javascripts/ember-qunit.js    |  266 --
 .../ui/app/assets/javascripts/jquery.mockjax.js |  692 -----
 .../assets/javascripts/modernizr-2.6.2.min.js   |    4 -
 .../ui/app/assets/javascripts/qunit.js          | 2495 ------------------
 .../ui/app/assets/javascripts/tests.js          |   29 -
 .../ui/app/assets/stylesheets/qunit.css         |  237 --
 .../src/main/resources/ui/app/assets/tests.html |   46 -
 .../main/resources/ui/app/components/.gitkeep   |    0
 .../ui/app/components/alert-message-display.js  |   45 +
 .../ui/app/components/alert-message.js          |   32 +
 .../resources/ui/app/components/breadCrumbs.js  |   47 -
 .../resources/ui/app/components/bsPopover.js    |   21 -
 .../resources/ui/app/components/bulkCheckbox.js |   29 -
 .../ui/app/components/confirmDelete.js          |   65 -
 .../ui/app/components/context-row-menu.js       |  137 +
 .../resources/ui/app/components/contextMenu.js  |   42 -
 .../resources/ui/app/components/copy-modal.js   |  126 +
 .../resources/ui/app/components/delete-modal.js |  130 +
 .../ui/app/components/directory-viewer.js       |  165 ++
 .../resources/ui/app/components/file-row.js     |   37 +
 .../resources/ui/app/components/file-search.js  |   42 +
 .../ui/app/components/files-breadcrumb.js       |   69 +
 .../ui/app/components/files-collection.js       |   98 +
 .../resources/ui/app/components/mkdirInput.js   |   50 -
 .../resources/ui/app/components/move-modal.js   |  126 +
 .../ui/app/components/new-directory.js          |   75 +
 .../ui/app/components/open-preview-modal.js     |   56 +
 .../ui/app/components/permission-modal.js       |  116 +
 .../ui/app/components/popoverDelete.js          |   68 -
 .../resources/ui/app/components/rename-modal.js |   77 +
 .../resources/ui/app/components/renameInput.js  |   92 -
 .../resources/ui/app/components/sortArrow.js    |   34 -
 .../ui/app/components/toggleContext.js          |   79 -
 .../resources/ui/app/components/upload-file.js  |   92 +
 .../resources/ui/app/components/uploader.js     |  111 -
 .../resources/ui/app/config/files-columns.js    |   73 +
 .../main/resources/ui/app/controllers/.gitkeep  |    0
 .../resources/ui/app/controllers/application.js |   24 +
 .../resources/ui/app/controllers/chmodModal.js  |   49 -
 .../main/resources/ui/app/controllers/error.js  |   49 -
 .../main/resources/ui/app/controllers/file.js   |  117 -
 .../main/resources/ui/app/controllers/files.js  |  299 +--
 .../resources/ui/app/controllers/filesAlert.js  |   32 -
 .../resources/ui/app/controllers/messages.js    |   32 +
 .../ui/app/controllers/messages/message.js      |   31 +
 .../ui/app/controllers/previewModal.js          |   91 -
 .../src/main/resources/ui/app/helpers/.gitkeep  |    0
 .../app/helpers/alert-message-context-class.js  |   27 +
 .../ui/app/helpers/alert-message-icon-class.js  |   37 +
 .../ui/app/helpers/get-sorting-icon.js          |   34 +
 .../ui/app/helpers/get-value-from-columns.js    |   34 +
 .../resources/ui/app/helpers/shorten-text.js    |   32 +
 .../main/resources/ui/app/helpers/show-date.js  |   27 +
 .../resources/ui/app/helpers/size-humanize.js   |   33 +
 .../ui/app/helpers/string-capitalize.js         |   25 +
 .../files/src/main/resources/ui/app/index.html  |   42 +
 .../src/main/resources/ui/app/initialize.js     |   99 -
 .../resources/ui/app/mixins/file-operation.js   |   57 +
 .../resources/ui/app/mixins/operation-modal.js  |   82 +
 .../src/main/resources/ui/app/models/.gitkeep   |    0
 .../src/main/resources/ui/app/models/alert.js   |   27 +
 .../src/main/resources/ui/app/models/file.js    |   50 +-
 .../files/src/main/resources/ui/app/router.js   |   16 +-
 .../src/main/resources/ui/app/routes/.gitkeep   |    0
 .../main/resources/ui/app/routes/application.js |   78 +
 .../src/main/resources/ui/app/routes/error.js   |   21 -
 .../src/main/resources/ui/app/routes/file.js    |  134 -
 .../src/main/resources/ui/app/routes/files.js   |   61 +
 .../src/main/resources/ui/app/routes/index.js   |   25 +
 .../main/resources/ui/app/routes/messages.js    |   31 +
 .../resources/ui/app/routes/messages/message.js |   31 +
 .../main/resources/ui/app/serializers/file.js   |   23 +
 .../resources/ui/app/services/alert-messages.js |  126 +
 .../main/resources/ui/app/services/file-copy.js |   48 +
 .../main/resources/ui/app/services/file-move.js |   47 +
 .../resources/ui/app/services/file-operation.js |  199 ++
 .../resources/ui/app/services/file-preview.js   |  119 +
 .../resources/ui/app/services/file-rename.js    |   54 +
 .../resources/ui/app/services/files-download.js |  157 ++
 .../ui/app/services/files-selection.js          |   64 +
 .../ui/app/services/modal-event-bus.js          |   48 +
 .../src/main/resources/ui/app/styles/app.less   |  188 ++
 .../resources/ui/app/styles/application.less    |  388 ---
 .../resources/ui/app/templates/application.hbs  |   48 +-
 .../ui/app/templates/components/.gitkeep        |    0
 .../components/alert-message-display.hbs        |   34 +
 .../app/templates/components/alert-message.hbs  |   34 +
 .../ui/app/templates/components/chmodInput.hbs  |  100 -
 .../templates/components/context-row-menu.hbs   |   39 +
 .../ui/app/templates/components/contextMenu.hbs |   43 -
 .../ui/app/templates/components/copy-modal.hbs  |   87 +
 .../app/templates/components/delete-modal.hbs   |   69 +
 .../ui/app/templates/components/deleteBulk.hbs  |   46 -
 .../app/templates/components/deletePopover.hbs  |   38 -
 .../templates/components/directory-viewer.hbs   |   17 +
 .../ui/app/templates/components/file-row.hbs    |   46 +
 .../ui/app/templates/components/file-search.hbs |   20 +
 .../templates/components/files-breadcrumb.hbs   |   42 +
 .../templates/components/files-collection.hbs   |   53 +
 .../ui/app/templates/components/mkdirInput.hbs  |   37 -
 .../ui/app/templates/components/move-modal.hbs  |   87 +
 .../app/templates/components/new-directory.hbs  |   48 +
 .../templates/components/open-preview-modal.hbs |   38 +
 .../templates/components/permission-modal.hbs   |   69 +
 .../app/templates/components/rename-modal.hbs   |   50 +
 .../ui/app/templates/components/renameInput.hbs |   38 -
 .../ui/app/templates/components/upload-file.hbs |   56 +
 .../ui/app/templates/components/uploader.hbs    |   35 -
 .../main/resources/ui/app/templates/error.hbs   |   32 -
 .../main/resources/ui/app/templates/files.hbs   |  293 +-
 .../main/resources/ui/app/templates/index.hbs   |   18 -
 .../main/resources/ui/app/templates/loading.hbs |   25 +
 .../resources/ui/app/templates/messages.hbs     |   54 +
 .../ui/app/templates/messages/message.hbs       |   48 +
 .../resources/ui/app/templates/modal/chmod.hbs  |   97 -
 .../ui/app/templates/modal/preview.hbs          |   33 -
 .../ui/app/templates/util/errorRow.hbs          |   32 -
 .../resources/ui/app/templates/util/fileRow.hbs |   79 -
 .../resources/ui/app/transforms/iso-date.js     |   35 +
 .../resources/ui/app/utils/file-uploader.js     |   32 +
 .../src/main/resources/ui/app/views/file.js     |   33 -
 .../src/main/resources/ui/app/views/files.js    |   32 -
 .../main/resources/ui/app/views/filesAlert.js   |   23 -
 .../main/resources/ui/app/views/modalChmod.js   |   50 -
 .../main/resources/ui/app/views/modalPreview.js |   51 -
 .../files/src/main/resources/ui/bower.json      |   43 +-
 .../files/src/main/resources/ui/config.coffee   |   53 -
 .../src/main/resources/ui/config/environment.js |   69 +
 .../src/main/resources/ui/ember-cli-build.js    |   68 +
 .../ui/generators/collection/collection.js.hbs  |   23 -
 .../ui/generators/collection/generator.json     |    9 -
 .../ui/generators/controller/controller.js.hbs  |   23 -
 .../ui/generators/controller/generator.json     |    9 -
 .../ui/generators/model/generator.json          |    9 -
 .../resources/ui/generators/model/model.js.hbs  |   23 -
 .../ui/generators/route/generator.json          |    9 -
 .../resources/ui/generators/route/route.js.hbs  |   25 -
 .../ui/generators/template/generator.json       |    9 -
 .../ui/generators/template/template.hbs.hbs     |   18 -
 .../resources/ui/generators/view/generator.json |    9 -
 .../resources/ui/generators/view/view.js.hbs    |   23 -
 .../files/src/main/resources/ui/package.json    |   78 +-
 .../views/files/src/main/resources/ui/runner.js |  136 -
 .../ui/test/unit/controllers/files_test.js      |   32 -
 .../files/src/main/resources/ui/testem.json     |   12 +
 .../files/src/main/resources/ui/tests/.jshintrc |   52 +
 .../resources/ui/tests/helpers/destroy-app.js   |   23 +
 .../resources/ui/tests/helpers/flash-message.js |   24 +
 .../ui/tests/helpers/module-for-acceptance.js   |   41 +
 .../main/resources/ui/tests/helpers/resolver.js |   29 +
 .../resources/ui/tests/helpers/start-app.js     |   36 +
 .../src/main/resources/ui/tests/index.html      |   52 +
 .../resources/ui/tests/integration/.gitkeep     |    0
 .../src/main/resources/ui/tests/test-helper.js  |   26 +
 .../src/main/resources/ui/tests/unit/.gitkeep   |    0
 .../files/src/main/resources/ui/vendor/.gitkeep |    0
 .../main/resources/ui/vendor/js/bsPopover.js    |  190 --
 .../resources/ui/vendor/js/ember-cloaking.js    |  436 ---
 183 files changed, 5719 insertions(+), 8928 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/files/pom.xml b/contrib/views/files/pom.xml
index 09d3abd..ccdd281 100644
--- a/contrib/views/files/pom.xml
+++ b/contrib/views/files/pom.xml
@@ -132,47 +132,44 @@
               <directory>${ui.directory}</directory>
               <followSymlinks>false</followSymlinks>
               <includes>
-                <include>public/**</include>
+                <include>tmp/**</include>
+                <!--
                 <include>node_modules/**</include>
                 <include>bower_components/**</include>
+                -->
                 <include>node/**</include>
               </includes>
             </fileset>
           </filesets>
         </configuration>
       </plugin>
+
+      <!-- Building frontend -->
       <plugin>
         <groupId>com.github.eirslett</groupId>
         <artifactId>frontend-maven-plugin</artifactId>
         <version>0.0.16</version>
         <configuration>
-          <workingDirectory>${ui.directory}</workingDirectory>
+          <nodeVersion>v0.12.2</nodeVersion>
+          <npmVersion>1.4.8</npmVersion>
+          <workingDirectory>src/main/resources/ui/</workingDirectory>
         </configuration>
-
         <executions>
           <execution>
             <id>install node and npm</id>
+            <phase>generate-sources</phase>
             <goals>
               <goal>install-node-and-npm</goal>
             </goals>
-            <!-- optional: default phase is "generate-resources" -->
-            <phase>initialize</phase>
-            <configuration>
-              <nodeVersion>v0.10.26</nodeVersion>
-              <npmVersion>1.4.3</npmVersion>
-            </configuration>
           </execution>
           <execution>
             <id>npm install</id>
+            <phase>generate-sources</phase>
             <goals>
               <goal>npm</goal>
             </goals>
-            <phase>generate-resources</phase>
             <configuration>
-              <!-- optional: The default argument is actually "install", so unless
-               you need to run some other npm command, you can remove this whole <configuration>
-               section. -->
-              <arguments>install --unsafe-perm</arguments>
+              <arguments>install --python="${project.basedir}/../src/main/unix/ambari-python-wrap" --unsafe-perm</arguments>
             </configuration>
           </execution>
         </executions>
@@ -180,52 +177,21 @@
       <plugin>
         <artifactId>exec-maven-plugin</artifactId>
         <groupId>org.codehaus.mojo</groupId>
-        <version>1.2.1</version>
+        <version>1.3.2</version>
         <executions>
           <execution>
-            <id>node gyp executable</id>
-            <phase>initialize</phase>
-            <goals>
-              <goal>exec</goal>
-            </goals>
-            <configuration>
-              <skip>${skip.nodegyp.chmod}</skip>
-              <workingDirectory>${ui.directory}</workingDirectory>
-              <executable>chmod</executable>
-              <arguments>
-                <argument>+x</argument>
-                <argument>${ui.directory}/node/npm/bin/node-gyp-bin/node-gyp</argument>
-              </arguments>
-            </configuration>
-          </execution>
-          <execution>
-            <id>Bower install</id>
-            <phase>generate-resources</phase>
-            <goals>
-              <goal>exec</goal>
-            </goals>
-            <configuration>
-              <workingDirectory>${ui.directory}</workingDirectory>
-              <executable>${ui.directory}/node/${node.executable}</executable>
-              <arguments>
-                <argument>${ui.directory}/node_modules/bower/bin/bower</argument>
-                <argument>install</argument>
-                <argument>--allow-root</argument>
-              </arguments>
-            </configuration>
-          </execution>
-          <execution>
-            <id>Brunch build</id>
-            <phase>generate-resources</phase>
+            <id>Files build</id>
+            <phase>generate-sources</phase>
             <goals>
               <goal>exec</goal>
             </goals>
             <configuration>
-              <workingDirectory>${ui.directory}</workingDirectory>
-              <executable>${ui.directory}/node/${node.executable}</executable>
+              <workingDirectory>${basedir}/src/main/resources/ui</workingDirectory>
+              <executable>node/node</executable>
               <arguments>
-                <argument>node_modules/brunch/bin/brunch</argument>
+                <argument>node_modules/.bin/ember</argument>
                 <argument>build</argument>
+                <argument>--environment=production</argument>
               </arguments>
             </configuration>
           </execution>
@@ -266,7 +232,7 @@
     </plugins>
     <resources>
       <resource>
-        <directory>src/main/resources/ui/public</directory>
+        <directory>src/main/resources/ui/dist</directory>
         <filtering>false</filtering>
       </resource>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/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 973fb8f..a0793ac 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
@@ -19,6 +19,10 @@
 package org.apache.ambari.view.filebrowser;
 
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
 
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
@@ -90,7 +94,7 @@ public class FileOperationService extends HdfsService {
         result = Response.ok(getApi(context).fileStatusToJSON(api
             .getFileStatus(request.dst)));
       } else {
-        result = Response.ok(new BoolResult(false, "Can't move '" + request.src + "' to '" + request.dst + "'")).status(422);
+        result = Response.ok(new FileOperationResult(false, "Can't move '" + request.src + "' to '" + request.dst + "'")).status(422);
       }
       return result.build();
     } catch (WebApplicationException ex) {
@@ -117,7 +121,7 @@ public class FileOperationService extends HdfsService {
         result = Response.ok(getApi(context).fileStatusToJSON(api
             .getFileStatus(request.path)));
       } else {
-        result = Response.ok(new BoolResult(false, "Can't chmod '" + request.path + "'")).status(422);
+        result = Response.ok(new FileOperationResult(false, "Can't chmod '" + request.path + "'")).status(422);
       }
       return result.build();
     } catch (WebApplicationException ex) {
@@ -133,26 +137,99 @@ public class FileOperationService extends HdfsService {
    * @return response with success
    */
   @POST
+  @Path("/move")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response move(final MultiSrcDstFileRequest request,
+                       @Context HttpHeaders headers, @Context UriInfo ui) {
+    try {
+      HdfsApi api = getApi(context);
+      ResponseBuilder result;
+      String message = "";
+
+      List<String> sources = request.sourcePaths;
+      String destination = request.destinationPath;
+      if(sources.isEmpty()) {
+        result = Response.ok(new FileOperationResult(false, "Can't move 0 file/folder to '" + destination + "'")).
+          status(422);
+        return result.build();
+      }
+
+      int index = 0;
+      for (String src : sources) {
+        String fileName = getFileName(src);
+        String finalDestination = getDestination(destination, fileName);
+        try {
+          if (api.rename(src, finalDestination)) {
+            index ++;
+          } else {
+            message = "Failed to move '" + src + "' to '" + finalDestination + "'";
+            break;
+          }
+        } catch (IOException exception) {
+          message = exception.getMessage();
+          logger.error("Failed to move '{}' to '{}'. Exception: {}", src, finalDestination,
+            exception.getMessage());
+          break;
+        }
+      }
+      if (index == sources.size()) {
+        result = Response.ok(new FileOperationResult(true)).status(200);
+      } else {
+        FileOperationResult errorResult = getFailureFileOperationResult(sources, index, message);
+        result = Response.ok(errorResult).status(422);
+      }
+      return result.build();
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Copy file
+   * @param request source and destination request
+   * @return response with success
+   */
+  @POST
   @Path("/copy")
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response copy(final SrcDstFileRequest request,
+  public Response copy(final MultiSrcDstFileRequest request,
                        @Context HttpHeaders headers, @Context UriInfo ui) {
     try {
       HdfsApi api = getApi(context);
       ResponseBuilder result;
-      try {
-        api.copy(request.src, request.dst);
+      String message = "";
 
-        result = Response.ok(getApi(context).fileStatusToJSON(api
-            .getFileStatus(request.dst)));
-      } catch (HdfsApiException e) {
-        result = Response.ok(new BoolResult(false, "Can't copy '" + request.src + "' to '" + request.dst + "'")).
-            status(422);
+      List<String> sources = request.sourcePaths;
+      String destination = request.destinationPath;
+      if(sources.isEmpty()) {
+        result = Response.ok(new FileOperationResult(false, "Can't copy 0 file/folder to '" + destination + "'")).
+          status(422);
+        return result.build();
+      }
+
+      int index = 0;
+      for (String src : sources) {
+        String fileName = getFileName(src);
+        String finalDestination = getDestination(destination, fileName);
+        try {
+          api.copy(src, finalDestination);
+          index ++;
+        } catch (IOException|HdfsApiException exception) {
+          message = exception.getMessage();
+          logger.error("Failed to copy '{}' to '{}'. Exception: {}", src, finalDestination,
+            exception.getMessage());
+          break;
+        }
+      }
+      if (index == sources.size()) {
+        result = Response.ok(new FileOperationResult(true)).status(200);
+      } else {
+        FileOperationResult errorResult = getFailureFileOperationResult(sources, index, message);
+        result = Response.ok(errorResult).status(422);
       }
       return result.build();
-    } catch (WebApplicationException ex) {
-      throw ex;
     } catch (Exception ex) {
       throw new ServiceFormattedException(ex.getMessage(), ex);
     }
@@ -173,7 +250,7 @@ public class FileOperationService extends HdfsService {
       if (api.mkdir(request.path)) {
         result = Response.ok(getApi(context).fileStatusToJSON(api.getFileStatus(request.path)));
       } else {
-        result = Response.ok(new BoolResult(false, "Can't create dir '" + request.path + "'")).status(422);
+        result = Response.ok(new FileOperationResult(false, "Can't create dir '" + request.path + "'")).status(422);
       }
       return result.build();
     } catch (WebApplicationException ex) {
@@ -194,7 +271,7 @@ public class FileOperationService extends HdfsService {
     try {
       HdfsApi api = getApi(context);
       api.emptyTrash();
-      return Response.ok(new BoolResult(true)).build();
+      return Response.ok(new FileOperationResult(true)).build();
     } catch (WebApplicationException ex) {
       throw ex;
     } catch (Exception ex) {
@@ -211,31 +288,49 @@ public class FileOperationService extends HdfsService {
   @Path("/moveToTrash")
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response moveToTrash(RemoveRequest request) {
+  public Response moveToTrash(MultiRemoveRequest request) {
     try {
       ResponseBuilder result;
-
       HdfsApi api = getApi(context);
       String trash = api.getTrashDirPath();
+      String message = "";
 
-      if (!api.exists(trash)) {
-        if (!api.mkdir(trash)) {
-          result = Response.ok(new BoolResult(false, "Trash dir does not exists. Can't create dir for trash '" + trash + "'")).status(422);
-          return result.build();
+      if (request.paths.size() == 0) {
+        result = Response.ok(new FileOperationResult(false, "No path entries provided.")).status(422);
+      } else {
+        if (!api.exists(trash)) {
+          if (!api.mkdir(trash)) {
+            result = Response.ok(new FileOperationResult(false, "Trash dir does not exists. Can't create dir for " +
+              "trash '" + trash + "'")).status(422);
+            return result.build();
+          }
         }
-      }
 
-      String trashFilePath = api.getTrashDirPath(request.path);
-
-      if (api.rename(request.path, trashFilePath)) {
-        result = Response.ok(getApi(context).fileStatusToJSON(api
-            .getFileStatus(trashFilePath)));
-      } else {
-        result = Response.ok(new BoolResult(false, "Can't move file to '" + trashFilePath + "'")).status(422);
+        int index = 0;
+        for (MultiRemoveRequest.PathEntry entry : request.paths) {
+          String trashFilePath = api.getTrashDirPath(entry.path);
+          try {
+            if (api.rename(entry.path, trashFilePath)) {
+              index ++;
+            } else {
+              message = "Failed to move '" + entry.path + "' to '" + trashFilePath + "'";
+              break;
+            }
+          } catch (IOException exception) {
+            message = exception.getMessage();
+            logger.error("Failed to move '{}' to '{}'. Exception: {}", entry.path, trashFilePath,
+              exception.getMessage());
+            break;
+          }
+        }
+        if (index == request.paths.size()) {
+          result = Response.ok(new FileOperationResult(true)).status(200);
+        } else {
+          FileOperationResult errorResult = getFailureFileOperationResult(getPathsFromPathsEntries(request.paths), index, message);
+          result = Response.ok(errorResult).status(422);
+        }
       }
       return result.build();
-    } catch (WebApplicationException ex) {
-      throw ex;
     } catch (Exception ex) {
       throw new ServiceFormattedException(ex.getMessage(), ex);
     }
@@ -250,24 +345,84 @@ public class FileOperationService extends HdfsService {
   @Path("/remove")
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
-  public Response remove(RemoveRequest request, @Context HttpHeaders headers,
+  public Response remove(MultiRemoveRequest request, @Context HttpHeaders headers,
                          @Context UriInfo ui) {
     try {
       HdfsApi api = getApi(context);
       ResponseBuilder result;
-      if (api.delete(request.path, request.recursive)) {
-        result = Response.ok(new BoolResult(true)).status(204);
+      String message = "";
+      if(request.paths.size() == 0) {
+        result = Response.ok(new FileOperationResult(false, "No path entries provided."));
       } else {
-        result = Response.ok(new BoolResult(false, "Can't remove '" + request.path + "'")).status(422);
+        int index = 0;
+        for (MultiRemoveRequest.PathEntry entry : request.paths) {
+          try {
+            if (api.delete(entry.path, entry.recursive)) {
+              index++;
+            } else {
+              message = "Failed to remove '" + entry.path + "'";
+              break;
+            }
+          } catch (IOException exception) {
+            message = exception.getMessage();
+            logger.error("Failed to remove '{}'. Exception: {}", entry.path, exception.getMessage());
+            break;
+          }
+
+        }
+        if (index == request.paths.size()) {
+          result = Response.ok(new FileOperationResult(true)).status(200);
+        } else {
+          FileOperationResult errorResult = getFailureFileOperationResult(getPathsFromPathsEntries(request.paths), index, message);
+          result = Response.ok(errorResult).status(422);
+        }
       }
       return result.build();
-    } catch (WebApplicationException ex) {
-      throw ex;
     } catch (Exception ex) {
       throw new ServiceFormattedException(ex.getMessage(), ex);
     }
   }
 
+  private List<String> getPathsFromPathsEntries(List<MultiRemoveRequest.PathEntry> paths) {
+    List<String> entries = new ArrayList<>();
+    for(MultiRemoveRequest.PathEntry path: paths) {
+      entries.add(path.path);
+    }
+    return entries;
+  }
+
+  private FileOperationResult getFailureFileOperationResult(List<String> paths, int failedIndex, String message) {
+    List<String> succeeded = new ArrayList<>();
+    List<String> unprocessed = new ArrayList<>();
+    List<String> failed = new ArrayList<>();
+    ListIterator<String> iter = paths.listIterator();
+    while (iter.hasNext()) {
+      int index = iter.nextIndex();
+      String path = iter.next();
+      if (index < failedIndex) {
+        succeeded.add(path);
+      } else if (index == failedIndex) {
+        failed.add(path);
+      } else {
+        unprocessed.add(path);
+      }
+    }
+    return new FileOperationResult(false, message, succeeded, failed, unprocessed);
+  }
+
+  private String getDestination(String baseDestination, String fileName) {
+    if(baseDestination.endsWith("/")) {
+      return baseDestination + fileName;
+    } else {
+      return baseDestination + "/" + fileName;
+    }
+  }
+
+  private String getFileName(String srcPath) {
+    return srcPath.substring(srcPath.lastIndexOf('/') + 1);
+  }
+
+
   /**
    * Wrapper for json mapping of mkdir request
    */
@@ -301,12 +456,29 @@ public class FileOperationService extends HdfsService {
   }
 
   /**
+   * Wrapper for json mapping of request with multiple
+   * source and destination
+   */
+  @XmlRootElement
+  public static class MultiSrcDstFileRequest {
+    @XmlElement(nillable = false, required = true)
+    public List<String> sourcePaths = new ArrayList<>();
+    @XmlElement(nillable = false, required = true)
+    public String destinationPath;
+  }
+
+  /**
    * Wrapper for json mapping of remove request
    */
   @XmlRootElement
-  public static class RemoveRequest {
+  public static class MultiRemoveRequest {
     @XmlElement(nillable = false, required = true)
-    public String path;
-    public boolean recursive;
+    public List<PathEntry> paths = new ArrayList<>();
+    public static class PathEntry {
+      @XmlElement(nillable = false, required = true)
+      public String path;
+      public boolean recursive;
+    }
+
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsService.java
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsService.java b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsService.java
index d47304f..acaebfa 100644
--- a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsService.java
+++ b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HdfsService.java
@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -50,20 +51,32 @@ public abstract class HdfsService {
   }
 
   /**
-   * Wrapper for json mapping of bool response
+   * Wrapper for json mapping of result of Multi Remove Request
    */
   @XmlRootElement
-  public static class BoolResult{
+  public static class FileOperationResult {
     public boolean success;
     public String message;
-    public BoolResult(boolean success){
+    public List<String> succeeded;
+    public List<String> failed;
+    public List<String> unprocessed;
+
+    public FileOperationResult(boolean success) {
       this.success = success;
     }
 
-    public BoolResult(boolean success, String message){
-      this.success = success;
+    public FileOperationResult(boolean success, String message) {
+      this(success);
       this.message = message;
     }
+
+    public FileOperationResult(boolean success, String message, List<String> succeeded, List<String> failed, List<String> unprocessed) {
+      this(success, message);
+      this.succeeded = succeeded;
+      this.failed = failed;
+      this.unprocessed = unprocessed;
+    }
+
   }
 
   private HdfsApi _api = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HelpService.java
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HelpService.java b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HelpService.java
index adc99a4..4fe1d20 100644
--- a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HelpService.java
+++ b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/HelpService.java
@@ -109,7 +109,7 @@ public class HelpService extends HdfsService {
   public Response trashEnabled() {
     try {
       HdfsApi api = getApi(context);
-      return Response.ok(new BoolResult(api.trashEnabled())).build();
+      return Response.ok(new FileOperationResult(api.trashEnabled())).build();
     } catch (WebApplicationException ex) {
       throw ex;
     } catch (Exception ex) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.bowerrc
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.bowerrc b/contrib/views/files/src/main/resources/ui/.bowerrc
new file mode 100644
index 0000000..959e169
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/.bowerrc
@@ -0,0 +1,4 @@
+{
+  "directory": "bower_components",
+  "analytics": false
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.editorconfig
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.editorconfig b/contrib/views/files/src/main/resources/ui/.editorconfig
new file mode 100644
index 0000000..47c5438
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/.editorconfig
@@ -0,0 +1,34 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+
+[*.js]
+indent_style = space
+indent_size = 2
+
+[*.hbs]
+insert_final_newline = false
+indent_style = space
+indent_size = 2
+
+[*.css]
+indent_style = space
+indent_size = 2
+
+[*.html]
+indent_style = space
+indent_size = 2
+
+[*.{diff,md}]
+trim_trailing_whitespace = false

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.ember-cli
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.ember-cli b/contrib/views/files/src/main/resources/ui/.ember-cli
new file mode 100644
index 0000000..5a339b9
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/.ember-cli
@@ -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.
+ */
+
+{
+  /**
+    Ember CLI sends analytics information by default. The data is completely
+    anonymous, but there are times when you might want to disable this behavior.
+
+    Setting `disableAnalytics` to true will prevent any data from being sent.
+  */
+  "disableAnalytics": false
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.gitignore b/contrib/views/files/src/main/resources/ui/.gitignore
index 23e84db..8621d39 100644
--- a/contrib/views/files/src/main/resources/ui/.gitignore
+++ b/contrib/views/files/src/main/resources/ui/.gitignore
@@ -1,3 +1,24 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+
+# dependencies
+/node_modules
+/bower_components
+node/
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage/*
+/libpeerconnection.log
+npm-debug.log
+testem.log
+
+/.idea
+
 # Numerous always-ignore extensions
 *.diff
 *.err
@@ -16,19 +37,7 @@
 .project
 .settings
 .tmproj
+dist
 nbproject
 Thumbs.db
 
-# NPM packages folder.
-node_modules/
-
-bower_components/
-
-node/
-
-# Brunch folder for temporary files.
-tmp/
-
-public/
-
-_generators/

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.jshintrc b/contrib/views/files/src/main/resources/ui/.jshintrc
new file mode 100644
index 0000000..e75f719
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/.jshintrc
@@ -0,0 +1,33 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "-Promise",
+    "moment"
+  ],
+  "browser": true,
+  "boss": true,
+  "curly": true,
+  "debug": false,
+  "devel": true,
+  "eqeqeq": true,
+  "evil": true,
+  "forin": false,
+  "immed": false,
+  "laxbreak": false,
+  "newcap": true,
+  "noarg": true,
+  "noempty": false,
+  "nonew": false,
+  "nomen": false,
+  "onevar": false,
+  "plusplus": false,
+  "regexp": false,
+  "undef": true,
+  "sub": true,
+  "strict": false,
+  "white": false,
+  "eqnull": true,
+  "esnext": true,
+  "unused": true
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.travis.yml
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.travis.yml b/contrib/views/files/src/main/resources/ui/.travis.yml
new file mode 100644
index 0000000..4e09a70
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/.travis.yml
@@ -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.
+
+---
+language: node_js
+node_js:
+  - "0.12"
+
+sudo: false
+
+cache:
+  directories:
+    - node_modules
+
+before_install:
+  - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
+  - "npm config set spin false"
+  - "npm install -g npm@^2"
+
+install:
+  - npm install -g bower
+  - npm install
+  - bower install
+
+script:
+  - npm test

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/.watchmanconfig
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/.watchmanconfig b/contrib/views/files/src/main/resources/ui/.watchmanconfig
new file mode 100644
index 0000000..523fdd7
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/.watchmanconfig
@@ -0,0 +1,20 @@
+/**
+ * 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.
+ */
+{
+  "ignore_dirs": ["tmp", "dist"]
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/README.md
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/README.md b/contrib/views/files/src/main/resources/ui/README.md
new file mode 100644
index 0000000..1a8ad2e
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/README.md
@@ -0,0 +1,68 @@
+<!---
+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](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.
+-->
+
+# Files-view
+
+This README outlines the details of collaborating on this Ember application.
+A short introduction of this app could easily go here.
+
+## Prerequisites
+
+You will need the following things properly installed on your computer.
+
+* [Git](http://git-scm.com/)
+* [Node.js](http://nodejs.org/) (with NPM)
+* [Bower](http://bower.io/)
+* [Ember CLI](http://www.ember-cli.com/)
+* [PhantomJS](http://phantomjs.org/)
+
+## Installation
+
+* `git clone <repository-url>` this repository
+* change into the new directory
+* `npm install`
+* `bower install`
+
+## Running / Development
+
+* `ember server`
+* Visit your app at [http://localhost:4200](http://localhost:4200).
+
+### Code Generators
+
+Make use of the many generators for code, try `ember help generate` for more details
+
+### Running Tests
+
+* `ember test`
+* `ember test --server`
+
+### Building
+
+* `ember build` (development)
+* `ember build --environment production` (production)
+
+### Deploying
+
+Specify what it takes to deploy your app.
+
+## Further Reading / Useful Links
+
+* [ember.js](http://emberjs.com/)
+* [ember-cli](http://www.ember-cli.com/)
+* Development Browser Extensions
+  * [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
+  * [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/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
deleted file mode 100644
index d1d1d2c..0000000
--- a/contrib/views/files/src/main/resources/ui/app/adapter.js
+++ /dev/null
@@ -1,419 +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 = require('app');
-
-function promiseArray(promise, label) {
-  return Ember.ArrayProxy.extend(Ember.PromiseProxyMixin).create({
-    promise: Ember.RSVP.Promise.cast(promise, label)
-  });
-}
-
-
-function serializerForAdapter(adapter, type) {
-  var serializer = adapter.serializer,
-      defaultSerializer = adapter.defaultSerializer,
-      container = adapter.container;
-
-  if (container && serializer === undefined) {
-    serializer = serializerFor(container, type.typeKey, defaultSerializer);
-  }
-
-  if (serializer === null || serializer === undefined) {
-    serializer = {
-      extract: function(store, type, payload) { return payload; }
-    };
-  }
-
-  return serializer;
-}
-
-function serializerFor(container, type, defaultSerializer) {
-  return container.lookup('serializer:'+type) ||
-                 container.lookup('serializer:application') ||
-                 container.lookup('serializer:' + defaultSerializer) ||
-                 container.lookup('serializer:-default');
-}
-
-function _listdir(adapter, store, type, query, recordArray) {
-  var promise = adapter.listdir(store, type, query, recordArray),
-      serializer = serializerForAdapter(adapter, type),
-      label = "";
-
-  return Ember.RSVP.Promise.cast(promise, label).then(function(adapterPayload) {
-    var payload = serializer.extract(store, type, adapterPayload, null, 'findAll');
-
-    Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
-
-    recordArray.load(payload);
-    return recordArray;
-  }, null, "DS: Extract payload of findQuery " + type);
-}
-
-function _move(adapter, store, record, query) {
-  var type = store.modelFor('file'),
-      promise = adapter.move(store, type, record, query),
-      serializer = serializerForAdapter(adapter, type),
-      label = "";
-
-  return promise.then(function(adapterPayload) {
-    var payload;
-
-    if (adapterPayload) {
-      payload = serializer.extractSingle(store, type, adapterPayload);
-    } else {
-      payload = adapterPayload;
-    }
-
-    //TODO very shady activity :/
-    if (typeof record == 'object') {
-      store.unloadRecord(record);
-    }
-
-    return store.push('file', payload);
-  }, function(reason) {
-
-    throw reason;
-  }, label);
-}
-
-function _mkdir(adapter, store, type, query) {
-  var promise = adapter.mkdir(store, type, query),
-      serializer = serializerForAdapter(adapter, type),
-      label = "";
-
-  return promise.then(function(adapterPayload) {
-    var payload;
-
-    if (adapterPayload) {
-      payload = serializer.extractSingle(store, type, adapterPayload);
-    } else {
-      payload = adapterPayload;
-    }
-
-    return store.push('file', payload);
-  }, function(reason) {
-    throw reason;
-  }, label);
-}
-
-function _remove(adapter, store, record, query, toTrash) {
-  var type = record.constructor;
-  var method = (toTrash)?'moveToTrash':'remove';
-  var promise = adapter[method](store, type, query),
-      serializer = serializerForAdapter(adapter, type),
-      label = "";
-
-  return promise.then(function(adapterPayload) {
-    store.unloadRecord(record);
-    return record;
-  }, function(reason) {
-    if (reason instanceof DS.InvalidError) {
-      store.recordWasInvalid(record, reason.errors);
-    } else {
-      record.rollback();
-      //store.recordWasError(record, reason);
-    }
-
-    throw reason;
-  }, label);
-}
-
-Ember.Inflector.inflector.uncountable('fileops');
-Ember.Inflector.inflector.uncountable('download');
-Ember.Inflector.inflector.uncountable('upload');
-
-function getNamespaceUrl() {
-  var parts = window.location.pathname.match(/\/[^\/]*/g);
-  var view = parts[1];
-  var version = '/versions' + parts[2];
-  var instance = parts[3];
-  if (parts.length == 4) { // version is not present
-    instance = parts[2];
-    version = '';
-  }
-  return 'api/v1/views' + view + version + '/instances' + instance + '/';
-}
-
-App.ApplicationStore = DS.Store.extend({
-  adapter: DS.RESTAdapter.extend({
-    namespace: getNamespaceUrl() + 'resources/files',
-    headers: {
-      'X-Requested-By': 'ambari'
-    },
-
-    /**
-      @method ajaxOptions
-      @param {String} url
-      @param {String} type The request type GET, POST, PUT, DELETE etc.
-      @param {Object} hash
-      @return {Object} hash
-    */
-    ajaxOptions: function(url, type, options) {
-      var hash = options || {};
-      hash.url = url;
-      hash.type = type;
-      hash.dataType = 'json';
-      hash.context = this;
-
-      if (hash.data && type !== 'GET') {
-        hash.contentType = 'application/json; charset=utf-8';
-        hash.data = JSON.stringify(hash.data);
-      }
-
-      var headers = this.get('headers');
-
-      if ((navigator.userAgent.indexOf("MSIE") != -1) || (!!navigator.userAgent.match(/Trident.*rv[ :]*11\./))) {
-        headers['Cache-Control'] = 'no-cache, no-store, must-revalidate';
-        headers['Pragma'] = 'no-cache';
-        headers['Expires'] = '0';
-      }
-
-      if (headers !== undefined) {
-        hash.beforeSend = function (xhr) {
-          Ember.keys(headers).forEach(function (key) {
-            xhr.setRequestHeader(key, headers[key]);
-          });
-        };
-      }
-
-      return hash;
-    },
-    listdir: function(store, type, query) {
-      return this.ajax(this.buildURL('fileops','listdir'), 'GET', { data: query });
-    },
-    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('?');
-    },
-    linkFor:function (option, query) {
-      return this.ajax(this.buildURL('download',[option,'generate-link'].join('/')), 'POST', { data: query });
-    }
-  }),
-  listdir:function (path) {
-    var query = {path: path};
-    var type = this.modelFor('file');
-    var array = this.recordArrayManager
-      .createAdapterPopulatedRecordArray(type, query);
-    this.recordArrayManager.registerFilteredRecordArray(array, type);
-
-    var adapter = this.adapterFor(type);
-
-    Ember.assert("You tried to load a query but you have no adapter (for " + type + ")", adapter);
-    Ember.assert("You tried to load a query but your adapter does not implement `listdir`", adapter.listdir);
-
-    return promiseArray(_listdir(adapter, this, type, query, array));
-  },
-  move:function (record, path) {
-    var oldpath = (typeof record === 'string')?record:record.get('id');
-    var query = {
-      "src":oldpath,
-      "dst":path
-    };
-    var promiseLabel = "DS: Model#move " + this;
-    var resolver = Ember.RSVP.defer(promiseLabel);
-    var adapter = this.adapterFor(record.constructor);
-
-    resolver.resolve(_move(adapter, this, record, query));
-
-    return DS.PromiseObject.create({ promise: resolver.promise });
-  },
-  chmod:function (record, path) {
-    return record.save();
-  },
-  mkdir:function (path) {
-    var query = {
-      "path":path
-    };
-    var type = this.modelFor('file');
-    var promiseLabel = "DS: Model#mkdir " + this;
-    var resolver = Ember.RSVP.defer(promiseLabel);
-    var adapter = this.adapterFor(type);
-
-    resolver.resolve(_mkdir(adapter, this, type, query));
-
-    return DS.PromiseObject.create({ promise: resolver.promise });
-  },
-  remove:function (record, toTrash) {
-    var query = {
-      "path":record.get('path'),
-      "recursive":true
-    };
-    var type = this.modelFor('file');
-    var promiseLabel = "DS: Model#remove " + this;
-    var resolver = Ember.RSVP.defer(promiseLabel);
-    var adapter = this.adapterFor(type);
-
-    record.deleteRecord();
-    resolver.resolve(_remove(adapter, this, record, query, toTrash));
-
-    return DS.PromiseObject.create({ promise: resolver.promise });
-  },
-  /**
-   * get dowload link
-   * @param  {Array} files     records for download
-   * @param  {String} option            browse, zip or concat
-   * @param  {Boolean} downloadArg
-   * @return {Promise}
-   */
-  linkFor:function (files, option, downloadArg, checkperm) {
-    var resolver = Ember.RSVP.defer('promiseLabel');
-    var query, adapter = this.adapterFor(this.modelFor('file')),
-        download = downloadArg || true,
-        checkPermission = checkperm || false;
-        option = option || "browse";
-
-    if (option == 'browse') {
-      query = { "path": (files.get('firstObject.path') || files.get('id')), "download": download, "checkperm": checkPermission };
-      resolver.resolve(adapter.downloadUrl('browse',query));
-      return resolver.promise;
-    }
-
-    query = {
-      "entries": [],
-      "download": download
-    };
-
-    files.forEach(function (item) {
-      query.entries.push(item.get('path'));
-    });
-
-    resolver.resolve(adapter.linkFor(option, query));
-
-    return resolver.promise.then(function(response) {
-      return adapter.downloadUrl(option,response);
-    }, function(reason) {
-      throw reason;
-    });
-  }
-});
-
-App.FileSerializer = DS.RESTSerializer.extend({
-  primaryKey:'path',
-  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({
-  url: '',
-  type:'PUT',
-  upload: function(file,extraData) {
-    var data = this.setupFormData(file,extraData);
-    var url  = this.get('url');
-    var type = this.get('type');
-    var self = this;
-
-    this.set('isUploading', true);
-
-    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 = {
-      url: url,
-      type: method || 'POST',
-      contentType: false,
-      processData: false,
-      xhr: function() {
-        var xhr = Ember.$.ajaxSettings.xhr();
-        xhr.upload.onprogress = function(e) {
-          self.didProgress(e);
-        };
-        return xhr;
-      },
-      beforeSend:function (xhr) {
-        xhr.setRequestHeader('X-Requested-By', 'ambari');
-      },
-      data: params
-    };
-
-    return this._ajax(settings);
-  }
-});
-
-App.IsodateTransform = DS.Transform.extend({
-  deserialize: function (serialized) {
-    if (serialized) {
-      return moment.utc(serialized).toDate();
-    }
-    return serialized;
-  },
-  serialize: function (deserialized) {
-    if (deserialized) {
-      return moment(deserialized).format('X');
-    }
-    return deserialized;
-  }
-});
-
-Ember.Handlebars.registerBoundHelper('showDate', function(date,format) {
-  return moment(date).format(format);
-});
-
-Ember.Handlebars.registerBoundHelper('showDateUnix', function(date,format) {
-  return moment.unix(date).format(format);
-});
-
-Ember.Handlebars.registerBoundHelper('capitalize', function(string) {
-  return string.capitalize();
-});
-
-Ember.Handlebars.registerBoundHelper('humanSize', function(fileSizeInBytes) {
-  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];
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/adapters/application.js b/contrib/views/files/src/main/resources/ui/app/adapters/application.js
new file mode 100644
index 0000000..a7ccbf4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/adapters/application.js
@@ -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.
+ */
+
+import DS from 'ember-data';
+import Ember from 'ember';
+
+export default DS.RESTAdapter.extend({
+  namespace: Ember.computed(function() {
+    var parts = window.location.pathname.match(/\/[^\/]*/g);
+    var view = parts[1];
+    var version = '/versions' + parts[2];
+    var instance = parts[3];
+    if (parts.length === 4) { // version is not present
+      instance = parts[2];
+      version = '';
+    }
+    return 'api/v1/views' + view + version + '/instances' + instance + '/resources/files/fileops';
+  }),
+
+  headers: {
+    'X-Requested-By': 'ambari'
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/adapters/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/adapters/file.js b/contrib/views/files/src/main/resources/ui/app/adapters/file.js
new file mode 100644
index 0000000..331d554
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/adapters/file.js
@@ -0,0 +1,66 @@
+/**
+ * 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 ApplicationAdapter from './application';
+
+export default ApplicationAdapter.extend({
+  pathForType: function(type) {
+    if (type === 'file') {
+      return 'listdir';
+    }
+  },
+  parseErrorResponse: function(responseText) {
+    var json = this._super(responseText);
+    if((typeof json) === 'object') {
+      var error = {};
+      if (Ember.isPresent(json.success)) {
+        // This error is for Invalid Error response (422)
+        error.success = json.success;
+        error.message = json.message;
+
+        delete json.success;
+        delete json.message;
+
+        if(Ember.isArray(json.succeeded)) {
+          error.succeeded = json.succeeded;
+          delete json.succeeded;
+        }
+        if (Ember.isArray(json.failed)) {
+          error.failed = json.failed;
+          delete json.failed;
+        }
+        if (Ember.isArray(json.unprocessed)) {
+          error.unprocessed = json.unprocessed;
+          delete json.unprocessed;
+        }
+      } else {
+        // Other errors
+        error.message = json.message;
+        error.trace = json.trace;
+        error.status = json.status;
+        delete json.trace;
+        delete json.status;
+        delete json.message;
+      }
+      json.errors = [error];
+    }
+
+    return json;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/app.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/app.js b/contrib/views/files/src/main/resources/ui/app/app.js
index 7041224..7d9e22d 100644
--- a/contrib/views/files/src/main/resources/ui/app/app.js
+++ b/contrib/views/files/src/main/resources/ui/app/app.js
@@ -16,4 +16,21 @@
  * limitations under the License.
  */
 
-module.exports = Em.Application.create();
+import Ember from 'ember';
+import Resolver from 'ember-resolver';
+import loadInitializers from 'ember/load-initializers';
+import config from './config/environment';
+
+let App;
+
+Ember.MODEL_FACTORY_INJECTIONS = true;
+
+App = Ember.Application.extend({
+  modulePrefix: config.modulePrefix,
+  podModulePrefix: config.podModulePrefix,
+  Resolver: Resolver
+});
+
+loadInitializers(App, config.modulePrefix);
+
+export default App;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/assets/fonts/fontawesome-webfont.eot
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/assets/fonts/fontawesome-webfont.eot b/contrib/views/files/src/main/resources/ui/app/assets/fonts/fontawesome-webfont.eot
deleted file mode 100644
index 7c79c6a..0000000
Binary files a/contrib/views/files/src/main/resources/ui/app/assets/fonts/fontawesome-webfont.eot and /dev/null differ