mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
WIP - UISP support and breadcrumb fixes
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
use crate::web::wss::{
|
||||
nodes::node_status,
|
||||
queries::{
|
||||
ext_device::{
|
||||
send_extended_device_capacity_graph, send_extended_device_info,
|
||||
send_extended_device_snr_graph,
|
||||
},
|
||||
omnisearch, root_heat_map, send_circuit_info, send_packets_for_all_nodes,
|
||||
send_packets_for_node, send_perf_for_node, send_rtt_for_all_nodes,
|
||||
send_rtt_for_all_nodes_circuit, send_rtt_for_all_nodes_site, send_rtt_for_node,
|
||||
send_site_info, send_site_parents, send_site_stack_map, send_throughput_for_all_nodes,
|
||||
send_throughput_for_all_nodes_by_circuit, send_throughput_for_all_nodes_by_site,
|
||||
send_throughput_for_node, site_heat_map, site_tree::send_site_tree,
|
||||
time_period::InfluxTimePeriod, ext_device::send_extended_device_info,
|
||||
send_throughput_for_node, site_heat_map,
|
||||
site_tree::send_site_tree,
|
||||
time_period::InfluxTimePeriod,
|
||||
send_circuit_parents, send_root_parents,
|
||||
},
|
||||
};
|
||||
use axum::{
|
||||
@@ -257,6 +263,12 @@ async fn handle_socket(mut socket: WebSocket, cnn: Pool<Postgres>) {
|
||||
(WasmRequest::SiteParents { site_id }, Some(credentials)) => {
|
||||
send_site_parents(&cnn, wss, &credentials.license_key, site_id).await;
|
||||
}
|
||||
(WasmRequest::CircuitParents { circuit_id }, Some(credentials)) => {
|
||||
send_circuit_parents(&cnn, wss, &credentials.license_key, circuit_id).await;
|
||||
}
|
||||
(WasmRequest::RootParents, Some(credentials)) => {
|
||||
send_root_parents(&cnn, wss, &credentials.license_key).await;
|
||||
}
|
||||
(WasmRequest::Search { term }, Some(credentials)) => {
|
||||
let _ = omnisearch(&cnn, wss, &credentials.license_key, term).await;
|
||||
}
|
||||
@@ -266,6 +278,26 @@ async fn handle_socket(mut socket: WebSocket, cnn: Pool<Postgres>) {
|
||||
(WasmRequest::ExtendedDeviceInfo { circuit_id }, Some(credentials)) => {
|
||||
send_extended_device_info(&cnn, wss, &credentials.license_key, circuit_id).await;
|
||||
}
|
||||
(WasmRequest::SignalNoiseChartExt { period, device_id }, Some(credentials)) => {
|
||||
let _ = send_extended_device_snr_graph(
|
||||
&cnn,
|
||||
wss,
|
||||
&credentials.license_key,
|
||||
device_id,
|
||||
InfluxTimePeriod::new(period),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
(WasmRequest::DeviceCapacityChartExt { period, device_id }, Some(credentials)) => {
|
||||
let _ = send_extended_device_capacity_graph(
|
||||
&cnn,
|
||||
wss,
|
||||
&credentials.license_key,
|
||||
device_id,
|
||||
InfluxTimePeriod::new(period),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
(_, None) => {
|
||||
tracing::error!("No credentials");
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use axum::extract::ws::WebSocket;
|
||||
use pgdb::sqlx::{Pool, Postgres};
|
||||
use wasm_pipe_types::CircuitList;
|
||||
use chrono::{DateTime, FixedOffset};
|
||||
use influxdb2::{FromDataPoint, models::Query, Client};
|
||||
use pgdb::{sqlx::{Pool, Postgres}, organization_cache::get_org_details};
|
||||
|
||||
use crate::web::wss::send_response;
|
||||
|
||||
use super::time_period::InfluxTimePeriod;
|
||||
|
||||
pub async fn send_extended_device_info(
|
||||
cnn: &Pool<Postgres>,
|
||||
socket: &mut WebSocket,
|
||||
@@ -65,19 +67,100 @@ pub async fn send_extended_device_info(
|
||||
}
|
||||
}
|
||||
|
||||
fn from(circuit: pgdb::CircuitInfo) -> CircuitList {
|
||||
CircuitList {
|
||||
circuit_name: circuit.circuit_name,
|
||||
device_id: circuit.device_id,
|
||||
device_name: circuit.device_name,
|
||||
parent_node: circuit.parent_node,
|
||||
mac: circuit.mac,
|
||||
download_min_mbps: circuit.download_min_mbps,
|
||||
download_max_mbps: circuit.download_max_mbps,
|
||||
upload_min_mbps: circuit.upload_min_mbps,
|
||||
upload_max_mbps: circuit.upload_max_mbps,
|
||||
comment: circuit.comment,
|
||||
ip_range: circuit.ip_range,
|
||||
subnet: circuit.subnet,
|
||||
pub async fn send_extended_device_snr_graph(
|
||||
cnn: &Pool<Postgres>,
|
||||
socket: &mut WebSocket,
|
||||
key: &str,
|
||||
device_id: &str,
|
||||
period: InfluxTimePeriod,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(org) = get_org_details(cnn, key).await {
|
||||
let influx_url = format!("http://{}:8086", org.influx_host);
|
||||
let client = Client::new(influx_url, &org.influx_org, &org.influx_token);
|
||||
|
||||
let qs = format!(
|
||||
"from(bucket: \"{}\")
|
||||
|> {}
|
||||
|> filter(fn: (r) => r[\"_measurement\"] == \"device_ext\")
|
||||
|> filter(fn: (r) => r[\"organization_id\"] == \"{}\")
|
||||
|> filter(fn: (r) => r[\"device_id\"] == \"{}\")
|
||||
|> filter(fn: (r) => r[\"_field\"] == \"noise_floor\" or r[\"_field\"] == \"rx_signal\")
|
||||
|> {}
|
||||
|> yield(name: \"last\")",
|
||||
org.influx_bucket, period.range(), org.key, device_id, period.aggregate_window()
|
||||
);
|
||||
//println!("{qs}");
|
||||
|
||||
let query = Query::new(qs);
|
||||
let rows = client.query::<SnrRow>(Some(query)).await?;
|
||||
|
||||
let mut sn = Vec::new();
|
||||
rows.iter().for_each(|row| {
|
||||
let snr = wasm_pipe_types::SignalNoiseChartExt {
|
||||
noise: row.noise_floor,
|
||||
signal: row.rx_signal,
|
||||
date: row.time.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
};
|
||||
sn.push(snr);
|
||||
});
|
||||
send_response(socket, wasm_pipe_types::WasmResponse::DeviceExtSnr { data: sn, device_id: device_id.to_string() }).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, FromDataPoint, Default)]
|
||||
pub struct SnrRow {
|
||||
pub device_id: String,
|
||||
pub noise_floor: f64,
|
||||
pub rx_signal: f64,
|
||||
pub time: DateTime<FixedOffset>,
|
||||
}
|
||||
|
||||
pub async fn send_extended_device_capacity_graph(
|
||||
cnn: &Pool<Postgres>,
|
||||
socket: &mut WebSocket,
|
||||
key: &str,
|
||||
device_id: &str,
|
||||
period: InfluxTimePeriod,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(org) = get_org_details(cnn, key).await {
|
||||
let influx_url = format!("http://{}:8086", org.influx_host);
|
||||
let client = Client::new(influx_url, &org.influx_org, &org.influx_token);
|
||||
|
||||
let qs = format!(
|
||||
"from(bucket: \"{}\")
|
||||
|> {}
|
||||
|> filter(fn: (r) => r[\"_measurement\"] == \"device_ext\")
|
||||
|> filter(fn: (r) => r[\"organization_id\"] == \"{}\")
|
||||
|> filter(fn: (r) => r[\"device_id\"] == \"{}\")
|
||||
|> filter(fn: (r) => r[\"_field\"] == \"dl_capacity\" or r[\"_field\"] == \"ul_capacity\")
|
||||
|> {}
|
||||
|> yield(name: \"last\")",
|
||||
org.influx_bucket, period.range(), org.key, device_id, period.aggregate_window()
|
||||
);
|
||||
//println!("{qs}");
|
||||
|
||||
let query = Query::new(qs);
|
||||
let rows = client.query::<CapacityRow>(Some(query)).await?;
|
||||
|
||||
let mut sn = Vec::new();
|
||||
rows.iter().for_each(|row| {
|
||||
let snr = wasm_pipe_types::CapacityChartExt {
|
||||
dl: row.dl_capacity,
|
||||
ul: row.ul_capacity,
|
||||
date: row.time.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
};
|
||||
sn.push(snr);
|
||||
});
|
||||
send_response(socket, wasm_pipe_types::WasmResponse::DeviceExtCapacity { data: sn, device_id: device_id.to_string() }).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, FromDataPoint, Default)]
|
||||
pub struct CapacityRow {
|
||||
pub device_id: String,
|
||||
pub dl_capacity: f64,
|
||||
pub ul_capacity: f64,
|
||||
pub time: DateTime<FixedOffset>,
|
||||
}
|
||||
@@ -20,7 +20,7 @@ pub use rtt::{send_rtt_for_all_nodes, send_rtt_for_all_nodes_site, send_rtt_for_
|
||||
pub use search::omnisearch;
|
||||
pub use site_heat_map::{root_heat_map, site_heat_map};
|
||||
pub use site_info::send_site_info;
|
||||
pub use site_parents::send_site_parents;
|
||||
pub use site_parents::{send_site_parents, send_circuit_parents, send_root_parents};
|
||||
pub use throughput::{
|
||||
send_throughput_for_all_nodes, send_throughput_for_all_nodes_by_circuit,
|
||||
send_throughput_for_all_nodes_by_site, send_throughput_for_node,
|
||||
|
||||
@@ -20,3 +20,28 @@ pub async fn send_site_parents(
|
||||
tracing::error!("Error getting children: {:?}", child_result);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_circuit_parents(
|
||||
cnn: &Pool<Postgres>,
|
||||
socket: &mut WebSocket,
|
||||
key: &str,
|
||||
circuit_id: &str,
|
||||
) {
|
||||
if let Ok(parents) = pgdb::get_circuit_parent_list(cnn, key, circuit_id).await {
|
||||
send_response(socket, wasm_pipe_types::WasmResponse::SiteParents { data: parents }).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_root_parents(
|
||||
cnn: &Pool<Postgres>,
|
||||
socket: &mut WebSocket,
|
||||
key: &str,
|
||||
) {
|
||||
let site_name = "Root";
|
||||
let child_result = pgdb::get_child_list(cnn, key, site_name).await;
|
||||
if let Ok(children) = child_result {
|
||||
send_response(socket, wasm_pipe_types::WasmResponse::SiteChildren { data: children }).await;
|
||||
} else {
|
||||
tracing::error!("Error getting children: {:?}", child_result);
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -137,5 +137,47 @@ pub async fn get_child_list(
|
||||
|
||||
result.sort_by(|a, b| a.2.cmp(&b.2));
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn get_circuit_parent_list(
|
||||
cnn: &Pool<Postgres>,
|
||||
key: &str,
|
||||
circuit_id: &str,
|
||||
) -> Result<Vec<(String, String)>, StatsHostError> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Get the site name to start at
|
||||
let site_name : String = sqlx::query("SELECT parent_node FROM shaped_devices WHERE key = $1 AND circuit_id= $2")
|
||||
.bind(key)
|
||||
.bind(circuit_id)
|
||||
.fetch_one(cnn)
|
||||
.await
|
||||
.map_err(|e| StatsHostError::DatabaseError(e.to_string()))?
|
||||
.get(0);
|
||||
|
||||
// Get the site index
|
||||
let site_id_db = sqlx::query("SELECT index FROM site_tree WHERE key = $1 AND site_name=$2")
|
||||
.bind(key)
|
||||
.bind(site_name)
|
||||
.fetch_one(cnn)
|
||||
.await
|
||||
.map_err(|e| StatsHostError::DatabaseError(e.to_string()))?;
|
||||
let mut site_id: i32 = site_id_db.try_get("index").map_err(|e| StatsHostError::DatabaseError(e.to_string()))?;
|
||||
|
||||
// Get the parent list
|
||||
while site_id != 0 {
|
||||
let parent_db = sqlx::query("SELECT site_name, parent, site_type FROM site_tree WHERE key = $1 AND index=$2")
|
||||
.bind(key)
|
||||
.bind(site_id)
|
||||
.fetch_one(cnn)
|
||||
.await
|
||||
.map_err(|e| StatsHostError::DatabaseError(e.to_string()))?;
|
||||
let parent: String = parent_db.try_get("site_name").map_err(|e| StatsHostError::DatabaseError(e.to_string()))?;
|
||||
let site_type: String = parent_db.try_get("site_type").map_err(|e| StatsHostError::DatabaseError(e.to_string()))?;
|
||||
site_id = parent_db.try_get("parent").map_err(|e| StatsHostError::DatabaseError(e.to_string()))?;
|
||||
result.push((site_type, parent));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@@ -5,7 +5,10 @@ import { Component } from '../components/component';
|
||||
import { CircuitInfo } from '../components/circuit_info';
|
||||
import { ThroughputCircuitChart } from '../components/throughput_circuit';
|
||||
import { RttChartCircuit } from '../components/rtt_circuit';
|
||||
import { request_ext_device_info } from "../../wasm/wasm_pipe";
|
||||
import { request_ext_device_info, request_ext_snr_graph, request_ext_capacity_graph } from "../../wasm/wasm_pipe";
|
||||
import * as echarts from 'echarts';
|
||||
import { scaleNumber } from '../helpers';
|
||||
import { CircuitBreadcrumbs } from '../components/circuit_breadcrumbs';
|
||||
|
||||
export class CircuitPage implements Page {
|
||||
menu: MenuPage;
|
||||
@@ -23,6 +26,7 @@ export class CircuitPage implements Page {
|
||||
new CircuitInfo(this.circuitId),
|
||||
new ThroughputCircuitChart(this.circuitId),
|
||||
new RttChartCircuit(this.circuitId),
|
||||
new CircuitBreadcrumbs(this.circuitId),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -49,27 +53,160 @@ export class CircuitPage implements Page {
|
||||
});
|
||||
|
||||
if (event.msg == "DeviceExt") {
|
||||
console.log(event.DeviceExt.data);
|
||||
//console.log(event.DeviceExt.data);
|
||||
let div = document.getElementById("ext") as HTMLDivElement;
|
||||
let html = "";
|
||||
|
||||
for (let i=0; i<event.DeviceExt.data.length; i++) {
|
||||
let d = event.DeviceExt.data[i];
|
||||
html += "<div class='row'>";
|
||||
html += "<div class='col-6'>";
|
||||
|
||||
html += "<div class='col-4'>";
|
||||
html += "<div class='card'>";
|
||||
html += "<div class='card-body' style='height: 250px'>";
|
||||
html += "<h4>" + d.name + "</h4>";
|
||||
html += "<strong>Status</strong>: " + d.status + "<br>";
|
||||
html += "<strong>Model</strong>: " + d.model + "<br>";
|
||||
html += "<strong>Mode</strong>: " + d.mode + "<br>";
|
||||
html += "<strong>Firmware</strong>: " + d.firmware + "<br>";
|
||||
html += "</div>";
|
||||
html += "<div class='col-6'>";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
|
||||
html += "<div class='col-4'>";
|
||||
html += "<div class='card'>";
|
||||
html += "<div class='card-body' id='extdev_" + d.device_id + "' style='height: 250px'>";
|
||||
html += "<p>Signal/noise graph</p>";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
request_ext_snr_graph(window.graphPeriod, d.device_id);
|
||||
|
||||
html += "<div class='col-4'>";
|
||||
html += "<div class='card'>";
|
||||
html += "<div class='card-body' id='extdev_cap_" + d.device_id + "' style='height: 250px'>";
|
||||
html += "<p>Capacity Graph</p>";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
request_ext_capacity_graph(window.graphPeriod, d.device_id);
|
||||
|
||||
// End row
|
||||
html += "</div>";
|
||||
}
|
||||
|
||||
div.outerHTML = html;
|
||||
} else if (event.msg == "DeviceExtSnr") {
|
||||
console.log(event);
|
||||
let div = document.getElementById("extdev_" + event.DeviceExtSnr.device_id) as HTMLDivElement;
|
||||
|
||||
let sig: number[] = [];
|
||||
let n: number[] = [];
|
||||
let x: any[] = [];
|
||||
|
||||
for (let i=0; i<event.DeviceExtSnr.data.length; i++) {
|
||||
let d = event.DeviceExtSnr.data[i];
|
||||
sig.push(d.signal);
|
||||
n.push(d.noise);
|
||||
x.push(d.date);
|
||||
}
|
||||
|
||||
let series: echarts.SeriesOption[] = [];
|
||||
let signal: echarts.SeriesOption = {
|
||||
name: "Signal",
|
||||
type: "line",
|
||||
data: sig,
|
||||
symbol: 'none',
|
||||
};
|
||||
let noise: echarts.SeriesOption = {
|
||||
name: "Noise",
|
||||
type: "line",
|
||||
data: n,
|
||||
symbol: 'none',
|
||||
};
|
||||
series.push(signal);
|
||||
series.push(noise);
|
||||
|
||||
let myChart: echarts.ECharts = echarts.init(div);
|
||||
var option: echarts.EChartsOption;
|
||||
myChart.setOption<echarts.EChartsOption>(
|
||||
(option = {
|
||||
title: { text: "Signal/Noise" },
|
||||
legend: {
|
||||
orient: "horizontal",
|
||||
right: 10,
|
||||
top: "bottom",
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: x,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'dB',
|
||||
},
|
||||
series: series
|
||||
})
|
||||
);
|
||||
option && myChart.setOption(option);
|
||||
} else if (event.msg == "DeviceExtCapacity") {
|
||||
console.log(event);
|
||||
let div = document.getElementById("extdev_cap_" + event.DeviceExtCapacity.device_id) as HTMLDivElement;
|
||||
|
||||
let down: number[] = [];
|
||||
let up: number[] = [];
|
||||
let x: any[] = [];
|
||||
|
||||
for (let i=0; i<event.DeviceExtCapacity.data.length; i++) {
|
||||
let d = event.DeviceExtCapacity.data[i];
|
||||
down.push(d.dl);
|
||||
up.push(d.ul);
|
||||
x.push(d.date);
|
||||
}
|
||||
|
||||
let series: echarts.SeriesOption[] = [];
|
||||
let signal: echarts.SeriesOption = {
|
||||
name: "Download",
|
||||
type: "line",
|
||||
data: down,
|
||||
symbol: 'none',
|
||||
};
|
||||
let noise: echarts.SeriesOption = {
|
||||
name: "Upload",
|
||||
type: "line",
|
||||
data: up,
|
||||
symbol: 'none',
|
||||
};
|
||||
series.push(signal);
|
||||
series.push(noise);
|
||||
|
||||
let myChart: echarts.ECharts = echarts.init(div);
|
||||
var option: echarts.EChartsOption;
|
||||
myChart.setOption<echarts.EChartsOption>(
|
||||
(option = {
|
||||
title: { text: "Estimated Capacity" },
|
||||
legend: {
|
||||
orient: "horizontal",
|
||||
right: 10,
|
||||
top: "bottom",
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: x,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'Mbps',
|
||||
axisLabel: {
|
||||
formatter: function (val: number) {
|
||||
return scaleNumber(Math.abs(val), 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
series: series
|
||||
})
|
||||
);
|
||||
option && myChart.setOption(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12" id="siteName">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="card">
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { request_circuit_parents } from "../../wasm/wasm_pipe";
|
||||
import { makeUrl } from "../helpers";
|
||||
import { Component } from "./component";
|
||||
|
||||
export class CircuitBreadcrumbs implements Component {
|
||||
circuitId: string;
|
||||
|
||||
constructor(siteId: string) {
|
||||
this.circuitId = siteId;
|
||||
}
|
||||
|
||||
wireup(): void {
|
||||
request_circuit_parents(this.circuitId);
|
||||
}
|
||||
|
||||
ontick(): void {
|
||||
}
|
||||
|
||||
onmessage(event: any): void {
|
||||
if (event.msg == "SiteParents") {
|
||||
//console.log(event.data);
|
||||
let div = document.getElementById("siteName") as HTMLDivElement;
|
||||
let html = "";
|
||||
let crumbs = event.SiteParents.data.reverse();
|
||||
for (let i = 0; i < crumbs.length; i++) {
|
||||
let url = makeUrl(crumbs[i][0], crumbs[i][1]);
|
||||
html += "<a href='#" + url + "' onclick='window.router.goto(\"" + url + "\")'>" + crumbs[i][1] + "</a> | ";
|
||||
}
|
||||
html = html.substring(0, html.length - 3);
|
||||
div.innerHTML = html;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { request_root_parents } from "../../wasm/wasm_pipe";
|
||||
import { makeUrl } from "../helpers";
|
||||
import { Component } from "./component";
|
||||
|
||||
export class RootBreadcrumbs implements Component {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
wireup(): void {
|
||||
let div = document.getElementById("siteName") as HTMLDivElement;
|
||||
div.innerHTML = "Root | <select id='siteChildren'></select>";
|
||||
request_root_parents();
|
||||
}
|
||||
|
||||
ontick(): void {
|
||||
}
|
||||
|
||||
onmessage(event: any): void {
|
||||
if (event.msg == "SiteChildren") {
|
||||
//console.log(event.data);
|
||||
let html = "<option value=''>-- Children --</option>";
|
||||
for (let i=0; i<event.SiteChildren.data.length; i++) {
|
||||
html += "<option value='" + makeUrl(event.SiteChildren.data[i][0], event.SiteChildren.data[i][1]) + "'>" + event.SiteChildren.data[i][2] + "</option>";
|
||||
}
|
||||
let select = document.getElementById("siteChildren") as HTMLSelectElement;
|
||||
select.innerHTML = html;
|
||||
select.onchange = () => {
|
||||
let select = document.getElementById("siteChildren") as HTMLSelectElement;
|
||||
window.router.goto(select.value);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ export class SiteStackChart implements Component {
|
||||
}
|
||||
|
||||
wireup(): void {
|
||||
request_site_stack(window.graphPeriod, this.siteId);
|
||||
}
|
||||
|
||||
ontick(): void {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { RttChart } from '../components/rtt_graph';
|
||||
import { RttHisto } from '../components/rtt_histo';
|
||||
import { RootHeat } from '../components/root_heat';
|
||||
import { SiteStackChart } from '../components/site_stack';
|
||||
import { RootBreadcrumbs } from '../components/root_breadcrumbs';
|
||||
|
||||
export class DashboardPage implements Page {
|
||||
menu: MenuPage;
|
||||
@@ -28,6 +29,7 @@ export class DashboardPage implements Page {
|
||||
new RttHisto(),
|
||||
new RootHeat(),
|
||||
new SiteStackChart("root"),
|
||||
new RootBreadcrumbs(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
<h1>Dashboard</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12" id="siteName">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="card">
|
||||
|
||||
@@ -6,15 +6,15 @@ export function getValueFromForm(id: string): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
export function scaleNumber(n: any): string {
|
||||
export function scaleNumber(n: any, decimals: number = 1): string {
|
||||
if (n >= 1000000000000) {
|
||||
return (n / 1000000000000).toFixed(1) + "T";
|
||||
return (n / 1000000000000).toFixed(decimals) + "T";
|
||||
} else if (n >= 1000000000) {
|
||||
return (n / 1000000000).toFixed(1) + "G";
|
||||
return (n / 1000000000).toFixed(decimals) + "G";
|
||||
} else if (n >= 1000000) {
|
||||
return (n / 1000000).toFixed(1) + "M";
|
||||
return (n / 1000000).toFixed(decimals) + "M";
|
||||
} else if (n >= 1000) {
|
||||
return (n / 1000).toFixed(1) + "K";
|
||||
return (n / 1000).toFixed(decimals) + "K";
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -104,6 +104,13 @@ export function request_site_info(site_id: string): void;
|
||||
*/
|
||||
export function request_site_parents(site_id: string): void;
|
||||
/**
|
||||
* @param {string} circuit_id
|
||||
*/
|
||||
export function request_circuit_parents(circuit_id: string): void;
|
||||
/**
|
||||
*/
|
||||
export function request_root_parents(): void;
|
||||
/**
|
||||
* @param {string} term
|
||||
*/
|
||||
export function request_search(term: string): void;
|
||||
@@ -115,6 +122,16 @@ export function request_circuit_info(circuit_id: string): void;
|
||||
* @param {string} circuit_id
|
||||
*/
|
||||
export function request_ext_device_info(circuit_id: string): void;
|
||||
/**
|
||||
* @param {string} period
|
||||
* @param {string} device_id
|
||||
*/
|
||||
export function request_ext_snr_graph(period: string, device_id: string): void;
|
||||
/**
|
||||
* @param {string} period
|
||||
* @param {string} device_id
|
||||
*/
|
||||
export function request_ext_capacity_graph(period: string, device_id: string): void;
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
@@ -142,9 +159,13 @@ export interface InitOutput {
|
||||
readonly request_tree: (a: number, b: number) => void;
|
||||
readonly request_site_info: (a: number, b: number) => void;
|
||||
readonly request_site_parents: (a: number, b: number) => void;
|
||||
readonly request_circuit_parents: (a: number, b: number) => void;
|
||||
readonly request_root_parents: () => void;
|
||||
readonly request_search: (a: number, b: number) => void;
|
||||
readonly request_circuit_info: (a: number, b: number) => void;
|
||||
readonly request_ext_device_info: (a: number, b: number) => void;
|
||||
readonly request_ext_snr_graph: (a: number, b: number, c: number, d: number) => void;
|
||||
readonly request_ext_capacity_graph: (a: number, b: number, c: number, d: number) => void;
|
||||
readonly __wbindgen_malloc: (a: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number) => number;
|
||||
readonly __wbindgen_export_2: WebAssembly.Table;
|
||||
|
||||
@@ -447,6 +447,21 @@ export function request_site_parents(site_id) {
|
||||
wasm.request_site_parents(ptr0, len0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} circuit_id
|
||||
*/
|
||||
export function request_circuit_parents(circuit_id) {
|
||||
const ptr0 = passStringToWasm0(circuit_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.request_circuit_parents(ptr0, len0);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export function request_root_parents() {
|
||||
wasm.request_root_parents();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} term
|
||||
*/
|
||||
@@ -474,6 +489,30 @@ export function request_ext_device_info(circuit_id) {
|
||||
wasm.request_ext_device_info(ptr0, len0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} period
|
||||
* @param {string} device_id
|
||||
*/
|
||||
export function request_ext_snr_graph(period, device_id) {
|
||||
const ptr0 = passStringToWasm0(period, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passStringToWasm0(device_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
wasm.request_ext_snr_graph(ptr0, len0, ptr1, len1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} period
|
||||
* @param {string} device_id
|
||||
*/
|
||||
export function request_ext_capacity_graph(period, device_id) {
|
||||
const ptr0 = passStringToWasm0(period, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passStringToWasm0(device_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
wasm.request_ext_capacity_graph(ptr0, len0, ptr1, len1);
|
||||
}
|
||||
|
||||
function handleError(f, args) {
|
||||
try {
|
||||
return f.apply(this, args);
|
||||
@@ -636,11 +675,11 @@ function __wbg_get_imports() {
|
||||
imports.wbg.__wbg_setonopen_6fd8b28538150568 = function(arg0, arg1) {
|
||||
getObject(arg0).onopen = getObject(arg1);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper1798 = function(arg0, arg1, arg2) {
|
||||
imports.wbg.__wbindgen_closure_wrapper1901 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 70, __wbg_adapter_12);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper1799 = function(arg0, arg1, arg2) {
|
||||
imports.wbg.__wbindgen_closure_wrapper1902 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 70, __wbg_adapter_12);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
|
||||
Binary file not shown.
@@ -23,9 +23,13 @@ export function request_site_heat(a: number, b: number, c: number, d: number): v
|
||||
export function request_tree(a: number, b: number): void;
|
||||
export function request_site_info(a: number, b: number): void;
|
||||
export function request_site_parents(a: number, b: number): void;
|
||||
export function request_circuit_parents(a: number, b: number): void;
|
||||
export function request_root_parents(): void;
|
||||
export function request_search(a: number, b: number): void;
|
||||
export function request_circuit_info(a: number, b: number): void;
|
||||
export function request_ext_device_info(a: number, b: number): void;
|
||||
export function request_ext_snr_graph(a: number, b: number, c: number, d: number): void;
|
||||
export function request_ext_capacity_graph(a: number, b: number, c: number, d: number): void;
|
||||
export function __wbindgen_malloc(a: number): number;
|
||||
export function __wbindgen_realloc(a: number, b: number, c: number): number;
|
||||
export const __wbindgen_export_2: WebAssembly.Table;
|
||||
|
||||
@@ -213,6 +213,16 @@ pub fn request_site_parents(site_id: String) {
|
||||
send_message(WasmRequest::SiteParents { site_id });
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn request_circuit_parents(circuit_id: String) {
|
||||
send_message(WasmRequest::CircuitParents { circuit_id });
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn request_root_parents() {
|
||||
send_message(WasmRequest::RootParents);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn request_search(term: String) {
|
||||
send_message(WasmRequest::Search { term });
|
||||
@@ -226,4 +236,14 @@ pub fn request_circuit_info(circuit_id: String) {
|
||||
#[wasm_bindgen]
|
||||
pub fn request_ext_device_info(circuit_id: String) {
|
||||
send_message(WasmRequest::ExtendedDeviceInfo { circuit_id });
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn request_ext_snr_graph(period: String, device_id: String) {
|
||||
send_message(WasmRequest::SignalNoiseChartExt { period, device_id });
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn request_ext_capacity_graph(period: String, device_id: String) {
|
||||
send_message(WasmRequest::DeviceCapacityChartExt { period, device_id });
|
||||
}
|
||||
@@ -24,9 +24,13 @@ pub enum WasmRequest {
|
||||
Tree { parent: String },
|
||||
SiteInfo { site_id: String },
|
||||
SiteParents { site_id: String },
|
||||
CircuitParents { circuit_id: String },
|
||||
RootParents,
|
||||
Search { term: String },
|
||||
CircuitInfo { circuit_id: String },
|
||||
ExtendedDeviceInfo { circuit_id: String },
|
||||
SignalNoiseChartExt { period: String, device_id: String },
|
||||
DeviceCapacityChartExt { period: String, device_id: String },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -52,6 +56,8 @@ pub enum WasmResponse {
|
||||
SearchResult { hits: Vec<SearchResult> },
|
||||
CircuitInfo { data: Vec<CircuitList> },
|
||||
DeviceExt { data: Vec<ExtendedDeviceInfo> },
|
||||
DeviceExtSnr { data: Vec<SignalNoiseChartExt>, device_id: String },
|
||||
DeviceExtCapacity { data: Vec<CapacityChartExt>, device_id: String },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -186,4 +192,18 @@ pub struct ExtendedDeviceInterface {
|
||||
pub status: String,
|
||||
pub speed: String,
|
||||
pub ip_list: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SignalNoiseChartExt {
|
||||
pub date: String,
|
||||
pub signal: f64,
|
||||
pub noise: f64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CapacityChartExt {
|
||||
pub date: String,
|
||||
pub dl: f64,
|
||||
pub ul: f64,
|
||||
}
|
||||
Reference in New Issue
Block a user