Improves UI for media items, associated tasks
This commit is contained in:
parent
6ba9b2f28e
commit
738e61a6c0
7 changed files with 139 additions and 99 deletions
|
|
@ -7,6 +7,7 @@ defmodule Pinchflat.Sources.Source do
|
|||
import Ecto.Changeset
|
||||
import Pinchflat.Utils.ChangesetUtils
|
||||
|
||||
alias Pinchflat.Tasks.Task
|
||||
alias Pinchflat.Media.MediaItem
|
||||
alias Pinchflat.Profiles.MediaProfile
|
||||
|
||||
|
|
@ -47,6 +48,7 @@ defmodule Pinchflat.Sources.Source do
|
|||
|
||||
belongs_to :media_profile, MediaProfile
|
||||
|
||||
has_many :tasks, Task
|
||||
has_many :media_items, MediaItem, foreign_key: :source_id
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ defmodule PinchflatWeb.CustomComponents.TextComponents do
|
|||
attr :href, :string, required: true
|
||||
slot :inner_block
|
||||
|
||||
def reference_link(assigns) do
|
||||
def inline_link(assigns) do
|
||||
~H"""
|
||||
<.link href={@href} target="_blank" class="text-blue-500 hover:text-blue-300">
|
||||
<%= render_slot(@inner_block) %>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
defmodule PinchflatWeb.MediaItems.MediaItemController do
|
||||
use PinchflatWeb, :controller
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Media
|
||||
|
||||
def show(conn, %{"id" => id}) do
|
||||
media_item = Media.get_media_item!(id)
|
||||
media_item =
|
||||
id
|
||||
|> Media.get_media_item!()
|
||||
|> Repo.preload([:source, tasks: [:job]])
|
||||
|
||||
render(conn, :show, media_item: media_item)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,23 +8,51 @@
|
|||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||
<div class="rounded-sm border border-stroke bg-white py-5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10 dark:text-white">
|
||||
<h3 class="font-bold text-xl">Attributes</h3>
|
||||
<.list_items_from_map map={Map.from_struct(@media_item)} />
|
||||
</div>
|
||||
<.tabbed_layout>
|
||||
<:tab title="Attributes">
|
||||
<div class="flex flex-col gap-10 dark:text-white">
|
||||
<h3 class="font-bold text-xl">Attributes</h3>
|
||||
<section>
|
||||
<strong>Source:</strong>
|
||||
<.inline_link href={~p"/sources/#{@media_item.source_id}"}>
|
||||
<%= @media_item.source.friendly_name %>
|
||||
</.inline_link>
|
||||
</section>
|
||||
|
||||
<section class="flex justify-center my-10">
|
||||
<.link
|
||||
href={~p"/sources/#{@media_item.source_id}/media/#{@media_item}?delete_files=true"}
|
||||
method="delete"
|
||||
data-confirm="Are you sure you want to delete this record and all associated files on disk? This cannot be undone."
|
||||
>
|
||||
<.button color="bg-meta-1" rounding="rounded-full">
|
||||
Delete Files
|
||||
</.button>
|
||||
</.link>
|
||||
</section>
|
||||
<.list_items_from_map map={Map.from_struct(@media_item)} />
|
||||
</div>
|
||||
|
||||
<section class="flex justify-center my-10">
|
||||
<.link
|
||||
href={~p"/sources/#{@media_item.source_id}/media/#{@media_item}?delete_files=true"}
|
||||
method="delete"
|
||||
data-confirm="Are you sure you want to delete this record and all associated files on disk? This cannot be undone."
|
||||
>
|
||||
<.button color="bg-meta-1" rounding="rounded-full">
|
||||
Delete Files
|
||||
</.button>
|
||||
</.link>
|
||||
</section>
|
||||
</:tab>
|
||||
<:tab title="Tasks">
|
||||
<%= if match?([_|_], @media_item.tasks) do %>
|
||||
<.table rows={@media_item.tasks} table_class="text-black dark:text-white">
|
||||
<:col :let={task} label="Worker">
|
||||
<%= task.job.worker %>
|
||||
</:col>
|
||||
<:col :let={task} label="State">
|
||||
<%= task.job.state %>
|
||||
</:col>
|
||||
<:col :let={task} label="Scheduled At">
|
||||
<%= Calendar.strftime(task.job.scheduled_at, "%y-%m-%d %I:%M:%S %p %Z") %>
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
</:tab>
|
||||
</.tabbed_layout>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
</li>
|
||||
<li>
|
||||
<code class="text-sm">yt-dlp</code>-style
|
||||
<.reference_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
|
||||
<.inline_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
|
||||
<.icon name="hero-arrow-top-right-on-square" class="h-4 w-4" />
|
||||
</.reference_link>:
|
||||
</.inline_link>:
|
||||
<.inline_code>/%(channel)s/%(duration>%H-%M-%S)s-%(id)s.%(ext)s</.inline_code>
|
||||
</li>
|
||||
<li>
|
||||
|
|
@ -50,9 +50,9 @@
|
|||
<p>
|
||||
Any single-word <code class="text-sm">yt-dlp</code>
|
||||
option
|
||||
<.reference_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
|
||||
<.inline_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
|
||||
<.icon name="hero-arrow-top-right-on-square" class="h-4 w-4" />
|
||||
</.reference_link>
|
||||
</.inline_link>
|
||||
can be used with the curly braced liquid-style syntax.
|
||||
This is just a list of the most common options as well as some custom aliases
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -54,10 +54,10 @@ defmodule PinchflatWeb.Sources.SourceController do
|
|||
source =
|
||||
id
|
||||
|> Sources.get_source!()
|
||||
|> Repo.preload(:media_profile)
|
||||
|> Repo.preload([:media_profile, tasks: [:job]])
|
||||
|
||||
pending_media = Media.list_pending_media_items_for(source)
|
||||
downloaded_media = Media.list_downloaded_media_items_for(source)
|
||||
pending_media = Media.list_pending_media_items_for(source, limit: 100)
|
||||
downloaded_media = Media.list_downloaded_media_items_for(source, limit: 100)
|
||||
|
||||
render(conn, :show, source: source, pending_media: pending_media, downloaded_media: downloaded_media)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,83 +18,89 @@
|
|||
</div>
|
||||
<div class="rounded-sm border border-stroke bg-white px-5 py-5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10 dark:text-white">
|
||||
<h3 class="font-bold text-xl">Attributes for "<%= @source.friendly_name %>"</h3>
|
||||
<.tabbed_layout>
|
||||
<:tab title="Attributes">
|
||||
<div class="flex flex-col gap-10 text-white">
|
||||
<h3 class="font-bold text-lg">Attributes</h3>
|
||||
<section>
|
||||
<strong>Media Profile:</strong>
|
||||
<.inline_link href={~p"/media_profiles/#{@source.media_profile_id}"}>
|
||||
<%= @source.media_profile.name %>
|
||||
</.inline_link>
|
||||
</section>
|
||||
|
||||
<h3 class="font-bold text-lg">Relationships</h3>
|
||||
<.list>
|
||||
<:item title="media_profile">
|
||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||
</div>
|
||||
|
||||
<section class="flex flex-col md:flex-row items-center md:justify-around mt-10">
|
||||
<.link
|
||||
navigate={~p"/media_profiles/#{@source.media_profile_id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out"
|
||||
href={~p"/sources/#{@source}"}
|
||||
method="delete"
|
||||
data-confirm="Are you sure you want to delete this source (leaving files in place)? This cannot be undone."
|
||||
>
|
||||
<%= @source.media_profile.name %>
|
||||
<.button color="bg-meta-1" rounding="rounded-full">
|
||||
Delete Source
|
||||
</.button>
|
||||
</.link>
|
||||
</:item>
|
||||
</.list>
|
||||
|
||||
<h3 class="font-bold text-lg">Attributes</h3>
|
||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||
|
||||
<h3 class="font-bold text-xl">Downloaded Media</h3>
|
||||
<%= if match?([_|_], @downloaded_media) do %>
|
||||
<.table rows={@downloaded_media} table_class="text-black dark:text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<%= StringUtils.truncate(media_item.title, 50) %>
|
||||
</:col>
|
||||
<:col :let={media_item} label="" class="flex place-content-evenly">
|
||||
<.link
|
||||
navigate={~p"/sources/#{@source.id}/media/#{media_item.id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||
>
|
||||
<.icon name="hero-eye" />
|
||||
</.link>
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
|
||||
<h3 class="font-bold text-xl">Pending Media</h3>
|
||||
<%= if match?([_|_], @pending_media) do %>
|
||||
<.table rows={@pending_media} table_class="text-black dark:text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<%= StringUtils.truncate(media_item.title, 50) %>
|
||||
</:col>
|
||||
<:col :let={media_item} label="" class="flex place-content-evenly">
|
||||
<.link
|
||||
navigate={~p"/sources/#{@source.id}/media/#{media_item.id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||
>
|
||||
<.icon name="hero-eye" />
|
||||
</.link>
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<section class="flex flex-col md:flex-row items-center md:justify-around mt-10">
|
||||
<.link
|
||||
href={~p"/sources/#{@source}"}
|
||||
method="delete"
|
||||
data-confirm="Are you sure you want to delete this source (leaving files in place)? This cannot be undone."
|
||||
>
|
||||
<.button color="bg-meta-1" rounding="rounded-full">
|
||||
Delete Source
|
||||
</.button>
|
||||
</.link>
|
||||
<.link
|
||||
href={~p"/sources/#{@source}?delete_files=true"}
|
||||
method="delete"
|
||||
data-confirm="Are you sure you want to delete this source and it's files on disk? This cannot be undone."
|
||||
class="mt-5 md:mt-0"
|
||||
>
|
||||
<.button color="bg-meta-1" rounding="rounded-full">
|
||||
Delete Source and Files
|
||||
</.button>
|
||||
</.link>
|
||||
</section>
|
||||
<.link
|
||||
href={~p"/sources/#{@source}?delete_files=true"}
|
||||
method="delete"
|
||||
data-confirm="Are you sure you want to delete this source and it's files on disk? This cannot be undone."
|
||||
class="mt-5 md:mt-0"
|
||||
>
|
||||
<.button color="bg-meta-1" rounding="rounded-full">
|
||||
Delete Source and Files
|
||||
</.button>
|
||||
</.link>
|
||||
</section>
|
||||
</:tab>
|
||||
<:tab title="Pending Media">
|
||||
<%= if match?([_|_], @pending_media) do %>
|
||||
<h4 class="text-white text-lg mb-6">Shows a maximum of 100 media items</h4>
|
||||
<.table rows={@pending_media} table_class="text-black dark:text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<%= StringUtils.truncate(media_item.title, 50) %>
|
||||
</:col>
|
||||
<:col :let={media_item} label="" class="flex place-content-evenly">
|
||||
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"} icon="hero-eye" />
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
</:tab>
|
||||
<:tab title="Downloaded Media">
|
||||
<%= if match?([_|_], @downloaded_media) do %>
|
||||
<h4 class="text-white text-lg mb-6">Shows a maximum of 100 media items</h4>
|
||||
<.table rows={@downloaded_media} table_class="text-black dark:text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<%= StringUtils.truncate(media_item.title, 50) %>
|
||||
</:col>
|
||||
<:col :let={media_item} label="" class="flex place-content-evenly">
|
||||
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"} icon="hero-eye" />
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
</:tab>
|
||||
<:tab title="Tasks">
|
||||
<%= if match?([_|_], @source.tasks) do %>
|
||||
<.table rows={@source.tasks} table_class="text-black dark:text-white">
|
||||
<:col :let={task} label="Worker">
|
||||
<%= task.job.worker %>
|
||||
</:col>
|
||||
<:col :let={task} label="State">
|
||||
<%= task.job.state %>
|
||||
</:col>
|
||||
<:col :let={task} label="Scheduled At">
|
||||
<%= Calendar.strftime(task.job.scheduled_at, "%y-%m-%d %I:%M:%S %p %Z") %>
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
</:tab>
|
||||
</.tabbed_layout>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue