fedimint_server_ui/dashboard/latency.rs
1use std::collections::BTreeMap;
2use std::time::Duration;
3
4use fedimint_core::PeerId;
5use fedimint_server_core::dashboard_ui::{ConnectionType, P2PConnectionStatus};
6use maud::{Markup, html};
7
8pub fn render(
9 consensus_ord_latency: Option<Duration>,
10 p2p_connection_status: &BTreeMap<PeerId, Option<P2PConnectionStatus>>,
11) -> Markup {
12 html! {
13 div class="card h-100" id="consensus-latency" {
14 div class="card-header dashboard-header" { "System Latency" }
15 div class="card-body" {
16 @if let Some(duration) = consensus_ord_latency {
17 div class=(format!("alert {}", if duration.as_millis() < 1000 {
18 "alert-success"
19 } else if duration.as_millis() < 2000 {
20 "alert-warning"
21 } else {
22 "alert-danger"
23 })) {
24 "Consensus Latency: " strong {
25 (format!("{} ms", duration.as_millis()))
26 }
27 }
28 }
29 @if p2p_connection_status.is_empty() {
30 p { "No peer connections available." }
31 } @else {
32 table class="table table-striped" {
33 thead {
34 tr {
35 th { "ID" }
36 th { "Status" }
37 th { "Connection Type" }
38 th { "Round Trip" }
39 }
40 }
41 tbody {
42 @for (peer_id, status) in p2p_connection_status {
43 tr {
44 td { (peer_id.to_string()) }
45 td {
46 @match status {
47 Some(_) => {
48 span class="badge bg-success" { "Connected" }
49 }
50 None => {
51 span class="badge bg-danger" { "Disconnected" }
52 }
53 }
54 }
55 td {
56 @match status.as_ref().and_then(|s| s.conn_type) {
57 Some(ConnectionType::Direct) => {
58 span class="badge bg-success" { "Direct" }
59 }
60 Some(ConnectionType::Relay) => {
61 span class="badge bg-warning" { "Relay" }
62 }
63 Some(ConnectionType::Mixed) => {
64 span class="badge bg-info" { "Mixed" }
65 }
66 None => {
67 span class="text-muted" { "N/A" }
68 }
69 }
70 }
71 td {
72 @match status.as_ref().and_then(|s| s.rtt) {
73 Some(duration) => {
74 (format!("{} ms", duration.as_millis()))
75 }
76 None => {
77 span class="text-muted" { "N/A" }
78 }
79 }
80 }
81 }
82 }
83 }
84 }
85 }
86 }
87 }
88 }
89}