From 0df348ae19f791851a6ea5b01cd3987320930def Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Sun, 14 Dec 2025 09:21:13 +0300 Subject: [PATCH] Add pagination for scrobble rules --- lib/music_library/scrobble_rules.ex | 55 +++++++++++ .../live/scrobble_rules_live/index.ex | 91 +++++++++++++++++-- .../live/scrobble_rules_live/index.html.heex | 20 +++- priv/gettext/default.pot | 5 + priv/gettext/en/LC_MESSAGES/default.po | 5 + .../live/scrobble_rules_live/index_test.exs | 2 +- 6 files changed, 167 insertions(+), 11 deletions(-) diff --git a/lib/music_library/scrobble_rules.ex b/lib/music_library/scrobble_rules.ex index 7f66e9dd..86993b68 100644 --- a/lib/music_library/scrobble_rules.ex +++ b/lib/music_library/scrobble_rules.ex @@ -45,9 +45,64 @@ defmodule MusicLibrary.ScrobbleRules do where: r.enabled == ^enabled end + query = + case Keyword.get(opts, :offset) do + nil -> + query + + offset -> + from r in query, + offset: ^offset + end + + query = + case Keyword.get(opts, :limit) do + nil -> + query + + limit -> + from r in query, + limit: ^limit + end + Repo.all(query) end + @doc """ + Returns the count of scrobble_rules. + + ## Examples + + iex> count_scrobble_rules() + 42 + + """ + def count_scrobble_rules(opts \\ []) do + query = from(r in ScrobbleRule) + + query = + case Keyword.get(opts, :type) do + nil -> + query + + type -> + from r in query, + where: r.type == ^type + end + + query = + case Keyword.get(opts, :enabled) do + nil -> + query + + enabled -> + from r in query, + where: r.enabled == ^enabled + end + + Repo.aggregate(query, :count) + end + @doc """ Gets a single scrobble_rule. diff --git a/lib/music_library_web/live/scrobble_rules_live/index.ex b/lib/music_library_web/live/scrobble_rules_live/index.ex index 1ff49571..cb556149 100644 --- a/lib/music_library_web/live/scrobble_rules_live/index.ex +++ b/lib/music_library_web/live/scrobble_rules_live/index.ex @@ -1,9 +1,18 @@ defmodule MusicLibraryWeb.ScrobbleRulesLive.Index do use MusicLibraryWeb, :live_view + import MusicLibraryWeb.Components.Pagination + alias MusicLibrary.ScrobbleRules alias MusicLibrary.ScrobbleRules.ScrobbleRule + @default_list_params %{ + page: 1, + page_size: 20, + query: "", + order: :inserted_at + } + @impl true def mount(_params, _session, socket) do {:ok, assign(socket, :current_section, :scrobble_rules)} @@ -28,11 +37,14 @@ defmodule MusicLibraryWeb.ScrobbleRulesLive.Index do |> assign(:scrobble_rule, %ScrobbleRule{}) end - defp apply_action(socket, :index, _params) do - socket - |> assign(:page_title, gettext("Scrobble Rules")) - |> assign(:scrobble_rule, nil) - |> stream(:scrobble_rules, ScrobbleRules.list_scrobble_rules(), reset: true) + defp apply_action(socket, :index, params) do + total_rules = ScrobbleRules.count_scrobble_rules() + + list_params = + @default_list_params + |> merge_pagination(params, total_rules) + + load_and_assign_rules(socket, list_params) end def apply_fallback_index(socket, params) do @@ -44,12 +56,74 @@ defmodule MusicLibraryWeb.ScrobbleRulesLive.Index do end end + defp merge_pagination(params, url_params, total_records) do + page = parse_page(url_params["page"]) + page_size = parse_page_size(url_params["page_size"]) + + params + |> Map.put(:page, page) + |> Map.put(:page_size, page_size) + |> Map.put(:total_records, total_records) + end + + defp parse_page(nil), do: 1 + + defp parse_page(page) when is_binary(page) do + case Integer.parse(page) do + {num, ""} when num > 0 -> num + _ -> 1 + end + end + + defp parse_page(_), do: 1 + + defp parse_page_size(nil), do: 20 + + defp parse_page_size(page_size) when is_binary(page_size) do + case Integer.parse(page_size) do + {num, ""} when num in [20, 50, 100] -> num + _ -> 20 + end + end + + defp parse_page_size(_), do: 20 + + defp load_and_assign_rules(socket, list_params) do + offset = page_to_offset(list_params.page, list_params.page_size) + + rules = + ScrobbleRules.list_scrobble_rules( + offset: offset, + limit: list_params.page_size + ) + + list_params_with_total = + Map.put(list_params, :total_entries, list_params.total_records) + + socket + |> assign(:list_params, list_params_with_total) + |> assign(:page_title, gettext("Scrobble Rules")) + |> assign(:scrobble_rule, nil) + |> stream(:scrobble_rules, rules, reset: true) + end + + def back_path(list_params) do + qs = + list_params + |> Map.take([:page, :page_size]) + + ~p"/scrobble-rules?#{qs}" + end + @impl true def handle_info( {MusicLibraryWeb.ScrobbleRulesLive.Form, {:created, scrobble_rule}}, socket ) do - {:noreply, stream_insert(socket, :scrobble_rules, scrobble_rule, at: 0)} + {:noreply, + socket + |> stream_insert(:scrobble_rules, scrobble_rule, at: 0) + |> load_and_assign_rules(socket.assigns.list_params)} end def handle_info( @@ -64,7 +138,10 @@ defmodule MusicLibraryWeb.ScrobbleRulesLive.Index do scrobble_rule = ScrobbleRules.get_scrobble_rule!(id) {:ok, _} = ScrobbleRules.delete_scrobble_rule(scrobble_rule) - {:noreply, stream_delete(socket, :scrobble_rules, scrobble_rule)} + {:noreply, + socket + |> stream_delete(:scrobble_rules, scrobble_rule) + |> load_and_assign_rules(socket.assigns.list_params)} end @impl true diff --git a/lib/music_library_web/live/scrobble_rules_live/index.html.heex b/lib/music_library_web/live/scrobble_rules_live/index.html.heex index 35d51728..824721b7 100644 --- a/lib/music_library_web/live/scrobble_rules_live/index.html.heex +++ b/lib/music_library_web/live/scrobble_rules_live/index.html.heex @@ -31,6 +31,16 @@
+ + <.pagination id={:bottom_pagination} pagination_params={@list_params} /> <.structured_modal :if={@live_action in [:new, :edit]} id="scrobble_rule-modal" - on_close={JS.patch(~p"/scrobble-rules")} + on_close={JS.patch(back_path(@list_params))} > <.live_component module={MusicLibraryWeb.ScrobbleRulesLive.Form} @@ -111,7 +125,7 @@ title={@page_title} action={@live_action} scrobble_rule={@scrobble_rule} - patch={~p"/scrobble-rules"} + patch={back_path(@list_params)} /> diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index b7296e41..c5a9bdd0 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -1667,3 +1667,8 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Artist MusicBrainz ID" msgstr "" + +#: lib/music_library_web/live/scrobble_rules_live/index.html.heex +#, elixir-autogen, elixir-format +msgid "No scrobble rules found" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 3c088f03..4ddd048c 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -1667,3 +1667,8 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Artist MusicBrainz ID" msgstr "" + +#: lib/music_library_web/live/scrobble_rules_live/index.html.heex +#, elixir-autogen, elixir-format, fuzzy +msgid "No scrobble rules found" +msgstr "" diff --git a/test/music_library_web/live/scrobble_rules_live/index_test.exs b/test/music_library_web/live/scrobble_rules_live/index_test.exs index e4f7a270..7a7a1951 100644 --- a/test/music_library_web/live/scrobble_rules_live/index_test.exs +++ b/test/music_library_web/live/scrobble_rules_live/index_test.exs @@ -66,7 +66,7 @@ defmodule MusicLibraryWeb.ScrobbleRulesLiveTest do |> render_click() =~ "Edit Scrobble Rule" - assert_patch(index_live, ~p"/scrobble-rules/#{scrobble_rule}/edit") + assert_patch(index_live, ~p"/scrobble-rules/#{scrobble_rule}/edit?page=1&page_size=20") assert index_live |> form("#scrobble_rule-form", scrobble_rule: @invalid_attrs)