Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pages: Sorting and Pagination #96

Merged
merged 17 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/beacon/live_admin/components/admin_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -621,4 +621,23 @@ defmodule Beacon.LiveAdmin.AdminComponents do
</div>
"""
end

@doc """
Renders navigation by defined pagination.

"""
attr :current_page, :integer, required: true
attr :pages, :integer, required: true

def pagination(assigns) do
~H"""
<div class="flex flex-row justify-center space-x-6 pt-8 text-xl font-semibold">
<button phx-click="prev-page" disabled={@current_page == 1} class="px-2 font-medium disabled:text-gray-400">&#8592; prev</button>
<button :for={page <- 1..@pages} phx-click="set-page" phx-value-page={page} class={if @current_page == page, do: "text-indigo-700", else: ""}>
<%= page %>
</button>
<button phx-click="next-page" disabled={@current_page == @pages} class="px-2 font-medium disabled:text-gray-400">next &#8594;</button>
</div>
"""
end
end
9 changes: 4 additions & 5 deletions lib/beacon/live_admin/content.ex
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,13 @@ defmodule Beacon.LiveAdmin.Content do
end

def list_pages(site, opts \\ []) do
opts =
opts
|> Keyword.put_new(:query, nil)
|> Keyword.put_new(:per_page, 20)

call(site, Beacon.Content, :list_pages, [site, opts])
end

def count_pages(site) do
call(site, Beacon.Content, :count_pages, [site])
end

def change_page_variant(site, variant, attrs \\ %{}) do
call(site, Beacon.Content, :change_page_variant, [variant, attrs])
end
Expand Down
126 changes: 108 additions & 18 deletions lib/beacon/live_admin/live/page_editor_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,95 @@ defmodule Beacon.LiveAdmin.PageEditorLive.Index do

on_mount {Beacon.LiveAdmin.Hooks.Authorized, {:page_editor, :index}}

@per_page 20
@default_sort :title

@impl true
def menu_link(_, :index), do: {:root, "Pages"}

@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :pages, [])}
{:ok,
socket
|> assign(
page: 1,
pages: number_of_pages(socket.assigns.beacon_page.site),
sort: @default_sort,
query: ""
)
|> stream_configure(:pages, dom_id: &"#{Ecto.UUID.generate()}-#{&1.id}")}
end

@impl true
def handle_params(%{"query" => query}, _uri, socket) do
pages = list_pages(socket.assigns.beacon_page.site, query: query)
{:noreply, assign(socket, :pages, pages)}
end
def handle_params(params, _uri, socket) do
query = params["query"]
offset = set_offset(params["page"])
sort = set_sort(params["sort"], socket)
socket = set_page(offset, params["page"], socket)

pages =
list_pages(socket.assigns.beacon_page.site,
per_page: @per_page,
offset: offset,
query: query,
sort: sort
)

def handle_params(_params, _uri, socket) do
pages = list_pages(socket.assigns.beacon_page.site)
{:noreply, assign(socket, :pages, pages)}
{:noreply,
socket
|> assign(sort: sort, query: query)
|> stream(:pages, pages, reset: true)}
end

@impl true
def handle_event("search", %{"search" => %{"query" => query}}, socket) do
def handle_event("search", %{"search" => %{"query" => query, "sort" => sort}}, socket) do
path =
beacon_live_admin_path(
socket,
socket.assigns.beacon_page.site,
"/pages?page=#{socket.assigns.page}&sort=#{sort}#{query_param(query)}"
)

{:noreply,
socket
|> assign(sort: set_sort(sort, socket))
|> push_patch(to: path)}
end

def handle_event("set-page", %{"page" => page}, socket) do
page
|> String.to_integer()
|> set_page(socket)
end

def handle_event("prev-page", _, %{assigns: %{page: 1}} = socket) do
{:noreply, socket}
end

def handle_event("prev-page", _, socket) do
set_page(socket.assigns.page - 1, socket)
end

def handle_event("next-page", _, %{assigns: %{page: page, pages: page}} = socket) do
{:noreply, socket}
end

def handle_event("next-page", _, socket) do
set_page(socket.assigns.page + 1, socket)
end

defp set_page(page, socket) do
path =
beacon_live_admin_path(
socket,
socket.assigns.beacon_page.site,
"/pages?query=#{query}"
"/pages?page=#{page}"
)

{:noreply, push_patch(socket, to: path)}
{:noreply,
socket
|> assign(page: page)
|> push_patch(to: path)}
end

@impl true
Expand All @@ -50,15 +110,22 @@ defmodule Beacon.LiveAdmin.PageEditorLive.Index do
</.header>

<.simple_form :let={f} for={%{}} as={:search} phx-change="search">
<.input field={f[:query]} type="search" autofocus={true} placeholder="Search by path or title (showing up to 20 results)" />
<div class="flex justify-between">
<div class="basis-10/12">
<.input field={f[:query]} value={@query} type="search" autofocus={true} placeholder="Search by path or title (showing up to 20 results)" />
</div>
<div :if={@pages > 0} class="basis-1/12">
<.input type="select" field={f[:sort]} value={@sort} options={[{"Title", "title"}, {"Path", "path"}]} />
</div>
</div>
</.simple_form>

<.main_content class="h-[calc(100vh_-_210px)]">
<.table id="pages" rows={@pages} row_click={fn page -> JS.navigate(beacon_live_admin_path(@socket, @beacon_page.site, "/pages/#{page.id}")) end}>
<:col :let={page} label="Title"><%= page.title %></:col>
<:col :let={page} label="Path"><%= page.path %></:col>
<:col :let={page} label="Status"><%= display_status(page.status) %></:col>
<:action :let={page}>
<.table id="pages" rows={@streams.pages} row_click={fn {_dom_id, page} -> JS.navigate(beacon_live_admin_path(@socket, @beacon_page.site, "/pages/#{page.id}")) end}>
<:col :let={{_, page}} label="Title"><%= page.title %></:col>
<:col :let={{_, page}} label="Path"><%= page.path %></:col>
<:col :let={{_, page}} label="Status"><%= display_status(page.status) %></:col>
<:action :let={{_, page}}>
<div class="sr-only">
<.link navigate={beacon_live_admin_path(@socket, @beacon_page.site, "/pages/#{page.id}")}>Show</.link>
</div>
Expand All @@ -67,19 +134,42 @@ defmodule Beacon.LiveAdmin.PageEditorLive.Index do
</.link>
</:action>
</.table>

<.pagination :if={@pages > 0} current_page={@page} pages={@pages} />
</.main_content>
"""
end

