diff --git a/meshview/web.py b/meshview/web.py index 65d69d8..ea145f5 100644 --- a/meshview/web.py +++ b/meshview/web.py @@ -431,8 +431,6 @@ async def packet_details_firehose(request): ) - - @routes.get("/packet/{packet_id}") async def packet(request): try: @@ -857,17 +855,28 @@ async def graph_traceroute2(request): } ) - # Create edges + # Create edges - organize by whether path is complete + incomplete_edges = [] + complete_edges = [] + for path in paths: color = '#' + hex(hash(tuple(path)))[3:9] - for src, dest in zip(path, path[1:], strict=False): - chart_edges.append( - { - "source": str(src), - "target": str(dest), - "originalColor": color, - } - ) + is_complete = path[-1] == dest + for src, dest_node in zip(path, path[1:], strict=False): + edge = { + "source": str(src), + "target": str(dest_node), + "originalColor": color, + } + if is_complete: + complete_edges.append(edge) + else: + incomplete_edges.append(edge) + + # Add incomplete edges first, then complete edges + # This ensures complete paths render on top + chart_edges.extend(incomplete_edges) + chart_edges.extend(complete_edges) chart_data = { "nodes": chart_nodes, @@ -1115,11 +1124,7 @@ async def net(request): @routes.get("/map") async def map(request): template = env.get_template("map.html") - return web.Response( - text=template.render(), - content_type="text/html" - ) - + return web.Response(text=template.render(), content_type="text/html") @routes.get("/stats") @@ -1321,6 +1326,7 @@ async def nodegraph(request): content_type="text/html", ) + # API Section ####################################################################### # How this works @@ -1476,7 +1482,6 @@ async def api_nodes(request): return web.json_response({"error": "Failed to fetch nodes"}, status=500) - @routes.get("/api/packets") async def api_packets(request): try: @@ -1500,14 +1505,16 @@ async def api_packets(request): for p in packets: payload = (p.payload or "").strip() - packets_json.append({ - "id": p.id, - "from_node_id": p.from_node_id, - "to_node_id": p.to_node_id, - "portnum": int(p.portnum) if p.portnum is not None else None, - "import_time": p.import_time.isoformat(), - "payload": payload, - }) + packets_json.append( + { + "id": p.id, + "from_node_id": p.from_node_id, + "to_node_id": p.to_node_id, + "portnum": int(p.portnum) if p.portnum is not None else None, + "import_time": p.import_time.isoformat(), + "payload": payload, + } + ) return web.json_response({"packets": packets_json}) @@ -1611,6 +1618,7 @@ async def api_edges(request): return web.json_response({"edges": edges_list}) + @routes.get("/api/config") async def api_config(request): try: @@ -1667,7 +1675,9 @@ async def api_config(request): "map_bottom_right_lon": get_float(site, "map_bottom_right_lon", -121.0), "map_interval": get_int(site, "map_interval", 3), "firehose_interval": get_int(site, "firehose_interval", 3), - "weekly_net_message": get_str(site, "weekly_net_message", "Weekly Mesh check-in message."), + "weekly_net_message": get_str( + site, "weekly_net_message", "Weekly Mesh check-in message." + ), "net_tag": get_str(site, "net_tag", "#BayMeshNet"), "version": str(SOFTWARE_RELEASE), } @@ -1676,6 +1686,7 @@ async def api_config(request): mqtt = CONFIG.get("mqtt", {}) topics_raw = get(mqtt, "topics", []) import json + if isinstance(topics_raw, str): try: topics = json.loads(topics_raw)