feat(plex): make the Collection filter multi-select with Any/All
A title can belong to several Plex collections, so the collection filter becomes multi-select combining with Any (OR, default) / All (AND) — the same shape as the genre/actor filters. Backend (query.py): `collection` (single) → `collections` CSV + `collection_mode` on LibraryFilters; meta_filter_conds ORs/ANDs `collection_keys.contains` per id. Frontend: PlexFilters `collection`/`collectionTitle` → `collections` + optional `collectionMode` + `collectionTitles` map; CollectionPicker is now a multi-select Combobox with the any/all match footer; one chip per collection (usePlexActive- Filters); the info-page "Browse collection" strip unions into the list; applyFilter now shallow-merges label maps so adding one keeps the others' titles. PlexProvider migrates a legacy persisted single `collection` into the new shape on read. Test: test_plex_collections_filter (single / any-union / all-intersection).
This commit is contained in:
@@ -239,8 +239,9 @@ export interface PlexFilters {
|
||||
actorMode?: "any" | "all"; // how multiple actors combine (default any = OR)
|
||||
studios: string[]; // OR — from any selected studio
|
||||
keywords: string[]; // AND — TMDB keyword chips from the detail page (E5 S5)
|
||||
collection?: string | null; // a single Plex collection (rating_key)
|
||||
collectionTitle?: string | null; // its title, for the active-filter chip
|
||||
collections: string[]; // Plex collection rating_keys; a title can be in several
|
||||
collectionMode?: "any" | "all"; // how multiple collections combine (default any = OR)
|
||||
collectionTitles?: Record<string, string>; // rating_key → title, for the active-filter chips
|
||||
}
|
||||
export const EMPTY_PLEX_FILTERS: PlexFilters = {
|
||||
genres: [],
|
||||
@@ -249,6 +250,7 @@ export const EMPTY_PLEX_FILTERS: PlexFilters = {
|
||||
actors: [],
|
||||
studios: [],
|
||||
keywords: [],
|
||||
collections: [],
|
||||
};
|
||||
export function plexFilterCount(f: PlexFilters): number {
|
||||
return (
|
||||
@@ -262,7 +264,7 @@ export function plexFilterCount(f: PlexFilters): number {
|
||||
f.actors.length +
|
||||
f.studios.length +
|
||||
f.keywords.length +
|
||||
(f.collection ? 1 : 0)
|
||||
f.collections.length
|
||||
);
|
||||
}
|
||||
// Serialize the shared PlexFilters metadata fields onto a query string. Used by both the library grid
|
||||
@@ -283,7 +285,8 @@ function appendPlexFilters(u: URLSearchParams, f: PlexFilters): void {
|
||||
if (f.actorMode === "all") u.set("actor_mode", "all");
|
||||
if (f.studios?.length) u.set("studios", f.studios.join(","));
|
||||
if (f.keywords?.length) u.set("keywords", f.keywords.join(","));
|
||||
if (f.collection) u.set("collection", f.collection);
|
||||
if (f.collections?.length) u.set("collections", f.collections.join(","));
|
||||
if (f.collectionMode === "all") u.set("collection_mode", "all");
|
||||
}
|
||||
export interface PlexFacets {
|
||||
genres: { value: string; count: number }[];
|
||||
|
||||
Reference in New Issue
Block a user