Add initial webui page migration analysis

This commit is contained in:
Antti Kettunen 2026-04-06 16:59:56 +03:00
parent d98dcd8606
commit 43db30608d
No known key found for this signature in database
GPG key ID: C6B2A3D250359BD7
3 changed files with 378 additions and 74 deletions

View file

@ -0,0 +1,331 @@
# WebUI Page Migration Analysis
Snapshot date: 2026-04-06
## Summary
- This document inventories the current hybrid WebUI shell and recommends an incremental migration order from legacy vanilla-JS rendering to the Vite + React + TanStack Router app.
- The canonical shell route list currently contains 15 page IDs in `webui/src/platform/shell/route-manifest.ts`.
- Only `issues` is React-owned today. Every other route is still rendered by the legacy shell, primarily through `webui/static/script.js`, `webui/index.html`, and the global stylesheet.
- The recommended order optimizes for low-risk wins first while still calling out a few high-value platform unlocks for later waves.
## Current Architecture
- `webui/index.html` is still the Flask-served shell. It owns the sidebar, media player, global overlays, and legacy `.page` containers for every non-React page.
- `#webui-react-root` is the single React mount point. It is treated like a shell page and becomes active when the current route belongs to React.
- `webui/static/script.js` is still the main rendering coordinator:
- route activation and page switching
- shell bridge exposure via `window.SoulSyncWebShellBridge`
- `loadPageData()` dispatch for nearly every legacy route
- page-local state, global shell state, polling, and many modal/workflow implementations
- TanStack Router delegates legacy pages back to the shell through `webui/src/routes/$.tsx` and `LegacyRouteController`, while React routes use `useReactPageShell()` to set shell chrome and show the React host.
- `issues` is the reference migration pattern:
- canonical route ownership lives in `route-manifest.ts`
- route UI lives under `webui/src/routes/issues/`
- React owns route rendering, data loading, and detail modal behavior
- the shell still owns route gating, nav chrome, and the page host
### Inventory Notes
- Manifest page IDs: `dashboard`, `sync`, `downloads`, `discover`, `playlist-explorer`, `artists`, `automations`, `library`, `artist-detail`, `stats`, `import`, `settings`, `issues`, `help`, `hydrabase`
- HTML `.page` containers exist for every shell page except `issues`.
- `issues` is the only route that resolves through the React host instead of a legacy `.page` container.
- `artist-detail` is a first-class route in the manifest and HTML, but it behaves like an extension of `library`, not a truly independent feature area.
## Cross-Cutting Features
These features are not owned by one page, but they affect migration scope, shell contracts, and ordering.
- Profile and permission routing
- Owned in `script.js` profile initialization and `isPageAllowed()` logic.
- Controls route gating, home-page redirects, admin-only settings, and the special `artist-detail -> library` permission relationship.
- Sidebar and shell chrome
- Nav highlighting, page activation, global search visibility, discover sidebar visibility, and route-path synchronization all stay shell-owned today.
- Any route migration must preserve these shell behaviors through the bridge rather than re-implementing them per route.
- Media player and queue
- The sidebar player, expanded player, queue, streaming preview, and media-session integration live outside page boundaries.
- Several pages launch playback or update queue state, so migration work has to preserve these entry points.
- WebSocket and polling infrastructure
- Socket.IO initialization is global.
- Many pages depend on active-process polling, sync/discovery polling, worker status polling, wishlist/watchlist polling, or progress refresh loops.
- Pages with heavy polling or live progress are materially riskier to migrate.
- Helper and docs systems
- `webui/static/docs.js` owns the Help page content.
- `webui/static/helper.js` owns contextual help, tours, setup flows, and page-specific selector metadata across the app.
- The Help page itself is easy to migrate, but the helper system is cross-cutting and should remain shell-owned until route migrations are further along.
- Visual shell effects
- `particles.js` and `worker-orbs.js` are shell/global effects.
- `worker-orbs.js` is dashboard-specific but mounted globally.
- These are low priority to migrate and should be treated as shell integrations unless a page migration explicitly needs to absorb them.
## Scoring Rubric
Each page is scored from 1 to 5 on five axes:
- Rendering surface size: HTML/UI area and number of distinct render states
- State/coupling complexity: amount of local state plus coupling to other pages or shell-global state
- Async/realtime complexity: fetch fan-out, polling, WebSocket/live progress, streaming, or long-running workflows
- Cross-cutting shell dependency: reliance on shared shell behaviors, globals, overlays, or non-route contracts
- Testability/parity difficulty: how hard it is to prove route parity without regressions
Rollups:
- Migration effort
- `Low`: total score 9-11
- `Medium`: total score 12-17
- `High`: total score 18-21
- `Very High`: total score 22-25
- Regression risk
- `Low`: mostly isolated UI with limited async and minimal shell coupling
- `Medium`: moderate data flow or workflow complexity with bounded blast radius
- `High`: broad coupling, many async states, or sensitive user workflows
## Summary Matrix
| Page | Owner | Scores (R/S/A/C/T) | Effort | Risk | Recommended Wave |
| --- | --- | --- | --- | --- | --- |
| `issues` | React | 2 / 2 / 2 / 2 / 2 | Low | Low | Baseline only |
| `help` | Legacy | 3 / 2 / 1 / 1 / 2 | Low | Low | Wave 1 |
| `hydrabase` | Legacy | 2 / 2 / 2 / 2 / 2 | Low | Low | Wave 1 |
| `stats` | Legacy | 2 / 2 / 2 / 2 / 2 | Low | Low | Wave 1 |
| `import` | Legacy | 3 / 3 / 3 / 2 / 3 | Medium | Medium | Wave 1 |
| `artists` | Legacy | 3 / 4 / 3 / 3 / 3 | Medium | Medium | Wave 2 |
| `downloads` | Legacy | 4 / 4 / 4 / 3 / 4 | High | High | Wave 3 |
| `dashboard` | Legacy | 4 / 4 / 4 / 4 / 4 | High | High | Wave 3 |
| `discover` | Legacy | 5 / 5 / 4 / 4 / 5 | Very High | High | Wave 4 |
| `library` | Legacy | 4 / 5 / 4 / 4 / 5 | Very High | High | Wave 5 |
| `artist-detail` | Legacy | 5 / 5 / 4 / 5 / 5 | Very High | High | Wave 5 |
| `playlist-explorer` | Legacy | 4 / 4 / 4 / 3 / 4 | High | High | Wave 6 |
| `sync` | Legacy | 5 / 5 / 5 / 4 / 5 | Very High | High | Wave 7 |
| `settings` | Legacy | 5 / 5 / 4 / 5 / 5 | Very High | High | Wave 8 |
| `automations` | Legacy | 4 / 5 / 4 / 3 / 4 | High | High | Wave 8 |
## Page Catalog
### `issues`
- Current owner: React
- Primary files: `webui/src/routes/issues/*`, `webui/src/platform/shell/*`, `plans/webui-issues-migration-plan.md`
- Main surface: counts cards, filtered issue list, issue-detail modal, mutation flows
- Async behavior: route loader prefetch, React Query list/detail/count queries, mutation-driven refresh
- Coupling: shell page gating, shell nav badge refresh, bridge-controlled chrome
- Blockers or prerequisites: none; this is the migration baseline
- Scores: `2 / 2 / 2 / 2 / 2`
- Rationale: already proves the route-manifest + bridge + React-host pattern with limited shell leakage
### `help`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/docs.js`, `webui/static/script.js`
- Main surface: documentation navigation, long-form content sections, screenshot lightbox, docs deep linking
- Async behavior: effectively none beyond image loading
- Coupling: shell nav and page activation only; contextual help metadata lives elsewhere but does not need to migrate with the page
- Blockers or prerequisites: keep `helper.js` shell-owned for now; migrate the Help route only, not the whole helper system
- Scores: `3 / 2 / 1 / 1 / 2`
- Rationale: large content surface, but low runtime complexity and limited cross-page coordination
- Recommendation: best low-risk route after `issues`
### `hydrabase`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`
- Main surface: connection state, saved credentials, peer count, comparison list
- Async behavior: status fetch, connect/disconnect flows, comparisons load
- Coupling: dev-mode visibility, settings linkage, shell route gating
- Blockers or prerequisites: keep the Hydrabase shell toggle behavior outside the route initially
- Scores: `2 / 2 / 2 / 2 / 2`
- Rationale: bounded feature area with limited UI states and no broad reusable legacy entanglement
- Recommendation: safe early migration
### `stats`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`
- Main surface: ranked lists, charts, db storage visualization, listening-stats refresh
- Async behavior: cached stats fetches, chart rendering, one-off sync actions
- Coupling: shell page activation, some library deep links back to artist/library routes
- Blockers or prerequisites: preserve chart library loading and route-to-library deep links
- Scores: `2 / 2 / 2 / 2 / 2`
- Rationale: read-heavy page with mostly isolated rendering and modest mutation behavior
- Recommendation: early migration candidate with good parity-test potential
### `import`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`
- Main surface: staging files, grouped import candidates, album/track search, suggestions, match and process flows
- Async behavior: multiple search/match/process endpoints, modal-like step transitions inside the page
- Coupling: settings-derived staging path assumptions, downstream library state
- Blockers or prerequisites: likely benefits from shared album-search and suggestion primitives, but does not require them
- Scores: `3 / 3 / 3 / 2 / 3`
- Rationale: moderate workflow complexity, but still much more self-contained than discovery, sync, or library management
- Recommendation: last route in the initial low-risk wave
### `artists`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: search/results/detail view switching inside one route, artist caching, discography snippets, similar artists, watchlist interactions, download bubbles
- Async behavior: search debouncing, cancellation via abort controllers, detail/discography fetches, similar-artist loading
- Coupling: shares artist concepts with `library`, `artist-detail`, `discover`, and watchlist workflows
- Blockers or prerequisites: decide whether route migration should keep its internal view-state approach or split search/detail sub-routes later
- Scores: `3 / 4 / 3 / 3 / 3`
- Rationale: not tiny, but still a manageable route for establishing artist-focused React patterns before touching library detail
- Recommendation: first medium-complexity route after the initial safe wave
### `downloads`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: enhanced search, basic search, source tabs, filters, result cards, preview playback, candidate selection, download manager queues
- Async behavior: many search endpoints, batch downloads, active-process rehydration, polling, streaming preview
- Coupling: media player, queue, settings-derived source configuration, modal reuse across other pages
- Blockers or prerequisites: shared result-card, album-detail, and mutation-state primitives would help, but they do not have to exist before migration starts
- Scores: `4 / 4 / 4 / 3 / 4`
- Rationale: feature-rich and mutation-heavy, but valuable once the app already has a few safer route wins
- Recommendation: migrate only after help/hydrabase/stats/import/artists establish a stable pattern
### `dashboard`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`, `webui/static/worker-orbs.js`
- Main surface: activity feed, service cards, worker buttons, backup manager, metadata cache, history modals, repair dashboard, recent sync history
- Async behavior: high polling density, worker status updates, activity feed refresh, backup and maintenance actions
- Coupling: almost every cross-cutting system eventually surfaces here
- Blockers or prerequisites: keep worker-orb visuals and global helper affordances shell-owned; route migration should focus on dashboard content first
- Scores: `4 / 4 / 4 / 4 / 4`
- Rationale: central page with broad read/write coverage and high shell entanglement
- Recommendation: treat as a mid-program migration, not an opening move
### `discover`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: hero carousel, your artists, Spotify library, recent releases, seasonal content, personalized shelves, ListenBrainz tabs, decade browser, genre browser, discovery blacklist
- Async behavior: very large parallel fetch fan-out, sync-status polling, watchlist integration, persistent playlist state hydration
- Coupling: shared album cards, watchlist/wishlist flows, sync actions, discovery-download sidebars, artist navigation
- Blockers or prerequisites: benefits from reusable album/artist card primitives, but the main risk is breadth rather than missing infrastructure
- Scores: `5 / 5 / 4 / 4 / 5`
- Rationale: one of the broadest pages in the app, with many semi-independent sections that still share global behaviors
- Recommendation: move after the team has already migrated a few medium-complexity, data-heavy routes
### `library`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: searchable artist grid, alphabet navigation, watchlist filters, pagination, download bubbles, deep links into `artist-detail`
- Async behavior: paginated fetches, watchlist mutations, shell-to-detail navigation
- Coupling: tightly bound to `artist-detail`, watchlist systems, active metadata source, and library-wide expectations
- Blockers or prerequisites: should not be migrated independently from the `artist-detail` strategy
- Scores: `4 / 5 / 4 / 4 / 5`
- Rationale: modest-looking page, but it is the entry point into the most complex library-management workflows
- Recommendation: migrate in the same program wave as `artist-detail`, not as an isolated quick win
### `artist-detail`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: hero section, standard discography, enhanced view, filters, selection/bulk operations, inline editing, manual match, tag preview/write, reorganize, quality enhancement
- Async behavior: detail fetches, streaming library-completion checks, multiple mutation workflows, modal stacks, playback actions
- Coupling: explicitly coupled to `library`; also touches watchlist settings, downloads, playback, metadata services, and file-organization settings
- Blockers or prerequisites: requires a clear React strategy for complex table/grid state, inline editing, and bulk actions before migration begins
- Scores: `5 / 5 / 4 / 5 / 5`
- Rationale: highest combined shell and workflow complexity outside `sync` and `settings`
- Recommendation: treat as a paired migration with `library`, and keep it out of early waves
### `playlist-explorer`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`
- Main surface: visual discovery tree, artist tiers, album expansion, selection model, wishlist submission flow, zoom/pan interactions
- Async behavior: tree build, album-track fetches, wishlist processing, drag-like navigation, global document listeners for pointer/wheel events
- Coupling: artist navigation, wishlist flows, page-level document event handlers
- Blockers or prerequisites: needs a deliberate React strategy for viewport interactions and document-level listeners before migration starts
- Scores: `4 / 4 / 4 / 3 / 4`
- Rationale: narrower than `sync`, but still interaction-heavy and easy to regress
- Recommendation: late-mid program route after the team is comfortable migrating complex visual state
### `sync`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: Spotify/Tidal/Deezer/YouTube/Beatport/ListenBrainz/public Spotify playlists, mirrored playlists, URL histories, server playlist manager, discovery and sync phases, modal rehydration
- Async behavior: the heaviest page in the app; many endpoints, long-running workflows, state rehydration, polling, and live progress
- Coupling: download manager, server integrations, discovery workflows, active-process hydration, and multiple global state buckets
- Blockers or prerequisites: likely needs reusable route-local infrastructure for task state, progress polling, and source-specific adapters
- Scores: `5 / 5 / 5 / 4 / 5`
- Rationale: broadest operational surface and highest parity burden
- Recommendation: one of the last major migrations
### `settings`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`, `webui/static/docs.js`
- Main surface: five-tab admin settings area, API/service credentials, media server setup, download source and quality config, file organization, appearance, advanced settings, profile/security integration, API keys
- Async behavior: large form hydration, auto-save, many service auth/test flows, dynamic source-specific form sections, media-library selectors
- Coupling: almost every other page depends on settings-derived behavior or stored configuration
- Blockers or prerequisites: route migration should be delayed until the app has settled conventions for large forms, auth/test actions, and configuration write flows
- Scores: `5 / 5 / 4 / 5 / 5`
- Rationale: the biggest shell container in `index.html` and one of the most globally coupled feature areas
- Recommendation: late migration despite the lack of constant polling, because the blast radius is large
### `automations`
- Current owner: Legacy
- Primary files: `webui/index.html`, `webui/static/script.js`, `webui/static/helper.js`
- Main surface: automation list, filters, execution status, run history modal, one-click hub groups, visual builder, block placement and config editing
- Async behavior: list loading, progress polling, run/deploy/toggle/history actions, builder save/load flows
- Coupling: uses many domain concepts but is less shell-dependent than settings or sync
- Blockers or prerequisites: migrating the builder safely requires a strong React approach for nested editable state and drag-like canvas interactions
- Scores: `4 / 5 / 4 / 3 / 4`
- Rationale: smaller shell footprint than settings or sync, but high internal interaction complexity
- Recommendation: save for the final wave with other complex authoring surfaces
## Platform Unlocks
These are not the primary ordering rule, but they are useful to recognize because they can lower later migration cost.
- `artists`
- Likely unlocks reusable artist search, discography preview, and watchlist primitives for `discover`, `library`, and `artist-detail`.
- `downloads`
- Likely unlocks reusable album/track result cards, playback-launch patterns, and download mutation handling for `discover`, `library`, and issue-detail admin actions.
- `library` + `artist-detail`
- Likely unlock reusable entity-detail patterns, richer table state, batch actions, and file-management workflows.
- `settings`
- Likely unlock shared admin form patterns and service-auth/test primitives, but the route is risky enough that it should not be used as an early proving ground.
## Recommended Migration Waves
### Wave 0: Reference baseline
- `issues`
- Goal: keep using the current Issues route as the canonical example for route ownership, shell bridge usage, and React-host activation.
### Wave 1: Safest wins
- `help`
- `hydrabase`
- `stats`
- `import`
- Why: these routes offer the best ratio of migration confidence to regression risk. They let the app add more React-owned routes without immediately entangling the team in global shell state or long-running workflow recovery.
### Wave 2: First medium-complexity route
- `artists`
- Why: good proving ground for async search, route-local cache/state, artist cards, and watchlist interactions before touching the full library-management stack.
### Wave 3: High-value operational routes
- `downloads`
- `dashboard`
- Why: both are important and complex, but by this point the team should already have route-local data-loading, mutation, and shell-bridge patterns that reduce migration risk.
### Wave 4: Broad discovery surface
- `discover`
- Why: very large rendering surface with many semi-independent sections. It should follow several prior migrations so the shared UI and query patterns are already mature.
### Wave 5: Library stack
- `library`
- `artist-detail`
- Why: these routes are tightly coupled and should be planned together. `artist-detail` is not an independent easy win and should not be pulled forward ahead of `library`.
### Wave 6: Visual interaction route
- `playlist-explorer`
- Why: highly interactive canvas/tree behaviors are easier to migrate once the broader React route architecture is already established.
### Wave 7: Multi-source orchestration route
- `sync`
- Why: this route has the deepest async orchestration, state rehydration, and external-service surface. It should be migrated only after the team has already de-risked several other route families.
### Wave 8: Final complex authoring/admin routes
- `settings`
- `automations`
- Why: these are high-blast-radius authoring surfaces with large state trees. They should land after the route architecture, shared UI patterns, and shell contracts are already stable.
## Why Earlier Waves Are Safer
- Wave 1 routes are either mostly static or bounded data UIs with limited cross-route side effects.
- Wave 2 adds moderate route-local state without forcing the app to solve shell-global task orchestration yet.
- Waves 3-4 add high-value routes once the migration pattern is established, rather than trying to learn the pattern inside the most coupled pages.
- Wave 5 intentionally treats the library stack as one problem space instead of creating a half-migrated split between `library` and `artist-detail`.
- Waves 6-8 defer the most interaction-heavy, orchestration-heavy, or configuration-heavy surfaces until the team has the most leverage.
## Final Recommendation
- Keep `issues` as the reference implementation and preserve the existing bridge contract.
- Migrate the low-risk routes first: `help`, `hydrabase`, `stats`, and `import`.
- Use `artists` as the first medium-complexity proving ground.
- Avoid pulling `settings`, `sync`, `library`, `artist-detail`, or `automations` forward unless there is a separate product priority strong enough to justify the added regression risk.

