diff --git a/status/js/container-logs.js b/status/js/container-logs.js index 88bac91..7abe28a 100644 --- a/status/js/container-logs.js +++ b/status/js/container-logs.js @@ -398,8 +398,10 @@ } }); - // Wire modal (close on backdrop click) - wireModal(modal, null, closeModal); + // Wire backdrop click to closeModal so the log stream stops too. + // (Can't use wireModal here — it only does modal.classList.remove('show') + // on backdrop click, which would leak the SSE/stream connection.) + modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); }); // Expose for use by service card buttons (grid.js calls openContainerLogsModal) window.openContainerLogsModal = function(containerId, containerName) { diff --git a/status/js/globals.js b/status/js/globals.js index 31d4642..1e0a72e 100644 --- a/status/js/globals.js +++ b/status/js/globals.js @@ -293,7 +293,15 @@ function closeModal(id) { function wireModal(modal, ...closeBtns) { if (!modal) return; modal.addEventListener('click', (e) => { if (e.target === modal) modal.classList.remove('show'); }); - closeBtns.forEach(btn => btn?.addEventListener('click', () => modal.classList.remove('show'))); + // Skip anything that isn't a real listener target. Without this guard, a + // single typo (e.g. passing a function or null instead of a button element) + // throws and aborts the rest of the calling module's init — which can take + // down license.js (FREE TIER badge), TOTP wiring, etc. + closeBtns.forEach(btn => { + if (btn && typeof btn.addEventListener === 'function') { + btn.addEventListener('click', () => modal.classList.remove('show')); + } + }); } /** Toast-style notification (replaces all alert() usage) */