874 Commits

Author SHA1 Message Date
Claudio Ortolina e64f2b12c4 ML-200: switch to a vertical chart 2026-05-31 22:02:12 +03:00
Claudio Ortolina e67b172d64 ML-200: daily scrobble count charts 2026-05-31 21:52:06 +03:00
Claudio Ortolina 611ca7e386 Rename vertical_bar_chart -> horizontal_bar_chart 2026-05-31 21:13:53 +03:00
Claudio Ortolina 75e2ec5c70 ML-199: extract shared record show logic 2026-05-29 08:50:27 +03:00
Claudio Ortolina f4648ce5d9 Scrobble entire release from wishlist show page 2026-05-29 08:22:14 +03:00
Claudio Ortolina 33474c1472 Allow scrobbling wishlisted records 2026-05-29 08:09:55 +03:00
Claudio Ortolina dd24258f33 Make stats formats and types counters sync 2026-05-27 23:45:29 +03:00
Claudio Ortolina 118171ed8a ML-169.8: restore formats/types stats position after counters
Formats and types stats should appear directly after the record counters,
before the TopArtists/TopAlbums/OnThisDay grid. The refactor had
accidentally moved them below.
2026-05-25 11:32:48 +03:00
Claudio Ortolina 2d8989a8d0 ML-169.8: keep latest record query synchronous
get_latest_record is a single fast ORDER BY LIMIT 1 query --
no reason to async-load it. Removes the <.async_result> wrapper
and the now-unnecessary render_async() from its test.
2026-05-25 09:42:14 +03:00
Claudio Ortolina f347f56218 ML-169.8: reduce Stats mount sync queries to 3
Move 7 non-critical queries out of synchronous mount into assign_async
and start_async tasks with skeleton loading placeholders.

Only scalar badge counters (collection count, wishlist count, scrobble
count) remain synchronous. All async sections use <.async_result> with
loading and failed slots. Scrobble activity preserves LiveView streams
via handle_async. On-this-day date changes use AsyncResult.ok/2.
2026-05-25 09:31:43 +03:00
Claudio Ortolina 6f5c959238 Show timezone settings in maintenance page 2026-05-25 09:16:56 +03:00
Claudio Ortolina b10be7ba3c ML-169.10: async delete actions with initial implementation 2026-05-22 16:19:54 +01:00
Claudio Ortolina f1fde63d42 ML-189: simplify release-component notifications
- Use a tagged type
- Leave skipping responsibility to subscribed process
2026-05-19 12:18:07 +01:00
Claudio Ortolina e204e555bd ML-188: guard PubSub record updates during edit mode
Add live_action guard to handle_info({:update, record}) in both
CollectionLive.Show and WishlistLive.Show. When the user is editing,
background worker updates are skipped and a warning toast is shown
instead of overwriting the socket. Normal show-mode updates and
mismatched-ID no-ops are unchanged.

6 tests added covering all three code paths.
2026-05-19 11:38:42 +01:00
Claudio Ortolina 8391cf275a ML-180: remove backup download feature
Delete ArchiveController, its routes, the maintenance UI backup
button, and the test file. Management scripts and Litestream
supersede this functionality.
2026-05-15 07:13:33 +01:00
Claudio Ortolina f108e6f062 ML-174: add empty action to record set dropdown menu
Add RecordSets.empty_record_set/1 that bulk-deletes all items in a set via
a single DELETE query and returns the reloaded empty set. Add Empty button
with confirmation prompt to both index and show view dropdowns.
2026-05-14 17:15:06 +01:00
Claudio Ortolina a59dd22a18 ML-168: broadcast index_changed event after background import
Import workers now broadcast :records_index_changed on
"records:index_changed" after successful import via
Records.broadcast_index_changed/0.

CollectionLive.Index and WishlistLive.Index subscribe to the
topic in mount/3 and reload their record streams on receipt,
with a live_action guard to skip reloads when the grid is
hidden behind a modal (:import, :barcode_scan).

IndexActions.handle_index_changed/1 refreshes total_entries
before reloading to keep the pagination bar accurate.
2026-05-14 17:15:06 +01:00
Claudio Ortolina b557fe3eea Fix record picker search results clearing on add
The update/2 callback unconditionally reset the query and results to empty
on every parent re-render. Changed to assign_new/3 so search state persists
when the parent updates the record set after adding a record.
2026-05-09 20:11:51 +01:00
Claudio Ortolina 621b35d824 Open universal search modal instantly via client-side JS
Replace phx-click server event with Fluxon.open_dialog for zero-latency
modal opening. The modal DOM is now always present (no :if conditional) so
it can be shown instantly; the server syncs state in the background.

