New updates to documentation

This commit is contained in:
Pablo Revilla
2025-08-18 14:27:00 -07:00
parent fedbd10bf8
commit b53bcd2d7b
3 changed files with 234 additions and 33 deletions

View File

@@ -0,0 +1,167 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>API Documentation - Packets</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css" />
<style>
body {
margin: 0;
background: #ffffff;
color: #000000;
}
#swagger-ui {
background: #ffffff;
color: #000000;
}
/* Override Swagger UI colors for white background */
.swagger-ui {
background-color: #ffffff !important;
color: #000000 !important;
}
.swagger-ui .topbar,
.swagger-ui .info,
.swagger-ui .opblock-summary-description,
.swagger-ui .parameters-col_description,
.swagger-ui .response-col_description {
color: #000000 !important;
}
.swagger-ui .opblock {
background-color: #f9f9f9 !important;
border-color: #ddd !important;
}
.swagger-ui .opblock-summary {
background-color: #eaeaea !important;
color: #000 !important;
}
.swagger-ui .opblock-section-header {
color: #000 !important;
}
.swagger-ui .parameters,
.swagger-ui .response {
background-color: #fafafa !important;
color: #000 !important;
}
.swagger-ui table {
color: #000 !important;
}
.swagger-ui a {
color: #1a0dab !important; /* classic link blue */
}
.swagger-ui input,
.swagger-ui select,
.swagger-ui textarea {
background-color: #fff !important;
color: #000 !important;
border: 1px solid #ccc !important;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script>
const spec = {
openapi: "3.0.0",
info: {
title: "Packets API",
version: "1.0.0",
description: "API for retrieving packet records with optional filters."
},
paths: {
"/api/packets": {
get: {
summary: "Get packets",
description: "Returns a list of recent packets, optionally filtered by a timestamp and limited by count.",
parameters: [
{
name: "limit",
in: "query",
required: false,
description: "Maximum number of packets to return. Default is 200.",
schema: {
type: "integer",
default: 200
}
},
{
name: "since",
in: "query",
required: false,
description: "Only return packets imported after this ISO8601 timestamp (e.g., `2025-08-12T14:15:20`).",
schema: {
type: "string",
format: "date-time"
}
}
],
responses: {
"200": {
description: "Successful response",
content: {
"application/json": {
schema: {
type: "object",
properties: {
packets: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "integer", example: 196988973 },
from_node_id: { type: "integer", example: 2381019191 },
to_node_id: { type: "integer", example: 1234567890 },
portnum: { type: "integer", example: 1 },
import_time: { type: "string", format: "date-time", example: "2025-08-12T14:15:20.503827" },
payload: { type: "string", example: "Hello Mesh" }
}
}
}
}
}
}
}
},
"500": {
description: "Internal server error",
content: {
"application/json": {
schema: {
type: "object",
properties: {
error: { type: "string", example: "Failed to fetch packets" }
}
}
}
}
}
}
}
}
}
};
window.onload = () => {
SwaggerUIBundle({
spec,
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "BaseLayout"
});
};
</script>
</body>
</html>

View File

@@ -111,7 +111,7 @@
value: `{{ node.long_name | tojson }}`,
symbol: 'circle',
symbolSize: 15,
itemStyle: { color: '#007bff' },
itemStyle: { color: '#007bff', opacity: 1},
label: {
show: true,
position: 'right',
@@ -138,7 +138,8 @@
originalColor: `{{ edge.originalColor }}`,
lineStyle: {
color: '#d3d3d3',
width: 2
width: 2,
opacity: 1
}
}{% if not loop.last %},{% endif %}
{% endfor %}
@@ -148,7 +149,6 @@
let filteredEdges = [];
let selectedChannel = 'LongFast';
let lastSelectedNode = null;
let currentZoom = 1;
function populateChannelDropdown() {
const channelSelect = document.getElementById('channel-select');
@@ -176,25 +176,43 @@
}
function updateChart() {
const baseSize = 15;
const adjustedSize = baseSize / currentZoom;
const updatedNodes = filteredNodes.map(node => ({
...node,
symbolSize: node.name === lastSelectedNode ? adjustedSize : adjustedSize,
itemStyle: {
color: node.name === lastSelectedNode ? '#ff8c00' : '#007bff'
const updatedNodes = filteredNodes.map(node => {
let opacity = 1;
let color = '#007bff';
if (lastSelectedNode) {
const connected = filteredEdges.some(e =>
(e.source === node.name && e.target === lastSelectedNode) ||
(e.target === node.name && e.source === lastSelectedNode)
);
if (node.name === lastSelectedNode) {
color = '#ff8c00'; // selected node orange
opacity = 1;
} else if (connected) {
opacity = 1; // keep neighbors visible
} else {
opacity = 0.4; // dim unrelated
}
}
}));
return {
...node,
itemStyle: { color, opacity }
};
});
const updatedEdges = filteredEdges.map(edge => {
const connected = edge.source === lastSelectedNode || edge.target === lastSelectedNode;
let opacity = .1;
let width = 2;
if (lastSelectedNode) {
const connected = edge.source === lastSelectedNode || edge.target === lastSelectedNode;
opacity = connected ? 1 : 0.05;
width = connected ? 2 : 1;
}
return {
...edge,
lineStyle: {
color: connected ? edge.originalColor : '#ccc',
width: connected ? 4 : 2,
opacity: connected ? 1 : 0.2
color: edge.originalColor || '#d3d3d3',
width,
opacity
}
};
});
@@ -211,16 +229,17 @@
});
}
chart.on('roam', function () {
const option = chart.getOption();
const zoom = option.series?.[0]?.zoom || 1;
currentZoom = zoom;
updateChart();
});
chart.on('click', function (params) {
if (params.dataType === 'node') {
updateSelectedNode(params.data.name);
} else {
// background click -> reset
lastSelectedNode = null;
updateChart();
document.getElementById('node-long-name').innerText = '';
document.getElementById('node-short-name').innerText = '';
document.getElementById('node-role').innerText = '';
document.getElementById('node-hw-model').innerText = '';
}
});

View File

@@ -1466,17 +1466,7 @@ async def get_config(request):
return web.json_response({"error": "Invalid configuration format"}, status=500)
@routes.get("/api-stats")
async def packet_details(request):
template = env.get_template("api-stats.html")
return web.Response(
text=template.render(
site_config = CONFIG,
SOFTWARE_RELEASE=SOFTWARE_RELEASE,
),
content_type="text/html",
)
# API Section
#######################################################################
# How this works
@@ -1707,6 +1697,31 @@ async def api_stats(request):
return web.json_response(stats)
@routes.get("/api-stats")
async def packet_details(request):
template = env.get_template("api-stats.html")
return web.Response(
text=template.render(
site_config = CONFIG,
SOFTWARE_RELEASE=SOFTWARE_RELEASE,
),
content_type="text/html",
)
@routes.get("/api-packets")
async def packet_details(request):
template = env.get_template("api-packets.html")
return web.Response(
text=template.render(
site_config = CONFIG,
SOFTWARE_RELEASE=SOFTWARE_RELEASE,
),
content_type="text/html",
)
async def run_server():
app = web.Application()