From f65ac4da1b48d94596dc43b69e6e542d7bec3243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Sun, 11 May 2025 17:32:26 -0300 Subject: [PATCH 1/8] Replace trigger editor jQuery UI's dialog with a modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- resources/js/src/database/routines.ts | 2 +- resources/js/src/triggers.ts | 142 +++++++----------- resources/templates/triggers/list.twig | 20 +++ .../Triggers/IndexControllerTest.php | 40 +++++ 4 files changed, 118 insertions(+), 86 deletions(-) diff --git a/resources/js/src/database/routines.ts b/resources/js/src/database/routines.ts index 55383fef94..572e589a0b 100644 --- a/resources/js/src/database/routines.ts +++ b/resources/js/src/database/routines.ts @@ -176,7 +176,7 @@ const DatabaseRoutines = { // Move the data from the codemirror editor back to the // textarea, where it can be used in the form submission. if (typeof window.CodeMirror !== 'undefined') { - that.syntaxHiglighter?.save(); + that.syntaxHiglighter.save(); } // Validate editor and submit request, if passed. diff --git a/resources/js/src/triggers.ts b/resources/js/src/triggers.ts index 0b910fcde9..aab697228c 100644 --- a/resources/js/src/triggers.ts +++ b/resources/js/src/triggers.ts @@ -14,11 +14,6 @@ AJAX.registerTeardown('triggers.js', function () { }); const DatabaseTriggers = { - /** - * @var $ajaxDialog Query object containing the reference to the - * dialog that contains the editor - */ - $ajaxDialog: null, /** * @var syntaxHiglighter Reference to the codemirror editor */ @@ -185,22 +180,12 @@ const DatabaseTriggers = { return; } - var buttonOptions = { - [window.Messages.strGo]: { - text: window.Messages.strGo, - class: 'btn btn-primary', - }, - [window.Messages.strClose]: { - text: window.Messages.strClose, - class: 'btn btn-secondary', - }, - }; // We have successfully fetched the editor form ajaxRemoveMessage($msg); - // Now define the function that is called when - // the user presses the "Go" button - // @ts-ignore - buttonOptions[window.Messages.strGo].click = function () { + + let isEditMode = false; + + function triggersEditorModalSaveEventHandler () { // Move the data from the codemirror editor back to the // textarea, where it can be used in the form submission. if (typeof window.CodeMirror !== 'undefined') { @@ -231,10 +216,10 @@ const DatabaseTriggers = { // Item created successfully ajaxRemoveMessage($msg); slidingMessage(data.message); - that.$ajaxDialog.dialog('close'); + window.bootstrap.Modal.getOrCreateInstance('#triggersEditorModal').hide(); // If we are in 'edit' mode, we must // remove the reference to the old row. - if (mode === 'edit' && $editRow !== null) { + if (isEditMode && $editRow !== null) { $editRow.remove(); } @@ -328,72 +313,59 @@ const DatabaseTriggers = { Navigation.reload(); }); // end $.post() - }; // end of function that handles the submission of the Editor - - // @ts-ignore - buttonOptions[window.Messages.strClose].click = function () { - $(this).dialog('close'); - }; - - /** - * Display the dialog to the user - */ - that.$ajaxDialog = $('
' + data.message + '
').dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - width: '70%', - minWidth: 500, - // @ts-ignore - buttons: buttonOptions, - // Issue #15810 - use button titles for modals (eg: new procedure) - // Respect the order: title on href tag, href content, title sent in response - title: $this.attr('title') || $this.text() || $(data.title).text(), - modal: true, - open: function () { - $('#rteDialog').dialog('option', 'max-height', $(window).height()); - if ($('#rteDialog').parents('.ui-dialog').height() > $(window).height()) { - $('#rteDialog').dialog('option', 'height', $(window).height()); - } - - $(this).find('input[name=item_name]').trigger('focus'); - $(this).find('input.datefield').each(function () { - addDatepicker($(this).css('width', '95%'), 'date'); - }); - - $(this).find('input.datetimefield').each(function () { - addDatepicker($(this).css('width', '95%'), 'datetime'); - }); - - // @ts-ignore - $.datepicker.initialized = false; - }, - close: function () { - $(this).remove(); - } - }); - - /** - * @var mode Used to remember whether the editor is in - * "Edit" or "Add" mode - */ - var mode = 'add'; - if ($('input[name=editor_process_edit]').length > 0) { - mode = 'edit'; } - // Attach syntax highlighted editor to the definition - /** - * @var elm jQuery object containing the reference to - * the Definition textarea. - */ - var $elm = $('textarea[name=item_definition]').last(); - var linterOptions = { - editorType: 'trigger', - }; - that.syntaxHiglighter = getSqlEditor($elm, {}, 'vertical', linterOptions); - window.codeMirrorEditor = that.syntaxHiglighter; - }); // end $.get() + const triggersEditorModal = document.getElementById('triggersEditorModal'); + + triggersEditorModal.addEventListener('shown.bs.modal', function () { + /** + * Issue #15810 - use button titles for modals (eg: new procedure) + * Respect the order: title on href tag, href content, title sent in response + */ + triggersEditorModal.querySelector('.modal-title').textContent = $this.attr('title') || $this.text() || $(data.title).text(); + triggersEditorModal.querySelector('.modal-body').innerHTML = data.message; + + const triggersEditorModalSaveButton = document.getElementById('triggersEditorModalSaveButton'); + triggersEditorModalSaveButton?.addEventListener('click', triggersEditorModalSaveEventHandler); + + $(this).find('input[name=item_name]').trigger('focus'); + $(this).find('input.datefield').each(function () { + addDatepicker($(this).css('width', '95%'), 'date'); + }); + + $(this).find('input.datetimefield').each(function () { + addDatepicker($(this).css('width', '95%'), 'datetime'); + }); + + // @ts-ignore + $.datepicker.initialized = false; + + if ($('input[name=editor_process_edit]').length > 0) { + isEditMode = true; + } + + // Attach syntax highlighted editor to the definition + /** + * @var elm jQuery object containing the reference to + * the Definition textarea. + */ + var $elm = $('textarea[name=item_definition]').last(); + var linterOptions = { + editorType: 'trigger', + }; + that.syntaxHiglighter = getSqlEditor($elm, {}, 'vertical', linterOptions); + window.codeMirrorEditor = that.syntaxHiglighter; + }); + + triggersEditorModal.addEventListener('hidden.bs.modal', function () { + const triggersEditorModalSaveButton = document.getElementById('triggersEditorModalSaveButton'); + triggersEditorModalSaveButton?.removeEventListener('click', triggersEditorModalSaveEventHandler); + document.getElementById('triggersEditorModal').querySelector('.modal-body').innerHTML = '
' + + '' + window.Messages.strLoading + '
'; + }); + + window.bootstrap.Modal.getOrCreateInstance(triggersEditorModal).show(); + }); }, dropDialog: function ($this) { diff --git a/resources/templates/triggers/list.twig b/resources/templates/triggers/list.twig index 04d710edcd..ec21603cab 100644 --- a/resources/templates/triggers/list.twig +++ b/resources/templates/triggers/list.twig @@ -73,4 +73,24 @@ + + diff --git a/tests/unit/Controllers/Triggers/IndexControllerTest.php b/tests/unit/Controllers/Triggers/IndexControllerTest.php index 958d4c74ce..32df242fc4 100644 --- a/tests/unit/Controllers/Triggers/IndexControllerTest.php +++ b/tests/unit/Controllers/Triggers/IndexControllerTest.php @@ -149,6 +149,26 @@ final class IndexControllerTest extends AbstractTestCase + + HTML; @@ -237,6 +257,26 @@ HTML; + + HTML; From 475780adb0dc5f69f3fab57192423fd45680f79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Mon, 12 May 2025 20:27:52 -0300 Subject: [PATCH 2/8] Replace triggers export jQuery UI's dialog with a modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- resources/js/src/triggers.ts | 50 ++++++------------- resources/templates/triggers/list.twig | 15 ++++++ .../JavaScriptMessagesController.php | 1 + .../Triggers/IndexControllerTest.php | 30 +++++++++++ 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/resources/js/src/triggers.ts b/resources/js/src/triggers.ts index aab697228c..42160b3d2d 100644 --- a/resources/js/src/triggers.ts +++ b/resources/js/src/triggers.ts @@ -116,43 +116,23 @@ const DatabaseTriggers = { } ajaxRemoveMessage($msg); - /** - * @var buttonOptions Object containing options - * for jQueryUI dialog buttons - */ - var buttonOptions = { - [window.Messages.strClose]: { - text: window.Messages.strClose, - class: 'btn btn-primary', - }, - }; - // @ts-ignore - buttonOptions[window.Messages.strClose].click = function () { - $(this).dialog('close').remove(); - }; - /** - * Display the dialog to the user - */ - data.message = ''; - var $ajaxDialog = $('
' + data.message + '
').dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - width: 500, - // @ts-ignore - buttons: buttonOptions, - title: data.title + const triggersExportTextarea = ''; + const triggersExportModal = document.getElementById('triggersExportModal'); + triggersExportModal.addEventListener('shown.bs.modal', function () { + triggersExportModal.querySelector('.modal-title').textContent = data.title; + triggersExportModal.querySelector('.modal-body').innerHTML = triggersExportTextarea; + document.getElementById('triggersExportTextarea').textContent = data.message; + getSqlEditor($('#triggersExportTextarea')); }); - // Attach syntax highlighted editor to export dialog - /** - * @var $elm jQuery object containing the reference - * to the Export textarea. - */ - var $elm = $ajaxDialog.find('textarea'); - getSqlEditor($elm); - } // end showExport() - }, // end exportDialog() + + triggersExportModal.addEventListener('hidden.bs.modal', function () { + triggersExportModal.querySelector('.modal-body').innerHTML = triggersExportTextarea; + }); + + window.bootstrap.Modal.getOrCreateInstance(triggersExportModal).show(); + } + }, editorDialog: function (isNew, $this) { var that = this; /** diff --git a/resources/templates/triggers/list.twig b/resources/templates/triggers/list.twig index ec21603cab..bf95d48aed 100644 --- a/resources/templates/triggers/list.twig +++ b/resources/templates/triggers/list.twig @@ -93,4 +93,19 @@ + + diff --git a/src/Controllers/JavaScriptMessagesController.php b/src/Controllers/JavaScriptMessagesController.php index f0fdf431a5..2b00a923b0 100644 --- a/src/Controllers/JavaScriptMessagesController.php +++ b/src/Controllers/JavaScriptMessagesController.php @@ -391,6 +391,7 @@ final class JavaScriptMessagesController implements InvocableController 'strExport' => __('Export'), 'NoExportable' => __('No routine is exportable. Required privileges may be lacking.'), 'strRoutine' => __('Routine'), + 'strTrigger' => __('Trigger'), /* For ENUM/SET editor*/ 'enum_columnVals' => __('Values for column %s'), diff --git a/tests/unit/Controllers/Triggers/IndexControllerTest.php b/tests/unit/Controllers/Triggers/IndexControllerTest.php index 32df242fc4..7a4b93222a 100644 --- a/tests/unit/Controllers/Triggers/IndexControllerTest.php +++ b/tests/unit/Controllers/Triggers/IndexControllerTest.php @@ -169,6 +169,21 @@ final class IndexControllerTest extends AbstractTestCase + + HTML; @@ -277,6 +292,21 @@ HTML; + + HTML; From dd0c8a4c8801151dd1b971b96c59f88afa3dcd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 14 May 2025 12:42:53 -0300 Subject: [PATCH 3/8] Replace events editor jQuery UI's dialog with a modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- resources/js/src/database/events.ts | 154 +++++++----------- .../templates/database/events/index.twig | 20 +++ .../Database/EventsControllerTest.php | 40 +++++ 3 files changed, 121 insertions(+), 93 deletions(-) diff --git a/resources/js/src/database/events.ts b/resources/js/src/database/events.ts index 8123e937c4..50598aee52 100644 --- a/resources/js/src/database/events.ts +++ b/resources/js/src/database/events.ts @@ -15,11 +15,6 @@ AJAX.registerTeardown('database/events.js', function () { }); const DatabaseEvents = { - /** - * @var $ajaxDialog Query object containing the reference to the - * dialog that contains the editor - */ - $ajaxDialog: null, /** * @var syntaxHiglighter Reference to the codemirror editor */ @@ -176,24 +171,10 @@ const DatabaseEvents = { // We have successfully fetched the editor form ajaxRemoveMessage($msg); - /** - * @var buttonOptions Object containing options - * for jQueryUI dialog buttons - */ - var buttonOptions = { - [window.Messages.strGo]: { - text: window.Messages.strGo, - class: 'btn btn-primary', - }, - [window.Messages.strClose]: { - text: window.Messages.strClose, - class: 'btn btn-secondary', - }, - }; - // Now define the function that is called when - // the user presses the "Go" button - // @ts-ignore - buttonOptions[window.Messages.strGo].click = function () { + + let isEditMode = false; + + function eventsEditorModalSaveEventHandler () { // Move the data from the codemirror editor back to the // textarea, where it can be used in the form submission. if (typeof window.CodeMirror !== 'undefined') { @@ -221,10 +202,10 @@ const DatabaseEvents = { // Item created successfully ajaxRemoveMessage($msg); slidingMessage(data.message); - that.$ajaxDialog.dialog('close'); + window.bootstrap.Modal.getOrCreateInstance('#eventsEditorModal').hide(); // If we are in 'edit' mode, we must // remove the reference to the old row. - if (mode === 'edit' && $editRow !== null) { + if (isEditMode && $editRow !== null) { $editRow.remove(); } @@ -317,75 +298,61 @@ const DatabaseEvents = { } Navigation.reload(); - }); // end $.post() - } // end "if (that.validate())" - }; // end of function that handles the submission of the Editor - - // @ts-ignore - buttonOptions[window.Messages.strClose].click = function () { - $(this).dialog('close'); - }; - - /** - * Display the dialog to the user - */ - that.$ajaxDialog = $('
' + data.message + '
').dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - height: 500, - width: '70%', - minWidth: 500, - // @ts-ignore - buttons: buttonOptions, - // Issue #15810 - use button titles for modals (eg: new procedure) - // Respect the order: title on href tag, href content, title sent in response - title: $this.attr('title') || $this.text() || $(data.title).text(), - modal: true, - open: function () { - $('#rteDialog').dialog('option', 'max-height', $(window).height()); - if ($('#rteDialog').parents('.ui-dialog').height() > $(window).height()) { - $('#rteDialog').dialog('option', 'height', $(window).height()); - } - - $(this).find('input[name=item_name]').trigger('focus'); - $(this).find('input.datefield').each(function () { - addDatepicker($(this).css('width', '95%'), 'date'); }); - - $(this).find('input.datetimefield').each(function () { - addDatepicker($(this).css('width', '95%'), 'datetime'); - }); - - // @ts-ignore - $.datepicker.initialized = false; - }, - close: function () { - $(this).remove(); } - }); - - /** - * @var mode Used to remember whether the editor is in - * "Edit" or "Add" mode - */ - var mode = 'add'; - if ($('input[name=editor_process_edit]').length > 0) { - mode = 'edit'; } - // Attach syntax highlighted editor to the definition - /** - * @var elm jQuery object containing the reference to - * the Definition textarea. - */ - var $elm = $('textarea[name=item_definition]').last(); - var linterOptions = { - editorType: 'event', - }; - that.syntaxHiglighter = getSqlEditor($elm, {}, 'vertical', linterOptions); - window.codeMirrorEditor = that.syntaxHiglighter; - }); // end $.get() + const eventsEditorModal = document.getElementById('eventsEditorModal'); + + eventsEditorModal.addEventListener('shown.bs.modal', function () { + /** + * Issue #15810 - use button titles for modals (eg: new procedure) + * Respect the order: title on href tag, href content, title sent in response + */ + eventsEditorModal.querySelector('.modal-title').textContent = $this.attr('title') || $this.text() || $(data.title).text(); + eventsEditorModal.querySelector('.modal-body').innerHTML = data.message; + + const eventsEditorModalSaveButton = document.getElementById('eventsEditorModalSaveButton'); + eventsEditorModalSaveButton?.addEventListener('click', eventsEditorModalSaveEventHandler); + + $(this).find('input[name=item_name]').trigger('focus'); + $(this).find('input.datefield').each(function () { + addDatepicker($(this).css('width', '95%'), 'date'); + }); + + $(this).find('input.datetimefield').each(function () { + addDatepicker($(this).css('width', '95%'), 'datetime'); + }); + + // @ts-ignore + $.datepicker.initialized = false; + + if ($('input[name=editor_process_edit]').length > 0) { + isEditMode = true; + } + + // Attach syntax highlighted editor to the definition + /** + * @var elm jQuery object containing the reference to + * the Definition textarea. + */ + var $elm = $('textarea[name=item_definition]').last(); + var linterOptions = { + editorType: 'event', + }; + that.syntaxHiglighter = getSqlEditor($elm, {}, 'vertical', linterOptions); + window.codeMirrorEditor = that.syntaxHiglighter; + }); + + eventsEditorModal.addEventListener('hidden.bs.modal', function () { + const eventsEditorModalSaveButton = document.getElementById('eventsEditorModalSaveButton'); + eventsEditorModalSaveButton?.removeEventListener('click', eventsEditorModalSaveEventHandler); + document.getElementById('eventsEditorModal').querySelector('.modal-body').innerHTML = '
' + + '' + window.Messages.strLoading + '
'; + }); + + window.bootstrap.Modal.getOrCreateInstance(eventsEditorModal).show(); + }); }, dropDialog: function ($this) { @@ -561,9 +528,10 @@ const DatabaseEvents = { * to an element that is being validated */ var $elm = null; - if (this.$ajaxDialog.find('select[name=item_type]').find(':selected').val() === 'RECURRING') { + const eventsEditorModal = $('#eventsEditorModal'); + if (eventsEditorModal.find('select[name=item_type]').find(':selected').val() === 'RECURRING') { // The interval field must not be empty for recurring events - $elm = this.$ajaxDialog.find('input[name=item_interval_value]'); + $elm = eventsEditorModal.find('input[name=item_interval_value]'); if ($elm.val() === '') { $elm.trigger('focus'); alert(window.Messages.strFormEmpty); @@ -572,7 +540,7 @@ const DatabaseEvents = { } } else { // The execute_at field must not be empty for "once off" events - $elm = this.$ajaxDialog.find('input[name=item_execute_at]'); + $elm = eventsEditorModal.find('input[name=item_execute_at]'); if ($elm.val() === '') { $elm.trigger('focus'); alert(window.Messages.strFormEmpty); diff --git a/resources/templates/database/events/index.twig b/resources/templates/database/events/index.twig index 8626bd09df..c91000b465 100644 --- a/resources/templates/database/events/index.twig +++ b/resources/templates/database/events/index.twig @@ -153,4 +153,24 @@ + + diff --git a/tests/unit/Controllers/Database/EventsControllerTest.php b/tests/unit/Controllers/Database/EventsControllerTest.php index b377e9d7bf..87bbbe27e1 100644 --- a/tests/unit/Controllers/Database/EventsControllerTest.php +++ b/tests/unit/Controllers/Database/EventsControllerTest.php @@ -181,6 +181,26 @@ final class EventsControllerTest extends AbstractTestCase + + HTML; @@ -307,6 +327,26 @@ HTML; + + HTML; From 65a4eed88f893d9abcda4ccb31a5644eae07967a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 14 May 2025 12:51:40 -0300 Subject: [PATCH 4/8] Replace events export jQuery UI's dialog with a modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- resources/js/src/database/events.ts | 50 ++++++------------- .../templates/database/events/index.twig | 15 ++++++ .../JavaScriptMessagesController.php | 1 + .../Database/EventsControllerTest.php | 30 +++++++++++ 4 files changed, 62 insertions(+), 34 deletions(-) diff --git a/resources/js/src/database/events.ts b/resources/js/src/database/events.ts index 50598aee52..068d3b9876 100644 --- a/resources/js/src/database/events.ts +++ b/resources/js/src/database/events.ts @@ -107,41 +107,23 @@ const DatabaseEvents = { } ajaxRemoveMessage($msg); - /** - * @var buttonOptions Object containing options - * for jQueryUI dialog buttons - */ - var buttonOptions = { - [window.Messages.strClose]: { - text: window.Messages.strClose, - class: 'btn btn-primary', - click: function () { - $(this).dialog('close').remove(); - }, - }, - }; - /** - * Display the dialog to the user - */ - data.message = ''; - var $ajaxDialog = $('
' + data.message + '
').dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - width: 500, - // @ts-ignore - buttons: buttonOptions, - title: data.title + + const eventsExportTextarea = ''; + const eventsExportModal = document.getElementById('eventsExportModal'); + eventsExportModal.addEventListener('shown.bs.modal', function () { + eventsExportModal.querySelector('.modal-title').textContent = data.title; + eventsExportModal.querySelector('.modal-body').innerHTML = eventsExportTextarea; + document.getElementById('eventsExportTextarea').textContent = data.message; + getSqlEditor($('#eventsExportTextarea')); }); - // Attach syntax highlighted editor to export dialog - /** - * @var $elm jQuery object containing the reference - * to the Export textarea. - */ - var $elm = $ajaxDialog.find('textarea'); - getSqlEditor($elm); - } // end showExport() - }, // end exportDialog() + + eventsExportModal.addEventListener('hidden.bs.modal', function () { + eventsExportModal.querySelector('.modal-body').innerHTML = eventsExportTextarea; + }); + + window.bootstrap.Modal.getOrCreateInstance(eventsExportModal).show(); + } + }, editorDialog: function (isNew, $this) { var that = this; /** diff --git a/resources/templates/database/events/index.twig b/resources/templates/database/events/index.twig index c91000b465..6477c0c284 100644 --- a/resources/templates/database/events/index.twig +++ b/resources/templates/database/events/index.twig @@ -173,4 +173,19 @@ + + diff --git a/src/Controllers/JavaScriptMessagesController.php b/src/Controllers/JavaScriptMessagesController.php index 2b00a923b0..a83f9f5852 100644 --- a/src/Controllers/JavaScriptMessagesController.php +++ b/src/Controllers/JavaScriptMessagesController.php @@ -392,6 +392,7 @@ final class JavaScriptMessagesController implements InvocableController 'NoExportable' => __('No routine is exportable. Required privileges may be lacking.'), 'strRoutine' => __('Routine'), 'strTrigger' => __('Trigger'), + 'strEvent' => __('Event'), /* For ENUM/SET editor*/ 'enum_columnVals' => __('Values for column %s'), diff --git a/tests/unit/Controllers/Database/EventsControllerTest.php b/tests/unit/Controllers/Database/EventsControllerTest.php index 87bbbe27e1..f6c56d1b40 100644 --- a/tests/unit/Controllers/Database/EventsControllerTest.php +++ b/tests/unit/Controllers/Database/EventsControllerTest.php @@ -201,6 +201,21 @@ final class EventsControllerTest extends AbstractTestCase + + HTML; @@ -347,6 +362,21 @@ HTML; + + HTML; From 13ce962cb509fb708b409418f3060f5e1320f2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 14 May 2025 13:45:20 -0300 Subject: [PATCH 5/8] Replace import monitor config jQuery UI's dialog with a modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- resources/js/src/server/status/monitor.ts | 143 +++++++----------- .../server/status/monitor/index.twig | 23 ++- .../JavaScriptMessagesController.php | 2 - 3 files changed, 79 insertions(+), 89 deletions(-) diff --git a/resources/js/src/server/status/monitor.ts b/resources/js/src/server/status/monitor.ts index a77c46a859..480d005486 100644 --- a/resources/js/src/server/status/monitor.ts +++ b/resources/js/src/server/status/monitor.ts @@ -117,7 +117,6 @@ AJAX.registerTeardown('server/status/monitor.js', function () { $('#monitorChartRefreshRateSelect').off('change'); $('#monitorAddNewChartButton').off('click'); $('#monitorExportConfigButton').off('click'); - $('#monitorImportConfigButton').off('click'); $('#monitorResetConfigButton').off('click'); $('#monitorPauseResumeButton').off('click'); $('#monitorInstructionsButton').off('click'); @@ -677,99 +676,71 @@ AJAX.registerOnload('server/status/monitor.js', function () { }, 100); }); - $('#monitorImportConfigButton').on('click', function () { - $('#emptyDialog').dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - title: window.Messages.strImportDialogTitle - }); + function monitorImportConfigImportEventHandler () { + var input = ($('#monitorImportConfigModal').find('#import_file') as JQuery)[0]; + var reader = new FileReader(); - $('#emptyDialog').html(window.Messages.strImportDialogMessage + '
' + - '
'); - - var dlgBtns = { - [window.Messages.strImport]: { - text: window.Messages.strImport, - class: 'btn btn-primary', - }, - [window.Messages.strCancel]: { - text: window.Messages.strCancel, - class: 'btn btn-secondary', - }, + reader.onerror = function (event) { + alert(window.Messages.strFailedParsingConfig + '\n' + event.target.error.code); }; - // @ts-ignore - dlgBtns[window.Messages.strImport].click = function () { - var input = ($('#emptyDialog').find('#import_file') as JQuery)[0]; - var reader = new FileReader(); + reader.onload = function (e) { + var data = (e.target.result as string); + var json = null; + // Try loading config + try { + json = JSON.parse(data); + } catch (err) { + alert(window.Messages.strFailedParsingConfig); + window.bootstrap.Modal.getOrCreateInstance('#monitorImportConfigModal').hide(); - reader.onerror = function (event) { - alert(window.Messages.strFailedParsingConfig + '\n' + event.target.error.code); - }; - - reader.onload = function (e) { - var data = (e.target.result as string); - var json = null; - // Try loading config - try { - json = JSON.parse(data); - } catch (err) { - alert(window.Messages.strFailedParsingConfig); - $('#emptyDialog').dialog('close'); - - return; - } - - // Basic check, is this a monitor config json? - if (! json || ! json.monitorCharts || ! json.monitorCharts) { - alert(window.Messages.strFailedParsingConfig); - $('#emptyDialog').dialog('close'); - - return; - } - - // If json ok, try applying config - try { - if (isStorageSupported('localStorage')) { - window.localStorage.monitorCharts = JSON.stringify(json.monitorCharts); - window.localStorage.monitorSettings = JSON.stringify(json.monitorSettings); - } - - rebuildGrid(); - } catch (err) { - alert(window.Messages.strFailedBuildingGrid); - // If an exception is thrown, load default again - if (isStorageSupported('localStorage')) { - window.localStorage.removeItem('monitorCharts'); - window.localStorage.removeItem('monitorSettings'); - } - - rebuildGrid(); - } - - $('#emptyDialog').dialog('close'); - }; - - if (input.files[0]) { - reader.readAsText(input.files[0]); + return; } + + // Basic check, is this a monitor config json? + if (! json || ! json.monitorCharts || ! json.monitorCharts) { + alert(window.Messages.strFailedParsingConfig); + window.bootstrap.Modal.getOrCreateInstance('#monitorImportConfigModal').hide(); + + return; + } + + // If json ok, try applying config + try { + if (isStorageSupported('localStorage')) { + window.localStorage.monitorCharts = JSON.stringify(json.monitorCharts); + window.localStorage.monitorSettings = JSON.stringify(json.monitorSettings); + } + + rebuildGrid(); + } catch (err) { + alert(window.Messages.strFailedBuildingGrid); + // If an exception is thrown, load default again + if (isStorageSupported('localStorage')) { + window.localStorage.removeItem('monitorCharts'); + window.localStorage.removeItem('monitorSettings'); + } + + rebuildGrid(); + } + + window.bootstrap.Modal.getOrCreateInstance('#monitorImportConfigModal').hide(); }; - // @ts-ignore - dlgBtns[window.Messages.strCancel].click = function () { - $(this).dialog('close'); - }; + if (input.files[0]) { + reader.readAsText(input.files[0]); + } + } - $('#emptyDialog').dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - width: 'auto', - height: 'auto', - // @ts-ignore - buttons: dlgBtns - }); + const monitorImportConfigModal = document.getElementById('monitorImportConfigModal'); + monitorImportConfigModal.addEventListener('shown.bs.modal', function () { + const monitorImportConfigImportButton = document.getElementById('monitorImportConfigImportButton'); + monitorImportConfigImportButton?.addEventListener('click', monitorImportConfigImportEventHandler); + }); + + monitorImportConfigModal.addEventListener('hidden.bs.modal', function () { + const monitorImportConfigImportButton = document.getElementById('monitorImportConfigImportButton'); + monitorImportConfigImportButton?.removeEventListener('click', monitorImportConfigImportEventHandler); }); $('#monitorResetConfigButton').on('click', function () { diff --git a/resources/templates/server/status/monitor/index.twig b/resources/templates/server/status/monitor/index.twig index 4b801b73c4..2a6fb7dd27 100644 --- a/resources/templates/server/status/monitor/index.twig +++ b/resources/templates/server/status/monitor/index.twig @@ -50,7 +50,28 @@ {{ t('The arrangement of the charts is stored to the browsers local storage. You may want to export it if you have a complicated set up.') }}

