%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/mvc/app/views/OPNsense/Interface/ |
Current File : //backups/router/usr/local/opnsense/mvc/app/views/OPNsense/Interface/overview.volt |
{# # Copyright (c) 2023 Deciso B.V. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #} <script> $( document ).ready(function() { function createTable(data) { let table = $('<table class="table table-condensed">'); let headerRow = $('<tr>'); table.append(headerRow); // Create table headers for (let key in data) { if (data.hasOwnProperty(key)) { headerRow.append($('<th>').text(key)); } } // Create table rows let dataRow = $('<tr>'); for (let key in data) { if (data.hasOwnProperty(key)) { let value = data[key]; if (Array.isArray(value)) { // If the value is an array, join the elements with a newline value = value.join('<br>'); } dataRow.append($('<td>').html(value)); } } table.append(dataRow); return table; } function format_linerate(value) { if (!isNaN(value) && value > 0) { let fileSizeTypes = ["", "K", "M", "G", "T", "P", "E", "Z", "Y"]; let ndx = Math.floor(Math.log(value) / Math.log(1000) ); if (ndx > 0) { return (value / Math.pow(1000, ndx)).toFixed(2) + ' ' + fileSizeTypes[ndx] + 'bit/s'; } else { return value.toFixed(2).toString(); } } else { return ""; } } function iterate_ips(obj) { let $elements = $('<div></div>'); 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']; } $carp.attr('title', title_text); $span.append($carp); } $elements.append($span); }); return $elements.prop('outerHTML'); } $("#grid-overview").UIBootgrid( { search: '/api/interfaces/overview/interfacesInfo', options: { selection: false, formatters: { "interface": function (column, row) { let descr = row.description; if (row.identifier) { descr += ' (' + row.identifier + ')'; } return descr; }, "vlan": function (column, row) { if (row.vlan_tag) { let $tooltip = $('<span></span>').attr('class', 'bootgrid-tooltip').text(row.vlan_tag); $tooltip.attr('data-toggle', 'tooltip'); let standard = row.vlan.proto && row.vlan.proto == "802.1q" ? "QinQ" : "VLAN"; let parent = row.vlan.parent ? row.vlan.parent : 'none'; $tooltip.attr('title', standard + ' ' + row.vlan_tag + ' / Parent: ' + parent); return $tooltip.prop('outerHTML'); } return ''; }, "routes": function (column, row) { let $elements = $('<div></div>').attr('class', 'route-container'); if (row.routes) { let i = 0; row.routes.forEach(function (route) { let $route = $('<span></span>').attr('class', 'route-content').text(route); if (route == 'default') { $route.css('color', 'green'); } if (i > 1) { $route.css("display", "none"); } $elements.append($route.append($('<br/>'))); i++; }); $elements.append($('<button></button>') .attr('class', 'route-expand btn btn-primary btn-xs') .text('Expand')); } return $elements.prop('outerHTML'); }, "status": function (column, row) { let connected = row.status == 'up' ? 'text-success' : 'text-danger'; if (!row.enabled) { row.status += ' (disabled)'; } return '<i class="fa fa-plug ' + connected + '" title="' + row.status + '" data-toggle="tooltip"></i>'; }, "ipv4": function (column, row) { if (row.ipv4) { return iterate_ips(row.ipv4); } return ''; }, "ipv6": function (column, row) { if (row.ipv6) { return iterate_ips(row.ipv6); } return ''; }, "gateways": function (column, row) { let $elements = $('<div></div>'); if (row.gateways) { row.gateways.forEach(function (gw) { let $span = $('<span></span><br/>').text(gw); $elements.append($span); }); } 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({html:true}); /* attach event handler to reload buttons */ $('.interface-reload').each(function () { $(this).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/reloadInterface/' + 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).click(function () { let $element = $(this); let device = $(this).data("row-id"); ajaxGet('/api/interfaces/overview/getInterface/' + 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({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; let $expand = $(this).find(".route-expand"); if (count > 2) { $expand.show(); } $expand.click(function () { let $collapsed = $route_container.children('.route-content').filter(function() { return $(this).css('display').toLowerCase().indexOf('none') > -1; }); if ($collapsed.length > 0) { $collapsed.show(); $expand.html('Collapse'); } else { $collapse = $route_container.children('.route-content').slice(2); $collapse.hide(); $expand.html('Expand'); } }); }); }); $("#export-wrapper").detach().appendTo('#grid-overview-header > .row > .actionBar > .btn-group'); $("#export").click(function () { $('<a></a>').attr('href', '/api/interfaces/overview/export').get(0).click(); }); }); </script> <style> .route-content { white-space: pre-line; text-overflow: ellipsis; overflow: hidden; } .route-expand { display: none; } .bootgrid-table { table-layout: auto; } .bootgrid-table td { text-align: center; vertical-align: middle; } .commands-td { text-align: right; vertical-align: middle; } .command { margin-left: 0.3em; } .bootgrid-table th { text-align: center; vertical-align: middle; } .details-dialog .modal-dialog{ position: relative; display: table; overflow-y: auto; overflow-x: auto; width: auto; min-width: 600px; } .details-dialog .modal-body { height: 60vh; overflow-y: auto; } </style> <div class="tab-content content-box"> <div id="export-wrapper" class="btn-group"> <button id="export" class="btn btn-default" data-toggle="tooltip" title="" type="button" data-original-title="Download overview (json)"> <span class="fa fa-cloud-download"></span> </button> </div> <table id="grid-overview" class="table table-bordered table-condensed table-hover table-striped"> <thead> <tr> <th data-column-id="status" data-width="5em" data-formatter="status" data-type="string">{{ lang._('Status') }}</th> <th data-column-id="description" data-formatter="interface" data-type="string">{{ lang._('Interface') }}</th> <th data-column-id="device" data-identifier="true" data-width="5em" data-type="string">{{ lang._('Device') }}</th> <th data-column-id="vlan_tag" data-formatter="vlan" data-type="string" data-width="3em">{{ lang._('VLAN') }}</th> <th data-column-id="link_type" data-type="string">{{ lang._('Link Type') }}</th> <th data-column-id="ipv4" data-formatter="ipv4" data-type="string">{{ lang._('IPv4') }}</th> <th data-column-id="ipv6" data-formatter="ipv6" data-type="string">{{ lang._('IPv6') }}</th> <th data-column-id="gateways" data-formatter="gateways" data-type="string">{{ lang._('Gateway') }}</th> <th data-column-id="routes" data-formatter="routes" data-type="string">{{ lang._('Routes') }}</th> <th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th> </tr> </thead> <tbody> </tbody> <tfoot> </tfoot> </table> </div>