From d70d2d1b69cdb1e8729450a7cff247c78b85a0c2 Mon Sep 17 00:00:00 2001 From: JohnBaumb <80135794+JohnBaumb@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:59:00 -0700 Subject: [PATCH] fix: make Download Manager a clickable link in all processing toasts --- webui/static/discover.js | 13 +----------- webui/static/downloads.js | 40 +++++++++++++++++++++++++++++++++--- webui/static/media-player.js | 2 +- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/webui/static/discover.js b/webui/static/discover.js index 376c14f8..195957ee 100644 --- a/webui/static/discover.js +++ b/webui/static/discover.js @@ -9295,18 +9295,7 @@ async function _doSyncDiscoverPlaylist(playlistType, playlistName) { const result = await batchResponse.json(); if (result.success) { - // Custom toast with clickable link to Downloads page - const _toastMsg = `${playlistName}: analyzing ${syncTracks.length} tracks...`; - const _toastContainer = document.getElementById('toast-container'); - if (_toastContainer) { - const _t = document.createElement('div'); - _t.className = 'toast-compact toast-info'; - _t.innerHTML = `${_toastMsg} View progress — missing tracks will be downloaded.`; - _t.onclick = () => { _t.classList.add('toast-exit'); setTimeout(() => { if (_toastContainer.contains(_t)) _toastContainer.removeChild(_t); }, 200); }; - _toastContainer.appendChild(_t); - requestAnimationFrame(() => _t.classList.add('toast-enter')); - setTimeout(() => { if (_toastContainer.contains(_t)) { _t.classList.add('toast-exit'); setTimeout(() => { if (_toastContainer.contains(_t)) _toastContainer.removeChild(_t); }, 300); } }, 6000); - } + showToastHtml(`${_escToast(playlistName)} processing started. View progress in Download Manager.`); const card = document.getElementById(`discover-sync-card-${playlistType}`); if (card) { const statusEl = card.querySelector('.discover-sync-status'); diff --git a/webui/static/downloads.js b/webui/static/downloads.js index ce20e659..db6d3686 100644 --- a/webui/static/downloads.js +++ b/webui/static/downloads.js @@ -1220,7 +1220,7 @@ function startWishlistCountdownTimer(currentCycle, initialSeconds) { if (data.is_auto_processing) { if (!_wishlistAutoProcessingNotified) { navigateToPage('active-downloads'); - showToast('Wishlist auto-processing started. View progress in Download Manager.', 'info'); + showToastHtml('Wishlist auto-processing started. View progress in Download Manager.'); _wishlistAutoProcessingNotified = true; } return; @@ -1243,7 +1243,7 @@ function startWishlistCountdownTimer(currentCycle, initialSeconds) { if (!_wishlistAutoProcessingNotified) { console.log('🤖 [Wishlist] Auto-processing detected, closing overview modal'); closeWishlistOverviewModal(); - showToast('Wishlist auto-processing started. View progress in Download Manager.', 'info'); + showToastHtml('Wishlist auto-processing started. View progress in Download Manager.'); _wishlistAutoProcessingNotified = true; } return; // Exit interval @@ -2222,7 +2222,7 @@ async function startWishlistMissingTracksProcess(playlistId) { // Special handling for auto-processing conflict if (response.status === 409) { console.log('🤖 [Wishlist] Auto-processing is running, redirecting to download manager'); - showToast('Wishlist auto-processing is already running. Opening Download Manager...', 'info'); + showToastHtml('Wishlist auto-processing is already running. Opening Download Manager...'); // Close wishlist modal and show download manager const wishlistModal = document.getElementById('download-modal-wishlist'); @@ -4838,6 +4838,40 @@ function showToast(message, type = 'success', helpSection = null) { function _escToast(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; } function _escAttr(s) { return _escToast(s).replace(/'/g, "\\'").replace(/\n/g, ' ').replace(/\r/g, ''); } +/** Show a toast with raw HTML content (for inline links). Also adds to notification history. */ +function showToastHtml(html, type = 'info', duration = 6000) { + const container = document.getElementById('toast-container'); + if (!container) return; + // Add to notification history (strip tags for plain text) + const tmp = document.createElement('div'); tmp.innerHTML = html; + const plainText = tmp.textContent || tmp.innerText || ''; + const entry = { id: Date.now() + Math.random(), message: plainText, type, helpSection: null, timestamp: Date.now(), read: false }; + _notifState.history.unshift(entry); + if (_notifState.history.length > _notifState.maxHistory) _notifState.history.pop(); + _notifState.unreadCount++; + _updateNotifBadge(); + + if (_notifState.currentToast && container.contains(_notifState.currentToast)) { + _notifState.currentToast.classList.add('toast-exit'); + const old = _notifState.currentToast; + setTimeout(() => { if (container.contains(old)) container.removeChild(old); }, 200); + } + if (_notifState.toastTimer) clearTimeout(_notifState.toastTimer); + + const icon = _notifIcons[type] || '\u2139'; + const toast = document.createElement('div'); + toast.className = `toast-compact toast-${type}`; + toast.innerHTML = `${icon}${html}`; + toast.onclick = () => { toast.classList.add('toast-exit'); setTimeout(() => { if (container.contains(toast)) container.removeChild(toast); }, 200); }; + container.appendChild(toast); + requestAnimationFrame(() => toast.classList.add('toast-enter')); + _notifState.currentToast = toast; + _notifState.toastTimer = setTimeout(() => { + if (container.contains(toast)) { toast.classList.add('toast-exit'); setTimeout(() => { if (container.contains(toast)) container.removeChild(toast); }, 300); } + _notifState.currentToast = null; + }, duration); +} + function _updateNotifBadge() { const badge = document.getElementById('notif-bell-badge'); if (badge) { diff --git a/webui/static/media-player.js b/webui/static/media-player.js index 85f25796..e082d1cb 100644 --- a/webui/static/media-player.js +++ b/webui/static/media-player.js @@ -488,7 +488,7 @@ function updateWishlistStatsFromData(data) { if (data.is_auto_processing) { if (!_wishlistAutoProcessingNotified) { if (currentPage === 'wishlist') navigateToPage('active-downloads'); - showToast('Wishlist auto-processing started. View progress in Download Manager.', 'info'); + showToastHtml('Wishlist auto-processing started. View progress in Download Manager.'); _wishlistAutoProcessingNotified = true; } return;