soulsync/webui/static
Broque Thomas 07a71f0432 Discover section controller foundation + migrate Recent Releases
Every section on the discover page (Recent Releases, Your Artists,
Your Albums, Seasonal Albums, Seasonal Mix, Fresh Tape, The Archives,
Build Playlist, Time Machine, Browse by Genre, ListenBrainz Playlists,
Because You Listen To, plus ~13 hidden sections) currently
re-implements the same lifecycle by hand:

  1. show a loading spinner in the carousel container
  2. fetch the section's endpoint
  3. parse the response, decide if the data is empty
  4. either render the items, show an empty-state, or show an error
  5. wire post-render handlers (download buttons, hover behavior, etc)
  6. maybe expose refresh()

~30 sections worth of duplicated boilerplate, all subtly drifting.
Different empty-state messages. Different error handling (some
`console.debug`, some silently swallowed, some leave the spinner
spinning forever). Different sync-status icons (✓//✗ vs ♪/✓/✗).
No consistent error toast.

Lifted the lifecycle into a shared `createDiscoverSectionController`
in `webui/static/discover-section-controller.js`. Renderers stay
per-section because section data shapes legitimately differ — album
cards vs artist circles vs playlist tiles vs track rows. The
controller is the wrapper, not a forced visual abstraction.

Foundation contract:

  createDiscoverSectionController({
    id: 'recent-releases',          // for diagnostic logging
    contentEl: '#carousel',          // selector or Element
    fetchUrl: '/api/discover/...',
    extractItems: (data) => [...],   // pull list from response
    renderItems: (items, data, ctx) => '<html>',
    onRendered: (ctx) => { ... },    // optional post-render hook
    loadingMessage / emptyMessage / errorMessage: copy
    sectionEl + hideWhenEmpty: optional whole-section visibility
    isSuccess / isEmpty: optional gate overrides
  })

Returns `{ load, refresh, destroy, getState }`. Validates config up
front so misuse fails at register-time, not silently on load. Coalesces
concurrent loads (same in-flight promise returned) so a double-click
or repeated trigger doesn't double-fetch. `refresh()` bypasses the
coalesce so the refresh button always re-fires. Errors are logged
(console.debug by default, console.error when verboseErrors=true).

Renderer hook errors are caught + logged so a buggy render callback
can't tear down the controller — keeps the page resilient.

Migrated `Recent Releases` as the proof — simplest album-card shape,
no source-gating, no refresh button. Verified the contract covers it
end-to-end. The legacy `loadDiscoverRecentReleases` entry-point stays
public so existing callers don't change; internally it lazy-builds
the controller and triggers `load()`.

NOT in this commit:

- Other section migrations (one section per follow-up commit, keeps
  reviews small + lets us sequence the work)
- Registry-driven section list (so the dead-section audit becomes
  registry deletions instead of section-by-section removal)
- Global error toast wrapper
- Per-section "requires X primary source" gate
- Sync-status icon renderer unification

Once every section is on the controller, the discover-page cleanup
work (kill the 13 dead sections, standardize sync-status icons, add
error toasts) becomes single-line registry-level edits instead of
30 separate section-by-section rewrites.

2204/2204 full suite green. JS parses clean (`node --check`). Manual
smoke deferred until follow-up commits — Recent Releases unchanged
on the wire (same endpoint, same payload shape, same render output).
2026-05-07 18:14:56 -07:00
..
docs update docs page 2026-03-13 08:35:28 -07:00
vendor Add WebSocket real-time updates with automatic HTTP polling fallback 2026-03-03 18:26:29 -08:00
api-monitor.js Stop watchlist countdown refetch loop 2026-05-02 22:02:00 +03:00
artists.png add static images 2026-03-09 17:35:46 -07:00
automation.png add static images 2026-03-09 17:35:46 -07:00
beatport-ui.js Add "All Libraries (combined)" mode to PlexClient 2026-05-06 15:39:19 -07:00
core.js Rename metadata source status selectors 2026-05-02 22:02:01 +03:00
dashboard.png add static images 2026-03-09 17:35:46 -07:00
discover-section-controller.js Discover section controller foundation + migrate Recent Releases 2026-05-07 18:14:56 -07:00
discover.js Discover section controller foundation + migrate Recent Releases 2026-05-07 18:14:56 -07:00
discover.png add static images 2026-03-09 17:35:46 -07:00
docs-images-needed.md Service Badges, Page Headers, Docs Page, and Bug Fixe 2026-03-10 14:47:11 -07:00
docs.js Clean up stale Artists-page references in helper.js + docs.js 2026-04-22 20:29:32 -07:00
downloads.js add guards to error, complete, and cancelled toasts 2026-05-02 07:50:12 -06:00
enrichment.js Repair job card badge — show pending count, not last-scan count 2026-05-07 08:28:17 -07:00
explorer.png Create explorer.png 2026-03-30 17:23:31 -07:00
favicon.png enlarge favicon 2026-02-13 16:11:32 -08:00
help.png Add media server setup, processing settings, text import, automation history, and streaming details 2026-03-10 15:35:18 -07:00
helper.js Discover section controller foundation + migrate Recent Releases 2026-05-07 18:14:56 -07:00
hydrabase.png Add Hydrabase dev UI and WebSocket support 2026-02-21 00:32:04 -08:00
import.png add static images 2026-03-09 17:35:46 -07:00
init.js Show artist breadcrumb on sidebar Library button when on artist-detail page 2026-05-01 17:49:34 -07:00
library.js Add download buttons + bulk action to artist top-tracks sidebar 2026-05-07 15:44:47 -07:00
library.png add static images 2026-03-09 17:35:46 -07:00
manifest.json Service worker for cover art + PWA manifest 2026-04-26 22:17:52 -07:00
media-player.js Split monolithic script.js (78K lines) into 17 domain modules 2026-04-21 23:52:30 -07:00
mobile.css Drop Show/Hide Results button + auto-restore cached results on navigate-back 2026-04-23 22:11:49 -07:00
pages-extra.js Fix bulk discography losing album source context (#399) 2026-04-30 12:42:46 -07:00
particles.js Add particle background toggle & optimize accent color caching 2026-03-13 16:05:22 -07:00
placeholder-album.png Add missing placeholder-album.png to stop 404 spam in console 2026-03-23 18:05:11 -07:00
pwa-icon-192.png Service worker for cover art + PWA manifest 2026-04-26 22:17:52 -07:00
pwa-icon-512.png Service worker for cover art + PWA manifest 2026-04-26 22:17:52 -07:00
search.js MusicBrainz: Fix artist images, total_tracks off-by-one, and Artist+Title queries 2026-04-24 10:17:59 -07:00
search.png add static images 2026-03-09 17:35:46 -07:00
settings.js Wire SoundCloud as a first-class download source 2026-05-03 12:54:21 -07:00
settings.png add static images 2026-03-09 17:35:46 -07:00
setup-wizard.css Add informative help text and tips to every setup wizard step 2026-04-11 23:26:01 -07:00
setup-wizard.js Rebrand folder terminology: Download→Input, Transfer→Output, Staging→Import 2026-04-18 17:35:20 -07:00
shared-helpers.js Fix non-admin profiles defaulting to Spotify on search picker 2026-05-07 11:53:02 -07:00
stats-automations.js Direct ID lookup in Enhance Quality, like Download Discography 2026-05-06 12:05:41 -07:00
style.css Add download buttons + bulk action to artist top-tracks sidebar 2026-05-07 15:44:47 -07:00
sw.js Service worker for cover art + PWA manifest 2026-04-26 22:17:52 -07:00
sync-services.js Split monolithic script.js (78K lines) into 17 domain modules 2026-04-21 23:52:30 -07:00
sync-spotify.js Fix album track source propagation 2026-04-22 21:21:32 +03:00
sync.png add static images 2026-03-09 17:35:46 -07:00
trans.png Add SoulID worker with API-based debut year disambiguation 2026-03-21 10:21:06 -07:00
trans2.png Create trans2.png 2026-03-21 10:23:36 -07:00
whisoul.png Add library repair worker and UI 2026-02-21 15:00:23 -08:00
wishlist-tools.js Rename status cache to metadata_source 2026-05-02 22:02:00 +03:00
worker-orbs.js Add Discogs to worker orbs animation and fix button styling 2026-04-02 17:18:31 -07:00