Add latency graph to site detail page

Shows ping latency for all devices in the site over the last 24 hours.
Each device is displayed as a separate line on the graph with its name
as the label.

Graph only appears if there is latency data available for at least
one device in the site.
This commit is contained in:
Graham McIntire 2026-01-17 16:58:59 -06:00
parent c4760ca0dc
commit 35ca827bd0
No known key found for this signature in database
2 changed files with 64 additions and 1 deletions

View file

@ -3,6 +3,7 @@ defmodule ToweropsWeb.SiteLive.Show do
use ToweropsWeb, :live_view
alias Towerops.Devices
alias Towerops.Monitoring
alias Towerops.Sites
@impl true
@ -15,11 +16,49 @@ defmodule ToweropsWeb.SiteLive.Show do
organization = socket.assigns.current_organization
site = Sites.get_organization_site!(organization.id, id)
device = Devices.list_site_devices(site.id)
latency_chart_data = load_site_latency_chart_data(device)
{:noreply,
socket
|> assign(:page_title, site.name)
|> assign(:site, site)
|> assign(:device, device)}
|> assign(:device, device)
|> assign(:latency_chart_data, latency_chart_data)}
end
defp load_site_latency_chart_data(devices) do
if Enum.empty?(devices) do
nil
else
twenty_four_hours_ago = DateTime.add(DateTime.utc_now(), -24, :hour)
datasets =
devices
|> Enum.map(fn device ->
checks =
device.id
|> Monitoring.get_latency_data(since: twenty_four_hours_ago, limit: 1000)
|> Enum.reverse()
%{
label: device.name,
data: Enum.map(checks, &latency_check_to_data_point/1)
}
end)
|> Enum.reject(fn dataset -> Enum.empty?(dataset.data) end)
if Enum.empty?(datasets) do
nil
else
Jason.encode!(%{datasets: datasets})
end
end
end
defp latency_check_to_data_point(check) do
%{
x: DateTime.to_unix(check.checked_at, :millisecond),
y: check.response_time_ms
}
end
end

View file

@ -120,4 +120,28 @@
<% end %>
</div>
</div>
<!-- Latency Chart -->
<%= if @latency_chart_data do %>
<div class="mt-8">
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
<div class="px-4 py-3 border-b border-zinc-200 dark:border-zinc-700">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
Site Latency - Last 24 Hours
</h3>
</div>
<div class="p-4">
<div
id="site-latency-chart"
phx-hook="SensorChart"
data-chart={@latency_chart_data}
data-unit="ms"
data-auto-scale="true"
style="height: 400px;"
>
<canvas></canvas>
</div>
</div>
</div>
</div>
<% end %>
</Layouts.authenticated>