aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/dashboard
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/dashboard')
-rw-r--r--src/api/dashboard/dashboard.html42
1 files changed, 34 insertions, 8 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html
index bb49dd8..db8dd15 100644
--- a/src/api/dashboard/dashboard.html
+++ b/src/api/dashboard/dashboard.html
@@ -104,6 +104,9 @@
box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--bad) 50%, transparent); }
.legend .silent::before { border-top-style: dotted; --colour: var(--muted); }
.legend .hint::before { display: none; }
+ /* A kind of message: a dot in its colour, as on the map. */
+ .legend .message::before { width: 8px; height: 8px; border: none; border-radius: 50%;
+ background: var(--colour); }
#legends { flex: none; }
/* Hides the legend, and shows it again. */
button.toggle { font: inherit; font-size: 12px; text-transform: none; letter-spacing: 0;
@@ -184,6 +187,7 @@
<span class="node focus">in focus (click a node)</span>
</div>
<div class="legend" id="legend"></div>
+ <div class="legend" id="messages-legend"></div>
<div class="legend">
<span class="hint">drag to pan, wheel or pinch to zoom, turn with two fingers;
drag a node to move it, double-click it to pin it there or let it go</span>
@@ -1472,6 +1476,7 @@ flowsToggle.addEventListener("click", () => {
flowsShown = !flowsShown;
try { localStorage.setItem("continuum-flows", flowsShown ? "1" : "0"); } catch (_) {}
showFlowsToggle();
+ showMessagesLegend();
if (!flowsShown) {
flows.length = 0;
document.getElementById("flows").replaceChildren();
@@ -1485,6 +1490,23 @@ function messages(byKind) {
return Object.fromEntries(Object.entries(byKind || {})
.map(([kind, counter]) => [kind, { messages: counter.messages, bytes: counter.bytes }]));
}
+// The colour of a kind of message (`traffic`'s kinds), on the map and in the console;
+// the replies as their requests.
+const KIND_COLOURS = [["sync", "#ea580c"], ["blob", "#a16207"], ["hello", "#16a34a"],
+ ["status", "#e11d48"], ["identity", "#0d9488"], ["paths", "var(--muted)"],
+ ["links", "#db2777"]];
+const kindColour = kind => (KIND_COLOURS.find(([name]) => kind === name ||
+ kind === name + "Reply") || [null, "var(--fg)"])[1];
+function showMessagesLegend() {
+ const legend = document.getElementById("messages-legend");
+ legend.hidden = !flowsShown;
+ if (legend.childElementCount === 0) {
+ legend.append(...KIND_COLOURS.map(([kind, colour]) =>
+ el("span", { class: "message", style: "--colour: " + colour },
+ kind === "paths" ? "paths (pings)" : kind)));
+ }
+}
+showMessagesLegend();
// A dot's radius for a message of `bytes`: grows with the size's logarithm, from 1.5
// (a ping) to 8.
const dotRadius = bytes => Math.min(8, Math.max(1.5, 1.5 + 1.1 * Math.log10(1 + bytes / 32)));
@@ -1555,16 +1577,20 @@ const size = bytes => bytes < 1024 ? bytes + " B" : bytes < 1048576
? (bytes / 1024).toFixed(1) + " KiB" : (bytes / 1048576).toFixed(1) + " MiB";
// The lines, kept while the box is collapsed and drawn when it's opened (`showConsole`).
const consoleLines = [];
-function consoleLine([when, text]) {
- return el("div", {}, el("span", { class: "when" }, when + " "), text);
+// A line: when, what, and the messages by kind, each kind in its colour.
+function consoleLine([when, text, kinds]) {
+ const parts = [];
+ for (const [kind, count] of kinds) {
+ if (parts.length) parts.push(", ");
+ parts.push(el("span", { style: "color: " + kindColour(kind) }, kind), " " + count);
+ }
+ return el("div", {}, el("span", { class: "when" }, when + " "), text, " (", ...parts, ")");
}
function logTraffic(way, peer, total, kinds) {
- const parts = Object.entries(kinds).map(([kind, grown]) => kind + " " + grown.messages)
- .join(", ");
const bytes = Object.values(kinds).reduce((sum, grown) => sum + grown.bytes, 0);
const line = [new Date().toLocaleTimeString(),
- (way === "sent" ? "→ " : "← ") + name(peer) + ": " + total + ", " + size(bytes) +
- " (" + parts + ")"];
+ (way === "sent" ? "→ " : "← ") + name(peer) + ": " + total + ", " + size(bytes),
+ Object.entries(kinds).map(([kind, grown]) => [kind, grown.messages])];
consoleLines.push(line);
if (consoleLines.length > CONSOLE_LINES) consoleLines.shift();
if (hidden(document.getElementById("console-box"))) return;
@@ -1592,7 +1618,7 @@ function drawFlows() {
const p = positions.get(flow.from), q = positions.get(flow.to);
if (now < flow.start || !p || !q) continue;
const t = (now - flow.start) / FLOW_MS;
- dots.push({ x: p.x + (q.x - p.x) * t, y: p.y + (q.y - p.y) * t, r: flow.r,
+ dots.push({ x: p.x + (q.x - p.x) * t, y: p.y + (q.y - p.y) * t, r: flow.r, kind: flow.kind,
opacity: Math.sin(Math.PI * t) });
}
while (layer.children.length < dots.length) layer.append(svg("circle"));
@@ -1602,7 +1628,7 @@ function drawFlows() {
circle.setAttribute("cx", dot.x);
circle.setAttribute("cy", dot.y);
circle.setAttribute("r", dot.r.toFixed(1));
- circle.setAttribute("fill", "var(--self)");
+ circle.setAttribute("fill", kindColour(dot.kind));
circle.setAttribute("opacity", dot.opacity.toFixed(2));
});
if (flows.length > 0) flowFrame = requestAnimationFrame(drawFlows);