tabulator: Improve responsiveness via minWidth() for grid and flex css for action row (#9240)

* firewall/automation: Small viewport layout for action bar
* bootgrid: Add minWidth and maxWidth and wire minWidth into firewall/automation/filter page for better responsiveness
* Make header even more responsive by allowing selectpickers to shrink and stretch in a flexbox, but only to a certain limit
* Generalize the action bar flex css so it improves all pages
* Add global default for minWidth since its an issue in all grids.
* Give width precedence over minWidth, fix some minWidth in firewall page
* Give search bar some left padding so when it collides with left elements there is some spacing
* Fix flex behavior for elements inside the button group, fix log.volt
* dnsmasq leases.volt fix flex behavior of selectpickers
* kea leases4.volt leases6.volt fix flex behavior of selectpickers
* dnsmasq settings.volt fix flex behavior of selectpickers
* alias alias.volt fix flex behavior of selectpickers
* virtual IP vip.volt fix flex behavior of selectpickers
* filter.volt fix flex behavior of selectpickers
* wireguard general.volt diagnostics.volt fix flex behavior of selectpickers
* Simplify by creating a new layout css file which can store layout focused bootgrid changes without regenerating themes
* Give the search bar some love too, allow it to be bigger and shrink
This commit is contained in:
Monviech 2025-10-15 11:31:06 +02:00 committed by GitHub
parent cddb65dc31
commit 7f6f768c30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 164 additions and 46 deletions

1
plist
View file

@ -2084,6 +2084,7 @@
/usr/local/opnsense/www/css/jqtree.css
/usr/local/opnsense/www/css/jquery.bootgrid.css
/usr/local/opnsense/www/css/nv.d3.css
/usr/local/opnsense/www/css/opnsense-bootgrid-layout.css
/usr/local/opnsense/www/css/opnsense-bootgrid.css
/usr/local/opnsense/www/css/tabulator.min.css
/usr/local/opnsense/www/css/tokenize2.css

View file

@ -98,6 +98,7 @@ class ControllerBase extends ControllerRoot
'/css/bootstrap-dialog.css',
'/css/tabulator.min.css',
'/css/opnsense-bootgrid.css',
'/css/opnsense-bootgrid-layout.css',
// Font awesome
'/ui/assets/fontawesome/css/all.min.css',
'/ui/assets/fontawesome/css/v4-shims.min.css',

View file

@ -60,6 +60,8 @@
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
@ -69,6 +71,7 @@
<help>You may enter a description here for your reference (not parsed).</help>
<grid_view>
<sequence>110</sequence>
<min-width>100</min-width>
</grid_view>
</field>
<field>
@ -129,6 +132,8 @@
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
@ -186,6 +191,7 @@
<grid_view>
<formatter>alias</formatter>
<sequence>50</sequence>
<min-width>100</min-width>
</grid_view>
</field>
<field>
@ -195,8 +201,10 @@
<help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
<style>port_selector</style>
<grid_view>
<label>Port</label>
<sequence>60</sequence>
<formatter>alias</formatter>
<min-width>60</min-width>
</grid_view>
</field>
<field>
@ -216,6 +224,7 @@
<grid_view>
<formatter>alias</formatter>
<sequence>70</sequence>
<min-width>100</min-width>
</grid_view>
</field>
<field>
@ -225,8 +234,10 @@
<help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
<style>port_selector</style>
<grid_view>
<label>Port</label>
<sequence>80</sequence>
<formatter>alias</formatter>
<min-width>60</min-width>
</grid_view>
</field>
<field>
@ -575,6 +586,7 @@
<grid_view>
<formatter>statistics</formatter>
<sequence>115</sequence>
<min-width>200</min-width>
</grid_view>
</field>
<field>

View file

@ -76,7 +76,7 @@
}
});
$("#zone-selection-wrapper").detach().prependTo('#grid-clients-header > .row > .actionBar > .actions');
$("#zone-selection-wrapper").detach().insertBefore('#grid-clients-header .search');
});
</script>

View file

@ -138,14 +138,10 @@
});
</script>
<style>
#grid_services-header .actionBar {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
#grid_services-header .actionBar > #sync_container {
margin-right: auto;
#grid_services-header .actionBar #act_restart_all {
flex: 0 0 auto !important;
width: auto !important;
align-self: center !important;
}
</style>
<section class="page-content-main">

View file

@ -129,8 +129,8 @@
}
});
$("#inactive-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar');
$("#interface-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
$("#inactive-selection-wrapper").detach().insertBefore('#grid-leases-header .search');
$("#interface-selection-wrapper").detach().insertAfter('#grid-leases-header .search');
updateServiceControlUI('dhcpv4');
});

View file