defp list_pages(site, opts \\ []) do
defp list_pages(site, opts) do
site
|> Content.list_pages(opts)
|> Enum.map(fn page ->
Map.put(page, :status, Content.get_latest_page_event(page.site, page.id).event)
end)
end

defp number_of_pages(site) do
site
|> Content.count_pages()
|> Kernel./(@per_page)
|> ceil()
end

defp set_offset(nil), do: 0
defp set_offset(page) when is_binary(page), do: String.to_integer(page) * @per_page - @per_page
defp set_offset(page), do: page * @per_page - @per_page

defp set_page(0, _page, socket), do: socket
defp set_page(_offset, page, socket), do: assign(socket, page: String.to_integer(page))

defp set_sort(nil, socket), do: socket.assigns.sort
defp set_sort("", socket), do: socket.assigns.sort
defp set_sort(sort, _socket), do: String.to_atom(sort)

defp display_status(:unpublished), do: "Unpublished"
defp display_status(:published), do: "Published"
defp display_status(:created), do: "Draft"

defp query_param(""), do: ""
defp query_param(query), do: "&query=#{query}"
end
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
%{
"accent": {:hex, :accent, "1.1.1", "20257356446d45078b19b91608f74669b407b39af891ee3db9ee6824d1cae19d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.3", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "6d5afa50d4886e3370e04fa501468cbaa6c4b5fe926f72ccfa844ad9e259adae"},
"beacon": {:git, "https://github.com/beaconCMS/beacon.git", "4fa1eca70e84ca7157b0e5dcbb4cc60f9f10b25f", []},
"beacon": {:git, "https://github.com/beaconCMS/beacon.git", "3edd59790e8d28b9d1610203f41396d3bf434015", []},
"castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"},
"cc_precompiler": {:hex, :cc_precompiler, "0.1.7", "77de20ac77f0e53f20ca82c563520af0237c301a1ec3ab3bc598e8a96c7ee5d9", [:mix], [{:elixir_make, "~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2768b28bf3c2b4f788c995576b39b8cb5d47eb788526d93bd52206c1d8bf4b75"},
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
Expand Down
Loading