diff --git a/web/package.json b/web/package.json
index d88885697..8edd4d83f 100644
--- a/web/package.json
+++ b/web/package.json
@@ -91,7 +91,7 @@
"snapsvg": "^0.5.1",
"spectrum-colorpicker": "^1.8.0",
"split.js": "^1.5.10",
- "tablesorter": "^2.31.1",
+ "tablesorter": "^2.31.2",
"tempusdominus-bootstrap-4": "^5.1.2",
"tempusdominus-core": "^5.0.3",
"underscore": "^1.9.1",
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 1fc5bd374..9bb060c03 100644
--- a/web/pgadmin/misc/file_manager/static/css/file_manager.css
+++ b/web/pgadmin/misc/file_manager/static/css/file_manager.css
@@ -14,10 +14,10 @@
.fileinfo #contents li .fm_file_rename,
.fileinfo table#contents tr td:first-child input.fm_file_rename {
display: none;
- width: 80px;
+ width: 100%;
margin: 0 auto;
text-align: center;
- height: 17px;
+ height: inherit;
}
.fileinfo > h1 {
diff --git a/web/pgadmin/misc/file_manager/static/js/utility.js b/web/pgadmin/misc/file_manager/static/js/utility.js
index 25aeaebe0..26077e7c0 100644
--- a/web/pgadmin/misc/file_manager/static/js/utility.js
+++ b/web/pgadmin/misc/file_manager/static/js/utility.js
@@ -432,13 +432,207 @@ define([
return permission;
};
+ var getNoDataView = function(data) {
+ var lg = pgAdmin.FileUtils.lg;
+ var cap_no_folders = ['upload', 'create'];
+ data.Capabilities = cap_no_folders;
+ bindToolbar(data);
+
+ return `
${lg.could_not_retrieve_folder}
`;
+ };
+
+ var getGridView = function(data, capabilities) {
+ let ret_ele = '';
+
+ if(no_data) {
+ ret_ele += getNoDataView(data);
+ }
+ return ret_ele;
+ };
+
+ var getListView = function(data, capabilities) {
+ let lg = pgAdmin.FileUtils.lg;
+ let no_data = _.isEmpty(data);
+
+ /* file_listing_table class makes height 100%, because of which No folder message is not displayed
+ * file_listing_table_no_data will be removed when new folder is created
+ */
+ let ret_ele =
+ `
+
+
+
+ ${lg.name}
+
+
+ ${lg.size}
+
+
+ ${lg.modified}
+
+
+
+ `;
+
+ if(!no_data) {
+ ret_ele += Object.keys(data).sort(function keyOrder(x, y) {
+ return pgAdmin.natural_sort(x.toLowerCase(), y.toLowerCase());
+ }).map(function(key) {
+ let item_data = data[key],
+ props = item_data.Properties,
+ icon_type = '',
+ class_type = '',
+ cap_classes = '';
+
+ cap_classes = Object.keys(capabilities).map(function(cap) {
+ if (has_capability(item_data, capabilities[cap])) {
+ return 'cap_' + capabilities[cap];
+ }
+ }).join(' ');
+
+ item_data.Capabilities = capabilities;
+ bindToolbar(item_data);
+
+ if (item_data.file_type == 'dir') {
+ class_type = 'tbl_folder';
+ icon_type = 'fa fa-folder-open fm_folder_list';
+ } else if (item_data.file_type == 'drive') {
+ class_type = 'tbl_drive';
+ icon_type = 'fa fa-hdd-o';
+ } else {
+ class_type = 'tbl_file';
+ icon_type = 'fa fa-file-text-o';
+ }
+
+ /* For the html ele */
+ let item_ele =
+ `
+ `;
+
+ let data_protected = '';
+ if (item_data.Protected == 1) {
+ data_protected = ' ';
+ }
+ if (!has_capability(data[key], 'rename')) {
+ item_ele +=
+ `${data_protected};
+ ${_.escape(item_data.Filename)} `;
+ } else {
+ item_ele +=
+ `
+
+
+
+
+ ${data_protected}
+ ${_.escape(item_data.Filename)}
+
+
+
`;
+ }
+ item_ele += '
';
+ if (props.Size && props.Size != '') {
+ item_ele += `${props.Size} `;
+ } else {
+ item_ele += ' ';
+ }
+
+ if (props['Date Modified'] && props['Date Modified'] != '') {
+ item_ele += `${props['Date Modified']} `;
+ } else {
+ item_ele += ' ';
+ }
+
+ item_ele += ' ';
+
+ return item_ele;
+ }).join('\n');
+ }
+
+ ret_ele +=
+ `
+
`;
+
+ if(no_data) {
+ ret_ele += getNoDataView(data);
+ }
+ return ret_ele;
+ };
/*
* Retrieves data for all items within the given folder and
* creates a list view.
*/
- var getFolderInfo = function(path, file_type) {
+ var getFolderInfo = function(path, file_type, user_input) {
$('.storage_dialog #uploader .input-path').prop('disabled', true);
if (!file_type) {
file_type = '';
@@ -446,6 +640,9 @@ define([
var capabilities = pgAdmin.FileUtils.data.Capabilities;
// Update location for status, upload, & new folder functions.
pgAdmin.FileUtils.setUploader(path);
+ if(user_input) {
+ $('.storage_dialog #uploader .input-path').val(path+user_input);
+ }
// set default selected file type
if (file_type === '') {
@@ -489,7 +686,6 @@ define([
'show_hidden': $('#show_hidden').prop('checked'),
};
- var lg = pgAdmin.FileUtils.lg;
$.ajax({
type: 'POST',
data: JSON.stringify(post_data),
@@ -513,184 +709,42 @@ define([
var $this, orig_value, newvalue;
// generate HTML for files/folder and render into container
- if (!_.isEmpty(data)) {
- if ($('.fileinfo').data('view') == 'grid') {
- result += '';
- } else {
- result += '';
- result += '';
- result += '' + lg.name + ' ';
- result += '' + lg.size + ' ';
- result += '' + lg.modified + ' ';
- result += '';
-
- Object.keys(data).sort(function keyOrder(x, y) {
- return pgAdmin.natural_sort(x.toLowerCase(), y.toLowerCase());
- }).forEach(function(key) {
- var path = _.escape((data[key]).Path),
- props = (data[key]).Properties,
- cap_classes = '',
- cap, class_type, icon_type;
-
- for (cap in capabilities) {
- if (has_capability(data[key], capabilities[cap])) {
- cap_classes += ' cap_' + capabilities[cap];
- }
- }
-
- (data[key]).Capabilities = capabilities;
- bindToolbar(data[key]);
-
- if ((data[key]).file_type == 'dir') {
- class_type = 'tbl_folder';
- icon_type = 'fa fa-folder-open fm_folder_list';
- } else if ((data[key]).file_type == 'drive') {
- class_type = 'tbl_drive';
- icon_type = 'fa fa-hdd-o';
- } else {
- class_type = 'tbl_file';
- icon_type = 'fa fa-file-text-o';
- }
-
- result += '';
-
- var fm_filename = (data[key]).Filename;
- if (fm_filename.length > 48) {
- fm_filename = (data[key]).Filename.substr(0, 48) + '...';
- }
- fm_filename = _.escape(fm_filename);
+ if ($('.fileinfo').data('view') == 'grid') {
+ result += getGridView(data, capabilities);
+ } else {
+ result += getListView(data, capabilities);
+ }
- result += '';
+ // Add the new markup to the DOM.
+ $('.fileinfo .file_listing').html(result);
- let data_protected = '';
- if ((data[key]).Protected == 1) {
- data_protected = ' ';
- }
- if (!has_capability(data[key], 'rename')) {
- result += data_protected;
- result += '' +
- fm_filename + ' ';
- } else {
- result += ''+
- '
' +
- ' ' +
- data_protected +
- '' + fm_filename + ' ' +
- '
' +
- '
';
- }
- if (props.Size && props.Size != '') {
- result += '' +
- props.Size + ' ';
- } else {
- result += ' ';
- }
+ let $listing_table = $('.fileinfo .file_listing .file_listing_table');
- if (props['Date Modified'] && props['Date Modified'] != '') {
- result += '' + props['Date Modified'] + ' ';
- } else {
- result += ' ';
- }
+ $listing_table.tablesorter({
+ widgets: [ 'resizable', 'stickyHeaders' ],
+ widgetOptions : {
+ stickyHeaders_attachTo:'.file_listing',
+ stickyHeaders_offset: 0,
+ resizable_widths: ['400px', '100px', '175px'],
+ },
+ });
- result += ' ';
- });
+ /* In order to fit our UI, some things need to be explicitly set
+ * as tablesorter resizable is creating trouble.
+ */
+ $listing_table.on( 'resizableComplete', function() {
+ let wo = this.config.widgetOptions;
+ $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]);
+ });
- result += ' ';
- result += '
';
- }
- } else {
- if ($('.fileinfo').data('view') == 'grid') {
- result += '';
- } else {
- /* file_listing_table class makes height 100%, because of which No folder message is not displayed
- * file_listing_table_no_data will be removed when new folder is created
- */
- result += '';
- result += '' + lg.name + ' ' +
- '' + lg.size + ' ' +
- '' + lg.modified + ' ' +
- ' ' +
- ' ';
- result += '
';
+ $listing_table.on( 'tablesorter-ready', function() {
+ let wo = this.config.widgetOptions;
+ if($.tablesorter.storage($listing_table[0], 'tablesorter-table-resized-width') === '') {
+ $.tablesorter.resizable.setWidth($listing_table, $('.fileinfo .file_listing').width());
}
- 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.
- $('.fileinfo .file_listing').html(result);
- $('.fileinfo .file_listing #contents').tablesorter();
+ $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]);
+ $listing_table.trigger('resizableUpdate');
+ });
// rename file/folder
$('.file_manager button.rename').off().on('click', function(e) {
@@ -720,7 +774,7 @@ define([
} else if ($('.fileinfo').data('view') == 'list') {
e.stopPropagation();
$this = $('.fileinfo').find(
- 'table#contents tbody tr.selected td:first-child div'
+ 'table#contents tbody tr.selected td.tbl_file'
);
orig_value = decodeURI($this.find('span.less_text').html()),
newvalue = orig_value.substring(0, orig_value.lastIndexOf('.'));
@@ -729,15 +783,15 @@ define([
newvalue = decodeURI(orig_value);
}
- $this.find('input').toggle().val(newvalue).trigger('focus');
- $this.find('span').toggle();
+ $this.find('.fm_file_rename').toggle().val(newvalue).trigger('focus');
+ $this.find('.fm_file_name').toggle();
// Rename folder/file on pressing enter key
$('.file_manager').off().on('keyup', function(e) {
if (e.keyCode == 13) {
e.stopPropagation();
- $('.fileinfo table#contents tr.selected td div').find(
- 'input'
+ $('.fileinfo table#contents tr.selected td.tbl_file').find(
+ 'fm_file_rename'
).trigger('blur');
}
});
@@ -1153,8 +1207,15 @@ define([
$('.allowed_file_types select').on('change', function() {
var selected_val = $(this).val(),
- curr_path = $('.currentpath').val();
- getFolderInfo(curr_path, selected_val);
+ curr_path = $('.currentpath').val(),
+ user_input_file = null,
+ input_path = $('.storage_dialog #uploader .input-path').val();
+ if (curr_path.endsWith('/')) {
+ user_input_file = input_path.substring(curr_path.lastIndexOf('/')+1);
+ } else {
+ user_input_file = input_path.substring(curr_path.lastIndexOf('\\')+1);
+ }
+ getFolderInfo(curr_path, selected_val, user_input_file);
});
// If user have preference to show hidden files
@@ -1623,15 +1684,21 @@ define([
} else if ($('.fileinfo').data('view') == 'list') {
// template to create new folder in table view
folder_div = $(
- '' +
- '' +
- ' ' +
- '' + lg.new_folder + ' ' +
- ' '+
- ' '+
- ' ' +
- ' ' +
- ' '
+ `
+
+
+
+
+
+
+ ${lg.new_folder}
+
+
+
+
+
+
+ `
);
$file_element_list = $(folder_div);
@@ -1639,7 +1706,7 @@ define([
tableEl.removeClass('file_listing_table_no_data');
tableEl.find('tbody').prepend($file_element_list);
- $file_element_list.find('td span.less_text').toggle();
+ $file_element_list.find('td .fm_file_name').toggle();
$file_element_list.find('td input').toggle().val(lg.new_folder).select();
// rename folder/file on pressing enter key
@@ -1656,7 +1723,8 @@ define([
var text_value = $file_element_list.find('td input').val();
path = $('.currentpath').val();
$file_element_list.find('td input').toggle();
- $file_element_list.find('td span.less_text').toggle().html(text_value);
+ $file_element_list.find('td .fm_file_name span.less_text').html(text_value);
+ $file_element_list.find('td .fm_file_name').toggle();
if (text_value === undefined) {
text_value = lg.new_folder;
}
diff --git a/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss b/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
index 6bd173dc9..fc9019036 100644
--- a/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
+++ b/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
@@ -5,38 +5,25 @@
.file_listing {
min-width: 100%;
+ position: relative;
+ overflow: auto;
.file_listing_table_no_data {
height: auto !important;
}
.file_listing_table {
- height: 100%;
- display: block;
- padding: 0;
- overflow-y: hidden !important;
- }
-
- .file_listing_table thead {
- display: table;
- width: 100%;
+ table-layout: fixed;
+ & td, &th {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
}
.file_listing_table thead tr {
- position: relative;
- display: block;
- width: 100%;
border-bottom: $panel-border;
}
- .file_listing_table tbody {
- display: block;
- overflow: auto;
- width: 100%;
- /* 100% minus thead height */
- height: calc(100% - 30px);
- }
-
.file_listing_table tbody tr {
max-width: 100%;
width: 100%;
@@ -45,21 +32,20 @@
.file_listing_table tbody tr td:nth-child(1),
.file_listing_table thead tr th:nth-child(1) {
width: 400px;
- min-width: 400px;
+ min-width: 100px;
}
.file_listing_table tbody tr td:nth-child(2),
.file_listing_table thead tr th:nth-child(2) {
width: 100px;
min-width: 100px;
- max-width: 100px;
}
.file_listing_table tbody tr td:nth-child(3),
.file_listing_table thead tr th:nth-child(3) {
- width: 100%;
- min-width: 100%;
- max-width: 100%;
+ width: 200px;
+ min-width: 200px;
+ max-width: 200px;
}
}
@@ -83,13 +69,12 @@
display: block;
}
-.fileinfo table#contents tr td:first-child {
+.fileinfo table#contents tr td {
& span.less_text {
- width: 100%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
- max-width: calc(400px - 30px);
+ display: block;
}
& .fa {
diff --git a/web/pgadmin/static/scss/_pgadmin.style.scss b/web/pgadmin/static/scss/_pgadmin.style.scss
index e6e4dabb9..32b7a08b7 100644
--- a/web/pgadmin/static/scss/_pgadmin.style.scss
+++ b/web/pgadmin/static/scss/_pgadmin.style.scss
@@ -652,12 +652,15 @@ fieldset.inline-fieldset > div {
outline: none;
}
-input[type="checkbox"]:focus,
-a:focus {
- &.navbar-brand, &.dropdown-item {
- outline: none !important;
+input[type="checkbox"],
+select,
+a {
+ &:focus {
+ &.navbar-brand, &.dropdown-item {
+ outline: none !important;
+ }
+ outline: 2px solid $input-focus-border-color !important;
}
- outline: 2px solid $input-focus-border-color !important;
}
div.rolmembership {
@@ -873,6 +876,14 @@ table.table-bottom-border {
}
}
+table.table-right-border {
+ tr {
+ & td:last-of-type, & th:last-of-type {
+ border-right: $panel-border;
+ }
+ }
+}
+
table.table-empty-rows{
thead th:last-of-type,tr:last-of-type{
& td, & th {
diff --git a/web/yarn.lock b/web/yarn.lock
index 9ac41f348..d4f3cfc86 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -8816,10 +8816,10 @@ table@^5.2.3:
slice-ansi "^2.1.0"
string-width "^3.0.0"
-tablesorter@^2.31.1:
- version "2.31.1"
- resolved "https://registry.yarnpkg.com/tablesorter/-/tablesorter-2.31.1.tgz#19c550c555fad4d3814500bfd4373e8b4f972305"
- integrity sha512-xXFYMu2vc73oKNWcf+hdId1Rvtl2W3zS9pJAX0BWjJcn6zmhquXCk+kuBQzKid/Iq/T8ERPlyAJ7q0Wkgym7Sg==
+tablesorter@^2.31.2:
+ version "2.31.2"
+ resolved "https://registry.yarnpkg.com/tablesorter/-/tablesorter-2.31.2.tgz#3a37759c2b269688138b46f88454d61d1895b275"
+ integrity sha512-e4ubgJpHNXHWm8tR+eGt2BPAqoOCY+uOQ6PVDCgtklCtJO6VHmORmjZdtm9aYqSqWsUih72wB0nS95JiXZ2l2g==
dependencies:
jquery ">=1.2.6"