Replace jqPlot with Chart.js for the profiling chart

Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
Maurício Meneghini Fauth 2023-06-17 21:23:44 -03:00
parent f22985ab15
commit 6cda25211e
No known key found for this signature in database
GPG Key ID: 6A16FD38AFC89CC8
12 changed files with 103 additions and 125 deletions

View File

@ -5,7 +5,6 @@ import { Navigation } from './modules/navigation.ts';
import { CommonParams } from './modules/common.ts';
import highlightSql from './modules/sql-highlight.ts';
import { ajaxRemoveMessage, ajaxShowMessage } from './modules/ajax-message.ts';
import createProfilingChart from './modules/functions/createProfilingChart.ts';
import { escapeHtml } from './modules/functions/escape.ts';
import refreshMainContent from './modules/functions/refreshMainContent.ts';
import isStorageSupported from './modules/functions/isStorageSupported.ts';
@ -1323,27 +1322,45 @@ AJAX.registerOnload('sql.js', function () {
}
});
/**
* Profiling Chart
*/
function makeProfilingChart () {
if ($('#profilingchart').length === 0 ||
$('#profilingchart').html().length !== 0 ||
! $.jqplot || ! $.jqplot.Highlighter || ! $.jqplot.PieRenderer
) {
function buildProfilingChart () {
const profilingChartCanvas = document.getElementById('profilingChartCanvas') as HTMLCanvasElement;
if (! profilingChartCanvas) {
return;
}
var data = [];
$.each(JSON.parse($('#profilingChartData').html()), function (key, value) {
data.push([key, parseFloat(value)]);
const chartDataJson = profilingChartCanvas.getAttribute('data-chart-data');
let chartData = null;
try {
chartData = JSON.parse(chartDataJson);
} catch (e) {
return;
}
if (! (chartData && 'labels' in chartData && 'data' in chartData)) {
return;
}
const lang = CommonParams.get('lang');
const numberFormat = new Intl.NumberFormat(lang.replace('_', '-'), {
style: 'unit',
unit: 'second',
unitDisplay: 'long',
notation: 'engineering',
});
// Remove chart and data divs contents
$('#profilingchart').html('').show();
$('#profilingChartData').html('');
createProfilingChart('profilingchart', data);
new window.Chart(profilingChartCanvas, {
type: 'pie',
data: {
labels: chartData.labels,
datasets: [{ data: chartData.data }],
},
options: {
plugins: {
legend: { position: 'bottom' },
tooltip: { callbacks: { label: context => context.parsed ? numberFormat.format(context.parsed) : '' } },
},
},
});
}
/**
@ -1390,8 +1407,8 @@ function initProfilingTables () {
}
AJAX.registerOnload('sql.js', function () {
Sql.makeProfilingChart();
Sql.initProfilingTables();
buildProfilingChart();
});
const Sql = {
@ -1407,7 +1424,6 @@ const Sql = {
browseForeignDialog: browseForeignDialog,
getAutoSavedKey: getAutoSavedKey,
checkSavedQuery: checkSavedQuery,
makeProfilingChart: makeProfilingChart,
initProfilingTables: initProfilingTables,
};

View File

@ -644,7 +644,8 @@ class Generator
$retval .= '<div class="card-footer tools d-print-none">' . "\n";
$retval .= '<div class="row align-items-center">' . "\n";
$retval .= '<div class="col-auto">' . "\n";
$retval .= '<form action="' . Url::getFromRoute('/sql') . '" method="post" class="disableAjax">' . "\n";
$retval .= '<form action="' . Url::getFromRoute('/sql', ['db' => $GLOBALS['db'], 'table' => $GLOBALS['table']])
. '" method="post" class="disableAjax">' . "\n";
$retval .= Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) . "\n";
$retval .= '<input type="hidden" name="sql_query" value="'
. htmlspecialchars($sqlQuery) . '">' . "\n";

View File

@ -73,10 +73,7 @@ final class Profiling
$scripts = $response->getHeader()->getScripts();
$scripts->addFiles([
'chart.js',
'vendor/jqplot/jquery.jqplot.js',
'vendor/jqplot/plugins/jqplot.pieRenderer.js',
'vendor/jqplot/plugins/jqplot.highlighter.js',
'vendor/chart.umd.js',
'vendor/jquery/jquery.tablesorter.js',
]);
}

View File

@ -27,6 +27,7 @@ use function __;
use function array_column;
use function array_keys;
use function array_sum;
use function arsort;
use function bin2hex;
use function ceil;
use function count;
@ -251,7 +252,7 @@ class Sql
* @psalm-return array{
* total_time: float,
* states: array<string, array{total_time: float, calls: int<1, max>}>,
* chart: array<string, float>,
* chart: array{labels: list<string>, data: list<float>},
* profile: list<array{status: string, duration: string, duration_raw: numeric-string}>
* }|array{}
*/
@ -263,7 +264,6 @@ class Sql
}
$states = [];
$chart = [];
$profile = [];
foreach ($profilingResults as $result) {
$status = ucwords($result['Status']);
@ -275,14 +275,15 @@ class Sql
if (! isset($states[$status])) {
$states[$status] = ['total_time' => (float) $result['Duration'], 'calls' => 1];
$chart[$status] = (float) $result['Duration'];
} else {
$states[$status]['calls']++;
$states[$status]['total_time'] += $result['Duration'];
$chart[$status] += $result['Duration'];
}
}
arsort($states);
$chart = ['labels' => array_keys($states), 'data' => array_column($states, 'total_time')];
return ['total_time' => $totalTime, 'states' => $states, 'chart' => $chart, 'profile' => $profile];
}

View File

@ -566,22 +566,6 @@ div {
// end serverstatus
// profiling
div#profilingchart {
width: 850px;
height: 370px;
float: left;
}
#profilingchart .jqplot-highlighter-tooltip {
top: auto !important;
left: 11px;
bottom: 24px;
}
// end profiling
// table charting
#resizer {
border: 1px solid silver;

View File

@ -817,16 +817,6 @@ div {
/* end serverstatus */
/* profiling */
div#profilingchart {
width: 850px;
height: 370px;
float: left;
}
/* END profiling */
/* table charting */
#resizer {

View File

@ -577,19 +577,6 @@ div#logTable {
padding-left: 7px;
}
/* profiling */
div#profilingchart {
width: 850px;
height: 370px;
float: left;
}
#profilingchart .jqplot-highlighter-tooltip {
top: auto !important;
left: 11px;
bottom: 24px;
}
textarea {
&#sqlquery {
width: 100%;

View File

@ -752,22 +752,6 @@ div {
// end serverstatus
// profiling
div#profilingchart {
width: 850px;
height: 370px;
float: left;
}
#profilingchart .jqplot-highlighter-tooltip {
top: auto !important;
left: 11px;
bottom: 24px;
}
// end profiling
// table charting
#resizer {
border: 1px solid silver;

