From eae275f515a42accaa756c24c4e496bb0d2178ca Mon Sep 17 00:00:00 2001 From: Dmitry Popov Date: Thu, 11 Dec 2025 01:16:24 +0100 Subject: [PATCH] fix(core): added pagination for long ACL lists --- .../live/access_lists/access_lists_live.ex | 45 ++++++++++++++++--- .../access_lists/access_lists_live.html.heex | 36 ++++++++++++--- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/lib/wanderer_app_web/live/access_lists/access_lists_live.ex b/lib/wanderer_app_web/live/access_lists/access_lists_live.ex index 12fd0ba1..6df89603 100755 --- a/lib/wanderer_app_web/live/access_lists/access_lists_live.ex +++ b/lib/wanderer_app_web/live/access_lists/access_lists_live.ex @@ -5,6 +5,8 @@ defmodule WandererAppWeb.AccessListsLive do require Ash.Query require Logger + @members_per_page 50 + @impl true def mount(_params, %{"user_id" => user_id} = _session, socket) when not is_nil(user_id) do {:ok, characters} = WandererApp.Api.Character.active_by_user(%{user_id: user_id}) @@ -25,7 +27,9 @@ defmodule WandererAppWeb.AccessListsLive do user_id: user_id, access_lists: access_lists |> Enum.map(fn acl -> map_ui_acl(acl, nil) end), characters: characters, - members: [] + members: [], + members_page: 1, + members_per_page: @members_per_page )} end @@ -39,7 +43,9 @@ defmodule WandererAppWeb.AccessListsLive do allow_acl_creation: false, access_lists: [], characters: [], - members: [] + members: [], + members_page: 1, + members_per_page: @members_per_page )} end @@ -93,10 +99,8 @@ defmodule WandererAppWeb.AccessListsLive do |> assign(:page_title, "Access Lists - Members") |> assign(:selected_acl_id, acl_id) |> assign(:access_list, access_list) - |> assign( - :members, - members - ) + |> assign(:members, members) + |> assign(:members_page, 1) else _ -> socket @@ -324,6 +328,20 @@ defmodule WandererAppWeb.AccessListsLive do {:noreply, assign(socket, form: form)} end + @impl true + def handle_event("members_prev_page", _, socket) do + new_page = max(1, socket.assigns.members_page - 1) + {:noreply, assign(socket, :members_page, new_page)} + end + + @impl true + def handle_event("members_next_page", _, socket) do + total_members = length(socket.assigns.members) + max_page = max(1, ceil(total_members / socket.assigns.members_per_page)) + new_page = min(max_page, socket.assigns.members_page + 1) + {:noreply, assign(socket, :members_page, new_page)} + end + @impl true def handle_event("noop", _, socket) do {:noreply, socket} @@ -719,6 +737,17 @@ defmodule WandererAppWeb.AccessListsLive do acl |> Map.put(:selected, acl.id == selected_id) end + defp paginated_members(members, page, per_page) do + members + |> Enum.sort_by(&{&1.role, &1.name}, &<=/2) + |> Enum.drop((page - 1) * per_page) + |> Enum.take(per_page) + end + + defp total_pages(members, per_page) do + max(1, ceil(length(members) / per_page)) + end + # Broadcast ACL update and invalidate map_characters cache for all maps using this ACL # This ensures the tracking page shows updated members even when map server isn't running defp broadcast_acl_updated(acl_id) do @@ -742,7 +771,9 @@ defmodule WandererAppWeb.AccessListsLive do end) {:error, error} -> - Logger.warning("Failed to invalidate map_characters cache for ACL #{acl_id}: #{inspect(error)}") + Logger.warning( + "Failed to invalidate map_characters cache for ACL #{acl_id}: #{inspect(error)}" + ) end end end diff --git a/lib/wanderer_app_web/live/access_lists/access_lists_live.html.heex b/lib/wanderer_app_web/live/access_lists/access_lists_live.html.heex index e3c46682..bf392e53 100644 --- a/lib/wanderer_app_web/live/access_lists/access_lists_live.html.heex +++ b/lib/wanderer_app_web/live/access_lists/access_lists_live.html.heex @@ -82,11 +82,14 @@
@members_per_page) + ]} id="acl_members" >
Enum.sort_by(&{&1.role, &1.name}, &<=/2)} + :for={member <- paginated_members(@members, @members_page, @members_per_page)} draggable="true" id={member.id} class="draggable !p-1 h-10 cursor-move bg-black bg-opacity-25 hover:text-white" @@ -113,10 +116,32 @@
+
+
@members_per_page} class="flex items-center justify-between px-3 py-2 border-t border-gray-500 bg-black bg-opacity-25"> + + Page {@members_page} of {total_pages(@members, @members_per_page)} ({length(@members)} members) + +
+ + +
+
<.link :if={@selected_acl_id != "" and can_add_members?(@access_list, @current_user)} - class="btn mt-2 w-full btn-neutral rounded-none" + class="btn w-full btn-neutral rounded-none" patch={~p"/access-lists/#{@selected_acl_id}/add-members"} > <.icon name="hero-plus-solid" class="w-6 h-6" /> @@ -129,6 +154,7 @@ <.icon name="hero-plus-solid" class="w-6 h-6" />

Add Members

+ @@ -153,10 +179,10 @@ placeholder="Select an owner" options={Enum.map(@characters, fn character -> {character.label, character.id} end)} /> - +
- +