diff --git a/lib/pinchflat_web/components/custom_components/table_components.ex b/lib/pinchflat_web/components/custom_components/table_components.ex index 7c661ba..17a0d72 100644 --- a/lib/pinchflat_web/components/custom_components/table_components.ex +++ b/lib/pinchflat_web/components/custom_components/table_components.ex @@ -24,6 +24,7 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do slot :col, required: true do attr :label, :string attr :class, :string + attr :sort_key, :string end def table(assigns) do @@ -31,7 +32,12 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do - @@ -53,6 +59,11 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do """ end + # attr : + # def my_table(assigns) do + + # end + @doc """ Renders simple pagination controls for a table in a liveview. 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 b6be923..7673b46 100644 --- a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex +++ b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex @@ -12,7 +12,12 @@
- {live_render(@conn, PinchflatWeb.Sources.IndexTableLive)} + {live_render(@conn, PinchflatWeb.Sources.SourceLive.IndexTableLive, + session: %{ + "initial_sort_key" => :custom_name, + "initial_sort_direction" => :asc + } + )}
diff --git a/lib/pinchflat_web/controllers/sources/source_html/index_table_live.ex b/lib/pinchflat_web/controllers/sources/source_html/index_table_live.ex deleted file mode 100644 index bd2051c..0000000 --- a/lib/pinchflat_web/controllers/sources/source_html/index_table_live.ex +++ /dev/null @@ -1,103 +0,0 @@ -defmodule PinchflatWeb.Sources.IndexTableLive do - use PinchflatWeb, :live_view - use Pinchflat.Media.MediaQuery - use Pinchflat.Sources.SourcesQuery - - alias Pinchflat.Repo - alias Pinchflat.Sources - alias Pinchflat.Sources.Source - alias Pinchflat.Media.MediaItem - - def render(assigns) do - ~H""" - <.table rows={@sources} table_class="text-white"> - <:col :let={source} label="Name"> - <.subtle_link href={~p"/sources/#{source.id}"}> - {StringUtils.truncate(source.custom_name || source.collection_name, 35)} - - - <:col :let={source} label="Pending"> - <.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}> - <.localized_number number={source.pending_count} /> - - - <:col :let={source} label="Downloaded"> - <.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}> - <.localized_number number={source.downloaded_count} /> - - - <:col :let={source} label="Retention"> - <%= 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"> - <.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}> - {source.media_profile.name} - - - <:col :let={source} label="Enabled?"> - <.input - name={"source[#{source.id}][enabled]"} - value={source.enabled} - id={"source_#{source.id}_enabled"} - phx-hook="formless-input" - data-subscribe="change" - data-event-name="toggle_enabled" - data-identifier={source.id} - type="toggle" - /> - - <:col :let={source} label="" class="flex place-content-evenly"> - <.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" /> - - - """ - end - - def mount(_params, _session, socket) do - {:ok, assign(socket, %{sources: get_sources()})} - end - - def handle_event("formless-input", %{"event" => "toggle_enabled"} = params, socket) do - source = Sources.get_source!(params["id"]) - should_enable = params["value"] == "true" - - {:ok, _} = Sources.update_source(source, %{enabled: should_enable}) - - {:noreply, assign(socket, %{sources: get_sources()})} - end - - defp get_sources do - query = - from s in Source, - as: :source, - inner_join: mp in assoc(s, :media_profile), - where: is_nil(s.marked_for_deletion_at) and is_nil(mp.marked_for_deletion_at), - preload: [media_profile: mp], - order_by: [asc: s.custom_name], - select: map(s, ^Source.__schema__(:fields)), - select_merge: %{ - downloaded_count: - subquery( - from m in MediaItem, - where: m.source_id == parent_as(:source).id, - where: ^MediaQuery.downloaded(), - select: count(m.id) - ), - pending_count: - subquery( - from m in MediaItem, - join: s in assoc(m, :source), - where: m.source_id == parent_as(:source).id, - where: ^MediaQuery.pending(), - select: count(m.id) - ) - } - - Repo.all(query) - end -end 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 new file mode 100644 index 0000000..f7a9400 --- /dev/null +++ b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex @@ -0,0 +1,100 @@ +defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do + use PinchflatWeb, :live_view + use Pinchflat.Media.MediaQuery + use Pinchflat.Sources.SourcesQuery + + import PinchflatWeb.Helpers.SortingHelpers + + alias Pinchflat.Repo + alias Pinchflat.Sources + alias Pinchflat.Sources.Source + alias Pinchflat.Media.MediaItem + + def mount(_params, session, socket) do + initial_params = %{ + sort_key: session["initial_sort_key"], + sort_direction: session["initial_sort_direction"] + } + + socket + |> assign(initial_params) + |> set_sources() + |> then(&{:ok, &1}) + end + + # def handle_event("formless-input", %{"event" => "toggle_enabled"} = params, socket) do + # source = Sources.get_source!(params["id"]) + # should_enable = params["value"] == "true" + + # {:ok, _} = Sources.update_source(source, %{enabled: should_enable}) + + # {:noreply, assign(socket, %{sources: get_sources(socket.assigns)})} + # end + + def handle_event("sort_update", %{"sort_key" => sort_key}, %{assigns: assigns} = socket) do + new_sort_key = String.to_existing_atom(sort_key) + + new_params = %{ + sort_key: new_sort_key, + sort_direction: get_sort_direction(assigns.sort_key, new_sort_key, assigns.sort_direction) + } + + socket + |> assign(new_params) + |> set_sources() + |> then(&{:noreply, &1}) + end + + defp set_sources(%{assigns: assigns} = socket) do + sources = + sources_query() + |> order_by(^[{assigns.sort_direction, sort_attr(assigns.sort_key)}]) + |> Repo.all() + + assign(socket, %{sources: sources}) + end + + defp sort_attr(:downloaded_count), do: dynamic([s, mp, dl], field(dl, :downloaded_count)) + defp sort_attr(:custom_name), do: dynamic([s], field(s, :custom_name)) + defp sort_attr(_), do: sort_attr(:custom_name) + + defp sources_query do + downloaded_subquery = + from( + m in MediaItem, + select: %{downloaded_count: count(m.id), source_id: m.source_id}, + where: ^MediaQuery.downloaded(), + group_by: m.source_id + ) + + from s in Source, + as: :source, + inner_join: mp in assoc(s, :media_profile), + left_join: d in subquery(downloaded_subquery), + on: d.source_id == s.id, + where: is_nil(s.marked_for_deletion_at) and is_nil(mp.marked_for_deletion_at), + preload: [media_profile: mp], + select: map(s, ^Source.__schema__(:fields)), + select_merge: %{ + downloaded_count: coalesce(d.downloaded_count, 0) + } + + # select_merge: %{ + # downloaded_count: + # subquery( + # from m in MediaItem, + # where: m.source_id == parent_as(:source).id, + # where: ^MediaQuery.downloaded(), + # select: count(m.id) + # ), + # pending_count: + # subquery( + # from m in MediaItem, + # join: s in assoc(m, :source), + # where: m.source_id == parent_as(:source).id, + # where: ^MediaQuery.pending(), + # select: count(m.id) + # ) + # } + end +end 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 new file mode 100644 index 0000000..2f8f134 --- /dev/null +++ b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.html.heex @@ -0,0 +1,12 @@ +<.table rows={@sources} table_class="text-white"> + <:col :let={source} label="Name" sort_key="custom_name"> + <.subtle_link href={~p"/sources/#{source.id}"}> + {source.custom_name} + + + <:col :let={source} label="Downloaded" sort_key="downloaded_count"> + <.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}> + <.localized_number number={source.downloaded_count} /> + + + diff --git a/lib/pinchflat_web/controllers/sources/source_live/index_table_live_BAK.html.heex b/lib/pinchflat_web/controllers/sources/source_live/index_table_live_BAK.html.heex new file mode 100644 index 0000000..2ea689b --- /dev/null +++ b/lib/pinchflat_web/controllers/sources/source_live/index_table_live_BAK.html.heex @@ -0,0 +1,45 @@ +<.table rows={@sources} table_class="text-white"> + <:col :let={source} label="Name"> + <.subtle_link href={~p"/sources/#{source.id}"}> + {StringUtils.truncate(source.custom_name || source.collection_name, 35)} + + + <:col :let={source} label="Pending"> + <.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}> + <.localized_number number={source.pending_count} /> + + + <:col :let={source} label="Downloaded"> + <.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}> + <.localized_number number={source.downloaded_count} /> + + + <:col :let={source} label="Retention"> + <%= 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"> + <.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}> + {source.media_profile.name} + + + <:col :let={source} label="Enabled?"> + <.input + name={"source[#{source.id}][enabled]"} + value={source.enabled} + id={"source_#{source.id}_enabled"} + phx-hook="formless-input" + data-subscribe="change" + data-event-name="toggle_enabled" + data-identifier={source.id} + type="toggle" + /> + + <:col :let={source} label="" class="flex place-content-evenly"> + <.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" /> + + diff --git a/lib/pinchflat_web/helpers/sorting_helpers.ex b/lib/pinchflat_web/helpers/sorting_helpers.ex new file mode 100644 index 0000000..6805424 --- /dev/null +++ b/lib/pinchflat_web/helpers/sorting_helpers.ex @@ -0,0 +1,10 @@ +defmodule PinchflatWeb.Helpers.SortingHelpers do + # TODO: test + def get_sort_direction(old_sort_attr, new_sort_attr, old_sort_direction) do + case {new_sort_attr, old_sort_direction} do + {^old_sort_attr, :desc} -> :asc + {^old_sort_attr, _} -> :desc + _ -> :asc + end + end +end
+ {col[:label]}