Added new searching capabilities to our node reports

This commit is contained in:
Pablo Revilla
2025-02-12 08:50:19 -08:00
parent 81703c9e49
commit 0556706a30
3 changed files with 52 additions and 24 deletions
+20 -20
View File
@@ -14,31 +14,31 @@ class Node(Base):
__tablename__ = "node"
id: Mapped[str] = mapped_column(primary_key=True)
node_id: Mapped[int] = mapped_column(BigInteger, nullable=True, unique=True)
long_name: Mapped[str]
short_name: Mapped[str]
hw_model: Mapped[str]
firmware: Mapped[str]
long_name: Mapped[str] = mapped_column(nullable=True)
short_name: Mapped[str] = mapped_column(nullable=True)
hw_model: Mapped[str] = mapped_column(nullable=True)
firmware: Mapped[str] = mapped_column(nullable=True)
role: Mapped[str] = mapped_column(nullable=True)
last_lat: Mapped[int] = mapped_column(BigInteger, nullable=True)
last_long: Mapped[int] = mapped_column(BigInteger, nullable=True)
channel: Mapped[str]
last_update: Mapped[datetime]
channel: Mapped[str] = mapped_column(nullable=True)
last_update: Mapped[datetime] = mapped_column(nullable=True)
class Packet(Base):
__tablename__ = "packet"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
portnum: Mapped[int]
from_node_id: Mapped[int] = mapped_column(BigInteger)
portnum: Mapped[int] = mapped_column(nullable=True)
from_node_id: Mapped[int] = mapped_column(BigInteger, nullable=True)
from_node: Mapped["Node"] = relationship(
primaryjoin="Packet.from_node_id == foreign(Node.node_id)", lazy="joined"
)
to_node_id: Mapped[int] = mapped_column(BigInteger)
to_node_id: Mapped[int] = mapped_column(BigInteger,nullable=True)
to_node: Mapped["Node"] = relationship(
primaryjoin="Packet.to_node_id == foreign(Node.node_id)", lazy="joined"
)
payload: Mapped[bytes]
import_time: Mapped[datetime]
channel: Mapped[str]
payload: Mapped[bytes] = mapped_column(nullable=True)
import_time: Mapped[datetime] = mapped_column(nullable=True)
channel: Mapped[str] = mapped_column(nullable=True)
class PacketSeen(Base):
@@ -49,13 +49,13 @@ class PacketSeen(Base):
lazy="joined", primaryjoin="PacketSeen.node_id == foreign(Node.node_id)"
)
rx_time: Mapped[int] = mapped_column(BigInteger, primary_key=True)
hop_limit: Mapped[int]
hop_limit: Mapped[int] = mapped_column(nullable=True)
hop_start: Mapped[int] = mapped_column(nullable=True)
channel: Mapped[str]
channel: Mapped[str] = mapped_column(nullable=True)
rx_snr: Mapped[float] = mapped_column(nullable=True)
rx_rssi: Mapped[int] = mapped_column(nullable=True)
topic: Mapped[str]
import_time: Mapped[datetime]
topic: Mapped[str] = mapped_column(nullable=True)
import_time: Mapped[datetime] = mapped_column(nullable=True)
class Traceroute(Base):
@@ -65,8 +65,8 @@ class Traceroute(Base):
packet: Mapped["Packet"] = relationship(
primaryjoin="Traceroute.packet_id == foreign(Packet.id)", lazy="joined"
)
gateway_node_id: Mapped[int] = mapped_column(BigInteger)
done: Mapped[bool]
route: Mapped[bytes]
import_time: Mapped[datetime]
gateway_node_id: Mapped[int] = mapped_column(BigInteger, nullable=True)
done: Mapped[bool] = mapped_column(nullable=True)
route: Mapped[bytes] = mapped_column(nullable=True)
import_time: Mapped[datetime] = mapped_column(nullable=True)
+1 -1
View File
@@ -34,7 +34,7 @@
</head>
<body hx-indicator="#spinner">
<br><div style="text-align:center"><strong>Bay Area Mesh - http://bayme.sh</strong></div>
<div style="text-align:center">Quick Links:&nbsp;&nbsp;<a href="/">Search for a node </a>&nbsp;-&nbsp;<a href="/chat">Conversations</a>&nbsp;-&nbsp;<a href="/firehose">See <strong>everything</strong> </a>&nbsp;-&nbsp;Mesh Graph <a href="/graph/longfast">LF</a>&nbsp;-&nbsp;<a href="/graph/mediumslow">MS </a>&nbsp;-&nbsp;<a href="/nodelist">Nodes</a>&nbsp;-&nbsp;<a href="/stats">Stats </a></div><br>
<div style="text-align:center">Quick Links:&nbsp;&nbsp;<a href="/nodelist">Nodes</a>&nbsp;-&nbsp;<a href="/chat">Conversations</a>&nbsp;-&nbsp;<a href="/firehose">See <strong>everything</strong> </a>&nbsp;-&nbsp;Mesh Graph <a href="/graph/longfast">LF</a>&nbsp;-&nbsp;<a href="/graph/mediumslow">MS </a>&nbsp;-&nbsp;<a href="/stats">Stats </a></div><br>
<div id="spinner" class="spinner-border secondary-primary htmx-indicator position-absolute top-50 start-50" role="status">
<span class="visually-hidden">Loading...</span>
</div>
+31 -3
View File
@@ -31,15 +31,16 @@ tr:nth-child(odd) {
display: flex;
gap: 10px;
margin-bottom: 10px;
align-items: center;
}
.search, .filter-role, .filter-channel, .export-btn {
.search, .filter-role, .filter-channel, .filter-hw_model, .export-btn {
padding: 8px;
border: 1px solid #333;
border-radius: 4px;
}
.filter-role, .filter-channel {
.filter-role, .filter-channel, .filter-hw_model {
cursor: pointer;
}
@@ -53,6 +54,12 @@ tr:nth-child(odd) {
.export-btn:hover {
background: #218838;
}
.node-count {
font-size: 16px;
font-weight: bold;
color: white;
}
{% endblock %}
{% block body %}
@@ -76,7 +83,18 @@ tr:nth-child(odd) {
{% endfor %}
</select>
<!-- Filter by HW Model Dropdown -->
<select class="filter-hw_model" onchange="applyFilters()">
<option value="">Filter by HW Model</option>
{% for node in nodes|groupby('hw_model') %}
<option value="{{ node.grouper }}">{{ node.grouper }}</option>
{% endfor %}
</select>
<button class="export-btn" onclick="exportToCSV()">Export to CSV</button>
<!-- Display the count of filtered nodes -->
<span class="node-count">Total Nodes: <span id="node-count-value">0</span></span>
</div>
{% if nodes %}
@@ -124,17 +142,27 @@ tr:nth-child(odd) {
valueNames: ["long_name", "short_name", "hw_model", "firmware", "role", "last_lat", "last_long", "channel", "last_update"]
};
nodeList = new List("node-list", options);
updateCount(); // Set initial count
});
function applyFilters() {
var selectedRole = document.querySelector(".filter-role").value;
var selectedChannel = document.querySelector(".filter-channel").value;
var selectedHWModel = document.querySelector(".filter-hw_model").value;
nodeList.filter(function (item) {
var matchesRole = selectedRole === "" || item.values().role === selectedRole;
var matchesChannel = selectedChannel === "" || item.values().channel === selectedChannel;
return matchesRole && matchesChannel;
var matchesHWModel = selectedHWModel === "" || item.values().hw_model === selectedHWModel;
return matchesRole && matchesChannel && matchesHWModel;
});
updateCount(); // Update the count after filtering
}
function updateCount() {
var visibleRows = document.querySelectorAll("#node-table tbody tr:not([style*='display: none'])").length;
document.getElementById("node-count-value").innerText = visibleRows;
}
function exportToCSV() {