From 4601f119867b87ab0b51c2e10ef4391145dc8661 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 28 Feb 2022 16:52:55 +0100 Subject: [PATCH 1/2] add all storage config rows in one go on load this prevents repeated reflows Signed-off-by: Robin Appelman --- apps/files_external/js/settings.js | 30 ++++++++++++++------ apps/files_external/tests/js/settingsSpec.js | 10 +++---- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 823c9a364a8fb..6bef914acf827 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -789,9 +789,10 @@ MountConfigListView.prototype = _.extend({ * * @param {StorageConfig} storageConfig storage config to pull values from * @param {jQuery.Deferred} onCompletion + * @param {boolean} deferAppend * @return {jQuery} created row */ - newStorage: function(storageConfig, onCompletion) { + newStorage: function(storageConfig, onCompletion, deferAppend) { var mountPoint = storageConfig.mountPoint; var backend = this._allBackends[storageConfig.backend]; @@ -803,8 +804,11 @@ MountConfigListView.prototype = _.extend({ } // FIXME: Replace with a proper Handlebar template - var $tr = this.$el.find('tr#addMountPoint'); - this.$el.find('tbody').append($tr.clone()); + var $template = this.$el.find('tr#addMountPoint'); + var $tr = $template.clone(); + if (!deferAppend) { + $tr.insertBefore($template); + } $tr.data('storageConfig', storageConfig); $tr.show(); @@ -812,7 +816,9 @@ MountConfigListView.prototype = _.extend({ $tr.find('td').last().removeAttr('style'); $tr.removeAttr('id'); $tr.find('select#selectBackend'); - addSelect2($tr.find('.applicableUsers'), this._userListLimit); + if (!deferAppend) { + addSelect2($tr.find('.applicableUsers'), this._userListLimit); + } if (storageConfig.id) { $tr.data('id', storageConfig.id); @@ -928,7 +934,8 @@ MountConfigListView.prototype = _.extend({ contentType: 'application/json', success: function(result) { var onCompletion = jQuery.Deferred(); - $.each(result, function(i, storageParams) { + var $rows = $(); + Object.values(result).forEach(function(storageParams) { var storageConfig; var isUserGlobal = storageParams.type === 'system' && self._isPersonal; storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash @@ -938,7 +945,7 @@ MountConfigListView.prototype = _.extend({ storageConfig = new self._storageConfigClass(); } _.extend(storageConfig, storageParams); - var $tr = self.newStorage(storageConfig, onCompletion); + var $tr = self.newStorage(storageConfig, onCompletion,true); // userglobal storages must be at the top of the list $tr.detach(); @@ -957,7 +964,10 @@ MountConfigListView.prototype = _.extend({ // userglobal storages do not expose configuration data $tr.find('.configuration').text(t('files_external', 'Admin defined')); } + $rows = $rows.add($tr); }); + addSelect2(self.$el.find('.applicableUsers'), this._userListLimit); + self.$el.find('tr#addMountPoint').before($rows); var mainForm = $('#files_external'); if (result.length === 0 && mainForm.attr('data-can-create') === 'false') { mainForm.hide(); @@ -980,14 +990,18 @@ MountConfigListView.prototype = _.extend({ contentType: 'application/json', success: function(result) { var onCompletion = jQuery.Deferred(); - $.each(result, function(i, storageParams) { + var $rows = $(); + Object.values(result).forEach(function(storageParams) { storageParams.mountPoint = (storageParams.mountPoint === '/')? '/' : storageParams.mountPoint.substr(1); // trim leading slash var storageConfig = new self._storageConfigClass(); _.extend(storageConfig, storageParams); - var $tr = self.newStorage(storageConfig, onCompletion); + var $tr = self.newStorage(storageConfig, onCompletion, true); self.recheckStorageConfig($tr); + $rows = $rows.add($tr); }); + addSelect2($rows.find('.applicableUsers'), this._userListLimit); + self.$el.find('tr#addMountPoint').before($rows); onCompletion.resolve(); onLoaded2.resolve(); } diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js index 0bdb9f5badb4e..189979411112b 100644 --- a/apps/files_external/tests/js/settingsSpec.js +++ b/apps/files_external/tests/js/settingsSpec.js @@ -183,8 +183,8 @@ describe('OCA.Files_External.Settings tests', function() { }); describe('selecting backend', function() { it('populates the row and creates a new empty one', function() { - var $firstRow = view.$el.find('tr:first'); selectBackend('\\OC\\TestBackend'); + var $firstRow = view.$el.find('tr:first'); expect($firstRow.find('.backend').text()).toEqual('Test Backend'); expect($firstRow.find('.selectBackend').length).toEqual(0); @@ -205,8 +205,8 @@ describe('OCA.Files_External.Settings tests', function() { // TODO: check "remove" button visibility }); it('shows row even if selection row is hidden', function() { - view.$el.find('tr#addMountPoint').hide(); selectBackend('\\OC\\TestBackend'); + view.$el.find('tr#addMountPoint').hide(); expect(view.$el.find('tr:first').is(':visible')).toBe(true); expect(view.$el.find('tr#addMountPoint').is(':visible')).toBe(false); }); @@ -217,8 +217,8 @@ describe('OCA.Files_External.Settings tests', function() { var $tr; beforeEach(function() { - $tr = view.$el.find('tr:first'); selectBackend('\\OC\\TestBackend'); + $tr = view.$el.find('tr:first'); }); it('saves storage after clicking the save button', function() { var $field1 = $tr.find('input[data-parameter=field1]'); @@ -274,8 +274,8 @@ describe('OCA.Files_External.Settings tests', function() { var $tr; beforeEach(function() { - $tr = view.$el.find('tr:first'); selectBackend('\\OC\\InputsTestBackend'); + $tr = view.$el.find('tr:first'); }); it('lists missing fields in storage errors', function() { @@ -342,9 +342,9 @@ describe('OCA.Files_External.Settings tests', function() { var $td; beforeEach(function() { + selectBackend('\\OC\\TestBackend'); $tr = view.$el.find('tr:first'); $td = $tr.find('.mountOptionsToggle'); - selectBackend('\\OC\\TestBackend'); }); it('shows popovermenu when clicking on toggle button, hides when clicking outside', function() { From 7933de00f3d03d4ec6d087edfc2c14cd0c65feaa Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 28 Feb 2022 17:02:17 +0100 Subject: [PATCH 2/2] don't recheck config automatically when there are a large number of storages Signed-off-by: Robin Appelman --- apps/files_external/js/settings.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 6bef914acf827..01c2c3bc95341 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -989,15 +989,21 @@ MountConfigListView.prototype = _.extend({ url: OC.generateUrl(url), contentType: 'application/json', success: function(result) { + result = Object.values(result); var onCompletion = jQuery.Deferred(); var $rows = $(); - Object.values(result).forEach(function(storageParams) { + result.forEach(function(storageParams) { storageParams.mountPoint = (storageParams.mountPoint === '/')? '/' : storageParams.mountPoint.substr(1); // trim leading slash var storageConfig = new self._storageConfigClass(); _.extend(storageConfig, storageParams); var $tr = self.newStorage(storageConfig, onCompletion, true); - self.recheckStorageConfig($tr); + // don't recheck config automatically when there are a large number of storages + if (result.length < 20) { + self.recheckStorageConfig($tr); + } else { + self.updateStatus($tr, StorageConfig.Status.INDETERMINATE, t('files_external', 'Automatic status checking is disabled due to the large number of configured storages, click to check status')); + } $rows = $rows.add($tr); }); addSelect2($rows.find('.applicableUsers'), this._userListLimit);