Merge pull request #14467 from Piyush3079/Mod_Js_Server_Status

Modularize Server Status JS files
This commit is contained in:
Deven Bansod 2018-07-28 18:19:16 +05:30 committed by GitHub
commit ed6f106470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 689 additions and 9 deletions

View File

@ -586,7 +586,8 @@ export let AJAX = {
* @todo This condition is to be removed once all the files are modularised
*/
if (checkNewCode(file)) {
var fileImports = ['server_privileges', 'server_databases'];
var fileImports = ['server_privileges', 'server_databases', 'server_status_advisor',
'server_status_processes', 'server_status_variables',];
if ($.inArray(file, fileImports) !== -1) {
// Dynamic import to load the files dynamically
// This is used for the purpose of code splitting

View File

@ -268,13 +268,11 @@ var ErrorReport = {
* @return function
*/
wrap_function: function (func) {
// console.log(func.wrapped);
if (!func.wrapped) {
var new_func = function () {
try {
return func.apply(this, arguments);
} catch (x) {
// console.log(new Error(x));
TraceKit.report(x);
}
};
@ -284,7 +282,6 @@ var ErrorReport = {
new_func.guid = func.guid = func.guid || new_func.guid || jQuery.guid++;
return new_func;
} else {
// console.log(func);
return func;
}
},

View File

@ -0,0 +1,164 @@
import { PMA_ajaxShowMessage } from '../../utils/show_ajax_messages';
import { PMA_highlightSQL } from '../../utils/sql';
import { PMA_Messages as PMA_messages } from '../../variables/export_variables';
import { PMA_commonParams } from '../../variables/common_params';
import { PMA_getImage } from '../../functions/get_image';
import { escapeHtml } from '../../utils/Sanitise';
import { jQuery as $ } from '../../utils/JqueryExtended';
// object to store process list state information
class ProcessList {
constructor () {
// denotes whether auto refresh is on or off
this.autoRefresh = false;
// stores the GET request which refresh process list
this.refreshRequest = null;
// stores the timeout id returned by setTimeout
this.refreshTimeout = null;
// the refresh interval in seconds
this.refreshInterval = null;
// the refresh URL (required to save last used option)
// i.e. full or sorting url
this.refreshUrl = null;
this.init = this.init.bind(this);
this.killProcessHandler = this.killProcessHandler.bind(this);
this.refresh = this.refresh.bind(this);
this.abortRefresh = this.abortRefresh.bind(this);
this.setRefreshLabel = this.setRefreshLabel.bind(this);
this.getUrlParams = this.getUrlParams.bind(this);
}
/**
* Handles killing of a process
*
* @return void
*/
init () {
this.setRefreshLabel();
if (this.refreshUrl === null) {
this.refreshUrl = 'server_status_processes.php' +
PMA_commonParams.get('common_query');
}
if (this.refreshInterval === null) {
this.refreshInterval = $('#id_refreshRate').val();
} else {
$('#id_refreshRate').val(this.refreshInterval);
}
}
/**
* Handles killing of a process
*
* @param object the event object
*
* @return void
*/
killProcessHandler (event, elementRef) {
event.preventDefault();
var url = $(elementRef).attr('href');
// Get row element of the process to be killed.
var $tr = $(elementRef).closest('tr');
$.getJSON(url, function (data) {
// Check if process was killed or not.
if (data.hasOwnProperty('success') && data.success) {
// remove the row of killed process.
$tr.remove();
// As we just removed a row, reapply odd-even classes
// to keep table stripes consistent
var $tableProcessListTr = $('#tableprocesslist').find('> tbody > tr');
$tableProcessListTr.filter(':even').removeClass('odd').addClass('even');
$tableProcessListTr.filter(':odd').removeClass('even').addClass('odd');
// Show process killed message
PMA_ajaxShowMessage(data.message, false);
} else {
// Show process error message
PMA_ajaxShowMessage(data.error, false);
}
});
}
/**
* Handles Auto Refreshing
*
* @param object the event object
*
* @return void
*/
refresh () {
// abort any previous pending requests
// this is necessary, it may go into
// multiple loops causing unnecessary
// requests even after leaving the page.
this.abortRefresh();
// if auto refresh is enabled
if (this.autoRefresh) {
var interval = parseInt(this.refreshInterval, 10) * 1000;
var urlParams = this.getUrlParams();
this.refreshRequest = $.get(this.refreshUrl,
urlParams,
function (data) {
if (data.hasOwnProperty('success') && data.success) {
var $newTable = $(data.message);
$('#tableprocesslist').html($newTable.html());
PMA_highlightSQL($('#tableprocesslist'));
}
this.refreshTimeout = setTimeout(
this.refresh,
interval
);
}.bind(this));
}
}
/**
* Stop current request and clears timeout
*
* @return void
*/
abortRefresh () {
if (this.refreshRequest !== null) {
this.refreshRequest.abort();
this.refreshRequest = null;
}
clearTimeout(this.refreshTimeout);
}
/**
* Set label of refresh button
* change between play & pause
*
* @return void
*/
setRefreshLabel () {
var img = 'play';
var label = PMA_messages.strStartRefresh;
if (this.autoRefresh) {
img = 'pause';
label = PMA_messages.strStopRefresh;
this.refresh();
}
$('a#toggleRefresh').html(PMA_getImage(img) + escapeHtml(label));
}
/**
* Return the Url Parameters
* for autorefresh request,
* includes showExecuting if the filter is checked
*
* @return urlParams - url parameters with autoRefresh request
*/
getUrlParams () {
var urlParams = { 'ajax_request': true, 'refresh': true };
if ($('#showExecuting').is(':checked')) {
urlParams.showExecuting = true;
return urlParams;
}
return urlParams;
}
}
/**
* Instance is exported to ensure that every time the import
* will have the instance only and not the class itself
*/
let processList = new ProcessList();
export default processList;

View File

@ -8,7 +8,10 @@
*/
const files = {
server_privileges: ['server_privileges'],
server_databases: ['server_databases']
server_databases: ['server_databases'],
server_status_advisor: ['server_status_advisor'],
server_status_processes: ['server_status_processes'],
server_status_variables: ['server_status_variables'],
};
export default files;

View File

@ -15,6 +15,7 @@ import { PMA_Messages as PMA_messages } from './variables/export_variables';
import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
import { PMA_commonParams } from './variables/common_params';
import { jQuery as $ } from './utils/JqueryExtended';
import { PMA_getSQLEditor } from './utils/sql';
/**
* AJAX scripts for server_privileges page.

View File

@ -0,0 +1,102 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Server Status Advisor
*
* @package PhpMyAdmin
*/
import { PMA_Messages as PMA_messages } from './variables/export_variables';
/**
* Unbind all event handlers before tearing down a page
*/
export function teardown1 () {
$('a[href="#openAdvisorInstructions"]').off('click');
$('#statustabs_advisor').html('');
$('#advisorDialog').remove();
$('#instructionsDialog').remove();
}
export function onload1 () {
// if no advisor is loaded
if ($('#advisorData').length === 0) {
return;
}
/** ** Server config advisor ****/
var $dialog = $('<div />').attr('id', 'advisorDialog');
var $instructionsDialog = $('<div />')
.attr('id', 'instructionsDialog')
.html($('#advisorInstructionsDialog').html());
$('a[href="#openAdvisorInstructions"]').click(function () {
var dlgBtns = {};
dlgBtns[PMA_messages.strClose] = function () {
$(this).dialog('close');
};
$instructionsDialog.dialog({
title: PMA_messages.strAdvisorSystem,
width: 700,
buttons: dlgBtns
});
});
var $cnt = $('#statustabs_advisor');
var $tbody;
var $tr;
var even = true;
var data = JSON.parse($('#advisorData').text());
$cnt.html('');
if (data.parse.errors.length > 0) {
$cnt.append('<b>Rules file not well formed, following errors were found:</b><br />- ');
$cnt.append(data.parse.errors.join('<br/>- '));
$cnt.append('<p></p>');
}
if (data.run.errors.length > 0) {
$cnt.append('<b>Errors occurred while executing rule expressions:</b><br />- ');
$cnt.append(data.run.errors.join('<br/>- '));
$cnt.append('<p></p>');
}
if (data.run.fired.length > 0) {
$cnt.append('<p><b>' + PMA_messages.strPerformanceIssues + '</b></p>');
$cnt.append('<table class="data" id="rulesFired" border="0"><thead><tr>' +
'<th>' + PMA_messages.strIssuse + '</th><th>' + PMA_messages.strRecommendation +
'</th></tr></thead><tbody></tbody></table>');
$tbody = $cnt.find('table#rulesFired');
var rc_stripped;
$.each(data.run.fired, function (key, value) {
// recommendation may contain links, don't show those in overview table (clicking on them redirects the user)
rc_stripped = $.trim($('<div>').html(value.recommendation).text());
$tbody.append($tr = $('<tr class="linkElem noclick"><td>' +
value.issue + '</td><td>' + rc_stripped + ' </td></tr>'));
even = !even;
$tr.data('rule', value);
$tr.click(function () {
var rule = $(this).data('rule');
$dialog
.dialog({ title: PMA_messages.strRuleDetails })
.html(
'<p><b>' + PMA_messages.strIssuse + ':</b><br />' + rule.issue + '</p>' +
'<p><b>' + PMA_messages.strRecommendation + ':</b><br />' + rule.recommendation + '</p>' +
'<p><b>' + PMA_messages.strJustification + ':</b><br />' + rule.justification + '</p>' +
'<p><b>' + PMA_messages.strFormula + ':</b><br />' + rule.formula + '</p>' +
'<p><b>' + PMA_messages.strTest + ':</b><br />' + rule.test + '</p>'
);
var dlgBtns = {};
dlgBtns[PMA_messages.strClose] = function () {
$(this).dialog('close');
};
$dialog.dialog({ width: 600, buttons: dlgBtns });
});
});
}
}

View File

@ -0,0 +1,41 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Server Status Processes
*
* @package PhpMyAdmin
*/
import processList from './classes/Server/ProcessList';
export function onload1 () {
processList.init();
// Bind event handler for kill_process
$('#tableprocesslist').on('click', 'a.kill_process', function (event) {
processList.killProcessHandler(event, this);
});
// Bind event handler for toggling refresh of process list
$('a#toggleRefresh').on('click', function (event) {
event.preventDefault();
processList.autoRefresh = !processList.autoRefresh;
processList.setRefreshLabel();
});
// Bind event handler for change in refresh rate
$('#id_refreshRate').on('change', function (event) {
processList.refreshInterval = $(this).val();
processList.refresh();
});
// Bind event handler for table header links
$('#tableprocesslist').on('click', 'thead a', function () {
processList.refreshUrl = $(this).attr('href');
});
}
/**
* Unbind all event handlers before tearing down a page
*/
export function teardown1 () {
$('#tableprocesslist').off('click', 'a.kill_process');
$('a#toggleRefresh').off('click');
$('#id_refreshRate').off('change');
$('#tableprocesslist').off('click', 'thead a');
// stop refreshing further
processList.abortRefresh();
}

View File

@ -0,0 +1,100 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
*
*
* @package PhpMyAdmin
*/
/**
* Unbind all event handlers before tearing down a page
*/
export function teardown1 () {
$('#filterAlert').off('change');
$('#filterText').off('keyup');
$('#filterCategory').off('change');
$('#dontFormat').off('change');
}
export function onload1 () {
// Filters for status variables
var textFilter = null;
var alertFilter = $('#filterAlert').prop('checked');
var categoryFilter = $('#filterCategory').find(':selected').val();
var text = ''; // Holds filter text
/* 3 Filtering functions */
$('#filterAlert').change(function () {
alertFilter = this.checked;
filterVariables();
});
$('#filterCategory').change(function () {
categoryFilter = $(this).val();
filterVariables();
});
$('#dontFormat').change(function () {
// Hiding the table while changing values speeds up the process a lot
$('#serverstatusvariables').hide();
$('#serverstatusvariables').find('td.value span.original').toggle(this.checked);
$('#serverstatusvariables').find('td.value span.formatted').toggle(! this.checked);
$('#serverstatusvariables').show();
}).trigger('change');
$('#filterText').keyup(function (e) {
var word = $(this).val().replace(/_/g, ' ');
if (word.length === 0) {
textFilter = null;
} else {
try {
textFilter = new RegExp('(^| )' + word, 'i');
$(this).removeClass('error');
} catch (e) {
if (e instanceof SyntaxError) {
$(this).addClass('error');
textFilter = null;
}
}
}
text = word;
filterVariables();
}).trigger('keyup');
/* Filters the status variables by name/category/alert in the variables tab */
function filterVariables () {
var useful_links = 0;
var section = text;
if (categoryFilter.length > 0) {
section = categoryFilter;
}
if (section.length > 1) {
$('#linkSuggestions').find('span').each(function () {
if ($(this).attr('class').indexOf('status_' + section) !== -1) {
useful_links++;
$(this).css('display', '');
} else {
$(this).css('display', 'none');
}
});
}
if (useful_links > 0) {
$('#linkSuggestions').css('display', '');
} else {
$('#linkSuggestions').css('display', 'none');
}
$('#serverstatusvariables').find('th.name').each(function () {
if ((textFilter === null || textFilter.exec($(this).text())) &&
(! alertFilter || $(this).next().find('span.attention').length > 0) &&
(categoryFilter.length === 0 || $(this).parent().hasClass('s_' + categoryFilter))
) {
$(this).parent().css('display', '');
} else {
$(this).parent().css('display', 'none');
}
});
}
}

272
js/src/utils/sql.js Normal file
View File

@ -0,0 +1,272 @@
import CodeMirror from 'codemirror';
import '../../../node_modules/codemirror/mode/sql/sql.js';
import '../../../node_modules/codemirror/addon/runmode/runmode.js';
import '../../../node_modules/codemirror/addon/hint/show-hint.js';
import '../../../node_modules/codemirror/addon/hint/sql-hint.js';
import '../../../node_modules/codemirror/addon/lint/lint.js';
// import '../../../node_modules/codemirror/addon/lint/sql-lint.js';
import { mysql_doc_builtin, mysql_doc_keyword } from '../consts/doclinks';
window.cm = CodeMirror;
/**
* Adds doc link to single highlighted SQL element
*/
function PMA_doc_add ($elm, params) {
if (typeof mysql_doc_template === 'undefined') {
return;
}
var url = PMA_sprintf(
decodeURIComponent(mysql_doc_template),
params[0]
);
if (params.length > 1) {
url += '#' + params[1];
}
var content = $elm.text();
$elm.text('');
$elm.append('<a target="mysql_doc" class="cm-sql-doc" href="' + url + '">' + content + '</a>');
}
/**
* Generates doc links for keywords inside highlighted SQL
*/
function PMA_doc_keyword (idx, elm) {
var $elm = $(elm);
/* Skip already processed ones */
if ($elm.find('a').length > 0) {
return;
}
var keyword = $elm.text().toUpperCase();
var $next = $elm.next('.cm-keyword');
if ($next) {
var next_keyword = $next.text().toUpperCase();
var full = keyword + ' ' + next_keyword;
var $next2 = $next.next('.cm-keyword');
if ($next2) {
var next2_keyword = $next2.text().toUpperCase();
var full2 = full + ' ' + next2_keyword;
if (full2 in mysql_doc_keyword) {
PMA_doc_add($elm, mysql_doc_keyword[full2]);
PMA_doc_add($next, mysql_doc_keyword[full2]);
PMA_doc_add($next2, mysql_doc_keyword[full2]);
return;
}
}
if (full in mysql_doc_keyword) {
PMA_doc_add($elm, mysql_doc_keyword[full]);
PMA_doc_add($next, mysql_doc_keyword[full]);
return;
}
}
if (keyword in mysql_doc_keyword) {
PMA_doc_add($elm, mysql_doc_keyword[keyword]);
}
}
/**
* Generates doc links for builtins inside highlighted SQL
*/
function PMA_doc_builtin (idx, elm) {
var $elm = $(elm);
var builtin = $elm.text().toUpperCase();
if (builtin in mysql_doc_builtin) {
PMA_doc_add($elm, mysql_doc_builtin[builtin]);
}
}
/**
* Higlights SQL using CodeMirror.
*/
export function PMA_highlightSQL ($base) {
var $elm = $base.find('code.sql');
$elm.each(function () {
var $sql = $(this);
var $pre = $sql.find('pre');
/* We only care about visible elements to avoid double processing */
if ($pre.is(':visible')) {
var $highlight = $('<div class="sql-highlight cm-s-default"></div>');
$sql.append($highlight);
if (typeof CodeMirror !== 'undefined') {
CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]);
$pre.hide();
$highlight.find('.cm-keyword').each(PMA_doc_keyword);
$highlight.find('.cm-builtin').each(PMA_doc_builtin);
}
}
});
}
/**
* "inputRead" event handler for CodeMirror SQL query editors for autocompletion
*/
let sql_autocomplete_in_progress = false;
let sql_autocomplete = false;
var sql_autocomplete_default_table = '';
export function codemirrorAutocompleteOnInputRead (instance) {
if (!sql_autocomplete_in_progress
&& (!instance.options.hintOptions.tables || !sql_autocomplete)) {
if (!sql_autocomplete) {
// Reset after teardown
instance.options.hintOptions.tables = false;
instance.options.hintOptions.defaultTable = '';
sql_autocomplete_in_progress = true;
var href = 'db_sql_autocomplete.php';
var params = {
'ajax_request': true,
'server': PMA_commonParams.get('server'),
'db': PMA_commonParams.get('db'),
'no_debug': true
};
var columnHintRender = function (elem, self, data) {
$('<div class="autocomplete-column-name">')
.text(data.columnName)
.appendTo(elem);
$('<div class="autocomplete-column-hint">')
.text(data.columnHint)
.appendTo(elem);
};
$.ajax({
type: 'POST',
url: href,
data: params,
success: function (data) {
if (data.success) {
var tables = JSON.parse(data.tables);
sql_autocomplete_default_table = PMA_commonParams.get('table');
sql_autocomplete = [];
for (var table in tables) {
if (tables.hasOwnProperty(table)) {
var columns = tables[table];
table = {
text: table,
columns: []
};
for (var column in columns) {
if (columns.hasOwnProperty(column)) {
var displayText = columns[column].Type;
if (columns[column].Key === 'PRI') {
displayText += ' | Primary';
} else if (columns[column].Key === 'UNI') {
displayText += ' | Unique';
}
table.columns.push({
text: column,
displayText: column + ' | ' + displayText,
columnName: column,
columnHint: displayText,
render: columnHintRender
});
}
}
}
sql_autocomplete.push(table);
}
instance.options.hintOptions.tables = sql_autocomplete;
instance.options.hintOptions.defaultTable = sql_autocomplete_default_table;
}
},
complete: function () {
sql_autocomplete_in_progress = false;
}
});
} else {
instance.options.hintOptions.tables = sql_autocomplete;
instance.options.hintOptions.defaultTable = sql_autocomplete_default_table;
}
}
if (instance.state.completionActive) {
return;
}
var cur = instance.getCursor();
var token = instance.getTokenAt(cur);
var string = '';
if (token.string.match(/^[.`\w@]\w*$/)) {
string = token.string;
}
if (string.length > 0) {
CodeMirror.commands.autocomplete(instance);
}
}
/**
* Creates an SQL editor which supports auto completing etc.
*
* @param $textarea jQuery object wrapping the textarea to be made the editor
* @param options optional options for CodeMirror
* @param resize optional resizing ('vertical', 'horizontal', 'both')
* @param lintOptions additional options for lint
*/
export function PMA_getSQLEditor ($textarea, options, resize, lintOptions) {
if ($textarea.length > 0 && typeof CodeMirror !== 'undefined') {
// merge options for CodeMirror
var defaults = {
lineNumbers: true,
matchBrackets: true,
extraKeys: { 'Ctrl-Space': 'autocomplete' },
hintOptions: { 'completeSingle': false, 'completeOnSingleClick': true },
indentUnit: 4,
mode: 'text/x-mysql',
lineWrapping: true
};
if (CodeMirror.sqlLint) {
$.extend(defaults, {
gutters: ['CodeMirror-lint-markers'],
lint: {
'getAnnotations': CodeMirror.sqlLint,
'async': true,
'lintOptions': lintOptions
}
});
}
$.extend(true, defaults, options);
// create CodeMirror editor
var codemirrorEditor = CodeMirror.fromTextArea($textarea[0], defaults);
// allow resizing
if (! resize) {
resize = 'vertical';
}
var handles = '';
if (resize === 'vertical') {
handles = 's';
}
if (resize === 'both') {
handles = 'all';
}
if (resize === 'horizontal') {
handles = 'e, w';
}
$(codemirrorEditor.getWrapperElement())
.css('resize', resize)
.resizable({
handles: handles,
resize: function () {
codemirrorEditor.setSize($(this).width(), $(this).height());
}
});
// enable autocomplete
codemirrorEditor.on('inputRead', codemirrorAutocompleteOnInputRead);
// page locking
codemirrorEditor.on('change', function (e) {
e.data = {
value: 3,
content: codemirrorEditor.isClean(),
};
AJAX.lockPageHandler(e);
});
return codemirrorEditor;
}
return null;
}

View File

@ -30,7 +30,6 @@ export const PMA_commonParams = (function () {
if (i === 'db' || i === 'table') {
updateNavigation = true;
}
// reload = true;
}
params[i] = obj[i];
}

View File

@ -19,7 +19,7 @@ $serverStatusData = new Data();
$response = Response::getInstance();
$scripts = $response->getHeader()->getScripts();
$scripts->addFile('server_status_advisor.js');
$scripts->addFile('server_status_advisor');
/**
* Output

View File

@ -52,7 +52,7 @@ if ($response->isAjax() && !empty($_REQUEST['kill'])) {
// Load the full page
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('server_status_processes.js');
$scripts->addFile('server_status_processes');
$response->addHTML('<div>');
$response->addHTML($serverStatusData->getMenuHtml());
$response->addHTML(Processes::getHtmlForProcessListFilter());

View File

@ -37,7 +37,7 @@ $serverStatusData = new Data();
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('server_status_variables.js');
$scripts->addFile('server_status_variables');
$scripts->addFile('vendor/jquery/jquery.tablesorter.js');
$scripts->addFile('server_status_sorter.js');