- H1: batch count queries in MobileController (org sites/devices/alerts, site device counts) — reduces 1+3N+2M queries to 4 + 2 - H2: batch Oban cancel for stop_device_checks — single ANY(?) query instead of one per check - H3: resolve_active_alerts_for_device uses update_all + deduped PubSub broadcasts (was N updates + N broadcasts) - H4: atomic ON CONFLICT upsert for auto-discovery checks; restore partial unique index dropped in 20260404000002 (dedup migration included) - H5: wrap apply_agent_to_all_equipment delete+insert in transaction so a failed insert_all rolls back the prior delete - H14: replace String.to_integer/1 on untrusted SNMP OID components with Integer.parse/1 + validation (neighbor_discovery, discovery storage index, printer supply index) - H15: ActivityFeedLive whitelists activity types against @all_types instead of String.to_existing_atom/1 - H16: defensive page param parsing in user_settings and admin dashboard LiveViews - H27: search sanitize/1 delegates to QueryHelpers.sanitize_like/1 which escapes backslash first - H30: JobCleanupTask no longer cancels jobs in "executing" state so in-flight polls complete naturally
54 lines
1.4 KiB
Elixir
54 lines
1.4 KiB
Elixir
defmodule ToweropsWeb.Admin.DashboardLive do
|
|
@moduledoc """
|
|
Admin dashboard showing system statistics and recent audit logs.
|
|
"""
|
|
use ToweropsWeb, :live_view
|
|
|
|
alias Towerops.Admin
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
{:ok,
|
|
socket
|
|
|> assign(:page_title, t("Dashboard"))
|
|
|> assign(:timezone, socket.assigns.current_scope.timezone)}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(params, _url, socket) do
|
|
page =
|
|
case Integer.parse(Map.get(params, "page", "1")) do
|
|
{n, _} when n >= 1 -> n
|
|
_ -> 1
|
|
end
|
|
|
|
per_page = 10
|
|
|
|
user_count = Admin.count_users()
|
|
org_count = Admin.count_organizations()
|
|
|
|
# Fetch all recent logs (limited to last 100 for performance)
|
|
all_logs = Admin.list_audit_logs(limit: 100)
|
|
total_count = length(all_logs)
|
|
total_pages = ceil(total_count / per_page)
|
|
|
|
# Ensure page is within valid range
|
|
page = max(1, min(page, max(1, total_pages)))
|
|
|
|
# Slice logs for current page
|
|
offset = (page - 1) * per_page
|
|
recent_logs = Enum.slice(all_logs, offset, per_page)
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:user_count, user_count)
|
|
|> assign(:org_count, org_count)
|
|
|> assign(:recent_logs, recent_logs)
|
|
|> assign(:pagination, %{
|
|
page: page,
|
|
per_page: per_page,
|
|
total_count: total_count,
|
|
total_pages: total_pages
|
|
})}
|
|
end
|
|
end
|