mirror of
https://github.com/opnsense/core.git
synced 2026-02-18 18:18:13 -05:00
interfaces: overview: clean up UI code and fix CARP badge alignment
This commit is contained in:
parent
5b3b163ce0
commit
8405980833
2 changed files with 132 additions and 135 deletions
|
|
@ -70,19 +70,31 @@
|
|||
}
|
||||
|
||||
function iterate_ips(obj) {
|
||||
let $elements = $('<div></div>');
|
||||
let $elements = $('<div>').css({
|
||||
'whiteSpace': 'normal',
|
||||
'lineHeight': '1.2'
|
||||
});
|
||||
obj.forEach(function (ip) {
|
||||
$span = $('<span></span><br/>').text(ip['ipaddr'] + ' ');
|
||||
if ('vhid' in ip) {
|
||||
$carp = $('<span style="cursor: pointer;"></span>').text('vhid ' + ip['vhid']);
|
||||
$carp.attr('class', 'badge badge-pill');
|
||||
$carp.css('background-color', ip['status'] == 'MASTER' ? 'green' : 'primary');
|
||||
$carp.attr('data-toggle', 'tooltip');
|
||||
let title_text = ip['status'] + ' (freq. ' + ip['advbase'] + '/' + ip['advskew'] + ')';
|
||||
if (ip['peer']) {
|
||||
title_text = title_text + ' <br/> ' + ip['peer'] + ' <br/> ' + ip['peer6'];
|
||||
const titleLines = [
|
||||
`${ip.status} (freq. ${ip.advbase}/${ip.advskew})`
|
||||
];
|
||||
|
||||
if (ip.peer) {
|
||||
titleLines.push(ip.peer, ip.peer6);
|
||||
}
|
||||
$carp.attr('title', title_text);
|
||||
|
||||
const $carp = $('<span>', {
|
||||
text: `vhid ${ip.vhid}`,
|
||||
css: { cursor: 'pointer' },
|
||||
'data-toggle': 'tooltip',
|
||||
'data-html': true
|
||||
})
|
||||
.addClass('badge badge-pill')
|
||||
.css('background-color', ip.status === 'MASTER' ? 'green' : 'primary')
|
||||
.prop('title', titleLines.join('<br/>'));
|
||||
|
||||
$span.append($carp);
|
||||
}
|
||||
$elements.append($span);
|
||||
|
|
@ -93,6 +105,115 @@
|
|||
$("#grid-overview").UIBootgrid(
|
||||
{
|
||||
search: '/api/interfaces/overview/interfaces_info',
|
||||
commands: {
|
||||
interface_reload: {
|
||||
filter: (cell) => {
|
||||
const data = cell.getData();
|
||||
return 'link_type' in data && ["dhcp", "pppoe", "pptp", "l2tp", "ppp"].includes(data.link_type);
|
||||
},
|
||||
method: (event, cell) => {
|
||||
const data = cell.getData();
|
||||
const $element = $(cell.getElement()).find('.command-interface_reload');
|
||||
$element.remove('i').html('<i class="fa fa-spinner fa-spin"></i>');
|
||||
ajaxCall('/api/interfaces/overview/reload_interface/' + data.identifier, {}, function (data, status) {
|
||||
/* delay slightly to allow the interface to come up */
|
||||
setTimeout(function() {
|
||||
$element.remove('i').html('<i class="fa fa-fw fa-refresh"></i>');
|
||||
$("#grid-overview").bootgrid('reload');
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
classname: 'fa fa-fw fa-refresh',
|
||||
title: "{{ lang._('Reload') }}"
|
||||
},
|
||||
settings: {
|
||||
filter: (cell) => {
|
||||
const data = cell.getData();
|
||||
return 'identifier' in data && data.identifier && 'config' in data && data.config && !data.config.internal_dynamic;
|
||||
},
|
||||
method: (event, cell) => {
|
||||
window.location.href = `/interfaces.php?if=${cell.getData().identifier}`;
|
||||
},
|
||||
classname: 'fa fa-fw fa-cog',
|
||||
title: "{{ lang._('Settings') }}"
|
||||
},
|
||||
firewall_rules: {
|
||||
filter: (cell) => {
|
||||
const data = cell.getData();
|
||||
return 'identifier' in data && data.identifier && data.enabled;
|
||||
},
|
||||
method: (event, cell) => {
|
||||
window.location.href = `/ui/firewall/filter/#interface=${cell.getData().identifier}`;
|
||||
},
|
||||
classname: 'fa fa-fw fa-fire',
|
||||
title: "{{ lang._('Firewall Rules') }}"
|
||||
},
|
||||
interface_info: {
|
||||
method: (event, cell) => {
|
||||
ajaxGet('/api/interfaces/overview/get_interface/' + cell.getData().device, {}, function(data, status) {
|
||||
data = data['message'];
|
||||
let $table = $('<table class="table table-bordered table-condensed table-hover table-striped"></table>');
|
||||
let $table_body = $('<tbody/>');
|
||||
|
||||
for (let key in data) {
|
||||
let $row = $('<tr/>');
|
||||
let value = data[key]['value'];
|
||||
if (key === 'line rate') {
|
||||
value = format_linerate(value.split(" ")[0]);
|
||||
}
|
||||
if (key === 'ipv4' || key === 'ipv6') {
|
||||
value = iterate_ips(value);
|
||||
}
|
||||
|
||||
if (!'translation' in data[key]) {
|
||||
continue;
|
||||
}
|
||||
key = data[key]['translation'];
|
||||
$row.append($('<td/>').text(key));
|
||||
if (typeof value === 'string' || Array.isArray(value)) {
|
||||
value = value.toString().split(",").join("<br/>");
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// skip any deeper nested structures
|
||||
let skip = false;
|
||||
for (let key in value) {
|
||||
if (typeof value[key] === 'object' && value !== null && !Array.isArray(value[key])) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table_sub = createTable(value);
|
||||
value = $table_sub.prop('outerHTML');
|
||||
}
|
||||
$row.append($('<td/>').html(value));
|
||||
$table_body.append($row);
|
||||
}
|
||||
|
||||
$table.append($table_body);
|
||||
$('[data-toggle="tooltip"]').tooltip({container: 'body', html:true});
|
||||
BootstrapDialog.show({
|
||||
title: data['description']['value'],
|
||||
message: $table.prop('outerHTML'),
|
||||
type: BootstrapDialog.TYPE_INFO,
|
||||
draggable: true,
|
||||
cssClass: 'details-dialog',
|
||||
buttons: [{
|
||||
label: "{{ lang._('Close') }}",
|
||||
action: function (dialogRef) {
|
||||
dialogRef.close();
|
||||
}
|
||||
}]
|
||||
});
|
||||
});
|
||||
},
|
||||
classname: 'fa fa-fw fa-search',
|
||||
title: "{{ lang._('Details') }}"
|
||||
}
|
||||
},
|
||||
options: {
|
||||
selection: false,
|
||||
formatters: {
|
||||
|
|
@ -169,134 +290,10 @@
|
|||
}
|
||||
return $elements.prop('outerHTML');
|
||||
},
|
||||
"commands": function (column, row) {
|
||||
let $commands = $('<div class="commands-td"></div>');
|
||||
let $btn = $('<button type="button" class="btn btn-xs btn-default command" data-toggle="tooltip"">\
|
||||
<i></i></button>');
|
||||
|
||||
/* reload action for dynamic configurations */
|
||||
if ('link_type' in row) {
|
||||
if (["dhcp", "pppoe", "pptp", "l2tp", "ppp"].includes(row.link_type)) {
|
||||
let $command = $btn.clone();
|
||||
$command.addClass('interface-reload').attr('title', 'Reload').attr('data-device-id', row.identifier);
|
||||
$command.find('i').addClass('fa fa-fw fa-refresh');
|
||||
$commands.append($command);
|
||||
}
|
||||
}
|
||||
|
||||
$anchor = $('<a class="btn btn-xs btn-default command" data-toggle="tooltip"><i></i></a>');
|
||||
if ('identifier' in row && row.identifier && 'config' in row && row.config) {
|
||||
if (!row.config.internal_dynamic) {
|
||||
$a_interfaces = $anchor.clone().attr('href', '/interfaces.php?if=' + row.identifier);
|
||||
$a_interfaces.attr('title', 'Settings');
|
||||
$a_interfaces.find('i').addClass('fa fa-fw fa-cog');
|
||||
$commands.append($a_interfaces);
|
||||
}
|
||||
|
||||
if (row.enabled) {
|
||||
$a_fw = $anchor.clone().attr('href', '/firewall_rules.php?if=' + row.identifier);
|
||||
$a_fw.attr('title', 'Firewall Rules');
|
||||
$a_fw.find('i').addClass('fa fa-fw fa-fire');
|
||||
$commands.append($a_fw);
|
||||
}
|
||||
}
|
||||
|
||||
$btn.addClass('interface-info').attr('title', 'Details').attr('data-row-id', row.device);
|
||||
$btn.find('i').addClass('fa fa-fw fa-search');
|
||||
|
||||
$commands.append($btn);
|
||||
return $commands.prop('outerHTML');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
).on("loaded.rs.jquery.bootgrid", function (e) {
|
||||
$('[data-toggle="tooltip"]').tooltip({container: 'body', html:true});
|
||||
|
||||
/* attach event handler to reload buttons */
|
||||
$('.interface-reload').each(function () {
|
||||
$(this).unbind('click').click(function () {
|
||||
let $element = $(this);
|
||||
let device = $(this).data("device-id");
|
||||
$element.remove('i').html('<i class="fa fa-spinner fa-spin"></i>');
|
||||
ajaxCall('/api/interfaces/overview/reload_interface/' + device, {}, function (data, status) {
|
||||
/* delay slightly to allow the interface to come up */
|
||||
setTimeout(function() {
|
||||
$element.remove('i').html('<i class="fa fa-fw fa-refresh"></i>');
|
||||
$("#grid-overview").bootgrid('reload');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* attach event handler to the command-info button */
|
||||
$(".interface-info").each(function () {
|
||||
$(this).unbind('click').click(function () {
|
||||
let $element = $(this);
|
||||
let device = $(this).data("row-id");
|
||||
|
||||
ajaxGet('/api/interfaces/overview/get_interface/' + device, {}, function(data, status) {
|
||||
data = data['message'];
|
||||
let $table = $('<table class="table table-bordered table-condensed table-hover table-striped"></table>');
|
||||
let $table_body = $('<tbody/>');
|
||||
|
||||
for (let key in data) {
|
||||
let $row = $('<tr/>');
|
||||
let value = data[key]['value'];
|
||||
if (key === 'line rate') {
|
||||
value = format_linerate(value.split(" ")[0]);
|
||||
}
|
||||
if (key === 'ipv4' || key === 'ipv6') {
|
||||
value = iterate_ips(value);
|
||||
}
|
||||
|
||||
if (!'translation' in data[key]) {
|
||||
continue;
|
||||
}
|
||||
key = data[key]['translation'];
|
||||
$row.append($('<td/>').text(key));
|
||||
if (typeof value === 'string' || Array.isArray(value)) {
|
||||
value = value.toString().split(",").join("<br/>");
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// skip any deeper nested structures
|
||||
let skip = false;
|
||||
for (let key in value) {
|
||||
if (typeof value[key] === 'object' && value !== null && !Array.isArray(value[key])) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table_sub = createTable(value);
|
||||
value = $table_sub.prop('outerHTML');
|
||||
}
|
||||
$row.append($('<td/>').html(value));
|
||||
$table_body.append($row);
|
||||
}
|
||||
|
||||
$table.append($table_body);
|
||||
$('[data-toggle="tooltip"]').tooltip({container: 'body', html:true});
|
||||
BootstrapDialog.show({
|
||||
title: data['description']['value'],
|
||||
message: $table.prop('outerHTML'),
|
||||
type: BootstrapDialog.TYPE_INFO,
|
||||
draggable: true,
|
||||
cssClass: 'details-dialog',
|
||||
buttons: [{
|
||||
label: "{{ lang._('Close') }}",
|
||||
action: function (dialogRef) {
|
||||
dialogRef.close();
|
||||
}
|
||||
}]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$(".route-container").each(function () {
|
||||
let $route_container = $(this);
|
||||
let count = $(this).children('.route-content').length;
|
||||
|
|
|
|||
|
|
@ -953,7 +953,7 @@ class UIBootgrid {
|
|||
// to the parent so no handlers on parent containers are executed
|
||||
$selector.unbind('click').on("click", function (event) {
|
||||
event.stopPropagation();
|
||||
commands[command].method?.bind(this)(event);
|
||||
commands[command].method?.bind(this)(event, cell);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1556,7 +1556,7 @@ class UIBootgrid {
|
|||
* register commands
|
||||
*
|
||||
* The command object can have the following properties:
|
||||
* - method: a function that is executed on command click
|
||||
* - method: a function that is executed on command click. function signature is (event, cell)
|
||||
* - title: translated title to be shown as a tooltip. Can be a function with the cell object as param
|
||||
* - requires: an array of strings marking which this.crud properties are required
|
||||
* - sequence: order of commands rendering
|
||||
|
|
|
|||
Loading…
Reference in a new issue