Fix test selectors that now match the always-present modal form by scoping
to forms without phx-target (which the modal form always has).
2026-05-07 20:43:15 +01:00
Claudio Ortolina 5f240fe573 Fix stale PubSub subscriptions on record navigation
Subscription management was only done in mount/3, meaning
navigating to a different record via handle_params/3 left the
old subscription active. A background update for the old record
would then overwrite the currently displayed record.

Fix: manage subscriptions in handle_params/3 (unsubscribe old,
subscribe new) via shared RecordActions.manage_subscription/2,
and guard handle_info({:update,...}) against mismatched IDs.
2026-05-07 10:14:10 +01:00
Claudio Ortolina c11009f3f9 Update dependencies
ex_slop 0.3.1 => 0.4.0
2026-05-01 17:03:14 +01:00
Claudio Ortolina 3849b338f3 Improve performance of job counting in maintenance
- Use a single query for all workers
- Replace the manual Ecto query against Oban.Job with Oban.Job.query/1
2026-04-30 14:54:56 +01:00
Claudio Ortolina 2e38412a84 ML-10: break compile cycle via Artists → Collection edge 2026-04-24 10:49:47 +01:00
Claudio Ortolina 0784fc5e0c Fix page title for scrobble anything release page 2026-04-23 21:06:32 +01:00
Claudio Ortolina 1bd5707cb4 Fix page title for scrobble anything index and release group route 2026-04-23 21:06:12 +01:00
Claudio Ortolina d03e288353 Make sure top_by_period components have a proper ID 2026-04-23 16:41:18 +01:00
Claudio Ortolina 779708e62e Hide print tracklist on scrobble release page 2026-04-23 15:05:05 +01:00
Claudio Ortolina 72818bfaf2 Validate release-group shape before parsing 2026-04-23 15:00:49 +01:00
Claudio Ortolina c7c7e1fe4e Navigate from scrobble search to release-group page 2026-04-23 14:47:50 +01:00
Claudio Ortolina 0dcd6eab83 Replace /scrobble/:release_id with nested route 2026-04-23 14:39:26 +01:00
Claudio Ortolina d8041dc0dd Add /scrobble/:rg_id release-group page 2026-04-23 14:35:58 +01:00
Claudio Ortolina 4c48bda7b2 Refactor Release component to take release_id 2026-04-23 14:19:11 +01:00
Claudio Ortolina 8179b4317c ML-142: forgot to support timezones 2026-04-22 18:14:14 +01:00
Claudio Ortolina 0776700170 ML-142: Improve scrobble UI in the release component
- Sticky bar for easier track-based scrobbling
- Support setting custom finish time
2026-04-22 17:19:35 +01:00
Claudio Ortolina 016c4691be Canonicalize tailwind classes 2026-04-21 14:22:41 +01:00
Claudio Ortolina 563135fcea Remove dead nil fallback on play_count 2026-04-21 12:48:17 +01:00
Claudio Ortolina 29bfa20978 Remove unreachable error clauses in form save helpers 2026-04-21 12:46:35 +01:00
Claudio Ortolina 9851a5c6bf Use cart with barcode scanner 2026-04-20 15:46:40 +01:00
Claudio Ortolina 3f5ce060b1 Implement ML-143: Cart-style multi record import
Closes ML-143.
2026-04-20 15:15:29 +01:00
Claudio Ortolina cf872cfed0 Secondary sort for artist albums in collection (purchase date desc) 2026-04-19 21:36:07 +01:00
Claudio Ortolina 7767933742 Give more space above the universal search input 2026-04-19 21:29:40 +01:00
Claudio Ortolina da12d5d693 Handle ArtistLive.Form saved message in show view 2026-04-19 08:59:04 +01:00
Claudio Ortolina b37162fce3 Fix colors of mixed badges 2026-04-17 22:30:27 +01:00
Claudio Ortolina 94143010c0 Fix doubly-wrapped safe tuple in artist bio render 2026-04-17 16:00:22 +01:00
Claudio Ortolina fbc548e903 Explicitly trust Wikipedia's HTML
Closes #168
2026-04-16 23:14:00 +01:00
Claudio Ortolina 464e627a63 Remove unnecessary padding from detail views 2026-04-16 22:54:39 +01:00
Claudio Ortolina 6b35b5cde5 Trigger search on Enter in search inputs inside forms 2026-04-16 15:15:47 +01:00
Claudio Ortolina fea1231304 Replace refresh scrobble list icon
Makes it for a better animation
2026-04-15 22:52:28 +01:00
Claudio Ortolina c816f2de4a Add scrobbled tracks search parser
Introduces ListeningStats.SearchParser with NimbleParsec supporting
record:, album_mbid:, artist_mbid:, artist:, album:, track: filters.
Links scrobble count on record page to filtered scrobbled tracks view.
2026-04-15 14:56:38 +01:00
Claudio Ortolina 851cb36858 Fix dl accessibility violations on stats dashboard 2026-04-15 14:16:24 +01:00