mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
1060 lines
55 KiB
HTML
1060 lines
55 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link href="/vendor/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="/vendor/solid.min.css">
|
|
<link rel="stylesheet" href="/lqos.css">
|
|
<link rel="icon" href="/favicon.png">
|
|
<title>LibreQoS - Local Node Manager</title>
|
|
<script src="/lqos.js"></script>
|
|
<script src="/vendor/plotly-2.16.1.min.js"></script>
|
|
<script src="/vendor/jquery.min.js"></script><script src="/vendor/msgpack.min.js"></script>
|
|
<script defer src="/vendor/bootstrap.bundle.min.js"></script>
|
|
</head>
|
|
<body class="bg-secondary">
|
|
<!-- Navigation -->
|
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
<div class="container-fluid">
|
|
<a class="navbar-brand" href="/"><img src="/vendor/tinylogo.svg" alt="LibreQoS SVG Logo" width="25" height="25" /> LibreQoS</a>
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="/tree?parent=0"><i class="fa fa-tree"></i> Tree</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" aria-current="page" href="/shaped"><i class="fa fa-users"></i> Shaped Devices <span id="shapedCount" class="badge badge-pill badge-success green-badge">?</span></a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="/unknown"><i class="fa fa-address-card"></i> Unknown IPs <span id="unshapedCount" class="badge badge-warning orange-badge">?</span></a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<ul class="navbar-nav ms-auto">
|
|
<li class="nav-item" id="currentLogin"></li>
|
|
<li class="nav-item ms-auto">
|
|
<a class="nav-link active" href="/config"><i class="fa fa-gear"></i> Configuration</a>
|
|
</li>
|
|
<li>
|
|
<a class="nav-link btn btn-small black-txt" href="#" id="btnReload"><i class="fa fa-refresh"></i> Reload LibreQoS</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div id="container" class="pad4">
|
|
|
|
<div class="row">
|
|
<div class="col-sm-1"></div>
|
|
<div class="col-sm-12">
|
|
<div class="card bg-light">
|
|
<div class="card-body">
|
|
<h5 class="card-title"><i class="fa fa-users"></i> Configuration</h5>
|
|
|
|
<div class="col-sm-8 mx-auto" class="pad4 mbot4" id="controls">
|
|
<a href="#" class="btn btn-primary" id="btnSaveIspConfig"><i class="fa fa-save"></i> Save Configuration</a>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-start">
|
|
<div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
|
<button class="nav-link active" id="v-pills-display-tab" data-bs-toggle="pill" data-bs-target="#v-pills-display" type="button" role="tab" aria-controls="v-pills-home" aria-selected="true"><i class="fa fa-tv"></i> Display</button>
|
|
<button class="nav-link" id="v-pills-home-tab" data-bs-toggle="pill" data-bs-target="#v-pills-home" type="button" role="tab" aria-controls="v-pills-home" aria-selected="true"><i class="fa fa-server"></i> General</button>
|
|
<button class="nav-link" id="v-pills-anon-tab" data-bs-toggle="pill" data-bs-target="#v-pills-anon" type="button" role="tab" aria-controls="v-pills-profile" aria-selected="false"><i class="fa fa-user-secret"></i> Anonymous Usage Stats</button>
|
|
<button class="nav-link" id="v-pills-tuning-tab" data-bs-toggle="pill" data-bs-target="#v-pills-tuning" type="button" role="tab" aria-controls="v-pills-server" aria-selected="false"><i class="fa fa-warning"></i> Tuning</button>
|
|
<button class="nav-link" id="v-pills-bridge-tab" data-bs-toggle="pill" data-bs-target="#v-pills-bridge" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-chain"></i> Bridge/On-a-Stick</button>
|
|
<button class="nav-link" id="v-pills-queues-tab" data-bs-toggle="pill" data-bs-target="#v-pills-queues" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-car"></i> Queues</button>
|
|
<button class="nav-link" id="v-pills-lts-tab" data-bs-toggle="pill" data-bs-target="#v-pills-lts" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-line-chart"></i> Long-Term Stats</button>
|
|
<button class="nav-link" id="v-pills-iprange-tab" data-bs-toggle="pill" data-bs-target="#v-pills-iprange" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-address-card"></i> IP Ranges</button>
|
|
<button class="nav-link" id="v-pills-flows-tab" data-bs-toggle="pill" data-bs-target="#v-pills-flows" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-arrow-circle-down"></i> Flow Tracking</button>
|
|
<button class="nav-link" id="v-pills-icommon-tab" data-bs-toggle="pill" data-bs-target="#v-pills-icommon" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-link"></i> Integration - Common</button>
|
|
<button class="nav-link" id="v-pills-spylnx-tab" data-bs-toggle="pill" data-bs-target="#v-pills-spylnx" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-link"></i> Spylnx</button>
|
|
<button class="nav-link" id="v-pills-uisp-tab" data-bs-toggle="pill" data-bs-target="#v-pills-uisp" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-link"></i> UISP</button>
|
|
<button class="nav-link" id="v-pills-powercode-tab" data-bs-toggle="pill" data-bs-target="#v-pills-powercode" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-link"></i> Powercode</button>
|
|
<button class="nav-link" id="v-pills-sonar-tab" data-bs-toggle="pill" data-bs-target="#v-pills-sonar" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-link"></i> Sonar</button>
|
|
<button class="nav-link" id="v-pills-influxdb-tab" data-bs-toggle="pill" data-bs-target="#v-pills-influxdb" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-link"></i> InfluxDB</button>
|
|
<button class="nav-link" id="v-pills-netjson-tab" data-bs-toggle="pill" data-bs-target="#v-pills-netjson" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-map"></i> Network Layout</button>
|
|
<button class="nav-link" id="v-pills-shapeddevs-tab" data-bs-toggle="pill" data-bs-target="#v-pills-shapeddevs" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-table"></i> Shaped Devices</button>
|
|
<button class="nav-link" id="v-pills-users-tab" data-bs-toggle="pill" data-bs-target="#v-pills-users" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false"><i class="fa fa-users"></i> LibreQoS Users</button>
|
|
</div>
|
|
<div class="tab-content" id="v-pills-tabContent">
|
|
<!-- Tabbed config elements -->
|
|
<div class="tab-pane fade show active" id="v-pills-display" role="tabpanel" aria-labelledby="v-pills-display-tab">
|
|
<h2><i class="fa fa-wifi"></i> Display Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td>
|
|
<p class="alert alert-info" role="alert">
|
|
<i class="fa fa-info"></i> The settings on this tab are per-computer and are stored locally in your browser's "local storage".
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<input class="form-check-input" type="checkbox" id="redact">
|
|
<label class="form-check-label" for="redact">
|
|
Redact Customer Information (screenshot mode)
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<select id="colorMode">
|
|
<option id="0">Regular Colors</option>
|
|
<option id="1">Metaverse Colors</option>
|
|
</select>
|
|
<label class="form-select-label" for="colorMode">
|
|
RTT Color Mode
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a class="btn btn-primary" id="applyDisplay">Apply Changes</a></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- General tab -->
|
|
<div class="tab-pane fade" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
|
|
<h2><i class="fa fa-server"></i> General Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindVersion">Version: </label></td>
|
|
<td><input type="text" id="bindVersion" style="background: #ddd" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindPath">Path to LibreQoS: </label></td>
|
|
<td><input type="text" id="bindPath" style="width: 500px" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindNodeId">Node ID: </label></td>
|
|
<td><input type="text" id="bindNodeId" style="width: 500px" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindNodeName">Node Name: </label></td>
|
|
<td><input type="text" id="bindNodeName" style="width: 500px" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindPacketCaptureTime">Packet Capture Time: </label></td>
|
|
<td><input type="number" min="1" max="300" id="bindPacketCaptureTime" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindQueueCheckPeriodMs">Queue Check Period (ms): </label></td>
|
|
<td><input type="number" min="10" max="5000" id="bindQueueCheckPeriodMs" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Anonymous Usage tab -->
|
|
<div class="tab-pane fade" id="v-pills-anon" role="tabpanel" aria-labelledby="v-pills-anon-tab">
|
|
<h2><i class="fa fa-user-secret"></i>Anonymous Usage Statistics Settings</h2>
|
|
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindSendAnonymous">Send Anonymous Stats: </label></td>
|
|
<td><input type="checkbox" id="bindSendAnonymous" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindAnonymousServer">Anonymous Stats Server: </label></td>
|
|
<td><input type="text" id="bindAnonymousServer" style="width: 500px" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Tuning tab -->
|
|
<div class="tab-pane fade" id="v-pills-tuning" role="tabpanel" aria-labelledby="v-pills-tuning-tab">
|
|
<h2><i class="fa fa-warning"></i> Tuning Settings</h2>
|
|
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindStopIrqBalance">Stop IRQ Balancer: </label></td>
|
|
<td><input type="checkbox" id="bindStopIrqBalance" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindNetdevBudgetUs">Netdev Budget (usecs): </label></td>
|
|
<td><input type="number" id="bindNetdevBudgetUs" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindNetdevBudgetPackets">Netdev Budget (packets): </label></td>
|
|
<td><input type="number" id="bindNetdevBudgetPackets" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindRxUs">Rx Period (usecs): </label></td>
|
|
<td><input type="number" id="bindRxUs" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindTxUs">Tx Period (usecs): </label></td>
|
|
<td><input type="number" id="bindTxUs" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindDisableRxVlan">Disable RxVlan Offload: </label></td>
|
|
<td><input type="checkbox" id="bindDisableRxVlan" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindDisableTxVlan">Disable TxVlan Offload: </label></td>
|
|
<td><input type="checkbox" id="bindDisableTxVlan" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindDisableOffload">Offloads to Disable: </label></td>
|
|
<td><input type="text" id="bindDisableOffload" style="width: 500px" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Bridge/On-a-Stick tab -->
|
|
<div class="tab-pane fade" id="v-pills-bridge" role="tabpanel" aria-labelledby="v-pills-bridge-tab">
|
|
<h2><i class="fa fa-chain"></i> Bridge Settings</h2>
|
|
|
|
<h3>Connection Mode: </h3>
|
|
<input type="radio" name="bridgeMode" value="bridge" id="radioBridge" onclick="setBridgeMode();">
|
|
<label for="radioBridge">Bridge Mode</label>
|
|
<br />
|
|
<input type="radio" name="bridgeMode" value="onatick" id="radioOnAStick" onclick="setStickMode();">
|
|
<label for="radioOnAStick">Single-Interface Mode</label>
|
|
<br />
|
|
<hr />
|
|
|
|
<div id="bridgeMode">
|
|
<h3>Bridge Mode</h3>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindUseXdpBridge">Use XDP Enhanced Bridge: </label></td>
|
|
<td><input type="checkbox" id="bindUseXdpBridge" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindBridgeToInternet">Network Interface Facing the Internet: </label></td>
|
|
<td><select id="bindBridgeToInternet"></select></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindBridgeToNetwork">Network Interface Facing Your Network: </label></td>
|
|
<td><select id="bindBridgeToNetwork"></select></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div id="OnAStickMode">
|
|
<h3>Single-Interface ("On a Stick") Mode</h3>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindSingleInterfaceNic">Network Interface: </label></td>
|
|
<td><select id="bindSingleInterfaceNic"></select></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSingleInterfaceInternetVlan">Internet VLAN: </label></td>
|
|
<td><input type="number" min="1" max="65535" id="bindSingleInterfaceInternetVlan" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSingleInterfaceNetworklan">Network VLAN: </label></td>
|
|
<td><input type="number" min="1" max="65535" id="bindSingleInterfaceNetworklan" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Queues Tab -->
|
|
<div class="tab-pane fade" id="v-pills-queues" role="tabpanel" aria-labelledby="v-pills-queues-tab">
|
|
<h2><i class="fa car"></i> Queue Settings</h2>
|
|
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindSqm">SQM Mode: </label></td>
|
|
<td>
|
|
<select id="bindSqm">
|
|
<option value="cake diffserv4">Cake with Diffserv4</option>
|
|
<option value="cake diffserv4 ack-filter">Cake with Diffserv4 + Duplicate ACK Filtering</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindMonitorMode">Monitor Only Mode (No Shaping): </label></td>
|
|
<td><input type="checkbox" id="bindMonitorMode" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUplinkMbps">Uplink Bandwidth (Mbps): </label></td>
|
|
<td><input type="number" id="bindUplinkMbps" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindDownlinkMbps">Downlink Bandwidth (Mbps): </label></td>
|
|
<td><input type="number" id="bindDownlinkMbps" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindGeneratedDownlinkMbps">Generated PN Download Bandwidth (Mbps): </label></td>
|
|
<td><input type="number" id="bindGeneratedDownlinkMbps" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindGeneratedUplinkMbps">Generated PN Upload Bandwidth (Mbps): </label></td>
|
|
<td><input type="number" id="bindGeneratedUplinkMbps" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindDryRun">Dry Run (Don't Make Queues): </label></td>
|
|
<td><input type="checkbox" id="bindDryRun" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSudo">Use Sudo: </label></td>
|
|
<td><input type="checkbox" id="bindSudo" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindBinpack">Use Binpacking to equalize CPU usage: </label></td>
|
|
<td><input type="checkbox" id="bindBinpack" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindQueuesAvailableOverride">Queues Available Override: </label></td>
|
|
<td><input type="number" id="bindQueuesAvailableOverride" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Long-Term Stats Tab -->
|
|
<div class="tab-pane fade" id="v-pills-lts" role="tabpanel" aria-labelledby="v-pills-lts-tab">
|
|
<h2><i class="fa fa-line-chart"></i> Long-Term Stats Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindEnableLTS">Send Statistics to Long-Term Stats: </label></td>
|
|
<td><input type="checkbox" id="bindEnableLTS" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindLtsCollation">Collation Period (seconds): </label></td>
|
|
<td><input type="number" id="bindLtsCollation" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindLtsLicense">License Key: </label></td>
|
|
<td><input type="text" id="bindLtsLicense" style="width: 500px" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindLtsUispInterval">UISP Reporting Interval (Seconds): </label></td>
|
|
<td><input type="number" id="bindLtsUispInterval" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- IP Ranges Stats Tab -->
|
|
<div class="tab-pane fade" id="v-pills-iprange" role="tabpanel" aria-labelledby="v-pills-iprange-tab">
|
|
<h2><i class="fa fa-address-card"></i> IP Ranges Settings</h2>
|
|
<table>
|
|
<tr>
|
|
<td><label for="bindIgnoreRanges">IP Subnets to Ignore</label></td>
|
|
<td>
|
|
<em>Enter one IP range per Line</em><br />
|
|
<textarea id="bindIgnoreRanges" rows="10" cols="40"></textarea>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindAllowRanges">IP Ranges to Allow</label></td>
|
|
<td>
|
|
<em>Enter one IP range per Line</em><br />
|
|
<textarea id="bindAllowRanges" rows="10" cols="40"></textarea>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Flows Tab -->
|
|
<div class="tab-pane fade" id="v-pills-flows" role="tabpanel" aria-labelledby="v-pills-flow-tab">
|
|
<h2><i class="fa fa-arrow-circle-down"></i> Flows Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindFlowsTimeout">Flow Timeout (Seconds): </label></td>
|
|
<td><input type="number" id="bindFlowsTimeout" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindEnableNetflow">Enable Netflow Collection: </label></td>
|
|
<td><input type="checkbox" id="bindEnableNetflow" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindFlowsPort">Netflow Port Number: </label></td>
|
|
<td><input type="number" id="bindFlowsPort" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindFlowsTarget">Send Netflow to IP: </label></td>
|
|
<td><input type="text" id="bindFlowsTarget" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindFlowsVersion">Netflow Version: </label></td>
|
|
<td>
|
|
<select id="bindFlowsVersion">
|
|
<option value="5">Netflow v5 - fast, but IPv4 only</option>
|
|
<option value="9">Netflow v6/IPFIX</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Integration Common Tab -->
|
|
<div class="tab-pane fade" id="v-pills-icommon" role="tabpanel" aria-labelledby="v-pills-icommon-tab">
|
|
<h2><i class="fa fa-link"></i> Common Integration Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindCircuitNameAsAddress">Use Circuit Name as Address: </label></td>
|
|
<td><input type="checkbox" id="bindCircuitNameAsAddress" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindOverwriteNetJson">Always Overwrite Network.json: </label></td>
|
|
<td><input type="checkbox" id="bindOverwriteNetJson" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindQueueRefreshInterval">Queue Refresh Interval (Minutes): </label></td>
|
|
<td><input type="number" id="bindQueueRefreshInterval" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Spylnx Tab -->
|
|
<div class="tab-pane fade" id="v-pills-spylnx" role="tabpanel" aria-labelledby="v-pills-spylnx-tab">
|
|
<h2><i class="fa fa-link"></i> Spylnx Integration Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindSplynxEnable">Enable Spylnx Integration: </label></td>
|
|
<td><input type="checkbox" id="bindSplynxEnable" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSplynxApiKey">API Key: </label></td>
|
|
<td><input type="text" id="bindSplynxApiKey" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSplynxApiSecret">API Secret: </label></td>
|
|
<td><input type="text" id="bindSplynxApiSecret" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSplynxApiUrl">API URL: </label></td>
|
|
<td><input type="text" id="bindSplynxApiUrl" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- UISP Tab -->
|
|
<div class="tab-pane fade" id="v-pills-uisp" role="tabpanel" aria-labelledby="v-pills-uisp-tab">
|
|
<h2><i class="fa fa-link"></i> UISP Integration Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindUispEnable">Enable UISP Integration: </label></td>
|
|
<td><input type="checkbox" id="bindUispEnable" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispToken">UISP Token: </label></td>
|
|
<td><input type="text" id="bindUispToken" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispUrl">UISP URL: </label></td>
|
|
<td><input type="text" id="bindUispUrl" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispSite">Root Site Name (for 'full' integrations): </label></td>
|
|
<td><input type="text" id="bindUispSite" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispStrategy">Generation Strategy: </label></td>
|
|
<td>
|
|
<select id="bindUispStrategy">
|
|
<option value="flat">Flat: no topology</option>
|
|
<option value="full">Full: construct a full hierarchy</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispSuspended">Suspended Customer Strategy: </label></td>
|
|
<td>
|
|
<select id="bindUispSuspended">
|
|
<option value="none">Do Nothing</option>
|
|
<option value="slow">Apply a Slow Speed</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispAirmaxCapacity">Airmax Capacity Multiplier: </label></td>
|
|
<td><input type="text" id="bindUispAirmaxCapacity" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispLtuCapacity">LTU Capacity Multiplier: </label></td>
|
|
<td><input type="text" id="bindUispLtuCapacity" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispIpv6Mikrotik">Query Mikrotiks for IPv6 Information: </label></td>
|
|
<td><input type="checkbox" id="bindUispIpv6Mikrotik" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispOverheadFactor">Bandwidth Overhead Factor: </label></td>
|
|
<td><input type="text" id="bindUispOverheadFactor" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispCommitMultiplier">Commit Bandwidth Multiplier: </label></td>
|
|
<td><input type="text" id="bindUispCommitMultiplier" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispExcludeSites">Exclude Sites: </label></td>
|
|
<td><input type="text" id="bindUispExcludeSites" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispExceptionCpes">Exception CPEs: </label></td>
|
|
<td><input type="text" id="bindUispExceptionCpes" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindUispUsePtmpAsParent">Use PTMP As Parent: </label></td>
|
|
<td><input type="checkbox" id="bindUispUsePtmpAsParent" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Powercode Tab -->
|
|
<div class="tab-pane fade" id="v-pills-powercode" role="tabpanel" aria-labelledby="v-pills-powercode-tab">
|
|
<h2><i class="fa fa-link"></i> Powercode Integration Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindPowercodeEnable">Enable Powercode Integration: </label></td>
|
|
<td><input type="checkbox" id="bindPowercodeEnable" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindPowercodeKey">Powercode API Key: </label></td>
|
|
<td><input type="text" id="bindPowercodeKey" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindPowercodeUrl">Powercode API URL: </label></td>
|
|
<td><input type="text" id="bindPowercodeUrl" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Sonar Tab -->
|
|
<div class="tab-pane fade" id="v-pills-sonar" role="tabpanel" aria-labelledby="v-pills-sonar-tab">
|
|
<h2><i class="fa fa-link"></i> Sonar Integration Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindSonarEnable">Enable Sonar Integration: </label></td>
|
|
<td><input type="checkbox" id="bindSonarEnable" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSonarApiKey">Sonar API Key: </label></td>
|
|
<td><input type="text" id="bindSonarApiKey" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSonarApiUrl">Sonar API URL: </label></td>
|
|
<td><input type="text" id="bindSonarApiUrl" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSonarSnmp">Sonar SNMP Community: </label></td>
|
|
<td><input type="text" id="bindSonarSnmp" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSonarAirmax">Sonar Airmax Model IDs: </label></td>
|
|
<td><input type="text" id="bindSonarAirmax" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSonarLtu">Sonar LTU Model IDs: </label></td>
|
|
<td><input type="text" id="bindSonarLtu" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindSonarActive">Sonar Active Status IDs: </label></td>
|
|
<td><input type="text" id="bindSonarActive" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- InfluxDB Tab -->
|
|
<div class="tab-pane fade" id="v-pills-influxdb" role="tabpanel" aria-labelledby="v-pills-influxdb-tab">
|
|
<h2><i class="fa fa-link"></i> InfluxDB Integration Settings</h2>
|
|
<table class="table">
|
|
<tr>
|
|
<td><label for="bindInfluxEnable">Enable InfluxDB Integration: </label></td>
|
|
<td><input type="checkbox" id="bindInfluxEnable" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindInfluxUrl">InfluxDB URL: </label></td>
|
|
<td><input type="text" id="bindInfluxUrl" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindInfluxOrg">InfluxDB Organization: </label></td>
|
|
<td><input type="text" id="bindInfluxOrg" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindInfluxBucket">InfluxDB Bucket: </label></td>
|
|
<td><input type="text" id="bindInfluxBucket" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="bindInfluxToken">InfluxDB Token: </label></td>
|
|
<td><input type="text" id="bindInfluxToken" /></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Network Layout/JSON Tab -->
|
|
<div class="tab-pane fade" id="v-pills-netjson" role="tabpanel" aria-labelledby="v-pills-netjson-tab">
|
|
<h2><i class="fa fa-map"></i> Network.Json - Network Layout</h2>
|
|
<div id="netjson"></div>
|
|
</div>
|
|
|
|
<!-- ShapedDevices.csv Tab -->
|
|
<div class="tab-pane fade" id="v-pills-shapeddevs" role="tabpanel" aria-labelledby="v-pills-shapeddevs-tab">
|
|
<h2><i class="fa table"></i> Shaped Devices</h2>
|
|
<p>All Shaped Devices. Note that if you have an integration enabled, this will be overwritten periodically.</p>
|
|
<div id="shapedDeviceTable"></div>
|
|
</div>
|
|
|
|
<div class="tab-pane fade" id="v-pills-users" role="tabpanel" aria-labelledby="v-pills-users-tab">
|
|
<h2><i class="fa fa-users"></i> LibreQos Web Interface Users</h2>
|
|
<div id="userManager"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<footer>© 2022-2023, LibreQoE LLC</footer>
|
|
|
|
<script>
|
|
let nics = null;
|
|
let lqosd_config = null;
|
|
let shaped_devices = null;
|
|
let network_json = null;
|
|
|
|
const bindings = [
|
|
// General
|
|
{ field: "bindVersion", path: ".version", data: "string", editable: false },
|
|
{ field: "bindPath", path: ".lqos_directory", data: "string", editable: true },
|
|
{ field: "bindNodeId", path: ".node_id", data: "string", editable: true },
|
|
{ field: "bindNodeName", path: ".node_name", data: "string", editable: true },
|
|
{ field: "bindPacketCaptureTime", path: ".packet_capture_time", data: "integer", editable: true },
|
|
{ field: "bindQueueCheckPeriodMs", path: ".queue_check_period_ms", data: "integer", editable: true },
|
|
|
|
// Anonymous Usage
|
|
{ field: "bindSendAnonymous", path: ".usage_stats.send_anonymous", data: "bool", editable: true },
|
|
{ field: "bindAnonymousServer", path: ".usage_stats.anonymous_server", data: "string", editable: true },
|
|
|
|
// Tuning
|
|
{ field: "bindStopIrqBalance", path: ".tuning.stop_irq_balance", data: "bool", editable: true },
|
|
{ field: "bindNetdevBudgetUs", path: ".tuning.netdev_budget_usecs", data: "integer", editable: true },
|
|
{ field: "bindNetdevBudgetPackets", path: ".tuning.netdev_budget_packets", data: "integer", editable: true },
|
|
{ field: "bindRxUs", path: ".tuning.rx_usecs", data: "integer", editable: true },
|
|
{ field: "bindTxUs", path: ".tuning.tx_usecs", data: "integer", editable: true },
|
|
{ field: "bindDisableRxVlan", path: ".tuning.disable_rxvlan", data: "bool", editable: true },
|
|
{ field: "bindDisableTxVlan", path: ".tuning.disable_txvlan", data: "bool", editable: true },
|
|
{ field: "bindDisableOffload", path: ".tuning.disable_offload", data: "array_of_strings", editable: true },
|
|
|
|
// Bridge/Stick
|
|
{ conditional: true, condition: "if_exists", path: ".bridge", showDiv: "bridgeMode", hideDiv: "OnAStickMode" },
|
|
{ field: "bindUseXdpBridge", path: ".bridge.use_xdp_bridge", data: "bool", editable: true },
|
|
{ field: "bindBridgeToInternet", path: ".bridge.to_internet", data: "interface", editable: true },
|
|
{ field: "bindBridgeToNetwork", path: ".bridge.to_network", data: "interface", editable: true },
|
|
{ end_conditional: true },
|
|
{ conditional: true, condition: "if_exists", path: ".single_interface", showDiv: "OnAStickMode", hideDiv: "bridgeMode" },
|
|
{ field: "bindSingleInterfaceNic", path: ".single_interface.interface", data: "interface", editable: true },
|
|
{ field: "bindSingleInterfaceInternetVlan", path: ".single_interface.internet_vlan", data: "integer", editable: true },
|
|
{ field: "bindSingleInterfaceNetworklan", path: ".single_interface.network_vlan", data: "integer", editable: true },
|
|
{ end_conditional: true },
|
|
|
|
// Queues
|
|
{ field: "bindSqm", path: ".queues.default_sqm", data: "select-premade", editable: true },
|
|
{ field: "bindMonitorMode", path: ".queues.monitor_only", data: "bool", editable: true },
|
|
{ field: "bindUplinkMbps", path: ".queues.uplink_bandwidth_mbps", data: "integer", editable: true },
|
|
{ field: "bindDownlinkMbps", path: ".queues.downlink_bandwidth_mbps", data: "integer", editable: true },
|
|
{ field: "bindGeneratedDownlinkMbps", path: ".queues.generated_pn_download_mbps", data: "integer", editable: true },
|
|
{ field: "bindGeneratedUplinkMbps", path: ".queues.generated_pn_upload_mbps", data: "integer", editable: true },
|
|
{ field: "bindDryRun", path: ".queues.dry_run", data: "bool", editable: true },
|
|
{ field: "bindSudo", path: ".queues.sudo", data: "bool", editable: true },
|
|
{ field: "bindBinpack", path: ".queues.use_binpacking", data: "bool", editable: true },
|
|
{ field: "bindQueuesAvailableOverride", path: ".queues.override_available_queues", data: "integer", editable: true },
|
|
|
|
// LTS
|
|
{ field: "bindEnableLTS", path: ".long_term_stats.gather_stats", data: "bool", editable: true },
|
|
{ field: "bindLtsCollation", path: ".long_term_stats.collation_period_seconds", data: "integer", editable: true },
|
|
{ field: "bindLtsLicense", path: ".long_term_stats.license_key", data: "string", editable: true },
|
|
{ field: "bindLtsUispInterval", path: ".long_term_stats.uisp_reporting_interval_seconds", data: "integer", editable: true },
|
|
|
|
// IP Ranges
|
|
{ field: "bindIgnoreRanges", path: ".ip_ranges.ignore_subnets", data: "ip_array", editable: true },
|
|
{ field: "bindAllowRanges", path: ".ip_ranges.allow_subnets", data: "ip_array", editable: true },
|
|
|
|
// Flow tracking
|
|
{ field: "bindFlowsTimeout", path: ".flows.flow_timeout_seconds", data: "integer", editable: true },
|
|
{ field: "bindEnableNetflow", path: ".flows.netflow_enabled", data: "bool", editable: true },
|
|
{ field: "bindFlowsPort", path: ".flows.netflow_port", data: "integer", editable: true },
|
|
{ field: "bindFlowsTarget", path: ".flows.netflow_ip", data: "string", editable: true },
|
|
{ field: "bindFlowsVersion", path: ".flows.netflow_ip", data: "select-premade", editable: true },
|
|
|
|
// Integration Common
|
|
{ field: "bindCircuitNameAsAddress", path: ".integration_common.circuit_name_as_address", data: "bool", editable: true },
|
|
{ field: "bindOverwriteNetJson", path: ".integration_common.always_overwrite_network_json", data: "bool", editable: true },
|
|
{ field: "bindQueueRefreshInterval", path: ".integration_common.queue_refresh_interval_mins", data: "integer", editable: true },
|
|
|
|
// Splynx
|
|
{ field: "bindSplynxEnable", path: ".spylnx_integration.enable_spylnx", data: "bool", editable: true },
|
|
{ field: "bindSplynxApiKey", path: ".spylnx_integration.api_key", data: "string", editable: true },
|
|
{ field: "bindSplynxApiSecret", path: ".spylnx_integration.api_secret", data: "string", editable: true },
|
|
{ field: "bindSplynxApiUrl", path: ".spylnx_integration.url", data: "string", editable: true },
|
|
|
|
// UISP
|
|
{ field: "bindUispEnable", path: ".uisp_integration.enable_uisp", data: "bool", editable: true },
|
|
{ field: "bindUispToken", path: ".uisp_integration.token", data: "string", editable: true },
|
|
{ field: "bindUispUrl", path: ".uisp_integration.url", data: "string", editable: true },
|
|
{ field: "bindUispSite", path: ".uisp_integration.site", data: "string", editable: true },
|
|
{ field: "bindUispStrategy", path: ".uisp_integration.strategy", data: "select-premade", editable: true },
|
|
{ field: "bindUispSuspended", path: ".uisp_integration.suspended_strategy", data: "select-premade", editable: true },
|
|
{ field: "bindUispAirmaxCapacity", path: ".uisp_integration.airmax_capacity", data: "float", editable: true },
|
|
{ field: "bindUispLtuCapacity", path: ".uisp_integration.ltu_capacity", data: "float", editable: true },
|
|
{ field: "bindUispIpv6Mikrotik", path: ".uisp_integration.ipv6_with_mikrotik", data: "bool", editable: true },
|
|
{ field: "bindUispOverheadFactor", path: ".uisp_integration.bandwidth_overhead_factor", data: "float", editable: true },
|
|
{ field: "bindUispCommitMultiplier", path: ".uisp_integration.commit_bandwidth_multiplier", data: "float", editable: true },
|
|
{ field: "bindUispExcludeSites", path: ".uisp_integration.exclude_sites", data: "array_of_strings", editable: true },
|
|
{ field: "bindUispExceptionCpes", path: ".uisp_integration.exception_cpes", data: "array_of_strings", editable: true },
|
|
{ field: "bindUispUsePtmpAsParent", path: ".uisp_integration.use_ptmp_as_parent", data: "bool", editable: true },
|
|
|
|
// Powercode
|
|
{ field: "bindPowercodeEnable", path: ".powercode_integration.enable_powercode", data: "bool", editable: true },
|
|
{ field: "bindPowercodeKey", path: ".powercode_integration.powercode_api_key", data: "string", editable: true },
|
|
{ field: "bindPowercodeUrl", path: ".powercode_integration.powercode_api_url", data: "string", editable: true },
|
|
|
|
// Sonar
|
|
{ field: "bindSonarEnable", path: ".sonar_integration.enable_sonar", data: "bool", editable: true },
|
|
{ field: "bindSonarApiKey", path: ".sonar_integration.sonar_api_key", data: "string", editable: true },
|
|
{ field: "bindSonarApiUrl", path: ".sonar_integration.sonar_api_url", data: "string", editable: true },
|
|
{ field: "bindSonarSnmp", path: ".sonar_integration.snmp_community", data: "string", editable: true },
|
|
{ field: "bindSonarAirmax", path: ".sonar_integration.airmax_model_ids", data: "array_of_strings", editable: true },
|
|
{ field: "bindSonarLtu", path: ".sonar_integration.ltu_model_ids", data: "array_of_strings", editable: true },
|
|
{ field: "bindSonarActive", path: ".sonar_integration.active_status_ids", data: "array_of_strings", editable: true },
|
|
|
|
// Influx
|
|
{ field: "bindInfluxEnable", path: ".influxdb.enable_influxdb", data: "bool", editable: true },
|
|
{ field: "bindInfluxUrl", path: ".influxdb.url", data: "string", editable: true },
|
|
{ field: "bindInfluxOrg", path: ".influxdb.org", data: "string", editable: true },
|
|
{ field: "bindInfluxBucket", path: ".influxdb.bucket", data: "string", editable: true },
|
|
{ field: "bindInfluxToken", path: ".influxdb.token", data: "string", editable: true },
|
|
|
|
];
|
|
|
|
function doBindings() {
|
|
let active = true;
|
|
|
|
for (var i=0; i<bindings.length; ++i) {
|
|
let entry = bindings[i];
|
|
|
|
if (entry.conditional != null) {
|
|
console.log("Conditional encountered");
|
|
if (entry.condition === "if_exists") {
|
|
let val = "lqosd_config" + entry.path;
|
|
if (eval(val) != null) {
|
|
console.log("Conditional fired");
|
|
active = true;
|
|
if (entry.showDiv != null) {
|
|
$("#" + entry.showDiv).show();
|
|
}
|
|
if (entry.hideDiv != null) {
|
|
$("#" + entry.hideDiv).hide();
|
|
}
|
|
} else {
|
|
console.log("Conditional did not fire")
|
|
active = false;
|
|
}
|
|
}
|
|
} else if (entry.end_conditional != null) {
|
|
console.log("Conditional ended");
|
|
active = true;
|
|
} else {
|
|
if (!active) {
|
|
console.log("Skipping " + entry.path);
|
|
continue;
|
|
}
|
|
let value_location = "lqosd_config" + entry.path;
|
|
let value = eval(value_location);
|
|
let controlId = "#" + entry.field;
|
|
if (entry.data === "bool") {
|
|
$(controlId).prop('checked', value);
|
|
} else if (entry.data === "selector-premade") {
|
|
$(controlId + " select").val(value);
|
|
} else if (entry.data === "array_of_strings") {
|
|
let expanded = "";
|
|
let length = eval("lqosd_config" + entry.path + ".length");
|
|
for (let j = 0; j < length; j++) {
|
|
let v = eval("lqosd_config" + entry.path + "[" + j + "]");
|
|
expanded += v + " ";
|
|
}
|
|
expanded = expanded.trimEnd();
|
|
$(controlId).val(expanded);
|
|
} else if (entry.data === "ip_array") {
|
|
let expanded = "";
|
|
let length = eval("lqosd_config" + entry.path + ".length");
|
|
for (let j = 0; j < length; j++) {
|
|
let v = eval("lqosd_config" + entry.path + "[" + j + "]");
|
|
expanded += v + "\n";
|
|
}
|
|
expanded = expanded.trimEnd();
|
|
$(controlId).val(expanded);
|
|
} else if (entry.data === "interface") {
|
|
console.log("NIC: " + entry.field);
|
|
fillNicList(entry.field, value);
|
|
} else {
|
|
$(controlId).val(value);
|
|
}
|
|
$(controlId).prop('readonly', !entry.editable);
|
|
}
|
|
}
|
|
}
|
|
|
|
function setBridgeMode() {
|
|
$("#bridgeMode").show();
|
|
$("#OnAStickMode").hide();
|
|
lqosd_config.single_interface = null;
|
|
lqosd_config.bridge = {
|
|
use_xdp_bridge: true,
|
|
to_internet: "",
|
|
to_network: "",
|
|
};
|
|
$("#bindUseXdpBridge").prop('checked', true);
|
|
fillNicList("bindBridgeToInternet", nics[0][0]);
|
|
fillNicList("bindBridgeToNetwork", nics[0][0]);
|
|
}
|
|
|
|
function setStickMode() {
|
|
$("#bridgeMode").hide();
|
|
$("#OnAStickMode").show();
|
|
lqosd_config.bridge = null;
|
|
lqosd_config.single_interface = {
|
|
interface: "",
|
|
internet_vlan: 2,
|
|
network_vlan: 3,
|
|
};
|
|
fillNicList("bindSingleInterfaceNic", nics[0][0]);
|
|
$("#bindSingleInterfaceInternetVlan").val('2');
|
|
$("#bindSingleInterfaceNetworklan").val('3');
|
|
}
|
|
|
|
function validateConfig() {
|
|
for (var i=0; i<bindings.length; ++i) {
|
|
let entry = bindings[i];
|
|
let controlId = entry.field;
|
|
if (entry.path != null) {
|
|
let path = "lqosd_config" + entry.path;
|
|
let currentValue = $("#" + controlId).val();
|
|
let storedVAlue = eval(path);
|
|
console.log(currentValue, storedVAlue);
|
|
}
|
|
}
|
|
}
|
|
|
|
function start() {
|
|
display();
|
|
colorReloadButton();
|
|
updateHostCounts();
|
|
$.get("/api/admin_check", (is_admin) => {
|
|
if (!is_admin) {
|
|
$("#controls").html("<p class='alert alert-danger' role='alert'>You have to be an administrative user to change configuration.");
|
|
$("#userManager").html("<p class='alert alert-danger' role='alert'>Only administrators can see/change user information.");
|
|
} else {
|
|
// Handle Saving ispConfig.py
|
|
$("#btnSaveIspConfig").on('click', (data) => {
|
|
validateConfig();
|
|
});
|
|
}
|
|
$.get("/api/config", (data) => {
|
|
lqosd_config = data;
|
|
console.log("Bindings Done");
|
|
$.get("/api/list_nics", (data) => {
|
|
nics = data;
|
|
console.log(lqosd_config);
|
|
doBindings();
|
|
|
|
// User management
|
|
if (is_admin) {
|
|
userManager();
|
|
}
|
|
|
|
$.get("/api/network_json", (njs) => {
|
|
network_json = njs;
|
|
$.get("/api/all_shaped_devices", (data) => {
|
|
shaped_devices = data;
|
|
shapedDevices(data);
|
|
RenderNetworkJson();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function iterateNetJson(level, depth) {
|
|
let html = "<div style='margin-left: " + depth * 30 + "px;'>";
|
|
for (const [key, value] of Object.entries(level)) {
|
|
html += "<div>";
|
|
html += "<strong>" + key + "</strong><br />";
|
|
html += "Download: <input type='number' value='" + value.downloadBandwidthMbps + "'></input><br />";
|
|
html += "Upload: <input type='number' value='" + value.uploadBandwidthMbps + "'></input><br />";
|
|
let num_children = 0;
|
|
for (let i=0; i<shaped_devices.length; i++) {
|
|
if (shaped_devices[i].parent_node === key) {
|
|
num_children++;
|
|
}
|
|
}
|
|
html += "<em>Associated Devices: " + num_children + "</em><br />";
|
|
//console.log(`${key}: ${value}`);
|
|
//console.log("Children", value.children);
|
|
if (value.children != null) {
|
|
html += iterateNetJson(value.children, depth + 1);
|
|
}
|
|
html += "</div>";
|
|
}
|
|
html += "</div>";
|
|
return html;
|
|
}
|
|
|
|
function RenderNetworkJson() {
|
|
let html = "";
|
|
html += iterateNetJson(network_json, 0);
|
|
$("#netjson").html(html);
|
|
}
|
|
|
|
function makeSheetBox(value, small=false) {
|
|
let html = "";
|
|
if (!small) {
|
|
html = "<td style='padding: 0px'><input type=\"text\" value=\"" + value + "\"></input></td>"
|
|
} else {
|
|
html = "<td style='padding: 0px'><input type=\"text\" value=\"" + value + "\" style='font-size: 8pt;'></input></td>"
|
|
}
|
|
return html;
|
|
}
|
|
|
|
function makeSheetNumberBox(value) {
|
|
let html = "<td style='padding: 0px'><input type=\"number\" value=\"" + value + "\" style='width: 100px; font-size: 8pt;'></input></td>"
|
|
return html;
|
|
}
|
|
|
|
function separatedIpArray(value) {
|
|
let html = "<td style='padding: 0px'>";
|
|
let val = "";
|
|
for (i = 0; i<value.length; i++) {
|
|
val += value[i][0];
|
|
val += "/";
|
|
val += value[i][1];
|
|
val += ", ";
|
|
}
|
|
if (val.length > 0) {
|
|
val = val.substring(0, val.length-2);
|
|
}
|
|
html += "<input type='text' style='font-size: 8pt; width: 100px;' value='" + val + "'></input>";
|
|
html += "</td>";
|
|
return html;
|
|
}
|
|
|
|
function nodeDropDown(selectedNode) {
|
|
let html = "<td style='padding: 0px'>";
|
|
html += "<select style='font-size: 8pt; width: 150px;'>";
|
|
|
|
function iterate(data, level) {
|
|
let html = "";
|
|
for (const [key, value] of Object.entries(data)) {
|
|
html += "<option value='" + key + "'";
|
|
if (key === selectedNode) html += " selected";
|
|
html += ">";
|
|
for (let i=0; i<level; i++) html += "-";
|
|
html += key;
|
|
html += "</option>";
|
|
|
|
if (value.children != null)
|
|
html += iterate(value.children, level+1);
|
|
}
|
|
return html;
|
|
}
|
|
html += iterate(network_json, 0);
|
|
|
|
html += "</select>";
|
|
html += "</td>";
|
|
return html;
|
|
}
|
|
|
|
function shapedDevices() {
|
|
let html = "<table style='height: 500px; overflow: scroll; border-collapse: collapse; width: 100%; padding: 0px'>";
|
|
html += "<thead style='position: sticky; top: 0; height: 50px; background: #ddd'>";
|
|
html += "<tr style='font-size: 9pt;'><th>Circuit ID</th><th>Circuit Name</th><th>Device ID</th><th>Device Name</th><th>Parent Node</th><th>MAC</th><th>IPv4</th><th>IPv6</th><th>Download Min</th><th>Upload Min</th><th>Download Max</th><th>Upload Max</th><th>Comment</th></tr>";
|
|
html += "</thead>>";
|
|
for (var i=0; i<shaped_devices.length; i++) {
|
|
let row = shaped_devices[i];
|
|
html += "<tr>";
|
|
html += makeSheetBox(row.circuit_id, true);
|
|
html += makeSheetBox(row.circuit_name, true);
|
|
html += makeSheetBox(row.device_id, true);
|
|
html += makeSheetBox(row.device_name, true);
|
|
html += nodeDropDown(row.parent_node, true);
|
|
html += makeSheetBox(row.mac, true);
|
|
html += separatedIpArray(row.ipv4);
|
|
html += separatedIpArray(row.ipv6);
|
|
html += makeSheetNumberBox(row.download_min_mbps);
|
|
html += makeSheetNumberBox(row.upload_min_mbps);
|
|
html += makeSheetNumberBox(row.download_max_mbps);
|
|
html += makeSheetNumberBox(row.upload_max_mbps);
|
|
html += makeSheetBox(row.comment, true);
|
|
|
|
html += "</tr>";
|
|
}
|
|
html += "</tbody></table>";
|
|
$("#shapedDeviceTable").html(html);
|
|
}
|
|
|
|
function userManager() {
|
|
let html = "<p>For now, please use <em>bin/lqusers</em> to manage users.</p>";
|
|
$("#userManager").html(html);
|
|
}
|
|
|
|
function fillNicList(id, selected) {
|
|
let select = $("#" + id);
|
|
let html = "";
|
|
for (i=0; i<nics.length; i++) {
|
|
html += "<option value=\"";
|
|
html += nics[i][0] + "\"";
|
|
if (nics[i][0] === selected) {
|
|
html += " selected";
|
|
}
|
|
html += ">" + nics[i][0] + " - " + nics[i][1] + " - " + nics[i][2] + "</option>";
|
|
}
|
|
select.html(html);
|
|
}
|
|
|
|
function buildNICList(id, selected, disabled=false) {
|
|
let html = "<select id='" + id + "'";
|
|
if (disabled) html += " disabled='true' ";
|
|
html += ">";
|
|
for (i=0; i<nics.length; i++) {
|
|
html += "<option value=\"";
|
|
html += nics[i][0] + "\"";
|
|
if (nics[i][0] == selected) {
|
|
html += " selected";
|
|
}
|
|
html += ">" + nics[i][0] + " - " + nics[i][1] + " - " + nics[i][2] + "</option>";
|
|
}
|
|
html += "</select>";
|
|
return html;
|
|
}
|
|
|
|
function display() {
|
|
let colorPreference = window.localStorage.getItem("colorPreference");
|
|
if (colorPreference == null) {
|
|
window.localStorage.setItem("colorPreference", 0);
|
|
colorPreference = 0;
|
|
}
|
|
$("#colorMode option[id='" + colorPreference + "']").attr("selected", true);
|
|
let redact = window.localStorage.getItem("redact");
|
|
if (redact == null) {
|
|
window.localStorage.setItem("redact", false);
|
|
redact = false;
|
|
}
|
|
if (redact == "false") redact = false;
|
|
$("#redact").prop('checked', redact);
|
|
$("#applyDisplay").on('click', () => {
|
|
let colorPreference = $("#colorMode").find('option:selected').attr('id');
|
|
window.localStorage.setItem("colorPreference", colorPreference);
|
|
let redact = $("#redact").prop('checked');
|
|
window.localStorage.setItem("redact", redact);
|
|
});
|
|
}
|
|
|
|
$(document).ready(start);
|
|
</script>
|
|
</body>
|
|
</html>
|