diff --git a/src/meshcore_hub/api/routes/dashboard.py b/src/meshcore_hub/api/routes/dashboard.py
index 621d576..c725fab 100644
--- a/src/meshcore_hub/api/routes/dashboard.py
+++ b/src/meshcore_hub/api/routes/dashboard.py
@@ -31,6 +31,7 @@ async def get_stats(
now = datetime.now(timezone.utc)
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
yesterday = now - timedelta(days=1)
+ seven_days_ago = now - timedelta(days=7)
# Total nodes
total_nodes = session.execute(select(func.count()).select_from(Node)).scalar() or 0
@@ -73,6 +74,26 @@ async def get_stats(
or 0
)
+ # Advertisements in last 7 days
+ advertisements_7d = (
+ session.execute(
+ select(func.count())
+ .select_from(Advertisement)
+ .where(Advertisement.received_at >= seven_days_ago)
+ ).scalar()
+ or 0
+ )
+
+ # Messages in last 7 days
+ messages_7d = (
+ session.execute(
+ select(func.count())
+ .select_from(Message)
+ .where(Message.received_at >= seven_days_ago)
+ ).scalar()
+ or 0
+ )
+
# Recent advertisements (last 10)
recent_ads = (
session.execute(
@@ -185,8 +206,10 @@ async def get_stats(
active_nodes=active_nodes,
total_messages=total_messages,
messages_today=messages_today,
+ messages_7d=messages_7d,
total_advertisements=total_advertisements,
advertisements_24h=advertisements_24h,
+ advertisements_7d=advertisements_7d,
recent_advertisements=recent_advertisements,
channel_message_counts=channel_message_counts,
channel_messages=channel_messages,
diff --git a/src/meshcore_hub/common/schemas/messages.py b/src/meshcore_hub/common/schemas/messages.py
index 72ef361..7a26900 100644
--- a/src/meshcore_hub/common/schemas/messages.py
+++ b/src/meshcore_hub/common/schemas/messages.py
@@ -239,10 +239,14 @@ class DashboardStats(BaseModel):
active_nodes: int = Field(..., description="Nodes active in last 24h")
total_messages: int = Field(..., description="Total number of messages")
messages_today: int = Field(..., description="Messages received today")
+ messages_7d: int = Field(default=0, description="Messages received in last 7 days")
total_advertisements: int = Field(..., description="Total advertisements")
advertisements_24h: int = Field(
default=0, description="Advertisements received in last 24h"
)
+ advertisements_7d: int = Field(
+ default=0, description="Advertisements received in last 7 days"
+ )
recent_advertisements: list[RecentAdvertisement] = Field(
default_factory=list, description="Last 10 advertisements"
)
diff --git a/src/meshcore_hub/web/templates/home.html b/src/meshcore_hub/web/templates/home.html
index a13d111..36ee5cb 100644
--- a/src/meshcore_hub/web/templates/home.html
+++ b/src/meshcore_hub/web/templates/home.html
@@ -19,25 +19,25 @@
{% endif %}
-
+
@@ -62,7 +62,7 @@
All discovered nodes
-
+
Advertisements
-
{{ stats.advertisements_24h }}
-
Received in last 24 hours
+
{{ stats.advertisements_7d }}
+
Last 7 days
-
+
-
Total Messages
-
{{ stats.total_messages }}
-
All time
-
-
-
-
-
-
Messages Today
-
{{ stats.messages_today }}
-
Last 24 hours
+
Messages
+
{{ stats.messages_7d }}
+
Last 7 days
@@ -239,8 +227,8 @@
datasets: [{
label: 'Advertisements',
data: counts,
- borderColor: 'oklch(0.7 0.15 250)',
- backgroundColor: 'oklch(0.7 0.15 250 / 0.1)',
+ borderColor: 'oklch(0.7 0.17 330)',
+ backgroundColor: 'oklch(0.7 0.17 330 / 0.1)',
fill: true,
tension: 0.3,
pointRadius: 2,
diff --git a/src/meshcore_hub/web/templates/network.html b/src/meshcore_hub/web/templates/network.html
index 48724ed..65dc7a6 100644
--- a/src/meshcore_hub/web/templates/network.html
+++ b/src/meshcore_hub/web/templates/network.html
@@ -22,8 +22,63 @@
{% endif %}
+
+
+
+
+
+
Total Nodes
+
{{ stats.total_nodes }}
+
All discovered nodes
+
+
+
+
+
+
Advertisements
+
{{ stats.advertisements_7d }}
+
Last 7 days
+
+
+
+
+
+
Messages
+
{{ stats.messages_7d }}
+
Last 7 days
+
+
+
+
+
+
+
+
+ Total Nodes
+
+
Over time (last 7 days)
+
+
+
+
+
+
-
-
-
-
-
-
- Total Nodes
-
-
Over time (last 7 days)
-
-
-
-
-
@@ -163,27 +202,6 @@
{% endif %}
-
-
{% endblock %}
{% block extra_scripts %}
@@ -232,7 +250,7 @@
});
}
- // Advertisements chart
+ // Advertisements chart (secondary color - pink/magenta)
const advertCtx = document.getElementById('advertChart');
if (advertCtx && advertData.data && advertData.data.length > 0) {
new Chart(advertCtx, {
@@ -242,8 +260,8 @@
datasets: [{
label: 'Advertisements',
data: advertData.data.map(d => d.count),
- borderColor: 'oklch(0.7 0.15 250)',
- backgroundColor: 'oklch(0.7 0.15 250 / 0.1)',
+ borderColor: 'oklch(0.7 0.17 330)',
+ backgroundColor: 'oklch(0.7 0.17 330 / 0.1)',
fill: true,
tension: 0.3,
pointRadius: 2,
@@ -254,7 +272,7 @@
});
}
- // Messages chart
+ // Messages chart (accent color - teal/cyan)
const messageCtx = document.getElementById('messageChart');
if (messageCtx && messageData.data && messageData.data.length > 0) {
new Chart(messageCtx, {
@@ -264,8 +282,8 @@
datasets: [{
label: 'Messages',
data: messageData.data.map(d => d.count),
- borderColor: 'oklch(0.7 0.15 160)',
- backgroundColor: 'oklch(0.7 0.15 160 / 0.1)',
+ borderColor: 'oklch(0.75 0.18 180)',
+ backgroundColor: 'oklch(0.75 0.18 180 / 0.1)',
fill: true,
tension: 0.3,
pointRadius: 2,
@@ -276,7 +294,7 @@
});
}
- // Node count chart
+ // Node count chart (primary color - purple/blue)
const nodeCtx = document.getElementById('nodeChart');
if (nodeCtx && nodeData.data && nodeData.data.length > 0) {
new Chart(nodeCtx, {
@@ -286,8 +304,8 @@
datasets: [{
label: 'Total Nodes',
data: nodeData.data.map(d => d.count),
- borderColor: 'oklch(0.7 0.15 30)',
- backgroundColor: 'oklch(0.7 0.15 30 / 0.1)',
+ borderColor: 'oklch(0.65 0.24 265)',
+ backgroundColor: 'oklch(0.65 0.24 265 / 0.1)',
fill: true,
tension: 0.3,
pointRadius: 2,