diff --git a/containers/libreportal/frontend/core/notifications/js/notifications.js b/containers/libreportal/frontend/core/notifications/js/notifications.js index a8b2ce4..acb70b0 100755 --- a/containers/libreportal/frontend/core/notifications/js/notifications.js +++ b/containers/libreportal/frontend/core/notifications/js/notifications.js @@ -356,6 +356,36 @@ window.removeNotification = (notificationId) => { } }; +// Navigate without dropping the SPA. Returns true when the router took it. +// +// The fallbacks below used to assign window.location.href, which is a FULL page +// load: the app re-boots, every panel re-fetches, and any open state is lost — +// for a button whose whole job is "show me that task". It fired more often than +// it looks, because the branches above only handle two situations (already on an +// app page WITH an app name, or already on /tasks). A "View Task" for a +// system-wide task carries no app name, and its /tasks// target keeps +// the id in the PATH rather than a ?task= query, so from the dashboard or the +// App Center every one of those guards missed and the reload was the outcome. +// +// The router handles the same URL perfectly well: tasks-manager reads the +// category and task id straight out of the path on mount, so /tasks/all/ +// arrives with that task already highlighted. location.href stays as the last +// resort for when the router genuinely is not there. +const _notifyNavigate = (url) => { + try { + if (window.spaClean && typeof window.spaClean.navigate === 'function') { + // navigate() wants a same-origin PATH; the incoming value may be absolute. + const u = new URL(url, window.location.origin); + if (u.origin !== window.location.origin) return false; // never route off-site + window.spaClean.navigate(u.pathname + u.search); + return true; + } + } catch (e) { + console.warn('SPA navigation failed, falling back to a page load:', e); + } + return false; +}; + window.handleNotificationNavigation = (url) => { try { console.log('🔗 handleNotificationNavigation called with URL:', url); @@ -472,14 +502,16 @@ window.handleNotificationNavigation = (url) => { } } - // If we get here and no managers were available, fallback - console.warn('⚠️ Falling back to page reload for URL:', url); + // No manager matched this URL — hand it to the router rather than reloading. + if (_notifyNavigate(url)) return true; + console.warn('⚠️ No SPA router available; falling back to a page load for URL:', url); window.location.href = url; return false; } catch (error) { console.error('❌ Error handling notification navigation:', error); - // Fallback to direct navigation if parsing fails - console.warn('⚠️ Falling back to page reload due to error for URL:', url); + // Parsing failed, but the router can still take the raw URL. + if (_notifyNavigate(url)) return true; + console.warn('⚠️ Falling back to a page load due to error for URL:', url); window.location.href = url; return false; }