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