/** * Transmission RSS Manager - System Status Module * @description Functionality for system status display and updates */ // System status and updates functionality function initSystemStatus() { // Elements const versionElement = document.getElementById('system-version'); const uptimeElement = document.getElementById('uptime'); const transmissionStatusElement = document.getElementById('transmission-status'); const updateStatusElement = document.getElementById('update-status'); const updateAvailableDiv = document.getElementById('update-available'); const updateButton = document.getElementById('btn-update-now'); const refreshButton = document.getElementById('btn-refresh-status'); // Load system status function loadSystemStatus() { fetch('/api/system/status', { headers: authHeaders() }) .then(handleResponse) .then(data => { if (data.status === 'success') { versionElement.textContent = data.data.version; uptimeElement.textContent = data.data.uptime; // Update transmission status with icon if (data.data.transmissionStatus === 'Connected') { transmissionStatusElement.innerHTML = ' Connected'; } else { transmissionStatusElement.innerHTML = ' Disconnected'; } } else { showNotification('Failed to load system status', 'danger'); } }) .catch(error => { console.error('Error fetching system status:', error); showNotification('Failed to connect to server', 'danger'); }); } // Check for updates function checkForUpdates() { updateStatusElement.innerHTML = ' Checking...'; updateAvailableDiv.classList.add('d-none'); // Add test=true parameter to force update availability for testing const testMode = localStorage.getItem('showUpdateButton') === 'true'; const url = testMode ? '/api/system/check-updates?test=true' : '/api/system/check-updates'; // Set a timeout to detect network issues const timeoutId = setTimeout(() => { updateStatusElement.innerHTML = ' Check timed out'; showNotification('Update check timed out. Please try again later.', 'warning'); }, 10000); // 10 second timeout fetch(url, { headers: authHeaders(), // Add a fetch timeout as well signal: AbortSignal.timeout(15000) // 15 second timeout (available in modern browsers) }) .then(response => { clearTimeout(timeoutId); // Better error checking if (!response.ok) { return response.json().then(data => { throw new Error(data.message || `Server error: ${response.status}`); }).catch(e => { if (e instanceof SyntaxError) { throw new Error(`Server error: ${response.status}`); } throw e; }); } return response.json(); }) .then(data => { if (data.status === 'success') { if (data.data && data.data.updateAvailable) { updateStatusElement.innerHTML = ' Update available'; updateAvailableDiv.classList.remove('d-none'); updateAvailableDiv.querySelector('span').textContent = `A new version is available: ${data.data.currentVersion} → ${data.data.remoteVersion}`; } else { updateStatusElement.innerHTML = ' Up to date'; } } else { // Error status but with a response updateStatusElement.innerHTML = ' Check failed'; showNotification(data.message || 'Failed to check for updates', 'danger'); } }) .catch(error => { clearTimeout(timeoutId); console.error('Error checking for updates:', error); updateStatusElement.innerHTML = ' Check failed'; // More specific error message based on the error type if (error.name === 'AbortError') { showNotification('Update check timed out. Please try again later.', 'warning'); } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) { showNotification('Network error. Please check your connection and try again.', 'danger'); } else { showNotification(error.message || 'Failed to connect to server', 'danger'); } }); } // Apply update function applyUpdate() { // Show confirmation dialog if (!confirm('Are you sure you want to update the application? The service will restart.')) { return; } // Show loading state updateButton.disabled = true; updateButton.innerHTML = ' Updating...'; showNotification('Applying update. Please wait...', 'info'); // Set a timeout for the update process const updateTimeoutId = setTimeout(() => { updateButton.disabled = false; updateButton.innerHTML = ' Update Now'; showNotification('Update process timed out. Please try again or check server logs.', 'warning'); }, 60000); // 60 second timeout for the entire update process fetch('/api/system/update', { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeaders() }, signal: AbortSignal.timeout(45000) // 45 second timeout }) .then(response => { // Better error checking if (!response.ok) { return response.json().then(data => { throw new Error(data.message || `Server error: ${response.status}`); }).catch(e => { if (e instanceof SyntaxError) { throw new Error(`Server error: ${response.status}`); } throw e; }); } return response.json(); }) .then(data => { clearTimeout(updateTimeoutId); if (data.status === 'success') { showNotification('Update applied successfully. The page will reload in 30 seconds.', 'success'); // Show a countdown to reload let secondsLeft = 30; updateButton.innerHTML = ` Reloading in ${secondsLeft}s...`; const countdownInterval = setInterval(() => { secondsLeft--; updateButton.innerHTML = ` Reloading in ${secondsLeft}s...`; if (secondsLeft <= 0) { clearInterval(countdownInterval); window.location.reload(); } }, 1000); // Set a timer to reload the page after the service has time to restart setTimeout(() => { clearInterval(countdownInterval); window.location.reload(); }, 30000); } else { updateButton.disabled = false; updateButton.innerHTML = ' Update Now'; showNotification(data.message || 'Failed to apply update', 'danger'); } }) .catch(error => { clearTimeout(updateTimeoutId); console.error('Error applying update:', error); updateButton.disabled = false; updateButton.innerHTML = ' Update Now'; // More specific error message based on the error type if (error.name === 'AbortError') { showNotification('Update request timed out. The server might still be processing the update.', 'warning'); } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) { showNotification('Network error. Please check your connection and try again.', 'danger'); } else { showNotification(error.message || 'Failed to connect to server', 'danger'); } }); } // Event listeners if (refreshButton) { refreshButton.addEventListener('click', () => { loadSystemStatus(); checkForUpdates(); }); } if (updateButton) { updateButton.addEventListener('click', applyUpdate); } // Test mode toggle (for developers) const testToggle = document.getElementById('toggle-test-update-button'); if (testToggle) { // Initialize based on current localStorage setting const isTestMode = localStorage.getItem('showUpdateButton') === 'true'; // Update toggle text testToggle.innerText = isTestMode ? 'Disable Test Update' : 'Enable Test Update'; // Add click handler testToggle.addEventListener('click', (e) => { e.preventDefault(); const currentSetting = localStorage.getItem('showUpdateButton') === 'true'; const newSetting = !currentSetting; localStorage.setItem('showUpdateButton', newSetting); testToggle.innerText = newSetting ? 'Disable Test Update' : 'Enable Test Update'; // Re-check for updates with new setting checkForUpdates(); showNotification(`Test update button ${newSetting ? 'enabled' : 'disabled'}`, 'info'); }); } // Initialize loadSystemStatus(); checkForUpdates(); // Set interval to refresh uptime every minute setInterval(loadSystemStatus, 60000); }