View File

@ -63,17 +63,9 @@
</div>
<div class="col">
<div id="profilingChartData" class="hide">{{ profiling.chart|json_encode() }}</div>
<div id="profilingchart" class="hide"></div>
<canvas id="profilingChartCanvas" data-chart-data="{{ profiling.chart|json_encode|e('html_attr') }}" aria-label="{{ 'Pie chart with profiling results.'|trans }}" role="img"></canvas>
</div>
</div>
</div>
</div>
<script>
window.AJAX.registerOnload('sql.js', function () {
Sql.makeProfilingChart();
Sql.initProfilingTables();
});
</script>
</div>

View File

@ -494,7 +494,7 @@ SELECT 1;
<div class="card-footer tools d-print-none">
<div class="row align-items-center">
<div class="col-auto">
<form action="index.php?route=/sql&server=2&lang=en" method="post" class="disableAjax">
<form action="index.php?route=/sql&db=test_db&table=test_table&server=2&lang=en" method="post" class="disableAjax">
<input type="hidden" name="db" value="test_db"><input type="hidden" name="table" value="test_table"><input type="hidden" name="server" value="2"><input type="hidden" name="lang" value="en"><input type="hidden" name="token" value="token">
<input type="hidden" name="sql_query" value="SELECT 1;">
<input type="hidden" name="profiling_form" value="1">
@ -546,7 +546,7 @@ $sql = "EXPLAIN SELECT 1;";
<div class="card-footer tools d-print-none">
<div class="row align-items-center">
<div class="col-auto">
<form action="index.php?route=/sql&server=2&lang=en" method="post" class="disableAjax">
<form action="index.php?route=/sql&db=test_db&table=test_table&server=2&lang=en" method="post" class="disableAjax">
<input type="hidden" name="db" value="test_db"><input type="hidden" name="table" value="test_table"><input type="hidden" name="server" value="2"><input type="hidden" name="lang" value="en"><input type="hidden" name="token" value="token">
<input type="hidden" name="sql_query" value="EXPLAIN SELECT 1;">
</form></div>

View File

