Implements exporting groups closes #428 #435
6 changed files with 66 additions and 22 deletions
|
|
@ -682,6 +682,18 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
|> update_selection_assigns()
|
|> update_selection_assigns()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Update sort components after rendering
|
||||||
|
socket =
|
||||||
|
if socket.assigns[:sort_needs_update] do
|
||||||
|
old_field = socket.assigns[:previous_sort_field] || socket.assigns.sort_field
|
||||||
|
socket
|
||||||
|
|> update_sort_components(old_field, socket.assigns.sort_field, socket.assigns.sort_order)
|
||||||
|
|> assign(:sort_needs_update, false)
|
||||||
|
|> assign(:previous_sort_field, nil)
|
||||||
|
else
|
||||||
|
socket
|
||||||
|
end
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -940,9 +952,10 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sort in memory if needed (custom fields, groups, group_count; computed fields are blocked)
|
# Sort in memory if needed (custom fields, groups, group_count; computed fields are blocked)
|
||||||
|
# Note: :groups is in computed_member_fields() but can be sorted in-memory, so we only block :membership_fee_status
|
||||||
members =
|
members =
|
||||||
if sort_after_load and
|
if sort_after_load and
|
||||||
socket.assigns.sort_field not in FieldVisibility.computed_member_fields() do
|
socket.assigns.sort_field != :membership_fee_status do
|
||||||
sort_members_in_memory(
|
sort_members_in_memory(
|
||||||
members,
|
members,
|
||||||
socket.assigns.sort_field,
|
socket.assigns.sort_field,
|
||||||
|
|
@ -1044,7 +1057,9 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
defp maybe_sort(query, _field, nil, _custom_fields), do: {query, false}
|
defp maybe_sort(query, _field, nil, _custom_fields), do: {query, false}
|
||||||
|
|
||||||
defp maybe_sort(query, field, order, _custom_fields) do
|
defp maybe_sort(query, field, order, _custom_fields) do
|
||||||
if computed_field?(field) do
|
# :groups is in computed_member_fields() but can be sorted in-memory
|
||||||
|
# Only :membership_fee_status should be blocked from sorting
|
||||||
|
if field == :membership_fee_status or field == "membership_fee_status" do
|
||||||
{query, false}
|
{query, false}
|
||||||
else
|
else
|
||||||
apply_sort_to_query(query, field, order)
|
apply_sort_to_query(query, field, order)
|
||||||
|
|
@ -1086,13 +1101,19 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp valid_sort_field?(field) when is_atom(field) do
|
defp valid_sort_field?(field) when is_atom(field) do
|
||||||
if field in FieldVisibility.computed_member_fields(),
|
# :groups is in computed_member_fields() but can be sorted
|
||||||
do: false,
|
# Only :membership_fee_status should be blocked
|
||||||
else: valid_sort_field_db_or_custom?(field)
|
if field == :membership_fee_status do
|
||||||
|
false
|
||||||
|
else
|
||||||
|
valid_sort_field_db_or_custom?(field)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp valid_sort_field?(field) when is_binary(field) do
|
defp valid_sort_field?(field) when is_binary(field) do
|
||||||
if field in Enum.map(FieldVisibility.computed_member_fields(), &Atom.to_string/1) do
|
# "groups" is in computed_member_fields() but can be sorted
|
||||||
|
# Only "membership_fee_status" should be blocked
|
||||||
|
if field == "membership_fee_status" do
|
||||||
false
|
false
|
||||||
else
|
else
|
||||||
valid_sort_field_db_or_custom?(field)
|
valid_sort_field_db_or_custom?(field)
|
||||||
|
|
@ -1249,10 +1270,13 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
defp maybe_update_sort(socket, %{"sort_field" => sf, "sort_order" => so}) do
|
defp maybe_update_sort(socket, %{"sort_field" => sf, "sort_order" => so}) do
|
||||||
field = determine_field(socket.assigns.sort_field, sf)
|
field = determine_field(socket.assigns.sort_field, sf)
|
||||||
order = determine_order(socket.assigns.sort_order, so)
|
order = determine_order(socket.assigns.sort_order, so)
|
||||||
|
old_field = socket.assigns.sort_field
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> assign(:sort_field, field)
|
|> assign(:sort_field, field)
|
||||||
|> assign(:sort_order, order)
|
|> assign(:sort_order, order)
|
||||||
|
|> assign(:sort_needs_update, old_field != field or socket.assigns.sort_order != order)
|
||||||
|
|> assign(:previous_sort_field, old_field)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_update_sort(socket, _), do: socket
|
defp maybe_update_sort(socket, _), do: socket
|
||||||
|
|
@ -1261,17 +1285,27 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
defp determine_field(default, nil), do: default
|
defp determine_field(default, nil), do: default
|
||||||
|
|
||||||
defp determine_field(default, sf) when is_binary(sf) do
|
defp determine_field(default, sf) when is_binary(sf) do
|
||||||
computed_strings = Enum.map(FieldVisibility.computed_member_fields(), &Atom.to_string/1)
|
# Handle "groups" specially - it's in computed_member_fields() but can be sorted
|
||||||
|
if sf == "groups" do
|
||||||
|
:groups
|
||||||
|
else
|
||||||
|
computed_strings = Enum.map(FieldVisibility.computed_member_fields(), &Atom.to_string/1)
|
||||||
|
|
||||||
if sf in computed_strings,
|
if sf in computed_strings,
|
||||||
do: default,
|
do: default,
|
||||||
else: determine_field_after_computed_check(default, sf)
|
else: determine_field_after_computed_check(default, sf)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp determine_field(default, sf) when is_atom(sf) do
|
defp determine_field(default, sf) when is_atom(sf) do
|
||||||
if sf in FieldVisibility.computed_member_fields(),
|
# Handle :groups specially - it's in computed_member_fields() but can be sorted
|
||||||
do: default,
|
if sf == :groups do
|
||||||
else: determine_field_after_computed_check(default, sf)
|
:groups
|
||||||
|
else
|
||||||
|
if sf in FieldVisibility.computed_member_fields(),
|
||||||
|
do: default,
|
||||||
|
else: determine_field_after_computed_check(default, sf)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp determine_field(default, _), do: default
|
defp determine_field(default, _), do: default
|
||||||
|
|
@ -1620,9 +1654,13 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
FieldVisibility.computed_member_fields()
|
FieldVisibility.computed_member_fields()
|
||||||
|> Enum.filter(&(&1 in member_fields_computed))
|
|> Enum.filter(&(&1 in member_fields_computed))
|
||||||
|
|
||||||
# Groups is always included in export if it's visible in the table
|
# Include groups in export only if it's visible in the table
|
||||||
# (groups column is always shown in the table, so we always include it in export)
|
member_fields_with_groups =
|
||||||
member_fields_with_groups = ordered_member_fields_db ++ ["groups"]
|
if :groups in socket.assigns[:member_fields_visible] do
|
||||||
|
ordered_member_fields_db ++ ["groups"]
|
||||||
|
else
|
||||||
|
ordered_member_fields_db
|
||||||
|
end
|
||||||
|
|
||||||
# Order custom fields like the table (same as dynamic_cols / all_custom_fields order)
|
# Order custom fields like the table (same as dynamic_cols / all_custom_fields order)
|
||||||
ordered_custom_field_ids =
|
ordered_custom_field_ids =
|
||||||
|
|
@ -1632,10 +1670,11 @@ defmodule MvWeb.MemberLive.Index do
|
||||||
|
|
||||||
%{
|
%{
|
||||||
selected_ids: socket.assigns.selected_members |> MapSet.to_list(),
|
selected_ids: socket.assigns.selected_members |> MapSet.to_list(),
|
||||||
member_fields: Enum.map(member_fields_with_groups, fn
|
member_fields:
|
||||||
f when is_atom(f) -> Atom.to_string(f)
|
Enum.map(member_fields_with_groups, fn
|
||||||
f when is_binary(f) -> f
|
f when is_atom(f) -> Atom.to_string(f)
|
||||||
end),
|
f when is_binary(f) -> f
|
||||||
|
end),
|
||||||
computed_fields: Enum.map(ordered_computed_fields, &Atom.to_string/1),
|
computed_fields: Enum.map(ordered_computed_fields, &Atom.to_string/1),
|
||||||
custom_field_ids: ordered_custom_field_ids,
|
custom_field_ids: ordered_custom_field_ids,
|
||||||
column_order:
|
column_order:
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,7 @@
|
||||||
</:col>
|
</:col>
|
||||||
<:col
|
<:col
|
||||||
:let={member}
|
:let={member}
|
||||||
|
:if={:groups in @member_fields_visible}
|
||||||
label={
|
label={
|
||||||
~H"""
|
~H"""
|
||||||
<.live_component
|
<.live_component
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
||||||
alias Mv.Membership.Helpers.VisibilityConfig
|
alias Mv.Membership.Helpers.VisibilityConfig
|
||||||
|
|
||||||
# Single UI key for "Membership Fee Status"; only this appears in the dropdown.
|
# Single UI key for "Membership Fee Status"; only this appears in the dropdown.
|
||||||
@pseudo_member_fields [:membership_fee_status]
|
# Groups is also a pseudo field (not a DB attribute, but displayed in the table).
|
||||||
|
@pseudo_member_fields [:membership_fee_status, :groups]
|
||||||
|
|
||||||
# Export/API may accept this as alias; must not appear in the UI options list.
|
# Export/API may accept this as alias; must not appear in the UI options list.
|
||||||
@export_only_alias :payment_status
|
@export_only_alias :payment_status
|
||||||
|
|
@ -201,7 +202,7 @@ defmodule MvWeb.MemberLive.Index.FieldVisibility do
|
||||||
"""
|
"""
|
||||||
@spec get_visible_member_fields_computed(%{String.t() => boolean()}) :: [atom()]
|
@spec get_visible_member_fields_computed(%{String.t() => boolean()}) :: [atom()]
|
||||||
def get_visible_member_fields_computed(field_selection) when is_map(field_selection) do
|
def get_visible_member_fields_computed(field_selection) when is_map(field_selection) do
|
||||||
computed_set = MapSet.new(@pseudo_member_fields)
|
computed_set = MapSet.new([:membership_fee_status])
|
||||||
|
|
||||||
field_selection
|
field_selection
|
||||||
|> Enum.filter(fn {field_string, visible} ->
|
|> Enum.filter(fn {field_string, visible} ->
|
||||||
|
|
|
||||||
|
|
@ -2205,6 +2205,7 @@ msgstr "Gruppe erfolgreich gespeichert."
|
||||||
#: lib/mv_web/live/group_live/index.ex
|
#: lib/mv_web/live/group_live/index.ex
|
||||||
#: lib/mv_web/live/member_live/index.html.heex
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
#: lib/mv_web/live/member_live/show.ex
|
#: lib/mv_web/live/member_live/show.ex
|
||||||
|
#: lib/mv_web/translations/member_fields.ex
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr "Gruppen"
|
msgstr "Gruppen"
|
||||||
|
|
|
||||||
|
|
@ -2206,6 +2206,7 @@ msgstr ""
|
||||||
#: lib/mv_web/live/group_live/index.ex
|
#: lib/mv_web/live/group_live/index.ex
|
||||||
#: lib/mv_web/live/member_live/index.html.heex
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
#: lib/mv_web/live/member_live/show.ex
|
#: lib/mv_web/live/member_live/show.ex
|
||||||
|
#: lib/mv_web/translations/member_fields.ex
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -2206,6 +2206,7 @@ msgstr ""
|
||||||
#: lib/mv_web/live/group_live/index.ex
|
#: lib/mv_web/live/group_live/index.ex
|
||||||
#: lib/mv_web/live/member_live/index.html.heex
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
#: lib/mv_web/live/member_live/show.ex
|
#: lib/mv_web/live/member_live/show.ex
|
||||||
|
#: lib/mv_web/translations/member_fields.ex
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue