forked from shibao/cannery
use container table component instead
This commit is contained in:
157
lib/cannery_web/components/container_table_component.ex
Normal file
157
lib/cannery_web/components/container_table_component.ex
Normal file
@ -0,0 +1,157 @@
|
||||
defmodule CanneryWeb.Components.ContainerTableComponent do
|
||||
@moduledoc """
|
||||
A component that displays a list of containers
|
||||
"""
|
||||
use CanneryWeb, :live_component
|
||||
alias Cannery.{Accounts.User, Containers, Containers.Container, Repo}
|
||||
alias CanneryWeb.Components.TagCard
|
||||
alias Ecto.UUID
|
||||
alias Phoenix.LiveView.{Rendered, Socket}
|
||||
|
||||
@impl true
|
||||
@spec update(
|
||||
%{
|
||||
required(:id) => UUID.t(),
|
||||
required(:current_user) => User.t(),
|
||||
optional(:containers) => [Container.t()],
|
||||
optional(:tag_actions) => Rendered.t(),
|
||||
optional(:actions) => Rendered.t(),
|
||||
optional(any()) => any()
|
||||
},
|
||||
Socket.t()
|
||||
) :: {:ok, Socket.t()}
|
||||
def update(%{id: _id, containers: _containers, current_user: _current_user} = assigns, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign_new(:tag_actions, fn -> [] end)
|
||||
|> assign_new(:actions, fn -> [] end)
|
||||
|> display_containers()
|
||||
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
defp display_containers(
|
||||
%{
|
||||
assigns: %{
|
||||
containers: containers,
|
||||
current_user: current_user,
|
||||
tag_actions: tag_actions,
|
||||
actions: actions
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
columns =
|
||||
[
|
||||
%{label: gettext("Name"), key: :name, type: :string},
|
||||
%{label: gettext("Description"), key: :desc, type: :string},
|
||||
%{label: gettext("Location"), key: :location, type: :string},
|
||||
%{label: gettext("Type"), key: :type, type: :string},
|
||||
%{label: gettext("Packs"), key: :packs, type: :integer},
|
||||
%{label: gettext("Rounds"), key: :rounds, type: :string},
|
||||
%{label: gettext("Tags"), key: :tags, type: :tags},
|
||||
%{label: nil, key: :actions, sortable: false, type: :actions}
|
||||
]
|
||||
|> Enum.filter(fn %{key: key, type: type} ->
|
||||
# remove columns if all values match defaults
|
||||
default_value =
|
||||
case type do
|
||||
:boolean -> false
|
||||
_other_type -> nil
|
||||
end
|
||||
|
||||
containers
|
||||
|> Enum.any?(fn container ->
|
||||
type in [:tags, :actions] or not (container |> Map.get(key) == default_value)
|
||||
end)
|
||||
end)
|
||||
|
||||
rows =
|
||||
containers
|
||||
|> Enum.map(fn container ->
|
||||
container
|
||||
|> get_row_data_for_container(columns, %{
|
||||
current_user: current_user,
|
||||
tag_actions: tag_actions,
|
||||
actions: actions
|
||||
})
|
||||
end)
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
columns: columns,
|
||||
rows: rows
|
||||
)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div id={@id} class="w-full">
|
||||
<.live_component
|
||||
module={CanneryWeb.Components.TableComponent}
|
||||
id={"table-#{@id}"}
|
||||
columns={@columns}
|
||||
rows={@rows}
|
||||
/>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@spec get_row_data_for_container(Container.t(), columns :: [map()], extra_data :: map) :: map()
|
||||
defp get_row_data_for_container(container, columns, extra_data) do
|
||||
container = container |> Repo.preload([:ammo_groups, :tags])
|
||||
|
||||
columns
|
||||
|> Map.new(fn %{key: key} -> {key, get_value_for_key(key, container, extra_data)} end)
|
||||
end
|
||||
|
||||
@spec get_value_for_key(atom(), Container.t(), extra_data :: map) :: any()
|
||||
defp get_value_for_key(:name, %{id: id, name: container_name}, _extra_data) do
|
||||
assigns = %{id: id, container_name: container_name}
|
||||
|
||||
{container_name,
|
||||
~H"""
|
||||
<div class="flex flex-wrap justify-center items-center">
|
||||
<.link navigate={Routes.container_show_path(Endpoint, :show, @id)} class="link">
|
||||
<%= @container_name %>
|
||||
</.link>
|
||||
</div>
|
||||
"""}
|
||||
end
|
||||
|
||||
defp get_value_for_key(:packs, container, _extra_data) do
|
||||
container |> Containers.get_container_ammo_group_count!()
|
||||
end
|
||||
|
||||
defp get_value_for_key(:rounds, container, _extra_data) do
|
||||
container |> Containers.get_container_rounds!()
|
||||
end
|
||||
|
||||
defp get_value_for_key(:tags, container, %{tag_actions: tag_actions}) do
|
||||
assigns = %{tag_actions: tag_actions, container: container}
|
||||
|
||||
{container.tags |> Enum.map(fn %{name: name} -> name end),
|
||||
~H"""
|
||||
<div class="flex flex-wrap justify-center items-center">
|
||||
<%= unless @container.tags |> Enum.empty?() do %>
|
||||
<%= for tag <- @container.tags do %>
|
||||
<TagCard.simple_tag_card tag={tag} />
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= render_slot(@tag_actions, @container) %>
|
||||
</div>
|
||||
"""}
|
||||
end
|
||||
|
||||
defp get_value_for_key(:actions, container, %{actions: actions}) do
|
||||
assigns = %{actions: actions, container: container}
|
||||
|
||||
~H"""
|
||||
<%= render_slot(@actions, @container) %>
|
||||
"""
|
||||
end
|
||||
|
||||
defp get_value_for_key(key, container, _extra_data), do: container |> Map.get(key)
|
||||
end
|
@ -6,7 +6,6 @@ defmodule CanneryWeb.ContainerLive.Index do
|
||||
use CanneryWeb, :live_view
|
||||
import CanneryWeb.Components.ContainerCard
|
||||
alias Cannery.{Containers, Containers.Container, Repo}
|
||||
alias CanneryWeb.{Components.TagCard, Endpoint}
|
||||
alias Ecto.Changeset
|
||||
|
||||
@impl true
|
||||
@ -124,133 +123,9 @@ defmodule CanneryWeb.ContainerLive.Index do
|
||||
|
||||
defp display_containers(%{assigns: %{search: search, current_user: current_user}} = socket) do
|
||||
containers =
|
||||
Containers.list_containers(search, current_user) |> Repo.preload([:tags, :ammo_groups])
|
||||
Containers.list_containers(search, current_user)
|
||||
|> Repo.preload([:tags, :ammo_groups])
|
||||
|
||||
columns =
|
||||
[
|
||||
%{label: gettext("Name"), key: :name, type: :string},
|
||||
%{label: gettext("Description"), key: :desc, type: :string},
|
||||
%{label: gettext("Location"), key: :location, type: :string},
|
||||
%{label: gettext("Type"), key: :type, type: :string},
|
||||
%{label: gettext("Packs"), key: :packs, type: :integer},
|
||||
%{label: gettext("Rounds"), key: :rounds, type: :string},
|
||||
%{label: gettext("Tags"), key: :tags, type: :tags},
|
||||
%{label: nil, key: :actions, sortable: false, type: :actions}
|
||||
]
|
||||
|> Enum.filter(fn %{key: key, type: type} ->
|
||||
# remove columns if all values match defaults
|
||||
default_value =
|
||||
case type do
|
||||
:boolean -> false
|
||||
_other_type -> nil
|
||||
end
|
||||
|
||||
containers
|
||||
|> Enum.any?(fn container ->
|
||||
type in [:tags, :actions] or not (container |> Map.get(key) == default_value)
|
||||
end)
|
||||
end)
|
||||
|
||||
rows =
|
||||
containers
|
||||
|> Enum.map(fn container -> container |> get_row_data_for_container(columns) end)
|
||||
|
||||
socket
|
||||
|> assign(
|
||||
containers: containers,
|
||||
columns: columns,
|
||||
rows: rows
|
||||
)
|
||||
socket |> assign(:containers, containers)
|
||||
end
|
||||
|
||||
@spec get_row_data_for_container(Container.t(), [map()]) :: map()
|
||||
defp get_row_data_for_container(container, columns) do
|
||||
container = container |> Repo.preload([:ammo_groups, :tags])
|
||||
|
||||
columns
|
||||
|> Map.new(fn %{key: key} -> {key, get_value_for_key(key, container)} end)
|
||||
end
|
||||
|
||||
@spec get_value_for_key(atom(), Container.t()) :: any()
|
||||
defp get_value_for_key(:name, %{id: id, name: container_name}) do
|
||||
assigns = %{id: id, container_name: container_name}
|
||||
|
||||
{container_name,
|
||||
~H"""
|
||||
<div class="flex flex-wrap justify-center items-center">
|
||||
<.link navigate={Routes.container_show_path(Endpoint, :show, @id)} class="link">
|
||||
<%= @container_name %>
|
||||
</.link>
|
||||
</div>
|
||||
"""}
|
||||
end
|
||||
|
||||
defp get_value_for_key(:packs, container) do
|
||||
container |> Containers.get_container_ammo_group_count!()
|
||||
end
|
||||
|
||||
defp get_value_for_key(:rounds, container) do
|
||||
container |> Containers.get_container_rounds!()
|
||||
end
|
||||
|
||||
defp get_value_for_key(:tags, container) do
|
||||
assigns = %{container: container}
|
||||
|
||||
{container.tags |> Enum.map(fn %{name: name} -> name end),
|
||||
~H"""
|
||||
<div class="flex flex-wrap justify-center items-center">
|
||||
<%= unless @container.tags |> Enum.empty?() do %>
|
||||
<%= for tag <- @container.tags do %>
|
||||
<TagCard.simple_tag_card tag={tag} />
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<div class="mx-4 my-2">
|
||||
<.link
|
||||
patch={Routes.container_index_path(Endpoint, :edit_tags, @container)}
|
||||
class="text-primary-600 link"
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-tags"></i>
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
"""}
|
||||
end
|
||||
|
||||
defp get_value_for_key(:actions, container) do
|
||||
assigns = %{container: container}
|
||||
|
||||
~H"""
|
||||
<.link
|
||||
patch={Routes.container_index_path(Endpoint, :edit, @container)}
|
||||
class="text-primary-600 link"
|
||||
data-qa={"edit-#{@container.id}"}
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-edit"></i>
|
||||
</.link>
|
||||
|
||||
<.link
|
||||
patch={Routes.container_index_path(Endpoint, :clone, @container)}
|
||||
class="text-primary-600 link"
|
||||
data-qa={"clone-#{@container.id}"}
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-copy"></i>
|
||||
</.link>
|
||||
|
||||
<.link
|
||||
href="#"
|
||||
class="text-primary-600 link"
|
||||
phx-click="delete"
|
||||
phx-value-id={@container.id}
|
||||
data-confirm={
|
||||
dgettext("prompts", "Are you sure you want to delete %{name}?", name: @container.name)
|
||||
}
|
||||
data-qa={"delete-#{@container.id}"}
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-trash"></i>
|
||||
</.link>
|
||||
"""
|
||||
end
|
||||
|
||||
defp get_value_for_key(key, container), do: container |> Map.get(key)
|
||||
end
|
||||
|
@ -51,12 +51,55 @@
|
||||
<% else %>
|
||||
<%= if @view_table do %>
|
||||
<.live_component
|
||||
module={CanneryWeb.Components.TableComponent}
|
||||
module={CanneryWeb.Components.ContainerTableComponent}
|
||||
id="containers_index_table"
|
||||
action={@live_action}
|
||||
columns={@columns}
|
||||
rows={@rows}
|
||||
/>
|
||||
containers={@containers}
|
||||
current_user={@current_user}
|
||||
>
|
||||
<:tag_actions :let={container}>
|
||||
<div class="mx-4 my-2">
|
||||
<.link
|
||||
patch={Routes.container_index_path(Endpoint, :edit_tags, container)}
|
||||
class="text-primary-600 link"
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-tags"></i>
|
||||
</.link>
|
||||
</div>
|
||||
</:tag_actions>
|
||||
<:actions :let={container}>
|
||||
<.link
|
||||
patch={Routes.container_index_path(Endpoint, :edit, container)}
|
||||
class="text-primary-600 link"
|
||||
data-qa={"edit-#{container.id}"}
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-edit"></i>
|
||||
</.link>
|
||||
|
||||
<.link
|
||||
patch={Routes.container_index_path(Endpoint, :clone, container)}
|
||||
class="text-primary-600 link"
|
||||
data-qa={"clone-#{container.id}"}
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-copy"></i>
|
||||
</.link>
|
||||
|
||||
<.link
|
||||
href="#"
|
||||
class="text-primary-600 link"
|
||||
phx-click="delete"
|
||||
phx-value-id={container.id}
|
||||
data-confirm={
|
||||
dgettext("prompts", "Are you sure you want to delete %{name}?",
|
||||
name: container.name
|
||||
)
|
||||
}
|
||||
data-qa={"delete-#{container.id}"}
|
||||
>
|
||||
<i class="fa-fw fa-lg fas fa-trash"></i>
|
||||
</.link>
|
||||
</:actions>
|
||||
</.live_component>
|
||||
<% else %>
|
||||
<%= for container <- @containers do %>
|
||||
<.container_card container={container}>
|
||||
|
Reference in New Issue
Block a user