defmodule ToweropsWeb.DeviceLive.Components.ChecksTab do @moduledoc """ LiveComponent for the device monitoring checks tab. Displays all monitoring checks for the device grouped by type (SNMP, HTTP, TCP, DNS, SSL, ping). """ use ToweropsWeb, :live_component alias Towerops.Monitoring alias ToweropsWeb.DeviceLive.Helpers.DataLoaders @impl true def update(assigns, socket) do {:ok, socket |> assign(assigns) |> load_checks_data()} end defp load_checks_data(socket) do device_id = socket.assigns.device.id organization_id = socket.assigns.device.organization_id checks_data = DataLoaders.load_checks_data(device_id, organization_id) socket |> assign(:checks, checks_data.checks) |> assign(:grouped_checks, checks_data.grouped_checks) end @impl true def render(assigns) do ~H"""
<%= if Enum.empty?(@checks) do %>
<.icon name="hero-clipboard-document-check" class="mx-auto h-12 w-12 text-gray-400" />

{t("No checks configured")}

{t( "Run discovery to automatically detect sensors, interfaces, and other monitorable items, or add a service check manually." )}

<%= if @device.snmp_enabled do %> <.button type="button" phx-click="run_discovery"> <.icon name="hero-magnifying-glass" class="h-4 w-4" /> Run Discovery <% end %> <.button type="button" phx-click="add_check"> <.icon name="hero-plus" class="h-4 w-4" /> Add Check
<% else %>

Checks ({length(@checks)})

<.button type="button" phx-click="add_check"> <.icon name="hero-plus" class="h-4 w-4" /> Add Check
<%= for {group_key, group_checks} <- @grouped_checks do %>

{group_title(group_key)} ({length(group_checks)})

<%= for check <- group_checks do %> <% end %>
{t("Name")} {t("Status")} {t("Value")} {t("Last Checked")} Actions
{check.name} {render_status_badge(check.current_state)} <%= if check.last_check_at do %> {get_latest_value(check)} <% else %> Pending <% end %> <%= if check.last_check_at do %> {format_relative_time(check.last_check_at)} <% else %> Never <% end %>
<.link navigate={ ~p"/devices/#{@device.id}/graph/check?check_id=#{check.id}&range=24h" } class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300 text-sm font-medium" > {t("Graph")} <%= if check.check_type in ["http", "tcp", "dns", "ssl"] do %> <% end %>
<% end %>
<% end %>
""" end # Helper functions defp group_title(:snmp_sensors), do: "SNMP Sensors" defp group_title(:snmp_interfaces), do: "SNMP Interfaces" defp group_title(:snmp_processors), do: "SNMP Processors" defp group_title(:snmp_storage), do: "SNMP Storage" defp group_title(:http_checks), do: "HTTP Checks" defp group_title(:tcp_checks), do: "TCP Checks" defp group_title(:dns_checks), do: "DNS Checks" defp group_title(:ssl_checks), do: "SSL Certificate Checks" defp group_title(:ping_checks), do: "Ping Checks" defp group_title(:other_checks), do: "Other Checks" defp render_status_badge(0) do assigns = %{} ~H""" OK """ end defp render_status_badge(1) do assigns = %{} ~H""" WARNING """ end defp render_status_badge(2) do assigns = %{} ~H""" CRITICAL """ end defp render_status_badge(3) do assigns = %{} ~H""" UNKNOWN """ end defp render_status_badge(_) do assigns = %{} ~H""" PENDING """ end defp get_latest_value(check) do # Get the latest check result to show current value case Monitoring.get_latest_check_result(check.id) do nil -> "-" result -> format_check_value(result, check) end end defp format_check_value(%{value: nil}, _check), do: "-" defp format_check_value(%{value: value}, check) when is_number(value) do case check.check_type do "snmp_sensor" -> format_check_sensor_value(value, check.config) "snmp_processor" -> "#{Float.round(value, 1)}%" "snmp_storage" -> "#{Float.round(value, 1)}%" t when t in ["ping", "http", "tcp", "dns"] -> "#{Float.round(value, 2)} ms" _ -> value |> Float.round(2) |> to_string() end end defp format_check_value(_result, _check), do: "-" @sensor_value_formats %{ "temperature" => {1, "°C"}, "voltage" => {2, "V"}, "current" => {2, "A"}, "power" => {1, "W"}, "frequency" => {0, "Hz"}, "humidity" => {1, "%"} } defp format_check_sensor_value(value, %{"sensor_type" => "fanspeed", "sensor_unit" => unit}) do "#{round(value)}#{unit || " RPM"}" end defp format_check_sensor_value(value, config) do sensor_type = config["sensor_type"] unit = config["sensor_unit"] {precision, default_unit} = Map.get(@sensor_value_formats, sensor_type, {2, ""}) "#{Float.round(value, precision)}#{unit || default_unit}" end defp format_relative_time(datetime) do ToweropsWeb.TimeHelpers.format_time_ago(datetime) end end