Current section
Files
Jump to
Current section
Files
lib/integrations/tls_cert/display.ex
defmodule Integrations.TlsCert.Display do
@moduledoc """
Dashboard panel for `Integrations.TlsCert` (same package).
Nested under the monitor's own namespace deliberately — the package's
top-level module name never changes, and this module's name is
guaranteed distinct from any separately-published standalone display
package. `Display.BundledDefault` auto-hooks this whenever
`Integrations.TlsCert` starts, the same as if they were still one module.
"""
use CodeNameRaven.Display, category: :infrastructure, size_hint: :medium
@default_port 443
@default_warn_days 30
@default_critical_days 7
@impl true
def display_name, do: "TLS Certificate"
@impl true
def compatible_monitors, do: [Integrations.TlsCert]
@impl true
def render(assigns) do
result = assigns[:result]
days_label =
if result do
d = result.days_remaining
cond do
d < 0 -> "Expired #{abs(d)}d ago"
d == 0 -> "Expires today"
true -> "#{d} days"
end
end
days_class =
if result do
d = result.days_remaining
warn = result[:warn_days] || @default_warn_days
crit = result[:critical_days] || @default_critical_days
cond do
d <= crit -> "text-error"
d <= warn -> "text-warning"
true -> "text-success"
end
else
""
end
assigns = Map.merge(assigns, %{
result: result,
days_label: days_label,
days_class: days_class
})
~H"""
<div class="space-y-3">
<div class="flex items-start justify-between gap-2">
<div class="min-w-0">
<h2 class="text-sm font-semibold text-base-content truncate">
<%= @config.name || host_port(@config.params) %>
</h2>
<p class="text-xs font-mono text-base-content/40 truncate">
<%= host_port(@config.params) %>
</p>
</div>
<CodeNameRaven.MonitorComponents.status_chip status={@status} />
</div>
<div :if={@result} class="grid grid-cols-2 gap-2">
<div class="bg-base-200 rounded-lg px-3 py-2 text-center">
<p class="text-xs text-base-content/40">Expiry</p>
<p class={"text-sm font-mono font-semibold #{@days_class}"}><%= @days_label %></p>
</div>
<div class="bg-base-200 rounded-lg px-3 py-2 text-center">
<p class="text-xs text-base-content/40">Not After</p>
<p class="text-xs font-mono font-semibold text-base-content">
<%= @result.not_after |> Date.to_string() %>
</p>
</div>
</div>
<div :if={@result} class="text-xs text-base-content/40 space-y-0.5">
<p>
<span class="text-base-content/30">Subject:</span>
<span class="font-mono"><%= @result.subject %></span>
</p>
<p>
<span class="text-base-content/30">Issuer:</span>
<span class="font-mono"><%= @result.issuer %></span>
</p>
</div>
<CodeNameRaven.MonitorComponents.error_message message={@last_error} />
<CodeNameRaven.MonitorComponents.check_time checked_at={@last_checked_at} />
</div>
"""
end
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
defp host_port(params) do
host = params[:host] || params["host"] || "?"
port = params[:port] || params["port"] || @default_port
"#{host}:#{port}"
end
end