Synchronize routines UX

Signed-off-by: Kamil Tekiela <tekiela246@gmail.com>
This commit is contained in:
Kamil Tekiela 2025-04-18 13:13:25 +01:00
parent c3a6d422f1
commit 0e5b3968b2
8 changed files with 68 additions and 141 deletions

View File

@ -5670,7 +5670,7 @@ parameters:
-
message: '#^Cannot access offset int\<0, max\> on mixed\.$#'
identifier: offsetAccess.nonOffsetAccessible
count: 16
count: 15
path: src/Database/Routines.php
-
@ -5703,12 +5703,6 @@ parameters:
count: 3
path: src/Database/Routines.php
-
message: '#^Cannot assign new offset to list\<string\>\|string\|null\.$#'
identifier: offsetAssign.dimType
count: 1
path: src/Database/Routines.php
-
message: '#^Cannot assign new offset to list\<string\|null\>\|string\.$#'
identifier: offsetAssign.dimType
@ -5808,7 +5802,7 @@ parameters:
-
message: '#^Parameter \#1 \$string of function mb_strtolower expects string, mixed given\.$#'
identifier: argument.type
count: 7
count: 5
path: src/Database/Routines.php
-

View File

@ -3674,8 +3674,6 @@
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$value]]></code>
<code><![CDATA[$value]]></code>
<code><![CDATA[$value]]></code>
@ -3708,8 +3706,6 @@
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
<code><![CDATA[$routine['item_param_type'][$i]]]></code>
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$routine['item_param_name'][$i]]]></code>

View File

@ -6,57 +6,62 @@
<div class="card">
<div class="card-header">{{ ajax ? t('Routine parameters') : routine['item_name'] }}</div>
<div class="card-body">
<table class="table w-auto rte_table{{ not ajax ? ' caption-top' }}">
{% if not ajax %}
<caption>{{ t('Routine parameters') }}</caption>
{% endif %}
<tr>
<th>{{ t('Name') }}</th>
<th>{{ t('Type') }}</th>
{% if show_function_fields %}
<th>{{ t('Function') }}</th>
{% if params is not empty %}
<div class="card-body">
<table class="table w-auto rte_table{{ not ajax ? ' caption-top' }}">
{% if not ajax %}
<caption>{{ t('Routine parameters') }}</caption>
{% endif %}
<th>{{ t('Value') }}</th>
</tr>
{% for i in 0..routine['item_num_params'] - 1 %}
<tr>
<td>{{ routine['item_param_name'][loop.index0] }}</td>
<td>{{ routine['item_param_type'][loop.index0] }}</td>
<th>{{ t('Name') }}</th>
<th>{{ t('Type') }}</th>
{% if show_function_fields %}
<td>
{% if (params[loop.index0]['generator'] ?? null) is not null %}
<select name="funcs[{{ routine['item_param_name'][loop.index0] }}]">
{{ params[loop.index0]['generator']|raw }}</select>
<th>{{ t('Function') }}</th>
{% endif %}
<th>{{ t('Value') }}</th>
</tr>
{% for i in 0..routine['item_num_params'] - 1 %}
<tr>
<td>{{ routine['item_param_name'][loop.index0] }}</td>
<td>{{ routine['item_param_type'][loop.index0] }}</td>
{% if show_function_fields %}
<td>
{% if (params[loop.index0]['generator'] ?? null) is not null %}
<select name="funcs[{{ routine['item_param_name'][loop.index0] }}]">
{{ params[loop.index0]['generator']|raw }}</select>
{% else %}
--
{% endif %}
</td>
{% endif %}
<td class="nowrap">
{% if routine['item_param_type'][loop.index0] in ['ENUM', 'SET'] %}
{% for value in routine['item_param_length_arr'][loop.index0] %}
<input name="params[{{ routine['item_param_name'][loop.parent.loop.index0] }}][]" value="{{ params[loop.parent.loop.index0]['htmlentities'][loop.index0] }}" type="{{ params[loop.parent.loop.index0]['input_type'] }}">
{{ params[loop.parent.loop.index0]['htmlentities'][loop.index0] }}
<br>
{% endfor %}
{% else %}
--
<input class="{{ params[loop.index0]['class'] ?? '' }}" type="text" name="params[{{ routine['item_param_name'][loop.index0] }}]">
{% endif %}
</td>
{% endif %}
<td class="nowrap">
{% if routine['item_param_type'][loop.index0] in ['ENUM', 'SET'] %}
{% for value in routine['item_param_length_arr'][loop.index0] %}
<input name="params[{{ routine['item_param_name'][loop.parent.loop.index0] }}][]" value="{{ params[loop.parent.loop.index0]['htmlentities'][loop.index0] }}" type="{{ params[loop.parent.loop.index0]['input_type'] }}">
{{ params[loop.parent.loop.index0]['htmlentities'][loop.index0] }}
<br>
{% endfor %}
{% elseif routine['item_param_type'][loop.index0]|lower in params['no_support_types'] %}
{% else %}
<input class="{{ params[loop.index0]['class'] ?? '' }}" type="text" name="params[{{ routine['item_param_name'][loop.index0] }}]">
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% if not ajax %}
<div class="card-footer">
<input class="btn btn-primary" type="submit" name="execute_routine" value="{{ t('Go') }}">
</tr>
{% endfor %}
</table>
</div>
{% else %}
<input type="hidden" name="execute_routine" value="true">
<input type="hidden" name="ajax_request" value="true">
<div class="card-body">
<p>{{ t('This routine does not require any parameters.') }}</p>
</div>
{% endif %}
</div>
{% if not ajax %}
<div class="card-footer">
<input class="btn btn-primary" type="submit" name="execute_routine" value="{{ t('Go') }}">
</div>
{% else %}
<input type="hidden" name="execute_routine" value="true">
<input type="hidden" name="ajax_request" value="true">
{% endif %}
</form>