View file

@ -109,7 +109,6 @@
<option value="automations">Automations</option>
<option value="active-downloads">Downloads</option>
<option value="library">Library</option>
<option value="tools">Tools</option>
<option value="stats">Listening Stats</option>
<option value="playlist-explorer">Playlist Explorer</option>
<option value="import">Import</option>
@ -126,7 +125,6 @@
<label><input type="checkbox" value="automations" checked> Automations</label>
<label><input type="checkbox" value="active-downloads" checked> Downloads</label>
<label><input type="checkbox" value="library" checked> Library</label>
<label><input type="checkbox" value="tools" checked> Tools</label>
<label><input type="checkbox" value="stats" checked> Listening Stats</label>
<label><input type="checkbox" value="playlist-explorer" checked> Playlist Explorer</label>
<label><input type="checkbox" value="import" checked> Import</label>
@ -2152,51 +2150,56 @@
<!-- Active Downloads Page -->
<div class="page{% if initial_client_page == 'active-downloads' %} active{% endif %}" id="active-downloads-page">
<div class="adl-container">
<div class="adl-header">
<h2 class="adl-title"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Downloads</h2>
<div class="adl-controls">
<div class="adl-filter-pills" id="adl-filter-pills">
<button class="adl-pill active" data-filter="all" onclick="adlSetFilter('all')">All</button>
<button class="adl-pill" data-filter="active" onclick="adlSetFilter('active')">Active</button>
<button class="adl-pill" data-filter="queued" onclick="adlSetFilter('queued')">Queued</button>
<button class="adl-pill" data-filter="completed" onclick="adlSetFilter('completed')">Completed</button>
<button class="adl-pill" data-filter="failed" onclick="adlSetFilter('failed')">Failed</button>
<div class="adl-layout">
<!-- Left: download list -->
<div class="adl-main">
<div class="adl-container">
<div class="adl-header">
<h2 class="adl-title"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Downloads</h2>
<div class="adl-controls">
<div class="adl-filter-pills" id="adl-filter-pills">
<button class="adl-pill active" data-filter="all" onclick="adlSetFilter('all')">All</button>
<button class="adl-pill" data-filter="active" onclick="adlSetFilter('active')">Active</button>
<button class="adl-pill" data-filter="queued" onclick="adlSetFilter('queued')">Queued</button>
<button class="adl-pill" data-filter="completed" onclick="adlSetFilter('completed')">Completed</button>
<button class="adl-pill" data-filter="failed" onclick="adlSetFilter('failed')">Failed</button>
</div>
<div style="display:flex;align-items:center;gap:10px;">
<span class="adl-count" id="adl-count"></span>
<button class="adl-clear-btn" id="adl-clear-btn" onclick="adlClearCompleted()" style="display:none">Clear Completed</button>
</div>
</div>
</div>
<div style="display:flex;align-items:center;gap:10px;">
<span class="adl-count" id="adl-count"></span>
<button class="adl-clear-btn" id="adl-clear-btn" onclick="adlClearCompleted()" style="display:none">Clear Completed</button>
<div class="adl-list" id="adl-list">
<div class="adl-empty" id="adl-empty">No downloads yet. Start one from Search, Sync, Discover, or Library.</div>
</div>
</div>
</div>
<div class="adl-list" id="adl-list">
<div class="adl-empty" id="adl-empty">No downloads yet. Start one from Search, Sync, Discover, or Library.</div>
</div>
</div>
<!-- Right: batch context panel -->
<div class="adl-batch-panel" id="adl-batch-panel">
<div class="adl-batch-panel-header">
<h3 class="adl-batch-panel-title">Batches</h3>
<div class="adl-batch-panel-header-actions">
<button class="library-history-btn" onclick="openLibraryHistoryModal()" title="View full download + import history">Download History</button>
<button class="adl-batch-panel-collapse" id="adl-batch-collapse" onclick="adlToggleBatchPanel()" title="Toggle batch panel">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
</button>
</div>
</div>
<div class="adl-batch-active" id="adl-batch-active">
<!-- Active batch cards rendered by JS -->
</div>
<div class="adl-batch-history-section" id="adl-batch-history-section" style="display:none">
<div class="adl-batch-history-header" onclick="adlToggleBatchHistory()">
<span>Recent History</span>
<div class="adl-batch-history-header-actions">
<button class="library-history-btn" onclick="event.stopPropagation();openLibraryHistoryModal()" title="View full download + import history">Download History</button>
<svg class="adl-batch-history-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
<!-- Right: batch context panel -->
<div class="adl-batch-panel" id="adl-batch-panel">
<div class="adl-batch-panel-header">
<h3 class="adl-batch-panel-title">Batches</h3>
<div class="adl-batch-panel-header-actions">
<button class="library-history-btn" onclick="openLibraryHistoryModal()" title="View full download + import history">Download History</button>
<button class="adl-batch-panel-collapse" id="adl-batch-collapse" onclick="adlToggleBatchPanel()" title="Toggle batch panel">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
</button>
</div>
</div>
<div class="adl-batch-history-list" id="adl-batch-history-list">
<!-- Completed batch history rendered by JS -->
<div class="adl-batch-active" id="adl-batch-active">
<!-- Active batch cards rendered by JS -->
</div>
<div class="adl-batch-history-section" id="adl-batch-history-section" style="display:none">
<div class="adl-batch-history-header" onclick="adlToggleBatchHistory()">
<span>Recent History</span>
<div class="adl-batch-history-header-actions">
<button class="library-history-btn" onclick="event.stopPropagation();openLibraryHistoryModal()" title="View full download + import history">Download History</button>
<svg class="adl-batch-history-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
</div>
</div>
<div class="adl-batch-history-list" id="adl-batch-history-list">
<!-- Completed batch history rendered by JS -->
</div>
</div>
</div>
</div>

