diff --git a/app/services_controllers.php b/app/services_controllers.php index 3cace05d2a..b123077b90 100644 --- a/app/services_controllers.php +++ b/app/services_controllers.php @@ -93,6 +93,10 @@ return [ 'class' => Console\Bookmark\RefreshController::class, 'arguments' => ['$response' => '@response', '$template' => '@template', '$console' => '@console'], ], + Console\UpdateConfigController::class => [ + 'class' => Console\UpdateConfigController::class, + 'arguments' => ['$response' => '@response', '$template' => '@template', '$config' => '@config'], + ], Database\CentralColumns\PopulateColumnsController::class => [ 'class' => Database\CentralColumns\PopulateColumnsController::class, 'arguments' => [ diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 52c84d5e2d..cc796d4994 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -12449,6 +12449,12 @@ + + + + + + @@ -14482,6 +14488,7 @@ + diff --git a/resources/js/src/modules/ajax.ts b/resources/js/src/modules/ajax.ts index 062f81f95a..d172d2704d 100644 --- a/resources/js/src/modules/ajax.ts +++ b/resources/js/src/modules/ajax.ts @@ -939,7 +939,7 @@ const AJAX = { console.log('AJAX error: status=' + request.status + ', text=' + request.statusText); } - if (settings.url.includes('/git-revision')) { + if (settings.url.includes('/git-revision') || settings.url.includes('/console/update-config')) { return; } diff --git a/resources/js/src/modules/console.ts b/resources/js/src/modules/console.ts index a0f7acd0a7..17a277656c 100644 --- a/resources/js/src/modules/console.ts +++ b/resources/js/src/modules/console.ts @@ -4,10 +4,11 @@ import { AJAX } from './ajax.ts'; import { Functions } from './functions.ts'; import { CommonParams } from './common.ts'; import { Navigation } from './navigation.ts'; -import { Config } from './console/config.ts'; -import { getConfigValue } from './functions/config.ts'; +import Config from './console/config.ts'; import { escapeHtml } from './functions/escape.ts'; +let config: Config; + /** * Console object */ @@ -58,18 +59,13 @@ var Console = { * Used for console initialize, reinit is ok, just some variable assignment */ initialize: function (): void { - if ($('#pma_console').length === 0) { + const consoleElement = document.getElementById('pma_console'); + if (consoleElement === null) { return; } - getConfigValue('Console', false, (data) => { - Config.init(data); - Console.setupAfterInit(); - }, () => { - Config.init({});// Avoid null pointers in setupAfterInit() - // Fetching data failed, still perform the console init - Console.setupAfterInit(); - }); + config = Config.createFromDataset(consoleElement.dataset); + Console.setupAfterInit(); }, /** @@ -101,28 +97,6 @@ var Console = { // Event binds shouldn't run again if (Console.isInitialized === false) { - // Load config first - if (Config.AlwaysExpand) { - (document.getElementById('consoleOptionsAlwaysExpandCheckbox') as HTMLInputElement).checked = true; - } - - if (Config.StartHistory) { - (document.getElementById('consoleOptionsStartHistoryCheckbox') as HTMLInputElement).checked = true; - } - - if (Config.CurrentQuery) { - (document.getElementById('consoleOptionsCurrentQueryCheckbox') as HTMLInputElement).checked = true; - } - - if (Config.EnterExecutes) { - (document.getElementById('consoleOptionsEnterExecutesCheckbox') as HTMLInputElement).checked = true; - } - - if (Config.DarkTheme) { - (document.getElementById('consoleOptionsDarkThemeCheckbox') as HTMLInputElement).checked = true; - $('#pma_console').find('>.content').addClass('console_dark_theme'); - } - ConsoleResizer.initialize(); ConsoleInput.initialize(); ConsoleMessages.initialize(); @@ -174,21 +148,65 @@ var Console = { Console.hideCard($(this).closest('.card')); }); - $('#pma_console_options').find('input[type=checkbox]').on('change', function () { - Config.update(); + const consoleOptionsAlwaysExpandCheckbox = document.getElementById('consoleOptionsAlwaysExpandCheckbox') as HTMLInputElement; + consoleOptionsAlwaysExpandCheckbox?.addEventListener('change', function (): void { + config.setAlwaysExpand(consoleOptionsAlwaysExpandCheckbox.checked); }); - $('#pma_console_options').find('.button.default').on('click', function () { - (document.getElementById('consoleOptionsAlwaysExpandCheckbox') as HTMLInputElement).checked = false; - (document.getElementById('consoleOptionsStartHistoryCheckbox') as HTMLInputElement).checked = false; - (document.getElementById('consoleOptionsCurrentQueryCheckbox') as HTMLInputElement).checked = true; - (document.getElementById('consoleOptionsEnterExecutesCheckbox') as HTMLInputElement).checked = false; - (document.getElementById('consoleOptionsDarkThemeCheckbox') as HTMLInputElement).checked = false; - Config.update(); + const consoleOptionsStartHistoryCheckbox = document.getElementById('consoleOptionsStartHistoryCheckbox') as HTMLInputElement; + consoleOptionsStartHistoryCheckbox?.addEventListener('change', function (): void { + config.setStartHistory(consoleOptionsStartHistoryCheckbox.checked); }); - $('#consoleOptionsEnterExecutesCheckbox').on('change', function () { - ConsoleMessages.showInstructions(Config.EnterExecutes); + const consoleOptionsCurrentQueryCheckbox = document.getElementById('consoleOptionsCurrentQueryCheckbox') as HTMLInputElement; + consoleOptionsCurrentQueryCheckbox?.addEventListener('change', function (): void { + config.setCurrentQuery(consoleOptionsCurrentQueryCheckbox.checked); + }); + + const consoleOptionsEnterExecutesCheckbox = document.getElementById('consoleOptionsEnterExecutesCheckbox') as HTMLInputElement; + consoleOptionsEnterExecutesCheckbox?.addEventListener('change', function (): void { + const isEnterExecutes = consoleOptionsEnterExecutesCheckbox.checked; + config.setEnterExecutes(isEnterExecutes); + ConsoleMessages.showInstructions(isEnterExecutes); + }); + + const consoleOptionsDarkThemeCheckbox = document.getElementById('consoleOptionsDarkThemeCheckbox') as HTMLInputElement; + consoleOptionsDarkThemeCheckbox?.addEventListener('change', function (): void { + const isDarkTheme = consoleOptionsDarkThemeCheckbox.checked; + config.setDarkTheme(isDarkTheme); + const consoleContent = document.getElementById('pma_console').querySelector('.content'); + consoleContent.classList.toggle('console_dark_theme', isDarkTheme); + }); + + const restoreConsoleOptionsButton = document.getElementById('pma_console_options').querySelector('.button.default'); + restoreConsoleOptionsButton?.addEventListener('click', function (): void { + if (consoleOptionsAlwaysExpandCheckbox.checked) { + consoleOptionsAlwaysExpandCheckbox.checked = false; + config.setAlwaysExpand(false); + } + + if (consoleOptionsStartHistoryCheckbox.checked) { + consoleOptionsStartHistoryCheckbox.checked = false; + config.setStartHistory(false); + } + + if (! consoleOptionsCurrentQueryCheckbox.checked) { + consoleOptionsCurrentQueryCheckbox.checked = true; + config.setCurrentQuery(true); + } + + if (consoleOptionsEnterExecutesCheckbox.checked) { + consoleOptionsEnterExecutesCheckbox.checked = false; + config.setEnterExecutes(false); + ConsoleMessages.showInstructions(false); + } + + if (consoleOptionsDarkThemeCheckbox.checked) { + consoleOptionsDarkThemeCheckbox.checked = false; + config.setDarkTheme(false); + const consoleContent = document.getElementById('pma_console').querySelector('.content'); + consoleContent.classList.remove('console_dark_theme'); + } }); $(document).on('ajaxComplete', function (event, xhr, ajaxOptions) { @@ -215,7 +233,7 @@ var Console = { } // Change console mode from cookie - switch (Config.Mode) { + switch (config.mode) { case 'collapse': Console.collapse(); break; @@ -227,7 +245,7 @@ var Console = { Console.scrollBottom(); break; default: - Config.set('Mode', 'info'); + config.setMode('info'); Console.info(); } }, @@ -282,7 +300,7 @@ var Console = { if (data.reloadQuerywindow.sql_query.length > 0) { ConsoleMessages.appendQuery(data.reloadQuerywindow, 'successed') // @ts-ignore - .$message.addClass(Config.CurrentQuery ? '' : 'hide'); + .$message.addClass(config.currentQuery ? '' : 'hide'); } } }, @@ -290,8 +308,8 @@ var Console = { * Change console to collapse mode */ collapse: function (): void { - Config.set('Mode', 'collapse'); - var pmaConsoleHeight = Math.max(92, Config.Height); + config.setMode('collapse'); + var pmaConsoleHeight = Math.max(92, config.height); Console.$consoleToolbar.addClass('collapsed'); Console.$consoleAllContents.height(pmaConsoleHeight); @@ -305,11 +323,11 @@ var Console = { * @param {boolean} inputFocus If true, focus the input line after show() */ show: function (inputFocus = undefined): void { - Config.set('Mode', 'show'); + config.setMode('show'); - var pmaConsoleHeight = Math.max(92, Config.Height); + var pmaConsoleHeight = Math.max(92, config.height); // eslint-disable-next-line compat/compat - pmaConsoleHeight = Math.min(Config.Height, (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) - 25); + pmaConsoleHeight = Math.min(config.height, (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) - 25); Console.$consoleContent.css({ display: 'block' }); if (Console.$consoleToolbar.hasClass('collapsed')) { Console.$consoleToolbar.removeClass('collapsed'); @@ -335,7 +353,7 @@ var Console = { * Used for toggle buttons and shortcuts */ toggle: function (): void { - if (Config.Mode === 'show') { + if (config.mode === 'show') { Console.collapse(); } else { Console.show(true); @@ -413,7 +431,7 @@ var ConsoleResizer = { * @param {MouseEvent} event */ mouseDown: function (event): void { - if (Config.Mode !== 'show') { + if (config.mode !== 'show') { return; } @@ -456,7 +474,7 @@ var ConsoleResizer = { * Mouseup event handler for bind to resizer */ mouseUp: function (): void { - Config.set('Height', Math.round(ConsoleResizer.resultHeight)); + config.setHeight(Math.round(ConsoleResizer.resultHeight)); Console.show(); $(document).off('mousemove'); $(document).off('mouseup'); @@ -638,7 +656,7 @@ var ConsoleInput = { */ keyDown: function (event): void { // Execute command - if (Config.EnterExecutes) { + if (config.enterExecutes) { // Enter, but not in combination with Shift (which writes a new line). if (! event.shiftKey && event.keyCode === 13) { ConsoleInput.execute(); @@ -810,7 +828,7 @@ var ConsoleMessages = { var now = new Date(); var $newMessage = $('
'); switch (msgType) { case 'query': @@ -1053,11 +1071,11 @@ var ConsoleMessages = { */ initialize: function (): void { ConsoleMessages.messageEventBinds($('#pma_console').find('.message:not(.binded)')); - if (Config.StartHistory) { + if (config.startHistory) { ConsoleMessages.showHistory(); } - ConsoleMessages.showInstructions(Config.EnterExecutes); + ConsoleMessages.showInstructions(config.enterExecutes); } }; @@ -1163,17 +1181,17 @@ var ConsoleDebug = { } }); - if (Config.GroupQueries) { + if (config.groupQueries) { $('#debug_console').addClass('grouped'); } else { $('#debug_console').addClass('ungrouped'); - if (Config.OrderBy === 'count') { + if (config.orderBy === 'count') { $('#debug_console').find('.button.order_by.sort_exec').addClass('active'); } } - var orderBy = Config.OrderBy; - var order = Config.Order; + var orderBy = config.orderBy; + var order = config.order; $('#debug_console').find('.button.order_by.sort_' + orderBy).addClass('active'); $('#debug_console').find('.button.order.order_' + order).addClass('active'); @@ -1181,9 +1199,9 @@ var ConsoleDebug = { $('#debug_console').find('.button.group_queries').on('click', function () { $('#debug_console').addClass('grouped'); $('#debug_console').removeClass('ungrouped'); - Config.set('GroupQueries', true); + config.setGroupQueries(true); ConsoleDebug.refresh(); - if (Config.OrderBy === 'count') { + if (config.orderBy === 'count') { $('#debug_console').find('.button.order_by.sort_exec').removeClass('active'); } }); @@ -1191,9 +1209,9 @@ var ConsoleDebug = { $('#debug_console').find('.button.ungroup_queries').on('click', function () { $('#debug_console').addClass('ungrouped'); $('#debug_console').removeClass('grouped'); - Config.set('GroupQueries', false); + config.setGroupQueries(false); ConsoleDebug.refresh(); - if (Config.OrderBy === 'count') { + if (config.orderBy === 'count') { $('#debug_console').find('.button.order_by.sort_exec').addClass('active'); } }); @@ -1203,11 +1221,11 @@ var ConsoleDebug = { $('#debug_console').find('.button.order_by').removeClass('active'); $this.addClass('active'); if ($this.hasClass('sort_time')) { - Config.set('OrderBy', 'time'); + config.setOrderBy('time'); } else if ($this.hasClass('sort_exec')) { - Config.set('OrderBy', 'exec'); + config.setOrderBy('exec'); } else if ($this.hasClass('sort_count')) { - Config.set('OrderBy', 'count'); + config.setOrderBy('count'); } ConsoleDebug.refresh(); @@ -1218,9 +1236,9 @@ var ConsoleDebug = { $('#debug_console').find('.button.order').removeClass('active'); $this.addClass('active'); if ($this.hasClass('order_asc')) { - Config.set('Order', 'asc'); + config.setOrder('asc'); } else if ($this.hasClass('order_desc')) { - Config.set('Order', 'desc'); + config.setOrder('desc'); } ConsoleDebug.refresh(); @@ -1507,7 +1525,7 @@ var ConsoleDebug = { // For sorting queries function sortByTime (a, b) { - var order = Config.Order === 'asc' ? 1 : -1; + var order = config.order === 'asc' ? 1 : -1; if (Array.isArray(a) && Array.isArray(b)) { // It is grouped var timeA = 0; @@ -1528,15 +1546,15 @@ var ConsoleDebug = { } function sortByCount (a, b) { - var order = Config.Order === 'asc' ? 1 : -1; + var order = config.order === 'asc' ? 1 : -1; return (a.length - b.length) * order; } - var orderBy = Config.OrderBy; - var order = Config.Order; + var orderBy = config.orderBy; + var order = config.order; - if (Config.GroupQueries) { + if (config.groupQueries) { // Sort queries if (orderBy === 'time') { uniqueQueries.sort(sortByTime); diff --git a/resources/js/src/modules/console/config.ts b/resources/js/src/modules/console/config.ts index 17b1f604d6..d33cbc7c5a 100644 --- a/resources/js/src/modules/console/config.ts +++ b/resources/js/src/modules/console/config.ts @@ -1,90 +1,139 @@ -import { setConfigValue } from '../functions/config.ts'; +import $ from 'jquery'; +import { ajaxShowMessage } from '../ajax-message.ts'; +import { CommonParams } from '../common.ts'; +import { escapeHtml } from '../functions/escape.ts'; /** * @link https://docs.phpmyadmin.net/en/latest/config.html#console-settings */ -export const Config = { - /** - * @type {boolean} - */ - StartHistory: false, - /** - * @type {boolean} - */ - AlwaysExpand: false, - /** - * @type {boolean} - */ - CurrentQuery: true, - /** - * @type {boolean} - */ - EnterExecutes: false, - /** - * @type {boolean} - */ - DarkTheme: false, - /** - * @type {'info'|'show'|'collapse'} - */ - Mode: 'info', - /** - * @type {number} - */ - Height: 92, - /** - * @type {boolean} - */ - GroupQueries: false, - /** - * @type {'exec'|'time'|'count'} - */ - OrderBy: 'exec', - /** - * @type {'asc'|'desc'} - */ - Order: 'asc', +export default class Config { + startHistory: boolean; - /** - * @param {Object} data - */ - init: function (data): void { - this.StartHistory = !! data.StartHistory; - this.AlwaysExpand = !! data.AlwaysExpand; - this.CurrentQuery = data.CurrentQuery !== undefined ? !! data.CurrentQuery : true; - this.EnterExecutes = !! data.EnterExecutes; - this.DarkTheme = !! data.DarkTheme; - this.Mode = data.Mode === 'show' || data.Mode === 'collapse' ? data.Mode : 'info'; - this.Height = data.Height > 0 ? Number(data.Height) : 92; - this.GroupQueries = !! data.GroupQueries; - this.OrderBy = data.OrderBy === 'time' || data.OrderBy === 'count' ? data.OrderBy : 'exec'; - this.Order = data.Order === 'desc' ? 'desc' : 'asc'; - }, + alwaysExpand: boolean; - /** - * @param {'StartHistory'|'AlwaysExpand'|'CurrentQuery'|'EnterExecutes'|'DarkTheme'|'Mode'|'Height'|'GroupQueries'|'OrderBy'|'Order'} key - * @param {boolean|string|number} value - */ - set: function (key, value): void { - this[key] = value; - setConfigValue('Console/' + key, value); - }, + currentQuery: boolean; - /** - * Used for update console config - */ - update: function (): void { - this.set('AlwaysExpand', !! (document.getElementById('consoleOptionsAlwaysExpandCheckbox') as HTMLInputElement).checked); - this.set('StartHistory', !! (document.getElementById('consoleOptionsStartHistoryCheckbox') as HTMLInputElement).checked); - this.set('CurrentQuery', !! (document.getElementById('consoleOptionsCurrentQueryCheckbox') as HTMLInputElement).checked); - this.set('EnterExecutes', !! (document.getElementById('consoleOptionsEnterExecutesCheckbox') as HTMLInputElement).checked); - this.set('DarkTheme', !! (document.getElementById('consoleOptionsDarkThemeCheckbox') as HTMLInputElement).checked); - /* Setting the dark theme of the console*/ - const consoleContent = document.getElementById('pma_console').querySelector('.content'); - if (this.DarkTheme) { - consoleContent.classList.add('console_dark_theme'); - } else { - consoleContent.classList.remove('console_dark_theme'); - } + enterExecutes: boolean; + + darkTheme: boolean; + + mode: 'info'|'show'|'collapse'; + + height: number; + + groupQueries: boolean; + + orderBy: 'exec'|'time'|'count'; + + order: 'asc'|'desc'; + + constructor ( + startHistory: boolean, + alwaysExpand: boolean, + currentQuery: boolean, + enterExecutes: boolean, + darkTheme: boolean, + mode: 'info'|'show'|'collapse', + height: number, + groupQueries: boolean, + orderBy: 'exec'|'time'|'count', + order: 'asc'|'desc', + ) { + this.startHistory = startHistory; + this.alwaysExpand = alwaysExpand; + this.currentQuery = currentQuery; + this.enterExecutes = enterExecutes; + this.darkTheme = darkTheme; + this.mode = mode; + this.height = height; + this.groupQueries = groupQueries; + this.orderBy = orderBy; + this.order = order; } -}; + + static createFromDataset (dataset: DOMStringMap): Config { + const height = Number(dataset.height); + + return new this( + dataset.startHistory === 'true', + dataset.alwaysExpand === 'true', + dataset.currentQuery !== undefined ? dataset.currentQuery === 'true' : true, + dataset.enterExecutes === 'true', + dataset.darkTheme === 'true', + dataset.mode === 'show' || dataset.mode === 'collapse' ? dataset.mode : 'info', + height > 0 ? height : 92, + dataset.groupQueries === 'true', + dataset.orderBy === 'time' || dataset.orderBy === 'count' ? dataset.orderBy : 'exec', + dataset.order === 'desc' ? 'desc' : 'asc', + ); + } + + setStartHistory (value: boolean): void { + this.startHistory = value; + setConfigValue('StartHistory', value); + } + + setAlwaysExpand (value: boolean): void { + this.alwaysExpand = value; + setConfigValue('AlwaysExpand', value); + } + + setCurrentQuery (value: boolean): void { + this.currentQuery = value; + setConfigValue('CurrentQuery', value); + } + + setEnterExecutes (value: boolean): void { + this.enterExecutes = value; + setConfigValue('EnterExecutes', value); + } + + setDarkTheme (value: boolean): void { + this.darkTheme = value; + setConfigValue('DarkTheme', value); + } + + setMode (value: 'info'|'show'|'collapse'): void { + this.mode = value; + setConfigValue('Mode', value); + } + + setHeight (value: number): void { + this.height = value; + setConfigValue('Height', value); + } + + setGroupQueries (value: boolean): void { + this.groupQueries = value; + setConfigValue('GroupQueries', value); + } + + setOrderBy (value: 'exec'|'time'|'count'): void { + this.orderBy = value; + setConfigValue('OrderBy', value); + } + + setOrder (value: 'asc'|'desc'): void { + this.order = value; + setConfigValue('Order', value); + } +} + +/** + * @param {'StartHistory'|'AlwaysExpand'|'CurrentQuery'|'EnterExecutes'|'DarkTheme'|'Mode'|'Height'|'GroupQueries'|'OrderBy'|'Order'} key + * @param {boolean|string|number} value + */ +function setConfigValue (key: string, value: boolean|number|string): void { + $.post( + 'index.php?route=/console/update-config', + { + 'ajax_request': true, + server: CommonParams.get('server'), + key: key, + value: value, + }, + ).fail(function (data) { + const message = ''; + ajaxShowMessage(message, false); + }); +} diff --git a/resources/templates/console/display.twig b/resources/templates/console/display.twig index 7f3540d40c..0dfe621904 100644 --- a/resources/templates/console/display.twig +++ b/resources/templates/console/display.twig @@ -1,5 +1,15 @@
-
+