You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/02/24 19:18:02 UTC
[04/10] ambari git commit: AMBARI-15145. Revamped Filebrowser Design
- UI. (dipayanb)
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/files.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/files.js b/contrib/views/files/src/main/resources/ui/app/controllers/files.js
index 1315f31..4b60ab3 100644
--- a/contrib/views/files/src/main/resources/ui/app/controllers/files.js
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/files.js
@@ -16,201 +16,154 @@
* limitations under the License.
*/
-var App = require('app');
-var bind = Ember.run.bind;
-
-App.FilesController = Ember.ArrayController.extend({
- actions:{
- moveFile:function (opt,fileArg) {
- var src, title,
- file = fileArg || this.get('selectedFiles.firstObject'),
- moving = this.get('movingFile');
-
- if (opt == 'cut') {
- src = file.toJSON({includeId: true});
- src = Em.merge(src,{name:file.get('name'),path:file.get('path')});
- this.set('movingFile',src);
- }
-
- if (opt == 'move') {
- this.store.move(moving.path,[this.get('path'),moving.name].join('/').replace('//','/'))
- .then(bind(this,this.set,'movingFile',null),bind(this,this.throwAlert));
- }
+import Ember from 'ember';
+import columnConfig from '../config/files-columns';
+
+export default Ember.Controller.extend({
+ fileSelectionService: Ember.inject.service('files-selection'),
+ lastSelectedFile: Ember.computed.oneWay('fileSelectionService.lastFileSelected'),
+ selectedFilesCount: Ember.computed.oneWay('fileSelectionService.filesCount'),
+ selectedFolderCount: Ember.computed.oneWay('fileSelectionService.folderCount'),
+ isSelected: Ember.computed('selectedFilesCount', 'selectedFolderCount', function() {
+ return (this.get('selectedFilesCount') + this.get('selectedFolderCount')) !== 0;
+ }),
- if (opt == 'cancel') {
- this.set('movingFile',null);
- }
- },
- showRenameInput:function () {
- this.toggleProperty('isRenaming');
- },
- renameDir:function (path,newName) {
- var _this = this,
- basedir = path.substring(0,path.lastIndexOf('/')+1);
- newPath = basedir + newName;
-
- if (path === newPath) {
- return false;
- }
-
- this.store.listdir(basedir).then(function (listdir) {
- var recordExists = listdir.isAny('id',newPath);
-
- listdir.forEach(function (file) {
- _this.store.unloadRecord(file);
- });
+ queryParams: ['path'],
+ path: '/',
+ columns: columnConfig,
+
+ hasHomePath: false,
+ hasTrashPath: false,
+
+ currentPathIsTrash: Ember.computed('path', 'trashPath', 'hasTrashPath', function() {
+ return this.get('hasTrashPath') && (this.get('path') === this.get('trashPath'));
+ }),
+
+ // This is required as the validSearchText will be debounced and will not be
+ // called at each change of searchText. searchText is required so that sub
+ // components(file search componenet) UI can be cleared from outside.(i.e, from
+ // the afterModel of the route when the route changes)
+ searchText: '',
+ validSearchText: '',
+
+ sortProperty: [],
+ sortEnabled: Ember.computed('fileSelectionService.files.length', function() {
+ return this.get('fileSelectionService.files.length') === 0;
+ }),
+
+ allSelected: Ember.computed('fileSelectionService.files.length', function() {
+ return this.get('fileSelectionService.files.length') !== 0 && this.get('fileSelectionService.files.length') === this.get('model.length');
+ }),
+
+ parentPath: Ember.computed('path', function() {
+ var path = this.get('path');
+ var parentPath = path.substring(0, path.lastIndexOf('/'));
+ if(Ember.isBlank(parentPath)) {
+ parentPath = '/';
+ }
- if (recordExists) {
- return _this.throwAlert({message:newPath + ' already exists.'});
- }
+ if(path === '/') {
+ parentPath = '';
+ }
+ return parentPath;
+ }),
- return _this.store.move(path,newPath);
- }).then(function (newDir) {
- if (newDir) {
- _this.store.unloadRecord(newDir);
- _this.set('path',newPath);
- }
- }).catch(bind(this,this.throwAlert));
+ sortedContent: Ember.computed.sort('model', 'sortProperty'),
- },
- deleteFile:function (deleteForever) {
- var self = this,
- selected = this.get('selectedFiles'),
- moveToTrash = !deleteForever;
- selected.forEach(function (file) {
- self.store.remove(file,moveToTrash).then(null,bind(self,self.deleteErrorCallback,file));
+ arrangedContent: Ember.computed('model', 'sortProperty', 'validSearchText', function() {
+ var searchText = this.get('validSearchText');
+ if(!Ember.isBlank(searchText)) {
+ return this.get('sortedContent').filter(function(entry) {
+ return !!entry.get('name').match(searchText);
});
+ }
+ return this.get('sortedContent');
+ }),
+
+ actions: {
+ sortFiles: function(sortColumn) {
+ if (sortColumn['sortOrder'] !== 0) {
+ var sortProperty = sortColumn['key'] + ':' + this._getSortOrderString(sortColumn);
+ this.set('sortProperty', [sortProperty]);
+ } else {
+ this.set('sortProperty', []);
+ }
},
- download:function (option) {
- var files = this.get('selectedFiles').filterBy('readAccess',true);
- var content = this.get('content');
- this.store.linkFor(content, option).then(function (link) {
- window.location.href = link;
- });
+
+ searchFiles: function(searchText) {
+ this.set('validSearchText', searchText);
},
- mkdir:function (newDirName) {
- this.store.mkdir(newDirName)
- .then(bind(this,this.mkdirSuccessCalback),bind(this,this.throwAlert));
+ /* Selects a single file. Clears previous selection */
+ selectSingle: function(file) {
+ this.get('fileSelectionService').deselectAll();
+ this.get('fileSelectionService').selectFiles([file]);
},
- upload:function (opt) {
- if (opt === 'open') {
- this.set('isUploading',true);
- }
- if (opt === 'close') {
- this.set('isUploading',false);
+ /*
+ Selects file without clearing the previous selection. If sticky is true
+ then shiftkey was pressed while clicking and we should select all the
+ files in between
+ */
+ selectMultiple: function(file, sticky) {
+ if(!sticky) {
+ if(file.get('isSelected')) {
+ this.get('fileSelectionService').deselectFile(file);
+ } else {
+ this.get('fileSelectionService').selectFiles([file]);
+ }
+ } else {
+ var lastFileSelected = this.get('fileSelectionService.lastFileSelected');
+ var indexRange = this._getIndexRangeBetweenfiles(lastFileSelected, file);
+ if(indexRange[0] === indexRange[1]) {
+ return false;
+ }
+ var filesInRange = this._getFilesInRange(indexRange[0], indexRange[1]);
+ this.get('fileSelectionService').deselectAll();
+ this.get('fileSelectionService').selectFiles(filesInRange);
}
},
- sort:function (pr) {
- var currentProperty = this.get('sortProperties');
- if (pr == currentProperty[0] || pr == 'toggle') {
- this.toggleProperty('sortAscending');
- } else{
- this.set('sortProperties',[pr]);
- this.set('sortAscending',true);
+
+ selectAll: function(selectStatus) {
+ this.get('fileSelectionService').deselectAll();
+ if(selectStatus === false) {
+ this.get('fileSelectionService').selectFiles(this.get('sortedContent'));
}
},
- confirmChmod:function (file) {
- this.store
- .chmod(file)
- .then(null,Em.run.bind(this,this.chmodErrorCallback,file));
- },
- confirmPreview:function (file) {
- //this.send('download');
- this.store.linkFor(file, "browse").then(function (link) {
- window.location.href = link;
- });
- },
- clearSearchField:function () {
- this.set('searchString','');
- }
- },
- init:function () {
- if (App.testing) {
- return this._super();
- }
- var controller = this;
- var adapter = controller.store.adapterFor('file');
- var url = adapter.buildURL('upload');
- this.uploader.set('url',url);
- this.uploader.on('didUpload', function (payload) {
- controller.store.pushPayload('file', {'file': payload });
- });
- this._super();
- },
- sortProperties: ['name'],
- sortAscending: true,
+ /* Deselects the current selections */
+ deselectAll: function() {
+ this.get('fileSelectionService').deselectAll();
+ },
- needs: ["file"],
- movingFile:null,
- uploader:App.Uploader,
- isRenaming:false,
- isUploading:false,
- queryParams: ['path'],
- path: '/',
- isRootDir:Ember.computed.equal('path', '/'),
- hideMoving:function () {
- return (this.movingFile)?[this.path,this.movingFile.name].join('/').replace('//','/')===this.movingFile.path:false;
- }.property('movingFile','path'),
- currentDir:function () {
- return this.get('path').split('/').get('lastObject') || '/';
- }.property('path'),
- selectedOne:Ember.computed.equal('selectedFiles.length', 1),
- isSelected:Ember.computed.gt('selectedFiles.length', 0),
- selectedFiles:function () {
- return this.get('content').filterBy('selected', true);
- }.property('content.@each.selected'),
- canConcat:function () {
- return this.get('selectedFiles').filterProperty('isDirectory').get('length')===0;
- }.property('selectedFiles.length'),
-
- isSortPropertyEqualsDate: function() {
- return this.get('sortProperties').get('firstObject') === 'date';
- }.property('sortProperties.firstObject'),
-
- searchString:'',
- fileList: function () {
- var fileList = this.get('arrangedContent');
- var search = this.get('searchString');
- return (search)?fileList.filter(function (file) {
- return !!file.get('name').match(search);
- }):fileList;
- }.property('arrangedContent','searchString'),
-
- mkdirSuccessCalback:function (newDir) {
- if (newDir.get('path') != [this.get('path'),newDir.get('name')].join('/')){
- newDir.unloadRecord();
- newDir.store.listdir(this.get('path'));
+ //Context Menu actions
+ openFolder: function(path) {
+ this.transitionToRoute({queryParams: {path: path}});
}
},
- clearSearch:function () {
- this.set('searchString','');
- }.observes('path'),
-
- deleteErrorCallback:function (record,error) {
- this.model.pushRecord(record);
- this.throwAlert(error);
- },
-
- chmodErrorCallback:function (record,error) {
- record.rollback();
- this.throwAlert({message:'Permissions change failed'});
- },
-
- throwAlert:function (error) {
- this.send('showAlert',error);
+ _getIndexRangeBetweenfiles: function(startFile, endFile) {
+ var startIndex = this.get('arrangedContent').indexOf(startFile);
+ var endIndex = this.get('arrangedContent').indexOf(endFile);
+ if (startIndex < endIndex) {
+ return [startIndex, endIndex];
+ } else {
+ return [endIndex, startIndex];
+ }
},
- showSpinner:function () {
- this.set('isLoadingFiles',true);
+ _getFilesInRange: function(startIndex, endIndex) {
+ var range = Array.apply(null, Array(endIndex - startIndex + 1)).map(function (_, i) {return startIndex + i;});
+ return this.get('arrangedContent').objectsAt(range);
},
- hideSpinner:function () {
- this.set('isLoadingFiles',false);
+ _getSortOrderString: function(column) {
+ if (column['sortOrder'] === -1) {
+ return 'desc';
+ } else if (column['sortOrder'] === 1) {
+ return 'asc';
+ } else {
+ return '';
+ }
}
});
-
-
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js b/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
deleted file mode 100644
index 64221e3..0000000
--- a/contrib/views/files/src/main/resources/ui/app/controllers/filesAlert.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-App.FilesAlertController = App.ErrorController.extend({
- content:null,
- output:function () {
- var error = this.get('content'),
- message = (error.responseJSON)?error.responseJSON.message:error.message,
- output;
-
- if (message) {
- message = message.split('\n').objectAt(0);
- }
-
- return message;
- }.property('content')
-});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/messages.js b/contrib/views/files/src/main/resources/ui/app/controllers/messages.js
new file mode 100644
index 0000000..52655e3
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/messages.js
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ filesController: Ember.inject.controller('files'),
+ currentBrowserPath: Ember.computed.oneWay('filesController.path'),
+ isExpanded: true,
+ shortenLength: Ember.computed('isExpanded', function() {
+ if(this.get('isExpanded') === true) {
+ return 200;
+ } else {
+ return 100;
+ }
+ })
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js b/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js
new file mode 100644
index 0000000..d46c1f6
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/controllers/messages/message.js
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+
+ showStatus: Ember.computed('model', function() {
+ return this.get('model.status') !== -1;
+ }),
+
+ displayBody: Ember.computed('model', function() {
+ return !(Ember.isBlank(this.get('model.responseMessage'))
+ && Ember.isBlank(this.get('model.trace')));
+ })
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js b/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
deleted file mode 100644
index 35973b2..0000000
--- a/contrib/views/files/src/main/resources/ui/app/controllers/previewModal.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var App = require('app');
-
-App.PreviewModalController = Em.ObjectController.extend({
- needs:['files', 'file'],
- offset: 3000 ,
- startIndex:0,
- file:Em.computed.alias('content'),
- filePageText:'',
- reload: false,
- pagecontent: Ember.computed('file', 'startIndex', 'endIndex', 'reload', function() {
- var file = this.get('file');
- var filepath = file.get('path');
- var filePageText = this.get('filePageText');
-
- var self = this,
- defer = Ember.RSVP.defer(),
- startIndex = this.get('startIndex'),
- endIndex = this.get('endIndex');
-
- var pathName = window.location.pathname;
- var pathNameArray = pathName.split("/");
- var ViewVersion = pathNameArray[3];
- var viewName = pathNameArray[4];
- var previewServiceURL = "/api/v1/views/FILES/versions/"+ ViewVersion + "/instances/" + viewName + "/resources/files/preview/file" + '?path=' + filepath + '&start='+ startIndex +'&end='+ endIndex;
-
- var previousText = $('.preview-content').text();
-
- $.ajax({
- url: previewServiceURL,
- dataType: "json",
- type: 'get',
- async: false,
- contentType: 'application/json',
- success: function( response, textStatus, jQxhr ){
- self.set('filePageText', previousText + response.data);
- self.set('isFileEnd',response.isFileEnd);
- },
- error: function( jqXhr, textStatus, errorThrown ){
- console.log( "Preview Fail pagecontent : " + errorThrown );
- self.send('removePreviewModal');
- self.send('showAlert', jqXhr);
- self.set('reload', !self.get('reload'));
- }
- });
-
- if(self.get('isFileEnd') == true){
- this.set('showNext', false);
- }
- return self.get('filePageText');
- }),
- endIndex: Ember.computed('startIndex', 'offset', function() {
- var startIndex = this.get('startIndex'),
- offset = this.get('offset');
- return startIndex + offset;
- }),
- showPrev : Ember.computed('startIndex', function() {
- var startIndex = this.get('startIndex');
- this.set('showNext', true);
- return ((startIndex == 0) ? false : true );
- }),
- showNext : true,
- actions:{
- next: function(){
- console.log('Next');
- this.set('startIndex', this.get('startIndex') + this.get('offset'));
- return this.get('filePageText');
- },
- prev: function(){
- console.log('Prev');
- this.set('startIndex', (this.get('startIndex') - this.get('offset')) > 0 ? (this.get('startIndex') - this.get('offset')) : 0);
- }
- }
-});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/.gitkeep b/contrib/views/files/src/main/resources/ui/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js
new file mode 100644
index 0000000..28a5a8d
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-context-class.js
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function alertMessageContextClass(params) {
+ let messageType = params[0];
+ let prefix = params[1];
+ return `${prefix}${messageType}`;
+}
+
+export default Ember.Helper.helper(alertMessageContextClass);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js
new file mode 100644
index 0000000..707f2d1
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/alert-message-icon-class.js
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function alertMessageIconClass(params) {
+ let type = params[0];
+ switch (type) {
+ case 'success':
+ return 'check';
+ case 'info':
+ return 'info';
+ case 'warning':
+ return 'exclamation';
+ case 'danger':
+ return 'times';
+ default:
+ return 'check';
+ }
+}
+
+export default Ember.Helper.helper(alertMessageIconClass);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js b/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js
new file mode 100644
index 0000000..25601c8
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/get-sorting-icon.js
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function getSortingIcon(params/*, hash*/) {
+ let sortOrder = params[0];
+ var iconClass;
+ if (sortOrder === 1) {
+ iconClass = "chevron-down";
+ } else if (sortOrder === -1) {
+ iconClass = "chevron-up";
+ } else {
+ iconClass = "chevron-right";
+ }
+ return iconClass;
+}
+
+export default Ember.Helper.helper(getSortingIcon);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js b/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js
new file mode 100644
index 0000000..7570327
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/get-value-from-columns.js
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function getValueFromColumns(params) {
+ let columnsArray = params[0];
+ let key = params[1];
+ let paramKey = params[2];
+
+ var column = columnsArray.filterBy('key', key);
+
+ if(column.length > 0) {
+ return column[0][paramKey];
+ }
+ return "";
+}
+
+export default Ember.Helper.helper(getValueFromColumns);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js b/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js
new file mode 100644
index 0000000..c50b5ca
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/shorten-text.js
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function shortenText(params) {
+ let text = params[0];
+ let length = params[1];
+ if (text.length < length) {
+ return text;
+ } else {
+ return text.substring(0, length - 3) + '...';
+ }
+
+}
+
+export default Ember.Helper.helper(shortenText);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js b/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js
new file mode 100644
index 0000000..0f47982
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/show-date.js
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function showDate(params) {
+ let date = params[0];
+ let format = params[1];
+ return moment(date).format(format);
+}
+
+export default Ember.Helper.helper(showDate);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js b/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js
new file mode 100644
index 0000000..2855ca4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/size-humanize.js
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function sizeHumanize(params) {
+ let fileSizeInBytes = params[0];
+ var i = -1;
+ var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
+ do {
+ fileSizeInBytes = fileSizeInBytes / 1024;
+ i++;
+ } while (fileSizeInBytes > 1024);
+
+ return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
+}
+
+export default Ember.Helper.helper(sizeHumanize);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js b/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js
new file mode 100644
index 0000000..d24780d
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/helpers/string-capitalize.js
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export function stringCapitalize(params/*, hash*/) {
+ return params;
+}
+
+export default Ember.Helper.helper(stringCapitalize);
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/index.html b/contrib/views/files/src/main/resources/ui/app/index.html
new file mode 100644
index 0000000..51d1839
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/index.html
@@ -0,0 +1,42 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <title>HDFS - File Browser</title>
+ <meta name="description" content="">
+
+ {{content-for "head"}}
+
+ <link rel="stylesheet" href="assets/vendor.css">
+ <link rel="stylesheet" href="assets/files-view.css">
+
+ {{content-for "head-footer"}}
+ </head>
+ <body>
+ {{content-for "body"}}
+
+ <script src="assets/vendor.js"></script>
+ <script src="assets/files-view.js"></script>
+
+ {{content-for "body-footer"}}
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/initialize.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/initialize.js b/contrib/views/files/src/main/resources/ui/app/initialize.js
deleted file mode 100644
index 7790397..0000000
--- a/contrib/views/files/src/main/resources/ui/app/initialize.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//////////////////////////////////
-// Adapter
-//////////////////////////////////
-
-require('adapter');
-
-//////////////////////////////////
-// Templates
-//////////////////////////////////
-
-require('templates/application');
-require('templates/index');
-require('templates/files');
-require('templates/error');
-require('templates/modal/chmod');
-require('templates/modal/preview');
-require('templates/util/errorRow');
-require('templates/util/fileRow');
-
-require('templates/components/uploader');
-require('templates/components/renameInput');
-require('templates/components/deletePopover');
-require('templates/components/mkdirInput');
-require('templates/components/contextMenu');
-require('templates/components/deleteBulk');
-
-//////////////////////////////////
-// Models
-//////////////////////////////////
-
-require('models/file');
-
-/////////////////////////////////
-// Controllers
-/////////////////////////////////
-
-require('controllers/files');
-require('controllers/file');
-require('controllers/error');
-require('controllers/filesAlert');
-require('controllers/chmodModal');
-require('controllers/previewModal');
-
-/////////////////////////////////
-// Components
-/////////////////////////////////
-
-require('components/uploader');
-require('components/contextMenu');
-require('components/renameInput');
-require('components/bsPopover');
-require('components/confirmDelete');
-require('components/sortArrow');
-require('components/breadCrumbs');
-require('components/popoverDelete');
-require('components/bulkCheckbox');
-require('components/mkdirInput');
-require('components/toggleContext');
-
-/////////////////////////////////
-// Views
-/////////////////////////////////
-
-require('views/file');
-require('views/files');
-require('views/filesAlert');
-require('views/modalChmod');
-require('views/modalPreview');
-
-/////////////////////////////////
-// Routes
-/////////////////////////////////
-
-require('routes/file');
-require('routes/error');
-
-/////////////////////////////////
-// Router
-/////////////////////////////////
-
-require('router');
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js b/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js
new file mode 100644
index 0000000..6f4d070
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/mixins/file-operation.js
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+/*
+ Base Mixin to be used by different Services to get the common behaviors mixed
+ in to the service.
+*/
+export default Ember.Mixin.create({
+ store: Ember.inject.service('store'),
+
+ getBaseFilesURLPath: function() {
+ // TODO: This has to be changed when it is integrated inside Ambari
+ //var pathName = window.location.pathname;
+ var pathname = '/api/v1/views/FILES/versions/1.0.0/instances/Files/resources/files';
+ return pathname;
+ },
+
+ getBaseDirPath: function(path) {
+ return path.substring(0, path.lastIndexOf('/') + 1);
+ },
+
+ _getBaseURLFragments: function() {
+ var adapter = this.get('store').adapterFor('file');
+ var baseURL = adapter.buildURL('file');
+ return baseURL.split('/');
+ },
+
+ extractError: function(error) {
+ if (Ember.isArray(error.errors) && (error.errors.length >= 0)) {
+ return error.errors[0];
+ }
+ return {};
+ },
+
+ isInvalidError: function(error) {
+ // This seems to a slight hack. But from backend the response of 422 is
+ // always a hash which has success param set and value is false
+ return Ember.isPresent(error.success) && error.success === false;
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js b/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js
new file mode 100644
index 0000000..543498f
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/mixins/operation-modal.js
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import { EKMixin, keyUp, EKFirstResponderOnFocusMixin } from 'ember-keyboard';
+
+export default Ember.Mixin.create(EKMixin, EKFirstResponderOnFocusMixin, {
+ modalEventBus: Ember.inject.service('modal-event-bus'),
+ name: '',
+ closeOnEscape: false,
+ isModalOpen: false,
+
+ setupKey: Ember.on('init', function() {
+ this.set('keyboardActivated', true);
+ }),
+
+ //disableEscape:
+ closeModalOnEscape: Ember.on(keyUp('Escape'), function() {
+ if (this.get('closeOnEscape')) {
+ this.$('.modal').modal('hide');
+ }
+ }),
+
+ initModal: function() {
+ Ember.defineProperty(this, 'modalGuard', Ember.computed.alias('modalEventBus.' + this.get('name')));
+ this.addObserver('modalGuard', () => {
+ if(this.get('modalGuard')) {
+ this.set('isModalOpen', true);
+ Ember.run.later(this, () => {
+ this.$('.modal').modal({backdrop: 'static', keyboard: false});
+ this.$('.modal').on('hide.bs.modal', () => {
+ this.send('closeModal');
+ });
+ this.send('modalOpened');
+ });
+
+ }
+ });
+ }.on('didInitAttrs'),
+
+ hideModal: Ember.on('willDestroyElement', function() {
+ if (this.get('isModalOpen')) {
+ this.$('.modal').modal('hide');
+ }
+ }),
+
+ actions: {
+ /** close by action in the UI **/
+ close: function() {
+ this.$('.modal').modal('hide');
+ },
+
+ closeModal: function() {
+ this.$('.modal').off('hide.bs.modal');
+ this.set('isModalOpen', false);
+ this.get('modalEventBus').resetModal(this.get('name'));
+ this.send('didCloseModal');
+ },
+
+ modalOpened: function() {
+ this.send('didOpenModal');
+ },
+
+ didCloseModal: function() {},
+ didOpenModal: function() {}
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/models/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/models/.gitkeep b/contrib/views/files/src/main/resources/ui/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/models/alert.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/models/alert.js b/contrib/views/files/src/main/resources/ui/app/models/alert.js
new file mode 100644
index 0000000..74b07f9
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/models/alert.js
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+ type: DS.attr('string'),
+ message: DS.attr('string'),
+ responseMessage: DS.attr('string'),
+ status: DS.attr('number'),
+ trace: DS.attr('string')
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/models/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/models/file.js b/contrib/views/files/src/main/resources/ui/app/models/file.js
index 0e31f71..a2ed1f3 100644
--- a/contrib/views/files/src/main/resources/ui/app/models/file.js
+++ b/contrib/views/files/src/main/resources/ui/app/models/file.js
@@ -16,36 +16,36 @@
* limitations under the License.
*/
-var App = require('app');
+import DS from 'ember-data';
+import Ember from 'ember';
-var dsa = DS.attr;
+export default DS.Model.extend({
+
+ isDirectory : DS.attr('boolean'),
+ readAccess : DS.attr('boolean'),
+ writeAccess : DS.attr('boolean'),
+ executeAccess : DS.attr('boolean'),
+ len : DS.attr('number'),
+ owner : DS.attr('string'),
+ group : DS.attr('string'),
+ permission : DS.attr('string'),
+ accessTime : DS.attr('iso-date'),
+ modificationTime : DS.attr('iso-date'),
+ blockSize : DS.attr('number'),
+ replication : DS.attr('number'),
+ size : Ember.computed.alias('len'),
-App.File = DS.Model.extend({
path: function() {
return this.get('id');
}.property('id'),
- basedir:function () {
- var path = this.get('id');
- return path.substring(0,path.lastIndexOf('/'))||'/';
- }.property('id'),
- isDirectory: dsa('boolean'),
- readAccess: dsa('boolean'),
- writeAccess: dsa('boolean'),
- executeAccess: dsa('boolean'),
- len: dsa('number'),
- owner: dsa('string'),
- group: dsa('string'),
- permission: dsa('string'),
- accessTime: dsa('isodate'),
- modificationTime: dsa('isodate'),
- blockSize: dsa('number'),
- replication: dsa('number'),
- name:function () {
- var splitpath = this.get('path').split('/');
- return splitpath.get(splitpath.length-1);
+
+ name: function() {
+ var splitPath = this.get('path').split('/');
+ return splitPath.get(splitPath.length - 1);
}.property('path'),
- date:function () {
+
+ date: function() {
return parseInt(moment(this.get('modificationTime')).format('X'));
- }.property('modificationTime'),
- size: Em.computed.alias('len')
+ }.property('modificationTime')
+
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/router.js b/contrib/views/files/src/main/resources/ui/app/router.js
index b38ac00..801e932 100644
--- a/contrib/views/files/src/main/resources/ui/app/router.js
+++ b/contrib/views/files/src/main/resources/ui/app/router.js
@@ -16,8 +16,18 @@
* limitations under the License.
*/
-App = require('app');
+import Ember from 'ember';
+import config from './config/environment';
-App.Router.map(function() {
- this.route('files', { queryParams:['path'],path: '/',});
+const Router = Ember.Router.extend({
+ location: config.locationType
});
+
+Router.map(function() {
+ this.route('files');
+ this.route('messages', function() {
+ this.route('message', {path: '/:message_id'});
+ });
+});
+
+export default Router;
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/.gitkeep b/contrib/views/files/src/main/resources/ui/app/routes/.gitkeep
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/application.js b/contrib/views/files/src/main/resources/ui/app/routes/application.js
new file mode 100644
index 0000000..eca62f4
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/application.js
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+ fileOperationService: Ember.inject.service('file-operation'),
+ model: function() {
+ var promise = {
+ homeDir: this.get('fileOperationService').getHome(),
+ trashDir: this.get('fileOperationService').getTrash()
+ };
+
+ return Ember.RSVP.hashSettled(promise).then(function(hash) {
+ var response = {
+ homeDir: {path: '', hasError: true},
+ trashDir: {path: '', hasError: true}
+ };
+
+ if(hash.homeDir.state === 'fulfilled'){
+ response.homeDir.path = hash.homeDir.value.path;
+ response.homeDir.hasError = false;
+ }
+
+ if(hash.trashDir.state === 'fulfilled'){
+ response.trashDir.path = hash.trashDir.value.path;
+ response.trashDir.hasError = false;
+ }
+
+ return response;
+ });
+ },
+ setupController: function(controller, hash) {
+ this._super(controller, hash);
+ if(hash.homeDir.hasError === false) {
+ this.controllerFor('files').set('homePath', hash.homeDir.path);
+ this.controllerFor('files').set('hasHomePath', true);
+ }
+
+ if(hash.trashDir.hasError === false) {
+ this.controllerFor('files').set('trashPath', hash.trashDir.path);
+ this.controllerFor('files').set('hasTrashPath', true);
+ }
+ },
+
+ actions: {
+ loading(transition, route) {
+ let startTime = moment();
+ let appController = this.controllerFor('application');
+ // when the application loads up we want the loading template to be
+ // rendered and not the loading spinner in the application template
+ if(appController.get('firstLoad') === false) {
+ appController.set('isLoading', true);
+ }
+ transition.promise.finally(() => {
+ console.log("Loaded in " + (moment() - startTime) + "ms");
+ appController.set('isLoading', false);
+ appController.set('firstLoad', false);
+ });
+ return appController.get('firstLoad');
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/error.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/error.js b/contrib/views/files/src/main/resources/ui/app/routes/error.js
deleted file mode 100644
index 3b71cde..0000000
--- a/contrib/views/files/src/main/resources/ui/app/routes/error.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var App = require('app');
-
-App.ErrorRoute = Em.Route.extend({});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/file.js b/contrib/views/files/src/main/resources/ui/app/routes/file.js
deleted file mode 100644
index b64a7b1..0000000
--- a/contrib/views/files/src/main/resources/ui/app/routes/file.js
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var App = require('app');
-
-App.FilesRoute = Em.Route.extend({
- queryParams: {
- path: {
- refreshModel: true
- }
- },
- actions:{
- refreshDir:function () {
- this.refresh();
- },
- loading:function (argument) {
- var target = this.controllerFor('files');
- target.showSpinner();
- this.router.one('didTransition', target, 'hideSpinner');
- },
- error:function (error,transition,e) {
- this.controllerFor('files').set('isLoadingFiles', false);
- if (this.router._lookupActiveView('files')) {
- this.send('showAlert',error);
- } else {
- return true;
- }
- },
- dirUp: function () {
- var currentPath = this.controllerFor('files').get('path');
- var upDir = currentPath.substring(0,currentPath.lastIndexOf('/'));
- var target = upDir || '/';
- return this.transitionTo('files',{queryParams: {path: target}});
- },
- willTransition:function (argument) {
- var hasModal = this.router._lookupActiveView('modal.chmod'),
- hasAlert = this.router._lookupActiveView('files.alert'),
- hasPreviewModal = this.router._lookupActiveView('modal.preview');
-
- Em.run.next(function(){
- if (hasAlert) this.send('removeAlert');
- if (hasModal) this.send('removeChmodModal');
- if (hasPreviewModal) this.send('removePreviewModal');
- }.bind(this));
- },
-
- showChmodModal:function (content) {
- this.controllerFor('chmodModal').set('content',content);
- this.render('modal.chmod',{
- into:'files',
- outlet:'modal',
- controller:'chmodModal'
- });
- },
-
- showPreviewModal :function (content) {
- var controller = this.controllerFor('previewModal');
- controller.set('reload', true);
- controller.set('content',content);
- controller.set('startIndex',0);
-
- this.render('modal.preview',{
- into:'files',
- outlet:'modal',
- controller:'previewModal'
- });
- },
-
- removeChmodModal:function () {
- this.disconnectOutlet({
- outlet: 'modal',
- parentView: 'files'
- });
- },
- removePreviewModal:function () {
- this.disconnectOutlet({
- outlet: 'modal',
- parentView: 'files'
- });
- },
- showAlert:function (error) {
- this.controllerFor('filesAlert').set('content',error);
- this.render('files.alert',{
- into:'files',
- outlet:'error',
- controller:'filesAlert'
- });
- },
- removeAlert:function () {
- this.disconnectOutlet({
- outlet: 'error',
- parentView: 'files'
- });
- }
- },
- model:function (params) {
- var path = (Em.isEmpty(params.path))?'/':params.path;
- var model = this.store.listdir(path);
- this.set('prevModel',model);
- return model;
- },
- prevModel:null,
- beforeModel:function () {
- if (this.get('prevModel.isPending')) {
- this.get('prevModel').then(function (files) {
- files.forEach(function (file) {
- file.store.unloadRecord(file);
- });
- });
- }
- },
- afterModel: function (model) {
- this.store.all('file').forEach(function (file) {
- if (!model.contains(file)) {
- file.unloadRecord();
- }
- });
- }
-});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/files.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/files.js b/contrib/views/files/src/main/resources/ui/app/routes/files.js
new file mode 100644
index 0000000..140732f
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/files.js
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Route.extend(FileOperationMixin, {
+ logger: Ember.inject.service('alert-messages'),
+ fileSelectionService: Ember.inject.service('files-selection'),
+ currentPath: '/',
+ queryParams: {
+ path: {
+ refreshModel: true
+ }
+ },
+ model: function(params) {
+ this.store.unloadAll('file');
+ return this.store.query('file', {path: params.path});
+ },
+
+ setupController: function(controller, model) {
+ this._super(controller, model);
+ controller.set('searchText', '');
+ this.get('fileSelectionService').reset();
+ this.set('currentPath', controller.get('path'));
+ },
+
+ actions: {
+ refreshCurrentRoute: function() {
+ this.refresh();
+ },
+
+ error: function(error, transition) {
+ this.get('fileSelectionService').reset();
+ let path = transition.queryParams.path;
+ var formattedError = this.extractError(error);
+ this.get('logger').danger(`Failed to transition to <strong>${path}</strong>`, formattedError);
+ // Had to do this as we are unloading all files before transitioning
+ this.transitionTo({
+ queryParams: {
+ path: this.get('currentPath')
+ }
+ });
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/index.js b/contrib/views/files/src/main/resources/ui/app/routes/index.js
new file mode 100644
index 0000000..1032334
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/index.js
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+ beforeModel: function(transition) {
+ this.transitionTo('files');
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/messages.js b/contrib/views/files/src/main/resources/ui/app/routes/messages.js
new file mode 100644
index 0000000..2d94782
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/messages.js
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+ logger: Ember.inject.service('alert-messages'),
+ model: function() {
+ return this.store.peekAll('alert');
+ },
+ setupController: function(controller, model) {
+ this._super(controller, model);
+ this.get('logger').clearMessages();
+ controller.set('isExpanded', true);
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js b/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js
new file mode 100644
index 0000000..84be53b
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/routes/messages/message.js
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+ model: function(params) {
+ return this.store.peekRecord('alert', params.message_id);
+ },
+
+ setupController: function(controller, model) {
+ this._super(controller, model);
+ var messagesController = this.controllerFor('messages');
+ messagesController.set('isExpanded', false);
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/serializers/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/serializers/file.js b/contrib/views/files/src/main/resources/ui/app/serializers/file.js
new file mode 100644
index 0000000..3edc933
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/serializers/file.js
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import DS from 'ember-data';
+
+export default DS.RESTSerializer.extend({
+ primaryKey: 'path'
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js b/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js
new file mode 100644
index 0000000..1a9c06d
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/alert-messages.js
@@ -0,0 +1,126 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+
+/**
+ Shows alert flash and also creates `alert` objects in store. If creation of
+ `alert` objects in store pass `options.flashOnly` as `true`. The options
+ required for creating the `alert` objects are:
+ ```
+ options.message: message field returned by the API server.
+ options.status : Status XHR request if the message is a response to XHR request. Defaults to -1.
+ options.error: Detailed error to be displayed.
+ ```
+ Options required for ember-cli-flash can also be passed in the alertOptions to override the
+ default behaviour.
+*/
+export default Ember.Service.extend({
+ flashMessages: Ember.inject.service('flash-messages'),
+ store: Ember.inject.service('store'),
+
+ success: function(message, options = {}, alertOptions = {}) {
+ this._processMessage('success', message, options, alertOptions);
+ },
+
+ warn: function(message, options = {}, alertOptions = {}) {
+ this._processMessage('warn', message, options, alertOptions);
+ },
+
+ info: function(message, options = {}, alertOptions = {}) {
+ this._processMessage('info', message, options, alertOptions);
+ },
+
+ danger: function(message, options = {}, alertOptions = {}) {
+ this._processMessage('danger', message, options, alertOptions);
+ },
+
+ clearMessages: function() {
+ this.get('flashMessages').clearMessages();
+ },
+
+ _processMessage: function(type, message, options, alertOptions) {
+ this._clearMessagesIfRequired(alertOptions);
+ let alertRecord = this._createAlert(message, type, options, alertOptions);
+ if(alertRecord) {
+ message = this._addDetailsToMessage(message, alertRecord);
+ }
+ switch (type) {
+ case 'success':
+ this.get('flashMessages').success(message, this._getOptions(alertOptions));
+ break;
+ case 'warn':
+ this.get('flashMessages').warning(message, this._getOptions(alertOptions));
+ break;
+ case 'info':
+ this.get('flashMessages').info(message, this._getOptions(alertOptions));
+ break;
+ case 'danger':
+ this.get('flashMessages').danger(message, this._getOptions(alertOptions));
+ }
+ },
+
+ _addDetailsToMessage: function(message, record) {
+ let id = record.get('id');
+ let suffix = `<a href="#/messages/${id}">(details)</a>`;
+ return message + " " + suffix;
+ },
+
+ _createAlert: function(message, type, options, alertOptions) {
+ var data = {};
+ data.message = message;
+ data.responseMessage = options.message || '';
+ data.id = this._getNextAlertId();
+ data.type = type;
+ data.status = options.status || -1;
+ data.trace = this._getDetailedError(options.trace);
+ delete options.status;
+ delete options.error;
+
+ if(alertOptions.flashOnly === true) {
+ return;
+ }
+
+ return this.get('store').createRecord('alert', data);
+ },
+
+ _getDetailedError: function(error) {
+ return error || '';
+ },
+
+ _getOptions: function(options = {}) {
+ var defaultOptions = {
+ priority: 100,
+ showProgress: true,
+ timeout: 6000
+ };
+ return Ember.merge(defaultOptions, options);
+ },
+
+ _getNextAlertId: function() {
+ return this.get('store').peekAll('alert').get('length') + 1;
+ },
+
+ _clearMessagesIfRequired: function(options = {}) {
+ var stackMessages = options.stackMessages || false;
+ if(stackMessages !== true) {
+ this.clearMessages();
+ }
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/file-copy.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/file-copy.js b/contrib/views/files/src/main/resources/ui/app/services/file-copy.js
new file mode 100644
index 0000000..7193177
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/file-copy.js
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Service.extend(FileOperationMixin, {
+ logger: Ember.inject.service('alert-messages'),
+
+ // Returns a promise for the operation. Upon sucess or error, this also
+ // appropriately sends error messages.
+
+ copy: function (srcPath, destName) {
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ var adapter = this.get('store').adapterFor('file');
+ var baseURL = adapter.buildURL('file');
+ var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/copy";
+ var data = {sourcePaths: srcPath, destinationPath: destName};
+ adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+ this.get('logger').success(`Successfully copied to ${destName}.`, {}, {flashOnly: true});
+ resolve(response);
+ }, (responseError) => {
+ var error = this.extractError(responseError);
+ this.get('logger').danger(`Failed to copy to ${destName}`, error);
+ reject(error);
+ });
+ });
+ },
+
+ _isDestinationPathExists(destinationPath) {
+ return this.get('store').peekAll('file').isAny('path', destinationPath);
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/file-move.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/file-move.js b/contrib/views/files/src/main/resources/ui/app/services/file-move.js
new file mode 100644
index 0000000..859f04c
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/file-move.js
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Service.extend(FileOperationMixin, {
+ logger: Ember.inject.service('alert-messages'),
+
+ // Returns a promise for the operation. Upon sucess or error, this also
+ // appropriately sends error messages.
+ move: function(srcPath, destName ) {
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ var adapter = this.get('store').adapterFor('file');
+ var baseURL = adapter.buildURL('file');
+ var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/move";
+ var data = {sourcePaths: srcPath, destinationPath: destName};
+ adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+ this.get('logger').success(`Successfully moved to ${destName}.`, {}, {flashOnly: true});
+ resolve(response);
+ }, (responseError) => {
+ var error = this.extractError(responseError);
+ this.get('logger').danger(`Failed to move to ${destName}`, error);
+ reject(error);
+ });
+ });
+ },
+
+ _isDestinationPathExists(destinationPath) {
+ return this.get('store').peekAll('file').isAny('path', destinationPath);
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/b988562a/contrib/views/files/src/main/resources/ui/app/services/file-operation.js
----------------------------------------------------------------------
diff --git a/contrib/views/files/src/main/resources/ui/app/services/file-operation.js b/contrib/views/files/src/main/resources/ui/app/services/file-operation.js
new file mode 100644
index 0000000..abb3000
--- /dev/null
+++ b/contrib/views/files/src/main/resources/ui/app/services/file-operation.js
@@ -0,0 +1,199 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import FileOperationMixin from '../mixins/file-operation';
+
+export default Ember.Service.extend(FileOperationMixin, {
+ logger: Ember.inject.service('alert-messages'),
+ chmod: function (path, permission) {
+ var adapter = this.get('store').adapterFor('file');
+ var data = {mode: permission, path: path};
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ adapter.ajax(this._getFileOperationUrl('chmod'), "POST", {data: data}).then(
+ (response) => {
+ this.get('logger').success(`Successfully changed permission of ${path}`, {}, {flashOnly: false});
+ return resolve(response);
+ }, (responseError) => {
+ var error = this.extractError(responseError);
+ this.get('logger').danger(`Failed to modify permission of ${path}`, error);
+ return reject(error);
+ });
+ });
+ },
+
+ createNewFolder: function (srcPath, folderName) {
+ var path = (srcPath === '/') ? '' : srcPath;
+
+ if (folderName.slice(0, 1) === '/') {
+ folderName = folderName.slice(0, folderName.length);
+ }
+ var adapter = this.get('store').adapterFor('file');
+ var data = {path: `${path}/${folderName}`};
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ adapter.ajax(this._getFileOperationUrl('mkdir'), "PUT", {data: data}).then(
+ (response) => {
+ this.get('logger').success(`Successfully created <strong>${path}/${folderName}`, {flashOnly: true});
+ return resolve(response);
+ }, (responseError) => {
+ var error = this.extractError(responseError);
+ this.get('logger').danger(`Failed to create ${path}/${folderName}`, error);
+ return reject(error);
+ });
+ });
+ },
+
+ deletePaths: function (paths, deletePermanently = false) {
+ var opsUrl;
+ if (deletePermanently) {
+ opsUrl = this._getFileOperationUrl('remove');
+ } else {
+ opsUrl = this._getFileOperationUrl('moveToTrash');
+ }
+ var data = {
+ paths: paths.map((path) => {
+ return {path: path, recursive: true};
+ })
+ };
+ var adapter = this.get('store').adapterFor('file');
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ adapter.ajax(opsUrl, "DELETE", {data: data}).then(
+ (response) => {
+ return resolve(response);
+ }, (rejectResponse) => {
+ var error = this.extractError(rejectResponse);
+ if (this.isInvalidError(error)) {
+ return reject(this._prepareUnprocessableErrorResponse(error));
+ } else {
+ return reject(Ember.merge({retry: false, unprocessable: false}, error));
+ }
+ });
+ });
+ },
+
+ listPath: function (queryPath, onlyDirectory = true) {
+ let baseUrl = this._getFileOperationUrl('listdir');
+ let url = `${baseUrl}?${queryPath}`;
+ var adapter = this.get('store').adapterFor('file');
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ adapter.ajax(url, "GET").then(
+ (response) => {
+ if (onlyDirectory) {
+ return resolve(response.files.filter((entry) => {
+ return entry.isDirectory;
+ }));
+ } else {
+ return resolve(response.files);
+ }
+ }, (responseError) => {
+ var error = this.extractError(responseError);
+ return reject(error);
+ });
+ });
+ },
+
+ movePaths: function (srcPath, destName) {
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ var adapter = this.get('store').adapterFor('file');
+ var baseURL = adapter.buildURL('file');
+ var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/move";
+ var data = {sourcePaths: srcPath, destinationPath: destName};
+ adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+ this.get('logger').success(`Successfully moved to ${destName}.`, {}, {flashOnly: true});
+ resolve(response);
+ }, (rejectResponse) => {
+ var error = this.extractError(rejectResponse);
+ if (this.isInvalidError(error)) {
+ return reject(this._prepareUnprocessableErrorResponse(error));
+ } else {
+ return reject(Ember.merge({retry: false, unprocessable: false}, error));
+ }
+ });
+ });
+ },
+
+ copyPaths: function (srcPath, destName) {
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ var adapter = this.get('store').adapterFor('file');
+ var baseURL = adapter.buildURL('file');
+ var moveUrl = baseURL.substring(0, baseURL.lastIndexOf('/')) + "/copy";
+ var data = {sourcePaths: srcPath, destinationPath: destName};
+ adapter.ajax(moveUrl, "POST", {data: data}).then((response) => {
+ this.get('logger').success(`Successfully copied to ${destName}.`, {}, {flashOnly: true});
+ resolve(response);
+ }, (rejectResponse) => {
+ var error = this.extractError(rejectResponse);
+ if (this.isInvalidError(error)) {
+ return reject(this._prepareUnprocessableErrorResponse(error));
+ } else {
+ return reject(Ember.merge({retry: false, unprocessable: false}, error));
+ }
+ });
+ });
+ },
+
+ _checkIfDeleteRetryIsRequired: function (error) {
+ return error.unprocessed.length >= 1;
+ },
+
+ _prepareUnprocessableErrorResponse: function (error) {
+ var response = {};
+ response.unprocessable = true;
+ if (this._checkIfDeleteRetryIsRequired(error)) {
+ response.retry = true;
+ response.failed = error.failed[0];
+ response.message = error.message;
+ response.unprocessed = error.unprocessed;
+ } else {
+ response.retry = false;
+ response.failed = error.failed[0];
+ response.message = error.message;
+ }
+
+ return response;
+ },
+
+ getHome: function () {
+ var adapter = this.get('store').adapterFor('file');
+ return adapter.ajax(this._getMiscUrl("/help/home"), "GET");
+ },
+
+ getTrash: function () {
+ var adapter = this.get('store').adapterFor('file');
+ return adapter.ajax(this._getMiscUrl("/help/trashDir"), "GET");
+ },
+
+ _getMiscUrl: function (segment) {
+ var urlFragments = this._getBaseURLFragments();
+ return urlFragments.slice(0, urlFragments.length - 2).join('/') + segment;
+ },
+
+ getUploadUrl: function () {
+ return this._getMiscUrl("/upload");
+ },
+
+ _getFileOperationUrl: function (pathFragment) {
+ var adapter = this.get('store').adapterFor('file');
+ var baseURL = adapter.buildURL('file');
+ return baseURL.substring(0, baseURL.lastIndexOf('/')) + `/${pathFragment}`;
+ },
+
+ isExistsInCurrentPath: function (name) {
+ return this.get('store').peekAll('file').isAny('name', name);
+ }
+});