bootgrid: replace with Tabulator (#8555)

* bootgrid: replace with Tabulator (https://github.com/opnsense/core/issues/8530)

Initial work for a compatibility layer between the old jQuery bootgrid implementation
and the new Tabulator inclusion

* whitespace

* cleanup pagination logic

* minor cleanup and hardcode filter_rule page command column width to 150px

* hasync: bring back sync & reconfigure all button

* bring back subtle horizontal/vertical lines in the right places

* improve row hovering/selection behavior

* refine css further and do not horizontally space commands. Also ditch resize guide as it is too much logic for little gain

* dynamically wire up default commands as well for virtualDOM rendering mode

* small cleanup

* remove 'last page' button in case of remote fetch and an unknown total

* fix 'add' command

* small CSS changes and change commands default to 100px

* fix 'em' parsing

* fixup internal formatter scoping

* skip boolean type on formatter assignment

* some more noise

* prevent flashing

* small interfaces overview fix, also use small buffer for em parsing to prevent early ellipsis

* let's make use of onRendered()

* handle table height responsiveness via our own ResizeObserver implementation

* cleanup

* account for scrollbar gutter, fix user defined rules on ids page

* final touches for scrollbar offsets

* fix 'datakey' usage

* tabulator: groundwork for themes, variable height tables

* tabulator: leftover

* tabulator: minor persistence issue, use headerClick event instead

* tabulator: fix up styles and small persistence/scrollbar glitches

* some more style changes with compiled scss

* better translation handling

* missing return here
This commit is contained in:
Stephan de Wit 2025-05-06 16:42:01 +02:00 committed by GitHub
parent 7e60d3c19d
commit 953815bad6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 3318 additions and 203 deletions

9
plist
View file

@ -2056,7 +2056,9 @@
/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.css
/usr/local/opnsense/www/css/pick-a-color-1.2.3.min.css
/usr/local/opnsense/www/css/tabulator.min.css
/usr/local/opnsense/www/css/tokenize2.css
/usr/local/opnsense/www/fonts/FontAwesome.otf
/usr/local/opnsense/www/fonts/glyphicons-halflings-regular.eot
@ -2097,6 +2099,7 @@
/usr/local/opnsense/www/js/nv.d3.min.js.LICENSE.md
/usr/local/opnsense/www/js/opnsense-treeview.js
/usr/local/opnsense/www/js/opnsense.js
/usr/local/opnsense/www/js/opnsense_bootgrid.js
/usr/local/opnsense/www/js/opnsense_bootgrid_plugin.js
/usr/local/opnsense/www/js/opnsense_health.js
/usr/local/opnsense/www/js/opnsense_status.js
@ -2109,6 +2112,8 @@
/usr/local/opnsense/www/js/polyfills.js
/usr/local/opnsense/www/js/qrcode.js
/usr/local/opnsense/www/js/smoothie.js
/usr/local/opnsense/www/js/tabulator.min.js
/usr/local/opnsense/www/js/tabulator.min.js.map
/usr/local/opnsense/www/js/theme.js
/usr/local/opnsense/www/js/tinycolor-1.4.1.min.js
/usr/local/opnsense/www/js/tokenize2.js
@ -2233,6 +2238,7 @@
/usr/local/opnsense/www/themes/opnsense-dark/assets/stylesheets/dashboard.scss
/usr/local/opnsense/www/themes/opnsense-dark/assets/stylesheets/dns-overview.scss
/usr/local/opnsense/www/themes/opnsense-dark/assets/stylesheets/main.scss
/usr/local/opnsense/www/themes/opnsense-dark/assets/stylesheets/opnsense-bootgrid.scss
/usr/local/opnsense/www/themes/opnsense-dark/build/css/bootstrap-dialog.css
/usr/local/opnsense/www/themes/opnsense-dark/build/css/bootstrap-select.css
/usr/local/opnsense/www/themes/opnsense-dark/build/css/dashboard.css
@ -2240,6 +2246,7 @@
/usr/local/opnsense/www/themes/opnsense-dark/build/css/jquery.bootgrid.css
/usr/local/opnsense/www/themes/opnsense-dark/build/css/main.css
/usr/local/opnsense/www/themes/opnsense-dark/build/css/nv.d3.css
/usr/local/opnsense/www/themes/opnsense-dark/build/css/opnsense-bootgrid.css
/usr/local/opnsense/www/themes/opnsense-dark/build/css/tokenize2.css
/usr/local/opnsense/www/themes/opnsense-dark/build/fonts/LICENSE.SourceSansPro.txt
/usr/local/opnsense/www/themes/opnsense-dark/build/fonts/SourceSansPro-Bold/SourceSansPro-Bold.eot
@ -2354,9 +2361,11 @@
/usr/local/opnsense/www/themes/opnsense/assets/stylesheets/config/colors.scss
/usr/local/opnsense/www/themes/opnsense/assets/stylesheets/dashboard.scss
/usr/local/opnsense/www/themes/opnsense/assets/stylesheets/main.scss
/usr/local/opnsense/www/themes/opnsense/assets/stylesheets/opnsense-bootgrid.scss
/usr/local/opnsense/www/themes/opnsense/build/css/bootstrap-dialog.css
/usr/local/opnsense/www/themes/opnsense/build/css/dashboard.css
/usr/local/opnsense/www/themes/opnsense/build/css/main.css
/usr/local/opnsense/www/themes/opnsense/build/css/opnsense-bootgrid.css
/usr/local/opnsense/www/themes/opnsense/build/fonts/LICENSE.SourceSansPro.txt
/usr/local/opnsense/www/themes/opnsense/build/fonts/SourceSansPro-Bold/SourceSansPro-Bold.eot
/usr/local/opnsense/www/themes/opnsense/build/fonts/SourceSansPro-Bold/SourceSansPro-Bold.otf

View file

@ -67,14 +67,14 @@ class ControllerBase extends ControllerRoot
// JQuery Tokenize2 (https://zellerda.github.io/Tokenize2/)
'/ui/js/tokenize2.js',
// Bootgrid (grid system from http://www.jquery-bootgrid.com/ )
'/ui/js/jquery.bootgrid.js',
'/ui/js/tabulator.min.js',
'/ui/js/opnsense_bootgrid.js',
// Bootstrap type ahead
'/ui/js/bootstrap3-typeahead.min.js',
// OPNsense standard toolkit
'/ui/js/opnsense.js',
'/ui/js/opnsense_theme.js',
'/ui/js/opnsense_ui.js',
'/ui/js/opnsense_bootgrid_plugin.js',
'/ui/js/opnsense_status.js',
// bootstrap script
'/ui/js/bootstrap.min.js',
@ -96,6 +96,8 @@ class ControllerBase extends ControllerRoot
'/css/bootstrap-select.css',
// bootstrap dialog
'/css/bootstrap-dialog.css',
'/css/tabulator.min.css',
'/css/opnsense-bootgrid.css',
// Font awesome
'/ui/assets/fontawesome/css/all.min.css',
'/ui/assets/fontawesome/css/v4-shims.min.css',

View file

@ -84,13 +84,13 @@
$(".xmlrpc_srv_status_act").each(function(){
switch($(this).data('service_action')) {
case 'start':
$(this).tooltip({title: "{{ lang._('Start') | safe}}"});
$(this).tooltip({title: "{{ lang._('Start') | safe}}", container: "body", trigger: "hover"});
break;
case 'restart':
$(this).tooltip({title: "{{ lang._('Synchronize and Restart') | safe}}"});
$(this).tooltip({title: "{{ lang._('Synchronize and Restart') | safe}}", container: "body", trigger: "hover"});
break;
case 'stop':
$(this).tooltip({title: "{{ lang._('Stop') | safe}}"});
$(this).tooltip({title: "{{ lang._('Stop') | safe}}", container: "body", trigger: "hover"});
break;
}
$(this).click(function(){
@ -110,17 +110,25 @@
$("#status_error").show();
}
$("#status_query").hide();
});
$("#act_restart_all").click(function(){
let icon = $(this).find('i');
if (icon.hasClass('spinner')) {
return;
}
icon.removeClass('fa-repeat').addClass('fa-spinner fa-pulse');
ajaxCall('/api/core/hasync_status/restart_all', {}, function(data){
icon.removeClass('fa-spinner fa-pulse').addClass('fa-repeat');
$('#grid_services').bootgrid('reload');
});
$("#grid_services-header > .row > .actionBar").prepend($(`
<div class="pull-left" style="position: absolute; top: 50%; transform:translateY(-50%);">
<span> {{ lang._('Synchronize and reconfigure all') }} </span>
<span id="act_restart_all" class="btn btn-xs btn-default" data-toggle="tooltip" title="{{ lang._('Synchronize and restart all services') }}">
<i class="fa fa-repeat fa-fw"></i>
</span>
</div>
`).click(function() {
let icon = $(this).find('i');
if (icon.hasClass('spinner')) {
return;
}
icon.removeClass('fa-repeat').addClass('fa-spinner fa-pulse');
ajaxCall('/api/core/hasync_status/restart_all', {}, function(data){
icon.removeClass('fa-spinner fa-pulse').addClass('fa-repeat');
$('#grid_services').bootgrid('reload');
});
}));
});
});
</script>
@ -177,16 +185,6 @@
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td><span style="padding-left: 30px;"> {{ lang._('Synchronize and reconfigure all') }} </span></td>
<td>
<span id="act_restart_all" class="btn btn-xs btn-default" data-toggle="tooltip" title="{{ lang._('Synchronize and restart all services') }}">
<i class="fa fa-repeat fa-fw"></i>
</span>
</td>
</tr>
</tfoot>
</table>
</div>
</div>

View file

@ -32,7 +32,6 @@
search:'/api/core/service/search',
options:{
multiSelect: false,
rowSelect: true,
selection: false,
formatters:{
commands: function (column, row) {
@ -47,20 +46,16 @@
},
status: function (column, row) {
if (row['running']) {
return '<span class="label label-opnsense label-opnsense-xs label-success pull-right" data-toggle="tooltip" title="{{ lang._('Running') }}"><i class="fa fa-play fa-fw"></i></span>';
return '<span class="label label-opnsense label-opnsense-xs label-success" data-toggle="tooltip" title="{{ lang._('Running') }}"><i class="fa fa-play fa-fw"></i></span>';
} else {
return '<span class="label label-opnsense label-opnsense-xs label-danger pull-right" data-toggle="tooltip" title="{{ lang._('Stopped') }}"><i class="fa fa-stop fa-fw"></i></span>';
return '<span class="label label-opnsense label-opnsense-xs label-danger" data-toggle="tooltip" title="{{ lang._('Stopped') }}"><i class="fa fa-stop fa-fw"></i></span>';
}
}
}
}
});
grid_service.on('loaded.rs.jquery.bootgrid', function () {
$('[data-toggle="tooltip"]').tooltip();
let ids = $("#grid-service").bootgrid("getCurrentRows");
if (ids.length > 0) {
$("#grid-service").bootgrid('select', [ids[0].name]);
}
$('[data-toggle="tooltip"]').tooltip({container: 'body', trigger: 'hover'});
$('.command-stop').click(function () {
$(this).toggleClass('disabled');
$(this).children().toggleClass('fa-stop fa-spinner fa-pulse');
@ -92,12 +87,11 @@
<thead>
<tr>
<th data-column-id="id" data-type="string" data-sortable="false" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="pad" data-type="string" data-sortable="false" data-width="1em"></th>
<th data-column-id="running" data-type="string" data-width="100" data-formatter="status" data-sortable="false"></th>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
<th data-column-id="locked" data-type="string" data-sortable="false" data-visible="false"></th>
<th data-column-id="running" data-type="string" data-width="3em" data-formatter="status" data-sortable="false"></th>
<th data-column-id="commands" data-width="5em" data-formatter="commands" data-sortable="false"></th>
<th data-column-id="commands" data-width="100" data-formatter="commands" data-sortable="false"></th>
</tr>
</thead>
<tbody>

View file

@ -54,6 +54,7 @@
search:'/api/dhcpv4/leases/searchLease/',
del:'/api/dhcpv4/leases/delLease/',
options: {
virtualDOM: true,
selection: false,
multiSelect: false,
useRequestHandlerOnGet: true,
@ -94,8 +95,11 @@
"tooltipformatter": function (column, row) {
return '<span class="overflow">' + row[column.id] + '</span><br/>'
},
"statusformatter": function (column, row) {
"statusformatter": function (column, row, onRendered) {
let connected = row.status == 'online' ? 'text-success' : 'text-danger';
onRendered(() => {
$('[data-toggle="tooltip"]').tooltip({container: 'body', trigger: 'hover'});
})
return '<i class="fa fa-plug ' + connected +'" title="' + row.status + '" data-toggle="tooltip"></i>'
},
"commands": function (column, row) {
@ -118,7 +122,7 @@
/* The delete action can be hooked up to the default bootgrid behaviour */
let deleteip = '<button type="button" class="btn btn-xs btn-default bootgrid-tooltip command-delete"' +
'data-row-id="' + row.address + '" data-action="deleteSelected">' +
'data-row-id="' + row.address + '">' +
'<i class="fa fa-trash fa-fw"></i>' +
'</a>';

View file

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
$("#grid-arp").UIBootgrid({
search:'/api/diagnostics/interface/search_arp/',
options:{
virtualDOM: true,
requestHandler: function(request){
request['resolve'] = $("#resolve").prop("checked") ? 'yes': 'no';
return request;

View file

@ -48,20 +48,37 @@
switch_mode(s_filter_val);
let grid_log = $("#grid-log").UIBootgrid({
datakey: 'rnum',
options:{
initialSearchPhrase: getUrlHash('search'),
sorting:false,
rowSelect: false,
selection: false,
rowCount:[20,50,100,200,500,1000,5000],
virtualDOM: true,
labels: {
infos: "{{ lang._('Showing %s to %s') | format('{{ctx.start}}','{{ctx.end}}') }}"
},
formatters:{
page: function (column, row) {
if ($("input.search-field").val() !== "" || $('#severity_filter').val().length > 0) {
return '<button type="button" class="btn btn-xs btn-default action-page bootgrid-tooltip" data-row-id="' +
row.rnum + '" title="{{ lang._('Go to page') }}"><span class="fa fa-arrow-right fa-fw"></span></button>';
let severity = $('#severity_filter').val();
let debug = (Array.isArray(severity) && severity.includes('Debug')) || severity === "Debug";
if ($("input.search-field").val() !== "" || !debug) {
let btn = $(`
<button type="button" class="btn btn-xs btn-default action-page bootgrid-tooltip" data-row-id="${row.rnum}"
title="{{ lang._('Go to page') }}">
<span class="fa fa-arrow-right fa-fw"></span>
</button>
`).on('click', function(event) {
if ($("#exact_severity").hasClass("fa-toggle-on")) {
$("#severity_filter").selectpicker('deselectAll');
} else {
$("#severity_filter").val("Debug");
}
$('#grid-log').bootgrid('setPageByRowId', parseInt($(this).data('row-id')));
});
return btn[0];
} else {
return "";
}
@ -87,7 +104,8 @@
},
search:'/api/diagnostics/log/{{module}}/{{scope}}'
});
$(".filter_act").change(function(){
$(".filter_act").change(function(event){
event.stopPropagation();
if (window.localStorage) {
localStorage.setItem('log_severity_{{module}}_{{scope}}', $("#severity_filter").val());
localStorage.setItem('log_validFrom_filter_{{module}}_{{scope}}', $("#validFrom_filter").val());
@ -95,25 +113,6 @@
$('#grid-log').bootgrid('reload');
});
grid_log.on("loaded.rs.jquery.bootgrid", function(){
if (page > 0) {
$("ul.pagination > li:last > a").data('page', page).click();
page = 0;
}
$(".action-page").click(function(event){
event.preventDefault();
$("#grid-log").bootgrid("search", "");
page = parseInt((parseInt($(this).data('row-id')) / $("#grid-log").bootgrid("getRowCount")))+1;
$("input.search-field").val("");
if ($("#exact_severity").hasClass("fa-toggle-on")) {
$("#severity_filter").selectpicker('deselectAll');
} else {
$("#severity_filter").val("Debug").change();
}
});
});
$("#flushlog").on('click', function(event){
event.preventDefault();
BootstrapDialog.show({
@ -159,6 +158,9 @@
$("#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();
function switch_mode(value) {
let select = $("#severity_filter");
let header_val = filter_exact ? m_header : s_header;
@ -229,6 +231,11 @@
</select>
</div>
</div>
<div id="export-wrapper" class="btn-group">
<button id="exportbtn" class="btn btn-default" data-toggle="tooltip" title="" type="button" data-original-title="{{ lang._('Download selection')}}">
<span class="fa fa-cloud-download"></span>
</button>
</div>
<table id="grid-log" class="table table-condensed table-hover table-striped table-responsive">
<thead>
<tr>
@ -245,14 +252,6 @@
</tbody>
<tfoot>
<td></td>
<td>
<button id="exportbtn"
data-toggle="tooltip" title="" type="button"
class="btn btn-xs btn-default pull-right"
data-original-title="{{ lang._('download selection')}}">
<span class="fa fa-cloud-download"></span>
</button>
</td>
</tfoot>
</table>
<table class="table">

View file

@ -26,16 +26,19 @@
<script>
$( document ).ready(function() {
let grid = $("#grid-routes").bootgrid({
ajax: false,
selection: false,
multiSelect: false,
formatters: {
"commands": function (column, row) {
return '<button type="button" class="btn btn-xs btn-default command-delete bootgrid-tooltip" title="{{ lang._('Delete') }}" \
data-row-id="' + row.destination + ',' + row.gateway +'"><span class="fa fa-trash-o fa-fw"></span></button>';
let grid = $("#grid-routes").UIBootgrid({
options: {
ajax: false,
selection: false,
multiSelect: false,
virtualDOM: true,
formatters: {
"commands": function (column, row) {
return '<button type="button" class="btn btn-xs btn-default command-delete bootgrid-tooltip" title="{{ lang._('Delete') }}" \
data-row-id="' + row.destination + ',' + row.gateway +'"><span class="fa fa-trash-o fa-fw"></span></button>';
}
}
}
},
}).on("loaded.rs.jquery.bootgrid", function(){
grid.find(".command-delete").on("click", function(e){
let route=$(this).data("row-id").split(',');

View file

@ -36,39 +36,28 @@ POSSIBILITY OF SUCH DAMAGE.
*/
function updateTop() {
var gridopt = {
ajax: false,
selection: true,
ajax: false, // handle pagination and sorting locally
selection: false,
multiSelect: true,
virtualDOM: true,
responseHandler: function(response) {
return response.details;
}
};
if ($("#grid-top").hasClass('bootgrid-table')) {
$("#grid-top").bootgrid('clear');
} else {
$("#grid-top")
.bootgrid(gridopt)
.UIBootgrid({
search: "/api/diagnostics/activity/getActivity",
options: gridopt
})
.on("loaded.rs.jquery.bootgrid", function (e) {
if ($('#grid-top tbody tr').length == 1 && $("#grid-top").bootgrid("getSearchPhrase") == '') {
$("#grid-top td").text("{{ lang._('Waiting for data...') }}");
}
});
}
ajaxGet("/api/diagnostics/activity/getActivity", {}, function (data, status) {
if (status == "success") {
let table = [];
$("#grid-top > tbody").html('');
$.each(data['details'], function (key, record) {
table.push(record);
});
$("#grid-top").bootgrid('append', table);
var header_txt = "";
$.each(data['headers'], function (key, value) {
header_txt += value;
header_txt += "<br/>";
});
$("#header_data").html(header_txt);
$('#header_data_show').show();
}
}
);
}

View file

@ -66,6 +66,7 @@
del:'/api/firewall/filter/del_rule/',
toggle:'/api/firewall/filter/toggle_rule/',
options: {
responsive: true,
triggerEditFor: getUrlHash('edit'),
initialSearchPhrase: getUrlHash('search'),
rowCount: [20,50,100,200,500,1000],
@ -687,7 +688,7 @@
</div>
</div>
<!-- grid -->
{{ partial('layout_partials/base_bootgrid_table', formGridFilterRule + {'command_width': '9em'}) }}
{{ partial('layout_partials/base_bootgrid_table', formGridFilterRule + {'command_width': '150'}) }}
</div>
{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/firewall/filter/apply'}) }}

View file

@ -234,49 +234,44 @@ POSSIBILITY OF SUCH DAMAGE.
/**
* load content on tab changes
*/
let gridRuleFilesInitialized = false;
let gridInstalledRulesInitialized = false;
let gridUserRulesInitialized = false;
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
loadGeneralSettings();
if (e.target.id == 'download_settings_tab') {
/**
* grid for installable rule files
*/
$('#grid-rule-files').bootgrid('destroy'); // always destroy previous grid, so data is always fresh
$("#grid-rule-files").UIBootgrid({
search:'/api/ids/settings/listRulesets',
get:'/api/ids/settings/getRuleset/',
set:'/api/ids/settings/setRuleset/',
toggle:'/api/ids/settings/toggleRuleset/',
options:{
navigation:0,
formatters:{
editor: function (column, row) {
return "<button type=\"button\" class=\"btn btn-xs btn-default command-edit bootgrid-tooltip\" data-row-id=\"" + row.filename + "\"><span class=\"fa fa-pencil fa-fw\"></span></button>";
},
boolean: function (column, row) {
if (parseInt(row[column.id], 2) == 1) {
return "<span class=\"fa fa-check fa-fw command-boolean\" data-value=\"1\" data-row-id=\"" + row.filename + "\"></span>";
} else {
return "<span class=\"fa fa-times fa-fw command-boolean\" data-value=\"0\" data-row-id=\"" + row.filename + "\"></span>";
}
}
},
converters: {
// show "not installed" for rules without timestamp (not on disc)
rulets: {
from: function (value) {
return value;
if (!gridRuleFilesInitialized) {
$("#grid-rule-files").UIBootgrid({
search:'/api/ids/settings/listRulesets',
get:'/api/ids/settings/getRuleset/',
set:'/api/ids/settings/setRuleset/',
toggle:'/api/ids/settings/toggleRuleset/',
options:{
navigation:0,
formatters:{
editor: function (column, row) {
return "<button type=\"button\" class=\"btn btn-xs btn-default command-edit bootgrid-tooltip\" data-row-id=\"" + row.filename + "\"><span class=\"fa fa-pencil fa-fw\"></span></button>";
},
to: function (value) {
if ( value == null ) {
return "{{ lang._('not installed') }}";
boolean: function (column, row) {
if (parseInt(row[column.id], 2) == 1) {
return "<span class=\"fa fa-check fa-fw command-boolean\" data-value=\"1\" data-row-id=\"" + row.filename + "\"></span>";
} else {
return value;
return "<span class=\"fa fa-times fa-fw command-boolean\" data-value=\"0\" data-row-id=\"" + row.filename + "\"></span>";
}
},
rulets: function (column, row) {
return row[column.id] == null ? "{{ lang._('not installed') }}" : row[column.id];
}
}
}
}
});
});
gridRuleFilesInitialized = true;
} else {
$('#grid-rule-files').bootgrid('reload');
}
// display file settings (if available)
ajaxGet("/api/ids/settings/getRulesetproperties", {}, function(data, status) {
if (status == "success") {
@ -316,8 +311,8 @@ POSSIBILITY OF SUCH DAMAGE.
/**
* grid installed rules
*/
$('#grid-installedrules').bootgrid('destroy'); // always destroy previous grid, so data is always fresh
$("#grid-installedrules").UIBootgrid(
if (!gridInstalledRulesInitialized) {
$("#grid-installedrules").UIBootgrid(
{ search:'/api/ids/settings/searchinstalledrules',
get:'/api/ids/settings/get_rule_info/',
set:'/api/ids/settings/set_rule/',
@ -367,7 +362,12 @@ POSSIBILITY OF SUCH DAMAGE.
},
toggle:'/api/ids/settings/toggleRule/'
}
);
);
gridInstalledRulesInitialized = true;
} else {
$('#grid-installedrules').bootgrid('reload');
}
/**
* disable/enable [+action] selected rules
*/
@ -563,16 +563,19 @@ POSSIBILITY OF SUCH DAMAGE.
});
}
} else if (e.target.id == 'userrules_tab') {
$('#grid-userrules').bootgrid('destroy'); // always destroy previous grid, so data is always fresh
$("#grid-userrules").UIBootgrid({
if (!gridUserRulesInitialized) {
$("#grid-userrules").UIBootgrid({
search:'/api/ids/settings/searchUserRule',
get:'/api/ids/settings/getUserRule/',
set:'/api/ids/settings/setUserRule/',
add:'/api/ids/settings/addUserRule/',
del:'/api/ids/settings/delUserRule/',
toggle:'/api/ids/settings/toggleUserRule/'
}
);
});
gridUserRulesInitialized = true;
} else {
$("#grid-userrules").bootgrid('reload');
}
}
});
@ -763,13 +766,13 @@ POSSIBILITY OF SUCH DAMAGE.
</td>
</tr>
</table>
<div style="max-height: 400px; width: 100%; margin: 0; overflow-y: auto;" id="grid-rule-files-container">
<div style="width: 100%; margin: 0; overflow-y: auto;" id="grid-rule-files-container">
<table id="grid-rule-files" class="table table-condensed table-hover table-striped table-responsive" data-editAlert="rulesetChangeMessage" data-editDialog="DialogRuleset">
<thead>
<tr>
<th data-column-id="filename" data-type="string" data-visible="false" data-identifier="true">{{ lang._('Filename') }}</th>
<th data-column-id="description" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Description') }}</th>
<th data-column-id="modified_local" data-type="rulets" data-sortable="false" data-visible="true">{{ lang._('Last updated') }}</th>
<th data-column-id="modified_local" data-formatter="rulets" data-sortable="false" data-visible="true">{{ lang._('Last updated') }}</th>
<th data-column-id="enabled" data-formatter="boolean" data-sortable="false" data-width="10em">{{ lang._('Enabled') }}</th>
<th data-column-id="edit" data-formatter="editor" data-sortable="false" data-width="10em">{{ lang._('Edit') }}</th>
</tr>

View file

@ -30,11 +30,13 @@
$( document ).ready(function() {
let grid_phase1 = $("#grid-phase1").UIBootgrid({
search:'/api/ipsec/sessions/search_phase1',
datakey: 'name',
options:{
initialSearchPhrase: getUrlHash('search'),
multiSelect: false,
rowSelect: true,
rowSelect: false,
selection: true,
stickySelect: true,
formatters:{
commands: function (column, row) {
let connect = "{{ lang._('Connect') }}";
@ -67,7 +69,7 @@
}
});
grid_phase1.on('loaded.rs.jquery.bootgrid', function() {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').tooltip({container: 'body', trigger: 'hover'});
let ids = $("#grid-phase1").bootgrid("getCurrentRows");
if (ids.length > 0) {
$("#grid-phase1").bootgrid('select', [ids[0].name]);

View file

@ -138,12 +138,12 @@
},
"status": function (column, row) {
let connected = row.status == 'up' ? 'text-success' : 'text-danger';
let status = row.status;
if (!row.enabled) {
row.status += ' (disabled)';
status += ' (disabled)';
}
return '<i class="fa fa-plug ' + connected + '" title="' + row.status + '" data-toggle="tooltip"></i>';
return '<i class="fa fa-plug ' + connected + '" title="' + status + '" data-toggle="tooltip"></i>';
},
"ipv4": function (column, row) {
if (row.ipv4) {
@ -211,7 +211,7 @@
}
}
).on("loaded.rs.jquery.bootgrid", function (e) {
$('[data-toggle="tooltip"]').tooltip({html:true});
$('[data-toggle="tooltip"]').tooltip({container: 'body', html:true});
/* attach event handler to reload buttons */
$('.interface-reload').each(function () {
@ -279,7 +279,7 @@
}
$table.append($table_body);
$('[data-toggle="tooltip"]').tooltip({html:true});
$('[data-toggle="tooltip"]').tooltip({container: 'body', html:true});
BootstrapDialog.show({
title: data['description']['value'],
message: $table.prop('outerHTML'),
@ -306,7 +306,7 @@
$expand.show();
}
$expand.click(function () {
$expand.click(function (even) {
let $collapsed = $route_container.children('.route-content').filter(function() {
return $(this).css('display').toLowerCase().indexOf('none') > -1;
});
@ -318,6 +318,8 @@
$collapse.hide();
$expand.html('Expand');
}
$("#grid-overview").bootgrid("normalizeRowHeight");
});
});
});
@ -385,7 +387,7 @@
<span class="fa fa-cloud-download"></span>
</button>
</div>
<table id="grid-overview" class="table table-bordered table-condensed table-hover table-striped">
<table id="grid-overview" class="table table-bordered table-condensed table-hover table-striped table-responsive">
<thead>
<tr>
<th data-column-id="status" data-width="5em" data-formatter="status" data-type="string">{{ lang._('Status') }}</th>

View file

@ -17,7 +17,7 @@
formatters: {
networkFormatter: function(column, row) {
return row.subnet + (row.subnet_bits ? '/' + row.subnet_bits : '');
}
},
},
}
}
@ -86,7 +86,7 @@
</select>
</div>
</div>
{{ partial('layout_partials/base_bootgrid_table', formGridVip)}}
{{ partial('layout_partials/base_bootgrid_table', formGridVip + {'command_width': '90'})}}
</div>
{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/interfaces/vip_settings/reconfigure'}) }}
{{ partial('layout_partials/base_dialog',['fields':formDialogVip,'id':formGridVip['edit_dialog_id'],'label':lang._('Edit Virtual IP')])}}

View file

@ -43,16 +43,6 @@
});
}
/**
* chain std_bootgrid_reload from opnsense_bootgrid_plugin.js
* to get the isSubsystemDirty state on "UIBootgrid" changes
*/
var opn_std_bootgrid_reload = std_bootgrid_reload;
std_bootgrid_reload = function(gridId) {
opn_std_bootgrid_reload(gridId);
isSubsystemDirty();
};
/**
* apply changes and reload monit
*/

View file

@ -41,11 +41,19 @@
toggle:'/api/syslog/settings/toggleDestination/'
}
);
let gridStatsInitialized = false;
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if (e.target.id === 'statistics') {
$("#grid-statistics").UIBootgrid({
search: '/api/syslog/service/stats/'
});
if (!gridStatsInitialized) {
$("#grid-statistics").UIBootgrid({
search: '/api/syslog/service/stats/'
});
let gridStatsInitialized = true;
} else {
$("#grid-statistics").bootgrid('reload');
}
}
});

View file

@ -37,6 +37,7 @@ $( document ).ready(function() {
selection: true,
multiSelect: false,
rowSelect: true,
stickySelect: true,
formatters: {
"mxformatter": function (column, row) {
/* Format the "Value" column so it shows either an MX host ("MX" type) or a raw IP address ("A" type) */
@ -50,10 +51,6 @@ $( document ).ready(function() {
}).on("selected.rs.jquery.bootgrid", function (e, rows) {
$("#{{formGridHostAlias['table_id']}}").bootgrid('reload');
}).on("deselected.rs.jquery.bootgrid", function (e, rows) {
// de-select not allowed, make sure always one items is selected. (sticky selected)
if ($("#{{formGridHostOverride['table_id']}}").bootgrid("getSelectedRows").length == 0) {
$("#{{formGridHostOverride['table_id']}}").bootgrid('select', [rows[0].uuid]);
}
$("#{{formGridHostAlias['table_id']}}").bootgrid('reload');
}).on("loaded.rs.jquery.bootgrid", function (e) {
let ids = $("#{{formGridHostOverride['table_id']}}").bootgrid("getCurrentRows");

View file

@ -5,7 +5,7 @@
{% 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="{{command_width|default('7em')}}" data-formatter="commands" data-sortable="false">
<th data-column-id="commands" data-width="{{command_width|default('100')}}" data-formatter="commands" data-sortable="false">
{{ lang._('Commands') }}
</th>
</tr>

View file

@ -306,37 +306,23 @@
</div>
<script>
/* hook translations when all JS modules are loaded*/
$.extend(jQuery.fn.bootgrid.prototype.constructor.Constructor.defaults.labels, {
all: "{{ lang._('All') }}",
infos: "{{ lang._('Showing %s to %s of %s entries') | format('{{ctx.start}}','{{ctx.end}}','{{ctx.total}}') }}",
noResults: "{{ lang._('No results found!') }}",
refresh: "{{ lang._('Refresh') }}",
reset: "{{ lang._('Reset to defaults') }}",
search: "{{ lang._('Search') }}"
});
$.extend(jQuery.fn.selectpicker.Constructor.DEFAULTS, {
noneSelectedText: "{{ lang._('Nothing selected') }}",
noneResultsText: "{{ lang._('No results matched {0}') }}",
selectAllText: "{{ lang._('Select All') }}",
deselectAllText: "{{ lang._('Deselect All') }}"
});
$.extend(jQuery.fn.UIBootgrid.defaults, {
removeWarningText: "{{ lang._('Remove selected item(s)?') }}",
editText: "{{ lang._('Edit') }}",
cloneText: "{{ lang._('Clone') }}",
deleteText: "{{ lang._('Delete') }}",
addText: "{{ lang._('Add') }}",
infoText: "{{ lang._('Info') }}",
enableText: "{{ lang._('Enable') }}",
disableText: "{{ lang._('Disable') }}",
deleteSelectedText: "{{ lang._('Delete selected') }}"
});
$.extend(stdDialogRemoveItem.defaults, {
title: "{{ lang._('Remove') }}",
accept: "{{ lang._('Yes') }}",
decline: "{{ lang._('Cancel') }}"
});
$.extend(jQuery.fn.UIBootgrid.translations, {
add: "{{ lang._('Add') }}",
deleteSelected: "{{ lang._('Delete selected') }}",
edit: "{{ lang._('Edit') }}",
disable: "{{ lang._('Disable') }}",
enable: "{{ lang._('Enable') }}",
delete: "{{ lang._('Delete') }}",
info: "{{ lang._('Info') }}",
clone: "{{ lang._('Clone') }}",
all: "{{ lang._('All') }}",
search: "{{ lang._('Search') }}",
removeWarning: "{{ lang._('Remove selected item(s)?') }}",
noresultsfound: "{{ lang._('No results found') }}",
refresh: "{{ lang._('Refresh') }}",
infosTotal: "{{ lang._('Showing %s to %s of %s entries') | format('{{ctx.start}}','{{ctx.end}}','{{ctx.totalRows}}') }}",
infos: "{{ lang._('Showing %s to %s') | format('{{ctx.start}}','{{ctx.end}}') }}",
});
</script>
</body>

View file

@ -0,0 +1,268 @@
/**
* Main theming elements
*/
.tabulator {
font-size: 15px;
background-color: transparent;
}
/* theme: header */
.tabulator .tabulator-header {
background-color: transparent;
border-top: 1px solid #373736; /* $table-bg-accent, was #eee */
border-left: 1px solid #373736; /* $table-bg-accent, was #eee */
border-right: 1px solid #373736; /* $table-bg-accent, was #eee */
border-bottom: none;
}
.tabulator .tabulator-header .tabulator-col {
border-right: 1px solid #373736; /* $table-bg-accent, was #e0e0e0 */
background-color: transparent;
background: transparent;
/* XXX need theme text color */
color: #ECECEC; /* $text-color */
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
background-color: #373736; /* $table-bg-accent */
}
.tabulator .tabulator-headers {
height: 100% !important; /* make sure the below border appears */
border-bottom: 1px solid #aaa; /* separates header from table rows */
}
/*------------*/
/* theme: body */
.tabulator .tabulator-tableholder .tabulator-table {
background-color: transparent;
}
.tabulator-row {
background-color: transparent;
color: #ECECEC; /* $text-color */
}
.tabulator-row.tabulator-row-odd {
background-color: #373736; /* $table-bg-accent, was (#FBFBFB) */
}
.tabulator-row.tabulator-row-odd.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: #373736; /* $table-bg-accent was (#FBFBFB) */
}
.tabulator-row.tabulator-row-even {
background-color: transparent;
}
.tabulator-row.tabulator-row-even.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: transparent;
}
.tabulator .tabulator-tableholder {
background-color: transparent;
border-left: 1px solid #373736; /* $table-bg-accent, was (#eee) */
border-right: 1px solid #373736; /* $table-bg-accent, was (#eee) */
/* overflow: scroll; */
scrollbar-gutter: stable;
}
.tabulator-row.tabulator-selected {
background-color: #9abcea; /* XXX needs new theme */
}
.tabulator-row.tabulator-selected:hover {
cursor: pointer;
background-color: #9abcea; /* XXX needs new theme */
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
color: #ECECEC; /* spinner icon, $text-color */
}
/* Command column styles */
.tabulator-col.tabulator-frozen.tabulator-frozen-right {
background-color: #101218; /* $body-background was #eee, probably needs new style */
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
background-color: #101218; /* $body-background was #eee, probably needs new style */
}
/* Checkbox column styles */
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid #aaa; /* separates checkbox column from table rows, needs same theme as .tabulator .tabulator-headers */
border-left: 1px solid #373736; /* $table-bg-accent, was #eee*/
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid #aaa; /* XXX needs new theme style */
border-top: 1px solid #373736; /* $table-bg-accent, was #eee*/
border-bottom: 1px solid #aaa; /* XXX needs new theme style */
border-left: 1px solid #373736; /* $table-bg-accent, was #eee*/
}
.tabulator-col.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #101218; /* $body-background was #eee, probably needs new style */
}
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #101218; /* $body-background was #eee, probably needs new style */
}
.tabulator-row:last-child >
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left:first-child {
}
/*------------*/
/* theme: cells */
.tabulator-row .tabulator-cell {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
vertical-align: top;
border-bottom: 1px solid #373736; /* $table-bg-accent (was #eee) should probably be something lighter */
border-right: 1px solid #373736; /* $table-bg-accent (was #eee) should probably be something lighter */
}
/*-------------*/
/* theme: footer */
.tabulator .tabulator-footer {
background-color: transparent;
}
.tabulator .tabulator-footer .tabulator-page {
background-color: #101218; /* $body-background */
color: #C03E14; /* $brand-primary */
}
.tabulator .tabulator-footer .tabulator-page.active {
background-color: #C03E14; /* $brand-primary */
border-color: #C03E14; /* $brand-primary */
cursor: default;
color: #101218; /* $body-background */
}
.tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
color: #7b280d; /* XXX where does this color come from? same in light mode as in dark mode */
background-color: #242937; /* XXX where does this color come from? light mode: #eeeeee dark mode: #242937 */
border-color: #ddd;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled).active:hover {
background-color: #C03E14; /* $brand-primary */
border-color: #C03E14; /* $brand-primary */
color: #101218; /* $body-background */
cursor: default;
}
.tabulator-page-counter {
color: #ECECEC; /* $text-color */
}
.tabulator .tabulator-footer .tabulator-paginator {
color: #ECECEC; /* $text-color */
}
.tabulator .tabulator-footer .tabulator-page {
border-radius: 0px;
margin: 0px;
padding: 6px 12px;
border: 1px solid #E5E5E5; /* $border-default (was #ddd) */
}
/*----------*/
/* end of main theming elements */
.tabulator-paginator {
flex: 0 !important;
}
.tabulator-page-counter {
flex: 1;
text-align: right;
}
.tabulator-col-sorter i {
display: flex;
justify-content: center;
align-items: center;
}
.tabulator .tabulator-header .tabulator-col {
padding: 5px;
}
.tabulator .tabulator-headers > :first-child {
padding-left: 10px;
}
.opnsense-bootgrid-responsive {
white-space: wrap !important;
text-overflow: inherit !important;
overflow: visible !important;
word-break: break-word !important;
}
.opnsense-bootgrid-ellipsis {
overflow: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
.tabulator-row > :first-child {
padding-left: 10px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 0px;
}
.tabulator-page-counter {
padding-right: 20px;
}
.bootgrid-footer-commands {
width: 90px;
padding-left: 8px;
}
/* move border from footer to last row */
.tabulator .tabulator-footer {
border-top: none;
}
.tabulator-tableholder::after {
content: '';
display: block;
width: 1px;
height: 1px;
min-width: 100%;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
/* border line corrections and hover/selection behavior */
.tabulator-row:first-child > .tabulator-cell {
border-top: none;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
padding: 0px;
}
/* Row highlight behavior */
@keyframes highlight {
0% {
background: #ffff99;
}
100% {
background: none;
}
}
.highlight-bg {
animation: highlight 2s;
}
/* Tabulator "loading" and "error" overrides */
.tabulator .tabulator-alert {
background: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
border: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg {
background: initial;
font-size: 18px;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
border: none;
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

3
src/opnsense/www/js/tabulator.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -10,5 +10,6 @@ $colors: (
navbar-default-bg: #101218,
text-color: #ECECEC,
border-default: #E5E5E5,
dashboard-widget-error: #721c24
dashboard-widget-error: #721c24,
border-highlight: #AAA,
);

View file

@ -0,0 +1,260 @@
@import "config/colors";
/**
* Main theming elements
*/
.tabulator {
font-size: 15px;
background-color: transparent;
border: 1px solid map-get($colors, border-default);
}
/* theme: header */
.tabulator .tabulator-header {
background-color: transparent;
border-bottom: none;
}
.tabulator .tabulator-header .tabulator-col {
border-right: 1px solid map-get($colors, border-default);
background-color: transparent;
background: transparent;
color: map-get($colors, text-color);
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
background-color: map-get($colors, table-bg-accent);
}
.tabulator .tabulator-headers {
height: 100% !important; /* make sure the border below appears */
border-bottom: 1px solid map-get($colors, border-default);
}
/*------------*/
/* theme: body */
.tabulator .tabulator-tableholder .tabulator-table {
background-color: transparent;
}
.tabulator-row {
background-color: transparent;
color: map-get($colors, text-color);
}
.tabulator-row.tabulator-row-odd {
background-color: map-get($colors, table-bg-accent);
}
.tabulator-row.tabulator-row-odd.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: map-get($colors, table-bg-accent);
}
.tabulator-row.tabulator-row-even {
background-color: transparent;
}
.tabulator-row.tabulator-row-even.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: transparent;
}
.tabulator .tabulator-tableholder {
background-color: transparent;
border-right: 1px solid map-get($colors, table-bg-accent);
}
.tabulator-row.tabulator-selected {
background-color: #9abcea;
}
.tabulator-row.tabulator-selected:hover {
cursor: pointer;
background-color: #9abcea;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
color: map-get($colors, text-color); /* spinner icon */
}
/* Command column styles */
.tabulator-col.tabulator-frozen.tabulator-frozen-right {
background-color: #101218;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
background-color: #101218;
}
/* Checkbox column styles */
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid map-get($colors, border-default); /* separates checkbox column from table rows */
border-left: 1px solid map-get($colors, table-bg-accent);
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid map-get($colors, border-default);
border-top: 1px solid map-get($colors, table-bg-accent);
border-bottom: 1px solid map-get($colors, border-default);
border-left: 1px solid map-get($colors, table-bg-accent);
}
.tabulator-col.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #101218;
}
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #101218;
}
.tabulator-row:last-child >
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left:first-child {
}
/*------------*/
/* theme: cells */
.tabulator-row .tabulator-cell {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
vertical-align: top;
border-bottom: 1px solid rgba(map-get($colors, border-default), 0.5);
border-right: 1px solid rgba(map-get($colors, border-default), 0.5);
}
/*-------------*/
/* theme: footer */
.tabulator .tabulator-footer {
border-top: 1px solid map-get($colors, border-default);
background-color: transparent;
}
.tabulator .tabulator-footer .tabulator-page {
background-color: map-get($colors, body-background);
color: map-get($colors, brand-primary);
}
.tabulator .tabulator-footer .tabulator-page.active {
background-color: map-get($colors, brand-primary);
border-color: map-get($colors, brand-primary);
cursor: default;
color: map-get($colors, body-background);
}
.tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
color: #7b280d;
background-color: #242937;
border-color: #ddd;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled).active:hover {
background-color: map-get($colors, brand-primary);
border-color: map-get($colors, brand-primary);
color: map-get($colors, body-background);
cursor: default;
}
.tabulator-page-counter {
color: map-get($colors,text-color);
}
.tabulator .tabulator-footer .tabulator-paginator {
color: map-get($colors,text-color);
}
.tabulator .tabulator-footer .tabulator-page {
border-radius: 0px;
margin: 0px;
padding: 6px 12px;
border: 1px solid map-get($colors, border-default);
}
/*----------*/
/* end of main theming elements */
.tabulator-paginator {
flex: 0 !important;
}
.tabulator-page-counter {
flex: 1;
text-align: right;
}
.tabulator-col-sorter i {
display: flex;
justify-content: center;
align-items: center;
}
.tabulator .tabulator-header .tabulator-col {
padding: 5px;
}
.tabulator .tabulator-headers > :first-child {
padding-left: 10px;
}
.opnsense-bootgrid-responsive {
white-space: wrap !important;
text-overflow: inherit !important;
overflow: visible !important;
word-break: break-word !important;
}
.opnsense-bootgrid-ellipsis {
overflow: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
.tabulator-row > :first-child {
padding-left: 10px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 0px;
}
.tabulator-page-counter {
padding-right: 20px;
}
.bootgrid-footer-commands {
width: 90px;
padding-left: 8px;
}
.tabulator-tableholder::after {
content: '';
display: block;
width: 1px;
height: 1px;
min-width: 100%;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
/* border line corrections and hover/selection behavior */
.tabulator-row:first-child > .tabulator-cell {
border-top: none;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
padding: 0px;
}
/* Row highlight behavior */
@keyframes highlight {
0% {
background: #ffff99;
}
100% {
background: none;
}
}
.highlight-bg {
animation: highlight 2s;
}
/* Tabulator "loading" and "error" overrides */
.tabulator .tabulator-alert {
background: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
border: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg {
background: initial;
font-size: 18px;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
border: none;
}

View file

@ -0,0 +1,276 @@
/**
* Main theming elements
*/
.tabulator {
font-size: 15px;
background-color: transparent;
border: 1px solid #E5E5E5;
}
/* theme: header */
.tabulator .tabulator-header {
background-color: transparent;
border-bottom: none;
}
.tabulator .tabulator-header .tabulator-col {
border-right: 1px solid #E5E5E5;
background-color: transparent;
background: transparent;
color: #ECECEC;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
background-color: #373736;
}
.tabulator .tabulator-headers {
height: 100% !important; /* make sure the border below appears */
border-bottom: 1px solid #E5E5E5;
}
/*------------*/
/* theme: body */
.tabulator .tabulator-tableholder .tabulator-table {
background-color: transparent;
}
.tabulator-row {
background-color: transparent;
color: #ECECEC;
}
.tabulator-row.tabulator-row-odd {
background-color: #373736;
}
.tabulator-row.tabulator-row-odd.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: #373736;
}
.tabulator-row.tabulator-row-even {
background-color: transparent;
}
.tabulator-row.tabulator-row-even.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: transparent;
}
.tabulator .tabulator-tableholder {
background-color: transparent;
border-right: 1px solid #373736;
}
.tabulator-row.tabulator-selected {
background-color: #9abcea;
}
.tabulator-row.tabulator-selected:hover {
cursor: pointer;
background-color: #9abcea;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
color: #ECECEC; /* spinner icon */
}
/* Command column styles */
.tabulator-col.tabulator-frozen.tabulator-frozen-right {
background-color: #101218;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
background-color: #101218;
}
/* Checkbox column styles */
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid #E5E5E5; /* separates checkbox column from table rows */
border-left: 1px solid #373736;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid #E5E5E5;
border-top: 1px solid #373736;
border-bottom: 1px solid #E5E5E5;
border-left: 1px solid #373736;
}
.tabulator-col.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #101218;
}
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #101218;
}
/*------------*/
/* theme: cells */
.tabulator-row .tabulator-cell {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
vertical-align: top;
border-bottom: 1px solid rgba(229, 229, 229, 0.5);
border-right: 1px solid rgba(229, 229, 229, 0.5);
}
/*-------------*/
/* theme: footer */
.tabulator .tabulator-footer {
border-top: 1px solid #E5E5E5;
background-color: transparent;
}
.tabulator .tabulator-footer .tabulator-page {
background-color: #101218;
color: #C03E14;
}
.tabulator .tabulator-footer .tabulator-page.active {
background-color: #C03E14;
border-color: #C03E14;
cursor: default;
color: #101218;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
color: #7b280d;
background-color: #242937;
border-color: #ddd;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled).active:hover {
background-color: #C03E14;
border-color: #C03E14;
color: #101218;
cursor: default;
}
.tabulator-page-counter {
color: #ECECEC;
}
.tabulator .tabulator-footer .tabulator-paginator {
color: #ECECEC;
}
.tabulator .tabulator-footer .tabulator-page {
border-radius: 0px;
margin: 0px;
padding: 6px 12px;
border: 1px solid #E5E5E5;
}
/*----------*/
/* end of main theming elements */
.tabulator-paginator {
flex: 0 !important;
}
.tabulator-page-counter {
flex: 1;
text-align: right;
}
.tabulator-col-sorter i {
display: flex;
justify-content: center;
align-items: center;
}
.tabulator .tabulator-header .tabulator-col {
padding: 5px;
}
.tabulator .tabulator-headers > :first-child {
padding-left: 10px;
}
.opnsense-bootgrid-responsive {
white-space: wrap !important;
text-overflow: inherit !important;
overflow: visible !important;
word-break: break-word !important;
}
.opnsense-bootgrid-ellipsis {
overflow: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
.tabulator-row > :first-child {
padding-left: 10px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 0px;
}
.tabulator-page-counter {
padding-right: 20px;
}
.bootgrid-footer-commands {
width: 90px;
padding-left: 8px;
}
.tabulator-tableholder::after {
content: "";
display: block;
width: 1px;
height: 1px;
min-width: 100%;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
/* border line corrections and hover/selection behavior */
.tabulator-row:first-child > .tabulator-cell {
border-top: none;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
padding: 0px;
}
/* Row highlight behavior */
@keyframes highlight {
0% {
background: #ffff99;
}
100% {
background: none;
}
}
.highlight-bg {
animation: highlight 2s;
}
/* Tabulator "loading" and "error" overrides */
.tabulator .tabulator-alert {
background: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
border: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg {
background: initial;
font-size: 18px;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
border: none;
}

View file

@ -11,5 +11,6 @@ $colors: (
list-group-link-color: #373736,
text-color: #373736,
border-default: #E5E5E5,
dashboard-widget-error: #721c24
dashboard-widget-error: #721c24,
border-highlight: #999,
);

View file

@ -0,0 +1,265 @@
@import "config/colors";
/**
* Main theming elements
*/
.tabulator {
font-size: 15px;
background-color: transparent;
border: 1px solid map-get($colors, border-default);
}
/* theme: header */
.tabulator .tabulator-header {
background-color: transparent;
border-bottom: none;
}
.tabulator .tabulator-header .tabulator-col {
border-right: 1px solid map-get($colors, border-default);
background-color: transparent;
background: transparent;
color: map-get($colors, text-color);
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
background-color: map-get($colors, table-bg-accent);
}
.tabulator .tabulator-headers {
height: 100% !important; /* make sure the border below appears */
border-bottom: 1px solid map-get($colors, border-default);
}
/*------------*/
/* theme: body */
.tabulator .tabulator-tableholder .tabulator-table {
background-color: transparent;
}
.tabulator-row {
background-color: transparent;
color: map-get($colors, text-color);
}
.tabulator-row.tabulator-row-odd {
background-color: map-get($colors, table-bg-accent);
}
.tabulator-row.tabulator-row-odd.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: map-get($colors, table-bg-accent);
}
.tabulator-row.tabulator-row-even {
background-color: transparent;
}
.tabulator-row.tabulator-row-even.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: transparent;
}
.tabulator .tabulator-tableholder {
background-color: transparent;
border-left: 1px solid map-get($colors, table-bg-accent);
border-right: 1px solid map-get($colors, table-bg-accent);
}
.tabulator-row.tabulator-selected {
background-color: #9abcea;
}
.tabulator-row.tabulator-selected:hover {
cursor: pointer;
background-color: #9abcea;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
color: map-get($colors, text-color); /* spinner icon */
}
/* Command column styles */
.tabulator-col.tabulator-frozen.tabulator-frozen-right {
background-color: #eee;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
background-color: #eee;
}
/* Checkbox column styles */
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid map-get($colors, border-default); /* separates checkbox column from table rows */
border-left: 1px solid map-get($colors, table-bg-accent);
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid map-get($colors, border-default);
border-top: 1px solid map-get($colors, table-bg-accent);
border-bottom: 1px solid map-get($colors, border-default);
border-left: 1px solid map-get($colors, table-bg-accent);
}
.tabulator-col.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #eee;
}
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #eee;
}
.tabulator-row:last-child >
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left:first-child {
}
/*------------*/
/* theme: cells */
.tabulator-row .tabulator-cell {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
vertical-align: top;
border-bottom: 1px solid rgba(map-get($colors, border-default), 0.5);
border-right: 1px solid rgba(map-get($colors, border-default), 0.5);
}
/*-------------*/
/* theme: footer */
.tabulator .tabulator-footer {
background-color: transparent;
}
.tabulator .tabulator-footer .tabulator-page {
background-color: map-get($colors, body-background);
color: map-get($colors, brand-primary);
}
.tabulator .tabulator-footer .tabulator-page.active {
background-color: map-get($colors, brand-primary);
border-color: map-get($colors, brand-primary);
cursor: default;
color: map-get($colors, body-background);
}
.tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
color: #7b280d;
background-color: #eeeeee;
border-color: #ddd;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled).active:hover {
background-color: map-get($colors, brand-primary);
border-color: map-get($colors, brand-primary);
color: map-get($colors, body-background);
cursor: default;
}
.tabulator-page-counter {
color: map-get($colors,text-color);
}
.tabulator .tabulator-footer .tabulator-paginator {
color: map-get($colors, text-color);
}
.tabulator .tabulator-footer .tabulator-page {
border-radius: 0px;
margin: 0px;
padding: 6px 12px;
border: 1px solid map-get($colors, border-default);
}
/*----------*/
/* end of main theming elements */
.tabulator-paginator {
flex: 0 !important;
}
.tabulator-page-counter {
flex: 1;
text-align: right;
}
.tabulator-col-sorter i {
display: flex;
justify-content: center;
align-items: center;
}
.tabulator .tabulator-header .tabulator-col {
padding: 5px;
}
.tabulator .tabulator-headers > :first-child {
padding-left: 10px;
}
.opnsense-bootgrid-responsive {
white-space: wrap !important;
text-overflow: inherit !important;
overflow: visible !important;
word-break: break-word !important;
}
.opnsense-bootgrid-ellipsis {
overflow: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
.tabulator-row > :first-child {
padding-left: 10px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 0px;
}
.tabulator-page-counter {
padding-right: 20px;
}
.bootgrid-footer-commands {
width: 90px;
padding-left: 8px;
}
/* move border from footer to last row */
.tabulator .tabulator-footer {
border-top: none;
}
.tabulator-tableholder::after {
content: '';
display: block;
width: 1px;
height: 1px;
min-width: 100%;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
/* border line corrections and hover/selection behavior */
.tabulator-row:first-child > .tabulator-cell {
border-top: none;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
padding: 0px;
}
/* Row highlight behavior */
@keyframes highlight {
0% {
background: #ffff99;
}
100% {
background: none;
}
}
.highlight-bg {
animation: highlight 2s;
}
/* Tabulator "loading" and "error" overrides */
.tabulator .tabulator-alert {
background: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
border: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg {
background: initial;
font-size: 18px;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
border: none;
}

View file

@ -0,0 +1,281 @@
/**
* Main theming elements
*/
.tabulator {
font-size: 15px;
background-color: transparent;
border: 1px solid #E5E5E5;
}
/* theme: header */
.tabulator .tabulator-header {
background-color: transparent;
border-bottom: none;
}
.tabulator .tabulator-header .tabulator-col {
border-right: 1px solid #E5E5E5;
background-color: transparent;
background: transparent;
color: #373736;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
background-color: #FBFBFB;
}
.tabulator .tabulator-headers {
height: 100% !important; /* make sure the border below appears */
border-bottom: 1px solid #E5E5E5;
}
/*------------*/
/* theme: body */
.tabulator .tabulator-tableholder .tabulator-table {
background-color: transparent;
}
.tabulator-row {
background-color: transparent;
color: #373736;
}
.tabulator-row.tabulator-row-odd {
background-color: #FBFBFB;
}
.tabulator-row.tabulator-row-odd.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: #FBFBFB;
}
.tabulator-row.tabulator-row-even {
background-color: transparent;
}
.tabulator-row.tabulator-row-even.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: transparent;
}
.tabulator .tabulator-tableholder {
background-color: transparent;
border-left: 1px solid #FBFBFB;
border-right: 1px solid #FBFBFB;
}
.tabulator-row.tabulator-selected {
background-color: #9abcea;
}
.tabulator-row.tabulator-selected:hover {
cursor: pointer;
background-color: #9abcea;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
color: #373736; /* spinner icon */
}
/* Command column styles */
.tabulator-col.tabulator-frozen.tabulator-frozen-right {
background-color: #eee;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
background-color: #eee;
}
/* Checkbox column styles */
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid #E5E5E5; /* separates checkbox column from table rows */
border-left: 1px solid #FBFBFB;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
border-right: 1px solid #E5E5E5;
border-top: 1px solid #FBFBFB;
border-bottom: 1px solid #E5E5E5;
border-left: 1px solid #FBFBFB;
}
.tabulator-col.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #eee;
}
.tabulator-cell.tabulator-row-header.tabulator-frozen.tabulator-frozen-left {
background-color: #eee;
}
/*------------*/
/* theme: cells */
.tabulator-row .tabulator-cell {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
vertical-align: top;
border-bottom: 1px solid rgba(229, 229, 229, 0.5);
border-right: 1px solid rgba(229, 229, 229, 0.5);
}
/*-------------*/
/* theme: footer */
.tabulator .tabulator-footer {
background-color: transparent;
}
.tabulator .tabulator-footer .tabulator-page {
background-color: #fff;
color: #C03E14;
}
.tabulator .tabulator-footer .tabulator-page.active {
background-color: #C03E14;
border-color: #C03E14;
cursor: default;
color: #fff;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
color: #7b280d;
background-color: #eeeeee;
border-color: #ddd;
}
.tabulator .tabulator-footer .tabulator-page:not(disabled).active:hover {
background-color: #C03E14;
border-color: #C03E14;
color: #fff;
cursor: default;
}
.tabulator-page-counter {
color: #373736;
}
.tabulator .tabulator-footer .tabulator-paginator {
color: #373736;
}
.tabulator .tabulator-footer .tabulator-page {
border-radius: 0px;
margin: 0px;
padding: 6px 12px;
border: 1px solid #E5E5E5;
}
/*----------*/
/* end of main theming elements */
.tabulator-paginator {
flex: 0 !important;
}
.tabulator-page-counter {
flex: 1;
text-align: right;
}
.tabulator-col-sorter i {
display: flex;
justify-content: center;
align-items: center;
}
.tabulator .tabulator-header .tabulator-col {
padding: 5px;
}
.tabulator .tabulator-headers > :first-child {
padding-left: 10px;
}
.opnsense-bootgrid-responsive {
white-space: wrap !important;
text-overflow: inherit !important;
overflow: visible !important;
word-break: break-word !important;
}
.opnsense-bootgrid-ellipsis {
overflow: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
.tabulator-row > :first-child {
padding-left: 10px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 0px;
}
.tabulator-page-counter {
padding-right: 20px;
}
.bootgrid-footer-commands {
width: 90px;
padding-left: 8px;
}
/* move border from footer to last row */
.tabulator .tabulator-footer {
border-top: none;
}
.tabulator-tableholder::after {
content: "";
display: block;
width: 1px;
height: 1px;
min-width: 100%;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
/* border line corrections and hover/selection behavior */
.tabulator-row:first-child > .tabulator-cell {
border-top: none;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
padding: 0px;
}
/* Row highlight behavior */
@keyframes highlight {
0% {
background: #ffff99;
}
100% {
background: none;
}
}
.highlight-bg {
animation: highlight 2s;
}
/* Tabulator "loading" and "error" overrides */
.tabulator .tabulator-alert {
background: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
border: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg {
background: initial;
font-size: 18px;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
border: none;
}