feat(plex): forbid duplicate collection names + a "New collection" button

Two follow-ups after testing the collection editing against real Plex, which revealed that
Plex CONFLATES same-named collections (two rating_keys resolve to one merged member list) —
a genuine footgun.

- Duplicate-name guard: create and rename now reject (409) a title that already exists in the
  target section (case-insensitive), before any Plex write. create() can also derive the
  library from the seed item, so the caller needn't know the section key. The create dialogs
  surface the 409, and the New-collection panel warns inline before submit.
- A "New collection" button on the Collections browse surface (admin only) opens a panel:
  a name field (with the live duplicate check) + a search to pick the FIRST title — Plex can't
  create an empty collection, it needs a seed. Creating opens the new collection's detail page
  straight away, so you can keep adding titles there. This is the B-route the user wanted,
  vs. the only prior path (a movie's "add to collection").

Verified live: the 409 guard (creating an existing name is blocked, no Plex write), and the
full New-collection flow (name + first title → create → lands on the detail page); test
collections created and deleted, real account left clean.

Gate: tsc/lint/knip/prettier clean, 424 vitest; backend ruff clean, 7 collections tests
(+ a duplicate-name-rejection assertion).
This commit is contained in:
2026-08-23 05:51:48 +02:00
parent 5d99a5f253
commit b71b33654a
6 changed files with 220 additions and 21 deletions
+6 -1
View File
@@ -20,7 +20,12 @@
"add": "Add",
"added": "Added",
"deleteConfirm": "Delete the collection \"{{title}}\"? This removes it from Plex too.",
"editFailed": "Collection edit failed"
"editFailed": "Collection edit failed",
"newCollection": "New collection",
"namePlaceholder": "Collection name",
"nameTaken": "A collection with this name already exists.",
"newHint": "Pick the first title to add — a collection needs at least one.",
"createWith": "Create"
},
"searchPlaceholder": "Search Plex…",
"searchField": {
+6 -1
View File
@@ -20,7 +20,12 @@
"add": "Hozzáad",
"added": "Hozzáadva",
"deleteConfirm": "Törlöd a(z) „{{title}}” kollekciót? Ez a Plexből is eltávolítja.",
"editFailed": "A kollekció szerkesztése sikertelen"
"editFailed": "A kollekció szerkesztése sikertelen",
"newCollection": "Új kollekció",
"namePlaceholder": "Kollekció neve",
"nameTaken": "Már létezik ilyen nevű kollekció.",
"newHint": "Válaszd ki az első címet — egy kollekcióhoz legalább egy elem kell.",
"createWith": "Létrehozás"
},
"searchPlaceholder": "Keresés a Plexben…",
"searchField": {