From e418395b23b524898b03371793faa331b1cd13c5 Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Mon, 9 Feb 2026 08:53:16 +0000 Subject: [PATCH] Edit record genres --- .claude/settings.local.json | 3 +- lib/music_library/records.ex | 9 + .../components/record_form.ex | 233 +++++++++++++++++- priv/gettext/default.pot | 11 + priv/gettext/en/LC_MESSAGES/default.po | 11 + 5 files changed, 265 insertions(+), 2 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9f2bd024..0b5ec4ff 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -33,7 +33,8 @@ "WebSearch", "Bash(mix shellcheck:*)", "Bash(mix compile:*)", - "mcp__tidewave__get_docs" + "mcp__tidewave__get_docs", + "mcp__tidewave__search_package_docs" ] }, "enableAllProjectMcpServers": false diff --git a/lib/music_library/records.ex b/lib/music_library/records.ex index 22942463..93d8910c 100644 --- a/lib/music_library/records.ex +++ b/lib/music_library/records.ex @@ -159,6 +159,15 @@ defmodule MusicLibrary.Records do end) end + def list_genres do + q = + from r in fragment("records, json_each(records.genres)"), + select: fragment("DISTINCT value"), + order_by: fragment("value COLLATE NOCASE ASC") + + Repo.all(q) + end + def get_record!(id), do: Repo.get!(Record, id) def get_release_status(release_id, format) do diff --git a/lib/music_library_web/components/record_form.ex b/lib/music_library_web/components/record_form.ex index f28a09fd..45130bb8 100644 --- a/lib/music_library_web/components/record_form.ex +++ b/lib/music_library_web/components/record_form.ex @@ -60,6 +60,179 @@ defmodule MusicLibraryWeb.Components.RecordForm do label={gettext("Purchased at")} /> +
+ <.label>{gettext("Genres")} + + +
+ + {genre} + + +
+
+ +
    +
  • + {suggestion} +
  • +
  • + {gettext("Create \"%{genre}\"", genre: String.downcase(String.trim(@genre_query)))} +
  • +
+
+ +
<.label for="dominant_colors"> @@ -164,7 +337,10 @@ defmodule MusicLibraryWeb.Components.RecordForm do |> assign(assigns) |> assign_new(:form, fn -> to_form(Records.change_record(record)) - end)} + end) + |> assign_new(:all_genres, fn -> Records.list_genres() end) + |> assign_new(:genre_query, fn -> "" end) + |> assign_new(:genre_suggestions, fn -> [] end)} end @impl true @@ -192,6 +368,57 @@ defmodule MusicLibraryWeb.Components.RecordForm do {:noreply, assign(socket, form: to_form(changeset, action: :validate))} end + def handle_event("search_genres", %{"value" => query}, socket) do + current_genres = get_current_genres(socket.assigns) + query = String.trim(query) + + suggestions = + if query == "" do + [] + else + downcased_query = String.downcase(query) + + socket.assigns.all_genres + |> Enum.filter(fn g -> + String.contains?(String.downcase(g), downcased_query) and g not in current_genres + end) + |> Enum.take(10) + end + + {:noreply, + socket + |> assign(:genre_query, query) + |> assign(:genre_suggestions, suggestions)} + end + + def handle_event("add_genre", %{"genre" => genre}, socket) do + genre = genre |> String.trim() |> String.downcase() + current_genres = get_current_genres(socket.assigns) + + if genre == "" or genre in current_genres do + {:noreply, socket |> assign(:genre_query, "") |> assign(:genre_suggestions, [])} + else + new_genres = current_genres ++ [genre] + params = Map.merge(socket.assigns.form.params, %{"genres" => new_genres}) + changeset = Records.change_record(socket.assigns.record, params) + + {:noreply, + socket + |> assign(:form, to_form(changeset, action: :validate)) + |> assign(:genre_query, "") + |> assign(:genre_suggestions, [])} + end + end + + def handle_event("remove_genre", %{"genre" => genre}, socket) do + current_genres = get_current_genres(socket.assigns) + new_genres = Enum.reject(current_genres, &(&1 == genre)) + params = Map.merge(socket.assigns.form.params, %{"genres" => new_genres}) + changeset = Records.change_record(socket.assigns.record, params) + + {:noreply, assign(socket, :form, to_form(changeset, action: :validate))} + end + defp save_record(socket, record_params, uploaded_covers) do params = case uploaded_covers do @@ -236,5 +463,9 @@ defmodule MusicLibraryWeb.Components.RecordForm do end) end + defp get_current_genres(assigns) do + Ecto.Changeset.get_field(assigns.form.source, :genres) || [] + end + defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) end diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 67daf110..7484bc03 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -83,6 +83,7 @@ msgstr "" msgid "Formats" msgstr "" +#: lib/music_library_web/components/record_form.ex #: lib/music_library_web/live/collection_live/show.html.heex #: lib/music_library_web/live/wishlist_live/show.html.heex #, elixir-autogen, elixir-format @@ -1821,3 +1822,13 @@ msgstr "" #, elixir-autogen, elixir-format msgid "No records in this set yet" msgstr "" + +#: lib/music_library_web/components/record_form.ex +#, elixir-autogen, elixir-format +msgid "Create \"%{genre}\"" +msgstr "" + +#: lib/music_library_web/components/record_form.ex +#, elixir-autogen, elixir-format +msgid "Search or add genres..." +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index f9d627d8..4ca2a783 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -83,6 +83,7 @@ msgstr "" msgid "Formats" msgstr "" +#: lib/music_library_web/components/record_form.ex #: lib/music_library_web/live/collection_live/show.html.heex #: lib/music_library_web/live/wishlist_live/show.html.heex #, elixir-autogen, elixir-format @@ -1821,3 +1822,13 @@ msgstr "" #, elixir-autogen, elixir-format, fuzzy msgid "No records in this set yet" msgstr "" + +#: lib/music_library_web/components/record_form.ex +#, elixir-autogen, elixir-format +msgid "Create \"%{genre}\"" +msgstr "" + +#: lib/music_library_web/components/record_form.ex +#, elixir-autogen, elixir-format +msgid "Search or add genres..." +msgstr ""