mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Dashboard revamp
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -339,7 +339,8 @@
|
|||||||
<li class="nav-item text-nowrap">
|
<li class="nav-item text-nowrap">
|
||||||
|
|
||||||
<form class="d-flex" role="search">
|
<form class="d-flex" role="search">
|
||||||
<input id="txtSearch" class="form-control me-2" type="search" placeholder="Search" aria-label="Search" autocomplete="off">
|
<input id="txtSearch" class="form-control me-2" type="search" placeholder="Search" aria-label="Search"
|
||||||
|
autocomplete="off">
|
||||||
<div id="searchResults"
|
<div id="searchResults"
|
||||||
style="position: fixed; display: none; color: black; background-color: #eee; top:55px; left: 0x; width: 300px; height: auto; z-index: 2000;">
|
style="position: fixed; display: none; color: black; background-color: #eee; top:55px; left: 0x; width: 300px; height: auto; z-index: 2000;">
|
||||||
Blah</div>
|
Blah</div>
|
||||||
@@ -403,6 +404,9 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div id="nodeStatus">
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -411,14 +415,15 @@
|
|||||||
<div
|
<div
|
||||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||||
id="mainContent">
|
id="mainContent">
|
||||||
<i class="fa-solid fa-spinner fa-spin"></i>
|
<i class="fa-solid fa-spinner fa-spin"></i>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="SpinLoad" style="z-index: 2000; position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; background: #ddd; font-size: 48px; color: #555; text-align: center;">
|
<div id="SpinLoad"
|
||||||
|
style="z-index: 2000; position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; background: #ddd; font-size: 48px; color: #555; text-align: center;">
|
||||||
<p>
|
<p>
|
||||||
Loading, Please Wait...
|
Loading, Please Wait...
|
||||||
<i class="fa-solid fa-spinner fa-spin"></i>
|
<i class="fa-solid fa-spinner fa-spin"></i>
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ declare global {
|
|||||||
login: any;
|
login: any;
|
||||||
graphPeriod: string;
|
graphPeriod: string;
|
||||||
changeGraphPeriod: any;
|
changeGraphPeriod: any;
|
||||||
|
toggleThroughput: any;
|
||||||
|
toggleLatency: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(window as any).onAuthFail = onAuthFail;
|
(window as any).onAuthFail = onAuthFail;
|
||||||
@@ -45,7 +47,11 @@ window.setInterval(() => {
|
|||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
updateDisplayedInterval();
|
updateDisplayedInterval();
|
||||||
window.bus.updateConnected();
|
window.bus.updateConnected();
|
||||||
window.bus.sendQueue();
|
try {
|
||||||
|
window.bus.sendQueue();
|
||||||
|
} catch (e) {
|
||||||
|
//console.log("Error sending queue: " + e);
|
||||||
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
function updateDisplayedInterval() {
|
function updateDisplayedInterval() {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { makeUrl } from "../helpers";
|
|||||||
import { Component } from "./component";
|
import { Component } from "./component";
|
||||||
|
|
||||||
export class RootBreadcrumbs implements Component {
|
export class RootBreadcrumbs implements Component {
|
||||||
|
loaded: boolean = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,6 +15,9 @@ export class RootBreadcrumbs implements Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ontick(): void {
|
ontick(): void {
|
||||||
|
if (!this.loaded) {
|
||||||
|
request_root_parents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onmessage(event: any): void {
|
onmessage(event: any): void {
|
||||||
@@ -30,6 +35,7 @@ export class RootBreadcrumbs implements Component {
|
|||||||
let select = document.getElementById("siteChildren") as HTMLSelectElement;
|
let select = document.getElementById("siteChildren") as HTMLSelectElement;
|
||||||
window.router.goto(select.value);
|
window.router.goto(select.value);
|
||||||
};
|
};
|
||||||
|
this.loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ export class RttHisto implements Component {
|
|||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: 'ms',
|
name: 'frequency',
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ export class DashboardPage implements Page {
|
|||||||
container.innerHTML = html;
|
container.innerHTML = html;
|
||||||
}
|
}
|
||||||
this.components = [
|
this.components = [
|
||||||
new NodeStatus(),
|
|
||||||
new RootBreadcrumbs(),
|
new RootBreadcrumbs(),
|
||||||
new PacketsChart(),
|
new PacketsChart(),
|
||||||
new ThroughputChart(),
|
new ThroughputChart(),
|
||||||
@@ -31,6 +30,8 @@ export class DashboardPage implements Page {
|
|||||||
new RootHeat(),
|
new RootHeat(),
|
||||||
new SiteStackChart("root"),
|
new SiteStackChart("root"),
|
||||||
];
|
];
|
||||||
|
window.toggleThroughput = toggleThroughput;
|
||||||
|
window.toggleLatency = toggleLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
wireup() {
|
wireup() {
|
||||||
@@ -55,4 +56,60 @@ export class DashboardPage implements Page {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleThroughput(mode: string) {
|
||||||
|
let elements = [
|
||||||
|
document.getElementById("bitsholder"),
|
||||||
|
document.getElementById("packetsholder"),
|
||||||
|
document.getElementById("sitestackholder"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Clear all
|
||||||
|
elements.forEach(element => {
|
||||||
|
if (element) {
|
||||||
|
element.style.height = "0px";
|
||||||
|
element.style.overflow = "none";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var element = 0;
|
||||||
|
switch (mode) {
|
||||||
|
case "tp": { var element = 0 } break;
|
||||||
|
case "pk": { var element = 1 } break;
|
||||||
|
case "st": { var element = 2 } break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = elements[element];
|
||||||
|
if (e) {
|
||||||
|
e.style.height = "250px";
|
||||||
|
e.style.overflow = "auto";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleLatency(mode: string) {
|
||||||
|
let elements = [
|
||||||
|
document.getElementById("rttHistoHolder"),
|
||||||
|
document.getElementById("rttChartHolder"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Clear all
|
||||||
|
elements.forEach(element => {
|
||||||
|
if (element) {
|
||||||
|
element.style.height = "0px";
|
||||||
|
element.style.overflow = "none";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var element = 0;
|
||||||
|
switch (mode) {
|
||||||
|
case "histo": { var element = 0 } break;
|
||||||
|
case "line": { var element = 1 } break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = elements[element];
|
||||||
|
if (e) {
|
||||||
|
e.style.height = "250px";
|
||||||
|
e.style.overflow = "auto";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,43 +1,32 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
|
||||||
<div class="col-12" id="nodeStatus">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12" id="siteName">
|
<div class="col-12" id="siteName">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div id="packetsChart" style="height: 250px"></div>
|
<h5 class="card-title">
|
||||||
</div>
|
<i class="fa-solid fa-gauge"></i> Throughput
|
||||||
</div>
|
<div class="btn-group" role="group" aria-label="Throughput Graph Selector">
|
||||||
</div>
|
<button type="button" class="btn btn-sm btn-secondary"
|
||||||
|
onclick="window.toggleThroughput('tp')">Throughput</button>
|
||||||
<div class="col-6">
|
<button type="button" class="btn btn-sm btn-secondary"
|
||||||
<div class="card">
|
onclick="window.toggleThroughput('pk')">Packets</button>
|
||||||
<div class="card-body">
|
<button type="button" class="btn btn-sm btn-secondary"
|
||||||
<div id="throughputChart" style="height: 250px"></div>
|
onclick="window.toggleThroughput('st')">Sites</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</h5>
|
||||||
</div>
|
<div id="bitsholder" style="height: 250px; overflow: auto;">
|
||||||
</div>
|
<div id="throughputChart" style="height: 250px"></div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div id="packetsholder" style="height: 0; overflow: hidden;">
|
||||||
<div class="col-6">
|
<div id="packetsChart" style="height: 250px"></div>
|
||||||
<div class="card">
|
</div>
|
||||||
<div class="card-body">
|
<div id="sitestackholder" style="height: 0; overflow: hidden;">
|
||||||
<div id="rttChart" style="height: 250px"></div>
|
<div id="siteStack" style="height: 250px"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-6">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
<div id="rttHisto" style="height: 250px"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,7 +36,21 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div id="siteStack" style="height: 250px"></div>
|
<h5 class="card-title">
|
||||||
|
<i class="fa-solid fa-clock"></i> Latency (TCP Round-Trip Time)
|
||||||
|
<div class="btn-group" role="group" aria-label="Latency Graph Selector">
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary"
|
||||||
|
onclick="window.toggleLatency('histo')">Histogram</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary"
|
||||||
|
onclick="window.toggleLatency('line')">Time-Series</button>
|
||||||
|
</div>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div id="rttHistoHolder" style="height: 250px; overflow: auto;">
|
||||||
|
<div id="rttHisto" style="height: 250px"></div>
|
||||||
|
</div>
|
||||||
|
<div id="rttChartHolder" style="height: 0; overflow: hidden;">
|
||||||
|
<div id="rttChart" style="height: 250px"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,4 +65,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -339,7 +339,8 @@
|
|||||||
<li class="nav-item text-nowrap">
|
<li class="nav-item text-nowrap">
|
||||||
|
|
||||||
<form class="d-flex" role="search">
|
<form class="d-flex" role="search">
|
||||||
<input id="txtSearch" class="form-control me-2" type="search" placeholder="Search" aria-label="Search" autocomplete="off">
|
<input id="txtSearch" class="form-control me-2" type="search" placeholder="Search" aria-label="Search"
|
||||||
|
autocomplete="off">
|
||||||
<div id="searchResults"
|
<div id="searchResults"
|
||||||
style="position: fixed; display: none; color: black; background-color: #eee; top:55px; left: 0x; width: 300px; height: auto; z-index: 2000;">
|
style="position: fixed; display: none; color: black; background-color: #eee; top:55px; left: 0x; width: 300px; height: auto; z-index: 2000;">
|
||||||
Blah</div>
|
Blah</div>
|
||||||
@@ -403,6 +404,9 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div id="nodeStatus">
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -411,14 +415,15 @@
|
|||||||
<div
|
<div
|
||||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||||
id="mainContent">
|
id="mainContent">
|
||||||
<i class="fa-solid fa-spinner fa-spin"></i>
|
<i class="fa-solid fa-spinner fa-spin"></i>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="SpinLoad" style="z-index: 2000; position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; background: #ddd; font-size: 48px; color: #555; text-align: center;">
|
<div id="SpinLoad"
|
||||||
|
style="z-index: 2000; position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; background: #ddd; font-size: 48px; color: #555; text-align: center;">
|
||||||
<p>
|
<p>
|
||||||
Loading, Please Wait...
|
Loading, Please Wait...
|
||||||
<i class="fa-solid fa-spinner fa-spin"></i>
|
<i class="fa-solid fa-spinner fa-spin"></i>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Page } from '../page'
|
import { Page } from '../page'
|
||||||
import { siteIcon } from '../helpers';
|
import { siteIcon } from '../helpers';
|
||||||
import { request_search } from "../../wasm/wasm_pipe";
|
import { request_search } from "../../wasm/wasm_pipe";
|
||||||
|
import { NodeStatus } from '../components/node_status';
|
||||||
|
|
||||||
const menuElements = [ "menuDash", "nodesDash", "sitetreeDash", "menuUser" ];
|
const menuElements = [ "menuDash", "nodesDash", "sitetreeDash", "menuUser" ];
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@ export class MenuPage implements Page {
|
|||||||
activePanel: string;
|
activePanel: string;
|
||||||
//searchButton: HTMLButtonElement;
|
//searchButton: HTMLButtonElement;
|
||||||
searchBar: HTMLInputElement;
|
searchBar: HTMLInputElement;
|
||||||
|
nodeStatus: NodeStatus;
|
||||||
|
|
||||||
constructor(activeElement: string) {
|
constructor(activeElement: string) {
|
||||||
let container = document.getElementById('mainContent');
|
let container = document.getElementById('mainContent');
|
||||||
@@ -39,7 +41,7 @@ export class MenuPage implements Page {
|
|||||||
|
|
||||||
this.searchBar = <HTMLInputElement>document.getElementById("txtSearch");
|
this.searchBar = <HTMLInputElement>document.getElementById("txtSearch");
|
||||||
//this.searchButton = <HTMLButtonElement>document.getElementById("btnSearch");
|
//this.searchButton = <HTMLButtonElement>document.getElementById("btnSearch");
|
||||||
|
this.nodeStatus = new NodeStatus();
|
||||||
this.wireup();
|
this.wireup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,6 +75,9 @@ export class MenuPage implements Page {
|
|||||||
onmessage(event: any) {
|
onmessage(event: any) {
|
||||||
if (event.msg) {
|
if (event.msg) {
|
||||||
switch (event.msg) {
|
switch (event.msg) {
|
||||||
|
case "NodeStatus" : {
|
||||||
|
this.nodeStatus.onmessage(event);
|
||||||
|
} break;
|
||||||
case "authOk": {
|
case "authOk": {
|
||||||
let username = document.getElementById('menuUser');
|
let username = document.getElementById('menuUser');
|
||||||
if (username) {
|
if (username) {
|
||||||
@@ -110,5 +115,6 @@ export class MenuPage implements Page {
|
|||||||
|
|
||||||
ontick(): void {
|
ontick(): void {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
this.nodeStatus.ontick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user