@ -136,8 +136,8 @@
search:'/api/dhcpv6/leases/search_prefix/'
});
$("#inactive-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar');
$("#interface-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
$("#inactive-selection-wrapper").detach().insertBefore('#grid-leases-header .search');
$("#interface-selection-wrapper").detach().insertAfter('#grid-leases-header .search');
if (window.location.hash != "") {
$('a[href="' + window.location.hash + '"]').click();

View file

@ -152,12 +152,9 @@
updateServiceControlUI('{{service}}');
// move filter into action header
$("#filter_container").detach().prependTo('#grid-log-header > .row > .actionBar > .actions');
$(".filter_act").tooltip();
$("#export-wrapper").detach().appendTo('#grid-log-header > .row > .actionBar > .btn-group');
$("#exportbtn").tooltip();
// Move filters directly into the actionBar instead of nested groups for better flex behavior
$("#filter_container").detach().insertAfter('#grid-log-header .search');
$("#export-wrapper").detach().appendTo('#grid-log-header .actionBar');
function switch_mode(value) {
let select = $("#severity_filter");

View file

@ -61,7 +61,7 @@
$('#grid-vips').bootgrid('reload');
});
$("#mode_filter_container").detach().prependTo('#grid-vips-header > .row > .actionBar > .actions');
$("#mode_filter_container").detach().insertAfter('#grid-vips-header .search');
$(".carp_action").each(function(){
$(this).SimpleActionButton({onAction: function(data, status){

View file

@ -128,8 +128,8 @@
}
});
$("#interface-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
$("#protocol-selection-wrapper").detach().insertBefore("#interface-selection-wrapper");
$("#interface-selection-wrapper").detach().insertAfter('#grid-leases-header .search');
$("#protocol-selection-wrapper").detach().insertAfter("#interface-selection-wrapper");
updateServiceControlUI('dnsmasq');
});

View file

@ -126,7 +126,7 @@
let header = $("#" + grid_id + "-header");
let $actionBar = header.find('.actionBar');
if ($actionBar.length) {
$('#tag_select_container').detach().insertBefore($actionBar.find('.search'));
$('#tag_select_container').detach().insertAfter($actionBar.find('.search'));
$('#tag_select_container').show();
}
}
@ -281,16 +281,6 @@
tbody.collapsible > tr > td:first-child {
padding-left: 30px;
}
#tag_select_clear {
border-right: none;
}
#tag_select_container {
margin-right: 20px;
}
#tag_select_container .bootstrap-select > .dropdown-toggle {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
</style>
<div id="tag_select_container" class="btn-group" style="display: none;">

View file

@ -616,7 +616,7 @@
});
// move filter into action header
$("#type_filter_container").detach().prependTo('#grid-aliases-header > .row > .actionBar > .actions');
$("#type_filter_container").detach().insertAfter('#grid-aliases-header .search');
// alias size in service container
$("#aliases_stat").detach().prependTo('#service_status_container');
$("#service_status_container").css('width', '250px');

View file

@ -58,7 +58,7 @@
$("#reconfigureAct").SimpleActionButton();
// move filter into action header
$("#type_filter_container").detach().prependTo('#grid-rules-header > .row > .actionBar > .actions');
$("#type_filter_container").detach().insertAfter('#grid-rules-header .search');
$("#category_filter").change(function(){
$('#grid-rules').bootgrid('reload');
});

View file

@ -736,7 +736,7 @@
$("#interface_select_container").show();
// move selectpickers into action bar
$("#interface_select_container").detach().insertBefore('#{{formGridFilterRule["table_id"]}}-header > .row > .actionBar > .search');
$("#interface_select_container").detach().insertBefore('#{{formGridFilterRule["table_id"]}}-header .search');
$('#interface_select').on('changed.bs.select', function () {
// Skip grid reload during reconfigureAct and initial page load
if (!interfaceInitialized || reconfigureActInProgress) return;
@ -978,6 +978,41 @@
opacity: 0.4;
}
/* Action bar specific layout */
#interface_select_container,
#type_filter_container {
float: none !important;
flex: 1 1 150px;
min-width: 0;
max-width: 400px;
}
#interface_select_container .bootstrap-select,
#type_filter_container .bootstrap-select {
flex: 1 1 auto;
min-width: 0;
}
.bootgrid-header .actionBar .btn-group {
align-items: flex-start;
}
@media (max-width: 1024px) {
#interface_select_container,
#type_filter_container {
flex: 1 1 100%;
max-width: 100%;
margin: 0;
}
#dialogFilterRule-header #inspect_toggle_container,
#dialogFilterRule-header #tree_toggle_container,
#dialogFilterRule-header #tree_expand_container {
flex: 1 1 0;
margin: 0;
}
}
.stats-cell {
display: flex;
flex-direction: column;
@ -993,11 +1028,11 @@
<!-- filters -->
<div class="hidden">
<div id="type_filter_container" class="btn-group">
<select id="category_filter" data-title="{{ lang._('Categories') }}" class="selectpicker" data-live-search="true" data-size="30" multiple data-width="300px" data-container="body">
<select id="category_filter" data-title="{{ lang._('Categories') }}" class="selectpicker" data-live-search="true" data-size="30" multiple data-container="body">
</select>
</div>
<div id="interface_select_container" class="btn-group">
<select id="interface_select" class="selectpicker" data-live-search="true" data-size="30" data-width="300px" data-container="body">
<select id="interface_select" class="selectpicker" data-live-search="true" data-size="30" data-container="body">
</select>
</div>
<div id="inspect_toggle_container" class="btn-group">

View file

@ -55,7 +55,7 @@
}
}
});
$("#pool_filter_container").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
$("#pool_filter_container").detach().insertAfter('#grid-leases-header .search');
$("#pool_filter").change(function(){
$('#grid-leases').bootgrid('reload');
});

