112 lines
3.0 KiB
Elixir
112 lines
3.0 KiB
Elixir
defmodule Luminous.Panel.Table do
|
|
alias Luminous.Attributes
|
|
|
|
use Luminous.Panel
|
|
|
|
@impl true
|
|
def data_attributes(),
|
|
do: [
|
|
title: [type: :string, default: ""],
|
|
halign: [type: {:in, [:left, :right, :center]}, default: :left],
|
|
table_totals: [type: {:in, [:avg, :sum, nil]}, default: nil],
|
|
number_formatting: [
|
|
type: :keyword_list,
|
|
keys: [
|
|
thousand_separator: [type: {:or, [:string, :boolean]}, default: false],
|
|
decimal_separator: [type: {:or, [:string, :boolean]}, default: false],
|
|
precision: [type: {:or, [:non_neg_integer, :boolean]}, default: false]
|
|
]
|
|
]
|
|
]
|
|
|
|
@impl true
|
|
def panel_attributes(),
|
|
do: [
|
|
hook: [type: :string, default: "TableHook"]
|
|
]
|
|
|
|
@impl true
|
|
def transform(rows, panel) do
|
|
col_defs =
|
|
rows
|
|
|> extract_labels()
|
|
|> Enum.map(fn label ->
|
|
attrs =
|
|
Map.get(panel.data_attributes, label) ||
|
|
Map.get(panel.data_attributes, to_string(label)) ||
|
|
Attributes.parse!([], data_attributes() ++ Attributes.Schema.data())
|
|
|
|
{label, attrs}
|
|
end)
|
|
|> Enum.sort_by(fn {_, attrs} -> attrs.order end)
|
|
|> Enum.map(fn {label, attrs} ->
|
|
%{
|
|
field: label,
|
|
title: attrs.title,
|
|
hozAlign: attrs.halign,
|
|
headerHozAlign: attrs.halign
|
|
}
|
|
|> add_table_totals_option(attrs)
|
|
|> add_number_formatting_option(attrs)
|
|
end)
|
|
|
|
%{rows: rows, columns: col_defs}
|
|
end
|
|
|
|
@impl true
|
|
def reduce(datasets, _panel, _dashboard) do
|
|
columns = Enum.flat_map(datasets, &Map.get(&1, :columns))
|
|
|
|
datasets =
|
|
datasets
|
|
|> Enum.map(&Map.get(&1, :rows))
|
|
|> Enum.zip()
|
|
|> Enum.map(&Tuple.to_list/1)
|
|
|> Enum.map(fn maps ->
|
|
Enum.reduce(maps, %{}, &Map.merge(&2, &1))
|
|
end)
|
|
|
|
%{rows: datasets, columns: columns}
|
|
end
|
|
|
|
@impl true
|
|
def actions(), do: [%{label: "Download CSV", event: "download:csv"}]
|
|
|
|
@impl true
|
|
def render(assigns) do
|
|
~H"""
|
|
<div class="w-full z-0">
|
|
<div id={"#{Luminous.Utils.dom_id(@panel)}"} phx-hook={@panel.hook} phx-update="ignore" />
|
|
</div>
|
|
"""
|
|
end
|
|
|
|
defp extract_labels(rows) when is_list(rows) do
|
|
rows
|
|
|> Enum.flat_map(&Map.keys/1)
|
|
|> Enum.uniq()
|
|
end
|
|
|
|
defp add_table_totals_option(col_params, attr) do
|
|
if is_nil(attr.table_totals),
|
|
do: col_params,
|
|
else: Map.put(col_params, :bottomCalc, attr.table_totals)
|
|
end
|
|
|
|
defp add_number_formatting_option(col_params, %{number_formatting: nf}) do
|
|
formatterParams = %{
|
|
thousand: Keyword.get(nf, :thousand_separator),
|
|
decimal: Keyword.get(nf, :decimal_separator),
|
|
precision: Keyword.get(nf, :precision)
|
|
}
|
|
|
|
col_params
|
|
|> Map.put(:formatter, "money")
|
|
|> Map.put(:formatterParams, formatterParams)
|
|
|> Map.put(:bottomCalcFormatter, "money")
|
|
|> Map.put(:bottomCalcFormatterParams, formatterParams)
|
|
end
|
|
|
|
defp add_number_formatting_option(col_params, _), do: col_params
|
|
end
|