- + + +
diff --git a/src/Controllers/JavaScriptMessagesController.php b/src/Controllers/JavaScriptMessagesController.php index a83f9f5852..f0f46090ab 100644 --- a/src/Controllers/JavaScriptMessagesController.php +++ b/src/Controllers/JavaScriptMessagesController.php @@ -324,8 +324,6 @@ final class JavaScriptMessagesController implements InvocableController 'strFailedBuildingGrid' => __( 'Failed building chart grid with imported config. Resetting to default config…', ), - 'strImport' => __('Import'), - 'strImportDialogTitle' => __('Import monitor configuration'), 'strImportDialogMessage' => __('Please select the file you want to import:'), 'strTableNameDialogMessage' => __('Please enter a valid table name.'), 'strDBNameDialogMessage' => __('Please enter a valid database name.'), From 1abc77697158e00b243609f2050f870c737df223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 14 May 2025 18:56:16 -0300 Subject: [PATCH 6/8] Replace monitor instructions jQuery UI's dialog with a modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- resources/js/src/server/status/monitor.ts | 239 ++++++++---------- .../server/status/monitor/index.twig | 57 +++-- .../Server/Status/MonitorControllerTest.php | 7 +- 3 files changed, 144 insertions(+), 159 deletions(-) diff --git a/resources/js/src/server/status/monitor.ts b/resources/js/src/server/status/monitor.ts index 480d005486..7647432992 100644 --- a/resources/js/src/server/status/monitor.ts +++ b/resources/js/src/server/status/monitor.ts @@ -119,7 +119,6 @@ AJAX.registerTeardown('server/status/monitor.js', function () { $('#monitorExportConfigButton').off('click'); $('#monitorResetConfigButton').off('click'); $('#monitorPauseResumeButton').off('click'); - $('#monitorInstructionsButton').off('click'); $('input[name="chartType"]').off('click'); $('input[name="useDivisor"]').off('click'); $('input[name="useUnit"]').off('click'); @@ -766,158 +765,138 @@ AJAX.registerOnload('server/status/monitor.js', function () { } }); - $('#monitorInstructionsButton').on('click', function () { - var $dialog = $('#monitorInstructionsDialog'); - var dlgBtns = { - [window.Messages.strClose]: { - text: window.Messages.strClose, - class: 'btn btn-primary', - click: function () { - $(this).dialog('close'); - } - }, + const $dialog = $('#monitorInstructionsModal'); + + function loadLogVars (getvars = undefined) { + var vars = { + 'ajax_request': true, + 'server': CommonParams.get('server'), }; - $dialog.dialog({ - classes: { - 'ui-dialog-titlebar-close': 'btn-close' - }, - width: '60%', - height: 'auto', - // @ts-ignore - buttons: dlgBtns - }).find('img.ajaxIcon').show(); + if (getvars) { + $.extend(vars, getvars); + } - var loadLogVars = function (getvars = undefined) { - var vars = { - 'ajax_request': true, - 'server': CommonParams.get('server') - }; - if (getvars) { - $.extend(vars, getvars); - } + $.post('index.php?route=/server/status/monitor/log-vars', vars, + function (data) { + var logVars; + if (typeof data !== 'undefined' && data.success === true) { + logVars = data.message; + } else { + return serverResponseError(); + } - $.post('index.php?route=/server/status/monitor/log-vars', vars, - function (data) { - var logVars; - if (typeof data !== 'undefined' && data.success === true) { - logVars = data.message; - } else { - return serverResponseError(); - } - - var icon = getImageTag('s_success'); - var msg = ''; - var str = ''; - - if (logVars.general_log === 'ON') { - if (logVars.slow_query_log === 'ON') { - msg = window.Messages.strBothLogOn; - } else { - msg = window.Messages.strGenLogOn; - } - } - - if (msg.length === 0 && logVars.slow_query_log === 'ON') { - msg = window.Messages.strSlowLogOn; - } - - if (msg.length === 0) { - icon = getImageTag('s_error'); - msg = window.Messages.strBothLogOff; - } - - str = '' + window.Messages.strCurrentSettings + '
'; - str += icon + msg + '
'; - - if (logVars.log_output !== 'TABLE') { - str += getImageTag('s_error') + ' ' + window.Messages.strLogOutNotTable + '
'; - } else { - str += getImageTag('s_success') + ' ' + window.Messages.strLogOutIsTable + '
'; - } + var icon = getImageTag('s_success'); + var msg = ''; + var str = ''; + if (logVars.general_log === 'ON') { if (logVars.slow_query_log === 'ON') { - if (logVars.long_query_time > 2) { - str += getImageTag('s_attention') + ' '; - str += window.sprintf(window.Messages.strSmallerLongQueryTimeAdvice, logVars.long_query_time); - str += '
'; - } + msg = window.Messages.strBothLogOn; + } else { + msg = window.Messages.strGenLogOn; + } + } - if (logVars.long_query_time < 2) { - str += getImageTag('s_success') + ' '; - str += window.sprintf(window.Messages.strLongQueryTimeSet, logVars.long_query_time); - str += '
'; - } + if (msg.length === 0 && logVars.slow_query_log === 'ON') { + msg = window.Messages.strSlowLogOn; + } + + if (msg.length === 0) { + icon = getImageTag('s_error'); + msg = window.Messages.strBothLogOff; + } + + str = '' + window.Messages.strCurrentSettings + '
'; + str += icon + msg + '
'; + + if (logVars.log_output !== 'TABLE') { + str += getImageTag('s_error') + ' ' + window.Messages.strLogOutNotTable + '
'; + } else { + str += getImageTag('s_success') + ' ' + window.Messages.strLogOutIsTable + '
'; + } + + if (logVars.slow_query_log === 'ON') { + if (logVars.long_query_time > 2) { + str += getImageTag('s_attention') + ' '; + str += window.sprintf(window.Messages.strSmallerLongQueryTimeAdvice, logVars.long_query_time); + str += '
'; } - str += '
'; + if (logVars.long_query_time < 2) { + str += getImageTag('s_success') + ' '; + str += window.sprintf(window.Messages.strLongQueryTimeSet, logVars.long_query_time); + str += '
'; + } + } - if (isSuperUser) { - str += '

