The Library showed a blocking error with the backend unreachable. Now it
composes a read-only library from everything already in the RTK Query
cache (Tier-2 rehydrated last-seen data + anything fetched this session),
so it keeps rendering offline instead of erroring.
- selectors: `selectLocalTracks/Albums/Artists` — memoized, union + dedupe
across getTracks/getAlbums/getArtists, the per-album/artist list
endpoints, and single-entity fetches; skips pending/rejected entries
- LibraryPage: when offline, fall back to the composed lists (live data
still wins online), filter client-side for search, show an offline
banner, and never show the retry-only ErrorState
- i18n: `library.offline.*` (en + ru)
- test: selector composition / dedup / status filtering (3 cases)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the scaffold Placeholder with a real artist page wired to the
existing `/artists/{id}` (+ `/albums`, `/tracks`) endpoints: header with
procedural avatar / counts / "Play all" (queues with source=artist),
discography grid (cards → album detail), and the full track list. All
three list states per async section.
Also make the Library artists-tab rows clickable → `/artists/:id`,
closing the previous navigation dead-end.
i18n: new `artist.*` block (en + ru).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Queue rows passed albumArtUrl straight to ArtTile, but for tracks that
field is usually empty — the real cover is served per-track from
/tracks/{id}/cover. Apply the same resolution PersistentPlayer uses
(getCoverUrl ?? getTrackCoverUrl) for both the now-playing tile and the
up-next rows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build out the full web route map from music-selfhost-routes.md as
scaffolding (no functionality on new screens):
- Full route tree: /login, /albums/:id, /artists/:id, /playlists(+detail),
/discover, /upload, metadata editor (single + batch), /storage/maintenance,
/queue, nested /settings and /admin, and a 404.
- Sidebar rebuilt to the A1 spec with permission-gated Discover/Upload.
- ProtectedRoute gains requirePermission; Permission exported.
- AppShell wraps Outlet in a Suspense boundary for lazy routes.
- Reusable Placeholder + SubNav; Settings/Admin become nested layouts.
- Settings/Profile: wired language + theme selectors.
- Remove orphaned Home feature (web has no Home; / -> /library) and the
now-unused house icon + nav.home keys.
- i18n keys (en + ru) and CSS for page-title/sub-nav.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>