[Enhancement] Adds ability to enable/disable sources (#481)
* [Unrelated] updated module name for existing liveview module * Updated toggle component and moved MP index table to a liveview * [WIP] reverted MP index table; added source count to MP index * Moved new live table to sources index * Added 'enabled' boolean to sources * Got 'enabled' logic working re: downloading pending media * Updated sources context to do the right thing when a source is updated * Docs and tests * Updated slow indexing to maintain its old schedule if re-enabled * Hooked up the enabled toggle to the sources page * [Unrelated] added direct links to various tabs on the sources table * More tests * Removed unneeded guard in * Removed outdated comment
This commit is contained in:
@@ -1,20 +1,31 @@
|
||||
defmodule PinchflatWeb.MediaProfiles.MediaProfileController do
|
||||
use PinchflatWeb, :controller
|
||||
use Pinchflat.Sources.SourcesQuery
|
||||
use Pinchflat.Profiles.ProfilesQuery
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Profiles
|
||||
alias Pinchflat.Sources.Source
|
||||
alias Pinchflat.Profiles.MediaProfile
|
||||
alias Pinchflat.Profiles.MediaProfileDeletionWorker
|
||||
|
||||
def index(conn, _params) do
|
||||
media_profiles =
|
||||
MediaProfile
|
||||
|> where([mp], is_nil(mp.marked_for_deletion_at))
|
||||
|> order_by(asc: :name)
|
||||
|> Repo.all()
|
||||
media_profiles_query =
|
||||
from mp in MediaProfile,
|
||||
as: :media_profile,
|
||||
where: is_nil(mp.marked_for_deletion_at),
|
||||
order_by: [asc: mp.name],
|
||||
select: map(mp, ^MediaProfile.__schema__(:fields)),
|
||||
select_merge: %{
|
||||
source_count:
|
||||
subquery(
|
||||
from s in Source,
|
||||
where: s.media_profile_id == parent_as(:media_profile).id,
|
||||
select: count(s.id)
|
||||
)
|
||||
}
|
||||
|
||||
render(conn, :index, media_profiles: media_profiles)
|
||||
render(conn, :index, media_profiles: Repo.all(media_profiles_query))
|
||||
end
|
||||
|
||||
def new(conn, params) do
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
</.link>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<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="flex flex-col gap-10 min-w-max">
|
||||
@@ -23,6 +22,11 @@
|
||||
<:col :let={media_profile} label="Preferred Resolution">
|
||||
<%= media_profile.preferred_resolution %>
|
||||
</:col>
|
||||
<:col :let={media_profile} label="Sources">
|
||||
<.subtle_link href={~p"/media_profiles/#{media_profile.id}/#tab-sources"}>
|
||||
<.localized_number number={media_profile.source_count} />
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<:col :let={media_profile} label="" class="flex justify-end">
|
||||
<.icon_link href={~p"/media_profiles/#{media_profile.id}/edit"} icon="hero-pencil-square" class="mr-4" />
|
||||
</:col>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
defmodule PinchflatWeb.Sources.SourceController do
|
||||
use PinchflatWeb, :controller
|
||||
use Pinchflat.Media.MediaQuery
|
||||
use Pinchflat.Sources.SourcesQuery
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Tasks
|
||||
alias Pinchflat.Sources
|
||||
alias Pinchflat.Sources.Source
|
||||
alias Pinchflat.Media.MediaItem
|
||||
alias Pinchflat.Profiles.MediaProfile
|
||||
alias Pinchflat.Media.FileSyncingWorker
|
||||
alias Pinchflat.Sources.SourceDeletionWorker
|
||||
@@ -15,33 +14,7 @@ defmodule PinchflatWeb.Sources.SourceController do
|
||||
alias Pinchflat.Metadata.SourceMetadataStorageWorker
|
||||
|
||||
def index(conn, _params) do
|
||||
source_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)
|
||||
)
|
||||
}
|
||||
|
||||
render(conn, :index, sources: Repo.all(source_query))
|
||||
render(conn, :index)
|
||||
end
|
||||
|
||||
def new(conn, params) do
|
||||
|
||||
@@ -12,32 +12,7 @@
|
||||
<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="flex flex-col gap-10 min-w-max">
|
||||
<.table rows={@sources} table_class="text-black dark:text-white">
|
||||
<:col :let={source} label="Name">
|
||||
<.subtle_link href={~p"/sources/#{source.id}"}>
|
||||
<%= StringUtils.truncate(source.custom_name || source.collection_name, 35) %>
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<:col :let={source} label="Type"><%= source.collection_type %></:col>
|
||||
<:col :let={source} label="Pending"><.localized_number number={source.pending_count} /></:col>
|
||||
<:col :let={source} label="Downloaded"><.localized_number number={source.downloaded_count} /></:col>
|
||||
<: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 %>
|
||||
<span class="text-lg">∞</span>
|
||||
<% end %>
|
||||
</:col>
|
||||
<:col :let={source} label="Media Profile">
|
||||
<.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}>
|
||||
<%= source.media_profile.name %>
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<:col :let={source} label="" class="flex place-content-evenly">
|
||||
<.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" />
|
||||
</:col>
|
||||
</.table>
|
||||
<%= live_render(@conn, PinchflatWeb.Sources.IndexTableLive) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
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) %>
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<:col :let={source} label="Pending">
|
||||
<.subtle_link href={~p"/sources/#{source.id}/#tab-pending"}>
|
||||
<.localized_number number={source.pending_count} />
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<:col :let={source} label="Downloaded">
|
||||
<.subtle_link href={~p"/sources/#{source.id}/#tab-downloaded"}>
|
||||
<.localized_number number={source.downloaded_count} />
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<: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 %>
|
||||
<span class="text-lg">∞</span>
|
||||
<% end %>
|
||||
</:col>
|
||||
<:col :let={source} label="Media Profile">
|
||||
<.subtle_link href={~p"/media_profiles/#{source.media_profile_id}"}>
|
||||
<%= source.media_profile.name %>
|
||||
</.subtle_link>
|
||||
</:col>
|
||||
<: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>
|
||||
<:col :let={source} label="" class="flex place-content-evenly">
|
||||
<.icon_link href={~p"/sources/#{source.id}/edit"} icon="hero-pencil-square" class="mx-1" />
|
||||
</:col>
|
||||
</.table>
|
||||
"""
|
||||
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
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule Pinchflat.Sources.MediaItemTableLive do
|
||||
defmodule PinchflatWeb.Sources.MediaItemTableLive do
|
||||
use PinchflatWeb, :live_view
|
||||
use Pinchflat.Media.MediaQuery
|
||||
|
||||
|
||||
@@ -39,21 +39,21 @@
|
||||
<:tab title="Pending" id="pending">
|
||||
<%= live_render(
|
||||
@conn,
|
||||
Pinchflat.Sources.MediaItemTableLive,
|
||||
PinchflatWeb.Sources.MediaItemTableLive,
|
||||
session: %{"source_id" => @source.id, "media_state" => "pending"}
|
||||
) %>
|
||||
</:tab>
|
||||
<:tab title="Downloaded" id="downloaded">
|
||||
<%= live_render(
|
||||
@conn,
|
||||
Pinchflat.Sources.MediaItemTableLive,
|
||||
PinchflatWeb.Sources.MediaItemTableLive,
|
||||
session: %{"source_id" => @source.id, "media_state" => "downloaded"}
|
||||
) %>
|
||||
</:tab>
|
||||
<:tab title="Other" id="other">
|
||||
<%= live_render(
|
||||
@conn,
|
||||
Pinchflat.Sources.MediaItemTableLive,
|
||||
PinchflatWeb.Sources.MediaItemTableLive,
|
||||
session: %{"source_id" => @source.id, "media_state" => "other"}
|
||||
) %>
|
||||
</:tab>
|
||||
|
||||
Reference in New Issue
Block a user