' + window.Messages.strChangeSettings + ''; - str += '
'; - str += window.Messages.strSettingsAppliedGlobal + '
'; + str += '
'; - var varValue: string | number = 'TABLE'; - if (logVars.log_output === 'TABLE') { - varValue = 'FILE'; - } + if (isSuperUser) { + str += '

' + window.Messages.strChangeSettings + ''; + str += '
'; + str += window.Messages.strSettingsAppliedGlobal + '
'; - str += '- '; - str += window.sprintf(window.Messages.strSetLogOutput, varValue); - str += '
'; + var varValue: string | number = 'TABLE'; + if (logVars.log_output === 'TABLE') { + varValue = 'FILE'; + } - if (logVars.general_log !== 'ON') { - str += '- '; - str += window.sprintf(window.Messages.strEnableVar, 'general_log'); - str += '
'; - } else { - str += '- '; - str += window.sprintf(window.Messages.strDisableVar, 'general_log'); - str += '
'; - } + str += '- '; + str += window.sprintf(window.Messages.strSetLogOutput, varValue); + str += '
'; - if (logVars.slow_query_log !== 'ON') { - str += '- '; - str += window.sprintf(window.Messages.strEnableVar, 'slow_query_log'); - str += '
'; - } else { - str += '- '; - str += window.sprintf(window.Messages.strDisableVar, 'slow_query_log'); - str += '
'; - } - - varValue = 5; - if (logVars.long_query_time > 2) { - varValue = 1; - } - - str += '- '; - str += window.sprintf(window.Messages.setSetLongQueryTime, varValue); + if (logVars.general_log !== 'ON') { + str += '- '; + str += window.sprintf(window.Messages.strEnableVar, 'general_log'); str += '
'; } else { - str += window.Messages.strNoSuperUser + '
'; + str += '- '; + str += window.sprintf(window.Messages.strDisableVar, 'general_log'); + str += '
'; } - str += '
'; + if (logVars.slow_query_log !== 'ON') { + str += '- '; + str += window.sprintf(window.Messages.strEnableVar, 'slow_query_log'); + str += '
'; + } else { + str += '- '; + str += window.sprintf(window.Messages.strDisableVar, 'slow_query_log'); + str += '
'; + } - $dialog.find('div.monitorUse').toggle( - logVars.log_output === 'TABLE' && (logVars.slow_query_log === 'ON' || logVars.general_log === 'ON') - ); + varValue = 5; + if (logVars.long_query_time > 2) { + varValue = 1; + } - $dialog.find('div.ajaxContent').html(str); - $dialog.find('img.ajaxIcon').hide(); - $dialog.find('a.set').on('click', function () { - var nameValue = $(this).attr('href').split('-'); - loadLogVars({ varName: nameValue[0].substring(1), varValue: nameValue[1] }); - $dialog.find('img.ajaxIcon').show(); - }); + str += '- '; + str += window.sprintf(window.Messages.setSetLongQueryTime, varValue); + str += '
'; + } else { + str += window.Messages.strNoSuperUser + '
'; } - ); - }; + str += '
'; + $dialog.find('div.monitorUse').toggle( + logVars.log_output === 'TABLE' && (logVars.slow_query_log === 'ON' || logVars.general_log === 'ON'), + ); + + $dialog.find('div.ajaxContent').html(str); + $dialog.find('img.ajaxIcon').hide(); + $dialog.find('a.set').on('click', function () { + var nameValue = $(this).attr('href').split('-'); + loadLogVars({ varName: nameValue[0].substring(1), varValue: nameValue[1] }); + $dialog.find('img.ajaxIcon').show(); + }); + }, + ); + } + + const monitorInstructionsModal = document.getElementById('monitorInstructionsModal'); + monitorInstructionsModal.addEventListener('shown.bs.modal', function () { loadLogVars(); - - return false; }); ($('input[name="chartType"]') as JQuery).on('change', function () { diff --git a/resources/templates/server/status/monitor/index.twig b/resources/templates/server/status/monitor/index.twig index 2a6fb7dd27..f3f2db5ddb 100644 --- a/resources/templates/server/status/monitor/index.twig +++ b/resources/templates/server/status/monitor/index.twig @@ -6,7 +6,7 @@
- +
@@ -80,32 +80,41 @@
-
-

- {{ t("The phpMyAdmin Monitor can assist you in optimizing the server configuration and track down time intensive queries. For the latter you will need to set log_output to 'TABLE' and have either the slow_query_log or general_log enabled. Note however, that the general_log produces a lot of data and increases server load by up to 15%.") }} -

- {{ t('Loading…') }} +