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
- |
+ |
{col[:label]}
|
@@ -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