Added search UI to source tables
This commit is contained in:
parent
43005b9a2f
commit
b167ada1c4
3 changed files with 77 additions and 18 deletions
|
|
@ -125,6 +125,15 @@ defmodule Pinchflat.Media.MediaQuery do
|
|||
)
|
||||
end
|
||||
|
||||
def matches_search_term(nil), do: dynamic([mi], true)
|
||||
|
||||
def matches_search_term(term) do
|
||||
case String.trim(term) do
|
||||
"" -> dynamic([mi], true)
|
||||
term -> dynamic([mi], fragment("media_items_search_index MATCH ?", ^term))
|
||||
end
|
||||
end
|
||||
|
||||
def require_assoc(query, identifier) do
|
||||
if has_named_binding?(query, identifier) do
|
||||
query
|
||||
|
|
@ -133,6 +142,10 @@ defmodule Pinchflat.Media.MediaQuery do
|
|||
end
|
||||
end
|
||||
|
||||
defp do_require_assoc(query, :media_items_search_index) do
|
||||
from(mi in query, join: s in assoc(mi, :media_items_search_index), as: :media_items_search_index)
|
||||
end
|
||||
|
||||
defp do_require_assoc(query, :source) do
|
||||
from(mi in query, join: s in assoc(mi, :source), as: :source)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
type="text"
|
||||
name="q"
|
||||
value={@params["q"]}
|
||||
placeholder="Type to search..."
|
||||
placeholder="Search all media..."
|
||||
class="w-full bg-transparent pl-9 pr-4 border-0 focus:ring-0 focus:outline-none"
|
||||
/>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
|
||||
@limit 10
|
||||
|
||||
def render(%{records: []} = assigns) do
|
||||
def render(%{total_record_count: 0} = assigns) do
|
||||
~H"""
|
||||
<div class="mb-4 flex items-center">
|
||||
<.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" />
|
||||
|
|
@ -17,13 +17,34 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
"""
|
||||
end
|
||||
|
||||
# TODO: make search results clickable for main search
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div>
|
||||
<span class="mb-4 flex items-center">
|
||||
<.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" tooltip="Refresh" />
|
||||
<span class="ml-2">Showing <%= length(@records) %> of <%= @total_record_count %></span>
|
||||
</span>
|
||||
<header class="flex justify-between items-center">
|
||||
<span class="mb-4 flex items-center">
|
||||
<.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" tooltip="Refresh" />
|
||||
<span class="ml-2">Showing <%= length(@records) %> of <%= @filtered_record_count %> total</span>
|
||||
</span>
|
||||
<div class="bg-meta-4 rounded-md">
|
||||
<div class="relative">
|
||||
<span class="absolute left-2 top-1/2 -translate-y-1/2 flex">
|
||||
<.icon name="hero-magnifying-glass" />
|
||||
</span>
|
||||
<form phx-change="search_term" phx-submit="search_term">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
value={@search_term}
|
||||
placeholder="Search in table..."
|
||||
class="w-full bg-transparent pl-9 pr-4 border-0 focus:ring-0 focus:outline-none"
|
||||
phx-debounce="200"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<.table rows={@records} table_class="text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<.subtle_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"}>
|
||||
|
|
@ -51,7 +72,7 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
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)
|
||||
pagination_attrs = fetch_pagination_attributes(base_query, page, "friendly")
|
||||
|
||||
new_assigns =
|
||||
Map.merge(
|
||||
|
|
@ -69,7 +90,14 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
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)
|
||||
new_assigns = fetch_pagination_attributes(assigns.base_query, new_page, assigns.search_term)
|
||||
|
||||
{:noreply, assign(socket, new_assigns)}
|
||||
end
|
||||
|
||||
def handle_event("search_term", params, socket) do
|
||||
search_term = Map.get(params, "q", nil)
|
||||
new_assigns = fetch_pagination_attributes(socket.assigns.base_query, 1, search_term)
|
||||
|
||||
{:noreply, assign(socket, new_assigns)}
|
||||
end
|
||||
|
|
@ -83,18 +111,28 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
end
|
||||
|
||||
def handle_info(%{topic: "media_table", event: "reload"}, %{assigns: assigns} = socket) do
|
||||
new_assigns = fetch_pagination_attributes(assigns.base_query, assigns.page)
|
||||
new_assigns = fetch_pagination_attributes(assigns.base_query, assigns.page, assigns.search_term)
|
||||
|
||||
{: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)
|
||||
defp fetch_pagination_attributes(base_query, page, search_term) do
|
||||
filtered_base_query = filter_base_query(base_query, search_term)
|
||||
|
||||
%{page: page, total_pages: total_pages, records: records, total_record_count: total_record_count}
|
||||
total_record_count = Repo.aggregate(base_query, :count, :id)
|
||||
filtered_record_count = Repo.aggregate(filtered_base_query, :count, :id)
|
||||
total_pages = max(ceil(filtered_record_count / @limit), 1)
|
||||
page = NumberUtils.clamp(page, 1, total_pages)
|
||||
records = fetch_records(filtered_base_query, page)
|
||||
|
||||
%{
|
||||
page: page,
|
||||
total_pages: total_pages,
|
||||
records: records,
|
||||
search_term: search_term,
|
||||
total_record_count: total_record_count,
|
||||
filtered_record_count: filtered_record_count
|
||||
}
|
||||
end
|
||||
|
||||
defp fetch_records(base_query, page) do
|
||||
|
|
@ -109,25 +147,33 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
defp generate_base_query(source, "pending") do
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:media_profile)
|
||||
|> MediaQuery.require_assoc(:media_items_search_index)
|
||||
|> where(^dynamic(^MediaQuery.for_source(source) and ^MediaQuery.pending()))
|
||||
|> order_by(desc: :id)
|
||||
|> order_by(desc: fragment("rank"), desc: :id)
|
||||
end
|
||||
|
||||
defp generate_base_query(source, "downloaded") do
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:media_items_search_index)
|
||||
|> where(^dynamic(^MediaQuery.for_source(source) and ^MediaQuery.downloaded()))
|
||||
|> order_by(desc: :id)
|
||||
|> order_by(desc: fragment("rank"), desc: :id)
|
||||
end
|
||||
|
||||
defp generate_base_query(source, "other") do
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:media_profile)
|
||||
|> MediaQuery.require_assoc(:media_items_search_index)
|
||||
|> where(
|
||||
^dynamic(
|
||||
^MediaQuery.for_source(source) and
|
||||
(not (^MediaQuery.downloaded()) and not (^MediaQuery.pending()))
|
||||
)
|
||||
)
|
||||
|> order_by(desc: :id)
|
||||
|> order_by(desc: fragment("rank"), desc: :id)
|
||||
end
|
||||
|
||||
defp filter_base_query(base_query, search_term) do
|
||||
base_query
|
||||
|> where(^MediaQuery.matches_search_term(search_term))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue