From 62b8ec7afdd3d741fd28b3aeea0ba7af50ab7703 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 13 Feb 2026 08:58:19 -0600 Subject: [PATCH] add contextual insights to device preseem tab --- lib/towerops_web/live/device_live/show.ex | 21 ++++++- .../live/device_live/show.html.heex | 57 +++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/lib/towerops_web/live/device_live/show.ex b/lib/towerops_web/live/device_live/show.ex index 9a93f179..905c69c3 100644 --- a/lib/towerops_web/live/device_live/show.ex +++ b/lib/towerops_web/live/device_live/show.ex @@ -436,16 +436,20 @@ defmodule ToweropsWeb.DeviceLive.Show do device = socket.assigns.device preseem_ap = Towerops.Preseem.get_access_point_for_device(device.id) - metrics = + {metrics, insights} = if preseem_ap do - Towerops.Preseem.list_subscriber_metrics(preseem_ap.id, limit: 50) + { + Towerops.Preseem.list_subscriber_metrics(preseem_ap.id, limit: 50), + Towerops.Preseem.list_device_insights(device.id) + } else - [] + {[], []} end socket |> assign(:preseem_access_point, preseem_ap) |> assign(:preseem_metrics, metrics) + |> assign(:preseem_insights, insights) end defp get_available_firmware(nil), do: nil @@ -1222,6 +1226,17 @@ defmodule ToweropsWeb.DeviceLive.Show do {:noreply, assign(socket, :selected_backup_ids, MapSet.new())} end + @impl true + def handle_event("dismiss_insight", %{"id" => insight_id}, socket) do + case Towerops.Preseem.dismiss_insight(insight_id) do + {:ok, _} -> + {:noreply, assign_preseem_data(socket)} + + {:error, _} -> + {:noreply, put_flash(socket, :error, "Failed to dismiss insight")} + end + end + @impl true def handle_event("delete_backup", %{"id" => backup_id}, socket) do import ToweropsWeb.Permissions diff --git a/lib/towerops_web/live/device_live/show.html.heex b/lib/towerops_web/live/device_live/show.html.heex index a0c643d8..7ce92a16 100644 --- a/lib/towerops_web/live/device_live/show.html.heex +++ b/lib/towerops_web/live/device_live/show.html.heex @@ -2206,6 +2206,63 @@ <% "preseem" -> %> <%= if @preseem_access_point do %>
+ <%!-- Insights section --%> + <%= if @preseem_insights != [] do %> +
+ <%= for insight <- @preseem_insights do %> +
+ "bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-800" + + "warning" -> + "bg-yellow-50 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800" + + _ -> + "bg-blue-50 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800" + end + ]}> +
+
"text-red-500" + "warning" -> "text-yellow-500" + _ -> "text-blue-500" + end + ]}> + <%= case insight.urgency do %> + <% "critical" -> %> + <.icon name="hero-exclamation-triangle" class="h-5 w-5" /> + <% "warning" -> %> + <.icon name="hero-exclamation-circle" class="h-5 w-5" /> + <% _ -> %> + <.icon name="hero-information-circle" class="h-5 w-5" /> + <% end %> +
+
+

+ {insight.title} +

+

+ {insight.description} +

+
+
+ +
+ <% end %> +
+ <% end %> + <%!-- Score cards --%>