Adds more consistency in various UX topics closes #447 #448

Merged
carla merged 9 commits from feat/447_concistency into main 2026-02-25 17:34:12 +01:00
26 changed files with 747 additions and 710 deletions
Showing only changes of commit 0f12befd11 - Show all commits

View file

@ -61,7 +61,7 @@ We are building a membership management system (Mila) using the following techno
8. [Accessibility Guidelines](#8-accessibility-guidelines) 8. [Accessibility Guidelines](#8-accessibility-guidelines)
**Related documents:** **Related documents:**
- **UI / UX:** [`DESIGN_DUIDELINES.md`](../DESIGN_DUIDELINES.md) defines visual and interaction consistency: use of CoreComponents (no raw DaisyUI in views), page skeleton (`<.header>`, `mt-6 space-y-6`), typography, buttons, forms, tables, flash/toast, and microcopy (e.g. German "du" and glossary). Follow "components first" and semantic variants instead of hard-coded colors. - **UI / UX:** [`DESIGN_DUIDELINES.md`](../DESIGN_DUIDELINES.md) defines visual and interaction consistency: use of CoreComponents (no raw DaisyUI in views), page skeleton (`<.header>`, `mt-6 space-y-6`), **Back button left in header for edit/new forms** (§2.2), typography, buttons, forms, tables, flash/toast, and microcopy (e.g. German "du" and glossary). Follow "components first" and semantic variants instead of hard-coded colors.
--- ---

View file

@ -46,19 +46,35 @@ Every authenticated page should follow the same structure:
**MUST:** Use `<.header>` on every page (except login/public pages). **MUST:** Use `<.header>` on every page (except login/public pages).
**SHOULD:** Put short explanations into `<:subtitle>` rather than sprinkling random text blocks. **SHOULD:** Put short explanations into `<:subtitle>` rather than sprinkling random text blocks.
**Template:** ### 2.2 Edit/New form header: Back button left (mandatory)
For LiveViews that render an edit or new form (e.g. member, group, role, user, custom field, membership fee type):
- **MUST:** Provide a **Back** button on the **left** side of the header using the `<:leading>` slot (same as data fields: Back left, title next, primary action on the right).
- **MUST:** Use the same pattern everywhere: Back button with `variant="neutral"`, arrow-left icon, and label “Back”. It navigates to the previous context (e.g. detail page or index) via a `return_path`-style helper.
- **SHOULD:** Place the primary action (e.g. “Save”) in `<:actions>` on the right.
- **Rationale:** Users expect a consistent way to leave the form without submitting; Back left matches the data fields edit view and keeps primary actions on the right.
**Template for form pages:**
```heex ```heex
<.header> <.header>
Title <:leading>
<:subtitle>Short explanation of what the page is for.</:subtitle> <.button navigate={return_path(@return_to, @resource)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")}
</.button>
</:leading>
Page title (e.g. “Edit Member” or “New User”)
<:subtitle>Short explanation.</:subtitle>
<:actions> <:actions>
<.button variant="primary" navigate={...}>Primary action</.button> <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
{gettext("Save")}
</.button>
</:actions> </:actions>
</.header> </.header>
```
<div class="mt-6 space-y-6"> If the `<.header>` is outside the `<.form>`, the submit button must reference the form via the `form` attribute (e.g. `form="user-form"`).
<!-- Sections / Cards / Tables -->
</div>
## 3) Typography (system) ## 3) Typography (system)

View file

@ -111,7 +111,7 @@ defmodule MvWeb.CoreComponents do
<.button variant="ghost" size="sm">Edit</.button> <.button variant="ghost" size="sm">Edit</.button>
<.button disabled={true}>Disabled</.button> <.button disabled={true}>Disabled</.button>
""" """
attr :rest, :global, include: ~w(href navigate patch method data-testid) attr :rest, :global, include: ~w(href navigate patch method data-testid form)
attr :variant, :string, attr :variant, :string,
values: ~w(primary secondary neutral ghost outline danger link icon), values: ~w(primary secondary neutral ghost outline danger link icon),
@ -633,17 +633,24 @@ defmodule MvWeb.CoreComponents do
@doc """ @doc """
Renders a header with title. Renders a header with title.
Use the `:leading` slot for the Back button (left side, consistent with data fields).
Use the `:actions` slot for primary actions (e.g. Save) on the right.
""" """
attr :class, :string, default: nil attr :class, :string, default: nil
slot :leading, doc: "Content on the left (e.g. Back button)"
slot :inner_block, required: true slot :inner_block, required: true
slot :subtitle slot :subtitle
slot :actions slot :actions
def header(assigns) do def header(assigns) do
~H""" ~H"""
<header class={[@actions != [] && "flex items-center justify-between gap-6", "pb-4", @class]}> <header class={["flex items-center gap-6 pb-4", @class]}>
<div> <div :if={@leading != []} class="shrink-0">
{render_slot(@leading)}
</div>
<div class="min-w-0 flex-1">
<h1 class="text-xl font-semibold leading-8"> <h1 class="text-xl font-semibold leading-8">
{render_slot(@inner_block)} {render_slot(@inner_block)}
</h1> </h1>
@ -651,7 +658,9 @@ defmodule MvWeb.CoreComponents do
{render_slot(@subtitle)} {render_slot(@subtitle)}
</p> </p>
</div> </div>
<div class="flex gap-4 justify-end">{render_slot(@actions)}</div> <div :if={@actions != []} class="shrink-0 flex gap-4 justify-end">
{render_slot(@actions)}
</div>
</header> </header>
""" """
end end

View file

@ -188,7 +188,7 @@ defmodule MvWeb.Components.FieldVisibilityDropdownComponent do
defp find_custom_field_name(id, _field_string, custom_fields) do defp find_custom_field_name(id, _field_string, custom_fields) do
case Enum.find(custom_fields, fn cf -> to_string(cf.id) == id end) do case Enum.find(custom_fields, fn cf -> to_string(cf.id) == id end) do
nil -> gettext("Custom Field %{id}", id: id) nil -> gettext("Datafield %{id}", id: id)
custom_field -> custom_field.name custom_field -> custom_field.name
end end
end end

View file

@ -252,7 +252,7 @@ defmodule MvWeb.Components.MemberFilterComponent do
<!-- Custom Fields Group --> <!-- Custom Fields Group -->
<div :if={length(@boolean_custom_fields) > 0} class="mb-2"> <div :if={length(@boolean_custom_fields) > 0} class="mb-2">
<div class="text-xs font-semibold opacity-70 mb-2 uppercase tracking-wider"> <div class="text-xs font-semibold opacity-70 mb-2 uppercase tracking-wider">
{gettext("Custom Fields")} {gettext("Individual datafields")}
</div> </div>
<div class="max-h-60 overflow-y-auto pr-2"> <div class="max-h-60 overflow-y-auto pr-2">
<fieldset <fieldset

View file

@ -107,7 +107,7 @@ defmodule MvWeb.CustomFieldLive.FormComponent do
<div class="border border-base-300 rounded-lg p-4 bg-base-100"> <div class="border border-base-300 rounded-lg p-4 bg-base-100">
<p class="text-base-content/70 mb-4"> <p class="text-base-content/70 mb-4">
{gettext( {gettext(
"Deleting this data field cannot be undone. All custom field values for this field will be permanently removed." "Deleting this data field cannot be undone. All datafield values for this field will be permanently removed."
)} )}
</p> </p>
<.button <.button

View file

@ -158,7 +158,7 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do
phx-target={@myself} phx-target={@myself}
disabled={@slug_confirmation != @custom_field_to_delete.slug} disabled={@slug_confirmation != @custom_field_to_delete.slug}
> >
{gettext("Delete Custom Field and All Values")} {gettext("Delete Datafields and All Values")}
</.button> </.button>
</div> </div>
</div> </div>

View file

@ -95,7 +95,7 @@ defmodule MvWeb.GlobalSettingsLive do
</div> </div>
<.button phx-disable-with={gettext("Saving...")} variant="primary"> <.button phx-disable-with={gettext("Saving...")} variant="primary">
{gettext("Save Settings")} {gettext("Save Name")}
</.button> </.button>
</.form> </.form>
</.form_section> </.form_section>

View file

@ -79,12 +79,14 @@ defmodule MvWeb.GroupLive.Form do
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.form for={@form} id="group-form" phx-change="validate" phx-submit="save"> <.form for={@form} id="group-form" phx-change="validate" phx-submit="save">
<.header> <.header>
{@page_title} <:leading>
<:actions>
<.button navigate={return_path(@return_to, @group)} variant="neutral"> <.button navigate={return_path(@return_to, @group)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" /> <.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading>
{@page_title}
<:actions>
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit"> <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
{gettext("Save")} {gettext("Save")}
</.button> </.button>

View file

@ -50,7 +50,7 @@ defmodule MvWeb.GroupLive.Show do
end end
end end
defp load_group_by_slug(socket, slug, actor, params \\ %{}) do defp load_group_by_slug(socket, slug, actor, params) do
# Load group with members and member_count # Load group with members and member_count
# Using explicit load ensures efficient preloading of members relationship # Using explicit load ensures efficient preloading of members relationship
require Ash.Query require Ash.Query
@ -92,8 +92,7 @@ defmodule MvWeb.GroupLive.Show do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{@group.name} <:leading>
<:actions>
<.button <.button
navigate={~p"/groups"} navigate={~p"/groups"}
variant="neutral" variant="neutral"
@ -102,13 +101,16 @@ defmodule MvWeb.GroupLive.Show do
<.icon name="hero-arrow-left" class="size-4" /> <.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading>
{@group.name}
<:actions>
<%= if can?(@current_user, :update, @group) do %> <%= if can?(@current_user, :update, @group) do %>
<.button <.button
variant="primary" variant="primary"
navigate={~p"/groups/#{@group.slug}/edit"} navigate={~p"/groups/#{@group.slug}/edit"}
data-testid="group-show-edit-btn" data-testid="group-show-edit-btn"
> >
{gettext("Edit group")} <.icon name="hero-pencil-square" /> {gettext("Edit group")}
</.button> </.button>
<% end %> <% end %>
</:actions> </:actions>

View file

@ -39,16 +39,18 @@ defmodule MvWeb.MemberLive.Form do
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.form for={@form} id="member-form" phx-change="validate" phx-submit="save"> <.form for={@form} id="member-form" phx-change="validate" phx-submit="save">
<.header> <.header>
<:leading>
<.button navigate={return_path(@return_to, @member)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")}
</.button>
</:leading>
<%= if @member do %> <%= if @member do %>
{MvWeb.Helpers.MemberHelpers.display_name(@member)} {MvWeb.Helpers.MemberHelpers.display_name(@member)}
<% else %> <% else %>
{gettext("New Member")} {gettext("New Member")}
<% end %> <% end %>
<:actions> <:actions>
<.button navigate={return_path(@return_to, @member)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")}
</.button>
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit"> <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
{gettext("Save")} {gettext("Save")}
</.button> </.button>
@ -408,32 +410,33 @@ defmodule MvWeb.MemberLive.Form do
member = socket.assigns.member member = socket.assigns.member
actor = current_actor(socket) actor = current_actor(socket)
if is_nil(member) do cond do
{:noreply, put_flash(socket, :error, gettext("Member not found"))} is_nil(member) ->
else
if to_string(id) != to_string(member.id) do
{:noreply, put_flash(socket, :error, gettext("Member not found"))} {:noreply, put_flash(socket, :error, gettext("Member not found"))}
else
case Ash.destroy(member, actor: actor) do
:ok ->
{:noreply,
socket
|> put_flash(:success, gettext("Member deleted successfully"))
|> push_navigate(to: ~p"/members")}
{:error, %Ash.Error.Forbidden{}} -> to_string(id) != to_string(member.id) ->
{:noreply, {:noreply, put_flash(socket, :error, gettext("Member not found"))}
put_flash(
socket,
:error,
gettext("You do not have permission to delete this member")
)}
{:error, error} -> true ->
Logger.warning("Member delete failed: member_id=#{member.id} error=#{inspect(error)}") handle_member_delete_destroy(socket, member, actor)
{:noreply, put_flash(socket, :error, format_destroy_error(error))} end
end end
end
defp handle_member_delete_destroy(socket, member, actor) do
case Ash.destroy(member, actor: actor) do
:ok ->
{:noreply,
socket
|> put_flash(:success, gettext("Member deleted successfully"))
|> push_navigate(to: ~p"/members")}
{:error, %Ash.Error.Forbidden{}} ->
{:noreply,
put_flash(socket, :error, gettext("You do not have permission to delete this member"))}
{:error, error} ->
Logger.warning("Member delete failed: member_id=#{member.id} error=#{inspect(error)}")
{:noreply, put_flash(socket, :error, format_destroy_error(error))}
end end
end end

View file

@ -31,8 +31,7 @@ defmodule MvWeb.MemberLive.Show do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{MvWeb.Helpers.MemberHelpers.display_name(@member)} <:leading>
<:actions>
<.button <.button
navigate={~p"/members?highlight=#{@member.id}"} navigate={~p"/members?highlight=#{@member.id}"}
variant="neutral" variant="neutral"
@ -41,13 +40,16 @@ defmodule MvWeb.MemberLive.Show do
<.icon name="hero-arrow-left" class="size-4" /> <.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading>
{MvWeb.Helpers.MemberHelpers.display_name(@member)}
<:actions>
<%= if can?(@current_user, :update, @member) do %> <%= if can?(@current_user, :update, @member) do %>
<.button <.button
variant="primary" variant="primary"
navigate={~p"/members/#{@member}/edit?return_to=show"} navigate={~p"/members/#{@member}/edit?return_to=show"}
data-testid="member-edit" data-testid="member-edit"
> >
{gettext("Edit member")} <.icon name="hero-pencil-square" /> {gettext("Edit member")}
</.button> </.button>
<% end %> <% end %>
</:actions> </:actions>

View file

@ -27,10 +27,26 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
<:leading>
<.button navigate={return_path(@return_to, @membership_fee_type)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")}
</.button>
</:leading>
{@page_title} {@page_title}
<:subtitle> <:subtitle>
{gettext("Use this form to manage membership fee types in your database.")} {gettext("Use this form to manage membership fee types in your database.")}
</:subtitle> </:subtitle>
<:actions>
<.button
form="membership-fee-type-form"
phx-disable-with={gettext("Saving...")}
variant="primary"
type="submit"
>
{gettext("Save")}
</.button>
</:actions>
</.header> </.header>
<.form <.form

View file

@ -23,13 +23,15 @@ defmodule MvWeb.RoleLive.Form do
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.form class="max-w-xl" for={@form} id="role-form" phx-change="validate" phx-submit="save"> <.form class="max-w-xl" for={@form} id="role-form" phx-change="validate" phx-submit="save">
<.header> <.header>
{@page_title} <:leading>
<:subtitle>{gettext("Use this form to manage roles in your database.")}</:subtitle>
<:actions>
<.button navigate={return_path(@return_to, @role)} variant="neutral"> <.button navigate={return_path(@return_to, @role)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" /> <.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading>
{@page_title}
<:subtitle>{gettext("Use this form to manage roles in your database.")}</:subtitle>
<:actions>
<.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit"> <.button phx-disable-with={gettext("Saving...")} variant="primary" type="submit">
{gettext("Save")} {gettext("Save")}
</.button> </.button>

View file

@ -161,10 +161,7 @@ defmodule MvWeb.RoleLive.Show do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
{gettext("Role")} {@role.name} <:leading>
<:subtitle>{gettext("Role details and permissions.")}</:subtitle>
<:actions>
<.button <.button
navigate={~p"/admin/roles"} navigate={~p"/admin/roles"}
variant="neutral" variant="neutral"
@ -173,13 +170,18 @@ defmodule MvWeb.RoleLive.Show do
<.icon name="hero-arrow-left" class="size-4" /> <.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")} {gettext("Back")}
</.button> </.button>
</:leading>
{gettext("Role")} {@role.name}
<:subtitle>{gettext("Role details and permissions.")}</:subtitle>
<:actions>
<%= if can?(@current_user, :update, Mv.Authorization.Role) do %> <%= if can?(@current_user, :update, Mv.Authorization.Role) do %>
<.button <.button
variant="primary" variant="primary"
navigate={~p"/admin/roles/#{@role}/edit"} navigate={~p"/admin/roles/#{@role}/edit"}
data-testid="role-show-edit-btn" data-testid="role-show-edit-btn"
> >
{gettext("Edit role")} <.icon name="hero-pencil-square" /> {gettext("Edit role")}
</.button> </.button>
<% end %> <% end %>
</:actions> </:actions>

View file

@ -46,8 +46,24 @@ defmodule MvWeb.UserLive.Form do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
<:leading>
<.button navigate={return_path(@return_to, @user)} variant="neutral">
<.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")}
</.button>
</:leading>
{@page_title} {@page_title}
<:subtitle>{gettext("Use this form to manage user records in your database.")}</:subtitle> <:subtitle>{gettext("Use this form to manage user records in your database.")}</:subtitle>
<:actions>
<.button
form="user-form"
phx-disable-with={gettext("Saving...")}
variant="primary"
type="submit"
>
{gettext("Save User")}
</.button>
</:actions>
</.header> </.header>
<.form class="max-w-xl" for={@form} id="user-form" phx-change="validate" phx-submit="save"> <.form class="max-w-xl" for={@form} id="user-form" phx-change="validate" phx-submit="save">
@ -300,7 +316,8 @@ defmodule MvWeb.UserLive.Form do
phx-click="delete" phx-click="delete"
phx-value-id={@user.id} phx-value-id={@user.id}
data-confirm={ data-confirm={
gettext("Are you sure you want to delete the user %{email}? This action cannot be undone.", gettext(
"Are you sure you want to delete the user %{email}? This action cannot be undone.",
email: @user.email email: @user.email
) )
} }
@ -442,36 +459,18 @@ defmodule MvWeb.UserLive.Form do
user = socket.assigns.user user = socket.assigns.user
actor = current_actor(socket) actor = current_actor(socket)
if is_nil(user) do cond do
{:noreply, put_flash(socket, :error, gettext("User not found"))} is_nil(user) ->
else
if to_string(id) != to_string(user.id) do
{:noreply, put_flash(socket, :error, gettext("User not found"))} {:noreply, put_flash(socket, :error, gettext("User not found"))}
else
if Mv.Helpers.SystemActor.system_user?(user) do
{:noreply,
put_flash(socket, :error, gettext("System user cannot be deleted."))}
else
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
:ok ->
{:noreply,
socket
|> put_flash(:success, gettext("User deleted successfully"))
|> push_navigate(to: ~p"/users")}
{:error, %Ash.Error.Forbidden{}} -> to_string(id) != to_string(user.id) ->
{:noreply, {:noreply, put_flash(socket, :error, gettext("User not found"))}
put_flash(
socket,
:error,
gettext("You do not have permission to delete this user")
)}
{:error, error} -> Mv.Helpers.SystemActor.system_user?(user) ->
{:noreply, put_flash(socket, :error, format_ash_error(error))} {:noreply, put_flash(socket, :error, gettext("System user cannot be deleted."))}
end
end true ->
end handle_user_delete_destroy(socket, user, actor)
end end
end end
@ -585,6 +584,23 @@ defmodule MvWeb.UserLive.Form do
{:noreply, socket} {:noreply, socket}
end end
defp handle_user_delete_destroy(socket, user, actor) do
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
:ok ->
{:noreply,
socket
|> put_flash(:success, gettext("User deleted successfully"))
|> push_navigate(to: ~p"/users")}
{:error, %Ash.Error.Forbidden{}} ->
{:noreply,
put_flash(socket, :error, gettext("You do not have permission to delete this user"))}
{:error, error} ->
{:noreply, put_flash(socket, :error, format_ash_error(error))}
end
end
defp handle_member_linking(socket, user, actor) do defp handle_member_linking(socket, user, actor) do
result = perform_member_link_action(socket, user, actor) result = perform_member_link_action(socket, user, actor)

View file

@ -7,15 +7,10 @@ defmodule MvWeb.UserLive.Index do
- Sort users by email (default) - Sort users by email (default)
- Navigate to user details (row click) and edit from details header - Navigate to user details (row click) and edit from details header
- Delete only via Danger zone on user show/edit - Delete only via Danger zone on user show/edit
- Bulk selection for future batch operations
## Relationships ## Relationships
Displays linked member information when a user is connected to a member account. Displays linked member information when a user is connected to a member account.
## Events
- `select_user` - Toggle individual user selection
- `select_all` - Toggle selection of all visible users
## Security ## Security
User deletion requires admin permissions (enforced by Ash policies). User deletion requires admin permissions (enforced by Ash policies).
""" """
@ -42,24 +37,7 @@ defmodule MvWeb.UserLive.Index do
|> assign(:page_title, gettext("Listing Users")) |> assign(:page_title, gettext("Listing Users"))
|> assign(:sort_field, :email) |> assign(:sort_field, :email)
|> assign(:sort_order, :asc) |> assign(:sort_order, :asc)
|> assign(:users, sorted) |> assign(:users, sorted)}
|> assign(:selected_users, [])}
end
# Selects one user in the list of users
@impl true
def handle_event("select_user", %{"id" => id}, socket) do
# Normalize ID to string for consistent comparison
id_str = to_string(id)
selected =
if id_str in socket.assigns.selected_users do
List.delete(socket.assigns.selected_users, id_str)
else
[id_str | socket.assigns.selected_users]
end
{:noreply, assign(socket, :selected_users, selected)}
end end
# Sorts the list of users according to a field, when you click on the column header # Sorts the list of users according to a field, when you click on the column header
@ -86,24 +64,6 @@ defmodule MvWeb.UserLive.Index do
|> assign(:users, sorted_users)} |> assign(:users, sorted_users)}
end end
# Selects all users in the list of users
@impl true
def handle_event("select_all", _params, socket) do
users = socket.assigns.users
# Normalize IDs to strings for consistent comparison
all_ids = Enum.map(users, &to_string(&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(:asc), do: :desc
defp toggle_order(:desc), do: :asc defp toggle_order(:desc), do: :asc
defp sort_fun(:asc), do: &<=/2 defp sort_fun(:asc), do: &<=/2

View file

@ -19,33 +19,6 @@
sort_field={@sort_field} sort_field={@sort_field}
sort_order={@sort_order} sort_order={@sort_order}
> >
<:col
:let={user}
label={
~H"""
<.input
type="checkbox"
name="select_all"
phx-click="select_all"
checked={Enum.sort(@selected_users) == Enum.map(@users, &to_string(&1.id)) |> Enum.sort()}
aria-label={gettext("Select all users")}
role="checkbox"
/>
"""
}
>
<.input
type="checkbox"
name={to_string(user.id)}
phx-click="select_user"
phx-value-id={to_string(user.id)}
checked={to_string(user.id) in @selected_users}
phx-capture-click
phx-stop-propagation
aria-label={gettext("Select user")}
role="checkbox"
/>
</:col>
<:col <:col
:let={user} :let={user}
sort_field={:email} sort_field={:email}

View file

@ -34,14 +34,20 @@ defmodule MvWeb.UserLive.Show do
~H""" ~H"""
<Layouts.app flash={@flash} current_user={@current_user}> <Layouts.app flash={@flash} current_user={@current_user}>
<.header> <.header>
<:leading>
<.button
navigate={~p"/users"}
variant="neutral"
aria-label={gettext("Back to users list")}
>
<.icon name="hero-arrow-left" class="size-4" />
{gettext("Back")}
</.button>
</:leading>
{gettext("User")} {@user.email} {gettext("User")} {@user.email}
<:subtitle>{gettext("This is a user record from your database.")}</:subtitle> <:subtitle>{gettext("This is a user record from your database.")}</:subtitle>
<:actions> <:actions>
<.button navigate={~p"/users"} variant="neutral" aria-label={gettext("Back to users list")}>
<.icon name="hero-arrow-left" />
<span class="sr-only">{gettext("Back to users list")}</span>
</.button>
<%= if can?(@current_user, :update, @user) do %> <%= if can?(@current_user, :update, @user) do %>
<.button <.button
variant="primary" variant="primary"
@ -99,7 +105,8 @@ defmodule MvWeb.UserLive.Show do
phx-click="delete" phx-click="delete"
phx-value-id={@user.id} phx-value-id={@user.id}
data-confirm={ data-confirm={
gettext("Are you sure you want to delete the user %{email}? This action cannot be undone.", gettext(
"Are you sure you want to delete the user %{email}? This action cannot be undone.",
email: @user.email email: @user.email
) )
} }
@ -141,33 +148,32 @@ defmodule MvWeb.UserLive.Show do
user = socket.assigns.user user = socket.assigns.user
actor = current_actor(socket) actor = current_actor(socket)
if to_string(id) != to_string(user.id) do cond do
{:noreply, put_flash(socket, :error, gettext("User not found"))} to_string(id) != to_string(user.id) ->
else {:noreply, put_flash(socket, :error, gettext("User not found"))}
if Mv.Helpers.SystemActor.system_user?(user) do
Mv.Helpers.SystemActor.system_user?(user) ->
{:noreply, put_flash(socket, :error, gettext("System user cannot be deleted."))}
true ->
handle_user_delete_destroy(socket, user, actor)
end
end
defp handle_user_delete_destroy(socket, user, actor) do
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do
:ok ->
{:noreply, {:noreply,
put_flash(socket, :error, gettext("System user cannot be deleted."))} socket
else |> put_flash(:success, gettext("User deleted successfully"))
case Ash.destroy(user, domain: Mv.Accounts, actor: actor) do |> push_navigate(to: ~p"/users")}
:ok ->
{:noreply,
socket
|> put_flash(:success, gettext("User deleted successfully"))
|> push_navigate(to: ~p"/users")}
{:error, %Ash.Error.Forbidden{}} -> {:error, %Ash.Error.Forbidden{}} ->
{:noreply, {:noreply,
put_flash( put_flash(socket, :error, gettext("You do not have permission to delete this user"))}
socket,
:error,
gettext("You do not have permission to delete this user")
)}
{:error, error} -> {:error, error} ->
{:noreply, {:noreply, put_flash(socket, :error, format_ash_error(error))}
put_flash(socket, :error, format_ash_error(error))}
end
end
end end
end end
end end

View file

@ -18,9 +18,6 @@ msgstr "Aktionen"
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Bist du sicher?" msgstr "Bist du sicher?"
@ -38,11 +35,8 @@ msgstr "Verbindung wird wiederhergestellt"
msgid "City" msgid "City"
msgstr "Stadt" msgstr "Stadt"
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete" msgid "Delete"
msgstr "Löschen" msgstr "Löschen"
@ -100,8 +94,6 @@ msgid "New Member"
msgstr "Neues Mitglied" msgstr "Neues Mitglied"
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Show" msgid "Show"
msgstr "Anzeigen" msgstr "Anzeigen"
@ -480,16 +472,6 @@ msgstr "Passwort"
msgid "Password requirements" msgid "Password requirements"
msgstr "Passwort-Anforderungen" msgstr "Passwort-Anforderungen"
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Select all users"
msgstr "Alle Benutzer*innen auswählen"
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Select user"
msgstr "Benutzer*in auswählen"
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Set Password" msgid "Set Password"
@ -605,7 +587,6 @@ msgstr "E-Mail kann nicht aktualisiert werden: Diese E-Mail-Adresse ist bereits
msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account." msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account."
msgstr "Diese E-Mail-Adresse ist bereits mit einem anderen OIDC-Konto verknüpft. Es können nicht mehrere OIDC-Provider mit demselben Konto verknüpft werden." msgstr "Diese E-Mail-Adresse ist bereits mit einem anderen OIDC-Konto verknüpft. Es können nicht mehrere OIDC-Provider mit demselben Konto verknüpft werden."
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -624,11 +605,6 @@ msgstr[1] "%{count} Mitglieder haben Werte für dieses benutzerdefinierte Feld z
msgid "All custom field values will be permanently deleted when you delete this custom field." msgid "All custom field values will be permanently deleted when you delete this custom field."
msgstr "Alle benutzerdefinierten Feldwerte werden beim Löschen dieses benutzerdefinierten Feldes dauerhaft gelöscht." msgstr "Alle benutzerdefinierten Feldwerte werden beim Löschen dieses benutzerdefinierten Feldes dauerhaft gelöscht."
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Delete Custom Field and All Values"
msgstr "Benutzerdefiniertes Feld und alle Werte löschen"
#: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Enter the text above to confirm" msgid "Enter the text above to confirm"
@ -662,7 +638,6 @@ msgstr "Vereinsdaten"
msgid "Manage global settings for the association." msgid "Manage global settings for the association."
msgstr "Passe übergreifende Einstellungen für den Verein an." msgstr "Passe übergreifende Einstellungen für den Verein an."
#: lib/mv_web/live/global_settings_live.ex
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Save Settings" msgid "Save Settings"
@ -785,8 +760,11 @@ msgstr "Adresse"
#: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_field_live/form_component.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Back" msgid "Back"
msgstr "Zurück" msgstr "Zurück"
@ -821,6 +799,7 @@ msgstr "Persönliche Daten"
#: lib/mv_web/live/group_live/form.ex #: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Save" msgid "Save"
@ -964,11 +943,6 @@ msgstr "Unbezahlt"
msgid "Yearly" msgid "Yearly"
msgstr "jährlich" msgstr "jährlich"
#: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#, elixir-autogen, elixir-format
msgid "Custom Field %{id}"
msgstr "Benutzerdefiniertes Feld %{id}"
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Last name" msgid "Last name"
@ -1604,17 +1578,11 @@ msgstr "Datenfeld speichern"
msgid "Back to roles list" msgid "Back to roles list"
msgstr "Zurück zur Rollen-Liste" msgstr "Zurück zur Rollen-Liste"
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Cannot delete system role"
msgstr "System-Rolle kann nicht gelöscht werden"
#: lib/mv_web/live/role_live/index.html.heex #: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Custom" msgid "Custom"
msgstr "Benutzerdefiniert" msgstr "Benutzerdefiniert"
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Failed to delete role: %{error}" msgid "Failed to delete role: %{error}"
@ -1631,7 +1599,6 @@ msgstr "Rollen auflisten"
msgid "Manage user roles and their permission sets." msgid "Manage user roles and their permission sets."
msgstr "Verwalte Benutzer*innen-Rollen und ihre Berechtigungssätze." msgstr "Verwalte Benutzer*innen-Rollen und ihre Berechtigungssätze."
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Cannot delete role. %{count} user(s) are still assigned to this role. Please assign them to another role first." msgid "Cannot delete role. %{count} user(s) are still assigned to this role. Please assign them to another role first."
@ -1642,11 +1609,6 @@ msgstr "Rolle kann nicht gelöscht werden. %{count} Benutzer*in(nen) sind dieser
msgid "Close sidebar" msgid "Close sidebar"
msgstr "Sidebar schließen" msgstr "Sidebar schließen"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete Role"
msgstr "Rolle löschen"
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Main navigation" msgid "Main navigation"
@ -1690,7 +1652,6 @@ msgstr "Profil"
msgid "Role" msgid "Role"
msgstr "Rolle" msgstr "Rolle"
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Role deleted successfully." msgid "Role deleted successfully."
@ -1702,7 +1663,6 @@ msgid "Role details and permissions."
msgstr "Rollen-Details und Berechtigungen." msgstr "Rollen-Details und Berechtigungen."
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Role not found." msgid "Role not found."
@ -1734,12 +1694,6 @@ msgstr "System"
msgid "System Role" msgid "System Role"
msgstr "System-Rolle" msgstr "System-Rolle"
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "System roles cannot be deleted"
msgstr "System-Rollen können nicht gelöscht werden"
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "System roles cannot be deleted." msgid "System roles cannot be deleted."
@ -1816,12 +1770,14 @@ msgstr "Mitgliedsbeitragsart nicht gefunden"
msgid "User %{action} successfully" msgid "User %{action} successfully"
msgstr "Benutzer*in wurde erfolgreich %{action}" msgstr "Benutzer*in wurde erfolgreich %{action}"
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User deleted successfully" msgid "User deleted successfully"
msgstr "Benutzer*in erfolgreich gelöscht" msgstr "Benutzer*in erfolgreich gelöscht"
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User not found" msgid "User not found"
msgstr "Benutzer*in nicht gefunden" msgstr "Benutzer*in nicht gefunden"
@ -1832,18 +1788,14 @@ msgstr "Benutzer*in nicht gefunden"
msgid "You do not have permission to access this membership fee type" msgid "You do not have permission to access this membership fee type"
msgstr "Du hast keine Berechtigung, auf diese Mitgliedsbeitragsart zuzugreifen" msgstr "Du hast keine Berechtigung, auf diese Mitgliedsbeitragsart zuzugreifen"
#: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format
msgid "You do not have permission to access this user"
msgstr "Du hast keine Berechtigung, auf diese*n Benutzer*in zuzugreifen"
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this membership fee type" msgid "You do not have permission to delete this membership fee type"
msgstr "Du hast keine Berechtigung, diese Mitgliedsbeitragsart zu löschen" msgstr "Du hast keine Berechtigung, diese Mitgliedsbeitragsart zu löschen"
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this user" msgid "You do not have permission to delete this user"
msgstr "Du hast keine Berechtigung, diese*n Benutzer*in zu löschen" msgstr "Du hast keine Berechtigung, diese*n Benutzer*in zu löschen"
@ -1864,16 +1816,19 @@ msgstr "aktualisiert"
msgid "Unknown error" msgid "Unknown error"
msgstr "Unbekannter Fehler" msgstr "Unbekannter Fehler"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member deleted successfully" msgid "Member deleted successfully"
msgstr "Mitglied wurde erfolgreich gelöscht" msgstr "Mitglied wurde erfolgreich gelöscht"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member not found" msgid "Member not found"
msgstr "Mitglied nicht gefunden" msgstr "Mitglied nicht gefunden"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this member" msgid "You do not have permission to delete this member"
@ -2130,6 +2085,7 @@ msgstr "Gruppe erstellen"
msgid "Delete Group" msgid "Delete Group"
msgstr "Gruppe löschen" msgstr "Gruppe löschen"
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Delete group" msgid "Delete group"
@ -2210,11 +2166,6 @@ msgstr[1] "Diese Gruppe hat %{count} Mitglieder. Alle Mitglied-Gruppen-Zuordnung
msgid "To confirm deletion, please enter the group name:" msgid "To confirm deletion, please enter the group name:"
msgstr "Um die Löschung zu bestätigen, gib bitte den Gruppennamen ein:" msgstr "Um die Löschung zu bestätigen, gib bitte den Gruppennamen ein:"
#: lib/mv_web/live/group_live/index.ex
#, elixir-autogen, elixir-format
msgid "View"
msgstr "Anzeigen"
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Total: %{count} member" msgid "Total: %{count} member"
@ -3073,38 +3024,42 @@ msgstr "Filter zurücksetzen“"
msgid "Apply filters" msgid "Apply filters"
msgstr "Filter auswählen" msgstr "Filter auswählen"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Are you sure you want to delete %{name}? This action cannot be undone." msgid "Are you sure you want to delete %{name}? This action cannot be undone."
msgstr "Möchtest du diese Gruppe wirklich löschen? Die Aktion kann nicht rückgängig gemacht werden." msgstr "Möchtest du diese Gruppe wirklich löschen? Die Aktion kann nicht rückgängig gemacht werden."
#: lib/mv_web/live/custom_field_live/form_component.ex
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Danger zone" msgid "Danger zone"
msgstr "Gefahrenzone" msgstr "Gefahrenzone"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Delete member" msgid "Delete member"
msgstr "Mitglied löschen" msgstr "Mitglied löschen"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete member %{name}" msgid "Delete member %{name}"
msgstr "Mitglied %{name} löschen" msgstr "Mitglied %{name} löschen"
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed." msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
msgstr "Das Löschen des Mitglieds kann nicht rückgängig gemacht werden. Alle dazugehörigen Daten (z.B. Mitgliedsbeitragszylen) werden gelöscht." msgstr "Das Löschen des Mitglieds kann nicht rückgängig gemacht werden. Alle dazugehörigen Daten (z.B. Mitgliedsbeitragszylen) werden gelöscht."
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit datafield"
msgstr "Datenfeld bearbeiten"
#: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Edit group" msgid "Edit group"
@ -3115,22 +3070,11 @@ msgstr "Gruppe bearbeiten"
msgid "Edit member" msgid "Edit member"
msgstr "Mitglied bearbeiten" msgstr "Mitglied bearbeiten"
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Edit role" msgid "Edit role"
msgstr "Rolle bearbeiten" msgstr "Rolle bearbeiten"
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit user"
msgstr "Benutzer*in bearbeiten"
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Click for datafield details"
msgstr "Klicke für Datenfeld-Details"
#: lib/mv_web/live/group_live/index.ex #: lib/mv_web/live/group_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Click for group details" msgid "Click for group details"
@ -3151,31 +3095,155 @@ msgstr "Klicke für Rollen-Details"
msgid "Click for user details" msgid "Click for user details"
msgstr "Klicke für Benutzer*innen-Details" msgstr "Klicke für Benutzer*innen-Details"
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Click for dataield details"
msgstr "Klicke für Datenfeld-Details"
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Members table" msgid "Members table"
msgstr "Mitglieder" msgstr "Mitglieder"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Are you sure you want to delete the role %{name}? This action cannot be undone."
msgstr "Möchtest du diese Gruppe wirklich löschen? Die Aktion kann nicht rückgängig gemacht werden."
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Are you sure you want to delete the user %{email}? This action cannot be undone."
msgstr "Möchtest du diese Gruppe wirklich löschen? Die Aktion kann nicht rückgängig gemacht werden."
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Click to edit datafield"
msgstr "Klicke für Datenfeld-Details"
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete data field"
msgstr "Datenfeld löschen"
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format
msgid "Delete data field %{name}"
msgstr "Datenfeld %{name} löschen"
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete group %{name}"
msgstr "Gruppe %{name} löschen"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete role"
msgstr "Rolle löschen"
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete role %{name}"
msgstr "Mitglied %{name} löschen"
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete user"
msgstr "Löschen"
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete user %{email}"
msgstr "Benutzer*in %{email} löschen"
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this group cannot be undone. All member-group associations will be permanently removed."
msgstr "Das Löschen der Gruppe kann nicht rückgängig gemacht werden. Alle Mitglieds-Gruppen Zugehörigkeiten werden gelöscht."
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this role cannot be undone. Users assigned to this role must be reassigned first."
msgstr "Das Löschen dieser Rolle kann nicht rückgängig gemacht werden. Benutzer*inen die dieser Rolle zugewiesen wurden, müssen zuerst einer anderen Rolle zugewiesen werden."
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this user cannot be undone. The user account and any linked member association will be affected."
msgstr "Das Löschen kann nicht rückgängig gemacht werden. Der Account und Verlinkungen zu Mitgliedern werden entfernt."
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "System user cannot be deleted."
msgstr "System-Rollen können nicht gelöscht werden."
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Save Name"
msgstr "Speichern"
#: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Datafield %{id}"
msgstr "Datenfelder"
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete Datafields and All Values"
msgstr "Benutzerdefiniertes Feld und alle Werte löschen"
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Deleting this data field cannot be undone. All datafield values for this field will be permanently removed."
msgstr "Das Löschen dieses Datenfeldes kann nicht rückgängig gemacht werden. Alle "
#: lib/mv_web/live/components/member_filter_component.ex
#, elixir-autogen, elixir-format
msgid "Individual datafields"
msgstr "Individuelle Datenfelder"
#~ #: lib/mv_web/live/member_field_live/form_component.ex #~ #: lib/mv_web/live/member_field_live/form_component.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Back to Settings" #~ msgid "Back to Settings"
#~ msgstr "Zurück zu den Einstellungen" #~ msgstr "Zurück zu den Einstellungen"
#~ #: lib/mv_web/live/role_live/index.html.heex
#~ #, elixir-autogen, elixir-format
#~ msgid "Cannot delete system role"
#~ msgstr "System-Rolle kann nicht gelöscht werden"
#~ #: lib/mv_web/live/custom_field_live/index_component.ex #~ #: lib/mv_web/live/custom_field_live/index_component.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Click for custom field details" #~ msgid "Click for custom field details"
#~ msgstr "Klicke für Datenfeld-Details" #~ msgstr "Klicke für Datenfeld-Details"
#~ #: lib/mv_web/live/member_field_live/index_component.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "Click for datafield details"
#~ msgstr "Klicke für Datenfeld-Details"
#~ #: lib/mv_web/live/member_live/form.ex #~ #: lib/mv_web/live/member_live/form.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Coming soon" #~ msgid "Coming soon"
#~ msgstr "Demnächst verfügbar" #~ msgstr "Demnächst verfügbar"
#~ #: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "Custom Field %{id}"
#~ msgstr "Benutzerdefiniertes Feld %{id}"
#~ #: lib/mv_web/live/custom_field_live/index_component.ex
#~ #: lib/mv_web/live/member_field_live/index_component.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Edit datafield"
#~ msgstr "Datenfeld bearbeiten"
#~ #: lib/mv_web/live/user_live/index.html.heex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Edit user"
#~ msgstr "Benutzer*in bearbeiten"
#~ #: lib/mv_web/live/components/member_filter_component.ex #~ #: lib/mv_web/live/components/member_filter_component.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Reset" #~ msgid "Reset"
@ -3191,7 +3259,32 @@ msgstr "Mitglieder"
#~ msgid "Save Role" #~ msgid "Save Role"
#~ msgstr "Rolle speichern" #~ msgstr "Rolle speichern"
#~ #: lib/mv_web/live/user_live/index.html.heex
#~ #, elixir-autogen, elixir-format
#~ msgid "Select all users"
#~ msgstr "Alle Benutzer*innen auswählen"
#~ #: lib/mv_web/live/user_live/index.html.heex
#~ #, elixir-autogen, elixir-format
#~ msgid "Select user"
#~ msgstr "Benutzer*in auswählen"
#~ #: lib/mv_web/live/role_live/index.html.heex
#~ #, elixir-autogen, elixir-format
#~ msgid "System roles cannot be deleted"
#~ msgstr "System-Rollen können nicht gelöscht werden"
#~ #: lib/mv_web/live/group_live/index.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "View"
#~ msgstr "Anzeigen"
#~ #: lib/mv_web/live/member_live/index.ex #~ #: lib/mv_web/live/member_live/index.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "You do not have permission to access this member" #~ msgid "You do not have permission to access this member"
#~ msgstr "Du hast keine Berechtigung, auf dieses Mitglied zuzugreifen" #~ msgstr "Du hast keine Berechtigung, auf dieses Mitglied zuzugreifen"
#~ #: lib/mv_web/live/user_live/index.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "You do not have permission to access this user"
#~ msgstr "Du hast keine Berechtigung, auf diese*n Benutzer*in zuzugreifen"

View file

@ -19,9 +19,6 @@ msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Are you sure?" msgid "Are you sure?"
msgstr "" msgstr ""
@ -39,11 +36,8 @@ msgstr ""
msgid "City" msgid "City"
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete" msgid "Delete"
msgstr "" msgstr ""
@ -101,8 +95,6 @@ msgid "New Member"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Show" msgid "Show"
msgstr "" msgstr ""
@ -481,16 +473,6 @@ msgstr ""
msgid "Password requirements" msgid "Password requirements"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Select all users"
msgstr ""
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Select user"
msgstr ""
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Set Password" msgid "Set Password"
@ -606,7 +588,6 @@ msgstr ""
msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account." msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account."
msgstr "" msgstr ""
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -625,11 +606,6 @@ msgstr[1] ""
msgid "All custom field values will be permanently deleted when you delete this custom field." msgid "All custom field values will be permanently deleted when you delete this custom field."
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Delete Custom Field and All Values"
msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Enter the text above to confirm" msgid "Enter the text above to confirm"
@ -663,7 +639,6 @@ msgstr ""
msgid "Manage global settings for the association." msgid "Manage global settings for the association."
msgstr "" msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Save Settings" msgid "Save Settings"
@ -786,8 +761,11 @@ msgstr ""
#: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_field_live/form_component.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Back" msgid "Back"
msgstr "" msgstr ""
@ -822,6 +800,7 @@ msgstr ""
#: lib/mv_web/live/group_live/form.ex #: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Save" msgid "Save"
@ -965,11 +944,6 @@ msgstr ""
msgid "Yearly" msgid "Yearly"
msgstr "" msgstr ""
#: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#, elixir-autogen, elixir-format
msgid "Custom Field %{id}"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Last name" msgid "Last name"
@ -1605,17 +1579,11 @@ msgstr ""
msgid "Back to roles list" msgid "Back to roles list"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Cannot delete system role"
msgstr ""
#: lib/mv_web/live/role_live/index.html.heex #: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Custom" msgid "Custom"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Failed to delete role: %{error}" msgid "Failed to delete role: %{error}"
@ -1632,7 +1600,6 @@ msgstr ""
msgid "Manage user roles and their permission sets." msgid "Manage user roles and their permission sets."
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Cannot delete role. %{count} user(s) are still assigned to this role. Please assign them to another role first." msgid "Cannot delete role. %{count} user(s) are still assigned to this role. Please assign them to another role first."
@ -1643,11 +1610,6 @@ msgstr ""
msgid "Close sidebar" msgid "Close sidebar"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete Role"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Main navigation" msgid "Main navigation"
@ -1691,7 +1653,6 @@ msgstr ""
msgid "Role" msgid "Role"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Role deleted successfully." msgid "Role deleted successfully."
@ -1703,7 +1664,6 @@ msgid "Role details and permissions."
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Role not found." msgid "Role not found."
@ -1735,12 +1695,6 @@ msgstr ""
msgid "System Role" msgid "System Role"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "System roles cannot be deleted"
msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "System roles cannot be deleted." msgid "System roles cannot be deleted."
@ -1817,12 +1771,14 @@ msgstr ""
msgid "User %{action} successfully" msgid "User %{action} successfully"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User deleted successfully" msgid "User deleted successfully"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "User not found" msgid "User not found"
msgstr "" msgstr ""
@ -1833,18 +1789,14 @@ msgstr ""
msgid "You do not have permission to access this membership fee type" msgid "You do not have permission to access this membership fee type"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format
msgid "You do not have permission to access this user"
msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this membership fee type" msgid "You do not have permission to delete this membership fee type"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this user" msgid "You do not have permission to delete this user"
msgstr "" msgstr ""
@ -1865,16 +1817,19 @@ msgstr ""
msgid "Unknown error" msgid "Unknown error"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member deleted successfully" msgid "Member deleted successfully"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member not found" msgid "Member not found"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this member" msgid "You do not have permission to delete this member"
@ -2131,6 +2086,7 @@ msgstr ""
msgid "Delete Group" msgid "Delete Group"
msgstr "" msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete group" msgid "Delete group"
@ -2211,11 +2167,6 @@ msgstr[1] ""
msgid "To confirm deletion, please enter the group name:" msgid "To confirm deletion, please enter the group name:"
msgstr "" msgstr ""
#: lib/mv_web/live/group_live/index.ex
#, elixir-autogen, elixir-format
msgid "View"
msgstr ""
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Total: %{count} member" msgid "Total: %{count} member"
@ -3073,38 +3024,42 @@ msgstr ""
msgid "Apply filters" msgid "Apply filters"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Are you sure you want to delete %{name}? This action cannot be undone." msgid "Are you sure you want to delete %{name}? This action cannot be undone."
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Danger zone" msgid "Danger zone"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete member" msgid "Delete member"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete member %{name}" msgid "Delete member %{name}"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed." msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Edit datafield"
msgstr ""
#: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Edit group" msgid "Edit group"
@ -3115,22 +3070,11 @@ msgstr ""
msgid "Edit member" msgid "Edit member"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Edit role" msgid "Edit role"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Edit user"
msgstr ""
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Click for datafield details"
msgstr ""
#: lib/mv_web/live/group_live/index.ex #: lib/mv_web/live/group_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Click for group details" msgid "Click for group details"
@ -3151,12 +3095,110 @@ msgstr ""
msgid "Click for user details" msgid "Click for user details"
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Click for dataield details"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Members table" msgid "Members table"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete the role %{name}? This action cannot be undone."
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete the user %{email}? This action cannot be undone."
msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Click to edit datafield"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format
msgid "Delete data field"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format
msgid "Delete data field %{name}"
msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete group %{name}"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete role"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete role %{name}"
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete user"
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete user %{email}"
msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this group cannot be undone. All member-group associations will be permanently removed."
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this role cannot be undone. Users assigned to this role must be reassigned first."
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this user cannot be undone. The user account and any linked member association will be affected."
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "System user cannot be deleted."
msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format
msgid "Save Name"
msgstr ""
#: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#, elixir-autogen, elixir-format
msgid "Datafield %{id}"
msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Delete Datafields and All Values"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format
msgid "Deleting this data field cannot be undone. All datafield values for this field will be permanently removed."
msgstr ""
#: lib/mv_web/live/components/member_filter_component.ex
#, elixir-autogen, elixir-format
msgid "Individual datafields"
msgstr ""

View file

@ -19,9 +19,6 @@ msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Are you sure?" msgid "Are you sure?"
msgstr "" msgstr ""
@ -39,11 +36,8 @@ msgstr ""
msgid "City" msgid "City"
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete" msgid "Delete"
msgstr "" msgstr ""
@ -101,8 +95,6 @@ msgid "New Member"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Show" msgid "Show"
msgstr "" msgstr ""
@ -481,16 +473,6 @@ msgstr ""
msgid "Password requirements" msgid "Password requirements"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy
msgid "Select all users"
msgstr ""
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy
msgid "Select user"
msgstr ""
#: lib/mv_web/live/user_live/form.ex #: lib/mv_web/live/user_live/form.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Set Password" msgid "Set Password"
@ -606,7 +588,6 @@ msgstr ""
msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account." msgid "This email is already linked to a different OIDC account. Cannot link multiple OIDC providers to the same account."
msgstr "" msgstr ""
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
@ -625,11 +606,6 @@ msgstr[1] ""
msgid "All custom field values will be permanently deleted when you delete this custom field." msgid "All custom field values will be permanently deleted when you delete this custom field."
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Delete Custom Field and All Values"
msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Enter the text above to confirm" msgid "Enter the text above to confirm"
@ -663,7 +639,6 @@ msgstr ""
msgid "Manage global settings for the association." msgid "Manage global settings for the association."
msgstr "" msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Save Settings" msgid "Save Settings"
@ -786,8 +761,11 @@ msgstr ""
#: lib/mv_web/live/member_field_live/form_component.ex #: lib/mv_web/live/member_field_live/form_component.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Back" msgid "Back"
msgstr "" msgstr ""
@ -822,6 +800,7 @@ msgstr ""
#: lib/mv_web/live/group_live/form.ex #: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex #: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/membership_fee_type_live/form.ex
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Save" msgid "Save"
@ -965,11 +944,6 @@ msgstr ""
msgid "Yearly" msgid "Yearly"
msgstr "" msgstr ""
#: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Custom Field %{id}"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Last name" msgid "Last name"
@ -1605,17 +1579,11 @@ msgstr ""
msgid "Back to roles list" msgid "Back to roles list"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Cannot delete system role"
msgstr ""
#: lib/mv_web/live/role_live/index.html.heex #: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Custom" msgid "Custom"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Failed to delete role: %{error}" msgid "Failed to delete role: %{error}"
@ -1632,7 +1600,6 @@ msgstr ""
msgid "Manage user roles and their permission sets." msgid "Manage user roles and their permission sets."
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Cannot delete role. %{count} user(s) are still assigned to this role. Please assign them to another role first." msgid "Cannot delete role. %{count} user(s) are still assigned to this role. Please assign them to another role first."
@ -1643,11 +1610,6 @@ msgstr ""
msgid "Close sidebar" msgid "Close sidebar"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete Role"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex #: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Main navigation" msgid "Main navigation"
@ -1691,7 +1653,6 @@ msgstr ""
msgid "Role" msgid "Role"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Role deleted successfully." msgid "Role deleted successfully."
@ -1703,7 +1664,6 @@ msgid "Role details and permissions."
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/form.ex #: lib/mv_web/live/role_live/form.ex
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Role not found." msgid "Role not found."
@ -1735,12 +1695,6 @@ msgstr ""
msgid "System Role" msgid "System Role"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "System roles cannot be deleted"
msgstr ""
#: lib/mv_web/live/role_live/index.ex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "System roles cannot be deleted." msgid "System roles cannot be deleted."
@ -1817,12 +1771,14 @@ msgstr ""
msgid "User %{action} successfully" msgid "User %{action} successfully"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "User deleted successfully" msgid "User deleted successfully"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "User not found" msgid "User not found"
msgstr "" msgstr ""
@ -1833,18 +1789,14 @@ msgstr ""
msgid "You do not have permission to access this membership fee type" msgid "You do not have permission to access this membership fee type"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "You do not have permission to access this user"
msgstr ""
#: lib/mv_web/live/membership_fee_settings_live.ex #: lib/mv_web/live/membership_fee_settings_live.ex
#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/membership_fee_type_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "You do not have permission to delete this membership fee type" msgid "You do not have permission to delete this membership fee type"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.ex #: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "You do not have permission to delete this user" msgid "You do not have permission to delete this user"
msgstr "" msgstr ""
@ -1865,16 +1817,19 @@ msgstr ""
msgid "Unknown error" msgid "Unknown error"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member deleted successfully" msgid "Member deleted successfully"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member not found" msgid "Member not found"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "You do not have permission to delete this member" msgid "You do not have permission to delete this member"
@ -2131,6 +2086,7 @@ msgstr ""
msgid "Delete Group" msgid "Delete Group"
msgstr "" msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Delete group" msgid "Delete group"
@ -2211,11 +2167,6 @@ msgstr[1] ""
msgid "To confirm deletion, please enter the group name:" msgid "To confirm deletion, please enter the group name:"
msgstr "" msgstr ""
#: lib/mv_web/live/group_live/index.ex
#, elixir-autogen, elixir-format
msgid "View"
msgstr ""
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Total: %{count} member" msgid "Total: %{count} member"
@ -3073,38 +3024,42 @@ msgstr ""
msgid "Apply filters" msgid "Apply filters"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Are you sure you want to delete %{name}? This action cannot be undone." msgid "Are you sure you want to delete %{name}? This action cannot be undone."
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/role_live/show.ex
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Danger zone" msgid "Danger zone"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Delete member" msgid "Delete member"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Delete member %{name}" msgid "Delete member %{name}"
msgstr "" msgstr ""
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed." msgid "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit datafield"
msgstr ""
#: lib/mv_web/live/group_live/index.ex
#: lib/mv_web/live/group_live/show.ex #: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Edit group" msgid "Edit group"
@ -3115,22 +3070,11 @@ msgstr ""
msgid "Edit member" msgid "Edit member"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/index.html.heex
#: lib/mv_web/live/role_live/show.ex #: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Edit role" msgid "Edit role"
msgstr "" msgstr ""
#: lib/mv_web/live/user_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit user"
msgstr ""
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format
msgid "Click for datafield details"
msgstr ""
#: lib/mv_web/live/group_live/index.ex #: lib/mv_web/live/group_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Click for group details" msgid "Click for group details"
@ -3151,31 +3095,155 @@ msgstr ""
msgid "Click for user details" msgid "Click for user details"
msgstr "" msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Click for dataield details"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Members table" msgid "Members table"
msgstr "" msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Are you sure you want to delete the role %{name}? This action cannot be undone."
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Are you sure you want to delete the user %{email}? This action cannot be undone."
msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#: lib/mv_web/live/member_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Click to edit datafield"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete data field"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format
msgid "Delete data field %{name}"
msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete group %{name}"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete role"
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete role %{name}"
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete user"
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Delete user %{email}"
msgstr ""
#: lib/mv_web/live/group_live/form.ex
#: lib/mv_web/live/group_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this group cannot be undone. All member-group associations will be permanently removed."
msgstr ""
#: lib/mv_web/live/role_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this role cannot be undone. Users assigned to this role must be reassigned first."
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format
msgid "Deleting this user cannot be undone. The user account and any linked member association will be affected."
msgstr ""
#: lib/mv_web/live/user_live/form.ex
#: lib/mv_web/live/user_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "System user cannot be deleted."
msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Save Name"
msgstr ""
#: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Datafield %{id}"
msgstr ""
#: lib/mv_web/live/custom_field_live/index_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Delete Datafields and All Values"
msgstr ""
#: lib/mv_web/live/custom_field_live/form_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Deleting this data field cannot be undone. All datafield values for this field will be permanently removed."
msgstr ""
#: lib/mv_web/live/components/member_filter_component.ex
#, elixir-autogen, elixir-format
msgid "Individual datafields"
msgstr ""
#~ #: lib/mv_web/live/member_field_live/form_component.ex #~ #: lib/mv_web/live/member_field_live/form_component.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Back to Settings" #~ msgid "Back to Settings"
#~ msgstr "" #~ msgstr ""
#~ #: lib/mv_web/live/role_live/index.html.heex
#~ #, elixir-autogen, elixir-format
#~ msgid "Cannot delete system role"
#~ msgstr ""
#~ #: lib/mv_web/live/custom_field_live/index_component.ex #~ #: lib/mv_web/live/custom_field_live/index_component.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Click for custom field details" #~ msgid "Click for custom field details"
#~ msgstr "" #~ msgstr ""
#~ #: lib/mv_web/live/member_field_live/index_component.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "Click for datafield details"
#~ msgstr ""
#~ #: lib/mv_web/live/member_live/form.ex #~ #: lib/mv_web/live/member_live/form.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Coming soon" #~ msgid "Coming soon"
#~ msgstr "" #~ msgstr ""
#~ #: lib/mv_web/live/components/field_visibility_dropdown_component.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Custom Field %{id}"
#~ msgstr ""
#~ #: lib/mv_web/live/custom_field_live/index_component.ex
#~ #: lib/mv_web/live/member_field_live/index_component.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Edit datafield"
#~ msgstr ""
#~ #: lib/mv_web/live/user_live/index.html.heex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Edit user"
#~ msgstr ""
#~ #: lib/mv_web/live/components/member_filter_component.ex #~ #: lib/mv_web/live/components/member_filter_component.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "Reset" #~ msgid "Reset"
@ -3191,7 +3259,32 @@ msgstr ""
#~ msgid "Save Role" #~ msgid "Save Role"
#~ msgstr "" #~ msgstr ""
#~ #: lib/mv_web/live/user_live/index.html.heex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Select all users"
#~ msgstr ""
#~ #: lib/mv_web/live/user_live/index.html.heex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Select user"
#~ msgstr ""
#~ #: lib/mv_web/live/role_live/index.html.heex
#~ #, elixir-autogen, elixir-format
#~ msgid "System roles cannot be deleted"
#~ msgstr ""
#~ #: lib/mv_web/live/group_live/index.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "View"
#~ msgstr ""
#~ #: lib/mv_web/live/member_live/index.ex #~ #: lib/mv_web/live/member_live/index.ex
#~ #, elixir-autogen, elixir-format #~ #, elixir-autogen, elixir-format
#~ msgid "You do not have permission to access this member" #~ msgid "You do not have permission to access this member"
#~ msgstr "" #~ msgstr ""
#~ #: lib/mv_web/live/user_live/index.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "You do not have permission to access this user"
#~ msgstr ""

View file

@ -46,6 +46,17 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
%{conn: conn, user: user_with_role} %{conn: conn, user: user_with_role}
end end
# Delete is in the edit form (FormComponent); open form by clicking the name cell (unique td with phx-click)
defp open_delete_modal(view, custom_field) do
view
|> element("tr#custom_fields-#{custom_field.id} td", custom_field.name)
|> render_click()
view
|> element("[data-testid=custom-field-delete]")
|> render_click()
end
describe "delete button and modal" do describe "delete button and modal" do
test "opens modal with correct member count when delete is clicked", %{conn: conn} do test "opens modal with correct member count when delete is clicked", %{conn: conn} do
{:ok, member} = create_member() {:ok, member} = create_member()
@ -55,11 +66,7 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
create_custom_field_value(member, custom_field, "test") create_custom_field_value(member, custom_field, "test")
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
# Click delete button - find the delete link within the component
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Modal should be visible # Modal should be visible
assert has_element?(view, "#delete-custom-field-modal") assert has_element?(view, "#delete-custom-field-modal")
@ -81,23 +88,17 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
create_custom_field_value(member2, custom_field, "test2") create_custom_field_value(member2, custom_field, "test2")
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Should show plural form # Should show plural form
assert render(view) =~ "2 members have values assigned for this custom field" assert render(view) =~ "2 members have values assigned for this custom field"
end end
test "shows 0 members for custom field without values", %{conn: conn} do test "shows 0 members for custom field without values", %{conn: conn} do
{:ok, _custom_field} = create_custom_field("test_field", :string) {:ok, custom_field} = create_custom_field("test_field", :string)
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Should show 0 members # Should show 0 members
assert render(view) =~ "0 members have values assigned for this custom field" assert render(view) =~ "0 members have values assigned for this custom field"
@ -109,10 +110,7 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
{:ok, custom_field} = create_custom_field("test_field", :string) {:ok, custom_field} = create_custom_field("test_field", :string)
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Type in slug input - use element to find the form with phx-target # Type in slug input - use element to find the form with phx-target
view view
@ -124,13 +122,10 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
end end
test "delete button is disabled when slug doesn't match", %{conn: conn} do test "delete button is disabled when slug doesn't match", %{conn: conn} do
{:ok, _custom_field} = create_custom_field("test_field", :string) {:ok, custom_field} = create_custom_field("test_field", :string)
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Type wrong slug - use element to find the form with phx-target # Type wrong slug - use element to find the form with phx-target
view view
@ -149,11 +144,7 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
{:ok, custom_field_value} = create_custom_field_value(member, custom_field, "test") {:ok, custom_field_value} = create_custom_field_value(member, custom_field, "test")
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
# Open modal
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Enter correct slug - use element to find the form with phx-target # Enter correct slug - use element to find the form with phx-target
view view
@ -162,7 +153,7 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
# Click confirm # Click confirm
view view
|> element("#delete-custom-field-modal button", "Delete Custom Field and All Values") |> element("#delete-custom-field-modal button", "Delete Datafields and All Values")
|> render_click() |> render_click()
# Should show success message # Should show success message
@ -186,10 +177,7 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
{:ok, custom_field} = create_custom_field("test_field", :string) {:ok, custom_field} = create_custom_field("test_field", :string)
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Enter wrong slug - use element to find the form with phx-target # Enter wrong slug - use element to find the form with phx-target
view view
@ -210,10 +198,7 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
{:ok, custom_field} = create_custom_field("test_field", :string) {:ok, custom_field} = create_custom_field("test_field", :string)
{:ok, view, _html} = live(conn, ~p"/admin/datafields") {:ok, view, _html} = live(conn, ~p"/admin/datafields")
open_delete_modal(view, custom_field)
view
|> element("#custom-fields-component a", "Delete")
|> render_click()
# Modal should be visible # Modal should be visible
assert has_element?(view, "#delete-custom-field-modal") assert has_element?(view, "#delete-custom-field-modal")

View file

@ -138,7 +138,7 @@ defmodule MvWeb.RoleLiveTest do
assert html =~ "System Role" || html =~ "system" assert html =~ "System Role" || html =~ "system"
end end
test "delete button disabled for system roles", %{conn: conn, actor: actor} do test "delete button not shown for system roles", %{conn: conn, actor: actor} do
system_role = system_role =
Role Role
|> Ash.Changeset.for_create(:create_role, %{ |> Ash.Changeset.for_create(:create_role, %{
@ -148,28 +148,19 @@ defmodule MvWeb.RoleLiveTest do
|> Ash.Changeset.force_change_attribute(:is_system_role, true) |> Ash.Changeset.force_change_attribute(:is_system_role, true)
|> Ash.create!(actor: actor) |> Ash.create!(actor: actor)
{:ok, view, _html} = live(conn, "/admin/roles") {:ok, view, _html} = live(conn, "/admin/roles/#{system_role.id}")
assert has_element?( # Danger zone (and delete button) is not rendered for system roles
view, refute has_element?(view, "[data-testid=role-delete]")
"button[phx-click='delete'][phx-value-id='#{system_role.id}'][disabled]"
) ||
not has_element?(
view,
"button[phx-click='delete'][phx-value-id='#{system_role.id}']"
)
end end
test "delete button enabled for non-system roles", %{conn: conn} do test "delete button enabled for non-system roles", %{conn: conn} do
role = create_role() role = create_role()
{:ok, view, html} = live(conn, "/admin/roles") {:ok, view, _html} = live(conn, "/admin/roles/#{role.id}")
# Delete is a link with phx-click containing delete event # Delete is on show page (Danger zone)
# Check if delete link exists in HTML (phx-click contains delete and role id) assert has_element?(view, "[data-testid=role-delete]")
assert (html =~ "phx-click" && html =~ "delete" && html =~ role.id) ||
has_element?(view, "a[phx-click*='delete'][phx-value-id='#{role.id}']") ||
has_element?(view, "a[aria-label='Delete role']")
end end
test "new role button navigates to form", %{conn: conn} do test "new role button navigates to form", %{conn: conn} do
@ -393,21 +384,21 @@ defmodule MvWeb.RoleLiveTest do
test "deletes non-system role", %{conn: conn, actor: actor} do test "deletes non-system role", %{conn: conn, actor: actor} do
role = create_role() role = create_role()
{:ok, view, html} = live(conn, "/admin/roles") {:ok, view, _html} = live(conn, "/admin/roles/#{role.id}")
# Delete is a link - JS.push creates phx-click with value containing id # Delete from Danger zone on show page
# Verify the role id is in the HTML (in phx-click value) view
assert html =~ role.id |> element("[data-testid=role-delete]")
|> render_click()
# Send delete event directly to avoid selector issues with multiple delete buttons assert_redirect(view, "/admin/roles")
render_click(view, "delete", %{"id" => role.id})
# Verify deletion by checking database # Verify deletion by checking database
assert {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Query.NotFound{}]}} = assert {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Query.NotFound{}]}} =
Authorization.get_role(role.id, actor: actor) Authorization.get_role(role.id, actor: actor)
end end
test "fails to delete system role with error message", %{conn: conn, actor: actor} do test "system role has no delete button and cannot be deleted", %{conn: conn, actor: actor} do
system_role = system_role =
Role Role
|> Ash.Changeset.for_create(:create_role, %{ |> Ash.Changeset.for_create(:create_role, %{
@ -417,19 +408,12 @@ defmodule MvWeb.RoleLiveTest do
|> Ash.Changeset.force_change_attribute(:is_system_role, true) |> Ash.Changeset.force_change_attribute(:is_system_role, true)
|> Ash.create!(actor: actor) |> Ash.create!(actor: actor)
{:ok, view, html} = live(conn, "/admin/roles") {:ok, view, _html} = live(conn, "/admin/roles/#{system_role.id}")
# System role delete button should be disabled # Danger zone is not rendered for system roles (no delete button)
assert html =~ "disabled" || html =~ "cursor-not-allowed" || refute has_element?(view, "[data-testid=role-delete]")
html =~ "System roles cannot be deleted"
# Try to delete via event (backend check) # Role still exists
render_click(view, "delete", %{"id" => system_role.id})
# Should show error message
assert render(view) =~ "System roles cannot be deleted"
# Role should still exist
{:ok, _role} = Authorization.get_role(system_role.id, actor: actor) {:ok, _role} = Authorization.get_role(system_role.id, actor: actor)
end end
end end

View file

@ -10,14 +10,16 @@ defmodule MvWeb.UserLiveAuthorizationTest do
describe "User Index - Admin" do describe "User Index - Admin" do
@tag role: :admin @tag role: :admin
test "sees New User, Edit and Delete buttons", %{conn: conn} do test "sees New User button; Edit and Delete are on show page", %{conn: conn} do
user = Fixtures.user_with_role_fixture("admin") user = Fixtures.user_with_role_fixture("admin")
{:ok, view, _html} = live(conn, "/users") {:ok, index_view, _html} = live(conn, "/users")
assert has_element?(index_view, "[data-testid=user-new]")
assert has_element?(view, "[data-testid=user-new]") # Edit and Delete are on user show page (Danger zone), not on index
assert has_element?(view, "#row-#{user.id} [data-testid=user-edit]") {:ok, show_view, _html} = live(conn, "/users/#{user.id}")
assert has_element?(view, "#row-#{user.id} [data-testid=user-delete]") assert has_element?(show_view, "[data-testid=user-edit]")
assert has_element?(show_view, "[data-testid=user-delete]")
end end
end end

View file

@ -16,11 +16,10 @@ defmodule MvWeb.UserLive.IndexTest do
assert html =~ "alice@example.com" assert html =~ "alice@example.com"
assert html =~ "bob@example.com" assert html =~ "bob@example.com"
# UI elements: New User button, action links # UI elements: New User button; row click navigates to show (no Edit/Delete on index)
assert html =~ "New User" assert html =~ "New User"
assert html =~ "Edit" # Row or navigation contains user id (e.g. row id or phx-click navigate)
assert html =~ "Delete" assert html =~ "row-#{user1.id}" or html =~ to_string(user1.id)
assert html =~ ~r/href="[^"]*\/users\/#{user1.id}\/edit"/
end end
@tag :ui @tag :ui
@ -116,177 +115,29 @@ defmodule MvWeb.UserLive.IndexTest do
end end
end end
describe "checkbox selection functionality" do
setup do
user1 = create_test_user(%{email: "user1@example.com", oidc_id: "user1"})
user2 = create_test_user(%{email: "user2@example.com", oidc_id: "user2"})
%{users: [user1, user2]}
end
@tag :ui
test "shows checkbox UI elements", %{conn: conn, users: [user1, user2]} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/users")
# Check select all checkbox exists
assert html =~ ~s(name="select_all")
assert html =~ ~s(phx-click="select_all")
# Check individual user checkboxes exist
assert html =~ ~s(name="#{user1.id}")
assert html =~ ~s(name="#{user2.id}")
assert html =~ ~s(phx-click="select_user")
end
@tag :ui
test "can select and deselect individual users", %{conn: conn, users: [user1, user2]} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/users")
# Initially, individual checkboxes should exist but not be checked
assert view |> element("input[type='checkbox'][name='#{user1.id}']") |> has_element?()
assert view |> element("input[type='checkbox'][name='#{user2.id}']") |> has_element?()
refute view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
# Select first user checkbox
html = view |> element("input[type='checkbox'][name='#{user1.id}']") |> render_click()
assert html =~ "Email"
assert html =~ to_string(user1.email)
# The select_all checkbox should still not be checked (not all users selected)
refute view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
# Deselect user
html = view |> element("input[type='checkbox'][name='#{user1.id}']") |> render_click()
assert html =~ "Email"
refute view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
end
@tag :ui
test "select all and deselect all functionality", %{conn: conn, users: [user1, user2]} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/users")
# Initially no checkboxes should be checked
refute view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
refute view
|> element("input[type='checkbox'][name='#{user1.id}'][checked]")
|> has_element?()
refute view
|> element("input[type='checkbox'][name='#{user2.id}'][checked]")
|> has_element?()
# Click select all
html = view |> element("input[type='checkbox'][name='select_all']") |> render_click()
# After selecting all, the select_all checkbox should be checked
assert view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
assert html =~ "Email"
assert html =~ to_string(user1.email)
assert html =~ to_string(user2.email)
# Then deselect all
html = view |> element("input[type='checkbox'][name='select_all']") |> render_click()
# After deselecting all, no checkboxes should be checked
refute view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
refute view
|> element("input[type='checkbox'][name='#{user1.id}'][checked]")
|> has_element?()
refute view
|> element("input[type='checkbox'][name='#{user2.id}'][checked]")
|> has_element?()
assert html =~ "Email"
end
@tag :slow
test "select all automatically checks when all individual users are selected", %{
conn: conn,
users: [_user1, _user2]
} do
conn = conn_with_oidc_user(conn)
{:ok, view, html} = live(conn, "/users")
# Get all user IDs from the rendered HTML by finding all checkboxes with phx-click="select_user"
# Extract user IDs from the HTML (they appear as name attributes on checkboxes)
user_ids =
html
|> String.split("phx-click=\"select_user\"")
|> Enum.flat_map(fn part ->
case Regex.run(~r/name="([^"]+)"[^>]*phx-value-id/, part) do
[_, user_id] -> [user_id]
_ -> []
end
end)
|> Enum.uniq()
# Skip if no users found (shouldn't happen, but be safe)
if user_ids != [] do
# Initially nothing should be checked
refute view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
# Select all users one by one
Enum.each(user_ids, fn user_id ->
view |> element("input[type='checkbox'][name='#{user_id}']") |> render_click()
end)
# Now select all should be automatically checked (all individual users are selected)
assert view
|> element("input[type='checkbox'][name='select_all'][checked]")
|> has_element?()
end
end
end
describe "delete functionality" do describe "delete functionality" do
test "can delete a user", %{conn: conn} do # Delete is only on user show page (Danger zone), not on index (per CODE_GUIDELINES: at most one UI smoke test for delete)
_user = create_test_user(%{email: "delete-me@example.com"}) test "can delete a user from show page", %{conn: conn} do
user = create_test_user(%{email: "delete-me@example.com"})
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/users") {:ok, index_view, _html} = live(conn, "/users")
assert render(index_view) =~ "delete-me@example.com"
# Confirm user is displayed # Navigate to user show and trigger delete from Danger zone
assert render(view) =~ "delete-me@example.com" {:ok, show_view, _html} = live(conn, "/users/#{user.id}")
# Click the delete button (phx-click="delete" event) show_view
view |> element("tbody tr:first-child a[data-confirm]") |> render_click() |> element("[data-testid=user-delete]")
|> render_click()
# Verify user was actually deleted (should not appear in HTML anymore) # Should redirect to index
html = render(view) assert_redirect(show_view, "/users")
# Reload index with same session; user should be gone
{:ok, _view_after, html} = live(conn, "/users")
refute html =~ "delete-me@example.com" refute html =~ "delete-me@example.com"
# Table header should still be there
assert html =~ "Email" assert html =~ "Email"
end end
test "shows delete confirmation", %{conn: conn} do
_user = create_test_user(%{email: "confirm-delete@example.com"})
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/users")
# Check that delete link has confirmation attribute
assert html =~ ~s(data-confirm="Are you sure?")
end
end end
describe "navigation" do describe "navigation" do
@ -296,36 +147,14 @@ defmodule MvWeb.UserLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/users") {:ok, _view, html} = live(conn, "/users")
# Check that user row contains link to show page # Row click navigates to show page (edit is on show page)
assert html =~ ~s(/users/#{user.id}) assert html =~ ~s(/users/#{user.id})
# Check edit link points to correct edit page
assert html =~ ~s(/users/#{user.id}/edit)
# Check new user button points to correct new page # Check new user button points to correct new page
assert html =~ ~s(/users/new) assert html =~ ~s(/users/new)
end end
end end
describe "translations" do
@tag :ui
test "shows translations for selection in different locales", %{conn: conn} do
conn = conn_with_oidc_user(conn)
# Test German translations
conn = Plug.Test.init_test_session(conn, locale: "de")
{:ok, _view, html_de} = live(conn, "/users")
assert html_de =~ "Alle Benutzer*innen auswählen"
assert html_de =~ "Benutzer*in auswählen"
# Test English translations
Gettext.put_locale(MvWeb.Gettext, "en")
{:ok, _view, html_en} = live(conn, "/users")
# Check that aria-label attributes exist (structure is there)
assert html_en =~ ~s(aria-label=)
end
end
describe "edge cases" do describe "edge cases" do
test "handles empty user list gracefully", %{conn: conn} do test "handles empty user list gracefully", %{conn: conn} do
# Don't create any users besides the authenticated one # Don't create any users besides the authenticated one