lib/luminous/panel/stat.ex

defmodule Luminous.Panel.Stat do
  require Decimal

  alias Luminous.{Dashboard, Utils}

  use Luminous.Panel

  @impl true
  # do we have a single number?
  def transform(n, _panel) when is_number(n) or Decimal.is_decimal(n) do
    [%{title: nil, value: n, unit: nil}]
  end

  # we have a map of values and the relevant attributes potentially
  def transform(data, panel) when is_map(data) or is_list(data) do
    data
    |> Enum.sort_by(fn {label, _} -> if(attr = panel.data_attributes[label], do: attr.order) end)
    |> Enum.map(fn {label, value} ->
      %{
        title: if(attr = panel.data_attributes[label], do: attr.title),
        value: value,
        unit: if(attr = panel.data_attributes[label], do: attr.unit)
      }
    end)
  end

  # fallback
  def transform(_), do: []

  @impl true
  def reduce(datasets, _panel, _dashboard), do: %{stats: datasets}

  @impl true
  def render(assigns) do
    ~H"""
    <%= case Dashboard.get_data(@dashboard, @panel.id) do %>
      <% %{stats: [_ | _] = stats} -> %>
        <div id={"#{Utils.dom_id(@panel)}-stat-values"} class={stats_grid_structure(length(stats))}>
          <%= for column <- stats do %>
            <div class="flex flex-col items-center">
              <div class="grow">
                <p class="text-lg"><%= column.title %></p>
              </div>
              <div>
                <span class="text-4xl font-bold"><%= Utils.print_number(column.value) %></span>
                <span class="text-2xl font-semibold"><%= column.unit %></span>
              </div>
            </div>
          <% end %>
        </div>
      <% _ -> %>
        <div class="flex flex-row items-center justify-center">
          <div id={"#{Utils.dom_id(@panel)}-stat-values"} class="text-4xl font-bold">-</div>
        </div>
    <% end %>
    """
  end

  defp stats_grid_structure(1), do: "grid grid-cols-1 w-full"
  defp stats_grid_structure(2), do: "grid grid-cols-2 w-full"
  defp stats_grid_structure(3), do: "grid grid-cols-3 w-full"
  defp stats_grid_structure(_), do: "grid grid-cols-4 w-full"
end