Redesign the server status advisor page

Uses an accordion instead of a table to show the issues.

Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
Maurício Meneghini Fauth 2020-03-13 02:56:16 -03:00
parent 1a3416da8d
commit e656f341ef
7 changed files with 103 additions and 124 deletions

View File

@ -322,16 +322,6 @@ $javascriptMessages = [
'strAnalyzeQuery' => __('Analyse query'),
/* Server status advisor */
'strPerformanceIssues' => __('Possible performance issues'),
'strIssuse' => __('Issue'),
'strRecommendation' => __('Recommendation'),
'strRuleDetails' => __('Rule details'),
'strJustification' => __('Justification'),
'strFormula' => __('Used variable / formula'),
'strTest' => __('Test'),
/* For query editor */
'strFormatting' => __('Formatting SQL…'),
'strNoParam' => __('No parameters found!'),

View File

@ -1,82 +0,0 @@
/**
* Server Status Advisor
*
* @package PhpMyAdmin
*/
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('server/status/advisor.js', function () {
$('#statustabs_advisor').html('');
$('#advisorDialog').remove();
});
AJAX.registerOnload('server/status/advisor.js', function () {
// if no advisor is loaded
if ($('#advisorData').length === 0) {
return;
}
/** ** Server config advisor ****/
var $dialog = $('<div></div>').attr('id', 'advisorDialog');
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>' + Messages.strPerformanceIssues + '</b></p>');
$cnt.append('<table class="data" id="rulesFired" border="0"><thead><tr>' +
'<th>' + Messages.strIssuse + '</th><th>' + Messages.strRecommendation +
'</th></tr></thead><tbody></tbody></table>');
$tbody = $cnt.find('table#rulesFired');
var rcStripped;
$.each(data.run.fired, function (key, value) {
// recommendation may contain links, don't show those in overview table (clicking on them redirects the user)
rcStripped = $.trim($('<div>').html(value.recommendation).text());
$tbody.append($tr = $('<tr class="linkElem noclick"><td>' +
value.issue + '</td><td>' + rcStripped + ' </td></tr>'));
even = !even;
$tr.data('rule', value);
$tr.on('click', function () {
var rule = $(this).data('rule');
$dialog
.dialog({ title: Messages.strRuleDetails })
.html(
'<p><b>' + Messages.strIssuse + ':</b><br>' + rule.issue + '</p>' +
'<p><b>' + Messages.strRecommendation + ':</b><br>' + rule.recommendation + '</p>' +
'<p><b>' + Messages.strJustification + ':</b><br>' + rule.justification + '</p>' +
'<p><b>' + Messages.strFormula + ':</b><br>' + rule.formula + '</p>' +
'<p><b>' + Messages.strTest + ':</b><br>' + rule.test + '</p>'
);
var dlgBtns = {};
dlgBtns[Messages.strClose] = function () {
$(this).dialog('close');
};
$dialog.dialog({ width: 600, buttons: dlgBtns });
});
});
}
});

View File

@ -1,7 +1,5 @@
<?php
/**
* Holds the PhpMyAdmin\Controllers\Server\Status\AdvisorController
*/
declare(strict_types=1);
namespace PhpMyAdmin\Controllers\Server\Status;
@ -11,7 +9,6 @@ use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Response;
use PhpMyAdmin\Server\Status\Data;
use PhpMyAdmin\Template;
use function json_encode;
/**
* Displays the advisor feature
@ -36,12 +33,9 @@ class AdvisorController extends AbstractController
public function index(): void
{
$scripts = $this->response->getHeader()->getScripts();
$scripts->addFile('server/status/advisor.js');
$data = '';
$data = [];
if ($this->data->dataLoaded) {
$data = json_encode($this->advisor->run());
$data = $this->advisor->run();
}
$this->response->addHTML($this->template->render('server/status/advisor/index', [

View File

@ -5,9 +5,10 @@
<h2>{% trans 'Advisor system' %}</h2>
{% if data is not empty %}
<button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#advisorInstructionsModal">
{% if data is empty %}
{{ 'Not enough privilege to view the advisor.'|trans|error }}
{% else %}
<button type="button" class="btn btn-secondary mb-4" data-toggle="modal" data-target="#advisorInstructionsModal">
{{ get_icon('b_help', 'Instructions'|trans) }}
</button>
@ -49,11 +50,63 @@
</div>
</div>
<div id="statustabs_advisor" class="row"></div>
{% if data.parse.errors|length > 0 %}
<div class="alert alert-danger mt-2 mb-2" role="alert">
<h4 class="alert-heading">{% trans 'Rules file not well formed, following errors were found:' %}</h4>
<ul>
{% for error in data.parse.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div id="advisorData" class="hide">{{ data }}</div>
{% else %}
{{ 'Not enough privilege to view the advisor.'|trans|error }}
{% if data.run.errors|length > 0 %}
<div class="alert alert-danger mt-2 mb-2" role="alert">
<h4 class="alert-heading">{% trans 'Errors occurred while executing rule expressions:' %}</h4>
<ul>
{% for error in data.run.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if data.run.fired|length > 0 %}
<h4>{% trans 'Possible performance issues' %}</h4>
<div class="accordion mb-4" id="rulesAccordion">
{% for rule in data.run.fired %}
<div class="card">
<div class="card-header" id="heading{{ loop.index }}">
<button class="btn btn-link{{ not loop.first ? ' collapsed' }}" type="button" data-toggle="collapse" data-target="#collapse{{ loop.index }}" aria-expanded="{{ loop.first ? 'true' : 'false' }}" aria-controls="collapse{{ loop.index }}">
{{ rule.issue }}
</button>
</div>
<div id="collapse{{ loop.index }}" class="collapse{{ loop.first ? ' show' }}" aria-labelledby="heading{{ loop.index }}" data-parent="#rulesAccordion">
<div class="card-body">
<dl>
<dt>{% trans 'Issue:' %}</dt>
<dd>{{ rule.issue }}</dd>
<dt>{% trans 'Recommendation:' %}</dt>
<dd>{{ rule.recommendation|raw }}</dd>
<dt>{% trans 'Justification:' %}</dt>
<dd>{{ rule.justification }}</dd>
<dt>{% trans 'Used variable / formula:' %}</dt>
<dd>{{ rule.formula }}</dd>
<dt>{% trans 'Test:' %}</dt>
<dd>{{ rule.test }}</dd>
</dl>
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% endblock %}

View File

@ -120,21 +120,5 @@ class AdvisorControllerTest extends TestCase
'Do note however that this system provides recommendations',
$html
);
$this->assertStringContainsString(
'<div id="advisorData" class="hide">',
$html
);
$this->assertStringContainsString(
htmlspecialchars(json_encode('parse')),
$html
);
$this->assertStringContainsString(
htmlspecialchars(json_encode('errors')),
$html
);
$this->assertStringContainsString(
htmlspecialchars(json_encode('run')),
$html
);
}
}

View File

@ -7,3 +7,22 @@
.card-body ul {
padding-#{$left}: 0;
}
.accordion {
> .card {
border-radius: 0;
> .card-header {
background-color: $button-background;
.btn {
color: $button-color;
&:hover,
&:active {
text-decoration: none;
}
}
}
}
}

View File

@ -19,3 +19,24 @@
-webkit-box-shadow: 1px 1px 15px #999 inset;
box-shadow: 1px 1px 15px #999 inset;
}
.accordion {
> .card {
> .card-header {
background-color: inherit;
box-shadow: none;
.btn {
color: #235a81;
&:active {
box-shadow: none;
}
}
}
.card-body {
background-color: #fff;
}
}
}