Add boolean custom field filters to member overview closes #309 #362

Merged
simon merged 15 commits from feature/filter-boolean-custom-fields into main 2026-01-23 14:53:08 +01:00
2 changed files with 114 additions and 0 deletions
Showing only changes of commit 4b67039a78 - Show all commits

View file

@ -263,5 +263,38 @@ defmodule MvWeb.Components.MemberFilterComponentTest do
# (String fields should not appear in boolean filter section)
refute dropdown_html =~ "String Field"
end
test "dropdown shows scrollbar when many boolean custom fields exist", %{conn: conn} do
conn = conn_with_oidc_user(conn)
# Create 15 boolean custom fields (more than typical, should trigger scrollbar)
boolean_fields =
Enum.map(1..15, fn i ->
create_boolean_custom_field(%{name: "Field #{i}"})
end)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("#member-filter button[aria-haspopup='true']")
|> render_click()
# Extract dropdown panel HTML
dropdown_html =
view
|> element("#member-filter div[role='dialog']")
|> render()
# Should have scrollbar classes: max-h-60 overflow-y-auto pr-2
# Check for the scrollable container (the div with max-h-60 and overflow-y-auto)
assert dropdown_html =~ "max-h-60"
assert dropdown_html =~ "overflow-y-auto"
# Verify all fields are present in the dropdown
Enum.each(boolean_fields, fn field ->
assert dropdown_html =~ field.name
end)
end
end
end

View file

@ -1525,5 +1525,86 @@ defmodule MvWeb.MemberLive.IndexTest do
assert html =~ "TrueMember"
refute html =~ "FalseMember"
end
test "boolean custom field appears in filter dropdown after being added", %{conn: conn} do
conn = conn_with_oidc_user(conn)
# Start with no boolean custom fields
{:ok, view, _html} = live(conn, "/members")
state_before = :sys.get_state(view.pid)
boolean_fields_before = state_before.socket.assigns.boolean_custom_fields
assert length(boolean_fields_before) == 0
# Create a new boolean custom field
new_boolean_field = create_boolean_custom_field(%{name: "Newly Added Field"})
# Navigate again - the new field should appear
{:ok, view2, _html} = live(conn, "/members")
state_after = :sys.get_state(view2.pid)
boolean_fields_after = state_after.socket.assigns.boolean_custom_fields
# New boolean field should be present
assert length(boolean_fields_after) == 1
assert Enum.any?(boolean_fields_after, &(&1.id == new_boolean_field.id))
assert Enum.any?(boolean_fields_after, &(&1.name == "Newly Added Field"))
end
test "boolean filter performance with 150 members", %{conn: conn} do
conn = conn_with_oidc_user(conn)
boolean_field = create_boolean_custom_field()
# Create 150 members - 75 with true, 75 with false
members_with_true =
Enum.map(1..75, fn i ->
create_member_with_boolean_value(
%{
first_name: "TrueMember#{i}",
email: "truemember#{i}@example.com"
},
boolean_field,
true
)
end)
members_with_false =
Enum.map(1..75, fn i ->
create_member_with_boolean_value(
%{
first_name: "FalseMember#{i}",
email: "falsemember#{i}@example.com"
},
boolean_field,
false
)
end)
# Verify all members were created
assert length(members_with_true) == 75
assert length(members_with_false) == 75
# Test filter performance - should complete in reasonable time (< 1 second)
start_time = System.monotonic_time(:millisecond)
{:ok, _view, html} =
live(conn, "/members?bf_#{boolean_field.id}=true")
end_time = System.monotonic_time(:millisecond)
duration = end_time - start_time
# Should complete in less than 1 second (1000ms)
assert duration < 1000, "Filter took #{duration}ms, expected < 1000ms"
# Verify filtering worked correctly - should show all true members
Enum.each(1..75, fn i ->
assert html =~ "TrueMember#{i}"
end)
# Should not show false members
Enum.each(1..75, fn i ->
refute html =~ "FalseMember#{i}"
end)
end
end
end