mvc: implement reusable grid template using form definitions. for https://github.com/opnsense/core/issues/8187

Although this might not be the final version, it adds the relevant metadata to the form definitions and offers a very simple template which can be used as a partial().

Example input field:

    <field>
        <id>sysctl.tunable</id>
        <label>Tunable</label>
        <type>text</type>
        <grid_view>
            <sequence>1</sequence>
        </grid_view>
    </field>

grid_view entries contain a sequence which may overwrite the default order and can overwrite any data-* attribute available, e.g. <sortable>false</sortable> would remove the sortable option from the field.
This commit is contained in:
Ad Schellevis 2025-01-07 17:08:39 +01:00
parent 970977f5bf
commit a7a99fcdfe
2 changed files with 67 additions and 26 deletions

View File

@ -234,7 +234,7 @@ class ControllerBase extends ControllerRoot
* Extract grid fields from form definition
* @return array
*/
public function getFormGrid($formname)
public function getFormGrid($formname, $grid_id=null, $edit_alert_id=null)
{
/* collect all fields, sort by sequence */
$all_data = [];
@ -242,42 +242,54 @@ class ControllerBase extends ControllerRoot
foreach ($this->getFormXML($formname) as $rootkey => $rootnode) {
if ($rootkey == 'field') {
$record = [
'sequence' => '9999999',
'visible' => 'false',
'ignore' => 'false',
'sortable' => 'false',
'width' => '',
'column-id' => '',
'label' => '',
'id' => '',
'type' => 'string'
'visible' => 'true',
'sortable' => 'true',
'identifier' => 'false',
'type' => 'string' /* XXX: convert to type + formatter using source type? */
];
foreach ($rootnode as $key => $item) {
if (isset($record[$key])) {
switch ($key) {
case 'label':
$record[$key] = gettext((string)$item);
break;
case 'type':
/* XXX: convert to type + formatter */
$record[$key] = 'string';
default:
$record[$key] = (string)$item;
break;
}
switch ($key) {
case 'label':
$record['label'] = gettext((string)$item);
break;
case 'id':
$record['column-id'] = end(explode('.', (string)$item));
break;
}
}
/* iterate field->grid_view items */
$this_sequence = '9999999';
foreach ($rootnode->grid_view->children() as $key => $item) {
$record[$key] = (string)$item;
}
if (strtolower($record['ignore']) == 'false') {
$record['fieldname'] = end(explode('.', $record['id']));
$all_data[sprintf("%010d.%03d", $record['sequence'], $idx++)] = $record;
if ($key == 'ignore' && $item != 'false') {
/* ignore field as requested */
continue 2;
} elseif ($key == 'sequence') {
$this_sequence = (string)$item;
} else {
$record[$key] = (string)$item;
}
}
$all_data[sprintf("%010d.%03d", $this_sequence, $idx++)] = $record;
}
}
/* prepend identifier */
$all_data[sprintf("%010d.%03d", 0, 0)] = [
'column-id' => 'uuid',
'label' => gettext('ID'),
'type' => 'string',
'identifier' => 'true',
'visible' => 'false'
];
ksort($all_data);
return array_values($all_data);
$basename = $grid_id ?? $formname;
return [
'table_id' => $basename,
'edit_dialog_id' => 'dialog_' . $basename,
'edit_alert_id' => $edit_alert_id == null ? 'change_message_' . $basename : $edit_alert_id,
'fields' => array_values($all_data)
];
}
/**

View File

@ -0,0 +1,29 @@
{# requires getFormGrid() input to render #}
<table id="{{ table_id }}" class="table table-condensed table-hover table-striped" data-editDialog="{{ edit_dialog_id }}" data-editAlert="{{ edit_alert_id }}">
<thead>
<tr>
{% for field in fields %}
<th {% for k,v in field %} data-{{k}}="{{v}}"{% endfor %} >{{field['label']}}</th>
{% endfor %}
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">
{{ lang._('Commands') }}
</th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td>
</td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-primary">
<span class="fa fa-plus"></span>
</button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default">
<span class="fa fa-trash-o"></span>
</button>
</td>
</tr>
</tfoot>
</table>