feat: add alert count badge to notification bell
Shows a red badge on the bell icon with the unresolved alert count. Displays the number when <= 100, blank red dot when > 100 (Apple-style). Count is loaded at mount and updated live when alerts change via PubSub. Uses process dictionary pattern (same as cookie consent) so no template changes needed across the 41 LiveView layouts.
This commit is contained in:
parent
ad4fde9415
commit
5d1d277697
2 changed files with 37 additions and 0 deletions
|
|
@ -115,6 +115,10 @@ defmodule ToweropsWeb.Layouts do
|
|||
default: nil,
|
||||
doc: "the currently active page (dashboard, sites, device, or alerts)"
|
||||
|
||||
attr :unresolved_alert_count, :integer,
|
||||
default: 0,
|
||||
doc: "number of unresolved alerts for the current organization"
|
||||
|
||||
slot :inner_block, required: true
|
||||
|
||||
def authenticated(assigns) do
|
||||
|
|
@ -122,6 +126,10 @@ defmodule ToweropsWeb.Layouts do
|
|||
requires_cookie_consent = Process.get(:requires_cookie_consent, false)
|
||||
assigns = Map.put(assigns, :requires_cookie_consent, requires_cookie_consent)
|
||||
|
||||
# Get unresolved alert count from process dictionary (set/updated in on_mount hook)
|
||||
unresolved_alert_count = Process.get(:unresolved_alert_count, 0)
|
||||
assigns = Map.put(assigns, :unresolved_alert_count, unresolved_alert_count)
|
||||
|
||||
# Extract organization and timezone from scope for template convenience
|
||||
current_organization = assigns[:current_scope] && assigns.current_scope.organization
|
||||
timezone = (assigns[:current_scope] && assigns.current_scope.timezone) || "UTC"
|
||||
|
|
@ -416,6 +424,15 @@ defmodule ToweropsWeb.Layouts do
|
|||
title={t("Alerts")}
|
||||
>
|
||||
<.icon name="hero-bell" class="h-5 w-5" />
|
||||
<%= if @unresolved_alert_count > 0 do %>
|
||||
<span class="absolute top-0.5 right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-red-500 px-0.5 text-[10px] font-bold leading-none text-white ring-1 ring-white dark:ring-gray-950">
|
||||
<%= if @unresolved_alert_count > 100 do %>
|
||||
|
||||
<% else %>
|
||||
{@unresolved_alert_count}
|
||||
<% end %>
|
||||
</span>
|
||||
<% end %>
|
||||
</.link>
|
||||
|
||||
<!-- Help icon -->
|
||||
|
|
|
|||
|
|
@ -546,10 +546,16 @@ defmodule ToweropsWeb.UserAuth do
|
|||
def on_mount(:subscribe_to_status_updates, _params, _session, socket) do
|
||||
organization = socket.assigns[:current_scope] && socket.assigns.current_scope.organization
|
||||
|
||||
alert_count =
|
||||
if organization, do: Towerops.Alerts.count_active_alerts(organization.id), else: 0
|
||||
|
||||
Process.put(:unresolved_alert_count, alert_count)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> maybe_subscribe_to_status_updates(organization)
|
||||
|> attach_status_title_hook(organization)
|
||||
|> attach_alert_count_hook(organization)
|
||||
|
||||
{:cont, socket}
|
||||
end
|
||||
|
|
@ -1003,4 +1009,18 @@ defmodule ToweropsWeb.UserAuth do
|
|||
{:cont, socket}
|
||||
end)
|
||||
end
|
||||
|
||||
defp attach_alert_count_hook(socket, nil), do: socket
|
||||
|
||||
defp attach_alert_count_hook(socket, organization) do
|
||||
LiveView.attach_hook(socket, :alert_count_updates, :handle_info, fn
|
||||
{:alert_changed, org_id}, socket when org_id == organization.id ->
|
||||
count = Towerops.Alerts.count_active_alerts(organization.id)
|
||||
Process.put(:unresolved_alert_count, count)
|
||||
{:cont, Phoenix.Component.assign(socket, :_alert_count_tick, count)}
|
||||
|
||||
_message, socket ->
|
||||
{:cont, socket}
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue