defmodule LiveAdmin.Components.Container do
use Phoenix.LiveView
use PhoenixHTMLHelpers
import LiveAdmin,
only: [
resource_title: 1,
route_with_params: 1,
route_with_params: 2,
trans: 1
]
import LiveAdmin.Components
alias LiveAdmin.Resource
alias Phoenix.LiveView.JS
@impl true
def mount(_params, %{"components" => components}, socket) do
socket =
assign(socket,
default_mod: Map.fetch!(components, socket.assigns.live_action),
loading: !connected?(socket)
)
if connected?(socket), do: Process.send_after(self(), :clear_flash, 2000)
{:ok, socket}
end
@impl true
def handle_info(:clear_flash, socket) do
{:noreply, clear_flash(socket)}
end
@impl true
def handle_params(
params = %{"record_id" => id},
uri,
socket = %{assigns: %{live_action: action, loading: false}}
)
when action in [:edit, :view] do
socket =
socket
|> assign_resource_info(uri)
|> assign_mod()
|> assign_repo()
|> assign_prefix(params)
record =
Resource.find(id, socket.assigns.resource, socket.assigns[:prefix], socket.assigns.repo)
socket = assign(socket, record: record)
{:noreply, socket}
end
@impl true
def handle_params(params, uri, socket = %{assigns: %{live_action: :list, loading: false}}) do
socket =
socket
|> assign(page: String.to_integer(params["page"] || "1"))
|> assign(sort_attr: String.to_existing_atom(params["sort-attr"] || "id"))
|> assign(sort_dir: String.to_existing_atom(params["sort-dir"] || "asc"))
|> assign(search: params["s"])
|> assign_resource_info(uri)
|> assign_mod()
|> assign_repo()
|> assign_prefix(params)
{:noreply, socket}
end
@impl true
def handle_params(params, uri, socket = %{assigns: %{live_action: :new}}),
do:
{:noreply,
socket
|> assign_resource_info(uri)
|> assign_mod()
|> assign_repo()
|> assign_prefix(params)}
def handle_params(_, _, socket), do: {:noreply, socket}
@impl true
def handle_event("set_locale", %{"locale" => locale}, socket) do
new_session = Map.put(socket.assigns.session, :locale, locale)
LiveAdmin.session_store().persist!(new_session)
{:noreply, assign(socket, :session, new_session)}
end
def render(assigns = %{loading: true}), do: ~H""
@impl true
def render(assigns) do
~H"""
<div class="resource__banner">
<h1 class="resource__title">
<%= resource_title(@resource) %>
</h1>
<div class="resource__actions">
<div>
<.link
navigate={route_with_params(assigns, params: [prefix: @prefix])}
class="resource__action--btn"
>
<%= trans("List") %>
</.link>
<%= if @resource.__live_admin_config__(:create_with) != false do %>
<.link
navigate={route_with_params(assigns, segments: ["new"], params: [prefix: @prefix])}
class="resource__action--btn"
>
<%= trans("New") %>
</.link>
<% else %>
<button class="resource__action--disabled" disabled="disabled">
<%= trans("New") %>
</button>
<% end %>
<.dropdown
:let={task}
label={trans("Run task")}
items={get_task_keys(@resource)}
disabled={@resource |> get_task_keys() |> Enum.empty?()}
>
<button
class="resource__action--link"
phx-click={JS.push("task", value: %{task: task}, page_loading: true, target: "#list")}
,
data-confirm="Are you sure?"
>
<%= task |> to_string() |> humanize() %>
</button>
</.dropdown>
<%= if Enum.any?(@prefix_options) do %>
<.dropdown
:let={prefix}
id="prefix-select"
label={@prefix || trans("Set prefix")}
items={[""] ++ Enum.filter(@prefix_options, &(to_string(&1) != @prefix))}
>
<.link navigate={route_with_params(assigns, params: [prefix: prefix])}>
<%= if prefix == "", do: trans("clear"), else: prefix %>
</.link>
</.dropdown>
<% end %>
<%= if LiveAdmin.use_i18n? do %>
<.dropdown
:let={locale}
id="locale-select"
label={@session.locale || "Set locale"}
items={
Enum.filter(
LiveAdmin.gettext_backend().locales(),
&(to_string(&1) != @session.locale)
)
}
>
<button
class="resource__action--link"
phx-click={JS.push("set_locale", value: %{locale: locale}, page_loading: true)}
>
<%= locale %>
</button>
</.dropdown>
<% end %>
</div>
</div>
</div>
<%= render("#{@live_action}.html", assigns) %>
"""
end
def render("list.html", assigns) do
~H"""
<.live_component
module={@mod}
id="list"
key={@key}
resource={@resource}
page={@page}
sort_attr={@sort_attr}
sort_dir={@sort_dir}
search={@search}
prefix={@prefix}
session={@session}
base_path={@base_path}
resources={@resources}
repo={@repo}
/>
"""
end
def render("new.html", assigns) do
~H"""
<.live_component
module={@mod}
id="form"
action="create"
session={@session}
key={@key}
resources={@resources}
resource={@resource}
prefix={@prefix}
base_path={@base_path}
repo={@repo}
/>
"""
end
def render("edit.html", assigns) do
~H"""
<.live_component
module={@mod}
id="form"
action="update"
session={@session}
key={@key}
record={@record}
resources={@resources}
resource={@resource}
prefix={@prefix}
repo={@repo}
base_path={@base_path}
/>
"""
end
def render("view.html", assigns) do
~H"""
<.live_component
module={@mod}
id="view"
record={@record}
resource={@resource}
resources={@resources}
session={@session}
key={@key}
base_path={@base_path}
prefix={@prefix}
repo={@repo}
/>
"""
end
defp assign_prefix(socket, %{"prefix" => ""}) do
socket
|> assign_and_presist_prefix(nil)
|> push_redirect(to: route_with_params(socket.assigns))
end
defp assign_prefix(socket, %{"prefix" => prefix}) do
socket.assigns.prefix_options
|> Enum.find(fn option -> to_string(option) == prefix end)
|> case do
nil ->
push_redirect(socket, to: route_with_params(socket.assigns, params: [prefix: ""]))
prefix ->
assign_and_presist_prefix(socket, prefix)
end
end
defp assign_prefix(socket = %{assigns: %{session: session}}, _) do
case session.prefix do
nil ->
assign_and_presist_prefix(socket, nil)
prefix ->
push_patch(socket, to: route_with_params(socket.assigns, params: [prefix: prefix]))
end
end
defp assign_and_presist_prefix(socket, prefix) do
new_session = Map.put(socket.assigns.session, :prefix, prefix)
LiveAdmin.session_store().persist!(new_session)
assign(socket, prefix: prefix, session: new_session)
end
defp get_task_keys(resource) do
:tasks
|> resource.__live_admin_config__()
|> Enum.map(fn
{key, _} -> key
key -> key
end)
end
defp assign_resource_info(socket, uri) do
%URI{host: host, path: path} = URI.parse(uri)
%{resource: {key, mod}} = Phoenix.Router.route_info(socket.router, "GET", path, host)
assign(socket, key: key, resource: mod)
end
defp assign_mod(
socket = %{assigns: %{resource: resource, live_action: action, default_mod: default}}
) do
mod =
:components
|> resource.__live_admin_config__()
|> Keyword.get(action, default)
assign(socket, :mod, mod)
end
defp assign_repo(socket = %{assigns: %{resource: resource, default_repo: default}}) do
repo =
:ecto_repo
|> resource.__live_admin_config__()
|> Kernel.||(default)
|> Kernel.||(raise "no repo configured")
prefix_options =
if function_exported?(repo, :prefixes, 0) do
repo.prefixes()
else
[]
end
assign(socket, repo: repo, prefix_options: prefix_options)
end
end