feat(overview): rework filter builder with editable chips and native date ranges

Editable filter chips, uniformly-sized value controls, working field-picker
search, and native date-range inputs with relative presets in place of the
vendored calendar — native inputs give year-jump, manual entry and keyboard
accessibility for free.
This commit is contained in:
Simon 2026-07-10 16:27:15 +02:00
parent c0d1550401
commit 8303a39041
23 changed files with 1905 additions and 565 deletions

View file

@ -0,0 +1,91 @@
defmodule MvWeb.MemberLive.IndexChipEditTest do
@moduledoc """
§1.18 clicking an applied-filter chip body re-opens that filter's value
control pre-filled with the current value; a changed selection re-commits and
updates the chip; the × still removes the filter.
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
alias Mv.Membership.Group
setup %{conn: conn} do
actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member} =
Mv.Membership.create_member(
%{first_name: "Edit", last_name: "Member", email: "edit@example.com"},
actor: actor
)
{:ok, group} =
Group |> Ash.Changeset.for_create(:create, %{name: "Board"}) |> Ash.create(actor: actor)
{:ok, _mg} =
Mv.Membership.create_member_group(%{member_id: member.id, group_id: group.id}, actor: actor)
%{conn: conn_with_oidc_user(conn), group: group}
end
test "clicking the chip body opens the value control pre-filled with the current value", %{
conn: conn,
group: group
} do
{:ok, view, _html} = live(conn, "/members?group_#{group.id}=in")
refute has_element?(view, "[data-testid='value-control-group']")
view |> element("[data-testid='filter-chip-edit']") |> render_click()
# The group control opens with this group's "is" (in) operator pre-selected.
assert has_element?(view, "[data-testid='value-control-group']")
assert has_element?(view, "input[name='group_#{group.id}'][value='in'][checked]")
end
test "the value control opens anchored under the edited chip, not as a new pending chip", %{
conn: conn,
group: group
} do
{:ok, view, _html} = live(conn, "/members?group_#{group.id}=in")
view |> element("[data-testid='filter-chip-edit']") |> render_click()
# §1.18: the control is a descendant of the chip's own list item (anchored in
# place under that chip), and no separate pending chip is spun up at the row.
assert has_element?(
view,
"[data-testid='filter-chip-item'] [data-testid='value-control-group']"
)
refute has_element?(view, "[data-testid='pending-chip']")
refute has_element?(view, "[data-testid='pending-filter']")
end
test "changing the value from the re-opened control re-commits and updates the URL", %{
conn: conn,
group: group
} do
{:ok, view, _html} = live(conn, "/members?group_#{group.id}=in")
view |> element("[data-testid='filter-chip-edit']") |> render_click()
view
|> element("[data-testid='value-control-group']")
|> render_change(%{"group_#{group.id}" => "not_in"})
_ = render(view)
path = assert_patch(view)
assert path =~ "group_#{group.id}=not_in"
end
test "the × still removes the filter", %{conn: conn, group: group} do
{:ok, view, _html} = live(conn, "/members?group_#{group.id}=in")
view |> element("[data-testid='filter-chip-remove']") |> render_click()
path = assert_patch(view)
refute path =~ "group_#{group.id}"
refute has_element?(view, "[data-testid='filter-chip']")
end
end