diff --git a/src/public/js/ui/alertManagementModal.js b/src/public/js/ui/alertManagementModal.js index 87216f4b9..8b843cb67 100644 --- a/src/public/js/ui/alertManagementModal.js +++ b/src/public/js/ui/alertManagementModal.js @@ -1,12 +1,86 @@ PulseApp.ui = PulseApp.ui || {}; PulseApp.ui.alertManagementModal = (() => { + // Constants + const TIMEOUTS = { + SHORT: 1000, + MEDIUM: 2000, + LONG: 3000, + REFRESH: 2000 + }; + + const VALIDATION = { + MIN_DURATION_MS: 5000, + MAX_DURATION_MS: 3600000, + MIN_THRESHOLD: 1, + MAX_THRESHOLD: 100 + }; + + const DEFAULTS = { + THRESHOLD_CPU: 85, + THRESHOLD_MEMORY: 85, + THRESHOLD_DISK: 85, + THRESHOLD_TEMPERATURE: 70, + THRESHOLD_IOWAIT: 50, + SMTP_PORT: 587, + SMTP_PORT_STRING: '587' + }; + + const TIME_UNITS = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000, + DAY: 24 * 60 * 60 * 1000 + }; + let isInitialized = false; let activeTab = 'alerts'; let currentConfig = {}; let formDataCache = {}; let isLoading = false; let refreshInterval = null; + + // DOM element cache + const domCache = {}; + + // Event listener tracking + const eventListeners = []; + + function getElement(id) { + if (!domCache[id]) { + domCache[id] = document.getElementById(id); + } + return domCache[id]; + } + + function clearDomCache() { + Object.keys(domCache).forEach(key => delete domCache[key]); + } + + function addTrackedEventListener(element, event, handler, options) { + if (!element) return; + element.addEventListener(event, handler, options); + eventListeners.push({ element, event, handler, options }); + } + + function removeAllEventListeners() { + eventListeners.forEach(({ element, event, handler, options }) => { + if (element) { + element.removeEventListener(event, handler, options); + } + }); + eventListeners.length = 0; + } + + // Common error handling function + function handleError(component, error, userMessage) { + console.error(`[${component}] ${error.message || error}`); + if (userMessage) { + PulseApp.ui.toast.error(userMessage); + } else { + PulseApp.ui.toast.error(`Error in ${component}: ${error.message || 'Unknown error'}`); + } + } function init() { if (isInitialized) return; @@ -29,7 +103,7 @@ PulseApp.ui.alertManagementModal = (() => { coordinatedRefresh(); } } catch (error) { - console.error('[Alert Modal] Error handling alert event:', error); + handleError('Alert Modal', error, null); } }); @@ -69,7 +143,7 @@ PulseApp.ui.alertManagementModal = (() => { if (isModalOpen()) { coordinatedRefresh(); } - }, 2000); + }, TIMEOUTS.MEDIUM); isInitialized = true; } @@ -117,7 +191,7 @@ PulseApp.ui.alertManagementModal = (() => { function openModal() { - const modal = document.getElementById('alert-management-modal'); + const modal = getElement('alert-management-modal'); if (modal) { modal.classList.remove('hidden'); modal.classList.add('flex'); @@ -130,7 +204,7 @@ PulseApp.ui.alertManagementModal = (() => { if (isModalOpen()) { coordinatedRefresh(); } - }, 2000); + }, TIMEOUTS.MEDIUM); } } } @@ -152,10 +226,13 @@ PulseApp.ui.alertManagementModal = (() => { // Reset state isLoading = false; + + // Remove all tracked event listeners + removeAllEventListeners(); } function closeModal() { - const modal = document.getElementById('alert-management-modal'); + const modal = getElement('alert-management-modal'); if (modal) { modal.classList.add('hidden'); modal.classList.remove('flex'); @@ -163,10 +240,13 @@ PulseApp.ui.alertManagementModal = (() => { // Clean up resources to prevent memory leaks cleanup(); + + // Clear DOM cache when modal closes + clearDomCache(); } function createModalHTML() { - const existingModal = document.getElementById('alert-management-modal'); + const existingModal = getElement('alert-management-modal'); if (existingModal) { existingModal.remove(); } @@ -224,21 +304,21 @@ PulseApp.ui.alertManagementModal = (() => { } function setupEventListeners() { - const modal = document.getElementById('alert-management-modal'); - const closeButton = document.getElementById('alert-management-modal-close'); - const cancelButton = document.getElementById('alert-management-cancel-button'); + const modal = getElement('alert-management-modal'); + const closeButton = getElement('alert-management-modal-close'); + const cancelButton = getElement('alert-management-cancel-button'); if (closeButton) { closeButton.addEventListener('click', closeModal); } if (cancelButton) { - cancelButton.addEventListener('click', closeModal); + addTrackedEventListener(cancelButton, 'click', closeModal); } // Close modal when clicking outside if (modal) { - modal.addEventListener('click', (e) => { + addTrackedEventListener(modal, 'click', (e) => { if (e.target === modal) { closeModal(); } @@ -246,11 +326,12 @@ PulseApp.ui.alertManagementModal = (() => { } // Handle escape key - document.addEventListener('keydown', (e) => { + const escapeHandler = (e) => { if (e.key === 'Escape' && modal && !modal.classList.contains('hidden')) { closeModal(); } - }); + }; + addTrackedEventListener(document, 'keydown', escapeHandler); // Set up tab navigation setupTabNavigation(); @@ -329,11 +410,15 @@ PulseApp.ui.alertManagementModal = (() => { loadEmailConfiguration(); await loadGlobalToggles(); }, 100); + }).catch(error => { + handleError('Configure Tab', error, 'Failed to load configuration'); }); } } catch (error) { console.error('[Alert Modal] Error rendering configure tab:', error); - modalBody.innerHTML = '

Error loading configure tab: ' + error.message + '

'; + modalBody.innerHTML = '

Error loading configure tab:

'; + const errorSpan = modalBody.querySelector('#error-message'); + if (errorSpan) errorSpan.textContent = error.message; } break; default: @@ -526,7 +611,7 @@ PulseApp.ui.alertManagementModal = (() => {
- +
@@ -538,6 +623,33 @@ PulseApp.ui.alertManagementModal = (() => {
+ +
+
+ + + +
+

Email Provider Setup Guides

+

Most email providers require app-specific passwords for security. Follow these guides to set up your email:

+ +
+
+
+