From 9e9157cb48e48cfd5b3719f3b5724e10f6ad3dd5 Mon Sep 17 00:00:00 2001 From: Merci Jacob <68013195+jacob-js@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:52:01 +0200 Subject: [PATCH] Fix the sieve filters page which is duplicating the modal content (#1358) * Fix the sieve filters page which is duplicating the modal content * Fix selenium tests: the navigation should be awaited only if the expected route isn't yet active * Deal with flaky tests --- modules/core/navigation/navigation.js | 5 +- modules/core/site.js | 8 +- .../sievefilters/js_modules/route_handlers.js | 4 + modules/sievefilters/site.js | 662 +----------------- tests/selenium/folder_list.py | 3 +- tests/selenium/profiles.py | 2 +- tests/selenium/settings.py | 6 +- 7 files changed, 27 insertions(+), 663 deletions(-) diff --git a/modules/core/navigation/navigation.js b/modules/core/navigation/navigation.js index 041475b6c2..8321efd8d0 100644 --- a/modules/core/navigation/navigation.js +++ b/modules/core/navigation/navigation.js @@ -36,7 +36,10 @@ window.addEventListener('load', function() { $(document).on('click', 'a', function(event) { if ($(this).attr('href') !== "#" && $(this).attr('target') !== '_blank' && !$(this).data('external')) { event.preventDefault(); - navigate($(this).attr('href')); + const currentPage = new URL(window.location.href).searchParams.toString(); + if (currentPage !== $(this).attr('href').split('?')[1]) { + navigate($(this).attr('href')); + } } }); diff --git a/modules/core/site.js b/modules/core/site.js index 845d5c37cb..afbffcccd4 100644 --- a/modules/core/site.js +++ b/modules/core/site.js @@ -303,9 +303,14 @@ function Hm_Modal(options) { }; this.opts = { ...defaults, ...options }; + this.modal = $(`#${this.opts.modalId}`); this.init = function () { - if (this.modal) { + if (this.modal.length) { + this.modalContent = this.modal.find('.modal-body'); + this.modalTitle = this.modal.find('.modal-title'); + this.modalFooter = this.modal.find('.modal-footer'); + this.bsModal = bootstrap.Modal.getOrCreateInstance(this.modal[0]); return; } @@ -338,6 +343,7 @@ function Hm_Modal(options) { }; this.open = () => { + this.bsModal = bootstrap.Modal.getOrCreateInstance(this.modal[0]); this.bsModal.show(); }; diff --git a/modules/sievefilters/js_modules/route_handlers.js b/modules/sievefilters/js_modules/route_handlers.js index 970e04dc64..fd12a92a2e 100644 --- a/modules/sievefilters/js_modules/route_handlers.js +++ b/modules/sievefilters/js_modules/route_handlers.js @@ -4,4 +4,8 @@ function applyBlockListPageHandlers() { function applySieveFiltersPageHandler() { sieveFiltersPageHandler(); + + return () => { + cleanUpSieveFiltersPage(); + }; } \ No newline at end of file diff --git a/modules/sievefilters/site.js b/modules/sievefilters/site.js index 73a655470b..aefc5f6c14 100644 --- a/modules/sievefilters/site.js +++ b/modules/sievefilters/site.js @@ -289,663 +289,11 @@ function blockListPageHandlers() { }); } -if (hm_page_name() === 'sieve_filters') { - /************************************************************************************** - * BOOTSTRAP SCRIPT MODAL - **************************************************************************************/ - var edit_script_modal = new Hm_Modal({ - size: 'xl', - modalId: 'myEditScript' - }); - - // set content - edit_script_modal.setContent(document.querySelector('#edit_script_modal').innerHTML); - $('#edit_script_modal').remove(); - - // add a button - edit_script_modal.addFooterBtn('Save', 'btn-primary', async function () { - save_script(current_account); - }); - - - /************************************************************************************** - * BOOTSTRAP SIEVE FILTER MODAL - **************************************************************************************/ - var edit_filter_modal = new Hm_Modal({ - size: 'xl', - modalId: 'myEditFilterModal', - }); - - // set content - edit_filter_modal.setContent(document.querySelector('#edit_filter_modal').innerHTML); - $('#edit_filter_modal').remove(); - - // add a button - edit_filter_modal.addFooterBtn('Save', 'btn-primary ms-auto', async function () { - let result = save_filter(current_account); - if (result) { - edit_filter_modal.hide(); - } - }); - - // add another button - edit_filter_modal.addFooterBtn('Convert to code', 'btn-warning', async function () { - let result = save_filter(current_account, true); - if (result) { - edit_filter_modal.hide(); - } - }); - - - function ordinal_number(n) - { - let ord = 'th'; - - if (n % 10 == 1 && n % 100 != 11) { - ord = 'st'; - } else if (n % 10 == 2 && n % 100 != 12) { - ord = 'nd'; - } else if (n % 10 == 3 && n % 100 != 13) { - ord = 'rd'; - } - - return n + ord; - } - - /************************************************************************************** - * FUNCTIONS - **************************************************************************************/ - function save_filter(imap_account, gen_script = false) { - let validation_failed = false - let conditions_parsed = [] - let actions_parsed = [] - let conditions = $('select[name^=sieve_selected_conditions_field]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - - let conditions_type = $('select[name^=sieve_selected_conditions_options]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - - let conditions_value = $('input[name^=sieve_selected_option_value]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - - let conditions_extra_value = $('input[name^=sieve_selected_extra_option_value]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - - let idx = 0; - if (conditions.length === 0) { - Hm_Utils.add_sys_message(hm_trans('You must provide at least one condition'), 'danger'); - return false; - } - - Hm_Utils.clear_sys_messages(); - conditions.forEach(function (elem, key) { - if (conditions_value[idx] === "" && conditions_value[idx] !== 'none') { - let order = ordinal_number(key + 1); - let previous_messages = $('.sys_messages').html(); - previous_messages += previous_messages ? '
': ''; - Hm_Utils.add_sys_message('The ' + order + ' condition (' + elem + ') must be provided', 'danger'); - validation_failed = true; - } - conditions_parsed.push( - { - 'condition': elem, - 'type': conditions_type[idx], - 'extra_option': conditions[idx].extra_option, - 'extra_option_value': conditions_extra_value[idx], - 'value': conditions_value[idx] - } - ) - idx = idx + 1; - }); - - let actions_type = $('select[name^=sieve_selected_actions]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - let actions_value = $('[name^=sieve_selected_action_value]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - let actions_field_type = $('[name^=sieve_selected_action_value]').map(function(idx, elem) { - return $(elem).attr('type'); - }).get(); - let actions_extra_value = $('input[name^=sieve_selected_extra_action_value]').map(function(idx, elem) { - return $(elem).val(); - }).get(); - - if (actions_type.length === 0) { - Hm_Utils.add_sys_message(hm_trans('You must provide at least one action'), 'danger'); - return false; - } - - idx = 0; - actions_type.forEach(function (elem, key) { - console.log(actions_field_type[idx]) - if (actions_value[idx] === "" && actions_field_type[idx] !== 'hidden') { - let order = ordinal_number(key + 1); - let previous_messages = $('.sys_messages').html(); - previous_messages += previous_messages ? '
': ''; - Hm_Utils.add_sys_message('The ' + order + ' action (' + elem + ') must be provided', 'danger'); - validation_failed = true; - } - actions_parsed.push( - { - 'action': elem, - 'value': actions_value[idx], - 'extra_option': actions_type[idx].extra_option, - 'extra_option_value': actions_extra_value[idx], - } - ) - idx = idx + 1; - }); - - if ($('#stop_filtering').is(':checked')) { - actions_parsed.push( - { - 'action': "stop", - 'value': "", - 'extra_option': "", - 'extra_option_value': "", - } - ) - } - if ($('.modal_sieve_filter_name').val() == "") { - Hm_Utils.add_sys_message(hm_trans('Filter name is required'), 'danger'); - return false; - } - - if (validation_failed) { - return false; - } - - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_save_filter'}, - {'name': 'imap_account', 'value': imap_account}, - {'name': 'sieve_filter_name', 'value': $('.modal_sieve_filter_name').val()}, - {'name': 'sieve_filter_priority', 'value': $('.modal_sieve_filter_priority').val()}, - {'name': 'is_editing_filter', 'value': is_editing_filter}, - {'name': 'current_editing_filter_name', 'value': current_editing_filter_name}, - {'name': 'conditions_json', 'value': JSON.stringify(conditions_parsed)}, - {'name': 'actions_json', 'value': JSON.stringify(actions_parsed)}, - {'name': 'filter_test_type', 'value': $('.modal_sieve_filter_test').val()}, - {'name': 'gen_script', 'value': gen_script}, - ], - function(res) { - if (Object.keys(res.script_details).length === 0) { - window.location = window.location; - } else { - edit_script_modal.open(); - $('.modal_sieve_script_textarea').val(res.script_details.gen_script); - $('.modal_sieve_script_name').val(res.script_details.filter_name); - $('.modal_sieve_script_priority').val(res.script_details.filter_priority); - } - } - ); - - return true; - } - - function save_script(imap_account) { - if ($('.modal_sieve_script_name').val() === "") { - Hm_Utils.add_sys_message(hm_trans('You must provide a name for your script'), 'danger'); - return false; - } - if ($('.modal_sieve_script_textarea').val() === "") { - Hm_Utils.add_sys_message(hm_trans('Empty script'), 'danger'); - return false; - } - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_save_script'}, - {'name': 'imap_account', 'value': imap_account}, - {'name': 'sieve_script_name', 'value': $('.modal_sieve_script_name').val()}, - {'name': 'sieve_script_priority', 'value': $('.modal_sieve_script_priority').val()}, - {'name': 'is_editing_script', 'value': is_editing_script}, - {'name': 'current_editing_script', 'value': current_editing_script_name}, - {'name': 'script', 'value': $('.modal_sieve_script_textarea').val()}], - function(res) { - window.location = window.location; - } - ); - } - - /************************************************************************************** - * MODAL EVENTS - **************************************************************************************/ - $('.sievefilters_accounts_title').on("click", function () { - $(this).parent().find('.sievefilters_accounts').toggleClass('d-none'); - }); - $('.add_filter').on('click', function () { - edit_filter_modal.setTitle('Add Filter'); - $('.modal_sieve_filter_priority').val(''); - $('.modal_sieve_filter_test').val('ALLOF'); - $('#stop_filtering').prop('checked', false); - current_account = $(this).attr('account'); - edit_filter_modal.open(); - - // Reset the form fields when opening the modal - $(".modal_sieve_filter_name").val(''); - $(".modal_sieve_script_priority").val(''); - $(".sieve_list_conditions_modal").empty(); - $(".filter_actions_modal_table").empty(); - }); - $('.add_script').on('click', function () { - edit_script_modal.setTitle('Add Script'); - $('.modal_sieve_script_textarea').val(''); - $('.modal_sieve_script_name').val(''); - $('.modal_sieve_script_priority').val(''); - is_editing_script = false; - current_editing_script_name = ''; - current_account = $(this).attr('account'); - edit_script_modal.open(); - }); - $('.edit_filter').on('click', function (e) { - e.preventDefault(); - let script_name = $(this).parent().parent().children().next().html(); - edit_filter_modal.setTitle(script_name); - edit_filter_modal.open(); - }); - - /** - * Delete action Button - */ - $(document).on('click', '.delete_else_action_modal_button', function (e) { - e.preventDefault(); - $(this).parent().parent().remove(); - }); - - /** - * Delete action Button - */ - $(document).on('click', '.delete_action_modal_button', function (e) { - e.preventDefault(); - $(this).parent().parent().remove(); - }); - - /** - * Delete Condition Button - */ - $(document).on('click', '.delete_condition_modal_button', function (e) { - e.preventDefault(); - $(this).parent().parent().remove(); - }); - - function add_filter_condition() { - let header_fields = ''; - let message_fields = ''; - - hm_sieve_condition_fields().Message.forEach(function (value) { - if (value.selected === true) { - message_fields += ''; - } else { - message_fields += ''; - } - }); - hm_sieve_condition_fields().Header.forEach(function (value) { - if (value.selected === true) { - header_fields += ''; - } else { - header_fields += ''; - } - }); - let extra_options = ''; - $('.sieve_list_conditions_modal').append( - ' ' + - ' ' + - ' ' + - ' ' + - extra_options + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' Delete' + - ' ' + - ' ' - ); - } - - /** - * Add Condition Button - */ - $(document).on('click', '.sieve_add_condition_modal_button', function () { - add_filter_condition(); - }); - - function add_filter_action(default_value = '') { - let possible_actions_html = ''; - - hm_sieve_possible_actions().forEach(function (value) { - if (value.selected === true) { - possible_actions_html += ''; - return; - } - possible_actions_html += ''; - }); - let extra_options = ''; - $('.filter_actions_modal_table').append( - '' + - ' ' + - ' ' + - ' ' + - extra_options + - ' ' + - ' ' + - ' ' + - ' ' + - ' Delete' + - ' ' + - '' - ); - } - - /** - * Add Action Button - */ - $(document).on('click', '.filter_modal_add_action_btn', function () { - add_filter_action(); - }); - - /** - * Add Else Action Button - */ - $(document).on('click', '.filter_modal_add_else_action_btn', function () { - let possible_actions_html = ''; - - hm_sieve_possible_actions().forEach(function (value) { - if (value.selected === true) { - possible_actions_html += ''; - return; - } - possible_actions_html += ''; - }); - - $('.filter_else_actions_modal_table').append( - '' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' ' + - ' Delete' + - ' ' + - '' - ); - }); - - - /** - * Action change - */ - $(document).on('change', '.sieve_actions_select', function () { - let tr_elem = $(this).parent().parent(); - console.log(tr_elem.attr('default_value')); - let elem = $(this).parent().next().next(); - let elem_extra = $(this).parent().next().find('.condition_extra_action_value'); - let action_name = $(this).val(); - let selected_action; - hm_sieve_possible_actions().forEach(function (action) { - if (action_name === action.name) { - selected_action = action; - } - }); - if (selected_action) { - elem_extra.attr('type', 'hidden'); - if (selected_action.extra_field) { - elem_extra.attr('type', 'text'); - elem_extra.attr('placeholder', selected_action.extra_field_placeholder) - } - if (selected_action.type === 'none') { - elem.html(''); - } - if (selected_action.type === 'string') { - elem.html(''); - } - if (selected_action.type === 'int') { - elem.html(''); - } - if (selected_action.type === 'number') { - elem.html(''); - } - if (selected_action.type === 'text') { - elem.html(''); - } - if (selected_action.type === 'select') { - options = ''; - selected_action.values.forEach(function(val) { - if (tr_elem.attr('default_value') === val) { - options = options + '' - } else { - options = options + '' - } - }); - elem.html(''); - } - if (selected_action.type === 'mailbox') { - let mailboxes = null; - tr_elem.children().eq(2).html(hm_spinner()); - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_get_mailboxes'}, - {'name': 'imap_account', 'value': current_account} ], - function(res) { - mailboxes = JSON.parse(res.mailboxes); - options = ''; - mailboxes.forEach(function(val) { - if (tr_elem.attr('default_value') === val) { - options = options + '' - } else { - options = options + '' - } - }); - elem.html(''); - $("[name^=sieve_selected_action_value]").last().val(elem.parent().attr('default_value')); - } - ); - } - } - }) - - /** - * Condition type change - */ - $(document).on('change', '.add_condition_sieve_filters', function () { - let condition_name = $(this).val(); - let elem = $(this).parent().next().next().find('.condition_options'); - let elem_extra = $(this).parent().next().find('.condition_extra_value'); - let elem_type = $(this).parent().next().next().next(); - let condition; - let options_html = ''; - let input_type_html = ''; - hm_sieve_condition_fields().Message.forEach(function (cond) { - if (condition_name === cond.name) { - condition = cond; - } - }); - hm_sieve_condition_fields().Header.forEach(function (cond) { - if (condition_name === cond.name) { - condition = cond; - } - }); - if (condition) { - if (condition.extra_option === true) { - elem_extra.attr('type', 'text'); - elem_extra.attr('placeholder', condition.extra_option_description); - } else { - elem_extra.attr('type', 'hidden'); - } - condition.options.forEach(function (option) { - options_html += ''; - options_html += ''; - }); - elem.html(options_html); - - if (condition.type === 'string') { - elem_type.html('') - } - if (condition.type === 'int') { - elem_type.html('') - } - if (condition.type === 'none') { - elem_type.html('') - } - } - }); - - /** - * Delete filter event - */ - $(document).on('click', '.delete_filter', function (e) { - e.preventDefault(); - if (!confirm('Do you want to delete filter?')) { - return; - } - let obj = $(this); - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_delete_filter'}, - {'name': 'imap_account', 'value': $(this).attr('imap_account')}, - {'name': 'sieve_script_name', 'value': $(this).attr('script_name')}], - function(res) { - if (res.script_removed == '1') { - obj.parent().parent().remove(); - } - } - ); - }); - - - /** - * Delete script event - */ - $(document).on('click', '.delete_script', function (e) { - e.preventDefault(); - if (!confirm('Do you want to delete script?')) { - return; - } - let obj = $(this); - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_delete_script'}, - {'name': 'imap_account', 'value': $(this).attr('imap_account')}, - {'name': 'sieve_script_name', 'value': $(this).attr('script_name')}], - function(res) { - if (res.script_removed == '1') { - obj.parent().parent().remove(); - } - } - ); - }); - - /** - * Edit script event - */ - $(document).on('click', '.edit_script', function (e) { - e.preventDefault(); - let obj = $(this); - edit_script_modal.setTitle('Edit Script'); - current_account = $(this).attr('account'); - is_editing_script = true; - current_editing_script_name = $(this).attr('script_name'); - current_account = $(this).attr('imap_account'); - $('.modal_sieve_script_name').val($(this).attr('script_name_parsed')); - $('.modal_sieve_script_priority').val($(this).attr('priority')); - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_edit_script'}, - {'name': 'imap_account', 'value': $(this).attr('imap_account')}, - {'name': 'sieve_script_name', 'value': $(this).attr('script_name')}], - function(res) { - $('.modal_sieve_script_textarea').html(res.script); - edit_script_modal.open(); - } - ); - }); - - /** - * Edit filter event - */ - $(document).on('click', '.edit_filter', function (e) { - e.preventDefault(); - let obj = $(this); - current_account = $(this).attr('account'); - is_editing_filter = true; - current_editing_filter_name = $(this).attr('script_name'); - current_account = $(this).attr('imap_account'); - // $('#stop_filtering').prop('checked', false); - $('.modal_sieve_filter_name').val($(this).attr('script_name_parsed')); - $('.modal_sieve_filter_priority').val($(this).attr('priority')); - $('.sieve_list_conditions_modal').html(''); - $('.filter_actions_modal_table').html(''); - Hm_Ajax.request( - [ {'name': 'hm_ajax_hook', 'value': 'ajax_sieve_edit_filter'}, - {'name': 'imap_account', 'value': $(this).attr('imap_account')}, - {'name': 'sieve_script_name', 'value': $(this).attr('script_name')}], - function(res) { - conditions = JSON.parse(JSON.parse(res.conditions)); - actions = JSON.parse(JSON.parse(res.actions)); - test_type = res.test_type; - $(".modal_sieve_filter_test").val(test_type); - conditions.forEach(function (condition) { - add_filter_condition(); - $(".add_condition_sieve_filters").last().val(condition.condition); - $(".add_condition_sieve_filters").last().trigger('change'); - $(".condition_options").last().val(condition.type); - $("[name^=sieve_selected_extra_option_value]").last().val(condition.extra_option_value); - if ($("[name^=sieve_selected_option_value]").last().is('input')) { - $("[name^=sieve_selected_option_value]").last().val(condition.value); - } - }); - - actions.forEach(function (action) { - if (action.action === "stop") { - $('#stop_filtering').prop('checked', true); - } else { - add_filter_action(action.value); - $(".sieve_actions_select").last().val(action.action); - $(".sieve_actions_select").last().trigger('change'); - $("[name^=sieve_selected_extra_action_value]").last().val(action.extra_option_value); - if ($("[name^=sieve_selected_action_value]").last().is('input')) { - $("[name^=sieve_selected_action_value]").last().val(action.value); - } else if ($("[name^=sieve_selected_action_value]").last().is('textarea')) { - $("[name^=sieve_selected_action_value]").last().text(action.value); - } - } - }); - } - ); - }); +function cleanUpSieveFiltersPage() { + bootstrap.Modal.getInstance(document.getElementById('myEditFilterModal')).dispose(); + bootstrap.Modal.getInstance(document.getElementById('myEditScript')).dispose(); + document.getElementById('myEditScript').remove(); + document.getElementById('myEditFilterModal').remove(); } function sieveFiltersPageHandler() { diff --git a/tests/selenium/folder_list.py b/tests/selenium/folder_list.py index dbeab8ec16..9102fbdb37 100644 --- a/tests/selenium/folder_list.py +++ b/tests/selenium/folder_list.py @@ -70,7 +70,8 @@ def show_folders(self): self.driver.execute_script("arguments[0].scrollIntoView(true);", a_tag) self.driver.execute_script("arguments[0].click();", a_tag) self.wait_with_folder_list() - self.wait_for_navigation_to_complete() + if self.by_class('content_title').text != 'Home': + self.wait_for_navigation_to_complete() assert self.by_class('content_title').text == 'Home' diff --git a/tests/selenium/profiles.py b/tests/selenium/profiles.py index 00fcdfa87d..678631a852 100644 --- a/tests/selenium/profiles.py +++ b/tests/selenium/profiles.py @@ -16,7 +16,7 @@ def load_profile_page(self): self.by_css('[data-bs-target=".settings"]').click() WebDriverWait(self.driver, 10).until(lambda x: self.by_class('settings').is_displayed()) list_item = self.by_class('menu_profiles') - list_item.find_element(By.TAG_NAME, 'a').click() + self.click_when_clickable(list_item.find_element(By.TAG_NAME, 'a')) self.wait_with_folder_list() self.wait_for_navigation_to_complete() assert self.by_class('profile_content_title').text == 'Profiles' diff --git a/tests/selenium/settings.py b/tests/selenium/settings.py index 30794bc421..86470a0c7b 100644 --- a/tests/selenium/settings.py +++ b/tests/selenium/settings.py @@ -36,7 +36,8 @@ def settings_section(self, section): list_item = self.by_class('menu_settings') self.click_when_clickable(list_item.find_element(By.TAG_NAME, 'a')) self.wait_with_folder_list() - self.wait_for_navigation_to_complete() + if self.by_class('content_title').text != 'Site Settings': + self.wait_for_navigation_to_complete() if not self.by_class(section).is_displayed(): self.by_css('[data-target=".'+section+'"]').click() @@ -91,7 +92,8 @@ def load_settings_page(self): list_item = self.by_class('menu_settings') self.click_when_clickable(list_item.find_element(By.TAG_NAME, 'a')) self.wait_with_folder_list() - self.wait_for_navigation_to_complete() + if self.by_class('content_title').text != 'Site Settings': + self.wait_for_navigation_to_complete() assert self.by_class('content_title').text == 'Site Settings' def list_style_test(self):