From 1b3404155c9a3940c00305901d541aece3563bbe Mon Sep 17 00:00:00 2001 From: Jamie Banks Date: Tue, 21 Jul 2026 11:05:17 +0100 Subject: [PATCH] refactor: :art: update dashboard activity data structure to use timestamps and add local hour bucketing --- app.py | 14 +++++++------- frontend/src/api.ts | 2 +- frontend/src/utils/datetime.ts | 11 +++++++++++ frontend/src/views/DashboardView.vue | 3 ++- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/app.py b/app.py index 08daf19..ac7d22d 100644 --- a/app.py +++ b/app.py @@ -2925,14 +2925,14 @@ def api_dashboard(): }) cursor.execute(''' - SELECT HOUR(timestamp) AS hour, COUNT(*) AS count - FROM AuditLog - WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 24 HOUR) - GROUP BY HOUR(timestamp) - ORDER BY hour + SELECT timestamp FROM AuditLog + WHERE timestamp >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 24 HOUR) ''') - activity_by_hour = {row['hour']: row['count'] for row in cursor.fetchall()} - activity = [{'hour': h, 'count': activity_by_hour.get(h, 0)} for h in range(24)] + activity = [ + row['timestamp'].strftime('%Y-%m-%d %H:%M:%S') + if hasattr(row['timestamp'], 'strftime') else str(row['timestamp']) + for row in cursor.fetchall() + ] return jsonify({ 'stats': { diff --git a/frontend/src/api.ts b/frontend/src/api.ts index c6ad8ce..929f182 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -213,7 +213,7 @@ export const api = { available: number; status: "active" | "alerting"; }[]; - activity: { hour: number; count: number }[]; + activity: string[]; }>(await fetchApi("/api/v2/dashboard")); }, async search(q: string) { diff --git a/frontend/src/utils/datetime.ts b/frontend/src/utils/datetime.ts index 9494565..208d22d 100644 --- a/frontend/src/utils/datetime.ts +++ b/frontend/src/utils/datetime.ts @@ -21,3 +21,14 @@ export function formatLocalTime(ts?: string | null, fallback = "—"): string { if (!d) return ts?.trim() || fallback; return d.toLocaleString(); } + +/** Bucket audit timestamps from the last 24h by local hour of day (0–23). */ +export function bucketActivityByLocalHour(timestamps: string[]): { hour: number; count: number }[] { + const counts = new Array(24).fill(0); + for (const ts of timestamps) { + const d = parseApiTimestamp(ts); + if (!d) continue; + counts[d.getHours()]++; + } + return counts.map((count, hour) => ({ hour, count })); +} diff --git a/frontend/src/views/DashboardView.vue b/frontend/src/views/DashboardView.vue index 1a273c8..e7b1f75 100644 --- a/frontend/src/views/DashboardView.vue +++ b/frontend/src/views/DashboardView.vue @@ -3,6 +3,7 @@ import { ref, onMounted, computed } from "vue"; import { RouterLink } from "vue-router"; import { Network, Wifi, Layers, Server } from "lucide-vue-next"; import { api } from "@/api"; +import { bucketActivityByLocalHour } from "@/utils/datetime"; interface DashboardStats { total_ips: number; @@ -46,7 +47,7 @@ onMounted(async () => { const d = await api.dashboard(); stats.value = d.stats; subnetOverview.value = d.subnet_overview; - activity.value = d.activity; + activity.value = bucketActivityByLocalHour(d.activity); } catch (e) { error.value = e instanceof Error ? e.message : "Failed to load dashboard"; } finally {