Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4253618731 for ; Wed, 24 Feb 2016 18:24:47 +0000 (UTC) Received: (qmail 7122 invoked by uid 500); 24 Feb 2016 18:18:00 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 6998 invoked by uid 500); 24 Feb 2016 18:18:00 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 6813 invoked by uid 99); 24 Feb 2016 18:18:00 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 24 Feb 2016 18:18:00 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E4857E8EBB; Wed, 24 Feb 2016 18:17:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: dbhowmick@apache.org To: commits@ambari.apache.org Date: Wed, 24 Feb 2016 18:18:02 -0000 Message-Id: <4e7932ca0cbe4518b0614a05d01af049@git.apache.org> In-Reply-To: <78259e64453f409c976ee91cdfc44215@git.apache.org> References: <78259e64453f409c976ee91cdfc44215@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [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 @@ + + + + + + + + HDFS - File Browser + + + {{content-for "head"}} + + + + + {{content-for "head-footer"}} + + + {{content-for "body"}} + + + + + {{content-for "body-footer"}} + + 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 ${path}`, 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 = `(details)`; + 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 ${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); + } +});