View file

@ -100,26 +100,6 @@ const HELPER_CONTENT = {
],
docsId: 'library'
},
'.nav-button[data-page="watchlist"]': {
title: 'Watchlist',
description: 'Artists you follow for new releases. Use this page to scan for fresh albums and singles, manage per-artist preferences, and keep discovery data up to date.',
tips: [
'Watchlist scans add matching releases to your Wishlist',
'The page keeps live scan activity visible while jobs run',
'Per-artist settings control which release types are included'
],
docsId: 'art-watchlist'
},
'.nav-button[data-page="wishlist"]': {
title: 'Wishlist',
description: 'Tracks waiting to be downloaded. Failed downloads, watchlist discoveries, and manual adds all land here for batch processing.',
tips: [
'Album and single queues are shown separately',
'Use batch select to remove or download multiple items',
'The page shows the next automatic processing cycle'
],
docsId: 'art-wishlist'
},
'.nav-button[data-page="active-downloads"]': {
title: 'Downloads',
description: 'Centralized view of every download across the entire app. Shows live status for all tracks from Sync, Discover, Artists, Search, and Wishlist in one place.',
@ -129,16 +109,6 @@ const HELPER_CONTENT = {
'Clear Completed button removes finished items from the list'
]
},
'.nav-button[data-page="tools"]': {
title: 'Tools',
description: 'Database and maintenance operations live here now: scans, backups, cleanup jobs, cache work, and repair tools.',
tips: [
'Library Maintenance is the hero section at the top of the page',
'Use this page for scans, backups, and repair jobs',
'The dashboard keeps only a compact link card'
],
docsId: 'dashboard'
},
'.nav-button[data-page="playlist-explorer"]': {
title: 'Playlist Explorer',
description: 'Visual exploration tool for playlists. Browse album art grids or full discographies from any playlist source. Select tracks to add to wishlist or download directly.',
@ -238,7 +208,7 @@ const HELPER_CONTENT = {
'#watchlist-button': {
title: 'Watchlist',
description: 'Artists you\'re following for new releases. Click to open the Watchlist page, where SoulSync scans for new albums and singles and sends matches to your Wishlist for download.',
description: 'Artists you\'re following for new releases. SoulSync periodically scans for new albums and singles from these artists and adds them to your Wishlist for download.',
tips: [
'Add artists from the Artists page or Library page',
'Badge shows total watched artist count',
@ -249,10 +219,10 @@ const HELPER_CONTENT = {
},
'#wishlist-button': {
title: 'Wishlist',
description: 'Tracks queued for download. Click to open the Wishlist page, where failed downloads, watchlist discoveries, and manual adds all land for retry.',
description: 'Tracks queued for download. Failed downloads, watchlist new releases, and manually added tracks all land here. Process the wishlist to retry downloads.',
tips: [
'Badge shows total wishlist track count',
'Use the page to manage all pending tracks in one place',
'Click to open the wishlist modal with all pending tracks',
'Process All starts downloading every wishlist item',
'Tracks can be added manually or arrive from failed batch downloads'
],