View File

@ -24,26 +24,16 @@
{% endif %}
</td>
<td>
{% if has_execute_privilege and execute_action is not empty %}
{% if execute_action == 'execute_routine' %}
<a class="ajax exec_anchor" href="{{ url('/database/routines', {'db': db, 'table': table}) }}" data-post="{{ get_common({
'execute_routine': true,
'item_name': routine.name,
'item_type': routine.type
}, '') }}">
{{ get_icon('b_nextpage', t('Execute')) }}
</a>
{% else %}
<a class="ajax exec_anchor" href="{{ url('/database/routines', {
'db': db,
'table': table,
'execute_dialog': true,
'item_name': routine.name,
'item_type': routine.type
}) }}">
{{ get_icon('b_nextpage', t('Execute')) }}
</a>
{% endif %}
{% if has_execute_privilege %}
<a class="ajax exec_anchor" href="{{ url('/database/routines', {
'db': db,
'table': table,
'execute_dialog': true,
'item_name': routine.name,
'item_type': routine.type
}) }}">
{{ get_icon('b_nextpage', t('Execute')) }}
</a>
{% else %}
{{ get_icon('bd_nextpage', t('Execute')) }}
{% endif %}

View File

@ -1084,10 +1084,7 @@ class Routines
$routine['item_param_name'][$i] = htmlentities($routine['item_param_name'][$i], ENT_QUOTES);
}
$noSupportTypes = Util::unsupportedDatatypes();
$params = [];
$params['no_support_types'] = $noSupportTypes;
for ($i = 0; $i < $routine['item_num_params']; $i++) {
if ($routine['item_type'] === 'PROCEDURE' && $routine['item_param_dir'][$i] === 'OUT') {
@ -1098,11 +1095,6 @@ class Routines
if (
stripos($routine['item_param_type'][$i], 'enum') !== false
|| stripos($routine['item_param_type'][$i], 'set') !== false
|| in_array(
mb_strtolower($routine['item_param_type'][$i]),
$noSupportTypes,
true,
)
) {
$params[$i]['generator'] = null;
} else {
@ -1137,8 +1129,6 @@ class Routines
$value = htmlentities(Util::unQuote($value), ENT_QUOTES);
$params[$i]['htmlentities'][] = $value;
}
} elseif (in_array(mb_strtolower($routine['item_param_type'][$i]), $noSupportTypes, true)) {
$params[$i]['input_type'] = null;
} else {
$params[$i]['input_type'] = 'text';
}
@ -1186,33 +1176,6 @@ class Routines
// we will show a dialog to get values for these parameters,
// otherwise we can execute it directly.
if ($routine->type === 'FUNCTION') {
$definition = self::getFunctionDefinition($this->dbi, Current::$database, $routine->name);
} else {
$definition = self::getProcedureDefinition($this->dbi, Current::$database, $routine->name);
}
$executeAction = '';
if ($definition !== null && $hasExecutePrivilege) {
$parser = new Parser('DELIMITER $$' . "\n" . $definition);
/** @var CreateStatement $stmt */
$stmt = $parser->statements[0];
$executeAction = 'execute_routine';
if ($stmt->parameters !== null) {
foreach ($stmt->parameters as $param) {
if ($routine->type === 'PROCEDURE' && $param->inOut === 'OUT') {
continue;
}
$executeAction = 'execute_dialog';
break;
}
}
}
return [
'db' => Current::$database,
'table' => Current::$table,
@ -1222,7 +1185,6 @@ class Routines
'has_edit_privilege' => $hasEditPrivilege,
'has_export_privilege' => $hasExportPrivilege,
'has_execute_privilege' => $hasExecutePrivilege,
'execute_action' => $executeAction,
];
}

