Added pagination to the sources table
This commit is contained in:
parent
e98c04727d
commit
b77f398427
6 changed files with 116 additions and 68 deletions
|
|
@ -85,7 +85,7 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do
|
||||||
class={[
|
class={[
|
||||||
"flex h-8 w-8 items-center justify-center rounded",
|
"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-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-click={@page_number != 1 && "page_change"}
|
||||||
phx-value-direction="dec"
|
phx-value-direction="dec"
|
||||||
|
|
@ -103,7 +103,7 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do
|
||||||
class={[
|
class={[
|
||||||
"flex h-8 w-8 items-center justify-center rounded",
|
"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-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-click={@page_number != @total_pages && "page_change"}
|
||||||
phx-value-direction="inc"
|
phx-value-direction="inc"
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,12 @@
|
||||||
|
|
||||||
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||||
<div class="max-w-full overflow-x-auto">
|
<div class="max-w-full overflow-x-auto">
|
||||||
<div class="flex flex-col gap-10 min-w-max">
|
{live_render(@conn, PinchflatWeb.Sources.SourceLive.IndexTableLive,
|
||||||
{live_render(@conn, PinchflatWeb.Sources.SourceLive.IndexTableLive,
|
session: %{
|
||||||
session: %{
|
"initial_sort_key" => :custom_name,
|
||||||
"initial_sort_key" => :custom_name,
|
"initial_sort_direction" => :asc,
|
||||||
"initial_sort_direction" => :asc
|
"results_per_page" => 10
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
|
||||||
use Pinchflat.Sources.SourcesQuery
|
use Pinchflat.Sources.SourcesQuery
|
||||||
|
|
||||||
import PinchflatWeb.Helpers.SortingHelpers
|
import PinchflatWeb.Helpers.SortingHelpers
|
||||||
|
import PinchflatWeb.Helpers.PaginationHelpers
|
||||||
|
|
||||||
alias Pinchflat.Repo
|
alias Pinchflat.Repo
|
||||||
alias Pinchflat.Sources
|
alias Pinchflat.Sources
|
||||||
|
|
@ -11,10 +12,15 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
|
||||||
alias Pinchflat.Media.MediaItem
|
alias Pinchflat.Media.MediaItem
|
||||||
|
|
||||||
def mount(_params, session, socket) do
|
def mount(_params, session, socket) do
|
||||||
initial_params = %{
|
limit = session["results_per_page"]
|
||||||
sort_key: session["initial_sort_key"],
|
initial_params =
|
||||||
sort_direction: session["initial_sort_direction"]
|
Map.merge(
|
||||||
}
|
%{
|
||||||
|
sort_key: session["initial_sort_key"],
|
||||||
|
sort_direction: session["initial_sort_direction"]
|
||||||
|
},
|
||||||
|
get_pagination_attributes(sources_query(), 1, limit)
|
||||||
|
)
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> assign(initial_params)
|
|> assign(initial_params)
|
||||||
|
|
@ -22,6 +28,15 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
|
||||||
|> then(&{:ok, &1})
|
|> then(&{:ok, &1})
|
||||||
end
|
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
|
def handle_event("sort_update", %{"sort_key" => sort_key}, %{assigns: assigns} = socket) do
|
||||||
new_sort_key = String.to_existing_atom(sort_key)
|
new_sort_key = String.to_existing_atom(sort_key)
|
||||||
|
|
||||||
|
|
@ -36,15 +51,6 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
|
||||||
|> then(&{:noreply, &1})
|
|> then(&{:noreply, &1})
|
||||||
end
|
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(: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(:downloaded_count), do: dynamic([s, mp, dl], field(dl, :downloaded_count))
|
||||||
defp sort_attr(:media_profile_name), do: dynamic([s, mp], field(mp, :name))
|
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(:retention_period_days), do: dynamic([s], field(s, :retention_period_days))
|
||||||
defp sort_attr(_), do: sort_attr(:custom_name)
|
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
|
defp sources_query do
|
||||||
downloaded_subquery =
|
downloaded_subquery =
|
||||||
from(
|
from(
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,46 @@
|
||||||
<.table rows={@sources} table_class="text-white" sort_key={@sort_key} sort_direction={@sort_direction}>
|
<div class="flex flex-col min-w-max">
|
||||||
<:col :let={source} label="Name" sort_key="custom_name">
|
<.table rows={@sources} table_class="text-white" sort_key={@sort_key} sort_direction={@sort_direction}>
|
||||||
<.subtle_link href={~p"/sources/#{source.id}"}>
|
<:col :let={source} label="Name" sort_key="custom_name">
|
||||||
{source.custom_name}
|
<.subtle_link href={~p"/sources/#{source.id}"}>
|
||||||
</.subtle_link>
|
{source.custom_name}
|
||||||
</:col>
|
</.subtle_link>
|
||||||
<:col :let={source} label="Pending" sort_key="pending_count">
|
</:col>
|
||||||
<.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}>
|
<:col :let={source} label="Pending" sort_key="pending_count">
|
||||||
<.localized_number number={source.pending_count} />
|
<.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}>
|
||||||
</.subtle_link>
|
<.localized_number number={source.pending_count} />
|
||||||
</:col>
|
</.subtle_link>
|
||||||
<:col :let={source} label="Downloaded" sort_key="downloaded_count">
|
</:col>
|
||||||
<.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}>
|
<:col :let={source} label="Downloaded" sort_key="downloaded_count">
|
||||||
<.localized_number number={source.downloaded_count} />
|
<.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}>
|
||||||
</.subtle_link>
|
<.localized_number number={source.downloaded_count} />
|
||||||
</:col>
|
</.subtle_link>
|
||||||
<:col :let={source} label="Retention" sort_key="retention_period_days">
|
</:col>
|
||||||
<%= if source.retention_period_days && source.retention_period_days > 0 do %>
|
<:col :let={source} label="Retention" sort_key="retention_period_days">
|
||||||
<.localized_number number={source.retention_period_days} />
|
<%= if source.retention_period_days && source.retention_period_days > 0 do %>
|
||||||
<.pluralize count={source.retention_period_days} word="day" />
|
<.localized_number number={source.retention_period_days} />
|
||||||
<% else %>
|
<.pluralize count={source.retention_period_days} word="day" />
|
||||||
<span class="text-lg">∞</span>
|
<% else %>
|
||||||
<% end %>
|
<span class="text-lg">∞</span>
|
||||||
</:col>
|
<% end %>
|
||||||
<:col :let={source} label="Media Profile" sort_key="media_profile_name">
|
</:col>
|
||||||
<.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}>
|
<:col :let={source} label="Media Profile" sort_key="media_profile_name">
|
||||||
{source.media_profile.name}
|
<.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}>
|
||||||
</.subtle_link>
|
{source.media_profile.name}
|
||||||
</:col>
|
</.subtle_link>
|
||||||
<:col :let={source} label="Enabled?" sort_key="enabled">
|
</:col>
|
||||||
<.live_component
|
<:col :let={source} label="Enabled?" sort_key="enabled">
|
||||||
module={PinchflatWeb.Sources.SourceLive.SourceEnableToggle}
|
<.live_component
|
||||||
source={source}
|
module={PinchflatWeb.Sources.SourceLive.SourceEnableToggle}
|
||||||
id={"source_#{source.id}_enabled"}
|
source={source}
|
||||||
/>
|
id={"source_#{source.id}_enabled"}
|
||||||
</:col>
|
/>
|
||||||
<:col :let={source} label="" class="flex place-content-evenly">
|
</:col>
|
||||||
<.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" />
|
<:col :let={source} label="" class="flex place-content-evenly">
|
||||||
</:col>
|
<.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" />
|
||||||
</.table>
|
</:col>
|
||||||
|
</.table>
|
||||||
|
|
||||||
|
<section class="flex justify-center my-5">
|
||||||
|
<.live_pagination_controls page_number={@page} total_pages={@total_pages} />
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,7 @@ defmodule PinchflatWeb.Sources.SourceLive.SourceEnableToggle do
|
||||||
~H"""
|
~H"""
|
||||||
<div>
|
<div>
|
||||||
<.form :let={f} for={@form} phx-change="update" phx-target={@myself}>
|
<.form :let={f} for={@form} phx-change="update" phx-target={@myself}>
|
||||||
<.input
|
<.input id={"source_#{@source_id}_enabled_input"} field={f[:enabled]} type="toggle" />
|
||||||
id={"source_#{@source_id}_enabled_input"}
|
|
||||||
field={f[:enabled]}
|
|
||||||
type="toggle"
|
|
||||||
/>
|
|
||||||
</.form>
|
</.form>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
30
lib/pinchflat_web/helpers/pagination_helpers.ex
Normal file
30
lib/pinchflat_web/helpers/pagination_helpers.ex
Normal file
|
|
@ -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
|
||||||
Loading…
Reference in a new issue