feat: use layout from memberlist

This commit is contained in:
Moritz 2025-07-22 19:57:18 +02:00 committed by moritz
parent df9966bb12
commit 5959c9f545
3 changed files with 158 additions and 48 deletions

View file

@ -1,54 +1,19 @@
defmodule MvWeb.UserLive.Index do defmodule MvWeb.UserLive.Index do
use MvWeb, :live_view use MvWeb, :live_view
import MvWeb.TableComponents
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash}>
<.header>
{gettext("Listing Users")}
<:actions>
<.button variant="primary" navigate={~p"/users/new"}>
<.icon name="hero-plus" /> {gettext("New User")}
</.button>
</:actions>
</.header>
<.table
id="users"
rows={@streams.users}
row_click={fn {_id, user} -> JS.navigate(~p"/users/#{user}") end}
>
<:col :let={{_id, user}} label={gettext("Email")}>{user.email}</:col>
<:col :let={{_id, user}} label={gettext("OIDC ID")}>{user.oidc_id}</:col>
<:action :let={{_id, user}}>
<div class="sr-only">
<.link navigate={~p"/users/#{user}"}>{gettext("Show")}</.link>
</div>
<.link navigate={~p"/users/#{user}/edit"}>{gettext("Edit")}</.link>
</:action>
<:action :let={{id, user}}>
<.link
phx-click={JS.push("delete", value: %{id: user.id}) |> hide("##{id}")}
data-confirm={gettext("Are you sure?")}
>
{gettext("Delete")}
</.link>
</:action>
</.table>
</Layouts.app>
"""
end
@impl true @impl true
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
users = Ash.read!(Mv.Accounts.User, domain: Mv.Accounts)
sorted = Enum.sort_by(users, & &1.email)
{:ok, {:ok,
socket socket
|> assign(:page_title, gettext("Listing Users")) |> assign(:page_title, gettext("Listing Users"))
|> stream(:users, Ash.read!(Mv.Accounts.User, domain: Mv.Accounts))} |> assign(:sort_field, :email)
|> assign(:sort_order, :asc)
|> assign(:users, sorted)
|> assign(:selected_users, [])}
end end
@impl true @impl true
@ -56,6 +21,66 @@ defmodule MvWeb.UserLive.Index do
user = Ash.get!(Mv.Accounts.User, id, domain: Mv.Accounts) user = Ash.get!(Mv.Accounts.User, id, domain: Mv.Accounts)
Ash.destroy!(user, domain: Mv.Accounts) Ash.destroy!(user, domain: Mv.Accounts)
{:noreply, stream_delete(socket, :users, user)} updated_users = Enum.reject(socket.assigns.users, &(&1.id == id))
{:noreply, assign(socket, :users, updated_users)}
end end
# Selects one user in the list of users
@impl true
def handle_event("select_user", %{"id" => id}, socket) do
selected =
if id in socket.assigns.selected_users do
List.delete(socket.assigns.selected_users, id)
else
[id | socket.assigns.selected_users]
end
{:noreply, assign(socket, :selected_users, selected)}
end
# Sorts the list of users according to a field, when you click on the column header
@impl true
def handle_event("sort", %{"field" => field_str}, socket) do
users = socket.assigns.users
field = String.to_existing_atom(field_str)
new_order =
if socket.assigns.sort_field == field do
toggle_order(socket.assigns.sort_order)
else
:asc
end
sorted_users =
users
|> Enum.sort_by(&Map.get(&1, field), sort_fun(new_order))
{:noreply,
socket
|> assign(:sort_field, field)
|> assign(:sort_order, new_order)
|> assign(:users, sorted_users)}
end
# Selects all users in the list of users
@impl true
def handle_event("select_all", _params, socket) do
users = socket.assigns.users
all_ids = Enum.map(users, & &1.id)
selected =
if Enum.sort(socket.assigns.selected_users) == Enum.sort(all_ids) do
[]
else
all_ids
end
{:noreply, assign(socket, :selected_users, selected)}
end
defp toggle_order(:asc), do: :desc
defp toggle_order(:desc), do: :asc
defp sort_fun(:asc), do: &<=/2
defp sort_fun(:desc), do: &>=/2
end end

View file

@ -0,0 +1,75 @@
<Layouts.app flash={@flash}>
<.header>
{gettext("Listing Users")}
<:actions>
<.button variant="primary" navigate={~p"/users/new"}>
<.icon name="hero-plus" /> {gettext("New User")}
</.button>
</:actions>
</.header>
<.table
id="users"
rows={@users}
row_click={fn user -> JS.navigate(~p"/users/#{user}") end}
>
<:col
:let={user}
label={
~H"""
<.input
type="checkbox"
name="select_all"
phx-click="select_all"
checked={Enum.sort(@selected_users) == Enum.map(@users, & &1.id) |> Enum.sort()}
aria-label={gettext("Select all users")}
role="checkbox"
/>
"""
}
>
<.input
type="checkbox"
name={user.id}
phx-click="select_user"
phx-value-id={user.id}
checked={user.id in @selected_users}
phx-capture-click
phx-stop-propagation
aria-label={gettext("Select user")}
role="checkbox"
/>
</:col>
<:col
:let={user}
label={
sort_button(%{
field: :email,
label: gettext("Email"),
sort_field: @sort_field,
sort_order: @sort_order
})
}
>
{user.email}
</:col>
<:col :let={user} label={gettext("OIDC ID")}>{user.oidc_id}</:col>
<:action :let={user}>
<div class="sr-only">
<.link navigate={~p"/users/#{user}"}>{gettext("Show")}</.link>
</div>
<.link navigate={~p"/users/#{user}/edit"}>{gettext("Edit")}</.link>
</:action>
<:action :let={user}>
<.link
phx-click={JS.push("delete", value: %{id: user.id}) |> hide("#row-#{user.id}")}
data-confirm={gettext("Are you sure?")}
>
{gettext("Delete")}
</.link>
</:action>
</.table>
</Layouts.app>

View file

@ -410,12 +410,12 @@ msgstr ""
#: lib/mv_web/live/member_live/index.html.heex:27 #: lib/mv_web/live/member_live/index.html.heex:27
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Select all members" msgid "Select all members"
msgstr "" msgstr "Alle Mitglieder auswählen"
#: lib/mv_web/live/member_live/index.html.heex:41 #: lib/mv_web/live/member_live/index.html.heex:41
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Select member" msgid "Select member"
msgstr "" msgstr "Mitglied auswählen"
#: lib/mv_web/components/layouts/navbar.ex:72 #: lib/mv_web/components/layouts/navbar.ex:72
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -476,12 +476,12 @@ msgstr ""
#: lib/mv_web/components/table_components.ex:30 #: lib/mv_web/components/table_components.ex:30
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "ascending" msgid "ascending"
msgstr "" msgstr "aufsteigend"
#: lib/mv_web/components/table_components.ex:30 #: lib/mv_web/components/table_components.ex:30
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "descending" msgid "descending"
msgstr "" msgstr "absteigend"
#: lib/mv_web/live/user_live/form.ex:51 #: lib/mv_web/live/user_live/form.ex:51
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -492,3 +492,13 @@ msgstr "Neuer"
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Users created here will need to set their password through the authentication system." msgid "Users created here will need to set their password through the authentication system."
msgstr "Hier erstellte Benutzer müssen ihr Passwort über das Authentifizierungssystem setzen." msgstr "Hier erstellte Benutzer müssen ihr Passwort über das Authentifizierungssystem setzen."
#: lib/mv_web/live/user_live/index.html.heex:15
#, elixir-autogen, elixir-format
msgid "Select all users"
msgstr "Alle Benutzer auswählen"
#: lib/mv_web/live/user_live/index.html.heex:29
#, elixir-autogen, elixir-format
msgid "Select user"
msgstr "Benutzer auswählen"