Add show route for record sets
This commit is contained in:
@@ -32,7 +32,8 @@
|
||||
"Bash(sqlite3:*)",
|
||||
"WebSearch",
|
||||
"Bash(mix shellcheck:*)",
|
||||
"Bash(mix compile:*)"
|
||||
"Bash(mix compile:*)",
|
||||
"mcp__tidewave__get_docs"
|
||||
]
|
||||
},
|
||||
"enableAllProjectMcpServers": false
|
||||
|
||||
@@ -55,7 +55,9 @@
|
||||
<div class="grow">
|
||||
<header class="sm:flex items-baseline justify-start">
|
||||
<h2 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
{record_set.name}
|
||||
<.link navigate={~p"/record-sets/#{record_set}"} class="hover:underline">
|
||||
{record_set.name}
|
||||
</.link>
|
||||
</h2>
|
||||
<span class="sm:ml-2 text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{gettext("%{collected}/%{total} records", RecordSet.count_by_status(record_set))}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
defmodule MusicLibraryWeb.RecordSetLive.Show do
|
||||
use MusicLibraryWeb, :live_view
|
||||
|
||||
import MusicLibraryWeb.RecordComponents, only: [artist_links: 1]
|
||||
|
||||
alias MusicLibrary.RecordSets
|
||||
alias MusicLibrary.RecordSets.RecordSet
|
||||
alias MusicLibraryWeb.Markdown
|
||||
alias Phoenix.LiveView.JS
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, assign(socket, :current_section, :record_sets)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_params(%{"id" => id}, _url, socket) do
|
||||
record_set = RecordSets.get_record_set!(id)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:record_set, record_set)
|
||||
|> assign(:page_title, page_title(socket.assigns.live_action, record_set))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
{MusicLibraryWeb.RecordSetLive.Form, {:updated, record_set}},
|
||||
socket
|
||||
) do
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:record_set, record_set)
|
||||
|> assign(:page_title, page_title(socket.assigns.live_action, record_set))}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{MusicLibraryWeb.RecordSetLive.RecordPicker, {:added, record_set}},
|
||||
socket
|
||||
) do
|
||||
{:noreply, assign(socket, :record_set, record_set)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete_set", _params, socket) do
|
||||
{:ok, _} = RecordSets.delete_record_set(socket.assigns.record_set)
|
||||
|
||||
{:noreply, push_navigate(socket, to: ~p"/record-sets")}
|
||||
end
|
||||
|
||||
def handle_event("remove_record", %{"record-id" => record_id}, socket) do
|
||||
{:ok, updated_set} =
|
||||
RecordSets.remove_record_from_set(socket.assigns.record_set, record_id)
|
||||
|
||||
{:noreply, assign(socket, :record_set, updated_set)}
|
||||
end
|
||||
|
||||
def handle_event("move_up", %{"record-id" => record_id}, socket) do
|
||||
{:ok, updated_set} =
|
||||
RecordSets.move_record_in_set(socket.assigns.record_set, record_id, :up)
|
||||
|
||||
{:noreply, assign(socket, :record_set, updated_set)}
|
||||
end
|
||||
|
||||
def handle_event("move_down", %{"record-id" => record_id}, socket) do
|
||||
{:ok, updated_set} =
|
||||
RecordSets.move_record_in_set(socket.assigns.record_set, record_id, :down)
|
||||
|
||||
{:noreply, assign(socket, :record_set, updated_set)}
|
||||
end
|
||||
|
||||
defp page_title(:show, record_set), do: record_set.name
|
||||
defp page_title(:edit, record_set), do: gettext("Edit") <> " · " <> record_set.name
|
||||
defp page_title(:add_record, record_set), do: gettext("Add Record") <> " · " <> record_set.name
|
||||
|
||||
defp render_description(description) do
|
||||
description
|
||||
|> Markdown.to_html()
|
||||
|> raw()
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,186 @@
|
||||
<Layouts.app flash={@flash} current_section={@current_section} socket={@socket}>
|
||||
<div class="mt-4">
|
||||
<header class="mt-4 flex items-baseline justify-between">
|
||||
<div>
|
||||
<h1 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
{@record_set.name}
|
||||
</h1>
|
||||
<span class="text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{gettext("%{collected}/%{total} records", RecordSet.count_by_status(@record_set))}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.button
|
||||
variant="solid"
|
||||
size="sm"
|
||||
patch={~p"/record-sets/#{@record_set}/show/add-record"}
|
||||
>
|
||||
<.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" />
|
||||
{gettext("Add Record")}
|
||||
</.button>
|
||||
<.dropdown id="set-actions" placement="bottom-end">
|
||||
<:toggle>
|
||||
<.button variant="ghost">
|
||||
<span class="sr-only">{gettext("Actions")}</span>
|
||||
<.icon
|
||||
name="hero-ellipsis-vertical"
|
||||
class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
|
||||
aria-hidden="true"
|
||||
data-slot="icon"
|
||||
/>
|
||||
</.button>
|
||||
</:toggle>
|
||||
<.dropdown_link
|
||||
id="set-actions-edit"
|
||||
patch={~p"/record-sets/#{@record_set}/show/edit"}
|
||||
>
|
||||
{gettext("Edit")}
|
||||
</.dropdown_link>
|
||||
<.separator />
|
||||
<.dropdown_button
|
||||
phx-click="delete_set"
|
||||
data-confirm={gettext("Are you sure?")}
|
||||
class={[
|
||||
"text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!"
|
||||
]}
|
||||
>
|
||||
{gettext("Delete")}
|
||||
</.dropdown_button>
|
||||
</.dropdown>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<article
|
||||
:if={@record_set.description}
|
||||
class="mt-4 prose dark:prose-invert prose-zinc prose-sm prose-h1:text-sm max-w-none"
|
||||
>
|
||||
{render_description(@record_set.description)}
|
||||
</article>
|
||||
|
||||
<div class="mt-6">
|
||||
<div
|
||||
:if={@record_set.items == []}
|
||||
id="no-records"
|
||||
class="p-8 text-center bg-zinc-50 dark:bg-zinc-800 rounded-lg"
|
||||
>
|
||||
<.icon name="hero-musical-note" class="h-12 w-12 text-zinc-400 mx-auto mb-4" />
|
||||
<p class="text-zinc-600 dark:text-zinc-400">
|
||||
{gettext("No records in this set yet")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:if={@record_set.items != []}
|
||||
class="grid grid-cols-2 sm:grid-cols-4 gap-4"
|
||||
id="record-set-records"
|
||||
>
|
||||
<div
|
||||
:for={item <- @record_set.items}
|
||||
id={"record-#{item.record.id}"}
|
||||
class={[
|
||||
"group relative",
|
||||
is_nil(item.record.purchased_at) &&
|
||||
"opacity-60 hover:opacity-100 transition-opacity"
|
||||
]}
|
||||
>
|
||||
<.link
|
||||
:if={item.record.purchased_at}
|
||||
navigate={~p"/collection/#{item.record}"}
|
||||
>
|
||||
<MusicLibraryWeb.RecordComponents.record_cover
|
||||
record={item.record}
|
||||
class="rounded-lg aspect-square object-cover"
|
||||
width={512}
|
||||
/>
|
||||
</.link>
|
||||
<.link
|
||||
:if={!item.record.purchased_at}
|
||||
navigate={~p"/wishlist/#{item.record}"}
|
||||
>
|
||||
<MusicLibraryWeb.RecordComponents.record_cover
|
||||
record={item.record}
|
||||
class="rounded-lg aspect-square object-cover"
|
||||
width={512}
|
||||
/>
|
||||
</.link>
|
||||
<div class="absolute top-1 right-1 rounded-full bg-zinc-100/50 hover:bg-zinc-100/75 dark:bg-zinc-700/50 dark:hover:bg-zinc-700/75 size-5">
|
||||
<.dropdown
|
||||
id={"item-actions-#{item.record.id}"}
|
||||
placement="bottom-end"
|
||||
>
|
||||
<:toggle>
|
||||
<span class="sr-only">{gettext("Actions")}</span>
|
||||
<.icon
|
||||
name="hero-ellipsis-vertical"
|
||||
class="size-5 text-zinc-800 dark:text-zinc-200 cursor-pointer"
|
||||
aria-hidden="true"
|
||||
data-slot="icon"
|
||||
/>
|
||||
</:toggle>
|
||||
<.dropdown_button
|
||||
:if={item.position > 0}
|
||||
phx-click="move_up"
|
||||
phx-value-record-id={item.record.id}
|
||||
>
|
||||
{gettext("Move left")}
|
||||
</.dropdown_button>
|
||||
<.dropdown_button
|
||||
:if={item.position < length(@record_set.items) - 1}
|
||||
phx-click="move_down"
|
||||
phx-value-record-id={item.record.id}
|
||||
>
|
||||
{gettext("Move right")}
|
||||
</.dropdown_button>
|
||||
<.separator />
|
||||
<.dropdown_button
|
||||
phx-click="remove_record"
|
||||
phx-value-record-id={item.record.id}
|
||||
data-confirm={gettext("Remove this record from the set?")}
|
||||
class={[
|
||||
"text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!"
|
||||
]}
|
||||
>
|
||||
{gettext("Remove")}
|
||||
</.dropdown_button>
|
||||
</.dropdown>
|
||||
</div>
|
||||
<h1 class="mt-1 text-xs sm:text-sm leading-6 text-zinc-700">
|
||||
<.artist_links joinphrase_class="text-xs" artists={item.record.artists} />
|
||||
</h1>
|
||||
<h2 class="flex font-semibold text-xs sm:text-sm leading-5 text-zinc-700 dark:text-zinc-300 text-wrap">
|
||||
{item.record.title}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.structured_modal
|
||||
:if={@live_action == :edit}
|
||||
id="record-set-modal"
|
||||
on_close={JS.patch(~p"/record-sets/#{@record_set}")}
|
||||
>
|
||||
<.live_component
|
||||
module={MusicLibraryWeb.RecordSetLive.Form}
|
||||
id={@record_set.id}
|
||||
title={@page_title}
|
||||
action={@live_action}
|
||||
record_set={@record_set}
|
||||
patch={~p"/record-sets/#{@record_set}"}
|
||||
/>
|
||||
</.structured_modal>
|
||||
|
||||
<.structured_modal
|
||||
:if={@live_action == :add_record}
|
||||
id="record-picker-modal"
|
||||
on_close={JS.patch(~p"/record-sets/#{@record_set}")}
|
||||
>
|
||||
<.live_component
|
||||
module={MusicLibraryWeb.RecordSetLive.RecordPicker}
|
||||
id={"record-picker-#{@record_set.id}"}
|
||||
title={@page_title}
|
||||
record_set={@record_set}
|
||||
patch={~p"/record-sets/#{@record_set}"}
|
||||
/>
|
||||
</.structured_modal>
|
||||
</Layouts.app>
|
||||
@@ -70,6 +70,10 @@ defmodule MusicLibraryWeb.Router do
|
||||
live "/record-sets/:id/edit", RecordSetLive.Index, :edit
|
||||
live "/record-sets/:id/add-record", RecordSetLive.Index, :add_record
|
||||
|
||||
live "/record-sets/:id", RecordSetLive.Show, :show
|
||||
live "/record-sets/:id/show/edit", RecordSetLive.Show, :edit
|
||||
live "/record-sets/:id/show/add-record", RecordSetLive.Show, :add_record
|
||||
|
||||
live "/scrobble-rules", ScrobbleRulesLive.Index, :index
|
||||
live "/scrobble-rules/new", ScrobbleRulesLive.Index, :new
|
||||
live "/scrobble-rules/:id/edit", ScrobbleRulesLive.Index, :edit
|
||||
|
||||
@@ -15,6 +15,7 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.html.heex
|
||||
@@ -40,6 +41,7 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.html.heex
|
||||
@@ -55,6 +57,8 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.ex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.ex
|
||||
@@ -908,6 +912,7 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.html.heex
|
||||
@@ -1699,6 +1704,8 @@ msgid "Regenerate embeddings"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.ex
|
||||
#: lib/music_library_web/live/record_set_live/show.ex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Add Record"
|
||||
msgstr ""
|
||||
@@ -1714,11 +1721,13 @@ msgid "Edit Set"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Move left"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Move right"
|
||||
msgstr ""
|
||||
@@ -1765,11 +1774,13 @@ msgid "Record set updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Remove this record from the set?"
|
||||
msgstr ""
|
||||
@@ -1800,6 +1811,7 @@ msgid "Search your records to add a record to this set."
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{collected}/%{total} records"
|
||||
msgstr ""
|
||||
@@ -1808,3 +1820,8 @@ msgstr ""
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Updated"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "No records in this set yet"
|
||||
msgstr ""
|
||||
|
||||
@@ -15,6 +15,7 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.html.heex
|
||||
@@ -40,6 +41,7 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.html.heex
|
||||
@@ -55,6 +57,8 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.ex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.ex
|
||||
@@ -908,6 +912,7 @@ msgstr ""
|
||||
#: lib/music_library_web/live/collection_live/show.html.heex
|
||||
#: lib/music_library_web/live/online_store_template_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#: lib/music_library_web/live/scrobble_rules_live/index.html.heex
|
||||
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
|
||||
#: lib/music_library_web/live/wishlist_live/show.html.heex
|
||||
@@ -1699,6 +1704,8 @@ msgid "Regenerate embeddings"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.ex
|
||||
#: lib/music_library_web/live/record_set_live/show.ex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Add Record"
|
||||
msgstr ""
|
||||
@@ -1714,11 +1721,13 @@ msgid "Edit Set"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Move left"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Move right"
|
||||
msgstr ""
|
||||
@@ -1765,11 +1774,13 @@ msgid "Record set updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "Remove this record from the set?"
|
||||
msgstr ""
|
||||
@@ -1800,6 +1811,7 @@ msgid "Search your records to add a record to this set."
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/index.html.heex
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "%{collected}/%{total} records"
|
||||
msgstr ""
|
||||
@@ -1808,3 +1820,8 @@ msgstr ""
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "Updated"
|
||||
msgstr ""
|
||||
|
||||
#: lib/music_library_web/live/record_set_live/show.html.heex
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "No records in this set yet"
|
||||
msgstr ""
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
defmodule MusicLibraryWeb.RecordSetLive.ShowTest do
|
||||
use MusicLibraryWeb.ConnCase
|
||||
|
||||
import MusicLibrary.Fixtures.RecordSets
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
alias MusicLibrary.RecordSets
|
||||
|
||||
describe "Show" do
|
||||
test "displays record set name", %{conn: conn} do
|
||||
set = record_set(%{name: "My Favorites"})
|
||||
|
||||
conn
|
||||
|> visit(~p"/record-sets/#{set}")
|
||||
|> assert_has("h1", text: "My Favorites")
|
||||
end
|
||||
|
||||
test "displays collected/total count", %{conn: conn} do
|
||||
{set, _records} = record_set_with_records(2)
|
||||
|
||||
conn
|
||||
|> visit(~p"/record-sets/#{set}")
|
||||
|> assert_has("span", text: "2/2 records")
|
||||
end
|
||||
|
||||
test "displays records in the set", %{conn: conn} do
|
||||
{set, [r1, r2]} = record_set_with_records(2)
|
||||
|
||||
conn
|
||||
|> visit(~p"/record-sets/#{set}")
|
||||
|> assert_has("h2", text: escape(r1.title))
|
||||
|> assert_has("h2", text: escape(r2.title))
|
||||
end
|
||||
|
||||
test "shows empty state when set has no records", %{conn: conn} do
|
||||
set = record_set()
|
||||
|
||||
conn
|
||||
|> visit(~p"/record-sets/#{set}")
|
||||
|> assert_has("p", text: "No records in this set yet")
|
||||
end
|
||||
|
||||
test "renders markdown description as HTML", %{conn: conn} do
|
||||
set = record_set(%{description: "This is **bold** text"})
|
||||
|
||||
conn
|
||||
|> visit(~p"/record-sets/#{set}")
|
||||
|> assert_has("article strong", text: "bold")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Remove record" do
|
||||
test "removes a record from the set", %{conn: conn} do
|
||||
{set, [r1 | _]} = record_set_with_records(2)
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/record-sets/#{set}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='remove_record'][phx-value-record-id='#{r1.id}']")
|
||||
|> render_click()
|
||||
|
||||
updated = RecordSets.get_record_set!(set.id)
|
||||
refute Enum.any?(updated.items, &(&1.record.id == r1.id))
|
||||
end
|
||||
end
|
||||
|
||||
describe "Reorder records" do
|
||||
test "moves a record right (down)", %{conn: conn} do
|
||||
{set, [r1, r2 | _]} = record_set_with_records(3)
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/record-sets/#{set}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='move_down'][phx-value-record-id='#{r1.id}']")
|
||||
|> render_click()
|
||||
|
||||
updated = RecordSets.get_record_set!(set.id)
|
||||
ids_in_order = Enum.map(updated.items, & &1.record.id)
|
||||
assert Enum.at(ids_in_order, 0) == r2.id
|
||||
assert Enum.at(ids_in_order, 1) == r1.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "Delete set" do
|
||||
test "deletes set and navigates to index", %{conn: conn} do
|
||||
set = record_set(%{name: "To Delete"})
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/record-sets/#{set}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='delete_set']")
|
||||
|> render_click()
|
||||
|
||||
assert_redirect(view, ~p"/record-sets")
|
||||
assert_raise Ecto.NoResultsError, fn -> RecordSets.get_record_set!(set.id) end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Navigation from index" do
|
||||
test "index links to show page", %{conn: conn} do
|
||||
set = record_set(%{name: "Linked Set"})
|
||||
|
||||
conn
|
||||
|> visit(~p"/record-sets")
|
||||
|> click_link("Linked Set")
|
||||
|> assert_has("h1", text: "Linked Set")
|
||||
|> assert_path(~p"/record-sets/#{set}")
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user