feat(filters+ui): per-element author/publisher filters, playlist toggles, Up Next API, reorder UI, dashboard badges
Phases 4 + 5 of the metadata overhaul (plan §4, §5) plus §3 handler wiring. Filters (§4.1): author_filter/publisher_filter now match per-element against the authors[]/publishers[] arrays — a co-authored book matches any one of its authors — with comma-joined params acting as OR-within-facet multi-select (string_to_array + cross unnest). Legacy single-value params unchanged on the wire; series/genre/language filters stay on their varchar columns; narrator filter already per-element. Collections API (§3.3-3.5): collection detail carries viewer + hide_finished into the listing query and exposes up_next (visible- library-enforced reading-queue head); PUT /api/collections/:id/items/order (owner-only, full-order rewrite); UpdateCollectionRequest gains hide_finished/show_up_next ([] string last-value-wins for the hidden-false-sibling checkbox pattern) merged server-side OVER stored view_settings so imported_from_series provenance survives edits; EditCollectionModal renders the toggles from view_settings. Dashboard (§5.5): sections JSON carries is_playlist/complete (dashboard.ts is the AGENTS-documented JSON-render exception; first paint stays templ). Fully-read playlists render '✓ Playlist complete' instead of an empty rail; imported playlists get a 📖 Playlist badge. Frontend: book detail shows subtitle + full authors + Explicit badge; edit modal gains subtitle, comma-separated authors/publishers (client- split to arrays exactly like narrators), step=any series number, explicit checkbox; collection book cards get playlist move ↑/↓ buttons persisting the full order via the reorder endpoint (templ partial re-render on failure — DOM order is client-local, API order is truth). AGENTS.md gotcha #3 amended per plan §3.7: user collections are dashboard sections by default; the show_on_dashboard premise is retired. Verified: full affected integration sweep green (pins widened for up_next/is_playlist/complete — changelog entries in docs/contract_pins.md); unit suite green; go build + templ + vite green.
This commit is contained in:
1 parent
1dbb0ce406
commit
f94e7472b4
20 files changed
+1711
-1339
No files matched your search
@@ -13218,14 +13218,26 @@ WHERE COALESCE(lv.is_visible, true) = true
|
||||
AND mi.missing_scan_count = 0
|
||||
AND ($2::uuid IS NULL
|
||||
OR mi.library_id = $2::uuid)
|
||||
-- Fuzzy author filter
|
||||
AND ($3 = '' OR word_similarity($3, COALESCE(mi.author, '')) > 0.3)
|
||||
-- Fuzzy author filter — per-element against the authors[] array (A2c
|
||||
-- §4.1): a co-authored book matches ANY one of its authors, and a
|
||||
-- comma-joined param is multi-select (OR within the facet).
|
||||
AND ($3 = '' OR EXISTS (
|
||||
SELECT 1
|
||||
FROM unnest(string_to_array($3, ',')) AS f
|
||||
JOIN unnest(mi.authors) AS a ON true
|
||||
WHERE word_similarity(f, COALESCE(a, '')) > 0.3
|
||||
))
|
||||
-- Fuzzy series filter
|
||||
AND ($4 = '' OR word_similarity($4, COALESCE(mi.series, '')) > 0.3)
|
||||
-- Fuzzy genre filter
|
||||
AND ($5 = '' OR word_similarity($5, COALESCE(mi.genre, '')) > 0.3)
|
||||
-- Fuzzy publisher filter
|
||||
AND ($6 = '' OR word_similarity($6, COALESCE(mi.publisher, '')) > 0.3)
|
||||
-- Fuzzy publisher filter — per-element against publishers[] (A2c §4.1).
|
||||
AND ($6 = '' OR EXISTS (
|
||||
SELECT 1
|
||||
FROM unnest(string_to_array($6, ',')) AS f
|
||||
JOIN unnest(mi.publishers) AS p ON true
|
||||
WHERE word_similarity(f, COALESCE(p, '')) > 0.3
|
||||
))
|
||||
-- Fuzzy language filter
|
||||
AND ($7 = '' OR word_similarity($7, COALESCE(mi.language, '')) > 0.3)
|
||||
-- Tags filter (NEW - fuzzy match against tags array)
|
||||
|
||||
@@ -679,14 +679,26 @@ WHERE COALESCE(lv.is_visible, true) = true
|
||||
AND mi.missing_scan_count = 0
|
||||
AND (sqlc.narg('library_id')::uuid IS NULL
|
||||
OR mi.library_id = sqlc.narg('library_id')::uuid)
|
||||
-- Fuzzy author filter
|
||||
AND (sqlc.narg('author_filter') = '' OR word_similarity(sqlc.narg('author_filter'), COALESCE(mi.author, '')) > 0.3)
|
||||
-- Fuzzy author filter — per-element against the authors[] array (A2c
|
||||
-- §4.1): a co-authored book matches ANY one of its authors, and a
|
||||
-- comma-joined param is multi-select (OR within the facet).
|
||||
AND (sqlc.narg('author_filter') = '' OR EXISTS (
|
||||
SELECT 1
|
||||
FROM unnest(string_to_array(sqlc.narg('author_filter'), ',')) AS f
|
||||
JOIN unnest(mi.authors) AS a ON true
|
||||
WHERE word_similarity(f, COALESCE(a, '')) > 0.3
|
||||
))
|
||||
-- Fuzzy series filter
|
||||
AND (sqlc.narg('series_filter') = '' OR word_similarity(sqlc.narg('series_filter'), COALESCE(mi.series, '')) > 0.3)
|
||||
-- Fuzzy genre filter
|
||||
AND (sqlc.narg('genre_filter') = '' OR word_similarity(sqlc.narg('genre_filter'), COALESCE(mi.genre, '')) > 0.3)
|
||||
-- Fuzzy publisher filter
|
||||
AND (sqlc.narg('publisher_filter') = '' OR word_similarity(sqlc.narg('publisher_filter'), COALESCE(mi.publisher, '')) > 0.3)
|
||||
-- Fuzzy publisher filter — per-element against publishers[] (A2c §4.1).
|
||||
AND (sqlc.narg('publisher_filter') = '' OR EXISTS (
|
||||
SELECT 1
|
||||
FROM unnest(string_to_array(sqlc.narg('publisher_filter'), ',')) AS f
|
||||
JOIN unnest(mi.publishers) AS p ON true
|
||||
WHERE word_similarity(f, COALESCE(p, '')) > 0.3
|
||||
))
|
||||
-- Fuzzy language filter
|
||||
AND (sqlc.narg('language_filter') = '' OR word_similarity(sqlc.narg('language_filter'), COALESCE(mi.language, '')) > 0.3)
|
||||
-- Tags filter (NEW - fuzzy match against tags array)
|
||||
|
||||
Reference in new issue
Block a user