@ -666,50 +666,75 @@ class SqlTest extends AbstractTestCase
$expected = [
'total_time' => 0.000299,
'states' => [
'Starting' => ['total_time' => 0.000017, 'calls' => 1],
'Checking Permissions' => ['total_time' => 0.000003, 'calls' => 1],
'Opening Tables' => ['total_time' => 0.00016, 'calls' => 2],
'After Opening Tables' => ['total_time' => 0.000006, 'calls' => 2],
'System Lock' => ['total_time' => 0.000004, 'calls' => 2],
'Sending Data' => ['total_time' => 0.000029, 'calls' => 1],
'Starting' => ['total_time' => 0.000017, 'calls' => 1],
'Table Lock' => ['total_time' => 0.000015, 'calls' => 2],
'Unlocking Tables' => ['total_time' => 0.000004, 'calls' => 2],
'Closing Tables' => ['total_time' => 0.000009, 'calls' => 3],
'Reset For Next Command' => ['total_time' => 0.000009, 'calls' => 1],
'Init' => ['total_time' => 0.000007, 'calls' => 1],
'Optimizing' => ['total_time' => 0.000004, 'calls' => 1],
'Updating Status' => ['total_time' => 0.000007, 'calls' => 1],
'After Opening Tables' => ['total_time' => 0.000006, 'calls' => 2],
'Statistics' => ['total_time' => 0.000006, 'calls' => 1],
'Preparing' => ['total_time' => 0.000006, 'calls' => 1],
'Executing' => ['total_time' => 0.000002, 'calls' => 1],
'Sending Data' => ['total_time' => 0.000029, 'calls' => 1],
'System Lock' => ['total_time' => 0.000004, 'calls' => 2],
'Unlocking Tables' => ['total_time' => 0.000004, 'calls' => 2],
'Optimizing' => ['total_time' => 0.000004, 'calls' => 1],
'Checking Permissions' => ['total_time' => 0.000003, 'calls' => 1],
'End Of Update Loop' => ['total_time' => 0.000003, 'calls' => 1],
'Executing' => ['total_time' => 0.000002, 'calls' => 1],
'Query End' => ['total_time' => 0.000002, 'calls' => 1],
'Commit' => ['total_time' => 0.000002, 'calls' => 1],
'Starting Cleanup' => ['total_time' => 0.000002, 'calls' => 1],
'Freeing Items' => ['total_time' => 0.000002, 'calls' => 1],
'Updating Status' => ['total_time' => 0.000007, 'calls' => 1],
'Reset For Next Command' => ['total_time' => 0.000009, 'calls' => 1],
],
'chart' => [
'Starting' => 0.000017,
'Checking Permissions' => 0.000003,
'Opening Tables' => 0.00016,
'After Opening Tables' => 0.000006,
'System Lock' => 0.000004,
'Table Lock' => 0.000015,
'Unlocking Tables' => 0.000004,
'Closing Tables' => 0.000009,
'Init' => 0.000007,
'Optimizing' => 0.000004,
'Statistics' => 0.000006,
'Preparing' => 0.000006,
'Executing' => 0.000002,
'Sending Data' => 0.000029,
'End Of Update Loop' => 0.000003,
'Query End' => 0.000002,
'Commit' => 0.000002,
'Starting Cleanup' => 0.000002,
'Freeing Items' => 0.000002,
'Updating Status' => 0.000007,
'Reset For Next Command' => 0.000009,
'labels' => [
'Opening Tables',
'Sending Data',
'Starting',
'Table Lock',
'Closing Tables',
'Reset For Next Command',
'Init',
'Updating Status',
'After Opening Tables',
'Statistics',
'Preparing',
'System Lock',
'Unlocking Tables',
'Optimizing',
'Checking Permissions',
'End Of Update Loop',
'Executing',
'Query End',
'Commit',
'Starting Cleanup',
'Freeing Items',
],
'data' => [
0.00016,
0.000029,
0.000017,
0.000015,
0.000009,
0.000009,
0.000007,
0.000007,
0.000006,
0.000006,
0.000006,
0.000004,
0.000004,
0.000004,
0.000003,
0.000003,
0.000002,
0.000002,
0.000002,
0.000002,
0.000002,
],
],
'profile' => [
['status' => 'Starting', 'duration' => '17 µ', 'duration_raw' => '0.000017'],

View File

@ -160,6 +160,7 @@ module.exports = [
{ from: rootPath + '/node_modules/updated-jqplot/build/plugins/jqplot.cursor.js', to: publicPath + '/js/vendor/jqplot/plugins/jqplot.cursor.js' },
{ from: rootPath + '/node_modules/updated-jqplot/build/plugins/jqplot.highlighter.js', to: publicPath + '/js/vendor/jqplot/plugins/jqplot.highlighter.js' },
{ from: rootPath + '/node_modules/chart.js/dist/chart.umd.js', to: publicPath + '/js/vendor/chart.umd.js' },
{ from: rootPath + '/node_modules/chart.js/dist/chart.umd.js.map', to: publicPath + '/js/vendor/chart.umd.js.map' },
],
}),
new WebpackConcatPlugin({