You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2015/11/04 20:23:40 UTC
ambari git commit: AMBARI-Files View: Enable to preview files in
WEBHDFS (Pallav Kulshreshtha via srimanth)
Repository: ambari
Updated Branches:
refs/heads/branch-2.1 f10ece280 -> 409ea0131
AMBARI-Files View: Enable to preview files in WEBHDFS (Pallav Kulshreshtha via srimanth)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/409ea013
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/409ea013
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/409ea013
Branch: refs/heads/branch-2.1
Commit: 409ea01317a76db8d3ad7c46424dddc1be0040d6
Parents: f10ece2
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Wed Nov 4 11:23:24 2015 -0800
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Wed Nov 4 11:23:24 2015 -0800
----------------------------------------------------------------------
.../view/filebrowser/FileBrowserService.java | 10 +++
.../view/filebrowser/FilePreviewService.java | 92 ++++++++++++++++++++
.../files/src/main/resources/ui/app/adapter.js | 2 +-
.../main/resources/ui/app/controllers/file.js | 13 ++-
.../main/resources/ui/app/controllers/files.js | 10 ++-
.../ui/app/controllers/previewModal.js | 87 ++++++++++++++++++
.../src/main/resources/ui/app/initialize.js | 3 +
.../src/main/resources/ui/app/routes/file.js | 23 ++++-
.../ui/app/templates/modal/preview.hbs | 33 +++++++
.../main/resources/ui/app/views/modalPreview.js | 51 +++++++++++
.../files/src/main/resources/ui/bower.json | 3 +-
.../files/src/main/resources/ui/package.json | 3 +-
12 files changed, 324 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileBrowserService.java
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileBrowserService.java b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileBrowserService.java
index 9224331..fd1c710 100644
--- a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileBrowserService.java
+++ b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FileBrowserService.java
@@ -68,4 +68,14 @@ public class FileBrowserService {
return new HelpService(context);
}
+
+ /**
+ * @see org.apache.ambari.view.filebrowser.FilePreviewService
+ * @return service
+ */
+ @Path("/preview")
+ public FilePreviewService preview() {
+ return new FilePreviewService(context);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FilePreviewService.java
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FilePreviewService.java b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FilePreviewService.java
new file mode 100644
index 0000000..0c1344d
--- /dev/null
+++ b/contrib/views/files/src/main/java/org/apache/ambari/view/filebrowser/FilePreviewService.java
@@ -0,0 +1,92 @@
+/**
+ * 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.
+ */
+
+package org.apache.ambari.view.filebrowser;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.filebrowser.utils.NotFoundFormattedException;
+import org.apache.ambari.view.filebrowser.utils.ServiceFormattedException;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.io.compress.CompressionCodec;
+import org.apache.hadoop.io.compress.CompressionCodecFactory;
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+/**
+ * File Preview Service
+ */
+public class FilePreviewService extends HdfsService{
+
+ private CompressionCodecFactory compressionCodecFactory;
+
+ public FilePreviewService(ViewContext context) {
+ super(context);
+
+ Configuration conf = new Configuration();
+ conf.set("io.compression.codecs","org.apache.hadoop.io.compress.GzipCodec," +
+ "org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.SnappyCodec," +
+ "org.apache.hadoop.io.compress.BZip2Codec");
+
+ compressionCodecFactory = new CompressionCodecFactory(conf);
+ }
+
+ @GET
+ @Path("/file")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response previewFile(@QueryParam("path") String path,@QueryParam("start") int start,@QueryParam("end") int end) {
+
+ try {
+ HdfsApi api = getApi(context);
+ FileStatus status = api.getFileStatus(path);
+
+ CompressionCodec codec = compressionCodecFactory.getCodec(status.getPath());
+
+ // check if we have a compression codec we need to use
+ InputStream stream = (codec != null) ? codec.createInputStream(api.open(path)) : api.open(path);
+
+ int length = end - start;
+ byte[] bytes = new byte[length];
+ // ((Seekable)stream).seek(start); //seek(start);
+ stream.skip(start);
+ int readBytes = stream.read(bytes, 0, length);
+ boolean isFileEnd = false;
+
+ if (readBytes < length) isFileEnd = true;
+
+ JSONObject response = new JSONObject();
+ response.put("data", new String(bytes));
+ response.put("readbytes", readBytes);
+ response.put("isFileEnd", isFileEnd);
+
+ return Response.ok(response).build();
+ } catch (WebApplicationException ex) {
+ throw ex;
+ } catch (FileNotFoundException ex) {
+ throw new NotFoundFormattedException(ex.getMessage(), ex);
+ } catch (Exception ex) {
+ throw new ServiceFormattedException(ex.getMessage(), ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/adapter.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/adapter.js b/contrib/views/files/src/main/resources/ui/app/adapter.js
index 6ec763b..74cb988 100644
--- a/contrib/views/files/src/main/resources/ui/app/adapter.js
+++ b/contrib/views/files/src/main/resources/ui/app/adapter.js
@@ -296,7 +296,7 @@ App.ApplicationStore = DS.Store.extend({
option = option || "browse";
if (option == 'browse') {
- query = { "path": files.get('firstObject.path'), "download": download };
+ query = { "path": (files.get('firstObject.path') || files.get('id')), "download": download };
resolver.resolve(adapter.downloadUrl('browse',query));
return resolver.promise;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/controllers/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/file.js b/contrib/views/files/src/main/resources/ui/app/controllers/file.js
index cf87041..b5054e4 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/file.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/file.js
@@ -21,6 +21,13 @@ var App = require('app');
App.FileController = Ember.ObjectController.extend({
needs:['files'],
actions:{
+ confirmPreview:function (option) {
+ if (this.get('content.readAccess')) {
+ this.store.linkFor([this.get('content')],option).then(function (link) {
+ window.location.href = link;
+ },Em.run.bind(this,this.sendAlert));
+ }
+ },
download:function (option) {
if (this.get('content.readAccess')) {
this.store.linkFor([this.get('content')],option).then(function (link) {
@@ -28,6 +35,9 @@ App.FileController = Ember.ObjectController.extend({
},Em.run.bind(this,this.sendAlert));
}
},
+ preview:function (option) {
+ this.send('showPreviewModal',this.get('content'));
+ },
showChmod:function () {
this.send('showChmodModal',this.get('content'));
},
@@ -55,7 +65,8 @@ App.FileController = Ember.ObjectController.extend({
if (this.get('content.isDirectory')) {
return this.transitionToRoute('files',{queryParams: {path: this.get('content.id')}});
} else{
- return this.send('download');
+ //return this.send('download');
+ return this.send('preview');
}
},
deleteFile:function (deleteForever) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/controllers/files.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/files.js b/contrib/views/files/src/main/resources/ui/app/controllers/files.js
index 22cbb7a..7fb55bd 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/files.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/files.js
@@ -87,10 +87,12 @@ App.FilesController = Ember.ArrayController.extend({
},
download:function (option) {
var files = this.get('selectedFiles').filterBy('readAccess',true);
- this.store.linkFor(files,option).then(function (link) {
+ var content = this.get('content');
+ this.store.linkFor(content, option).then(function (link) {
window.location.href = link;
});
},
+
mkdir:function (newDirName) {
this.store.mkdir(newDirName)
.then(bind(this,this.mkdirSuccessCalback),bind(this,this.throwAlert));
@@ -118,6 +120,12 @@ App.FilesController = Ember.ArrayController.extend({
.chmod(file)
.then(null,Em.run.bind(this,this.chmodErrorCallback,file));
},
+ confirmPreview:function (file) {
+ //this.send('download');
+ this.store.linkFor(file, "browse").then(function (link) {
+ window.location.href = link;
+ });
+ },
clearSearchField:function () {
this.set('searchString','');
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js b/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
new file mode 100644
index 0000000..a2d0c9e
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.PreviewModalController = Em.ObjectController.extend({
+ needs:['files'],
+ offset: 3000 ,
+ startIndex:0,
+ file:Em.computed.alias('content'),
+ filePageText:'',
+ pagecontent: Ember.computed('file','startIndex', 'endIndex', function() {
+ var file = this.get('file');
+ var filepath = file.get('path');
+ var filePageText = this.get('filePageText');
+
+ var self = this,
+ defer = Ember.RSVP.defer(),
+ startIndex = this.get('startIndex'),
+ endIndex = this.get('endIndex');
+
+ var pathName = window.location.pathname;
+ var pathNameArray = pathName.split("/");
+ var ViewVersion = pathNameArray[3];
+ var viewName = pathNameArray[4];
+ var previewServiceURL = "/api/v1/views/FILES/versions/"+ ViewVersion + "/instances/" + viewName + "/resources/files/preview/file" + '?path=' + filepath + '&start='+ startIndex +'&end='+ endIndex;
+
+ var previousText = $('.preview-content').text();
+
+ $.ajax({
+ url: previewServiceURL,
+ dataType: "json",
+ type: 'get',
+ async: false,
+ contentType: 'application/json',
+ success: function( response, textStatus, jQxhr ){
+ self.set('filePageText', previousText + response.data);
+ self.set('isFileEnd',response.isFileEnd);
+ },
+ error: function( jqXhr, textStatus, errorThrown ){
+ console.log( "Preview Fail pagecontent : " + errorThrown );
+ }
+ });
+
+ if(self.get('isFileEnd') == true){
+ this.set('showNext', false);
+ }
+ return self.get('filePageText');
+ }),
+ endIndex: Ember.computed('startIndex', 'offset', function() {
+ var startIndex = this.get('startIndex'),
+ offset = this.get('offset');
+ return startIndex + offset;
+ }),
+ showPrev : Ember.computed('startIndex', function() {
+ var startIndex = this.get('startIndex');
+ this.set('showNext', true);
+ return ((startIndex == 0) ? false : true );
+ }),
+ showNext : true,
+ actions:{
+ next: function(){
+ console.log('Next');
+ this.set('startIndex', this.get('startIndex') + this.get('offset'));
+ return self.get('filePageText');
+ },
+ prev: function(){
+ console.log('Prev');
+ this.set('startIndex', (this.get('startIndex') - this.get('offset')) > 0 ? (this.get('startIndex') - this.get('offset')) : 0);
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/initialize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/initialize.js b/contrib/views/files/src/main/resources/ui/app/initialize.js
index fc6cbc7..7790397 100644
--- a/contrib/views/files/src/main/resources/ui/app/initialize.js
+++ b/contrib/views/files/src/main/resources/ui/app/initialize.js
@@ -31,6 +31,7 @@ require('templates/index');
require('templates/files');
require('templates/error');
require('templates/modal/chmod');
+require('templates/modal/preview');
require('templates/util/errorRow');
require('templates/util/fileRow');
@@ -56,6 +57,7 @@ require('controllers/file');
require('controllers/error');
require('controllers/filesAlert');
require('controllers/chmodModal');
+require('controllers/previewModal');
/////////////////////////////////
// Components
@@ -81,6 +83,7 @@ require('views/file');
require('views/files');
require('views/filesAlert');
require('views/modalChmod');
+require('views/modalPreview');
/////////////////////////////////
// Routes
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/routes/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/file.js b/contrib/views/files/src/main/resources/ui/app/routes/file.js
index ee6a45a..207b57a 100644
--- a/contrib/views/files/src/main/resources/ui/app/routes/file.js
+++ b/contrib/views/files/src/main/resources/ui/app/routes/file.js
@@ -48,13 +48,16 @@ App.FilesRoute = Em.Route.extend({
},
willTransition:function (argument) {
var hasModal = this.router._lookupActiveView('modal.chmod'),
- hasAlert = this.router._lookupActiveView('files.alert');
+ hasAlert = this.router._lookupActiveView('files.alert'),
+ hasPreviewModal = this.router._lookupActiveView('modal.preview');
Em.run.next(function(){
if (hasAlert) this.send('removeAlert');
if (hasModal) this.send('removeChmodModal');
+ if (hasPreviewModal) this.send('removePreviewModal');
}.bind(this));
},
+
showChmodModal:function (content) {
this.controllerFor('chmodModal').set('content',content);
this.render('modal.chmod',{
@@ -63,12 +66,30 @@ App.FilesRoute = Em.Route.extend({
controller:'chmodModal'
});
},
+
+ showPreviewModal :function (content) {
+ this.controllerFor('previewModal').set('content',content);
+ this.controllerFor('previewModal').set('startIndex',0);
+
+ this.render('modal.preview',{
+ into:'files',
+ outlet:'modal',
+ controller:'previewModal'
+ });
+ },
+
removeChmodModal:function () {
this.disconnectOutlet({
outlet: 'modal',
parentView: 'files'
});
},
+ removePreviewModal:function () {
+ this.disconnectOutlet({
+ outlet: 'modal',
+ parentView: 'files'
+ });
+ },
showAlert:function (error) {
this.controllerFor('filesAlert').set('content',error);
this.render('files.alert',{
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/templates/modal/preview.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/templates/modal/preview.hbs b/contrib/views/files/src/main/resources/ui/app/templates/modal/preview.hbs
new file mode 100644
index 0000000..d619bd9
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/templates/modal/preview.hbs
@@ -0,0 +1,33 @@
+{{!
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+}}
+<div class="modal preview" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
+ <h4 class="modal-title">File Preview</h4>
+ {{ file.path }}
+ </div>
+ <pre class="modal-body preview-content" style="white-space:pre;margin: 10px; padding: 10px;overflow-y: auto; height: 350px">{{ pagecontent }}</pre>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" {{action 'close' target="view"}}>Close</button>
+ <button type="button" class="btn btn-primary" {{action 'confirm' target="view"}}>Download File</button>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/app/views/modalPreview.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/views/modalPreview.js b/contrib/views/files/src/main/resources/ui/app/views/modalPreview.js
new file mode 100644
index 0000000..927e267
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/views/modalPreview.js
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.ModalPreviewView = Em.View.extend({
+ actions:{
+ confirm:function (file) {
+ this.get('controller.controllers.files').send('confirmPreview', this.get('controller.file'));
+ this.$('.preview').modal('hide');
+ },
+ close:function () {
+ this.$('.preview').modal('hide');
+ }
+ },
+ didInsertElement:function (argument) {
+ var self = this;
+
+ this.$('.preview').modal();
+
+ this.$('.preview').on('hidden.bs.modal',function () {
+ this.get('controller.controllers.files').send('removePreviewModal');
+ }.bind(this));
+
+ this.$('.preview-content').on('scroll', function() {
+ if($(this).scrollTop() + $(this).innerHeight() >= this.scrollHeight) {
+ self.get('controller').send('next');
+ }
+ });
+
+ },
+ willClearRender:function () {
+ this.$('.preview').off('hidden.bs.modal');
+ this.$('.preview').modal('hide');
+ }
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/bower.json b/contrib/views/files/src/main/resources/ui/bower.json
index b7cb52a..c0a4049 100644
--- a/contrib/views/files/src/main/resources/ui/bower.json
+++ b/contrib/views/files/src/main/resources/ui/bower.json
@@ -12,7 +12,8 @@
"moment": "~2.5.1",
"ember-i18n": "~1.6.0",
"bootstrap-contextmenu": "~0.2.0",
- "font-awesome": "~4.0.3"
+ "font-awesome": "~4.0.3",
+ "ivy-codemirror": "~1.0.0"
},
"overrides": {
"ember-uploader": {
http://git-wip-us.apache.org/repos/asf/ambari/blob/409ea013/contrib/views/files/src/main/resources/ui/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/package.json b/contrib/views/files/src/main/resources/ui/package.json
index 1fab7e8..f172af8 100644
--- a/contrib/views/files/src/main/resources/ui/package.json
+++ b/contrib/views/files/src/main/resources/ui/package.json
@@ -30,7 +30,8 @@
"phantomjs": "^1.9.2",
"karma": "*",
"karma-qunit": "*",
- "karma-phantomjs-launcher": "~0.1.2"
+ "karma-phantomjs-launcher": "~0.1.2",
+ "ivy-codemirror": "^1.2.0"
},
"ignore": [
"**/.*",