diff --git a/lib/pinchflat_web/components/custom_components/table_components.ex b/lib/pinchflat_web/components/custom_components/table_components.ex
index 1fad86e..cde3f9c 100644
--- a/lib/pinchflat_web/components/custom_components/table_components.ex
+++ b/lib/pinchflat_web/components/custom_components/table_components.ex
@@ -85,7 +85,7 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do
class={[
"flex h-8 w-8 items-center justify-center rounded",
@page_number != 1 && "cursor-pointer hover:bg-primary hover:text-white",
- @page_number == 1 && "cursor-not-allowed"
+ @page_number <= 1 && "cursor-not-allowed"
]}
phx-click={@page_number != 1 && "page_change"}
phx-value-direction="dec"
@@ -103,7 +103,7 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do
class={[
"flex h-8 w-8 items-center justify-center rounded",
@page_number != @total_pages && "cursor-pointer hover:bg-primary hover:text-white",
- @page_number == @total_pages && "cursor-not-allowed"
+ @page_number >= @total_pages && "cursor-not-allowed"
]}
phx-click={@page_number != @total_pages && "page_change"}
phx-value-direction="inc"
diff --git a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex
index 7673b46..4761552 100644
--- a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex
+++ b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex
@@ -11,13 +11,12 @@
-
- {live_render(@conn, PinchflatWeb.Sources.SourceLive.IndexTableLive,
- session: %{
- "initial_sort_key" => :custom_name,
- "initial_sort_direction" => :asc
- }
- )}
-
+ {live_render(@conn, PinchflatWeb.Sources.SourceLive.IndexTableLive,
+ session: %{
+ "initial_sort_key" => :custom_name,
+ "initial_sort_direction" => :asc,
+ "results_per_page" => 10
+ }
+ )}
diff --git a/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex
index a4068b3..aefa499 100644
--- a/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex
+++ b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex
@@ -4,6 +4,7 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
use Pinchflat.Sources.SourcesQuery
import PinchflatWeb.Helpers.SortingHelpers
+ import PinchflatWeb.Helpers.PaginationHelpers
alias Pinchflat.Repo
alias Pinchflat.Sources
@@ -11,10 +12,15 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
alias Pinchflat.Media.MediaItem
def mount(_params, session, socket) do
- initial_params = %{
- sort_key: session["initial_sort_key"],
- sort_direction: session["initial_sort_direction"]
- }
+ limit = session["results_per_page"]
+ initial_params =
+ Map.merge(
+ %{
+ sort_key: session["initial_sort_key"],
+ sort_direction: session["initial_sort_direction"]
+ },
+ get_pagination_attributes(sources_query(), 1, limit)
+ )
socket
|> assign(initial_params)
@@ -22,6 +28,15 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
|> then(&{:ok, &1})
end
+ def handle_event("page_change", %{"direction" => direction}, %{assigns: assigns} = socket) do
+ new_page = update_page_number(assigns.page, direction, assigns.total_pages)
+
+ socket
+ |> assign(get_pagination_attributes(sources_query(), new_page, assigns.limit))
+ |> set_sources()
+ |> then(&{:noreply, &1})
+ end
+
def handle_event("sort_update", %{"sort_key" => sort_key}, %{assigns: assigns} = socket) do
new_sort_key = String.to_existing_atom(sort_key)
@@ -36,15 +51,6 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
|> then(&{:noreply, &1})
end
- defp set_sources(%{assigns: assigns} = socket) do
- sources =
- sources_query()
- |> order_by(^[{assigns.sort_direction, sort_attr(assigns.sort_key)}, asc: :id])
- |> Repo.all()
-
- assign(socket, %{sources: sources})
- end
-
defp sort_attr(:pending_count), do: dynamic([s, mp, dl, pe], field(pe, :pending_count))
defp sort_attr(:downloaded_count), do: dynamic([s, mp, dl], field(dl, :downloaded_count))
defp sort_attr(:media_profile_name), do: dynamic([s, mp], field(mp, :name))
@@ -53,6 +59,17 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
defp sort_attr(:retention_period_days), do: dynamic([s], field(s, :retention_period_days))
defp sort_attr(_), do: sort_attr(:custom_name)
+ defp set_sources(%{assigns: assigns} = socket) do
+ sources =
+ sources_query()
+ |> order_by(^[{assigns.sort_direction, sort_attr(assigns.sort_key)}, asc: :id])
+ |> limit(^assigns.limit)
+ |> offset(^assigns.offset)
+ |> Repo.all()
+
+ assign(socket, %{sources: sources})
+ end
+
defp sources_query do
downloaded_subquery =
from(
diff --git a/lib/pinchflat_web/controllers/sources/source_live/index_table_live.html.heex b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.html.heex
index 7fb7a97..4d87655 100644
--- a/lib/pinchflat_web/controllers/sources/source_live/index_table_live.html.heex
+++ b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.html.heex
@@ -1,40 +1,46 @@
-<.table rows={@sources} table_class="text-white" sort_key={@sort_key} sort_direction={@sort_direction}>
- <:col :let={source} label="Name" sort_key="custom_name">
- <.subtle_link href={~p"/sources/#{source.id}"}>
- {source.custom_name}
-
-
- <:col :let={source} label="Pending" sort_key="pending_count">
- <.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}>
- <.localized_number number={source.pending_count} />
-
-
- <:col :let={source} label="Downloaded" sort_key="downloaded_count">
- <.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}>
- <.localized_number number={source.downloaded_count} />
-
-
- <:col :let={source} label="Retention" sort_key="retention_period_days">
- <%= if source.retention_period_days && source.retention_period_days > 0 do %>
- <.localized_number number={source.retention_period_days} />
- <.pluralize count={source.retention_period_days} word="day" />
- <% else %>
- ∞
- <% end %>
-
- <:col :let={source} label="Media Profile" sort_key="media_profile_name">
- <.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}>
- {source.media_profile.name}
-
-
- <:col :let={source} label="Enabled?" sort_key="enabled">
- <.live_component
- module={PinchflatWeb.Sources.SourceLive.SourceEnableToggle}
- source={source}
- id={"source_#{source.id}_enabled"}
- />
-
- <:col :let={source} label="" class="flex place-content-evenly">
- <.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" />
-
-
+
+ <.table rows={@sources} table_class="text-white" sort_key={@sort_key} sort_direction={@sort_direction}>
+ <:col :let={source} label="Name" sort_key="custom_name">
+ <.subtle_link href={~p"/sources/#{source.id}"}>
+ {source.custom_name}
+
+
+ <:col :let={source} label="Pending" sort_key="pending_count">
+ <.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}>
+ <.localized_number number={source.pending_count} />
+
+
+ <:col :let={source} label="Downloaded" sort_key="downloaded_count">
+ <.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}>
+ <.localized_number number={source.downloaded_count} />
+
+
+ <:col :let={source} label="Retention" sort_key="retention_period_days">
+ <%= if source.retention_period_days && source.retention_period_days > 0 do %>
+ <.localized_number number={source.retention_period_days} />
+ <.pluralize count={source.retention_period_days} word="day" />
+ <% else %>
+ ∞
+ <% end %>
+
+ <:col :let={source} label="Media Profile" sort_key="media_profile_name">
+ <.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}>
+ {source.media_profile.name}
+
+
+ <:col :let={source} label="Enabled?" sort_key="enabled">
+ <.live_component
+ module={PinchflatWeb.Sources.SourceLive.SourceEnableToggle}
+ source={source}
+ id={"source_#{source.id}_enabled"}
+ />
+
+ <:col :let={source} label="" class="flex place-content-evenly">
+ <.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" />
+
+
+
+
+ <.live_pagination_controls page_number={@page} total_pages={@total_pages} />
+
+
diff --git a/lib/pinchflat_web/controllers/sources/source_live/source_enable_toggle.ex b/lib/pinchflat_web/controllers/sources/source_live/source_enable_toggle.ex
index c0f4b65..e8125c2 100644
--- a/lib/pinchflat_web/controllers/sources/source_live/source_enable_toggle.ex
+++ b/lib/pinchflat_web/controllers/sources/source_live/source_enable_toggle.ex
@@ -8,11 +8,7 @@ defmodule PinchflatWeb.Sources.SourceLive.SourceEnableToggle do
~H"""
<.form :let={f} for={@form} phx-change="update" phx-target={@myself}>
- <.input
- id={"source_#{@source_id}_enabled_input"}
- field={f[:enabled]}
- type="toggle"
- />
+ <.input id={"source_#{@source_id}_enabled_input"} field={f[:enabled]} type="toggle" />
"""
diff --git a/lib/pinchflat_web/helpers/pagination_helpers.ex b/lib/pinchflat_web/helpers/pagination_helpers.ex
new file mode 100644
index 0000000..1d2e690
--- /dev/null
+++ b/lib/pinchflat_web/helpers/pagination_helpers.ex
@@ -0,0 +1,30 @@
+defmodule PinchflatWeb.Helpers.PaginationHelpers do
+ alias Pinchflat.Repo
+ alias Pinchflat.Utils.NumberUtils
+
+ # TODO: test
+ def get_pagination_attributes(query, page, records_per_page) do
+ total_record_count = Repo.aggregate(query, :count, :id)
+ total_pages = max(ceil(total_record_count / records_per_page), 1)
+ clamped_page = NumberUtils.clamp(page, 1, total_pages)
+
+ %{
+ page: clamped_page,
+ total_pages: total_pages,
+ total_record_count: total_record_count,
+ limit: records_per_page,
+ offset: (clamped_page - 1) * records_per_page
+ }
+ end
+
+ # TODO: test
+ def update_page_number(current_page, direction, total_pages) do
+ updated_page =
+ case to_string(direction) do
+ "inc" -> current_page + 1
+ "dec" -> current_page - 1
+ end
+
+ NumberUtils.clamp(updated_page, 1, total_pages)
+ end
+end