From 5348f6e96a0ef538b991d4e13779847fe67c2384 Mon Sep 17 00:00:00 2001 From: Surinder Kumar Date: Sat, 14 May 2016 00:38:58 +0530 Subject: [PATCH] Improvised the file manager functionalities as per comments given: * Do not show the drives on windows, if STORAGE_DIR is set. * Do not show non-applicable buttons, whenever no files/directory present in the storage directory. * Showing dimmer under the warning messages for replace/delete. * Select file type other than 'All Files' in create/replace mode. Tweaked a bit by Ashesh. --- web/pgadmin/misc/file_manager/__init__.py | 68 +++--- .../file_manager/static/css/file_manager.css | 43 +++- .../templates/file_manager/index.html | 11 +- .../templates/file_manager/js/file_manager.js | 6 +- .../file_manager/js/file_manager_config.json | 46 ++-- .../templates/file_manager/js/languages/en.js | 3 +- .../templates/file_manager/js/utility.js | 229 +++++++++++------- 7 files changed, 250 insertions(+), 156 deletions(-) diff --git a/web/pgadmin/misc/file_manager/__init__.py b/web/pgadmin/misc/file_manager/__init__.py index e6c4e004f..bc67a5943 100644 --- a/web/pgadmin/misc/file_manager/__init__.py +++ b/web/pgadmin/misc/file_manager/__init__.py @@ -233,36 +233,6 @@ def delete_trans_id(trans_id): data={'status': True} ) - -def __get_drives(drive_name=None): - """ - This is a generic function which returns the default path for storage - manager dialog irrespective of any Platform type to list all - files and directories. - Platform windows: - if no path is given, it will list volumes, else list directory - Platform unix: - it returns path to root directory if no path is specified. - """ - if _platform == "win32": - try: - drives = [] - bitmask = ctypes.windll.kernel32.GetLogicalDrives() - for letter in letters: - if bitmask & 1: - drives.append(letter) - bitmask >>= 1 - if (drive_name != '' and drive_name is not None and - drive_name in drives): - return "{0}{1}".format(drive_name, ':/') - else: - return drives # return drives if no argument is passed - except Exception: - return 'C:/' - else: - return '/' - - class Filemanager(object): """FileManager Class.""" def __init__(self, trans_id): @@ -295,8 +265,7 @@ class Filemanager(object): # It is used in utitlity js to decide to # show or hide select file type options - show_volumes = True if (isinstance(storage_dir, list) or - not storage_dir) else False + show_volumes = isinstance(storage_dir, list) or not storage_dir supp_types = allow_upload_files = params['supported_types'] \ if 'supported_types' in params else [] if fm_type == 'select_file': @@ -395,6 +364,35 @@ class Filemanager(object): return make_json_response(data={'status': True}) + @staticmethod + def _get_drives(drive_name=None): + """ + This is a generic function which returns the default path for storage + manager dialog irrespective of any Platform type to list all + files and directories. + Platform windows: + if no path is given, it will list volumes, else list directory + Platform unix: + it returns path to root directory if no path is specified. + """ + if _platform == "win32": + try: + drives = [] + bitmask = ctypes.windll.kernel32.GetLogicalDrives() + for letter in letters: + if bitmask & 1: + drives.append(letter) + bitmask >>= 1 + if (drive_name != '' and drive_name is not None and + drive_name in drives): + return "{0}{1}".format(drive_name, ':/') + else: + return drives # return drives if no argument is passed + except Exception: + return ['C:/'] + else: + return '/' + @staticmethod def list_filesystem(dir, path, trans_data, file_type): """ @@ -402,8 +400,8 @@ class Filemanager(object): directory. """ files = {} - if (_platform == "win32" and path == '/') and (not dir): - drives = __get_drives() + if (_platform == "win32" and path == '/') and dir is None: + drives = Filemanager._get_drives() for drive in drives: protected = 0 path = file_name = "{0}:/".format(drive) @@ -426,6 +424,8 @@ class Filemanager(object): } return files + if dir is None: + dir = "" orig_path = "{0}{1}".format(dir, path) user_dir = path folders_only = trans_data['folders_only'] if 'folders_only' in \ diff --git a/web/pgadmin/misc/file_manager/static/css/file_manager.css b/web/pgadmin/misc/file_manager/static/css/file_manager.css index cebed17c4..069d00302 100755 --- a/web/pgadmin/misc/file_manager/static/css/file_manager.css +++ b/web/pgadmin/misc/file_manager/static/css/file_manager.css @@ -360,7 +360,6 @@ button.list span { overflow: hidden; position: relative; top: 35px; - font-size: 12px; } .file_manager .fileinfo #contents{ @@ -596,14 +595,33 @@ a.dz-remove { border: 1px solid black; } +.fileinfo .fm_dimmer { + height: calc(100% - 32px); + display: none; + top: 0px; + background: black; + opacity: 0.5; + width: 100%; + position: absolute; + z-index: 3; +} + .fileinfo .delete_item, .fileinfo .replace_file { display: none; - padding: 7px 5px; + padding: 15px 15px; opacity: 0.8; color: #fff; border: 1px solid darkgrey; + border-left: 0; + border-right: 0; background: #000; - box-shadow: 1px 0px 3px 1px red; + box-shadow: 1px 0px 3px 1px white; + font-weight: bold; + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 4; } .fileinfo .delete_item span.pull-right .btn, @@ -612,11 +630,7 @@ a.dz-remove { color: #000; background: #fff; font-size: 12px; -} - -.fileinfo .delete_item span, -.fileinfo .replace_file span { - margin-right: 10px; + margin-right: 4px; } .upload_file .dz_cross_btn { @@ -658,3 +672,16 @@ a.dz-remove { background: #F9F8F7; border: 1px inset #ccc; } + +.file_listing .no_folder_found { + text-align: center; + position: absolute; + top: 35; + width: 100%; +} + +.fileinfo .is_file_replace { + width: 100%; + height: 100%; + background: #ccc; +} diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/index.html b/web/pgadmin/misc/file_manager/templates/file_manager/index.html index 51044da4a..26c54ac8e 100755 --- a/web/pgadmin/misc/file_manager/templates/file_manager/index.html +++ b/web/pgadmin/misc/file_manager/templates/file_manager/index.html @@ -29,6 +29,10 @@ +
+
+
+
Are you sure you want to delete this item ? @@ -43,12 +47,7 @@
-
-
-
-
-
-
+ diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js b/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js index 535a890cc..bf7171f5f 100644 --- a/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js +++ b/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js @@ -451,9 +451,9 @@ define([ }; }, replace_file: function() { - $('.replace_file').show(); + $('.replace_file, .fm_dimmer').show(); $('.replace_file .btn_yes').click(function(self) { - $('.replace_file').hide(); + $('.replace_file, .fm_dimmer').hide(); var selected_item = $('.allowed_file_types .create_input input[type="text"]').val(), newFile = $('.currentpath').val() + selected_item, newFile = newFile.substr(1); @@ -461,7 +461,7 @@ define([ $('.file_manager_create_cancel').trigger('click'); }); $('.replace_file .btn_no').click(function() { - $('.replace_file').hide(); + $('.replace_file, .fm_dimmer').hide(); }); }, is_file_exist: function() { diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager_config.json b/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager_config.json index efb7fcb6d..f74430df7 100644 --- a/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager_config.json +++ b/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager_config.json @@ -1,25 +1,25 @@ { - "options": { - "culture": "en", - "lang": "py", - "defaultViewMode": "grid", - "autoload": true, - "showFullPath": false, - "dialog_type": "{{data.dialog_type}}", - "fileRoot": "{{data.fileroot}}", - "capabilities": [{% for i in data.capabilities %}{% if loop.index != 1 %}, {% endif %}"{{i}}"{% endfor %}], - "allowed_file_types": [{% for i in data.supported_types %}{% if loop.index != 1 %}, {% endif %}"{{i}}"{% endfor %}], - "platform_type": "{{ data.platform_type }}", - "show_volumes":"{{data.show_volumes}}" - }, - "security": { - "uploadPolicy": "{{ data.security.uploadPolicy }}", - "uploadRestrictions": [{% for i in data.security.uploadRestrictions %}{% if loop.index != 1 %}, {% endif %}"{{i}}"{% endfor %}] - }, - "upload": { - "multiple": "{{ data.upload.multiple }}", - "number": 20, - "fileSizeLimit": "{{ data.upload.fileSizeLimit }}", - "imagesOnly": false - } + "options": { + "culture": "en", + "lang": "py", + "defaultViewMode": "grid", + "autoload": true, + "showFullPath": false, + "dialog_type": "{{data.dialog_type}}", + "fileRoot": "{{data.fileroot}}", + "capabilities": [{% for i in data.capabilities %}{% if loop.index != 1 %}, {% endif %}"{{i}}"{% endfor %}], + "allowed_file_types": [{% for i in data.supported_types %}{% if loop.index != 1 %}, {% endif %}"{{i}}"{% endfor %}], + "platform_type": "{{ data.platform_type }}", + "show_volumes": {% if data.show_volumes %}true{% else %}false{% endif %} + }, + "security": { + "uploadPolicy": "{{ data.security.uploadPolicy }}", + "uploadRestrictions": [{% for i in data.security.uploadRestrictions %}{% if loop.index != 1 %}, {% endif %}"{{i}}"{% endfor %}] + }, + "upload": { + "multiple": "{{ data.upload.multiple }}", + "number": 20, + "fileSizeLimit": "{{ data.upload.fileSizeLimit }}", + "imagesOnly": false + } } diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/js/languages/en.js b/web/pgadmin/misc/file_manager/templates/file_manager/js/languages/en.js index dba85e8e8..cc2b91b4d 100644 --- a/web/pgadmin/misc/file_manager/templates/file_manager/js/languages/en.js +++ b/web/pgadmin/misc/file_manager/templates/file_manager/js/languages/en.js @@ -37,5 +37,6 @@ "successful_delete": "Delete successful.", "successful_rename": "Rename successful.", "upload": "Upload", - "yes": "Yes" + "yes": "Yes", + "could_not_retrieve_folder": "No files/folders found" } diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js b/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js index 7fcb2b9ef..d55dbe08e 100755 --- a/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js +++ b/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js @@ -10,6 +10,7 @@ */ (function($) { +"use strict"; // User alertify object var alertify = require("alertify"); @@ -22,10 +23,11 @@ var alertify = require("alertify"); // function to retrieve GET params $.urlParam = function(name) { var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); - if (results) + if (results) { return results[1]; - else + } else { return 0; + } }; var getFileExtension = function(name) { @@ -52,7 +54,9 @@ var getTransId = function() { // Load language file var loadLangFile = function(enjs) { - if($.urlParam('langCode') !== 0 && file_exists (enjs)) culture = $.urlParam('langCode'); + if($.urlParam('langCode') !== 0 && file_exists (enjs)) { + culture = $.urlParam('langCode'); + } return $.ajax({ async: false, url: enjs, @@ -61,12 +65,13 @@ var loadLangFile = function(enjs) { }); }; +var userconfig = file_manager_config_json; + // We retrieve config settings from filemanager.config.js var loadConfigFile = function (type) { type = (typeof type === "undefined") ? "user" : type; if (type == 'user') { url = file_manager_config_json; - userconfig = file_manager_config_json; } return $.ajax({ async: false, @@ -81,8 +86,8 @@ var loadConfigFile = function (type) { * Called on initial page load and on resize. */ var setDimensions = function() { - var main_container_height = ( $(window).height() ) / 2 + 35, - newH = main_container_height - $('#uploader').height() - 30; + var main_container_height = ( $(window).height() ) / 2 + 35; + var newH = main_container_height - $('#uploader').height() - 30; }; // Display Min Path @@ -114,13 +119,16 @@ var setViewButtonsFor = function(viewMode) { */ var preg_replace = function(array_pattern, array_pattern_replace, str) { var new_str = String (str); - for (i=0; i'+split_path[i]+''); + mypath = $(''+split_path[i]+'/'); $(mypath).appendTo($('.storage_dialog #uploader h1')); } } @@ -284,7 +294,7 @@ var setUploader = function(path){ // create new folder $('.create').unbind().click(function(){ - var foldername = lg.default_foldername; + var foldername = lg.new_folder; var $file_element, $file_element_list; @@ -292,10 +302,11 @@ var setUploader = function(path){ if($('.fileinfo').data('view') == 'grid'){ // template for creating new folder - var folder_div = "
  • "+ - "
    "+ - "

    New_Folder

    "+ - "
  • "; + var folder_div = + "
  • " + + "
    " + + "

    New_Folder

    " + + "
  • "; var path = $('.currentpath').val(), $file_element = $(folder_div); @@ -327,13 +338,15 @@ var setUploader = function(path){ else if($('.fileinfo').data('view') == 'list'){ // template to create new folder in table view - var folder_div = $(""+ - ""+ - "

    "+lg.new_folder+"

    "+ - ""+ - ""+ - ""+ - ""); + var folder_div = $( + "" + + "" + + "

    " + + lg.new_folder + "

    " + + "" + + "" + + "" + ); $file_element_list = $(folder_div); $('.fileinfo #contents.list').prepend($file_element_list); @@ -369,7 +382,7 @@ var setUploader = function(path){ foldername = cleanString(fname); var d = new Date(); // to prevent IE cache issues $.getJSON(fileConnector + '?mode=addfolder&path=' + $('.currentpath').val() + '&name=' + foldername + '&time=' + d.getMilliseconds(), function(resp){ - result = resp.data.result; + var result = resp.data.result; if(result['Code'] === 0){ alertify.success(lg.successful_added_folder); getFolderInfo(result['Parent']); @@ -408,7 +421,8 @@ var bindToolbar = function(data){ $('.file_manager').find('button.delete').hide(); } else { $('.file_manager').find('button.delete').click(function(){ - $('.fileinfo .delete_item').show(); + // hide dimmer + $('.fileinfo .delete_item, .fm_dimmer').show(); }); // take action based on pressed button yes or no @@ -433,6 +447,8 @@ var bindToolbar = function(data){ deleteItem(data); } } + // hide dimmer + $('.fileinfo .fm_dimmer').hide(); }); } @@ -541,7 +557,7 @@ var renameItem = function(data){ contentType: "application/json; charset=utf-8", async: false, success: function(resp){ - result = resp.data.result; + var result = resp.data.result; if(result['Code'] === 0){ var newPath = result['New Path'], newName = result['New Name'], @@ -604,7 +620,7 @@ var deleteItem = function(data){ contentType: "application/json; charset=utf-8", async: false, success: function(resp){ - result = resp.data.result; + var result = resp.data.result; if(result['Code'] === 0){ isDeleted = true; if(isDeleted) { @@ -627,9 +643,9 @@ var deleteItem = function(data){ }; -// hide message prompt if clicked no +// hide message prompt and dimmer if clicked no $('.delete_item button.btn_no').on('click', function() { - $('.delete_item').hide(); + $('.delete_item, .fileinfo .fm_dimmer').hide(); }); /*--------------------------------------------------------- @@ -642,7 +658,10 @@ $('.delete_item button.btn_no').on('click', function() { var getDetailView = function(path){ if(path.lastIndexOf('/') == path.length - 1){ var allowed_types = config.options.allowed_file_types; - getFolderInfo(path, allowed_types[0]); + var set_type = allowed_types[0]; + if(allowed_types[0] == "*") + set_type = allowed_types[1]; + getFolderInfo(path, set_type); } }; @@ -673,7 +692,7 @@ var getFileInfo = function(file){ contentType: "application/json; charset=utf-8", async: false, success: function(resp){ - data = resp.data.result; + var data = resp.data.result; if(data['Code'] === 0){ var properties = ''; if(data['Properties']['Size'] || parseInt(data['Properties']['Size'])==0) properties += '
    ' + lg.size + '
    ' + formatBytes(data['Properties']['Size']) + '
    '; @@ -696,7 +715,7 @@ var getFolderInfo = function(path, file_type=''){ // set default selected file type if (file_type === '') - var file_type = $('.change_file_types select').val(); + file_type = $('.change_file_types select').val(); // navigate to directory or path when clicked on breadcrumbs $('.file_manager a.breadcrumbs').unbind().on('click', function() { @@ -716,7 +735,9 @@ var getFolderInfo = function(path, file_type=''){ } // Display an activity indicator. - $('.fileinfo').find('span.activity').html(""); + $('.fileinfo').find('span.activity').html( + "" + ); // Retrieve the data and generate the markup. var d = new Date(); // to prevent IE cache issues @@ -747,13 +768,13 @@ var getFolderInfo = function(path, file_type=''){ } // generate HTML for files/folder and render into container - if(data){ + if(!_.isEmpty(data)){ if($('.fileinfo').data('view') == 'grid') { result += ''; } else { result += ''; - result += ''; + result += ''; + result += ''; result += ''; - for(key in data){ + for(var key in data){ var path = encodeURI(data[key]['Path']), props = data[key]['Properties'], cap_classes = ""; - for (cap in capabilities) { + for (var cap in capabilities) { if (has_capability(data[key], capabilities[cap])) { cap_classes += " cap_" + capabilities[cap]; } @@ -862,7 +886,18 @@ var getFolderInfo = function(path, file_type=''){ result += '
    ' + lg.name + '' + lg.size + '' + lg.modified + '
    '; + result += '' + lg.name +'' + lg.size + ''; + result += '' + lg.modified + '
    '; } } else { - result += '

    ' + lg.could_not_retrieve_folder + '

    '; + if($('.fileinfo').data('view') == 'grid') { + result += ''; + } + else { + result += ''; + result += ''; + result += ''; + } + result += '

    ' + lg.could_not_retrieve_folder + '

    '; + var cap_no_folders = ['upload', 'create'] + data['Capabilities'] = cap_no_folders; + bindToolbar(data); } // Add the new markup to the DOM. @@ -914,7 +949,7 @@ var getFolderInfo = function(path, file_type=''){ $('.fileinfo #contents li p').on('dblclick',function(e){ e.stopPropagation(); - $this = $(this); + var $this = $(this); var orig_value = decodeURI($this.find('span').attr('title')), newvalue = orig_value.substring(0, orig_value.indexOf('.')); @@ -937,7 +972,7 @@ var getFolderInfo = function(path, file_type=''){ $('.fileinfo #contents li p').on('blur dblclick','input', function(e){ e.stopPropagation(); var old_name = decodeURI($(this).siblings('span').attr('title')), - newvalue = old_name.substring(0, old_name.indexOf('.')); + newvalue = old_name.substring(0, old_name.indexOf('.')), last = getFileExtension(old_name); if(old_name.indexOf('.') == 0) last = '' @@ -1066,6 +1101,7 @@ var getFolderInfo = function(path, file_type=''){ } }); + var data_cap = {} /* * Bind click events * Select items - afolder dblclick @@ -1092,7 +1128,6 @@ var getFolderInfo = function(path, file_type=''){ } }); - data_cap = {} data_cap['Capabilities'] = capabilities; $('.fileinfo').find('#contents li').click(function(e){ e.stopPropagation(); @@ -1199,7 +1234,7 @@ var enab_dis_level_up = function() { $('.show_selected_file').remove(); setTimeout(function() { var b = $('.currentpath').val(), - $level_up = $('.file_manager').find('button.level-up'); + $level_up = $('.file_manager').find('button.level-up'), $home_btn = $('.file_manager').find('button.home'); if (b === fileRoot) { $level_up.attr('disabled', 'disabled'); @@ -1225,12 +1260,12 @@ var root_url = '{{ url_for("file_manager.index") }}', file_manager_config_json = root_url+t_id+'/file_manager_config.json', file_manager_config_js = root_url+'file_manager_config.js', fileConnector = root_url+'filemanager/'+t_id+'/', - confg = loadConfigFile(); - + cfg = loadConfigFile(), + config; // load user configuration file -if (confg.readyState == 4) - config = JSON.parse(confg.responseText); +if (cfg.readyState == 4) + config = JSON.parse(cfg.responseText); var fileRoot = config.options.fileRoot, capabilities = config.options.capabilities; @@ -1240,7 +1275,7 @@ var fileRoot = config.options.fileRoot, * through culture var or from URL */ var lg = [], - enjs = '{{ url_for("file_manager.index") }}'+"en.js", + enjs = '{{ url_for("file_manager.index") }}' + "en.js", lgf = loadLangFile(enjs); if (lgf.readyState == 4) @@ -1250,18 +1285,37 @@ if (lgf.readyState == 4) $('.file_manager').find('button.home').attr('disabled', 'disabled'); $('.file_manager').find('button.rename').attr('disabled', 'disabled'); -if (config.options.dialog_type == 'select_file' || - config.options.dialog_type == 'create_file' || - config.options.dialog_type == 'storage_dialog') { - +if ( + config.options.dialog_type == 'select_file' || + config.options.dialog_type == 'create_file' || + config.options.dialog_type == 'storage_dialog' +) { // Create file selection dropdown var allowed_types = config.options.allowed_file_types, - types_len = allowed_types.length; + types_len = allowed_types.length, + select_box = '', file_type = "All Files"; if(types_len > 0) { - var i = 0, + var i = 0, j = 0, select_box = "
    "; @@ -1300,6 +1354,8 @@ if (config.options.dialog_type == 'create_file') { ---------------------------------------------------------*/ $(function(){ + var expandedFolder = ''; + if(config.extra_js) { for(var i=0; i< config.extra_js.length; i++) { $.ajax({ @@ -1312,10 +1368,6 @@ $(function(){ if($.urlParam('expandedFolder') != 0) { expandedFolder = $.urlParam('expandedFolder'); - fullexpandedFolder = fileRoot + expandedFolder; - } else { - expandedFolder = ''; - fullexpandedFolder = null; } // Adjust layout. @@ -1341,10 +1393,25 @@ $(function(){ $(".newfile").change(function() { $(".filepath").val($(this).val()); }); - /** Input file Replacement - end */ } + // stop click event on dimmer click + $('.fileinfo .fm_dimmer').on('click', function(e) { + e.stopPropagation(); + }); + + $('.fileinfo .replace_file').not( + $(this).find('span.pull-right') + ).on( + 'click', function(e) { + $('#uploader .filemanager-btn-group').unbind().on( + 'click', function() { + $('.fileinfo .delete_item, .fileinfo .replace_file, .fileinfo .fm_dimmer').hide(); + }); + e.stopPropagation(); + }); + // Set initial view state. $('.fileinfo').data('view', config.options.defaultViewMode); setViewButtonsFor(config.options.defaultViewMode);
    ' + lg.name + '' + lg.size + '' + lg.modified + '