-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Enhancement] Add pagination for a source's media (#190)
* [WIP] added first attempt at pagination component * Hooked up pagination for downloaded media
- Loading branch information
1 parent
a4d5f45
commit aea40a3
Showing
7 changed files
with
247 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
defmodule Pinchflat.Utils.NumberUtils do | ||
@moduledoc """ | ||
Utility methods for working with numbers | ||
""" | ||
|
||
@doc """ | ||
Clamps a number between a minimum and maximum value | ||
Returns integer() | float() | ||
""" | ||
def clamp(num, minimum, maximum) do | ||
num | ||
|> max(minimum) | ||
|> min(maximum) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
defmodule Pinchflat.Sources.MediaItemTableLive do | ||
use PinchflatWeb, :live_view | ||
import Ecto.Query, warn: false | ||
|
||
alias Pinchflat.Repo | ||
alias Pinchflat.Sources | ||
alias Pinchflat.Media.MediaQuery | ||
alias Pinchflat.Utils.NumberUtils | ||
|
||
@limit 10 | ||
|
||
def render(%{records: []} = assigns) do | ||
~H""" | ||
<p class="text-black dark:text-white">Nothing Here!</p> | ||
""" | ||
end | ||
|
||
def render(assigns) do | ||
~H""" | ||
<div> | ||
<span class="mb-4 inline-block"> | ||
Showing <%= length(@records) %> of <%= @total_record_count %> | ||
</span> | ||
<.table rows={@records} table_class="text-black dark:text-white"> | ||
<:col :let={media_item} label="Title"> | ||
<.subtle_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"}> | ||
<%= StringUtils.truncate(media_item.title, 50) %> | ||
</.subtle_link> | ||
</:col> | ||
<:col :let={media_item} label="" class="flex place-content-evenly"> | ||
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"} icon="hero-eye" class="mx-1" /> | ||
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}/edit"} icon="hero-pencil-square" class="mx-1" /> | ||
</:col> | ||
</.table> | ||
<section class="flex justify-center mt-5"> | ||
<.live_pagination_controls page_number={@page} total_pages={@total_pages} /> | ||
</section> | ||
</div> | ||
""" | ||
end | ||
|
||
def mount(_params, session, socket) do | ||
page = 1 | ||
media_state = session["media_state"] | ||
source = Sources.get_source!(session["source_id"]) | ||
base_query = generate_base_query(source, media_state) | ||
pagination_attrs = fetch_pagination_attributes(base_query, page) | ||
|
||
{:ok, assign(socket, Map.merge(pagination_attrs, %{base_query: base_query, source: source}))} | ||
end | ||
|
||
def handle_event("page_change", %{"direction" => direction}, %{assigns: assigns} = socket) do | ||
direction = if direction == "inc", do: 1, else: -1 | ||
new_page = assigns.page + direction | ||
new_assigns = fetch_pagination_attributes(assigns.base_query, new_page) | ||
|
||
{:noreply, assign(socket, new_assigns)} | ||
end | ||
|
||
defp fetch_pagination_attributes(base_query, page) do | ||
total_record_count = Repo.aggregate(base_query, :count, :id) | ||
total_pages = max(ceil(total_record_count / @limit), 1) | ||
page = NumberUtils.clamp(page, 1, total_pages) | ||
records = fetch_records(base_query, page) | ||
|
||
%{page: page, total_pages: total_pages, records: records, total_record_count: total_record_count} | ||
end | ||
|
||
defp fetch_records(base_query, page) do | ||
offset = (page - 1) * @limit | ||
|
||
base_query | ||
|> limit(^@limit) | ||
|> offset(^offset) | ||
|> Repo.all() | ||
end | ||
|
||
defp generate_base_query(source, "pending") do | ||
MediaQuery.new() | ||
|> MediaQuery.for_source(source) | ||
|> MediaQuery.where_pending_download() | ||
|> order_by(desc: :id) | ||
end | ||
|
||
defp generate_base_query(source, "downloaded") do | ||
MediaQuery.new() | ||
|> MediaQuery.for_source(source) | ||
|> MediaQuery.with_media_filepath() | ||
|> order_by(desc: :id) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
defmodule Pinchflat.Utils.NumberUtilsTest do | ||
use ExUnit.Case, async: true | ||
|
||
alias Pinchflat.Utils.NumberUtils | ||
|
||
describe "clamp/3" do | ||
test "returns the minimum when the number is less than the minimum" do | ||
assert NumberUtils.clamp(1, 2, 3) == 2 | ||
end | ||
|
||
test "returns the maximum when the number is greater than the maximum" do | ||
assert NumberUtils.clamp(4, 2, 3) == 3 | ||
end | ||
|
||
test "returns the number when it is between the minimum and maximum" do | ||
assert NumberUtils.clamp(2, 1, 3) == 2 | ||
end | ||
end | ||
end |
60 changes: 60 additions & 0 deletions
60
test/pinchflat_web/controllers/sources/media_item_table_live_test.exs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
defmodule PinchflatWeb.Sources.MediaItemTableLiveTest do | ||
use PinchflatWeb.ConnCase | ||
|
||
import Phoenix.LiveViewTest | ||
import Pinchflat.MediaFixtures | ||
import Pinchflat.SourcesFixtures | ||
|
||
alias Pinchflat.Sources.MediaItemTableLive | ||
|
||
setup do | ||
source = source_fixture() | ||
|
||
{:ok, source: source} | ||
end | ||
|
||
describe "initial rendering" do | ||
test "shows message when no records", %{conn: conn, source: source} do | ||
{:ok, _view, html} = live_isolated(conn, MediaItemTableLive, session: create_session(source)) | ||
|
||
assert html =~ "Nothing Here!" | ||
refute html =~ "Showing" | ||
end | ||
|
||
test "shows records when present", %{conn: conn, source: source} do | ||
media_item = media_item_fixture(source_id: source.id, media_filepath: nil) | ||
|
||
{:ok, _view, html} = live_isolated(conn, MediaItemTableLive, session: create_session(source)) | ||
|
||
assert html =~ "Showing 1 of 1" | ||
assert html =~ "Title" | ||
assert html =~ media_item.title | ||
end | ||
end | ||
|
||
describe "media_state" do | ||
test "shows pending media when pending", %{conn: conn, source: source} do | ||
downloaded_media_item = media_item_fixture(source_id: source.id) | ||
pending_media_item = media_item_fixture(source_id: source.id, media_filepath: nil) | ||
|
||
{:ok, _view, html} = live_isolated(conn, MediaItemTableLive, session: create_session(source, "pending")) | ||
|
||
assert html =~ pending_media_item.title | ||
refute html =~ downloaded_media_item.title | ||
end | ||
|
||
test "shows downloaded media when downloaded", %{conn: conn, source: source} do | ||
downloaded_media_item = media_item_fixture(source_id: source.id) | ||
pending_media_item = media_item_fixture(source_id: source.id, media_filepath: nil) | ||
|
||
{:ok, _view, html} = live_isolated(conn, MediaItemTableLive, session: create_session(source, "downloaded")) | ||
|
||
assert html =~ downloaded_media_item.title | ||
refute html =~ pending_media_item.title | ||
end | ||
end | ||
|
||
defp create_session(source, media_state \\ "pending") do | ||
%{"source_id" => source.id, "media_state" => media_state} | ||
end | ||
end |