View file

@ -77,7 +77,8 @@
)
);
$("#mode_filter_container").detach().prependTo('#{{formGridVip["table_id"]}}-header > .row > .actionBar > .actions');
$("#mode_filter_container").detach().insertAfter('#{{formGridVip["table_id"]}}-header .search');
/**
* select an unassigned carp vhid
*/

View file

@ -77,7 +77,7 @@
}
});
$("#interface-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
$("#interface-selection-wrapper").detach().insertAfter('#grid-leases-header .search');
updateServiceControlUI('kea');
});

View file

@ -77,7 +77,7 @@
}
});
$("#interface-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
$("#interface-selection-wrapper").detach().insertAfter('#grid-leases-header .search');
updateServiceControlUI('kea');
});

View file

@ -101,7 +101,7 @@
$('#grid-sessions').bootgrid('reload');
});
$("#type_filter_container").detach().prependTo('#grid-sessions-header > .row > .actionBar > .actions');
$("#type_filter_container").detach().insertAfter('#grid-sessions-header .search');
});
</script>

View file

@ -212,7 +212,7 @@
}
});
$("#filter_container").detach().prependTo('#{{formGridCert['table_id']}}-header > .row > .actionBar > .actions');
$("#filter_container").detach().insertAfter('#{{formGridCert['table_id']}}-header .search');
$(".cert_filter").change(function(){
$("#{{formGridCert['table_id']}}").bootgrid('reload');
});

View file

@ -89,7 +89,7 @@
$('[data-toggle="tooltip"]').tooltip();
});
$("#type_filter_container").detach().prependTo('#grid-sessions-header > .row > .actionBar > .actions');
$("#type_filter_container").detach().insertAfter('#grid-sessions-header .search');
});
</script>

View file

@ -108,7 +108,7 @@
/**
* Quick instance filter on top
*/
$("#filter_container").detach().prependTo('#{{formGridWireguardClient["table_id"]}}-header > .row > .actionBar > .actions');
$("#filter_container").detach().insertAfter('#{{formGridWireguardClient["table_id"]}}-header .search');
$("#server_filter").change(function(){
$('#{{formGridWireguardClient['table_id']}}').bootgrid('reload');
});

View file

@ -0,0 +1,76 @@
/*
* For universal layout adjustments that do not need theme compilation.
* No color or other variables allowed, only static layout changes.
* Avoids having to recompile/fix themes.
* /
/* Action Bar responsive style */
.bootgrid-header .actionBar {
display: flex;
flex-wrap: nowrap;
gap: 8px;
min-width: 0;
}
.bootgrid-header .actionBar > .search {
margin-left: auto;
padding-left: 20px;
flex: 0 1 400px;
min-width: 100px;
}
.bootgrid-header .actionBar > .btn-group,
.bootgrid-header .actionBar > .actions .btn-group {
display: flex;
flex-wrap: wrap;
}
@media (max-width: 1024px) {
.bootgrid-header .actionBar {
flex-wrap: wrap;
justify-content: flex-start;
align-items: stretch;
max-width: 100%;
}
.bootgrid-header .actionBar > * {
flex: 1 1 100%;
margin: 0;
float: none;
display: flex;
}
.bootgrid-header .actionBar .bootstrap-select,
.bootgrid-header .actionBar .bootstrap-select > .dropdown-toggle,
.bootgrid-header .actionBar .btn,
.bootgrid-header .actionBar .search .input-group,
.bootgrid-header .actionBar .search .form-control {
flex: 1;
width: 100%;
max-width: 100%;
}
.bootgrid-header .actionBar .search {
flex: 1 1 100%;
margin: 0;
padding-left: 0;
}
.bootgrid-header .actionBar .search .input-group {
margin: 0;
}
.bootgrid-header .actionBar .actions,
.bootgrid-header .actionBar .actions-group {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
gap: 8px;
flex: 1 1 100%;
}
.bootgrid-header .actionBar .actions > *,
.bootgrid-header .actionBar .actions-group > * {
flex: 1;
}
}

View file

@ -486,6 +486,8 @@ class UIBootgrid {
visible: data.visible ?? true,
sequence: data.sequence ?? null,
width: val.width,
minWidth: data.minWidth || 80,
maxWidth: data.maxWidth ?? null,
editable: false,
sortable: data.sortable ?? true
}
@ -564,6 +566,13 @@ class UIBootgrid {
col['maxWidth'] = field.width;
} else if (field.width) {
col['width'] = field.width;
} else {
if (field.minWidth) {
col['minWidth'] = field.minWidth;
}
if (field.maxWidth) {
col['maxWidth'] = field.maxWidth;
}
}
result.push(col);