From 8193f6696c69cafffb024d7959baac501fc6a2c1 Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Mon, 21 Mar 2016 07:20:47 -0300 Subject: [PATCH 01/17] Test Connection & BackUp Added Test Connection button on Settings Dialog and created an Backup All Button for downloading the current changed files --- html/dialog-backup-files.html | 23 +++ html/dialog-message.html | 15 ++ html/dialog-settings.html | 8 + html/panel.html | 1 + main.js | 143 +++++++++++-- modules/BackupFilesDialog.js | 67 ++++++ modules/SettingsDialog.js | 80 +++++-- nls/pt/Strings.js | 15 +- nls/root/Strings.js | 22 +- node/SftpUploadDomain.js | 379 ++++++++++++++++++++++++++-------- node/package.json | 7 +- 11 files changed, 624 insertions(+), 136 deletions(-) create mode 100644 html/dialog-backup-files.html create mode 100644 html/dialog-message.html create mode 100644 modules/BackupFilesDialog.js diff --git a/html/dialog-backup-files.html b/html/dialog-backup-files.html new file mode 100644 index 0000000..002b47d --- /dev/null +++ b/html/dialog-backup-files.html @@ -0,0 +1,23 @@ + diff --git a/html/dialog-message.html b/html/dialog-message.html new file mode 100644 index 0000000..4c19d57 --- /dev/null +++ b/html/dialog-message.html @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/html/dialog-settings.html b/html/dialog-settings.html index 0617af6..4309a01 100644 --- a/html/dialog-settings.html +++ b/html/dialog-settings.html @@ -49,6 +49,12 @@

{{ Strings.SETTINGS_DIALOG_TITLE }}

+
+ + +
@@ -57,7 +63,9 @@

{{ Strings.SETTINGS_DIALOG_TITLE }}

