[Enhancement] Improve flow for adding many sources at once (#306)
* Added mechamism for using existing sources as a reference for adding new sources * Added test
This commit is contained in:
parent
7f1daf90ca
commit
8f91c4e6a2
7 changed files with 53 additions and 9 deletions
|
|
@ -41,13 +41,30 @@ defmodule PinchflatWeb.Sources.SourceController do
|
||||||
render(conn, :index, sources: Repo.all(source_query))
|
render(conn, :index, sources: Repo.all(source_query))
|
||||||
end
|
end
|
||||||
|
|
||||||
def new(conn, _params) do
|
def new(conn, params) do
|
||||||
changeset = Sources.change_source(%Source{})
|
# This lets me preload the settings from another source for more efficient creation
|
||||||
|
cs_struct =
|
||||||
|
case to_string(params["template_id"]) do
|
||||||
|
"" -> %Source{}
|
||||||
|
template_id -> Repo.get(Source, template_id) || %Source{}
|
||||||
|
end
|
||||||
|
|
||||||
render(conn, :new,
|
render(conn, :new,
|
||||||
changeset: changeset,
|
|
||||||
media_profiles: media_profiles(),
|
media_profiles: media_profiles(),
|
||||||
layout: get_onboarding_layout()
|
layout: get_onboarding_layout(),
|
||||||
|
# Most of these don't actually _need_ to be nullified at this point,
|
||||||
|
# but if I don't do it now I know it'll bite me
|
||||||
|
changeset:
|
||||||
|
Sources.change_source(%Source{
|
||||||
|
cs_struct
|
||||||
|
| id: nil,
|
||||||
|
uuid: nil,
|
||||||
|
custom_name: nil,
|
||||||
|
collection_name: nil,
|
||||||
|
collection_id: nil,
|
||||||
|
collection_type: nil,
|
||||||
|
original_url: nil
|
||||||
|
})
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ defmodule PinchflatWeb.Sources.SourceHTML do
|
||||||
attr :changeset, Ecto.Changeset, required: true
|
attr :changeset, Ecto.Changeset, required: true
|
||||||
attr :action, :string, required: true
|
attr :action, :string, required: true
|
||||||
attr :media_profiles, :list, required: true
|
attr :media_profiles, :list, required: true
|
||||||
|
attr :method, :string, required: true
|
||||||
|
|
||||||
def source_form(assigns)
|
def source_form(assigns)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,11 @@
|
||||||
<span x-show="copied" x-transition.duration.150ms><.icon name="hero-check" class="ml-2 h-4 w-4" /></span>
|
<span x-show="copied" x-transition.duration.150ms><.icon name="hero-check" class="ml-2 h-4 w-4" /></span>
|
||||||
</span>
|
</span>
|
||||||
</:option>
|
</:option>
|
||||||
|
<:option>
|
||||||
|
<.link href={~p"/sources/new?template_id=#{@source}"} method="get">
|
||||||
|
Use as Template
|
||||||
|
</.link>
|
||||||
|
</:option>
|
||||||
<:option>
|
<:option>
|
||||||
<div class="h-px w-full bg-bodydark2"></div>
|
<div class="h-px w-full bg-bodydark2"></div>
|
||||||
</:option>
|
</:option>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,12 @@
|
||||||
<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 px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
<div class="max-w-full">
|
<div class="max-w-full">
|
||||||
<div class="flex flex-col gap-10">
|
<div class="flex flex-col gap-10">
|
||||||
<.source_form changeset={@changeset} media_profiles={@media_profiles} action={~p"/sources/#{@source}"} />
|
<.source_form
|
||||||
|
changeset={@changeset}
|
||||||
|
media_profiles={@media_profiles}
|
||||||
|
action={~p"/sources/#{@source}"}
|
||||||
|
method="patch"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<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 px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
<div class="max-w-full">
|
<div class="max-w-full">
|
||||||
<div class="flex flex-col gap-10">
|
<div class="flex flex-col gap-10">
|
||||||
<.source_form changeset={@changeset} media_profiles={@media_profiles} action={~p"/sources"} />
|
<.source_form changeset={@changeset} media_profiles={@media_profiles} action={~p"/sources"} method="post" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
:let={f}
|
:let={f}
|
||||||
for={@changeset}
|
for={@changeset}
|
||||||
action={@action}
|
action={@action}
|
||||||
|
method={@method}
|
||||||
x-data="{ advancedMode: !!JSON.parse(localStorage.getItem('advancedMode')) }"
|
x-data="{ advancedMode: !!JSON.parse(localStorage.getItem('advancedMode')) }"
|
||||||
x-init="$watch('advancedMode', value => localStorage.setItem('advancedMode', JSON.stringify(value)))"
|
x-init="$watch('advancedMode', value => localStorage.setItem('advancedMode', JSON.stringify(value)))"
|
||||||
>
|
>
|
||||||
|
|
@ -10,7 +11,7 @@
|
||||||
</.error>
|
</.error>
|
||||||
|
|
||||||
<section x-data="{ mediaProfileId: null }">
|
<section x-data="{ mediaProfileId: null }">
|
||||||
<section class="flex justify-between items-center mt-8">
|
<section class="flex justify-between items-center mt-4">
|
||||||
<h3 class=" text-2xl text-black dark:text-white">
|
<h3 class=" text-2xl text-black dark:text-white">
|
||||||
General Options
|
General Options
|
||||||
</h3>
|
</h3>
|
||||||
|
|
@ -19,6 +20,14 @@
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<.input
|
||||||
|
field={f[:original_url]}
|
||||||
|
type="text"
|
||||||
|
label="Source URL"
|
||||||
|
help="URL of a channel or playlist (required)"
|
||||||
|
x-init="$el.focus()"
|
||||||
|
/>
|
||||||
|
|
||||||
<.input
|
<.input
|
||||||
field={f[:custom_name]}
|
field={f[:custom_name]}
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -26,8 +35,6 @@
|
||||||
help="Does not impact indexing or downloading. Will be inferred from the source if left blank"
|
help="Does not impact indexing or downloading. Will be inferred from the source if left blank"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<.input field={f[:original_url]} type="text" label="Source URL" help="URL of a channel or playlist (required)" />
|
|
||||||
|
|
||||||
<.input
|
<.input
|
||||||
field={f[:media_profile_id]}
|
field={f[:media_profile_id]}
|
||||||
options={Enum.map(@media_profiles, &{&1.name, &1.id})}
|
options={Enum.map(@media_profiles, &{&1.name, &1.id})}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,15 @@ defmodule PinchflatWeb.SourceControllerTest do
|
||||||
|
|
||||||
refute html_response(conn, 200) =~ "MENU"
|
refute html_response(conn, 200) =~ "MENU"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "preloads some attributes when using a template", %{conn: conn} do
|
||||||
|
source = source_fixture(custom_name: "My first source", download_cutoff_date: "2021-01-01")
|
||||||
|
|
||||||
|
conn = get(conn, ~p"/sources/new", %{"template_id" => source.id})
|
||||||
|
assert html_response(conn, 200) =~ "New Source"
|
||||||
|
assert html_response(conn, 200) =~ "2021-01-01"
|
||||||
|
refute html_response(conn, 200) =~ source.custom_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "create source" do
|
describe "create source" do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue