defmodule Integrations.HttpDisplay do @moduledoc """ HTTP endpoint monitor's dashboard panel — display only, no collection. Renders the same panel `raven_integration_http`'s bundled module does, but as a standalone display with its own configurable watch-list of monitor ids — proof-of-shape package for `#261` (see `code-name-raven`'s backlog, "Display as an Independent, Installable Role"): the "separately-published display, no bundled monitor to assume" case. Declares compatibility with `Integrations.HttpMonitor` via `compatible_monitors/0`, but will render for any watched monitor whose collected result matches the shape it expects (`:status_code`, `:latency_ms`, `:timing`, etc.) — the same params `raven_integration_http_monitor` produces. """ use CodeNameRaven.Display, category: :web, size_hint: :full def display_timezone, do: "America/Chicago" @impl true def compatible_monitors, do: [Integrations.HttpMonitor] @impl true def render(assigns) do window_seconds = assigns.config.display_window_seconds cutoff = DateTime.add(DateTime.utc_now(), -window_seconds, :second) sample_key = Map.get(assigns.config, :target_id) || assigns.config.id samples = CodeNameRaven.Runtime.recent_samples(sample_key, limit: 120) samples = Enum.filter(samples, fn s -> DateTime.compare(s.collected_at, cutoff) != :lt end) local_id = CodeNameRaven.Runtime.instance_id() latest_local = samples |> Enum.filter(&(&1.instance_id == local_id)) |> List.last() result = assigns[:result] || (latest_local && %{ status_code: latest_local.status_code, latency_ms: latest_local.latency_ms, cert_expiry_days: latest_local.metrics["cert_expiry_days"], timing: %{ dns_ms: latest_local.metrics["dns_ms"], tcp_ms: latest_local.metrics["tcp_ms"], ssl_ms: latest_local.metrics["ssl_ms"], ttfb_ms: latest_local.metrics["ttfb_ms"], download_ms: latest_local.metrics["download_ms"] }, redirects: latest_local.metrics["redirects"] }) assigns = Map.merge(assigns, %{samples: samples, local_id: local_id, result: result}) ~H"""
<%!-- Header --%>

<%= @config.name || @config.params[:url] || "HTTP Check" %>

<%= @config.params[:url] %>

<.status_chip status={@status} />
<%!-- Vital row --%>
<.stat label="Status" value={to_string(@result.status_code)} /> <.stat label="Latency" value={"#{@result.latency_ms} ms"} />

Cert Expiry

<%= @result.cert_expiry_days %>d

0} class="bg-base-200 rounded-lg px-3 py-2 flex-1 text-center">

Redirects

<%= @result.redirects %>

<%!-- Timing Breakdown --%>
DNS <%= @result.timing.dns_ms %>ms
TCP <%= @result.timing.tcp_ms %>ms
SSL <%= if @result.timing.ssl_ms, do: "#{@result.timing.ssl_ms}ms", else: "—" %>
TTFB <%= @result.timing.ttfb_ms %>ms
Download <%= @result.timing.download_ms %>ms
<%!-- Assertions Check --%>

Assertions Check

<%= for assertion <- @result.assertions do %> <% outcome = CodeNameRaven.Monitor.Assertion.evaluate(assertion, @result) %>
<%= assertion.type %><%= if assertion.target, do: " [#{assertion.target}]" %> <%= assertion.operator %> <%= inspect(assertion.value) %> <%= if outcome == :pass do %> ✓ Pass <% else %> ✗ Fail <% end %>
<% end %>
<%!-- Error --%>

<%= @last_error %>

<%!-- Footer --%>

Checked <%= CodeNameRaven.Timezone.format_datetime(@last_checked_at, __MODULE__) %>

""" end # --------------------------------------------------------------------------- # Private components # --------------------------------------------------------------------------- defp status_chip(%{status: :up} = assigns) do ~H""" Up """ end defp status_chip(%{status: :degraded} = assigns) do ~H""" Degraded """ end defp status_chip(%{status: :down} = assigns) do ~H""" Down """ end defp status_chip(assigns) do ~H""" Unknown """ end defp stat(assigns) do ~H"""

<%= @label %>

<%= @value %>

""" end end