{{/info}}
diff --git a/html/panel.html b/html/panel.html index 6a447a4..241b302 100644 --- a/html/panel.html +++ b/html/panel.html @@ -9,6 +9,7 @@
+
× diff --git a/main.js b/main.js index fe3db21..8ce27f7 100644 --- a/main.js +++ b/main.js @@ -33,6 +33,7 @@ define( function( require, exports, module ) { Strings = require( 'modules/Strings' ), dataStorage = require( 'modules/DataStorageManager' ), settingsDialog = require( 'modules/SettingsDialog' ), + backupDialog = require('modules/BackupFilesDialog'), // Preferences. preferences = PreferencesManager.getExtensionPrefs( 'bigeyex.bracketsSFTPUpload' ), @@ -49,7 +50,9 @@ define( function( require, exports, module ) { // Get view menu. menu = Menus.getMenu( Menus.AppMenuBar.VIEW_MENU ), - contextMenu = Menus.getContextMenu(Menus.ContextMenuIds.PROJECT_MENU); + contextMenu = Menus.getContextMenu(Menus.ContextMenuIds.PROJECT_MENU), + is_downloading = false, + downloadCounts = { ok: 0, error: 0}; // Define preferences. preferences.definePreference( 'enabled', 'boolean', false ); @@ -80,6 +83,16 @@ define( function( require, exports, module ) { // Load stylesheet. ExtensionUtils.loadStyleSheet( module, 'todo.css' ); + /** + * Get saved serverInfo + */ + function _getServerInfo() { + var serverInfo = dataStorage.get('server_info'); + if ( serverInfo.backupPath === undefined ) serverInfo.backupPath = settingsDialog.getFolder(); + + return serverInfo; + } + /** * Set state of extension. */ @@ -124,7 +137,7 @@ define( function( require, exports, module ) { // Save enabled state. preferences.set( 'enabled', enabled ); - preferences.save() + preferences.save(); // Mark menu item as enabled/disabled. CommandManager.get( COMMAND_ID ).setChecked( enabled ); @@ -211,7 +224,73 @@ define( function( require, exports, module ) { updateStatus(err); }); } + + // backup all files in the panel to a folder + function downloadAllItems(folder){ + is_downloading = true; + downloadCounts.ok = 0; + downloadCounts.error = 0; + var serverInfo = _getServerInfo(), + trs = $('#brackets-sftp-upload tr .upload-button'), + filelist = [], + projectUrl = ProjectManager.getProjectRoot().fullPath, + basePath = _getBackupFullPath(serverInfo, folder); + + for(var i=0;i -1 ) { // full dir + basePath = serverInfo.backupPath + folder + "/"; + } + else { + basePath = projectUrl + serverInfo.backupPath + "/" + folder + "/"; + } + // replace any '//' to '/' + basePath = basePath.replace(/\/+/g, "/"); + return basePath; + } + + // Test Server Connection + function testConnection(serverInfo) { + settingsDialog.updateStatus(Strings.TEST_CONNECTION_STARTING); + _nodeDomain.exec('testConnection', serverInfo) + .fail(function(err){ + settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED + ":" + err); + }); + } + + // Disable all buttons in the panel + function disableButtons() { + $('#brackets-sftp-upload button').attr('disabled', 'disabled'); + } + // Enable all buttons in the panel + function enableButtons() { + $('#brackets-sftp-upload button').removeAttr('disabled'); + } + + // Remove item from the changed files list function skipItem(path) { var changedFiles = dataStorage.get('changed_files') || {}; $('#brackets-sftp-upload tr[x-file="'+path+'"]').remove(); @@ -221,11 +300,13 @@ define( function( require, exports, module ) { } } + // Remove all itens from the changed files list function skipAllItems(){ $('#brackets-sftp-upload tr').remove(); dataStorage.set('changed_files', {}); } - + + // Update Panel Status function updateStatus(status){ $('#brackets-sftp-upload .status-stab').text(status); } @@ -248,7 +329,7 @@ define( function( require, exports, module ) { } var projectUrl = ProjectManager.getProjectRoot().fullPath; var serverInfo = dataStorage.get('server_info'); - if(serverInfo != null && serverInfo.uploadOnSave){ + if(serverInfo !== null && serverInfo.uploadOnSave){ uploadItem(path, path.replace(projectUrl, '')); return; } @@ -303,18 +384,18 @@ define( function( require, exports, module ) { } ).appendTo( '#main-toolbar .buttons' ); $todoPanel.on('click', '.btn-server-setup',function(){ - settingsDialog.showDialog(); - }); - - $todoPanel.on('click', '.btn-upload-all',function(){ + settingsDialog.showDialog(testConnection); + }) + .on('click', '.btn-upload-all',function(){ uploadAllItems(); - }); - - $todoPanel.on('click', '.btn-skip-all',function(){ + }) + .on('click', '.btn-skip-all',function(){ skipAllItems(); + }) + .on('click', '.btn-backup-all', function(){ + backupDialog.showDialog(downloadAllItems, _getBackupFullPath(_getServerInfo(), '')); }); - // Enable extension if loaded last time. if ( preferences.get( 'enabled' ) ) { enablePanel( true ); @@ -322,17 +403,41 @@ define( function( require, exports, module ) { $(_nodeDomain).on('uploading', function(err, msg){ updateStatus('Uploading: '+msg); - }); - $(_nodeDomain).on('uploaded', function(err, msg){ + }) + .on('downloading', function(err, remoteFile, localFile){ + updateStatus('Downloading: '+remoteFile + '('+ downloadCounts.ok + ' ok / ' + downloadCounts.error + ' errors)'); + }) + .on('uploaded', function(err, msg){ var projectUrl = ProjectManager.getProjectRoot().fullPath; skipItem(projectUrl+msg); updateStatus('Finished: '+msg); - }); - $(_nodeDomain).on('error', function(err, msg){ - updateStatus('Error: '+msg); - }); - $(_nodeDomain).on('jobCompleted', function(err, msg){ + }) + .on('downloaded', function(err, remoteFile, localFile){ + downloadCounts.ok = downloadCounts.ok + 1; + updateStatus('Downloaded: '+remoteFile); + }) + .on('connection-tested', function(err, ok, msg){ + if (ok) { + settingsDialog.updateStatus(Strings.TEST_CONNECTION_SUCCESS); + } + else { + settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED); + } + }) + .on('error', function(err, msg){ + if ( is_downloading ) { + downloadCounts.error = downloadCounts.error + 1; + } + else { + updateStatus('Error: ' + msg); + } + }) + .on('jobCompleted', function(err, msg){ showUploadingIconStatus(false); + if ( is_downloading ) { + updateStatus('Backup Complete! ' + '('+ downloadCounts.ok + ' ok / ' + downloadCounts.error + ' errors)' ); + enableButtons(); + } }); } ); } ); diff --git a/modules/BackupFilesDialog.js b/modules/BackupFilesDialog.js new file mode 100644 index 0000000..48fa4f4 --- /dev/null +++ b/modules/BackupFilesDialog.js @@ -0,0 +1,67 @@ +define( function( require, exports ) { + 'use strict'; + + // Get module dependencies. + var Dialogs = brackets.getModule( 'widgets/Dialogs' ), + + // Extension modules. + Strings = require( 'modules/Strings' ), + dataStorage = require( 'modules/DataStorageManager' ), + bkpDialogTemplate = require( 'text!../html/dialog-backup-files.html' ), + msgDialogTemplate = require( 'text!../html/dialog-message.html' ), + + // Variables. + dialog, + HasPortChanged, + defaultFolderName = (function(d){ return d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate(); }(new Date())); + + /** + * Set each value of the preferences in dialog. + */ + function setValues( values ) { + } + + + /** + * Initialize dialog values. + */ + function init() { + + } + /** + * Exposed method to show dialog. + */ + exports.showDialog = function(callback, localPath) { + // Compile dialog template. + var serverInfo = dataStorage.get('server_info'), + compiledTemplate; + + if(!serverInfo || serverInfo.host === '' ){ + compiledTemplate = Mustache.render(msgDialogTemplate, { + Strings: Strings, + Message: { + Title: Strings.NO_SEVER_SETUP, + Text: Strings.SERVER_SETUP_NEDEED + } + }); + } + else { + compiledTemplate= Mustache.render( bkpDialogTemplate, { + Strings: Strings, + info: $.extend({ folder: defaultFolderName}, serverInfo), + LocalPath: localPath + }); + } + + // Save dialog to variable. + dialog = Dialogs.showModalDialogUsingTemplate( compiledTemplate ); + + // Open dialog. + dialog.done( function( buttonId ) { + // Save preferences if OK button was clicked. + if ( buttonId === 'start' ) { + callback.call(callback, $(".input-folder", dialog.getElement()).val()); + } + }); + }; +}); \ No newline at end of file diff --git a/modules/SettingsDialog.js b/modules/SettingsDialog.js index 0c87a2d..a0714c7 100644 --- a/modules/SettingsDialog.js +++ b/modules/SettingsDialog.js @@ -13,7 +13,8 @@ define( function( require, exports ) { dialog, HasPortChanged, defaultSFTPport = 22, - defaultFTPport = 21; + defaultFTPport = 21, + defaultBackUpPath = 'sftp-backups'; /** * Set each value of the preferences in dialog. @@ -21,6 +22,12 @@ define( function( require, exports ) { function setValues( values ) { } + /** + * Exposed method to get the backup folder name + */ + exports.getFolder = function() { + return dialog !== undefined ? $(".input-backup-path", dialog.getElement()).val() : defaultBackUpPath; + } /** * Initialize dialog values. */ @@ -36,14 +43,28 @@ define( function( require, exports ) { } }); } - /** + + /** + * Exposed method to update footer status + */ + exports.updateStatus = function(status) { + if ( dialog !== undefined ) { + $("label.test-connection-status", dialog.getElement()).html(status); + } + }; + + /** * Exposed method to show dialog. */ - exports.showDialog = function() { + exports.showDialog = function(testConnection) { // Compile dialog template. var serverInfo = dataStorage.get('server_info'); if(!serverInfo){ - serverInfo = {method:'sftp', host:'', port:defaultSFTPport, username:'', rsaPath:'', password:'', serverPath:'', uploadOnSave:0}; + serverInfo = {method:'sftp', host:'', port:defaultSFTPport, username:'', rsaPath:'', password:'', serverPath:'', uploadOnSave:0, backupPath:defaultBackUpPath}; + } + // For compability with previous version + else if ( serverInfo.backupPath === undefined ) { + serverInfo.backupPath = defaultBackUpPath; } var compiledTemplate = Mustache.render( settingsDialogTemplate, { @@ -52,7 +73,7 @@ define( function( require, exports ) { } ); // Save dialog to variable. - dialog = Dialogs.showModalDialogUsingTemplate( compiledTemplate ); + dialog = Dialogs.showModalDialogUsingTemplate( compiledTemplate, false ); // Initialize dialog values. init(); @@ -68,23 +89,44 @@ define( function( require, exports ) { } $('.input-method').val(serverInfo.method); - // Open dialog. - dialog.done( function( buttonId ) { - // Save preferences if OK button was clicked. + // manually handle ESC and buttons Key because of autoDismiss = false + $(dialog.getElement()) + .off('keyup') + .on('keyup', function(evt) { + if ( evt.keyCode === 27 ) { + dialog.close(); + } + }) + .off('click', 'button') + .on('click', 'button', function(evt) { + var buttonId = $(this).data('button-id'), + _getInfo = function() { + var $dialog = dialog.getElement(); + return { + method: $('.input-method', $dialog).val(), + host: $('.input-host', $dialog).val(), + port: $('.input-port', $dialog).val(), + username: $('.input-username', $dialog).val(), + rsaPath: $('.input-rsa-path', $dialog).val(), + password: $('.input-password', $dialog).val(), + serverPath: $('.input-server-path', $dialog).val(), + uploadOnSave: $('.input-save', $dialog).is(':checked') + } + }; + if ( buttonId === 'ok' ) { - var $dialog = dialog.getElement(); - var serverInfo = { - method: $('.input-method', $dialog).val(), - host: $('.input-host', $dialog).val(), - port: $('.input-port', $dialog).val(), - username: $('.input-username', $dialog).val(), - rsaPath: $('.input-rsa-path', $dialog).val(), - password: $('.input-password', $dialog).val(), - serverPath: $('.input-server-path', $dialog).val(), - uploadOnSave: $('.input-save', $dialog).is(':checked') - } + var serverInfo = _getInfo(); dataStorage.set('server_info', serverInfo); + dialog.close(); + } + else if (buttonId === 'test') { + var serverInfo = _getInfo(); + testConnection.call(testConnection, serverInfo); + } + else { + dialog.close(); } }); + }; }); \ No newline at end of file diff --git a/nls/pt/Strings.js b/nls/pt/Strings.js index fbec92d..771cdbf 100644 --- a/nls/pt/Strings.js +++ b/nls/pt/Strings.js @@ -18,6 +18,7 @@ define( { SERVER_SETUP: "Configurar Servidor", UPLOAD_ALL: "Enviar Todos", SKIP_ALL: "Pular Todos", + BACKUP_ALL: "Backup Todos", // SETTINGS DIALOG. SETTINGS_DIALOG_TITLE: "Configurações SFTP", @@ -28,7 +29,17 @@ define( { SETTINGS_DIALOG_PORT: "Porta", SETTINGS_DIALOG_USERNAME: "Nome de Usuário", SETTINGS_DIALOG_PASSWORD: "Senha", - SETTINGS_DIALOG_RSAMSG: "Caminho para Chave RSA", + SETTINGS_DIALOG_RSAMSG: "Caminho para Chave RSA", SETTINGS_DIALOG_PATH: "Caminho no Servidor", - SETTINGS_UPLOAD_ON_SAVE: "Enviar ao salvar" + SETTINGS_UPLOAD_ON_SAVE: "Enviar ao salvar", + SETTINGS_DIALOG_PATH_BACKUP: "Pasta para Backups", + + // BACKUP DIALOG + BACKUP_FILES_TITLE: "SFTP - Backup de Arquivos Alterados", + BACKUP_FILES_LOCAL_PATH: "Salvar em", + BACKUP_FILES_START: "Iniciar Download", + + // NO SERVER SETUP DIALOG + NO_SEVER_SETUP: "SFTP - Nenhuma configuração de servidor", + SERVER_SETUP_NEDEED: "Por favor realize a configuração do servidor (S)FTP antes de realizar backups ou uploads." } ); diff --git a/nls/root/Strings.js b/nls/root/Strings.js index 67814a8..22c84f3 100644 --- a/nls/root/Strings.js +++ b/nls/root/Strings.js @@ -13,11 +13,13 @@ define( { CANCEL: "Cancel", UPLOAD: "Upload", SKIP: "Skip", + TEST_CONNECTION: "Test Connection", // TOOLBAR. SERVER_SETUP: "Server Setup", UPLOAD_ALL: "Upload All", SKIP_ALL: "Skip All", + BACKUP_ALL: "Backup All", // SETTINGS DIALOG. SETTINGS_DIALOG_TITLE: "SFTP Settings", @@ -28,7 +30,23 @@ define( { SETTINGS_DIALOG_PORT: "Port", SETTINGS_DIALOG_USERNAME: "User Name", SETTINGS_DIALOG_PASSWORD: "Password", - SETTINGS_DIALOG_RSAMSG: "RSA Key Path", + SETTINGS_DIALOG_RSAMSG: "RSA Key Path", SETTINGS_DIALOG_PATH: "Server Path", - SETTINGS_UPLOAD_ON_SAVE: "Upload On Save" + SETTINGS_UPLOAD_ON_SAVE: "Upload On Save", + SETTINGS_DIALOG_PATH_BACKUP: "Backup Path", + + // BACKUP DIALOG + BACKUP_FILES_TITLE: "SFTP - Backup Changed Files", + BACKUP_FILES_LOCAL_PATH: "Save To", + BACKUP_FILES_START: "Start Download", + + // NO SERVER SETUP DIALOG + NO_SEVER_SETUP: "SFTP - No Server Setup", + SERVER_SETUP_NEDEED: "Please create an server setup before uploading or backup.", + + // Autenthication + TEST_CONNECTION_STARTING: 'Starting authentication...', + TEST_CONNECTION_SUCCESS: 'Authentication successfull', + TEST_CONNECTION_FAILED: 'Authentication failed' + } ); \ No newline at end of file diff --git a/node/SftpUploadDomain.js b/node/SftpUploadDomain.js index ca1e1c2..29b5f2a 100644 --- a/node/SftpUploadDomain.js +++ b/node/SftpUploadDomain.js @@ -5,6 +5,7 @@ walk = require('walk'), nodepath = require('path'), fs = require('fs'), + mkdirp = require('mkdirp'), _domainManager; JSFtp = require('jsftp-mkdirp')(JSFtp); @@ -43,6 +44,56 @@ this.ftpClient = null; var self = this; + var _ftp_downloadFile = function (fullRemotePath, fullLocalPath, callback) + { + var local_dir = fullLocalPath.replace(/[^\/]*$/, '').replace(/\/$/, ''), + _get_file = function() { + try + { + self.ftpClient.get(fullRemotePath, fullLocalPath, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", ['Download Error:' + err.message]); + } + else{ + _domainManager.emitEvent("sftpUpload", "downloaded", [fullRemotePath, fullLocalPath]); + } + callback.call(callback, err); + }); + + _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, fullLocalPath]); + } + catch(err) { + _domainManager.emitEvent("sftpUpload", "error", ['Download Error:' + err.description]); + callback.call(callback, err); + } + }, + _make_dir = function() { + mkdirp(local_dir, function (errdir) { // creates new directory + if (errdir) { + _domainManager.emitEvent("sftpUpload", "error", ['Create Dir Error: ' + errdir]); + callback.call(callback, errdir); + } + else { + _get_file(); + } + }); + }; + + // Creates local diretory of backup + try { + fs.stat(local_dir, function(err, dirStat) { + if(dirStat !== null && dirStat !== undefined && dirStat.isDirectory()) { // Directory already exists + _get_file(); + } + else { + _make_dir(); + } + }); + } + catch(err2) { + _make_dir(); + } + }; self.run = function(){ var job; if(job=self.jobQueue.shift()){ @@ -64,9 +115,11 @@ } } - // do sftp upload - var fullRemotePath = self._getFullRemotePath(job.remotePath); - + var fullRemotePath = self._getFullRemotePath(job.remotePath), + remotePath = job.remotePath, + path_only = job.localPath.replace(/[^\/]*$/, '').replace(/\/$/, ''); + + // do SFTP upload if(self.config.method == 'sftp'){ if(self.sftpClient === null){ self.sftpClient = new SftpClient.Client(); @@ -82,12 +135,12 @@ } if(fs.existsSync(rsa_path)){ defaults.privateKey = fs.readFileSync(rsa_path); - defaults.passphrase = self.config.password + defaults.passphrase = self.config.password; } else { defaults.password = self.config.password; } self.sftpClient.defaults(defaults); - self.sftpClient.on('error', function(err){ + self.sftpClient.on('error', function(err){ var message = err.message; if(message == 'connect ECONNREFUSED'){ message = 'Broken Connection / Wrong Password'; @@ -95,45 +148,79 @@ self.sftpClient = null; self.isRunning = false; self.jobQueue = []; - _domainManager.emitEvent("sftpUpload", "error", [message]); + + if ( job.type === 'test-connection' ) { + _domainManager.emitEvent("sftpUpload", "connection-tested", [false, message]); + } + else { + _domainManager.emitEvent("sftpUpload", "error", [message]); + } }); } - - - var remotePath = job.remotePath; - fs.stat(job.localPath, function(err, stats){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + if ( job.type !== undefined && job.type === 'download' ) // Download files + { + _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, job.localPath]); + // Creates local diretory of backup + mkdirp(path_only, function (err) { + if (err) { + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + } + else { + self.sftpClient.download(fullRemotePath, job.localPath, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + else{ + _domainManager.emitEvent("sftpUpload", "downloaded", [fullRemotePath, job.localPath]); + self.run(); + } + }); + } + }); + } + else if ( job.type === 'test-connection' ) { + self.sftpClient.testConnection(function(err, isOk) { + _domainManager.emitEvent("sftpUpload", "connection-tested", [isOk, ""]); self.run(); - } - if(stats.isFile()) { - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); - self.sftpClient.upload(job.localPath, fullRemotePath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); - self.run(); - } - }); - } - else if(stats.isDirectory()){ - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); - self.sftpClient.mkdir(fullRemotePath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); - self.run(); - } - }); - } - }); // fs.stat - } // if method == sftp + }); + } + else { + fs.stat(job.localPath, function(err, stats){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + if(stats.isFile()) { + _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + self.sftpClient.upload(job.localPath, fullRemotePath, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + else{ + _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); + self.run(); + } + }); + } + else if(stats.isDirectory()){ + _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + self.sftpClient.mkdir(fullRemotePath, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err]); + self.run(); + } + else{ + _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); + self.run(); + } + }); + } + }); // fs.stat + } // else method == upload + } + // do FTP upload else if(self.config.method == 'ftp'){ if(self.ftpClient === null){ self.ftpClient = new JSFtp({ @@ -151,52 +238,78 @@ self.ftpClient = null; self.isRunning = false; self.jobQueue = []; - _domainManager.emitEvent("sftpUpload", "error", [message]); + if ( job.type === 'test-connection' ) { + _domainManager.emitEvent("sftpUpload", "connection-tested", [false, message]); + } + else { + _domainManager.emitEvent("sftpUpload", "error", [message]); + } + self.run(); }); - var remotePath = job.remotePath; - fs.stat(job.localPath, function(err, stats){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + if ( job.type !== undefined && job.type === 'download' ) // Download files + { + _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, job.localPath]); + + _ftp_downloadFile(fullRemotePath, job.localPath, function() { self.run(); - } - if(stats.isFile()) { - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); - var path_only = fullRemotePath.replace(/[^\/]*$/, '').replace(/\/$/, ''); - self.ftpClient.mkdirp(path_only, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - self.run(); - } - else{ - self.ftpClient.put(job.localPath, fullRemotePath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); - self.run(); - } - }); - } - }); - - } - else if(stats.isDirectory()){ - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); - self.ftpClient.raw.mkd(fullRemotePath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); - self.run(); - } - }); - } - }); // fs.stat + }); + } + else if ( job.type === 'test-connection' ) { + self.ftpClient.raw.stat(function(err, data) { + if ( data.code === 211 ) { // Successfull auth + _domainManager.emitEvent("sftpUpload", "connection-tested", [true, data.text]); + } + else { + _domainManager.emitEvent("sftpUpload", "connection-tested", [false, err.message]); + } + self.run(); + }); + } + else // Do Upload + { + fs.stat(job.localPath, function(err, stats){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + if(stats.isFile()) { + _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + var path_only = fullRemotePath.replace(/[^\/]*$/, '').replace(/\/$/, ''); + self.ftpClient.mkdirp(path_only, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + else{ + self.ftpClient.put(job.localPath, fullRemotePath, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + else{ + _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); + self.run(); + } + }); + } + }); + } + else if(stats.isDirectory()){ + _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + self.ftpClient.raw.mkd(fullRemotePath, function(err){ + if(err){ + _domainManager.emitEvent("sftpUpload", "error", [err.message]); + self.run(); + } + else{ + _domainManager.emitEvent("sftpUpload", "uploaded", [remotePath]); + self.run(); + } + }); + } + }); // fs.stat + } // else job == upload } // if method == ftp } // if there is job @@ -216,9 +329,9 @@ } } }; - - self.add = function(localPath, remotePath, config){ - self.jobQueue.push({localPath: localPath, remotePath: remotePath, config: config}); + + self.add = function(localPath, remotePath, config, jobType){ + self.jobQueue.push({localPath: localPath, remotePath: remotePath, config: config, type: jobType}); if(!self.isRunning){ self.run(); } @@ -242,7 +355,7 @@ fullRemotePath = self.config.serverPath+'/'+remotePath; } return fullRemotePath; - } + }; } var sftpJobs = new SftpJobs(); @@ -259,6 +372,18 @@ } } + function cmdDownloadAll(filelist, config){ + if(config === undefined) {config=null;} + for(var i in filelist){ + sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'download'); + } + } + + function cmdTestConnection(config) { + if(config === undefined) {config=null;} + sftpJobs.add('', '', config, 'test-connection'); + } + function cmdUploadDirectory(localPath, remotePath, config){ if(config === undefined) {config=null;} sftpJobs.addDirectory(localPath, remotePath, config); @@ -284,7 +409,7 @@ type: "string", description: "(relative) path or filename of the destination"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string}", + type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); @@ -299,11 +424,38 @@ type: "[{localPath:string, remotePath:string},...]", description: "a list of files to be uploaded"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string}", + type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); + domainManager.registerCommand( + "sftpUpload", // domain name + "testConnection", // command name + cmdTestConnection, // command handler function + false, // this command is synchronous in Node + "Test the connection with the server setup", + [{name: "config", // parameters + type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + description: "(optional) server configuration."}], + [] + ); + + domainManager.registerCommand( + "sftpUpload", // domain name + "downloadAll", // command name + cmdDownloadAll, // command handler function + false, // this command is synchronous in Node + "Download a list of files in a batch", + [{name: "filelist", // parameters + type: "[{localPath:string, remotePath:string},...]", + description: "a list of files to be downloaded"}, + {name: "config", // parameters + type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + description: "(optional) server configuration."}], + [] + ); + domainManager.registerCommand( "sftpUpload", // domain name "uploadDirectory", // command name @@ -317,7 +469,7 @@ type: "string", description: "(relative) path or filename of the destination"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string}", + type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); @@ -333,6 +485,36 @@ }] ); + domainManager.registerEvent( + "sftpUpload", + "connection-tested", + [{ + name: "ok", + type: "bool", + description: "true if the authentication was succesfull" + }, + { + name: "result", + type: "object", // or string + description: "Authentication result text or error object" + }] + ); + + domainManager.registerEvent( + "sftpUpload", + "downloading", + [{ + name: "remotePath", + type: "string", + description: "the absolute remote path of the file being downloaded" + }, + { + name: "localPath", + type: "string", + description: "the absolute local path of the file being uploaded" + }] + ); + domainManager.registerEvent( "sftpUpload", "uploaded", @@ -343,6 +525,21 @@ }] ); + domainManager.registerEvent( + "sftpUpload", + "downloaded", + [{ + name: "remotePath", + type: "string", + description: "the absolute remote path of the file being downloaded" + }, + { + name: "localPath", + type: "string", + description: "the absolute local path of the file being uploaded" + }] + ); + domainManager.registerEvent( "sftpUpload", "jobCompleted", diff --git a/node/package.json b/node/package.json index 5002198..482c916 100644 --- a/node/package.json +++ b/node/package.json @@ -10,10 +10,11 @@ "brackets" ], "dependencies": { - "scp2": "~0.1.4", + "scp2": "~0.2.2", "walk": "~2.3.3", - "jsftp": "~1.3.0", - "jsftp-mkdirp": "~0.1.2" + "jsftp": "~1.5.0", + "jsftp-mkdirp": "~1.0.0", + "mkdirp": "~0.5.1" }, "repository": { "type": "git", From 6f68b239c45bbbd0d51249fcd3843576646cbf85 Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Thu, 24 Mar 2016 21:51:39 -0300 Subject: [PATCH 02/17] Log Viewer & Upload/Download Status Once you click on the status text it'll open the log viewer dialog. Added completed %, number of errors and succesfull transactions at the end of the status line. --- html/dialog-view-logs.html | 16 +++++++++++ main.js | 19 +++++++++++-- modules/LogViewerDialog.js | 58 ++++++++++++++++++++++++++++++++++++++ nls/root/Strings.js | 8 ++++-- todo.css | 1 + 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 html/dialog-view-logs.html create mode 100644 modules/LogViewerDialog.js diff --git a/html/dialog-view-logs.html b/html/dialog-view-logs.html new file mode 100644 index 0000000..99ca8ee --- /dev/null +++ b/html/dialog-view-logs.html @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/main.js b/main.js index 8ce27f7..3caef4d 100644 --- a/main.js +++ b/main.js @@ -34,6 +34,7 @@ define( function( require, exports, module ) { dataStorage = require( 'modules/DataStorageManager' ), settingsDialog = require( 'modules/SettingsDialog' ), backupDialog = require('modules/BackupFilesDialog'), + logsDialog = require('modules/LogViewerDialog'), // Preferences. preferences = PreferencesManager.getExtensionPrefs( 'bigeyex.bracketsSFTPUpload' ), @@ -41,7 +42,7 @@ define( function( require, exports, module ) { // Mustache templates. todoPanelTemplate = require( 'text!html/panel.html' ), todoRowTemplate = require( 'text!html/row.html' ), - + // Setup extension. serverInfo, //sftp username/password etc; $todoPanel, @@ -52,7 +53,8 @@ define( function( require, exports, module ) { menu = Menus.getMenu( Menus.AppMenuBar.VIEW_MENU ), contextMenu = Menus.getContextMenu(Menus.ContextMenuIds.PROJECT_MENU), is_downloading = false, - downloadCounts = { ok: 0, error: 0}; + downloadCounts = { ok: 0, error: 0}, + consoleLogs = []; // Define preferences. preferences.definePreference( 'enabled', 'boolean', false ); @@ -310,6 +312,10 @@ define( function( require, exports, module ) { function updateStatus(status){ $('#brackets-sftp-upload .status-stab').text(status); } + + function addLog(type, text) { + consoleLogs.push({type: type, text: text}); + } /** * Listen for save or refresh and look for todos when needed. @@ -394,6 +400,11 @@ define( function( require, exports, module ) { }) .on('click', '.btn-backup-all', function(){ backupDialog.showDialog(downloadAllItems, _getBackupFullPath(_getServerInfo(), '')); + }) + .on('click', '.status-stab', function() { + logsDialog.showDialog(consoleLogs, function() { + consoleLogs = []; + }); }); // Enable extension if loaded last time. @@ -411,10 +422,12 @@ define( function( require, exports, module ) { var projectUrl = ProjectManager.getProjectRoot().fullPath; skipItem(projectUrl+msg); updateStatus('Finished: '+msg); + addLog('Uploaded', msg); }) .on('downloaded', function(err, remoteFile, localFile){ downloadCounts.ok = downloadCounts.ok + 1; updateStatus('Downloaded: '+remoteFile); + addLog('Downloaded', remoteFile); }) .on('connection-tested', function(err, ok, msg){ if (ok) { @@ -422,6 +435,7 @@ define( function( require, exports, module ) { } else { settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED); + addLog('Error', msg); } }) .on('error', function(err, msg){ @@ -431,6 +445,7 @@ define( function( require, exports, module ) { else { updateStatus('Error: ' + msg); } + addLog('Error', msg); }) .on('jobCompleted', function(err, msg){ showUploadingIconStatus(false); diff --git a/modules/LogViewerDialog.js b/modules/LogViewerDialog.js new file mode 100644 index 0000000..4b47189 --- /dev/null +++ b/modules/LogViewerDialog.js @@ -0,0 +1,58 @@ +define( function( require, exports ) { + 'use strict'; + + // Get module dependencies. + var Dialogs = brackets.getModule( 'widgets/Dialogs' ), + + // Extension modules. + Strings = require( 'modules/Strings' ), + dataStorage = require( 'modules/DataStorageManager' ), + dialogTemplate = require( 'text!../html/dialog-view-logs.html' ), + + // Variables. + dialog; + + /** + * Set each value of the preferences in dialog. + */ + function setValues( values ) { + } + + + /** + * Initialize dialog values. + */ + function init() { + + } + /** + * Exposed method to show dialog. + */ + exports.showDialog = function(logs, clearCallback) { + // Compile dialog template. + var compiledTemplate = Mustache.render( dialogTemplate, { + Strings: Strings + }), + logsHtml = (function() { + var tmp = ''; + if ( logs.length == 0 ) return '
  • ' + Strings.LOG_VIEWER_EMPTY + '
  • '; + for(var i=0,il=logs.length,l;i'; + } + return tmp; + }()); + // Save dialog to variable. + dialog = Dialogs.showModalDialogUsingTemplate( compiledTemplate ); + + $("#sftpupload-log-viewer").html(logsHtml); + + // Open dialog. + dialog.done( function( buttonId ) { + // Save preferences if OK button was clicked. + if ( buttonId === 'clear' ) { + clearCallback.call(clearCallback); + } + }); + }; +}); \ No newline at end of file diff --git a/nls/root/Strings.js b/nls/root/Strings.js index 22c84f3..23f20df 100644 --- a/nls/root/Strings.js +++ b/nls/root/Strings.js @@ -13,6 +13,7 @@ define( { CANCEL: "Cancel", UPLOAD: "Upload", SKIP: "Skip", + CLEAR: "Clear", TEST_CONNECTION: "Test Connection", // TOOLBAR. @@ -47,6 +48,9 @@ define( { // Autenthication TEST_CONNECTION_STARTING: 'Starting authentication...', TEST_CONNECTION_SUCCESS: 'Authentication successfull', - TEST_CONNECTION_FAILED: 'Authentication failed' - + TEST_CONNECTION_FAILED: 'Authentication failed', + + // Log Viewer + LOG_VIEWER_TITLE: 'Log Viewer', + LOG_VIEWER_EMPTY: 'No log to show.' } ); \ No newline at end of file diff --git a/todo.css b/todo.css index a66835e..f6472cc 100644 --- a/todo.css +++ b/todo.css @@ -1,5 +1,6 @@ #brackets-sftp-upload .status-stab{ color: #555; + cursor: pointer; } .brackets-sftp-upload table { From 7f648c02702c2dfd40bf8a200f9c3fc278a9a9d5 Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Fri, 25 Mar 2016 22:24:09 -0300 Subject: [PATCH 03/17] Multiple Servers per Project / View Log / Upload/Download Status ##Added support for multiple server settings - Changed preferences name from server_info to server_list - On the first time it opens and only have server_info it will add it to the server_list with the "default" name and make it the selected server - To change server open the server setup and select it on the left panel list - After adding a server it will not be selected, you need to. - When selecting a project the setup button will show it's name ##Added Log Dialog Viewer - Click on the updating label to open the log viewer - Has clear button - Log is per brackets session, not saved ### Updated Status Bar Messages - Looks like this: Uploading ... 66% (2 ok/0errors )[Queued 3] - When uploading a folder from project explorer it will show [Queueing 5...] - Add events 'queued' and 'queuedend' for this Added Log Viewer --- html/dialog-settings.html | 131 +++--- html/dialog-view-logs.html | 5 +- main.js | 857 ++++++++++++++++++++--------------- modules/BackupFilesDialog.js | 19 +- modules/SettingsDialog.js | 215 +++++++-- node/SftpUploadDomain.js | 66 ++- todo.css | 65 +++ 7 files changed, 877 insertions(+), 481 deletions(-) diff --git a/html/dialog-settings.html b/html/dialog-settings.html index 4309a01..84f651e 100644 --- a/html/dialog-settings.html +++ b/html/dialog-settings.html @@ -3,69 +3,86 @@

    {{ Strings.SETTINGS_DIALOG_TITLE }}

    {{#info}} - + diff --git a/main.js b/main.js index 33aada6..fc06478 100644 --- a/main.js +++ b/main.js @@ -32,7 +32,9 @@ define( function( require, exports, module ) { COMMAND_ID_UPLOAD_ALL = 'bigeyex.bracketsSFTPUpload.uploadAll', COMMAND_ID_DOWNLOAD_ALL = 'bigeyex.bracketsSFTPUpload.downloadAll', COMMAND_ID_VIEW_LOG = 'bigeyex.bracketsSFTPUpload.viewLog', - + COMMAND_ID_DOWNLOAD = 'bigeyex.bracketsSFTPUpload.download', + COMMAND_ID_DOWNLOAD_FTP_WALK = 'bigeyex.bracketsSFTPUpload.downloadFtpWalk', + Strings = require('modules/Strings'), dataStorage = require('modules/DataStorageManager'), settingsDialog = require('modules/SettingsDialog'), @@ -121,8 +123,10 @@ define( function( require, exports, module ) { // Register extension. CommandManager.register(Strings.EXTENSION_NAME, COMMAND_ID, togglePanel); CommandManager.register(Strings.UPLOAD_MENU_NAME, COMMAND_ID_UPLOAD, uploadMenuAction); + CommandManager.register(Strings.DOWNLOAD_MENU_NAME, COMMAND_ID_DOWNLOAD, downloadMenuAction); + CommandManager.register(Strings.DOWNLOAD_MENU_NAME_FTP_WALK, COMMAND_ID_DOWNLOAD_FTP_WALK, downloadMenuActionFtpWalk); CommandManager.register(Strings.UPLOAD_ALL, COMMAND_ID_UPLOAD_ALL, uploadAllItems); - CommandManager.register(Strings.BACKUP_ALL, COMMAND_ID_DOWNLOAD_ALL, setUpDownLoadFolder); + CommandManager.register(Strings.BACKUP_ALL, COMMAND_ID_DOWNLOAD_ALL, startBackup); CommandManager.register(Strings.VIEW_LOG, COMMAND_ID_VIEW_LOG, viewLog); // Add command to menu. @@ -132,15 +136,17 @@ define( function( require, exports, module ) { menu.addMenuItem(COMMAND_ID, 'Ctrl-Alt-Shift-U'); menu.addMenuItem(COMMAND_ID_UPLOAD, 'Ctrl-Alt-U'); menu.addMenuItem(COMMAND_ID_UPLOAD_ALL, 'Ctrl-Shift-U'); - menu.addMenuItem(COMMAND_ID_DOWNLOAD_ALL, 'Ctrl-Alt-D'); - menu.addMenuItem(COMMAND_ID_VIEW_LOG, 'Ctrl-Alt-V'); + //menu.addMenuItem(COMMAND_ID_DOWNLOAD_ALL, 'Ctrl-Alt-D'); + //menu.addMenuItem(COMMAND_ID_VIEW_LOG, 'Ctrl-Alt-V'); menu.addMenuDivider(); } - if ( contextMenu !== undefined ) { - contextMenu.addMenuDivider(); - contextMenu.addMenuItem( COMMAND_ID_UPLOAD ); - } + if (contextMenu !== undefined) { + contextMenu.addMenuDivider(); + contextMenu.addMenuItem(COMMAND_ID_UPLOAD); + contextMenu.addMenuItem(COMMAND_ID_DOWNLOAD); + contextMenu.addMenuItem(COMMAND_ID_DOWNLOAD_FTP_WALK); + } // Load stylesheet. ExtensionUtils.loadStyleSheet( module, 'todo.css' ); @@ -176,11 +182,13 @@ define( function( require, exports, module ) { enablePanel(!enabled); } - // Upload from Project Explorer Context Menu + /** + Upload from Project Explorer Context Menu + */ function uploadMenuAction() { var item = ProjectManager.getSelectedItem(), projectUrl = ProjectManager.getProjectRoot().fullPath, - remotePath = item.fullPath.replace(projectUrl, '').replace(/\\/g, "/"); + remotePath = item.fullPath.replace(projectUrl, ''); if (item.isFile) { uploadItem(item.fullPath, remotePath); } else { @@ -188,6 +196,44 @@ define( function( require, exports, module ) { } } + /** + Download from Project Explorer Context Menu + */ + function downloadMenuAction() { + var item = ProjectManager.getSelectedItem(), + projectUrl = ProjectManager.getProjectRoot().fullPath, + remotePath = item.fullPath.replace(projectUrl, ''); + + setUpDownLoadFolder(function(folder) { + if ( item.isFile ) { + downloadFile(remotePath, folder + FileUtils.getBaseName(item.fullPath), false); + } + else { + downloadFile(remotePath, folder, item.fullPath); + } + + }); + } + + /** + Download from Project Explorer Context Menu + */ + function downloadMenuActionFtpWalk() { + var item = ProjectManager.getSelectedItem(), + projectUrl = ProjectManager.getProjectRoot().fullPath, + remotePath = item.fullPath.replace(projectUrl, ''); + + setUpDownLoadFolder(function(folder) { + if ( item.isFile ) { + downloadFile(remotePath, folder + FileUtils.getBaseName(item.fullPath), false); + } + else { + downloadFile(remotePath, folder, true); + } + }); + } + + /** * Initialize extension. */ @@ -316,13 +362,13 @@ define( function( require, exports, module ) { } // backup all files in the panel to a folder - function downloadAllItems(folder) { + function downloadAllItems(toFolder) { var serverInfo = _getServerInfo(), trs = $('#brackets-sftp-upload tr .upload-button'), filelist = [], projectUrl = ProjectManager.getProjectRoot().fullPath, - basePath = _getBackupFullPath(serverInfo, folder); + basePath = _getBackupFullPath(serverInfo, toFolder); for (var i = 0; i < trs.length; i++) { var $el = $(trs[i]), @@ -347,9 +393,11 @@ define( function( require, exports, module ) { } // Opens dialog to make backup - function setUpDownLoadFolder() { - var path = _getBackupFullPath(_getServerInfo(), ''); - if ( path ) backupDialog.showDialog(downloadAllItems, path); + function setUpDownLoadFolder(callback) { + var serverInfo = _getServerInfo(), + path = _getBackupFullPath(serverInfo, ''); + + if ( path ) backupDialog.showDialog(serverInfo, callback, path); } // Get the full path of the backup folder @@ -376,14 +424,44 @@ define( function( require, exports, module ) { return basePath; } - // Test Server Connection - function testConnection(serverInfo) { - settingsDialog.updateStatus(Strings.TEST_CONNECTION_STARTING); - _nodeDomain.exec('testConnection', serverInfo) - .fail(function(err){ - settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED + ":" + err); - }); - } + function startBackup() { + setUpDownLoadFolder(downloadAllItems); + } + + function downloadFile(remotePath, localPath, walkPath) { + + var config = _getServerInfo(), + basePath = _getBackupFullPath(config, localPath); + + disableButtons(); + + _nodeDomain.exec('download', remotePath, basePath, walkPath, config) + .fail(function (err) { + status.is_downloading = false; + showUploadingIconStatus(false); + updateStatus(err); + enableButtons(); + }); + } + + function serverBrowser(remotePath) { + var config = _getServerInfo(); + status.status('Listing...'); + _nodeDomain.exec('list', remotePath || '', config) + .fail(function (err) { + status.log('Error', err); + }); + + } + + // Test Server Connection + function testConnection(serverInfo) { + settingsDialog.updateStatus(Strings.TEST_CONNECTION_STARTING); + _nodeDomain.exec('testConnection', serverInfo) + .fail(function (err) { + settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED + ":" + err); + }); + } // Disable all buttons in the panel function disableButtons() { @@ -423,8 +501,7 @@ define( function( require, exports, module ) { $projectManager = $(ProjectManager); // Listeners bound to Brackets modules. - $documentManager - .on('documentSaved.todo', function (event, document) { + DocumentManager.on('documentSaved.todo', function (event, document) { //TODO: add current document to change list var path = document.file.fullPath, projectUrl = ProjectManager.getProjectRoot().fullPath, @@ -434,7 +511,7 @@ define( function( require, exports, module ) { if (changedFiles === null) { changedFiles = {}; } - if (serverInfo !== null && serverInfo.uploadOnSave) { + if ( !serverInfo && serverInfo !== null && serverInfo.uploadOnSave) { uploadItem(path, path.replace(projectUrl, '')); return; } @@ -462,7 +539,7 @@ define( function( require, exports, module ) { }); - $projectManager.on('projectOpen', function(prj) { + ProjectManager.on('projectOpen', function(prj) { loadSettings(function() { }); @@ -508,6 +585,9 @@ define( function( require, exports, module ) { } }); }) + .on('click', '.btn-server-browse', function() { + serverBrowser(); + }) .on('click', '.btn-upload-all', function () { uploadAllItems(); }) @@ -515,7 +595,7 @@ define( function( require, exports, module ) { skipAllItems(); }) .on('click', '.btn-backup-all', function () { - setUpDownLoadFolder(); + setUpDownLoadFolder(downloadAllItems); }) .on('click', '.status-stab', function () { viewLog(); @@ -546,7 +626,7 @@ define( function( require, exports, module ) { if (ok) { settingsDialog.updateStatus(Strings.TEST_CONNECTION_SUCCESS); } else { - settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED); + settingsDialog.updateStatus(Strings.TEST_CONNECTION_FAILED + '' + msg + ''); status.log('Error', msg); } }) diff --git a/modules/BackupFilesDialog.js b/modules/BackupFilesDialog.js index cc772b1..a66896d 100644 --- a/modules/BackupFilesDialog.js +++ b/modules/BackupFilesDialog.js @@ -41,23 +41,17 @@ define( function( require, exports ) { }); Dialogs.showModalDialogUsingTemplate( compiledTemplate ); } - exports.showDialog = function(callback, localPath) { + exports.showDialog = function(serverInfo, callback, localPath) { // Compile dialog template. - var serverInfo = dataStorage.get('server_info'), - self = this, + var self = this, compiledTemplate; - if(!serverInfo || serverInfo.host === '' ){ - self.showMessage(Strings.NO_SERVER_SETUP, Strings.SERVER_SETUP_NEDEED); - } - else { - compiledTemplate= Mustache.render( bkpDialogTemplate, { - Strings: Strings, - info: $.extend({ folder: defaultFolderName}, serverInfo), - LocalPath: localPath - }); - } - + compiledTemplate= Mustache.render( bkpDialogTemplate, { + Strings: Strings, + info: $.extend({ folder: defaultFolderName}, serverInfo), + LocalPath: localPath + }); + // Save dialog to variable. dialog = Dialogs.showModalDialogUsingTemplate( compiledTemplate ); diff --git a/modules/SettingsDialog.js b/modules/SettingsDialog.js index 497e529..10c5d3a 100644 --- a/modules/SettingsDialog.js +++ b/modules/SettingsDialog.js @@ -1,3 +1,4 @@ +/*jshint node: true, jquery: true*/ define( function( require, exports ) { 'use strict'; diff --git a/nls/pt/Strings.js b/nls/pt/Strings.js index 771cdbf..075a425 100644 --- a/nls/pt/Strings.js +++ b/nls/pt/Strings.js @@ -4,15 +4,20 @@ define( { // MENUS UPLOAD_MENU_NAME: "Enviar via SFTP", - DOWNLOAD_MENU_NAME: "Baixar do Servidor", - + DOWNLOAD_MENU_NAME: "Baixar do Servidor (Apenas arquivos locais)", + DOWNLOAD_MENU_NAME_FTP_WALK: "Baixar do Servidor (Tudo do FTP)" // GENERAL. YES: "Sim", NO: "Não", OK: "Ok", + SAVE: "Salvar", CANCEL: "Cancelar", UPLOAD: "Enviar", SKIP: "Pular", + CLEAR: "Limpar", + SERVER: "Servidor", + TEST_CONNECTION: "Testar Conexão", + VIEW_LOG: "Ver Logs", // TOOLBAR. SERVER_SETUP: "Configurar Servidor", @@ -31,9 +36,14 @@ define( { SETTINGS_DIALOG_PASSWORD: "Senha", SETTINGS_DIALOG_RSAMSG: "Caminho para Chave RSA", SETTINGS_DIALOG_PATH: "Caminho no Servidor", - SETTINGS_UPLOAD_ON_SAVE: "Enviar ao salvar", - SETTINGS_DIALOG_PATH_BACKUP: "Pasta para Backups", - + SETTINGS_DIALOG_PATH_BACKUP: "Caminho para Backup", + SETTINGS_DIALOG_SERVER_NAME: "Nome", + SETTINGS_DIALOG_SERVER_LIST: "Servidores", + SETTINGS_DIALOG_SERVER_DEFAULT_NAME: "default", + SETTINGS_DIALOG_SERVER_NEW: "Novo", + SETTINGS_DIALOG_SAVE_TO_APLLY: "Clique salvar para aplicar as alterações.", + SETTINGS_DIALOG_SAVED: "Configurações salvas", + // BACKUP DIALOG BACKUP_FILES_TITLE: "SFTP - Backup de Arquivos Alterados", BACKUP_FILES_LOCAL_PATH: "Salvar em", @@ -41,5 +51,15 @@ define( { // NO SERVER SETUP DIALOG NO_SEVER_SETUP: "SFTP - Nenhuma configuração de servidor", - SERVER_SETUP_NEDEED: "Por favor realize a configuração do servidor (S)FTP antes de realizar backups ou uploads." + SERVER_SETUP_NEDEED: "Por favor realize a configuração do servidor (S)FTP antes de realizar backups ou uploads.", + NO_BACKUP_FOLDER: "No backup folder configured for this server. ", + + // Autenthication + TEST_CONNECTION_STARTING: 'Iniciando autenticação...', + TEST_CONNECTION_SUCCESS: 'Autenticação realizada com sucesso.', + TEST_CONNECTION_FAILED: 'Autenticação falhou.', + + // Log Viewer + LOG_VIEWER_TITLE: 'Log Viewer', + LOG_VIEWER_EMPTY: 'No log to show.' } ); diff --git a/nls/root/Strings.js b/nls/root/Strings.js index 23f20df..60da431 100644 --- a/nls/root/Strings.js +++ b/nls/root/Strings.js @@ -4,17 +4,21 @@ define( { // MENUS UPLOAD_MENU_NAME: "Upload via SFTP", - DOWNLOAD_MENU_NAME: "Download from Server", + DOWNLOAD_MENU_NAME: "Download from Server (Local Walk)", + DOWNLOAD_MENU_NAME_FTP_WALK: "Download from Server (FTP Walk)", // GENERAL. YES: "Yes", NO: "No", OK: "Ok", + SAVE: "Save", CANCEL: "Cancel", UPLOAD: "Upload", SKIP: "Skip", - CLEAR: "Clear", + CLEAR: "Clear", + SERVER: "Server", TEST_CONNECTION: "Test Connection", + VIEW_LOG: "View Log", // TOOLBAR. SERVER_SETUP: "Server Setup", @@ -35,22 +39,29 @@ define( { SETTINGS_DIALOG_PATH: "Server Path", SETTINGS_UPLOAD_ON_SAVE: "Upload On Save", SETTINGS_DIALOG_PATH_BACKUP: "Backup Path", - + SETTINGS_DIALOG_SERVER_NAME: "Name", + SETTINGS_DIALOG_SERVER_LIST: "Servers", + SETTINGS_DIALOG_SERVER_DEFAULT_NAME: "Default", + SETTINGS_DIALOG_SERVER_NEW: "New Server", + SETTINGS_DIALOG_SAVE_TO_APLLY: "Click save to aplly changes", + SETTINGS_DIALOG_SAVED: "Settings Saved", + // BACKUP DIALOG BACKUP_FILES_TITLE: "SFTP - Backup Changed Files", BACKUP_FILES_LOCAL_PATH: "Save To", BACKUP_FILES_START: "Start Download", // NO SERVER SETUP DIALOG - NO_SEVER_SETUP: "SFTP - No Server Setup", + NO_SERVER_SETUP: "SFTP - No Server Setup", SERVER_SETUP_NEDEED: "Please create an server setup before uploading or backup.", + NO_BACKUP_FOLDER: "No backup folder configured for this server. ", // Autenthication TEST_CONNECTION_STARTING: 'Starting authentication...', TEST_CONNECTION_SUCCESS: 'Authentication successfull', TEST_CONNECTION_FAILED: 'Authentication failed', - // Log Viewer - LOG_VIEWER_TITLE: 'Log Viewer', + // Log Viewer + LOG_VIEWER_TITLE: 'Log Viewer', LOG_VIEWER_EMPTY: 'No log to show.' } ); \ No newline at end of file diff --git a/node/SftpUploadDomain.js b/node/SftpUploadDomain.js index 921dc70..97e22b7 100644 --- a/node/SftpUploadDomain.js +++ b/node/SftpUploadDomain.js @@ -167,7 +167,26 @@ } }); } - if ( job.type !== undefined && job.type === 'download' ) // Download files + + + if (job.type !== undefined && job.type === 'list') { + clog("SFTP Listing ", fullRemotePath); + self.sftpClient.ls(fullRemotePath, function(err, res) { + clog("SFTP Listed:", res); + if ( typeof job.callback === 'function' ) { + //setTimeout(function(){ + job.callback.call(job.callback, err, res); + //}, 50); + } + else { + _domainManager.emitEvent("sftpUpload", "listed", [fullRemotePath, res]); + } + self.run(); + + //_domainManager.emitEvent() + }); + } + else if ( job.type !== undefined && job.type === 'download' ) // Download files { _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, job.localPath]); // Creates local diretory of backup @@ -192,8 +211,19 @@ else if ( job.type === 'test-connection' ) { self.sftpClient.sftp(function(err, sftp) { var isOk = err === undefined || err === null || err === false; - _domainManager.emitEvent("sftpUpload", "connection-tested", [isOk, ""]); - self.sftpClient.close(); + _domainManager.emitEvent("sftpUpload", "connection-tested", [isOk, !isOk ? (err.code +' at '+ err.level ) : '' ]); + try { + if (self.sftpClient !== undefined && self.sftpClient !== null ) { + self.sftpClient.close(); + } + } + catch(erro) { + + } + finally + { + self.run(); + } }); } else { @@ -259,15 +289,33 @@ self.run(); }); - if ( job.type !== undefined && job.type === 'download' ) // Download files + if (job.type !== undefined && job.type === 'list') { + clog("FTP Listing ", fullRemotePath); + self.ftpClient.ls(fullRemotePath, function(err, res) { + + if ( typeof job.callback === 'function' ) { + //setTimeout(function(){ + job.callback.call(job.callback, err, res); + //}, 50); + } + else { + _domainManager.emitEvent("sftpUpload", "listed", [fullRemotePath, res]); + } + self.run(); + + //_domainManager.emitEvent() + }); + } + else if ( job.type !== undefined && job.type === 'download' ) // Download files { + clog("Downloading " + fullRemotePath + " to " + job.localPath); _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, job.localPath]); _ftp_downloadFile(fullRemotePath, job.localPath, function() { self.run(); }); - } - else if ( job.type === 'test-connection' ) { + }// end Download Files + else if ( job.type === 'test-connection' ) { self.ftpClient.raw.stat(function(err, data) { clog('ftp test-connection', { err: err, @@ -281,7 +329,7 @@ } self.run(); }); - } + }// end Test Connection else // Do Upload { fs.stat(job.localPath, function(err, stats){ @@ -346,10 +394,15 @@ } }; - self.add = function(localPath, remotePath, config, jobType){ - remotePath = remotePath.replace(/\\/g, "/"); - localPath = localPath.replace(/\\/g, "/"); - self.jobQueue.push({localPath: localPath, remotePath: remotePath, config: config, type: jobType}); + self.list = function(remotePath, config, callback) { + self.add('', remotePath, config, 'list', callback); + }; + + self.add = function(localPath, remotePath, config, jobType, callback){ + remotePath = remotePath.replace(/\\/g, "/").replace(/\/+/g, "/"); + localPath = localPath.replace(/\\/g, "/").replace(/\/+/g, "/"); + clog(self.isRunning + " - Add Job", {type: jobType, local: localPath, remote: remotePath}) + self.jobQueue.push({localPath: localPath, remotePath: remotePath, config: config, type: jobType, callback: callback || false}); if(!self.isRunning){ self.run(); } @@ -366,7 +419,7 @@ if ( relativeRemotePath.indexOf('.DS_Store') > 0 ) { return next(); } - self.add(nodepath.join(root, stats.name), nodepath.join(relativeRemotePath, stats.name), config); + self.add(nodepath.join(root, stats.name), nodepath.join(relativeRemotePath, stats.name), config, 'upload'); files_added = files_added +1; tmp_count = tmp_count + 1; @@ -381,7 +434,35 @@ }); }; - self._getFullRemotePath = function(remotePath){ + self.downDirectory = function(remotePath, localPath, downPath, config){ + var walker = walk.walk(localPath, {followLinks:false, filters:[".DS_Store"]}), + files_added = 0, + trigger_on = 1, + tmp_count = 0; + + walker.on("file", function(root, stats, next){ + var relativeRemotePath = nodepath.join(remotePath, root.replace(localPath, '')), + fullDownloadPath = nodepath.join(downPath, root.replace(localPath, '')) + '/ '+ stats.name; + + if ( relativeRemotePath.indexOf('.DS_Store') > 0 ) { + return next(); + } + self.add(fullDownloadPath, nodepath.join(relativeRemotePath, stats.name), config, 'download'); + + files_added = files_added +1; + tmp_count = tmp_count + 1; + if ( tmp_count > trigger_on ) { + _domainManager.emitEvent("sftpUpload", "queued", [files_added]); + tmp_count = 0; + } + next(); + }); + walker.on('end', function() { + _domainManager.emitEvent("sftpUpload", "queuedend", [files_added]); + }); + }; + + self._getFullRemotePath = function(remotePath){ var fullRemotePath; if(/\/$/.test(self.config.serverPath)){ // if the user forget to add '/' in the path config, help with it. fullRemotePath = self.config.serverPath+remotePath; @@ -398,13 +479,19 @@ function cmdUpload(localPath, remotePath, config){ if(config === undefined) {config=null;} clog('Start Upload: ' + localPath); - sftpJobs.add(localPath, remotePath, config); + sftpJobs.add(localPath, remotePath, config, 'upload'); } + + function cmdList(remotePath, config) { + if(config === undefined) {config=null;} + clog('Start Listing: ' + remotePath); + sftpJobs.list(remotePath, config, false); + } function cmdUploadAll(filelist, config){ if(config === undefined) {config=null;} for(var i in filelist){ - sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config); + sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'upload'); } } @@ -415,6 +502,39 @@ } } + function cmdDownload(remotePath, localPath, walkPath, config){ + if(config === undefined) {config=null;} + if ( ! walkPath || walkPath === null ) { + sftpJobs.add(localPath, remotePath, config, 'download'); + } + // Walk on local path + else if ( typeof walkPath === 'string' ) { + clog('Downloading Folder: ', remotePath + ' to ' + localPath); + sftpJobs.downDirectory(remotePath, walkPath, localPath, config); + } + else if ( walkPath === true ) { + var files_added = 0; + var list = function(path) { + sftpJobs.list(path, config, function(err, files) { + files_added = files_added + files.length; + _domainManager.emitEvent("sftpUpload", "queued", [files_added]); + files.forEach(function(file) { + if ( file.type == 0 ) { // file + var downPath = localPath + '/' + path + file.name, + rpath = path+ file.name; + sftpJobs.add(downPath, rpath , config, 'download'); + } + else { + list(file.name); + } + }); + }); + }; + list(remotePath); + } + + } + function cmdTestConnection(config) { if(config === undefined) {config=null;} clog('Start Connection Test', config); @@ -446,7 +566,7 @@ type: "string", description: "(relative) path or filename of the destination"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); @@ -461,7 +581,7 @@ type: "[{localPath:string, remotePath:string},...]", description: "a list of files to be uploaded"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); @@ -473,7 +593,7 @@ false, // this command is synchronous in Node "Test the connection with the server setup", [{name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); @@ -488,7 +608,28 @@ type: "[{localPath:string, remotePath:string},...]", description: "a list of files to be downloaded"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + description: "(optional) server configuration."}], + [] + ); + + domainManager.registerCommand( + "sftpUpload", // domain name + "download", // command name + cmdDownload, // command handler function + false, // this command is synchronous in Node + "Download a list of files in a batch", + [{name: "remotePath", // parameters + type: "string", + description: "remote path to download"}, + {name: "localPath", + type: "string", + description: "remote path to download it to"}, + {name: "walkPath", // parameters + type: "object", + description: "null/false for files, local path for walk on local" }, + {name: "config", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); @@ -506,11 +647,25 @@ type: "string", description: "(relative) path or filename of the destination"}, {name: "config", // parameters - type: "{host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", description: "(optional) server configuration."}], [] ); + domainManager.registerCommand( + "sftpUpload", // domain name + "list", // command name + cmdList, // command handler function + false, // this command is synchronous in Node + "List files on a directory", + [{name: "remotePath", // parameters + type: "string", + description: "remote path to download"}, + {name: "config", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + description: "(optional) server configuration."}], + [] + ); domainManager.registerEvent( "sftpUpload", diff --git a/todo.css b/todo.css index d18a069..8561c77 100644 --- a/todo.css +++ b/todo.css @@ -2,7 +2,6 @@ color: #555; cursor: pointer; } - .brackets-sftp-upload table { width: 100%; position: relative; @@ -262,6 +261,16 @@ button.btn-server-setup > b { margin-left: 10px; } +.sftp-conn-error { + color: #852222; + display: block; + background: #090909; + border-radius: 4px; + font-size: 1.3em; + padding: 4px 6px; +} + + .sftp-clearfix:after { content: " "; display: block; From a151da7ed4461f89a6c28d0f676efeb78ef36015 Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Mon, 28 Mar 2016 12:11:13 -0300 Subject: [PATCH 05/17] read me update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a99d4b0..2023912 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ brackets-sftp-upload Extension Home: https://github.com/bigeyex/brackets-sftp-upload +Those improvements are eventually going to be merged into the extension + ### Improvements made ### * Multiple server settings per project From b73612b35c499a65041408590de126a3f879b753 Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Mon, 28 Mar 2016 12:13:47 -0300 Subject: [PATCH 06/17] readme update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2023912..c9ef466 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Those improvements are eventually going to be merged into the extension * Backup changed files * Download files - FTP Walk (All files on FTP) * Download file - Local Walk (Only files that exists locally) +* Test Connection Button & Show Connection Error * Improved Status Bar * Log dialog From bea7d35df5e054dd00c497e597e54a2e30a5a9de Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Thu, 31 Mar 2016 09:35:56 -0300 Subject: [PATCH 07/17] FTP Browser Started ftp browser; Fixed download of file paths being stuck fir dirname. Added full description to log (remotePath + localPath) --- html/browser-panel.html | 12 ++ html/panel.html | 1 + main.js | 229 ++++++++++++++++++++++++++------------- nls/root/Strings.js | 4 +- node/SftpUploadDomain.js | 52 +++++++-- todo.css | 44 ++++++++ 6 files changed, 252 insertions(+), 90 deletions(-) create mode 100644 html/browser-panel.html diff --git a/html/browser-panel.html b/html/browser-panel.html new file mode 100644 index 0000000..b86c841 --- /dev/null +++ b/html/browser-panel.html @@ -0,0 +1,12 @@ +
    +
    + + + × +
    + +
    + +
      +
      +
      \ No newline at end of file diff --git a/html/panel.html b/html/panel.html index 241b302..2e85b63 100644 --- a/html/panel.html +++ b/html/panel.html @@ -5,6 +5,7 @@
      +
      diff --git a/main.js b/main.js index fc06478..d35f477 100644 --- a/main.js +++ b/main.js @@ -6,25 +6,25 @@ * @author Mikael Jorhult * @license http://mikaeljorhult.mit-license.org MIT */ -define( function( require, exports, module ) { - 'use strict'; - - // Get dependencies. - var Async = brackets.getModule( 'utils/Async' ), - Menus = brackets.getModule( 'command/Menus' ), - CommandManager = brackets.getModule( 'command/CommandManager' ), - Commands = brackets.getModule( 'command/Commands' ), - PreferencesManager = brackets.getModule( 'preferences/PreferencesManager' ), - ProjectManager = brackets.getModule( 'project/ProjectManager' ), - EditorManager = brackets.getModule( 'editor/EditorManager' ), - DocumentManager = brackets.getModule( 'document/DocumentManager' ), - WorkspaceManager = brackets.getModule( 'view/WorkspaceManager' ), - Resizer = brackets.getModule( 'utils/Resizer' ), - AppInit = brackets.getModule( 'utils/AppInit' ), - FileUtils = brackets.getModule( 'file/FileUtils' ), - FileSystem = brackets.getModule( 'filesystem/FileSystem' ), - ExtensionUtils = brackets.getModule( 'utils/ExtensionUtils' ), - NodeDomain = brackets.getModule("utils/NodeDomain"), +define(function (require, exports, module) { + 'use strict'; + + // Get dependencies. + var Async = brackets.getModule('utils/Async'), + Menus = brackets.getModule('command/Menus'), + CommandManager = brackets.getModule('command/CommandManager'), + Commands = brackets.getModule('command/Commands'), + PreferencesManager = brackets.getModule('preferences/PreferencesManager'), + ProjectManager = brackets.getModule('project/ProjectManager'), + EditorManager = brackets.getModule('editor/EditorManager'), + DocumentManager = brackets.getModule('document/DocumentManager'), + WorkspaceManager = brackets.getModule('view/WorkspaceManager'), + Resizer = brackets.getModule('utils/Resizer'), + AppInit = brackets.getModule('utils/AppInit'), + FileUtils = brackets.getModule('file/FileUtils'), + FileSystem = brackets.getModule('filesystem/FileSystem'), + ExtensionUtils = brackets.getModule('utils/ExtensionUtils'), + NodeDomain = brackets.getModule("utils/NodeDomain"), // Extension basics. COMMAND_ID = 'bigeyex.bracketsSFTPUpload.enable', @@ -41,18 +41,21 @@ define( function( require, exports, module ) { backupDialog = require('modules/BackupFilesDialog'), logsDialog = require('modules/LogViewerDialog'), - // Preferences. - preferences = PreferencesManager.getExtensionPrefs( 'bigeyex.bracketsSFTPUpload' ), + // Preferences. + preferences = PreferencesManager.getExtensionPrefs('bigeyex.bracketsSFTPUpload'), // Mustache templates. todoPanelTemplate = require('text!html/panel.html'), todoRowTemplate = require('text!html/row.html'), + browserPanelTemplate = require('text!html/browser-panel.html'), // Setup extension. serverInfo, //sftp username/password etc; $todoPanel, projectUrl, $todoIcon = $(''), + $statusIndicator, + $browserPanel, // Get view menu. menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU), @@ -81,16 +84,16 @@ define( function( require, exports, module ) { this.log('Error', msg); }, - downloaded: function (msg) { + downloaded: function (remoteFile, localFile) { this.itens_ok = this.itens_ok + 1; this.itens_completed = this.itens_completed + 1; - this.log('Downloaded', msg); + this.log('Downloaded', localFile + ' --> ' + remoteFile); }, - uploaded: function (msg) { + uploaded: function (remoteFile, localFile) { this.itens_ok = this.itens_ok + 1; this.itens_completed = this.itens_completed + 1; - this.log('Uploaded', msg); + this.log('Uploaded', localFile + ' --> ' + remoteFile); }, log: function (type, text) { @@ -113,12 +116,12 @@ define( function( require, exports, module ) { }; - // Define preferences. - preferences.definePreference( 'enabled', 'boolean', false ); + // Define preferences. + preferences.definePreference('enabled', 'boolean', false); - // Get Node module domain - var _domainPath = ExtensionUtils.getModulePath(module, "node/SftpUploadDomain"); - var _nodeDomain = new NodeDomain("sftpUpload", _domainPath); + // Get Node module domain + var _domainPath = ExtensionUtils.getModulePath(module, "node/SftpUploadDomain"); + var _nodeDomain = new NodeDomain("sftpUpload", _domainPath); // Register extension. CommandManager.register(Strings.EXTENSION_NAME, COMMAND_ID, togglePanel); @@ -148,8 +151,8 @@ define( function( require, exports, module ) { contextMenu.addMenuItem(COMMAND_ID_DOWNLOAD_FTP_WALK); } - // Load stylesheet. - ExtensionUtils.loadStyleSheet( module, 'todo.css' ); + // Load stylesheet. + ExtensionUtils.loadStyleSheet(module, 'todo.css'); /** * Get saved serverInfo @@ -206,12 +209,11 @@ define( function( require, exports, module ) { setUpDownLoadFolder(function(folder) { if ( item.isFile ) { - downloadFile(remotePath, folder + FileUtils.getBaseName(item.fullPath), false); + downloadFile(remotePath, folder +'/'+ FileUtils.getBaseName(item.fullPath), false, true); } else { - downloadFile(remotePath, folder, item.fullPath); + downloadFile(remotePath, folder, item.fullPath, false); } - }); } @@ -225,14 +227,20 @@ define( function( require, exports, module ) { setUpDownLoadFolder(function(folder) { if ( item.isFile ) { - downloadFile(remotePath, folder + FileUtils.getBaseName(item.fullPath), false); + downloadFile(remotePath, folder +'/'+ FileUtils.getBaseName(item.fullPath), false, true); } else { - downloadFile(remotePath, folder, true); + downloadFile(remotePath, folder, true, false); } }); } + /** + * Resize Browser Panel + */ + function resizeBrowserPanel() { + $browserPanel.height(($("#editor-holder").height() - 24) + 'px'); + } /** * Initialize extension. @@ -243,9 +251,10 @@ define( function( require, exports, module ) { // Show panel. Resizer.show($todoPanel); }); - + // Set active class on icon. $todoIcon.addClass('active'); + enableButtons(); } else { // Hide panel. Resizer.hide($todoPanel); @@ -401,7 +410,7 @@ define( function( require, exports, module ) { } // Get the full path of the backup folder - function _getBackupFullPath(serverInfo, folder) { + function _getBackupFullPath(serverInfo, folder, isFile) { var projectUrl = ProjectManager.getProjectRoot().fullPath, basePath; @@ -415,9 +424,9 @@ define( function( require, exports, module ) { } if (serverInfo.backupPath.indexOf(":") > -1) { // full dir - basePath = serverInfo.backupPath + folder + "/"; + basePath = serverInfo.backupPath + folder + (isFile !== true ? "/" : ''); } else { - basePath = projectUrl + serverInfo.backupPath + "/" + folder + "/"; + basePath = projectUrl + serverInfo.backupPath + "/" + folder + (isFile !== true ? "/" : ''); } // replace any '//' to '/' basePath = basePath.replace(/\/+/g, "/"); @@ -428,11 +437,12 @@ define( function( require, exports, module ) { setUpDownLoadFolder(downloadAllItems); } - function downloadFile(remotePath, localPath, walkPath) { + function downloadFile(remotePath, localPath, walkPath, isFile) { var config = _getServerInfo(), - basePath = _getBackupFullPath(config, localPath); + basePath = _getBackupFullPath(config, localPath, isFile); + status.is_downloading = true; disableButtons(); _nodeDomain.exec('download', remotePath, basePath, walkPath, config) @@ -444,14 +454,53 @@ define( function( require, exports, module ) { }); } - function serverBrowser(remotePath) { + function listRemoteDir(remotePath) { var config = _getServerInfo(); status.status('Listing...'); + $browserPanel.show(); + resizeBrowserPanel(); _nodeDomain.exec('list', remotePath || '', config) .fail(function (err) { status.log('Error', err); }); + } + + function startServerBrowser() { + var config = _getServerInfo(); + $("div.sftp-update-browser-holder > span", $browserPanel).html(config.serverPath); + $("div.sftp-update-browser-holder > ul", $browserPanel).empty(); + listRemoteDir(); + } + function showListedItems(err, path, files) { + var html = ''; + files.sort(function(a,b) { + if ( a.type == 1 && b.type !== 1 ) return -1; + else if ( a.type === 0 && b.type === 1 ) return 1; + else { + if(a.name < b.name) return -1; + else if(a.name > b.name) return 1; + else return 0; + } + }).forEach(function(file) { + var css = ''; + if ( file.type == 1 ) { // folder + css += 'folder'; + } + html += '
    • '; + }); + + var $mainUl = $(".sftp-update-browser-holder > ul", $browserPanel); + + if ( $mainUl.is(':empty') ) { + $mainUl.append(html); + } + else { + var $li = $('li[data-path="'+path+'"]', $mainUl); + if ( $li ) { + $li.append('
        '+html+' b { height: 0; clear: both; *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML += '
        ' ); +} + +#sftp-update-browser { + position: absolute; + right: 29px; + top: 0; + z-index: 999; + width: 250px; + background: #2c2c2c; + min-height: 450px; + padding: 6px; + display: none; + box-sizing: border-box; + overflow: auto; +} +#sftp-update-browser * { box-sizing: border-box; } + +#sftp-update-browser a.close { position: absolute; top: 3px; right: 3px;} + +#sftp-update-browser > .header button, +#sftp-update-browser > .header label { + display: inline-block; } + + +#sftp-update-browser ul { list-style-type: none; padding: 0; margin: 0; } + +#sftp-update-browser ul li.folder > label:before { + content: " + "; + padding: 4px; + margin-right: 4px; +} + +#sftp-update-browser ul li.folder.open > label:before { + content: " - "; + padding: 4px; + margin-right: 4px; +} + +#sftp-update-browser ul li:not(.folder) > label { + margin-left: 10px; +} + +#sftp-update-browser ul li.folder > ul { + margin-left: 10px; } \ No newline at end of file From d70d877271df5bb9ae700522a08803a660c086d9 Mon Sep 17 00:00:00 2001 From: alemonteiro Date: Thu, 31 Mar 2016 10:13:59 -0300 Subject: [PATCH 08/17] fix upload on save --- main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.js b/main.js index d35f477..a68fc94 100644 --- a/main.js +++ b/main.js @@ -560,7 +560,7 @@ define(function (require, exports, module) { if (changedFiles === null) { changedFiles = {}; } - if ( !serverInfo && serverInfo !== null && serverInfo.uploadOnSave) { + if ( serverInfo && serverInfo !== null && serverInfo.uploadOnSave) { uploadItem(path, path.replace(projectUrl, '')); return; } From d5c02ae1cb695dc8455347375e967b1afdb28546 Mon Sep 17 00:00:00 2001 From: ale Date: Mon, 20 Jun 2016 07:17:44 -0300 Subject: [PATCH 09/17] Bug Fixes; Transactions Tab; More options for backup settings; Browser download --- .DS_Store | Bin 0 -> 10244 bytes .gitignore | 9 +- README.md | 10 +- html/.DS_Store | Bin 0 -> 6148 bytes html/browser-panel.html | 4 +- html/dialog-backup-files.html | 11 +- html/dialog-settings.html | 36 ++- html/dialog-view-logs.html | 8 +- html/indicator.html | 5 + html/panel.html | 29 ++- html/row-transaction.html | 7 + images/.DS_Store | Bin 0 -> 6148 bytes main.js | 299 +++++++++++++++--------- modules/.DS_Store | Bin 0 -> 6148 bytes modules/BackupFilesDialog.js | 48 +++- modules/DataStorageManager.js | 19 +- modules/LogViewerDialog.js | 25 +- modules/SettingsDialog.js | 73 +++++- nls/.DS_Store | Bin 0 -> 6148 bytes nls/it/.DS_Store | Bin 0 -> 6148 bytes nls/root/Strings.js | 21 +- node/.DS_Store | Bin 0 -> 6148 bytes node/SftpUploadDomain.js | 414 +++++++++++++++++++--------------- todo.css | 50 +++- 24 files changed, 701 insertions(+), 367 deletions(-) create mode 100644 .DS_Store create mode 100644 html/.DS_Store create mode 100644 html/indicator.html create mode 100644 html/row-transaction.html create mode 100644 images/.DS_Store create mode 100644 modules/.DS_Store create mode 100644 nls/.DS_Store create mode 100644 nls/it/.DS_Store create mode 100644 node/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bd520b833d3cb87e6db9a025c9ba259e0d019dc0 GIT binary patch literal 10244 zcmeHMYitx%6h7y+w6icvrxb(*g%yYtsL&S5Q>0I@mP+mR4N`V@20AjGX?C_Pu#(hQ z;ycC%;18py_>3A8-;W=@O*GLTs{wx)-#?5-<0C#2g6H0uUA9{$CK?TibCbE}&b{Z{ znf>nl?m1@`0I+^otpW%GfJ7IUicHmM3Lod!gu>jOIV6$nq1mwFF~f?{y)r@D@9+`u z5%3Z45%3Z45jYbNAfL^PG{upA?IYkL;3JSlfS(Uxy11-$<(MPI(Lt3+0Z0~7w7f)x~j$8c3U(#kZE^VmXU2oV_mv7+OJG+ zu*_ssH?>5L>Gp2jRISl^YuHrn?Gb0bZe2|d^eZ#k650rvwna^?OSkoyZs^H<0V-0U zUzwRoRoASo2(MUmpdy@Fy}Gg@ymD3Lfdk56Nt&~`rmnSj=)ev4-T%PR2OoO)wKv2s z26T@bD0A+!^_$en;-T7cBSyb~k7heZA_>#5%-z(-Cn*A*AdbRr(7?_E`aK%wKo__` zkJI(R1`hT(OmYDqH;@NHZmXn-cT1R~Hh9(HW!u%8r#S^&jjfpjoo8C;&fNOoWaKXq5RU}tMK0*BmJhZ7 z+eIT6WVb61+(H7E?^SIgUj)39vi`u;%K`Z7j6XP*^#^qP1_LF*f8QJYl>?ZSN>#0? zs;LOCsT}VCBq_9L#m1IyGj;nNcOE=+_^zkLd2s6VFLmy-^)uAUqLd40w$rdj+8h^I za3llC$5}`wPmzODcl7U^8I}8$Y20OP9ZKq!X?JM}n`FOIVw3M|j$5Yd()yLsc+`jw z8_}dzXBZKEzh-yGEn|4lw7GUXVHrl7W$S#J-kzkkH_3G-4E6NcRwCIT4108%-_cTr zZLM9S$@LMfkse_y7?2(9jI=hCH)-g!@%P>m21Sw>N6XHB;5i z-F@VU&7{6d*AjtJ+!yFDqk~$yEHr!0*}=K;DLuz7Gs||Bp4Dop+)kC0X9DT6bLTHu z7@QmQve?Eg8WI}SswAb$$`>zL8a&_g0Ub7hASqFrxU#Bxg^!VDk`UbhlQ?+}U69$$3u?=qW=>C~ z(-WYq>>Q|uM(BZ^kbo52Oo7S~cp9FC=iqsGosQfzd<qS5zP$ zT<*0k#fhOnI<#bI#reVIo?BjFbVf+&Q1yzHHNn-MR8|TE<3sD#U$8;m=snvc!QoJS zLt~S?*?YD^aVmr^ZrRc*Z}pz7NRT|#9_i=|c6+Nyf~cXsZQG{=mwP@`3gnRSZ`1Q# zBIj}V3cew7{sJe6m?4}`w5-N8Sc~=8fSYhLwh=XV-~j4q5IHT}i&x=wcq`t9x8t37 z5bwc9@JS-(3-}_wjIZEZ_yLjg6Z{lE!!Phl{0@J`6GYBpCb7wE3Y*U6vW2XIEn~}x zq}6OaYho=d!a9kjJ*=0-m?3DIVpp(h*)8l4yVoURhM=l*pQ+gqYGnzU7p%xIL|IiF z_PDu~2;C`sG4p~K3g1QW!rb5`0PU0()X~w_N^%*6=jwP1;353pob*7VB$XjsO-mMjGpBp3M21KPCUx9;Rz2 zUA%C;F-Hm$s>J7blHzkb-SE%x!f#QZ8%zqjTI%QaV~(U2mH+(DfdA#^N;xDAs5lfwjUG{V@6=8N4~SxGw7A0&mbk^LXQ997(r@3#3=g>e>v=?T-n2K5%vpW2HRp9Br^14}zHEz^ zi;Z~QCnXt329kkfAQ|`x1H7|Usy)Zl$v`rY416-6=R@I8tOGkoJ36SW1t1RTHleLg zW6ddnbztYn8H#u+(NiT_4DodOOT^WIouj8iqWO^6`J;Ie+nwtd3y0K>sgr?ZV4VT& zeJLZo|4;ds>22~YBvmqy4E$FHWH`B;j9FdWt>5a@yS8v#aj0lqrv`=g+9QBJ^c*>` dNuMujGp-Ko9Ca1-TRJfx0!B!xWZ)MVcn7XRIadGx literal 0 HcmV?d00001 diff --git a/html/browser-panel.html b/html/browser-panel.html index b86c841..5807e41 100644 --- a/html/browser-panel.html +++ b/html/browser-panel.html @@ -4,9 +4,9 @@ ×
      - +
        - \ No newline at end of file + diff --git a/html/dialog-backup-files.html b/html/dialog-backup-files.html index d2a9358..9e0d641 100644 --- a/html/dialog-backup-files.html +++ b/html/dialog-backup-files.html @@ -1,17 +1,12 @@ -
        +
        -
        -
        - - +
        +
        +
        +
        + + + + ? +
        +
        + +
        +
        + +
        +
        {{/info}} diff --git a/html/dialog-view-logs.html b/html/dialog-view-logs.html index 843ef74..235d7a4 100644 --- a/html/dialog-view-logs.html +++ b/html/dialog-view-logs.html @@ -2,16 +2,16 @@ - + - + - - \ No newline at end of file + + diff --git a/html/indicator.html b/html/indicator.html new file mode 100644 index 0000000..bf0f95e --- /dev/null +++ b/html/indicator.html @@ -0,0 +1,5 @@ +
        +
        +
        +
        +
        diff --git a/html/panel.html b/html/panel.html index 2e85b63..ad068f9 100644 --- a/html/panel.html +++ b/html/panel.html @@ -1,6 +1,12 @@
        {{ strings.EXTENSION_NAME }}
        +
        +
          +
        • {{ strings.MODIFICATIONS }}
        • +
        • {{ strings.TRANSACTIONS }}
        • +
        +
        @@ -11,16 +17,25 @@ +
        ×
        -
        - - - -
        +
        +
        + + + +
        +
        -
        -
        \ No newline at end of file +
        + + + +
        +
        +
        + diff --git a/html/row-transaction.html b/html/row-transaction.html new file mode 100644 index 0000000..7d25365 --- /dev/null +++ b/html/row-transaction.html @@ -0,0 +1,7 @@ + + {{ type }} + {{ localPath }} + {{ signal }} + {{ fullRemotePath }} + {{ status }} + diff --git a/images/.DS_Store b/images/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4770db77d25973e291c3b3575457ccf36c5083db GIT binary patch literal 6148 zcmeHK%SuB*3_Y=36s6Fm%UQZn@DGMk1-JSG(pIHVyv4Sz?+5x%dh$?gz2HI+kpz;H zW|EmZ2RbtWAmi=)92fx@P!&a;4$*Mu&_N{kh+=b`Vu2YNJmRclqQ4l@Zy#cfdu*`6 z=kH(R84p*>W;R_mQ)Veem(-J26MDcQD_3~pt~a>jp1W#Z_G*UAZ7`>PvzlD*RqBc< z$v`rY3?u`|z)uF72LpOO6slqkY#r_Bps^N!*k{;;zCM(-rUcf& z){!F=@lv9fO0*c_<&2letAVYfmqViYkXZS>c@bNk^A}5pRL8W*Kr*n)fcCzWk>39o z{L6GU`IeF<8At~HD+AJ>+)T#YUEHl-_NjMmq25weG_O^MLVxEGz#n>!9NVCe7xkG} X16xO(MdMaZ%!hyxk|r7W1qR*#Dor>W literal 0 HcmV?d00001 diff --git a/main.js b/main.js index a68fc94..789e16e 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,5 @@ -/*jshint node: true, jquery: true*/ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ +/*global define, $, brackets, window, Mustache */ /*! * Brackets Todo 0.5.3 * Display all todo comments in current document or project. @@ -19,12 +20,14 @@ define(function (require, exports, module) { EditorManager = brackets.getModule('editor/EditorManager'), DocumentManager = brackets.getModule('document/DocumentManager'), WorkspaceManager = brackets.getModule('view/WorkspaceManager'), + Mustache = brackets.getModule("thirdparty/mustache/mustache"), Resizer = brackets.getModule('utils/Resizer'), AppInit = brackets.getModule('utils/AppInit'), FileUtils = brackets.getModule('file/FileUtils'), FileSystem = brackets.getModule('filesystem/FileSystem'), ExtensionUtils = brackets.getModule('utils/ExtensionUtils'), NodeDomain = brackets.getModule("utils/NodeDomain"), + StatusBar = brackets.getModule('widgets/StatusBar'), // Extension basics. COMMAND_ID = 'bigeyex.bracketsSFTPUpload.enable', @@ -47,7 +50,9 @@ define(function (require, exports, module) { // Mustache templates. todoPanelTemplate = require('text!html/panel.html'), todoRowTemplate = require('text!html/row.html'), + transactionRowTemplate = require('text!html/row-transaction.html'), browserPanelTemplate = require('text!html/browser-panel.html'), + indicatorTemplate = require('text!html/indicator.html'), // Setup extension. serverInfo, //sftp username/password etc; @@ -56,6 +61,7 @@ define(function (require, exports, module) { $todoIcon = $(''), $statusIndicator, $browserPanel, + $indicator, // Get view menu. menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU), @@ -76,24 +82,57 @@ define(function (require, exports, module) { this.itens_length = length; this.queuing = false; this.queuing_fisined = false; + $("#sftp-transactions-tbody").empty(); + this.status(); }, - error: function (msg) { + error: function (msg, jobId) { this.itens_error = this.itens_error + 1; this.itens_completed = this.itens_completed + 1; this.log('Error', msg); + + var $tr = this.getTransactionRow(jobId); + $tr.removeClass("processing") + .addClass("error") + .children('td.status') + .html( msg ); + + this.status(); }, - downloaded: function (remoteFile, localFile) { - this.itens_ok = this.itens_ok + 1; - this.itens_completed = this.itens_completed + 1; - this.log('Downloaded', localFile + ' --> ' + remoteFile); + getTransactionRow: function(jobId) { + return $('tr[data-job-id='+jobId+']', $("#sftp-transactions-tbody")); }, - uploaded: function (remoteFile, localFile) { + jobQueued: function(job) { + this.itens_length = this.itens_length + 1; + if ( job.type == "upload" ) job.signal = "-->"; + else job.signal = "<--"; + job.status = Strings.QUEUED; + $("#sftp-transactions-tbody").append(Mustache.render(transactionRowTemplate, job)); + this.status(); + }, + + processing: function(jobId) { + var $tr = this.getTransactionRow(jobId); + $tr.addClass("processing") + .children('td.status') + .html( Strings.PROCESSING ); + }, + + completed: function(jobId) { this.itens_ok = this.itens_ok + 1; this.itens_completed = this.itens_completed + 1; - this.log('Uploaded', localFile + ' --> ' + remoteFile); + var $tr = this.getTransactionRow(jobId); + $tr.removeClass("processing") + .addClass("completed") + .children('td.status') + .html( Strings.FINISHED ); + + this.status(); + if ( $tr.data('type') === 'upload' ) { + skipItem($.trim($tr.find('td.localPath').text())); + } }, log: function (type, text) { @@ -109,9 +148,12 @@ define(function (require, exports, module) { status: function () { var perc = this.itens_length > 0 ? Math.floor((this.itens_completed * 100) / this.itens_length) : 0; - return (' ' + perc + '% (' + this.itens_ok + ' ok/' + this.itens_error + ' errors)' + - (this.queuing === true ? '[Queuing ' + this.itens_length + '...]' : - (this.queuing_fisined === true ? '[Queued '+this.itens_length+']' : ''))); + var str = this.itens_length > 0 ? ((' ' + perc + '% (' + this.itens_ok + ' ok/' + this.itens_error + ' errors)' + + (this.queuing === true ? ('[ ' + Strings.QUEUING + ' ' + this.itens_length + '...]' ) : + (this.queuing_fisined === true ? ('[' + Strings.QUEUED + ' ' +this.itens_length+']') : '')))) : Strings.NO_QUEUE; + + $('#brackets-sftp-upload .status-stab').text(str); + $('div.label',$indicator).html(str); } }; @@ -159,16 +201,21 @@ define(function (require, exports, module) { */ function _getServerInfo() { var serverInfo = dataStorage.get('server_list'); - if ( ! serverInfo || serverInfo === undefined || serverInfo == "" ) + if ( ! serverInfo || serverInfo === undefined || serverInfo === "" ) serverInfo = dataStorage.get('server_info'); if ( typeof serverInfo === 'object' && serverInfo.hasOwnProperty('servers')) { return serverInfo.servers[serverInfo.selected_id]; } else if ( typeof serverInfo === 'object') { - if (serverInfo.backupPath === undefined) { - serverInfo.name = "default"; - serverInfo.backupPath = settingsDialog.getFolder(); + if ( serverInfo.backupPath === undefined || serverInfo.backup === undefined ) { + if ( serverInfo.backupPath === undefined ) serverInfo.name = "default"; + serverInfo.backup = { + enabled: false, + path: serverInfo.backupPath || settingsDialog.getFolder(), + byDate: true, + alwaysPrompt: false + }; } return serverInfo; } @@ -327,25 +374,18 @@ define(function (require, exports, module) { // upload ONE file to the server function uploadItem(localPath, remotePath) { var serverInfo = _getServerInfo(); - status.reset(1); + //status.reset(1); showUploadingIconStatus(true); - _nodeDomain.exec('upload', localPath, remotePath, serverInfo).fail(function (err) { - showUploadingIconStatus(false); - updateStatus(err); - }); + _nodeDomain.exec('upload', localPath, remotePath, serverInfo); } // upload ONE dir to the server function uploadDirectory(localPath, remotePath) { - status.reset(); + //status.reset(); status.queuing = true; var serverInfo = _getServerInfo(); showUploadingIconStatus(true); - _nodeDomain.exec('uploadDirectory', localPath, remotePath, serverInfo).fail(function (err) { - status.log('Error', err); - showUploadingIconStatus(false); - updateStatus(err); - }); + _nodeDomain.exec('uploadDirectory', localPath, remotePath, serverInfo); } // upload all files in the panel to the server @@ -361,52 +401,38 @@ define(function (require, exports, module) { }); } - status.reset(filelist.length); + //status.reset(filelist.length); showUploadingIconStatus(true); - _nodeDomain.exec('uploadAll', filelist, serverInfo).fail(function (err) { - showUploadingIconStatus(false); - updateStatus(err); - }); + _nodeDomain.exec('uploadAll', filelist, serverInfo); } // backup all files in the panel to a folder function downloadAllItems(toFolder) { - var serverInfo = _getServerInfo(), trs = $('#brackets-sftp-upload tr .upload-button'), filelist = [], - projectUrl = ProjectManager.getProjectRoot().fullPath, - basePath = _getBackupFullPath(serverInfo, toFolder); + projectUrl = ProjectManager.getProjectRoot().fullPath; for (var i = 0; i < trs.length; i++) { var $el = $(trs[i]), filePath = $el.attr('x-file').replace(projectUrl, ''); filelist.push({ - localPath: (basePath + filePath), + localPath: (toFolder + filePath), remotePath: $el.attr('r-file') }); } - status.reset(filelist.length, true); - - disableButtons(); - _nodeDomain.exec('downloadAll', filelist, serverInfo) - .fail(function (err) { - status.is_downloading = false; - showUploadingIconStatus(false); - updateStatus(err); - enableButtons(); - }); + _nodeDomain.exec('downloadAll', filelist, serverInfo); } // Opens dialog to make backup - function setUpDownLoadFolder(callback) { + function setUpDownLoadFolder(callback, forBackup) { var serverInfo = _getServerInfo(), - path = _getBackupFullPath(serverInfo, ''); + path = forBackup !== false ? _getBackupFullPath(serverInfo, '') : dataStorage.getProjectUrl(); - if ( path ) backupDialog.showDialog(serverInfo, callback, path); + if ( path ) backupDialog.showDialog(serverInfo, callback, path ); } // Get the full path of the backup folder @@ -418,15 +444,23 @@ define(function (require, exports, module) { backupDialog.showMessage(Strings.NO_SERVER_SETUP, Strings.SERVER_SETUP_NEDEED); return false; } - else if ( !serverInfo.backupPath || serverInfo.backupPath === undefined || serverInfo.backupPath === "" ) { + else if ( serverInfo.backup === undefined || !serverInfo.backup.path || serverInfo.backup.path === undefined || serverInfo.backup.path === "" ) { backupDialog.showMessage(Strings.NO_SERVER_SETUP, Strings.NO_BACKUP_FOLDER); return false; } + folder = folder || ''; + var path = serverInfo.backup.path; + + if (path.lastIndexOf("/") !== path.length-1) { + path += "/"; + } - if (serverInfo.backupPath.indexOf(":") > -1) { // full dir - basePath = serverInfo.backupPath + folder + (isFile !== true ? "/" : ''); + if ( serverInfo.backup.byDate ) path += backupDialog.getDateFolderName(); + + if ( path.indexOf("/") === 0 || path.indexOf(":") > -1) { // full dir + basePath = path + folder + (isFile !== true ? "/" : ''); } else { - basePath = projectUrl + serverInfo.backupPath + "/" + folder + (isFile !== true ? "/" : ''); + basePath = projectUrl + path + "/" + folder + (isFile !== true ? "/" : ''); } // replace any '//' to '/' basePath = basePath.replace(/\/+/g, "/"); @@ -434,24 +468,19 @@ define(function (require, exports, module) { } function startBackup() { - setUpDownLoadFolder(downloadAllItems); + var objServer = _getServerInfo(); + if ( objServer.backup.alwaysPrompt !== false ) { + setUpDownLoadFolder(downloadAllItems); + } + else { + var path = _getBackupFullPath(objServer); + downloadAllItems(path); + } } function downloadFile(remotePath, localPath, walkPath, isFile) { - - var config = _getServerInfo(), - basePath = _getBackupFullPath(config, localPath, isFile); - - status.is_downloading = true; - disableButtons(); - - _nodeDomain.exec('download', remotePath, basePath, walkPath, config) - .fail(function (err) { - status.is_downloading = false; - showUploadingIconStatus(false); - updateStatus(err); - enableButtons(); - }); + var config = _getServerInfo(); + _nodeDomain.exec('download', remotePath, localPath, walkPath, config); } function listRemoteDir(remotePath) { @@ -459,10 +488,7 @@ define(function (require, exports, module) { status.status('Listing...'); $browserPanel.show(); resizeBrowserPanel(); - _nodeDomain.exec('list', remotePath || '', config) - .fail(function (err) { - status.log('Error', err); - }); + _nodeDomain.exec('list', remotePath || '', config); } function startServerBrowser() { @@ -486,8 +512,10 @@ define(function (require, exports, module) { var css = ''; if ( file.type == 1 ) { // folder css += 'folder'; + }else { + css += 'file'; } - html += '
      • '; + html += '
      • '; }); var $mainUl = $(".sftp-update-browser-holder > ul", $browserPanel); @@ -538,10 +566,6 @@ define(function (require, exports, module) { dataStorage.set('changed_files', {}); } - // Upda₢te Panel Status - function updateStatus(status) { - $('#brackets-sftp-upload .status-stab').text(status); - } /** * Listen for save or refresh and look for todos when needed. */ @@ -589,6 +613,7 @@ define(function (require, exports, module) { }); ProjectManager.on('projectOpen', function(prj) { + dataStorage.setProjectUrl(ProjectManager.getProjectRoot().fullPath); loadSettings(function() { }); @@ -602,12 +627,74 @@ define(function (require, exports, module) { }); } + // Shows browser panel context menu + function showContextMenu(evt, $li) { + var path = $li.data('path'), + type = $li.hasClass("folder") ? "folder" : 'file', + isOpen = type === 'folder' && $li.hasClass('open'), + actions = { + 'folder' : [ + {action: 'toggle-folder', label: (isOpen ? Strings.CLOSE : Strings.OPEN) + " " + Strings.FOLDER}, + {action: 'download-folder', label: Strings.DOWNLOAD + " " + Strings.FOLDER} + ], + 'file': [ + {action: 'download-file', label: Strings.DOWNLOAD + " " + Strings.FILE} + ] + }, + html = ''; + + var $ul = $(html); + + $ul.appendTo("body").css({ + position: 'absolute', + top: evt.pageY +'px', + left: evt.pageX +'px', + 'z-index': 9999 + }); + + $ul.on('mousedown', 'a', function(evt) { + evt.stopPropagation(); + evt.preventDefault(); + var $a = $(this), + act = $a.parent().data("action"); + if (act === "download-file") { + setUpDownLoadFolder(function(folder) { + downloadFile(path, folder, false, true); + }, false); + } + else if (act === 'download-folder') { + setUpDownLoadFolder(function(folder) { + downloadFile(path, folder, true, false); + }, false); + } + else if (act === 'toggle-folder') { + $li.trigger('click'); + } + $ul.remove(); + }) + .on('blur', function(evt){ + $(this).remove(); + }) + .focus(); + + } + // Register panel and setup event listeners. AppInit.appReady(function () { var panelHTML = Mustache.render(todoPanelTemplate, { strings: Strings }); + dataStorage.setProjectUrl(ProjectManager.getProjectRoot().fullPath); + // Create and cache todo panel. WorkspaceManager.createBottomPanel('bigeyex.bracketsSFTPUpload.panel', $(panelHTML), 100); $todoPanel = $('#brackets-sftp-upload'); @@ -621,6 +708,11 @@ define(function (require, exports, module) { // Setup listeners. registerListeners(); + $indicator = $(Mustache.render(indicatorTemplate, { + Strings: Strings + })); + StatusBar.addIndicator('bigeyex.sftpUpload.connIndicator', $indicator, true, 'brackets-sftp-upload-indicator'); + $browserPanel = $(Mustache.render(browserPanelTemplate, { Strings: Strings })); @@ -640,6 +732,9 @@ define(function (require, exports, module) { else { $li.children('ul').remove(); } + }) + .on('contextmenu', 'li', function(evt) { + showContextMenu(evt, $(this)); }); // Add listener for toolbar icon.. @@ -655,6 +750,14 @@ define(function (require, exports, module) { } }); }) + .on('click', '.tabs > ul > li', function() { + var $li = $(this), + tab = $li.data('tab'), + $tab = $('div.table-container.'+tab, $todoPanel); + + $tab.addClass("selected").siblings('.table-container').removeClass("selected"); + $li.addClass("selected").siblings('li.selected').removeClass("selected"); + }) .on('click', '.btn-server-browse', function() { startServerBrowser(); }) @@ -665,7 +768,10 @@ define(function (require, exports, module) { skipAllItems(); }) .on('click', '.btn-backup-all', function () { - setUpDownLoadFolder(downloadAllItems); + startBackup(); + }) + .on('click', '.btn-clear-all', function () { + status.reset(); }) .on('click', '.status-stab', function () { viewLog(); @@ -676,20 +782,12 @@ define(function (require, exports, module) { enablePanel(true); } - $(_nodeDomain).on('uploading', function (err, msg) { - updateStatus('Uploading: ' + msg + status.status()); + $(_nodeDomain) + .on('processing', function(err, jobId) { + status.processing(jobId); }) - .on('downloading', function (err, remoteFile, localFile) { - updateStatus('Downloading: ' + remoteFile + status.status()); - }) - .on('uploaded', function (err, remoteFile, localFile) { - skipItem(localFile); - status.uploaded(remoteFile, localFile); - updateStatus('Finished: ' + remoteFile + status.status()); - }) - .on('downloaded', function (err, remoteFile, localFile) { - status.downloaded(remoteFile, localFile); - updateStatus('Downloaded: ' + remoteFile); + .on('processed', function(err, jobId) { + status.completed(jobId); }) .on('connection-tested', function (err, ok, msg) { if (ok) { @@ -699,30 +797,29 @@ define(function (require, exports, module) { status.log('Error', msg); } }) - .on('queued', function(err, num) { - status.itens_length = num; + .on('queued', function(err, num, job) { + $("button.btn-clear-all", $todoPanel).prop("disabled", true); + status.queuing_fisined = false; + status.queuing = true; + status.jobQueued(job); }) .on('queuedend', function(err, num) { - status.itens_length = num; status.queuing = false; status.queuing_fisined = true; + status.status(); }) .on('listed', function(err, path, list) { showListedItems(err, path, list); }) - .on('error', function (err, msg) { - status.error(msg); - updateStatus('Error: ' + msg); + .on('error', function (err, msg, jobId) { + status.error(msg, jobId); }) .on('jobCompleted', function (err, msg) { showUploadingIconStatus(false); - if (status.is_downloading) { - updateStatus('Backup Complete! ' + status.status()); - } else { - updateStatus('Upload Complete! ' + status.status()); - } status.is_downloading = false; + status.status(); enableButtons(); + $("button.btn-clear-all", $todoPanel).removeProp("disabled"); }); }); }); diff --git a/modules/.DS_Store b/modules/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..21aebbd05de5fa54f48d1632f9e6be2e696d96df GIT binary patch literal 6148 zcmeHK%SyyR5Ukccta@1wg2x;^3I0J?qOb=q<^wdVA*=)g+4Y_e^aK2xSlu&*jpi(( z-Oy9>=&qR*WF7!y`TBGPEC9^uilUVX)9%TkgBUy`igD!Fp+SpsRZkH8#x7m^5iXG- z$31;mfAhGmn>9x%jl2^tdNccoGsYK;EryH&6-wN)=Y_8ImaNa%uIhaz+$a-W`repM z$xxDMhYd3;Y{|SKLrop4NrpFN*jvl7t)U(ACuWtqFF7`~7p{OS;0m|`|5O2<*=qBX zfL^)+u7E2rD4_d8LRU;9b^&ecU|~-HqF$rTSl73N<|Gl*h+ROA&?KZ1L#o6lhJS@MQnERCl(G#1A6HSxB_DZ4nuRH=l?Z-naM}~IK^A8fGhCF z6p&e#XG?xmJX^ngo}RS{{eiBgah+CZtdA}MZ0J66Zi8Vw(K_SOh+RNs(SA!O`bEG5 L@xm4O0R=t)3z 1 + if (files.length > 0) { + $btn.prev('input:text').val(files[0]); + } + } + }); + }); + // Open dialog. dialog.done( function( buttonId ) { // Save preferences if OK button was clicked. @@ -63,4 +95,4 @@ define( function( require, exports ) { } }); }; -}); \ No newline at end of file +}); diff --git a/modules/DataStorageManager.js b/modules/DataStorageManager.js index 1ca3ad2..acf5bdc 100644 --- a/modules/DataStorageManager.js +++ b/modules/DataStorageManager.js @@ -1,3 +1,6 @@ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ +/*global define, $, brackets, window, Mustache */ + define( function( require, exports, module ) { 'use strict'; @@ -10,18 +13,12 @@ define( function( require, exports, module ) { PreferencesManager = brackets.getModule( 'preferences/PreferencesManager' ), preferences = PreferencesManager.getExtensionPrefs( 'bigeyex.bracketsSFTPUpload' ); - - var self = this, propertyList = {}, projectUrl = ''; - $(ProjectManager).on('projectOpen', function(){ - projectUrl = ProjectManager.getProjectRoot().fullPath; - }); - function init(callback){ - + projectUrl = ProjectManager.getProjectRoot().fullPath; } function get(key){ @@ -39,7 +36,15 @@ define( function( require, exports, module ) { function _save(){ } + exports.get = get; exports.set = set; + exports.setProjectUrl = function(url) { + projectUrl = url; + }; + exports.getProjectUrl = function() { + return projectUrl; + }; + } ); diff --git a/modules/LogViewerDialog.js b/modules/LogViewerDialog.js index 4b47189..c807c28 100644 --- a/modules/LogViewerDialog.js +++ b/modules/LogViewerDialog.js @@ -1,29 +1,32 @@ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ +/*global define, $, brackets, window */ define( function( require, exports ) { 'use strict'; - + // Get module dependencies. var Dialogs = brackets.getModule( 'widgets/Dialogs' ), - + Mustache = brackets.getModule("thirdparty/mustache/mustache"), + // Extension modules. Strings = require( 'modules/Strings' ), dataStorage = require( 'modules/DataStorageManager' ), dialogTemplate = require( 'text!../html/dialog-view-logs.html' ), - + // Variables. dialog; - + /** * Set each value of the preferences in dialog. */ function setValues( values ) { } - - + + /** * Initialize dialog values. */ function init() { - + } /** * Exposed method to show dialog. @@ -35,7 +38,7 @@ define( function( require, exports ) { }), logsHtml = (function() { var tmp = ''; - if ( logs.length == 0 ) return '
      • ' + Strings.LOG_VIEWER_EMPTY + '
      • '; + if ( logs.length === 0 ) return '
      • ' + Strings.LOG_VIEWER_EMPTY + '
      • '; for(var i=0,il=logs.length,l;i'; @@ -44,9 +47,9 @@ define( function( require, exports ) { }()); // Save dialog to variable. dialog = Dialogs.showModalDialogUsingTemplate( compiledTemplate ); - + $("#sftpupload-log-viewer").html(logsHtml); - + // Open dialog. dialog.done( function( buttonId ) { // Save preferences if OK button was clicked. @@ -55,4 +58,4 @@ define( function( require, exports ) { } }); }; -}); \ No newline at end of file +}); diff --git a/modules/SettingsDialog.js b/modules/SettingsDialog.js index 10c5d3a..f1798df 100644 --- a/modules/SettingsDialog.js +++ b/modules/SettingsDialog.js @@ -1,10 +1,13 @@ -/*jshint node: true, jquery: true*/ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ +/*global define, $, brackets, window */ define( function( require, exports ) { 'use strict'; // Get module dependencies. var Dialogs = brackets.getModule( 'widgets/Dialogs' ), - + FileSystem = brackets.getModule( 'filesystem/FileSystem' ), + Mustache = brackets.getModule("thirdparty/mustache/mustache"), + // Extension modules. Strings = require( 'modules/Strings' ), dataStorage = require( 'modules/DataStorageManager' ), @@ -44,15 +47,30 @@ define( function( require, exports ) { port.val(defaultFTPport); } }); + $('#sftpupload-settings-dialog .input-backup-enabled').change(function(){ + if ( $(this).is(':checked')) { + $(this).parents('.checkbox').next('fieldset').show(); + } + else { + $(this).parents('.checkbox').next('fieldset').hide(); + } + }); } function newServerObj() { - return { __id: 0, name: "default", method:'sftp', host:'', port:defaultSFTPport, username:'', rsaPath:'', password:'', serverPath:'', uploadOnSave:0, backupPath:defaultBackUpPath}; + return { __id: 0, name: "default", method:'sftp', host:'', port:defaultSFTPport, username:'', rsaPath:'', password:'', serverPath:'', uploadOnSave:0, backupPath: defaultBackUpPath, + backup: { + enabled: false, + byDate: true, + path: defaultBackUpPath, + alwaysPrompt: false + } + }; } function saveServer(serverInfo) { var serverList = dataStorage.get('server_list'); - if ( serverInfo.__id == 0 ) { + if ( serverInfo.__id === 0 ) { serverList.server_ids = serverList.server_ids + 1; serverInfo.__id = serverList.server_ids; } @@ -90,17 +108,22 @@ define( function( require, exports ) { rsaPath: $('.input-rsa-path', $dialog).val(), password: $('.input-password', $dialog).val(), serverPath: $('.input-server-path', $dialog).val(), - backupPath: $('.input-backup-path', $dialog).val(), - uploadOnSave: $('.input-save', $dialog).is(':checked') + uploadOnSave: $('.input-save', $dialog).is(':checked'), + backup: { + enabled: $('.input-backup-enabled', $dialog).is(':checked'), + path: $('.input-backup-path', $dialog).val(), + byDate: $('.input-backup-by-day', $dialog).is(':checked'), + alwaysPrompt:$('.input-backup-prompt', $dialog).is(':checked') + } }; } - - + function clearForm() { var $dialog = dialog.getElement(); $('input:text', $dialog).val(''); $('.input-id', $dialog).val(0); $('.input-port', $dialog).val(defaultFTPport); + $('input[type=checkbox]', $dialog).removeProp('checked'); } function fillForm(serverInfo) { @@ -118,7 +141,22 @@ define( function( require, exports ) { $('.input-rsa-path', $dialog).val(serverInfo.rsaPath); $('.input-password', $dialog).val(serverInfo.password); $('.input-server-path', $dialog).val(serverInfo.serverPath); - $('.input-backup-path', $dialog).val(serverInfo.backupPath); + + if ( serverInfo.backup !== undefined ) { + $('.input-backup-path', $dialog).val(serverInfo.backup.path); + + if ( serverInfo.backup.enabled === true ) { + $('.input-backup-enabled', $dialog).prop('checked', true).parents('.checkbox').next('fieldset').show(); + } + else { + $('.input-backup-enabled', $dialog).parents('.checkbox').next('fieldset').hide(); + } + if ( serverInfo.backup.byDate ) $('.input-backup-by-day', $dialog).prop('checked', true); + if ( serverInfo.backup.alwaysPrompt ) $('.input-backup-prompt', $dialog).prop('checked', true); + } + else { + $('.input-backup-path', $dialog).val(serverInfo.backupPath); + } } /** * Exposed method to update footer status @@ -163,7 +201,7 @@ define( function( require, exports ) { selected_id: 1, server_ids: 1, servers: { - '1' : $.extend({}, serverInfo, { + '1' : $.extend(true, {}, serverInfo, { __id: 1, name: "default", backupPath: defaultBackUpPath @@ -229,7 +267,8 @@ define( function( require, exports ) { }) .off('click', 'button') .on('click', 'button', function(evt) { - var buttonId = $(this).data('button-id'); + var $btn = $(this), + buttonId = $btn.data('button-id'); if ( buttonId === 'ok' ) { itensToRemove = []; saveServer(getFormInfo()); @@ -258,6 +297,16 @@ define( function( require, exports ) { else if (buttonId === 'new') { clearForm(); } + else if (buttonId === 'open-folder') { + FileSystem.showOpenDialog(false, true, Strings.CHOOSE_FOLDER, dataStorage.getProjectUrl(), null, function (err, files) { + if (!err) { + // If length == 0, user canceled the dialog; length should never be > 1 + if (files.length > 0) { + $btn.prev('input:text').val(files[0]); + } + } + }); + } else { itensToRemove = []; dialog.close(); @@ -265,4 +314,4 @@ define( function( require, exports ) { }); }; -}); \ No newline at end of file +}); diff --git a/nls/.DS_Store b/nls/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..053ff8ddee155bb887b92d39141c9f8cba710e33 GIT binary patch literal 6148 zcmeHKO>fgc5S>i}*r5up00H9S8z4m}rKAxjLI_9*Aw?LqLKFqNwi+YL8`(}H2$6Dx z0taqA^HtzyAh_`Ziufbk!t6&)oRk}?DB6j3-|X&;oqf;V^#TB?cinja0{}EE4D$u7 zb}=^2%9Q0~&nzP0*RUV~3K4iWf~jcLp%_pM{A&!bcUOn=&;ScsSkm{Gt~vpAaFi_# z*Rh-(aYGLv2QGWZGcn($Vth!lG2}Lj!9qqOtl4!i#_7c!d9R;NC-CE>T>egSGx-At z4{3SWc9n*S?T218 zmb$X+hc4~aX*YD^6-!)i*>{t6%Q)VQymd@%+M&1P$G+nSe)331)AW{cqTjzzxl}S2 z76&D>U#*r)=EcSGU|?)&+UawZE4S`;1{<&6ynXk6>%-?Se6~PvmE?9*;tqU8hjX!R zMPWe0HEgrkJg%h_f0I0JmyDLE!AaCwA1<%dO1K!#(Cu(6GEjK`^k|{qjq>d{b}`I6$6TaJz;>Y4<;6d zHHkxkeCfc79{~{a*v$=n_QAk%Oo=s#LxDJgMno#2NG0-!K}0(Cn=-B@aVSuv1CfUh zBJWJ(35D>x@2WoRZvI zrzXetS`*6yEX-KkP#{miN^Zy8VO#M@EZlI+WDa6Y;!q&=ps5c5PJ^lx1AEHAFH}nP AzyJUM literal 0 HcmV?d00001 diff --git a/nls/it/.DS_Store b/nls/it/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..19e7832b2c48ec4c0e959f406881ba8700a1d7a4 GIT binary patch literal 6148 zcmeHKJxfDD5S-N%L7SA8S6T`FgCit@b^d@vL6l%1YX7SIF8`U%ejtX2AcBp|!0z1b z?Y_&K;%ydy&0p^>ff;})%^7=lWB9q-2uBq$GL6r8!abgGfk*nE!D~;j!V7kI_*#Fx z+1{=<+cnSq$6e9R-ve9;Qa}nw0VyB_q`+?#@ZL*IPm|@PfE17dp9=W*q0yXs@sJ#! z4!Rft$P z4(rMCQa}nEDsY_JnfL!C?VI`kut+;8AO-%F0ybH!7IVH*_14kLd9Q7>8=B|5(HvYy o30<^faPWK*5epYjD?*?KDDBB)^HkRv+MoF-t`g@YYn0%kxfJvRAB82irThji z^Z()e`~P&1sTl?g1OF8Rtk(A1Ei6f&tuu=gXRQN$1r;LvDuprxg+7j@A&%lTs1)=$ X!T@?2D}`u*m>&U2gDDIHf0cn>vIe2W literal 0 HcmV?d00001 diff --git a/node/SftpUploadDomain.js b/node/SftpUploadDomain.js index 7b0553f..6f356f1 100644 --- a/node/SftpUploadDomain.js +++ b/node/SftpUploadDomain.js @@ -11,6 +11,7 @@ JSFtp = require('jsftp-mkdirp')(JSFtp); + // Utility function to log to console var clog = function(text, extra) { if (typeof console === 'object') { console.log('SFTPUploadDomain: ' + text + ( @@ -20,6 +21,65 @@ } }; + var STATUS_QUEUED = 0, + STATUS_PROCESSING = 1, + STATUS_COMPLETED = 2, + STATUS_ERROR = 3, + STATUS_CANCELED = 4, + STATUS_PAUSED = 5; + + function SftpJob(config) { + this.id = config.id; + this.localPath = config.localPath; + this.remotePath = config.remotePath; + this.fullRemotePath = config.fullRemotePath; + this.type = config.type; + this.callback = config.callback; + this.config = config.config; + this.status = STATUS_QUEUED; + } + + SftpJob.prototype.getEventData = function() { + return { + id: this.id, + localPath: this.localPath, + remotePath: this.remotePath, + fullRemotePath: this.fullRemotePath, + type: this.type + }; + }; + SftpJob.prototype.emitEvent = function(eventName, params) { + _domainManager.emitEvent("sftpUpload", eventName, params); + }; + SftpJob.prototype.queued = function() { + this.status = STATUS_QUEUED; + this.emitEvent("queued", [this.getEventData()]); + }; + SftpJob.prototype.pause = function() { + this.status = STATUS_PAUSED; + this.emitEvent("paused", [this.id]); + }; + SftpJob.prototype.pause = function() { + this.status = STATUS_PAUSED; + this.emitEvent("paused", [this.id]); + }; + SftpJob.prototype.error = function(err) { + this.status = STATUS_ERROR; + this.emitEvent("error", [err.message, this.id]); + }; + SftpJob.prototype.processing = function() { + this.status = STATUS_PROCESSING; + this.emitEvent("processing", [this.id]); + }; + SftpJob.prototype.completed = function() { + this.status = STATUS_COMPLETED; + this.emitEvent("processed", [this.id]); + }; + SftpJob.prototype.folderListed = function(files) { + this.status = STATUS_COMPLETED; + this.emitEvent("listed", [this.remotePath, files]); + }; + function SftpJobs(sftpClient){ this.config = { host: '', @@ -52,35 +112,33 @@ this.jobQueue = []; this.sftpClient = null; this.ftpClient = null; + this._jobCount = 0; + this._queueCount = 0; + var self = this; - var _ftp_downloadFile = function (fullRemotePath, fullLocalPath, callback) + var _ftp_downloadFile = function (job, fullRemotePath, fullLocalPath, callback) { var local_dir = fullLocalPath.replace(/[^\/]*$/, '').replace(/\/$/, ''), _get_file = function() { try { self.ftpClient.get(fullRemotePath, fullLocalPath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", ['Download Error:' + err.message]); - } - else{ - _domainManager.emitEvent("sftpUpload", "downloaded", [fullRemotePath, fullLocalPath]); - } + if(err) job.error(err); + else job.completed(); callback.call(callback, err); }); - - _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, fullLocalPath]); + job.processing(); } catch(err) { - _domainManager.emitEvent("sftpUpload", "error", ['Download Error:' + err.description]); + job.error(); callback.call(callback, err); } }, _make_dir = function() { mkdirp(local_dir, function (errdir) { // creates new directory if (errdir) { - _domainManager.emitEvent("sftpUpload", "error", ['Create Dir Error: ' + errdir]); + job.error(); callback.call(callback, errdir); } else { @@ -127,7 +185,7 @@ } } - var fullRemotePath = self._getFullRemotePath(job.remotePath), + var fullRemotePath = job.fullRemotePath, remotePath = job.remotePath, path_only = job.localPath.replace(/[^\/]*$/, '').replace(/\/$/, ''); @@ -167,62 +225,59 @@ _domainManager.emitEvent("sftpUpload", "connection-tested", [false, message]); } else { - _domainManager.emitEvent("sftpUpload", "error", [message]); + job.error(err); } }); } - + // List directory files/folders if (job.type !== undefined && job.type === 'list') { clog("SFTP Listing ", fullRemotePath); self.sftpClient.ls(fullRemotePath, function(err, res) { clog("SFTP Listed:", res); if ( typeof job.callback === 'function' ) { - //setTimeout(function(){ - job.callback.call(job.callback, err, res); - //}, 50); + job.callback.call(job.callback, err, res); } else { - _domainManager.emitEvent("sftpUpload", "listed", [job.remotePath, res]); + job.folderListed(res); } self.run(); - - //_domainManager.emitEvent() }); } - else if ( job.type !== undefined && job.type === 'download' ) // Download files + // Download files + else if ( job.type !== undefined && job.type === 'download' ) { - _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, job.localPath]); - // Creates local diretory of backup - mkdirp(path_only, function (err) { - if (err) { - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - } - else { - self.sftpClient.download(fullRemotePath, job.localPath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "downloaded", [fullRemotePath, job.localPath]); - self.run(); - } - }); - } - }); + job.processing(); + // Creates local diretory of backup + mkdirp(path_only, function (err) { + if (err) job.error(err); + else { + self.sftpClient.download(fullRemotePath, job.localPath, function(err){ + if(err){ + job.error(err); + } + else{ + job.downloaded(); + } + self.run(); + }); + } + }); } + // Test Server Connection else if ( job.type === 'test-connection' ) { + // try connection self.sftpClient.sftp(function(err, sftp) { var isOk = err === undefined || err === null || err === false; - _domainManager.emitEvent("sftpUpload", "connection-tested", [isOk, !isOk ? (err.code +' at '+ err.level ) : '' ]); + job.emitEvent("connection-tested", [isOk, !isOk ? (err.code +' at '+ err.level ) : '' ]); try { + // close if connection ok if (self.sftpClient !== undefined && self.sftpClient !== null ) { self.sftpClient.close(); } } catch(erro) { - + clog("SFTPUploadDomain test-connection", err); } finally { @@ -230,36 +285,29 @@ } }); } + // Upload Files else { fs.stat(job.localPath, function(err, stats){ if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + job.error(err); self.run(); + return; } if(stats.isFile()) { - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + job.processing(); self.sftpClient.upload(job.localPath, fullRemotePath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [fullRemotePath, job.localPath]); - self.run(); - } + if (err) job.error(err); + else job.completed(); + self.run(); }); } + // Upload files else if(stats.isDirectory()){ - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + job.processing(); self.sftpClient.mkdir(fullRemotePath, function(err){ - if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err]); - self.run(); - } - else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [fullRemotePath, job.localPath]); - self.run(); - } + if (err) job.error(err); + else job.completed(); + self.run(); }); } }); // fs.stat @@ -267,6 +315,8 @@ } // do FTP upload else if(self.config.method == 'ftp'){ + + // Create FTP Client if(self.ftpClient === null){ self.ftpClient = new JSFtp({ port: self.config.port, @@ -274,48 +324,51 @@ user: self.config.username, pass: self.config.password }); + // Attach error handler + self.ftpClient.on('error', function(err){ + clog('ftp error', err); + var message = err.message; + if(message == 'connect ECONNREFUSED'){ + message = 'Broken Connection / Wrong Password'; + } + self.ftpClient = null; + self.isRunning = false; + self.jobQueue = []; + if ( job.type === 'test-connection' ) { + job.emitEvent("connection-tested", [false, message]); + } + else { + job.error(err); + } + self.run(); + }); } - self.ftpClient.on('error', function(err){ - clog('ftp error', err); - var message = err.message; - if(message == 'connect ECONNREFUSED'){ - message = 'Broken Connection / Wrong Password'; - } - self.ftpClient = null; - self.isRunning = false; - self.jobQueue = []; - if ( job.type === 'test-connection' ) { - _domainManager.emitEvent("sftpUpload", "connection-tested", [false, message]); - } - else { - _domainManager.emitEvent("sftpUpload", "error", [message]); - } - self.run(); - }); + // List directory job if (job.type !== undefined && job.type === 'list') { clog("FTP Listing ", fullRemotePath); self.ftpClient.ls(fullRemotePath, function(err, res) { - - if ( typeof job.callback === 'function' ) { - //setTimeout(function(){ - job.callback.call(job.callback, err, res); - //}, 50); + if ( err ) { + job.error(err); } else { - _domainManager.emitEvent("sftpUpload", "listed", [job.remotePath, res]); + clog("FTP Listed", res.length); + if ( typeof job.callback === 'function' ) { + clog("FTP Listed Calling Callback"); + job.callback.call(job.callback, err, res); + } + else { + job.emitEvent("listed", [job.remotePath, res]); + } } self.run(); - - //_domainManager.emitEvent() }); } + // Download job else if ( job.type !== undefined && job.type === 'download' ) // Download files { - clog("Downloading " + fullRemotePath + " to " + job.localPath); - _domainManager.emitEvent("sftpUpload", "downloading", [fullRemotePath, job.localPath]); - - _ftp_downloadFile(fullRemotePath, job.localPath, function() { + job.processing(); + _ftp_downloadFile(job, fullRemotePath, job.localPath, function() { self.run(); }); }// end Download Files @@ -326,10 +379,10 @@ data: data }); if ( data.code === 211 ) { // Successfull auth - _domainManager.emitEvent("sftpUpload", "connection-tested", [true, data.text]); + job.emitEvent("connection-tested", [true, data.text]); } else { - _domainManager.emitEvent("sftpUpload", "connection-tested", [false, err.message]); + job.emitEvent("connection-tested", [false, err.message]); } self.run(); }); @@ -338,25 +391,26 @@ { fs.stat(job.localPath, function(err, stats){ if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + job.error(err); self.run(); + return; } if(stats.isFile()) { - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + job.processing(); var path_only = fullRemotePath.replace(/[^\/]*$/, '').replace(/\/$/, ''); self.ftpClient.mkdirp(path_only, function(err){ if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + job.error(err); self.run(); } else{ self.ftpClient.put(job.localPath, fullRemotePath, function(err){ if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + job.error(err); self.run(); } else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [fullRemotePath, job.localPath]); + job.completed(); self.run(); } }); @@ -364,14 +418,14 @@ }); } else if(stats.isDirectory()){ - _domainManager.emitEvent("sftpUpload", "uploading", [remotePath]); + job.processing(); self.ftpClient.raw.mkd(fullRemotePath, function(err){ if(err){ - _domainManager.emitEvent("sftpUpload", "error", [err.message]); + job.error(err); self.run(); } else{ - _domainManager.emitEvent("sftpUpload", "uploaded", [fullRemotePath, job.localPath]); + job.completed(err); self.run(); } }); @@ -403,20 +457,36 @@ }; self.add = function(localPath, remotePath, config, jobType, callback){ + self._jobCount = self._jobCount + 1; remotePath = remotePath.replace(/\\/g, "/").replace(/\/+/g, "/"); localPath = localPath.replace(/\\/g, "/").replace(/\/+/g, "/"); - clog(self.isRunning + " - Add Job", {type: jobType, local: localPath, remote: remotePath}); - self.jobQueue.push({localPath: localPath, remotePath: remotePath, config: config, type: jobType, callback: callback || false}); + + var job_data = { + id: this._jobCount, + localPath: localPath, + remotePath: remotePath, + fullRemotePath: self._getFullRemotePath(remotePath), + config: config, + type: jobType, + callback: typeof callback === 'function' ? callback : false + }, + job = new SftpJob(job_data); + + self.jobQueue.push(job); + clog(self.isRunning + " - Add Job", job.getEventData()); + + if ( job.type === "download" || job.type === "upload" ) { + self._queueCount = self._queueCount + 1; + job.queued(); + } + if(!self.isRunning){ self.run(); } }; self.addDirectory = function(localPath, remotePath, config){ - var walker = walk.walk(localPath, {followLinks:false, filters:[".DS_Store"]}), - files_added = 0, - trigger_on = 1, - tmp_count = 0; + var walker = walk.walk(localPath, {followLinks:false, filters:[".DS_Store"]}); walker.on("file", function(root, stats, next){ var relativeRemotePath = nodepath.join(remotePath, root.replace(localPath, '')); @@ -424,17 +494,11 @@ return next(); } self.add(nodepath.join(root, stats.name), nodepath.join(relativeRemotePath, stats.name), config, 'upload'); - - files_added = files_added +1; - tmp_count = tmp_count + 1; - if ( tmp_count > trigger_on ) { - _domainManager.emitEvent("sftpUpload", "queued", [files_added]); - tmp_count = 0; - } + next(); }); walker.on('end', function() { - _domainManager.emitEvent("sftpUpload", "queuedend", [files_added]); + _domainManager.emitEvent("sftpUpload", "queuedend", [self._queueCount]); }); }; @@ -453,16 +517,17 @@ } self.add(fullDownloadPath, nodepath.join(relativeRemotePath, stats.name), config, 'download'); + /* files_added = files_added +1; tmp_count = tmp_count + 1; if ( tmp_count > trigger_on ) { _domainManager.emitEvent("sftpUpload", "queued", [files_added]); tmp_count = 0; - } + }*/ next(); }); walker.on('end', function() { - _domainManager.emitEvent("sftpUpload", "queuedend", [files_added]); + _domainManager.emitEvent("sftpUpload", "queuedend", [self._queueCount]); }); }; @@ -503,6 +568,7 @@ for(var i in filelist){ sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'upload'); } + _domainManager.emitEvent("sftpUpload", "queuedend", [sftpJobs._queueCount]); } function cmdDownloadAll(filelist, config){ @@ -510,6 +576,7 @@ for(var i in filelist){ sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'download'); } + _domainManager.emitEvent("sftpUpload", "queuedend", [sftpJobs._queueCount]); } function cmdDownload(remotePath, localPath, walkPath, config){ @@ -522,30 +589,38 @@ clog('Downloading Folder: ', remotePath + ' to ' + localPath); sftpJobs.downDirectory(remotePath, walkPath, localPath, config); } + // Walk on Server Side else if ( walkPath === true ) { - var files_added = 0; + var num_lists = 0, num_recieved = 0; var list = function(path) { + clog("FTP Walk - Listing", path); + num_lists = num_lists + 1; sftpJobs.list(path, config, function(err, files) { - files_added = files_added + files.length; - _domainManager.emitEvent("sftpUpload", "queued", [files_added]); files.forEach(function(file) { + clog("FTP Walking", file); if ( file.type.toString() === "0" ) { // file - var downPath = localPath + '/' + path + file.name, - rpath = path+ file.name; + var downPath = localPath + '/' + path + '/' + file.name, + rpath = path + "/" + file.name; + downPath = downPath.replace(/\/+/g, "/"); + rpath = rpath.replace(/\/+/g, "/"); + sftpJobs.add(downPath, rpath , config, 'download'); } else { - list(file.name); + list(path + "/" + file.name); } }); + num_recieved = num_recieved + 1; + if ( num_recieved === num_lists) { + _domainManager.emitEvent("sftpUpload", "queuedend", [sftpJobs._queueCount]); + } }); }; list(remotePath); } } - - + function cmdTestConnection(config) { if(config === undefined) {config=null;} clog('Start Connection Test', config); @@ -577,7 +652,7 @@ type: "string", description: "(relative) path or filename of the destination"}, {name: "config", // parameters - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object}", description: "(optional) server configuration."}], [] ); @@ -592,7 +667,7 @@ type: "[{localPath:string, remotePath:string},...]", description: "a list of files to be uploaded"}, {name: "config", // parameters - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object}", description: "(optional) server configuration."}], [] ); @@ -604,7 +679,7 @@ false, // this command is synchronous in Node "Test the connection with the server setup", [{name: "config", // parameters - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object", description: "(optional) server configuration."}], [] ); @@ -619,7 +694,7 @@ type: "[{localPath:string, remotePath:string},...]", description: "a list of files to be downloaded"}, {name: "config", // parameters - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object}", description: "(optional) server configuration."}], [] ); @@ -640,7 +715,7 @@ type: "object", description: "null/false for files, local path for walk on local" }, {name: "config", - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object}", description: "(optional) server configuration."}], [] ); @@ -658,7 +733,7 @@ type: "string", description: "(relative) path or filename of the destination"}, {name: "config", // parameters - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object}", description: "(optional) server configuration."}], [] ); @@ -673,7 +748,7 @@ type: "string", description: "remote path to download"}, {name: "config", - type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backupPath: string}", + type: "{name: string, host: string, username: string, rsaPath: string, password: string, port: string, serverPath: string, method: string, backup: object}", description: "(optional) server configuration."}], [] ); @@ -694,11 +769,21 @@ domainManager.registerEvent( "sftpUpload", - "uploading", + "processing", [{ - name: "path", - type: "string", - description: "the absolute local path of the file being uploaded" + name: "id", + type: "int", + description: "job id" + }] + ); + + domainManager.registerEvent( + "sftpUpload", + "processed", + [{ + name: "id", + type: "int", + description: "job id" }] ); @@ -716,59 +801,15 @@ description: "Authentication result text or error object" }] ); - - domainManager.registerEvent( - "sftpUpload", - "downloading", - [{ - name: "remotePath", - type: "string", - description: "the absolute remote path of the file being downloaded" - }, - { - name: "localPath", - type: "string", - description: "the absolute local path of the file being uploaded" - }] - ); - - domainManager.registerEvent( - "sftpUpload", - "uploaded", - [{ - name: "remotePath", - type: "string", - description: "the absolute remote path of uploaded filed" - }, - { - name: "localPath", - type: "string", - description: "the absolute local path of the uploaded path" - }] - ); - - domainManager.registerEvent( - "sftpUpload", - "downloaded", - [{ - name: "remotePath", - type: "string", - description: "the absolute remote path of the file being downloaded" - }, - { - name: "localPath", - type: "string", - description: "the absolute local path of the file being uploaded" - }] - ); + domainManager.registerEvent( "sftpUpload", "queued", [{ - name: "num", - type: "int", - description: "number of files queued until now" + name: "job", + type: "object", + description: "object representation of the job" }] ); @@ -794,10 +835,15 @@ name: "errorString", type: "string", description: "the description of the error" + }, + { + name: "jobId", + type: "int", + description: "jobId" }] ); } exports.init = init; -}()); \ No newline at end of file +}()); diff --git a/todo.css b/todo.css index 8af0fc3..b7dd365 100644 --- a/todo.css +++ b/todo.css @@ -91,6 +91,18 @@ } /*--- TOOLBAR ---*/ +.brackets-sftp-upload .tabs ul { list-style-type: none; } +.brackets-sftp-upload .tabs ul li { + display: inline-block; + cursor: pointer; + padding: 4px; +} +.brackets-sftp-upload .tabs ul li:hover { background: rgba(0, 0, 0, 0.25); } +.brackets-sftp-upload .tabs ul li.selected { background: rgba(0, 0, 0, 0.25); } + +.brackets-sftp-upload .table-container {display: none; height: 100%;} +.brackets-sftp-upload .table-container.selected {display: block;} + .brackets-sftp-upload .tools { position: absolute; top: 1px; @@ -180,19 +192,28 @@ } .sftp-upload-server-config-form input, .sftp-upload-server-config-form select { - margin-left: 105px; margin-bottom: 0; display: inline-block; } .sftp-upload-server-config-form label { - position: absolute; - margin-top: 5px; display: inline-block; width: 100px; text-align: right; } +.sftp-upload-server-config-form .checkbox input[type=checkbox] { + float: none; + display: inline-block; +} + +.sftp-upload-server-config-form .checkbox label { + position: relative; + width: auto; + text-align: left; + margin-left: 100px; +} + /* Checkbox has less height than standard text box */ .sftp-upload-server-config-form .upload-on-save label { margin-top: 0px; @@ -202,9 +223,9 @@ width: 210px; margin-top: 7px; } - +.input-folder.large { width: 400px; } #sftpupload-log-viewer-dialog { width: 70%; } -#sftpupload-settings-dialog { width: 750px; } +#sftpupload-settings-dialog { width: 750px; min-height: 500px; } #sftpuoload-settings-server-list { background: #333; padding: 0.5em; @@ -253,14 +274,15 @@ button.btn-server-setup > b { .sftp-upload-settings-list-panel { float: left; width: 250px; -} - -.sftp-upload-settings-list-panel { float: left; display: inline-block; margin-left: 10px; } +.sftp-upload-settings-list-panel:nth-child(2) { + width: auto; +} + .sftp-conn-error { color: #852222; display: block; @@ -321,4 +343,14 @@ button.btn-server-setup > b { #sftp-update-browser ul li.folder > ul { margin-left: 10px; -} \ No newline at end of file +} + + +ul.sftp-browser-context-menu { + max-height: 620px !important; min-height: 100px; height: auto; + overflow: visible; +} +.sftp-browser-context-menu li { padding: 3px 0; } +.sftp-browser-context-menu li:hover { + background: rgba(0, 0, 185, 0.5); +} From 8a5e83ce36282d54508d40c8f632d5e222d4a233 Mon Sep 17 00:00:00 2001 From: ale Date: Mon, 20 Jun 2016 07:25:06 -0300 Subject: [PATCH 10/17] removed fixed colors --- html/browser-panel.html | 2 +- html/dialog-settings.html | 2 +- todo.css | 11 ++--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/html/browser-panel.html b/html/browser-panel.html index 5807e41..a1d5a3e 100644 --- a/html/browser-panel.html +++ b/html/browser-panel.html @@ -1,4 +1,4 @@ -
        +
        diff --git a/html/dialog-settings.html b/html/dialog-settings.html index be5f0ae..2b874f9 100644 --- a/html/dialog-settings.html +++ b/html/dialog-settings.html @@ -9,7 +9,7 @@

        {{ Strings.SETTINGS_DIALOG_SERVER_LIST }}

        -
          +
            diff --git a/todo.css b/todo.css index b7dd365..90ce726 100644 --- a/todo.css +++ b/todo.css @@ -227,7 +227,6 @@ #sftpupload-log-viewer-dialog { width: 70%; } #sftpupload-settings-dialog { width: 750px; min-height: 500px; } #sftpuoload-settings-server-list { - background: #333; padding: 0.5em; /*border: 1px solid #999;*/ list-style-type: none; @@ -241,14 +240,11 @@ padding: 0.2em 0.2em; } #sftpuoload-settings-server-list li.selected { - color: #FFF; font-weight: bolder; - background: #2c2c2c; } #sftpuoload-settings-server-list li:hover { - background: #3c3c3c; + background: rgba(0, 0, 0, 0.3); cursor: pointer; - color: #000; font-weight: bold; } #sftpuoload-settings-server-list li > a.close { display: none; } @@ -264,12 +260,10 @@ margin: 0; } #sftpuoload-settings-server-list li:hover > a.close:hover { - background: #852222; - color: #FFF; + background: rgba(0, 0, 0, 0.3); } button.btn-server-setup > b { font-weight: bold; - color: #FFF; } .sftp-upload-settings-list-panel { float: left; @@ -307,7 +301,6 @@ button.btn-server-setup > b { top: 0; z-index: 999; width: 250px; - background: #2c2c2c; min-height: 450px; padding: 6px; display: none; From f74f87659e889645debd0a9aa79093bfdf06ff9a Mon Sep 17 00:00:00 2001 From: ale Date: Mon, 20 Jun 2016 07:27:08 -0300 Subject: [PATCH 11/17] fixed indicator style --- html/indicator.html | 2 +- main.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/html/indicator.html b/html/indicator.html index bf0f95e..fdfcbd9 100644 --- a/html/indicator.html +++ b/html/indicator.html @@ -1,5 +1,5 @@
            -
            +
            diff --git a/main.js b/main.js index 789e16e..d761913 100644 --- a/main.js +++ b/main.js @@ -153,7 +153,7 @@ define(function (require, exports, module) { (this.queuing_fisined === true ? ('[' + Strings.QUEUED + ' ' +this.itens_length+']') : '')))) : Strings.NO_QUEUE; $('#brackets-sftp-upload .status-stab').text(str); - $('div.label',$indicator).html(str); + $('div.indicator-label',$indicator).html(str); } }; From 70fab58e185789267d9103ef19bede73b24b50d6 Mon Sep 17 00:00:00 2001 From: ale Date: Wed, 22 Jun 2016 01:00:44 -0300 Subject: [PATCH 12/17] correctly recieve queued file --- main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.js b/main.js index d761913..c0b19f5 100644 --- a/main.js +++ b/main.js @@ -797,7 +797,7 @@ define(function (require, exports, module) { status.log('Error', msg); } }) - .on('queued', function(err, num, job) { + .on('queued', function(err, job) { $("button.btn-clear-all", $todoPanel).prop("disabled", true); status.queuing_fisined = false; status.queuing = true; From a3999acff62a2779ed8cc694a1b2613faf05ffc0 Mon Sep 17 00:00:00 2001 From: ale Date: Wed, 22 Jun 2016 02:02:24 -0300 Subject: [PATCH 13/17] send queuedend event even for single itens --- node/SftpUploadDomain.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/node/SftpUploadDomain.js b/node/SftpUploadDomain.js index 6f356f1..a262084 100644 --- a/node/SftpUploadDomain.js +++ b/node/SftpUploadDomain.js @@ -498,7 +498,7 @@ next(); }); walker.on('end', function() { - _domainManager.emitEvent("sftpUpload", "queuedend", [self._queueCount]); + self.queueingEnd(); }); }; @@ -527,7 +527,7 @@ next(); }); walker.on('end', function() { - _domainManager.emitEvent("sftpUpload", "queuedend", [self._queueCount]); + self.queuedend(); }); }; @@ -547,7 +547,11 @@ fullRemotePath = fullRemotePath.replace(re, self.config.serverPath); return fullRemotePath; }; - } + + self.queueingEnd = function() { + _domainManager.emitEvent("sftpUpload", "queuedend", [this._queueCount]); + } + } var sftpJobs = new SftpJobs(); @@ -555,6 +559,7 @@ if(config === undefined) {config=null;} clog('Start Upload: ' + localPath); sftpJobs.add(localPath, remotePath, config, 'upload'); + sftpJobs.queueingEnd(); } function cmdList(remotePath, config) { @@ -568,7 +573,6 @@ for(var i in filelist){ sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'upload'); } - _domainManager.emitEvent("sftpUpload", "queuedend", [sftpJobs._queueCount]); } function cmdDownloadAll(filelist, config){ @@ -576,13 +580,14 @@ for(var i in filelist){ sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'download'); } - _domainManager.emitEvent("sftpUpload", "queuedend", [sftpJobs._queueCount]); + sftpJobs.queuedend(); } function cmdDownload(remotePath, localPath, walkPath, config){ if(config === undefined) {config=null;} if ( ! walkPath || walkPath === null ) { sftpJobs.add(localPath, remotePath, config, 'download'); + sftpJobs.queueingEnd(); } // Walk on local path else if ( typeof walkPath === 'string' ) { @@ -612,13 +617,12 @@ }); num_recieved = num_recieved + 1; if ( num_recieved === num_lists) { - _domainManager.emitEvent("sftpUpload", "queuedend", [sftpJobs._queueCount]); + sftpJobs.queueingEnd(); } }); }; list(remotePath); } - } function cmdTestConnection(config) { From 88c75b1444caaf3ba2a6cd990070158ea0cbc780 Mon Sep 17 00:00:00 2001 From: ale Date: Wed, 22 Jun 2016 02:09:49 -0300 Subject: [PATCH 14/17] fixed status count freezed after clearing transactions --- main.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/main.js b/main.js index c0b19f5..4128984 100644 --- a/main.js +++ b/main.js @@ -74,12 +74,12 @@ define(function (require, exports, module) { itens_error: 0, _logs: [], - reset: function (length, download) { - this.is_downloading = (download === true); + reset: function () { + this.is_downloading = false; this.itens_error = 0; this.itens_ok = 0; this.itens_completed = 0; - this.itens_length = length; + this.itens_length = 0; this.queuing = false; this.queuing_fisined = false; $("#sftp-transactions-tbody").empty(); @@ -105,6 +105,8 @@ define(function (require, exports, module) { }, jobQueued: function(job) { + this.queuing_fisined = false; + this.queuing = true; this.itens_length = this.itens_length + 1; if ( job.type == "upload" ) job.signal = "-->"; else job.signal = "<--"; @@ -113,6 +115,12 @@ define(function (require, exports, module) { this.status(); }, + queueEnded: function(num) { + this.queuing = false; + this.queuing_fisined = true; + status.status(); + }, + processing: function(jobId) { var $tr = this.getTransactionRow(jobId); $tr.addClass("processing") @@ -799,14 +807,10 @@ define(function (require, exports, module) { }) .on('queued', function(err, job) { $("button.btn-clear-all", $todoPanel).prop("disabled", true); - status.queuing_fisined = false; - status.queuing = true; status.jobQueued(job); }) .on('queuedend', function(err, num) { - status.queuing = false; - status.queuing_fisined = true; - status.status(); + status.queueEnded(num); }) .on('listed', function(err, path, list) { showListedItems(err, path, list); From 0c72ccfa2cc51c9bf7fc6b3f2358caeca844c893 Mon Sep 17 00:00:00 2001 From: ale Date: Wed, 22 Jun 2016 07:07:44 -0300 Subject: [PATCH 15/17] Bug fixes; Name of server / No server setup at status indicator; --- main.js | 119 ++++++++++++++++++++++++++------------- nls/root/Strings.js | 2 + node/SftpUploadDomain.js | 5 +- todo.css | 6 ++ 4 files changed, 91 insertions(+), 41 deletions(-) diff --git a/main.js b/main.js index 4128984..bfcd3ac 100644 --- a/main.js +++ b/main.js @@ -74,6 +74,15 @@ define(function (require, exports, module) { itens_error: 0, _logs: [], + $status: undefined, + $indicator: undefined, + + init : function() { + this.$status = $('#brackets-sftp-upload .status-stab'); + this.$indicator = $('div.indicator-label', $indicator); + this.reset(); + }, + reset: function () { this.is_downloading = false; this.itens_error = 0; @@ -91,12 +100,22 @@ define(function (require, exports, module) { this.itens_completed = this.itens_completed + 1; this.log('Error', msg); + // Update transaction var $tr = this.getTransactionRow(jobId); $tr.removeClass("processing") .addClass("error") .children('td.status') .html( msg ); + $tr = $('#sftp-upload-tbody tr[data-job-id="'+jobId+'"]'); + if ( $tr.length === 1 ) { + $tr.find('button').removeProp('disabled'); + } + + // Modification TR + $tr = this.getModificationRow(jobId); + $tr.find("button").removeProp("disabled").first().text(Strings.UPLOAD); + this.status(); }, @@ -104,6 +123,10 @@ define(function (require, exports, module) { return $('tr[data-job-id='+jobId+']', $("#sftp-transactions-tbody")); }, + getModificationRow: function(jobId) { + return $('#sftp-upload-tbody tr[data-job-id='+jobId+']'); + }, + jobQueued: function(job) { this.queuing_fisined = false; this.queuing = true; @@ -111,7 +134,12 @@ define(function (require, exports, module) { if ( job.type == "upload" ) job.signal = "-->"; else job.signal = "<--"; job.status = Strings.QUEUED; + $("#sftp-transactions-tbody").append(Mustache.render(transactionRowTemplate, job)); + var $tr = $('#sftp-upload-tbody tr[x-file="'+job.localPath+'"]'); + if ( $tr.length === 1 ) { + $tr.attr('data-job-id', job.id).find('button').prop('disabled', 'disabled').first().text(Strings.QUEUED); + } this.status(); }, @@ -126,6 +154,11 @@ define(function (require, exports, module) { $tr.addClass("processing") .children('td.status') .html( Strings.PROCESSING ); + + $tr = this.getModificationRow(jobId); + $tr.find("button").prop("disabled", "disabled").first().text(Strings.PROCESSING); + + status.status($tr.find('td.filename').text()); }, completed: function(jobId) { @@ -137,9 +170,13 @@ define(function (require, exports, module) { .children('td.status') .html( Strings.FINISHED ); - this.status(); + this.status($tr.children('td.localPath').text()); if ( $tr.data('type') === 'upload' ) { - skipItem($.trim($tr.find('td.localPath').text())); + var $trMod = this.getModificationRow(jobId), + path = $trMod.attr('x-file'); + + $trMod.addClass("success").find("td:last").text(Strings.FINISHED); + skipItem(path); } }, @@ -154,14 +191,21 @@ define(function (require, exports, module) { this._logs = []; }, - status: function () { - var perc = this.itens_length > 0 ? Math.floor((this.itens_completed * 100) / this.itens_length) : 0; - var str = this.itens_length > 0 ? ((' ' + perc + '% (' + this.itens_ok + ' ok/' + this.itens_error + ' errors)' + - (this.queuing === true ? ('[ ' + Strings.QUEUING + ' ' + this.itens_length + '...]' ) : - (this.queuing_fisined === true ? ('[' + Strings.QUEUED + ' ' +this.itens_length+']') : '')))) : Strings.NO_QUEUE; - - $('#brackets-sftp-upload .status-stab').text(str); - $('div.indicator-label',$indicator).html(str); + status: function (text) { + text = text || ""; + var server = this.selectedServer !== undefined ? this.selectedServer.name : Strings.NO_SERVER_SETUP, + perc = this.itens_length > 0 ? Math.floor((this.itens_completed * 100) / this.itens_length) : 0, + perc_erro = this.itens_error > 0 ? Math.floor((this.itens_error * 100) / this.itens_error) : 0, + strIndicator = this.itens_length === 0 ? server : (perc + '%'), + css_class = perc_erro === 100 ? 'error' : + (perc_erro === 0 && perc === 100 ? 'success' : + (perc_erro > 0 ? 'warn' : '')), + strStatus = text + (this.itens_length > 0 ? (('(' + this.itens_ok + ' ok/' + this.itens_error + ' errors)' + + (this.queuing === true ? ('[ ' + Strings.QUEUING + ' ' + this.itens_length + '...]' ) : + (this.queuing_fisined === true ? ('[' + Strings.QUEUED + ' ' +this.itens_length+']') : '')))) : Strings.NO_QUEUE); + + this.$status.removeClass('error warn success').addClass(css_class).html(strStatus); + this.$indicator.removeClass('error warn success').addClass(css_class).html(strIndicator); } }; @@ -336,6 +380,8 @@ define(function (require, exports, module) { $("button.btn-server-setup").html(Strings.SERVER + ': '+ (serverInfo ? serverInfo.name : ' ') +''); + status.selectedServer = serverInfo; + for (var filepath in changedFiles) { files.push({ path: filepath, @@ -348,23 +394,6 @@ define(function (require, exports, module) { files: files })); - $('#sftp-upload-tbody tr').off().on('click', function () { - var fullPath = $(this).attr('x-file'); - CommandManager.execute(Commands.FILE_OPEN, { - fullPath: fullPath - }); - }); - - $('#sftp-upload-tbody .upload-button').off().on('click', function (e) { - uploadItem($(this).attr('x-file'), $(this).attr('r-file')); - e.stopPropagation(); - }); - - $('#sftp-upload-tbody .skip-button').off().on('click', function (e) { - skipItem($(this).attr('x-file')); - e.stopPropagation(); - }); - if (callback) { callback(); } @@ -606,18 +635,7 @@ define(function (require, exports, module) { file: path.replace(projectUrl, '') }] })); - - $('#sftp-upload-tbody .upload-button').off().on('click', function (e) { - uploadItem($(this).attr('x-file'), $(this).attr('r-file')); - e.stopPropagation(); - }); - - $('#sftp-upload-tbody .skip-button').off().on('click', function (e) { - skipItem($(this).attr('x-file')); - e.stopPropagation(); - }); } - }); ProjectManager.on('projectOpen', function(prj) { @@ -720,7 +738,9 @@ define(function (require, exports, module) { Strings: Strings })); StatusBar.addIndicator('bigeyex.sftpUpload.connIndicator', $indicator, true, 'brackets-sftp-upload-indicator'); - + $indicator.on('click', function() { + viewLog(); + }); $browserPanel = $(Mustache.render(browserPanelTemplate, { Strings: Strings })); @@ -745,6 +765,22 @@ define(function (require, exports, module) { showContextMenu(evt, $(this)); }); + $('#sftp-upload-tbody') + .on('click', '.upload-button', function (e) { + uploadItem($(this).attr('x-file'), $(this).attr('r-file')); + e.stopPropagation(); + }) + .on('click', '.skip-button', function (e) { + skipItem($(this).attr('x-file')); + e.stopPropagation(); + }) + .on('click', function () { + var fullPath = $(this).attr('x-file'); + CommandManager.execute(Commands.FILE_OPEN, { + fullPath: fullPath + }); + }); + // Add listener for toolbar icon.. $todoIcon.click(function () { CommandManager.execute(COMMAND_ID); @@ -754,6 +790,7 @@ define(function (require, exports, module) { settingsDialog.showDialog({ testConnection: testConnection, serverSelected: function(server) { + status.selectedServer = server; $("button.btn-server-setup").html(Strings.SERVER+': '+ server.name+''); } }); @@ -790,6 +827,10 @@ define(function (require, exports, module) { enablePanel(true); } + // init status comp + status.init(); + + // Register for node events $(_nodeDomain) .on('processing', function(err, jobId) { status.processing(jobId); diff --git a/nls/root/Strings.js b/nls/root/Strings.js index 4d8dc74..612ce7c 100644 --- a/nls/root/Strings.js +++ b/nls/root/Strings.js @@ -26,6 +26,8 @@ define( { CLOSE: "Close", MODIFICATIONS: "Modifications", TRANSACTIONS: "Transactions", + UPLOADING: "Uploading", + DOWNLOADING: "Downloading", QUEUED: 'Queued', QUEUING: 'Queuing', diff --git a/node/SftpUploadDomain.js b/node/SftpUploadDomain.js index a262084..3fe7035 100644 --- a/node/SftpUploadDomain.js +++ b/node/SftpUploadDomain.js @@ -527,7 +527,7 @@ next(); }); walker.on('end', function() { - self.queuedend(); + self.queueingEnd(); }); }; @@ -573,6 +573,7 @@ for(var i in filelist){ sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'upload'); } + sftpJobs.queueingEnd(); } function cmdDownloadAll(filelist, config){ @@ -580,7 +581,7 @@ for(var i in filelist){ sftpJobs.add(filelist[i].localPath, filelist[i].remotePath, config, 'download'); } - sftpJobs.queuedend(); + sftpJobs.queueingEnd(); } function cmdDownload(remotePath, localPath, walkPath, config){ diff --git a/todo.css b/todo.css index 90ce726..44191b6 100644 --- a/todo.css +++ b/todo.css @@ -286,6 +286,12 @@ button.btn-server-setup > b { padding: 4px 6px; } +/* +.brackets-sftp-upload .error, +.brackets-sftp-upload-indicator .error, +#brackets-sftp-upload .status-stab.error{ color: #852222; } +.brackets-sftp-upload .success, .brackets-sftp-upload-indicator .success { color: #696; } +.brackets-sftp-upload .warn, .brackets-sftp-upload-indicator .warn { color: #FFF; }*/ .sftp-clearfix:after { content: " "; From 84ee60a3f86880b84f1982cc9d5e01941eb44981 Mon Sep 17 00:00:00 2001 From: ale Date: Thu, 23 Jun 2016 01:17:25 -0300 Subject: [PATCH 16/17] Fixed status when removing servers --- main.js | 11 +++++++++-- modules/SettingsDialog.js | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/main.js b/main.js index bfcd3ac..5d99f60 100644 --- a/main.js +++ b/main.js @@ -74,6 +74,7 @@ define(function (require, exports, module) { itens_error: 0, _logs: [], + selectedServer: undefined, $status: undefined, $indicator: undefined, @@ -193,7 +194,7 @@ define(function (require, exports, module) { status: function (text) { text = text || ""; - var server = this.selectedServer !== undefined ? this.selectedServer.name : Strings.NO_SERVER_SETUP, + var server = this.selectedServer !== undefined && this.selectedServer !== false ? this.selectedServer.name : Strings.NO_SERVER_SETUP, perc = this.itens_length > 0 ? Math.floor((this.itens_completed * 100) / this.itens_length) : 0, perc_erro = this.itens_error > 0 ? Math.floor((this.itens_error * 100) / this.itens_error) : 0, strIndicator = this.itens_length === 0 ? server : (perc + '%'), @@ -791,7 +792,13 @@ define(function (require, exports, module) { testConnection: testConnection, serverSelected: function(server) { status.selectedServer = server; - $("button.btn-server-setup").html(Strings.SERVER+': '+ server.name+''); + status.status(); + if ( server !== undefined && server !== false ) { + $("button.btn-server-setup").html(Strings.SERVER+': '+ server.name+''); + } + else { + $("button.btn-server-setup").html(Strings.NO_SERVER_SETUP); + } } }); }) diff --git a/modules/SettingsDialog.js b/modules/SettingsDialog.js index f1798df..f5d8784 100644 --- a/modules/SettingsDialog.js +++ b/modules/SettingsDialog.js @@ -158,6 +158,7 @@ define( function( require, exports ) { $('.input-backup-path', $dialog).val(serverInfo.backupPath); } } + /** * Exposed method to update footer status */ @@ -281,6 +282,8 @@ define( function( require, exports ) { delete list.servers[itensToRemove[i]]; if ( list.selected_id == itensToRemove[i] ) { list.selected_id = 0; + clearForm(); + opts.serverSelected(false); } } dataStorage.set('server_list', list); From 1ee5c828f78f1e0c41d560374b3a57908da13a88 Mon Sep 17 00:00:00 2001 From: ale Date: Fri, 4 Nov 2016 09:51:14 -0200 Subject: [PATCH 17/17] option to duplicate server config + some fixes --- html/dialog-settings.html | 5 +++ modules/DataStorageManager.js | 4 ++- modules/SettingsDialog.js | 60 ++++++++++++++++++++++++++--------- nls/root/Strings.js | 2 ++ todo.css | 5 +++ 5 files changed, 60 insertions(+), 16 deletions(-) diff --git a/html/dialog-settings.html b/html/dialog-settings.html index 2b874f9..ffbcb6d 100644 --- a/html/dialog-settings.html +++ b/html/dialog-settings.html @@ -10,6 +10,11 @@

              + +
              + + +
              diff --git a/modules/DataStorageManager.js b/modules/DataStorageManager.js index acf5bdc..9800161 100644 --- a/modules/DataStorageManager.js +++ b/modules/DataStorageManager.js @@ -36,10 +36,12 @@ define( function( require, exports, module ) { function _save(){ } - exports.get = get; exports.set = set; + exports.refreshProjectUrl = function() { + projectUrl = ProjectManager.getProjectRoot().fullPath; + }; exports.setProjectUrl = function(url) { projectUrl = url; }; diff --git a/modules/SettingsDialog.js b/modules/SettingsDialog.js index f5d8784..c93c0c9 100644 --- a/modules/SettingsDialog.js +++ b/modules/SettingsDialog.js @@ -37,7 +37,8 @@ define( function( require, exports ) { * Initialize dialog values. */ function init() { - $('#sftpupload-settings-dialog .input-method').change(function(){ + + $('#sftpupload-settings-dialog').on('change', '.input-method', function(){ var protcolType = $('#sftpupload-settings-dialog .input-method').val(); var port = $('#sftpupload-settings-dialog .input-port'); if(protcolType == 'sftp' && port.val() == defaultFTPport && !HasPortChanged){ @@ -46,15 +47,21 @@ define( function( require, exports ) { else if(protcolType == 'ftp' && port.val() == defaultSFTPport && !HasPortChanged){ port.val(defaultFTPport); } - }); - $('#sftpupload-settings-dialog .input-backup-enabled').change(function(){ + }) + .on('chamge', '.input-port', function(evt){ + HasPortChanged = true; + }) + .on('change', 'input-backup-enabled').change(function(){ if ( $(this).is(':checked')) { $(this).parents('.checkbox').next('fieldset').show(); } else { $(this).parents('.checkbox').next('fieldset').hide(); } - }); + }) + .on('contextmenu', '#sftpuoload-settings-server-list > li', function(evt) { + + }); } function newServerObj() { @@ -70,7 +77,8 @@ define( function( require, exports ) { function saveServer(serverInfo) { var serverList = dataStorage.get('server_list'); - if ( serverInfo.__id === 0 ) { + + if ( !serverInfo.__id || parseInt(serverInfo.__id) === 0 ) { serverList.server_ids = serverList.server_ids + 1; serverInfo.__id = serverList.server_ids; } @@ -86,18 +94,23 @@ define( function( require, exports ) { } function updateList(serverList) { + serverList = serverList || dataStorage.get('server_list'); var html = ''; - for(var id in serverList.servers) { - html += '
            • ' + - serverList.servers[id].name + + for(var i in serverList.servers) { + if ( i !== undefined && parseInt(i) > 0 ) { + var sv = serverList.servers[i]; + html += '
            • ' + + sv.name + 'x' + '
            • '; + } } $("#sftpuoload-settings-server-list").html(html); } function getFormInfo() { var $dialog = dialog.getElement(); + return { __id: $('.input-id', $dialog).val(), name: $('.input-name', $dialog).val(), @@ -177,6 +190,9 @@ define( function( require, exports ) { testConnection: undefined, // function(serverInfo) serverSelected: undefined, // function(serverInfo) }; + + dataStorage.refreshProjectUrl(); + // Compile dialog template. var serverInfo = dataStorage.get('server_info'), serverList = dataStorage.get('server_list'), @@ -230,10 +246,12 @@ define( function( require, exports ) { HasPortChanged = false; - $('#sftpupload-settings-dialog .input-port').change(function(){ - HasPortChanged = true; - }); - + var removeServer = function(id) { + itensToRemove.push(id); + self.updateStatus(Strings.SETTINGS_DIALOG_SAVE_TO_APLLY); + $("#sftp-upload-settings-list-menu").hide(); + }; + $('#sftpuoload-settings-server-list').off('click', 'li').on('click','li', function(evt){ var $li = $(this), serverId = $(this).data('id'), @@ -245,14 +263,15 @@ define( function( require, exports ) { $li.addClass('selected').siblings().removeClass('selected'); fillForm(server); opts.serverSelected(server); + + $("#sftp-upload-settings-list-menu").show(); }) .on('click', 'li > a.close', function(evt) { evt.stopPropagation(); - itensToRemove.push($(this).parent().data('id')); - self.updateStatus(Strings.SETTINGS_DIALOG_SAVE_TO_APLLY); + removeServer($(this).parent().data('id')); $(this).parent().remove(); }); - + fillForm(selectedServer); updateList(serverList); @@ -275,6 +294,16 @@ define( function( require, exports ) { saveServer(getFormInfo()); dialog.close(); } + else if ( buttonId === 'clone') { + var newObj = getFormInfo(); + newObj.__id = 0; + saveServer(newObj); + updateList(); + } + else if ( buttonId === 'remove') { + removeServer(getFormInfo().__id); + $('#sftpuoload-settings-server-list li.selected').remove(); + } else if (buttonId === 'save') { if ( itensToRemove.length > 0 ) { var list = dataStorage.get('server_list'); @@ -299,6 +328,7 @@ define( function( require, exports ) { } else if (buttonId === 'new') { clearForm(); + $("#sftp-upload-settings-list-menu").hide(); } else if (buttonId === 'open-folder') { FileSystem.showOpenDialog(false, true, Strings.CHOOSE_FOLDER, dataStorage.getProjectUrl(), null, function (err, files) { diff --git a/nls/root/Strings.js b/nls/root/Strings.js index 612ce7c..27e98fa 100644 --- a/nls/root/Strings.js +++ b/nls/root/Strings.js @@ -17,6 +17,8 @@ define( { SKIP: "Skip", CLEAR: "Clear", SERVER: "Server", + REMOVE: "Remove", + DUPLICATE: "Duplicate", TEST_CONNECTION: "Test Connection", VIEW_LOG: "View Log", DOWNLOAD: "Download", diff --git a/todo.css b/todo.css index 44191b6..6f3a94d 100644 --- a/todo.css +++ b/todo.css @@ -353,3 +353,8 @@ ul.sftp-browser-context-menu { .sftp-browser-context-menu li:hover { background: rgba(0, 0, 185, 0.5); } + +#sftp-upload-settings-list-menu { + display: none; + position: absolute; +}