View File

@ -1171,17 +1171,6 @@ class Util
return $retval;
}
/**
* Returns a list of datatypes that are not (yet) handled by PMA.
* Used by: /table/change and libraries/Routines.php
*
* @return string[] list of datatypes
*/
public static function unsupportedDatatypes(): array
{
return [];
}
/**
* This function is to check whether database support UUID
*/

View File

@ -186,10 +186,10 @@ final class RoutinesControllerTest extends AbstractTestCase
</a>
</td>
<td>
<a class="ajax exec_anchor" href="index.php?route=/database/routines&db=test_db&table=&execute_dialog=1&item_name=test_func&item_type=FUNCTION&server=2&lang=en">
<span class="text-nowrap"><img src="themes/dot.gif" title="Execute" alt="Execute" class="icon ic_b_nextpage">&nbsp;Execute</span>
</a>
</td>
<a class="ajax exec_anchor" href="index.php?route=/database/routines&db=test_db&table=&execute_dialog=1&item_name=test_func&item_type=FUNCTION&server=2&lang=en">
<span class="text-nowrap"><img src="themes/dot.gif" title="Execute" alt="Execute" class="icon ic_b_nextpage">&nbsp;Execute</span>
</a>
</td>
<td>
<a class="ajax export_anchor" href="index.php?route=/database/routines&db=test_db&table=&export_item=1&item_name=test_func&item_type=FUNCTION&server=2&lang=en">
<span class="text-nowrap"><img src="themes/dot.gif" title="Export" alt="Export" class="icon ic_b_export">&nbsp;Export</span>
@ -215,10 +215,10 @@ final class RoutinesControllerTest extends AbstractTestCase
</a>
</td>
<td>
<a class="ajax exec_anchor" href="index.php?route=/database/routines&db=test_db&table=&execute_dialog=1&item_name=test_proc&item_type=PROCEDURE&server=2&lang=en">
<span class="text-nowrap"><img src="themes/dot.gif" title="Execute" alt="Execute" class="icon ic_b_nextpage">&nbsp;Execute</span>
</a>
</td>
<a class="ajax exec_anchor" href="index.php?route=/database/routines&db=test_db&table=&execute_dialog=1&item_name=test_proc&item_type=PROCEDURE&server=2&lang=en">
<span class="text-nowrap"><img src="themes/dot.gif" title="Execute" alt="Execute" class="icon ic_b_nextpage">&nbsp;Execute</span>
</a>
</td>
<td>
<a class="ajax export_anchor" href="index.php?route=/database/routines&db=test_db&table=&export_item=1&item_name=test_proc&item_type=PROCEDURE&server=2&lang=en">
<span class="text-nowrap"><img src="themes/dot.gif" title="Export" alt="Export" class="icon ic_b_export">&nbsp;Export</span>

View File

@ -1002,15 +1002,6 @@ class UtilTest extends AbstractTestCase
return [['test', 'test'], ["\r\ntest", "\n\r\ntest"], ["\ntest", "\ntest"], ["\n\r\ntest", "\n\r\ntest"]];
}
public function testUnsupportedDatatypes(): void
{
$noSupportTypes = [];
self::assertSame(
$noSupportTypes,
Util::unsupportedDatatypes(),
);
}
public function testGetPageFromPosition(): void
{
self::assertSame(Util::getPageFromPosition(0, 1), 1);