- Added detection of 'already have the latest version' scenario - Implemented proper handling when no update is available with friendly message - Added cache busting parameters to ensure fresh data from server - Enhanced test mode toggle to properly check real update status - Added specific handling for the case where update script runs but no update is needed - Improved logging to show actual update check response - Modified reload mechanics to force cache refresh with timestamp parameter - Added special handling to avoid unnecessary page reloads 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
645 lines
25 KiB
JavaScript
645 lines
25 KiB
JavaScript
/**
|
|
* 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() {
|
|
// Add cache-busting parameter
|
|
const cacheBuster = `?_=${new Date().getTime()}`;
|
|
fetch('/api/system/status' + cacheBuster, {
|
|
headers: authHeaders()
|
|
})
|
|
.then(handleResponse)
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
// Update version display
|
|
versionElement.textContent = data.data.version;
|
|
uptimeElement.textContent = data.data.uptime;
|
|
|
|
// Also update footer version
|
|
const footerVersion = document.getElementById('footer-version');
|
|
if (footerVersion) {
|
|
footerVersion.textContent = 'v' + data.data.version;
|
|
}
|
|
|
|
// Update version in about modal too if it exists
|
|
const aboutVersionElement = document.getElementById('about-version');
|
|
if (aboutVersionElement) {
|
|
aboutVersionElement.textContent = 'Transmission RSS Manager v' + data.data.version;
|
|
}
|
|
|
|
// Update transmission status with icon
|
|
if (data.data.transmissionStatus === 'Connected') {
|
|
transmissionStatusElement.innerHTML = '<i class="fas fa-check-circle text-success"></i> Connected';
|
|
} else {
|
|
transmissionStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> 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');
|
|
});
|
|
}
|
|
|
|
// More robust update check status tracking
|
|
const UPDATE_KEY = 'trm_update_available';
|
|
const CURRENT_VERSION_KEY = 'trm_current_version';
|
|
const REMOTE_VERSION_KEY = 'trm_remote_version';
|
|
let updateCheckInProgress = false;
|
|
|
|
// Function to show update alert
|
|
function showUpdateAlert(currentVersion, remoteVersion) {
|
|
// Set status text in the system status panel
|
|
updateStatusElement.innerHTML = '<i class="fas fa-exclamation-circle text-warning"></i> Update available';
|
|
|
|
// Try to show the original alert box, but don't rely on it
|
|
try {
|
|
const alertBox = updateAvailableDiv.querySelector('.alert');
|
|
if (alertBox) {
|
|
alertBox.style.display = 'block';
|
|
const spanElement = alertBox.querySelector('span');
|
|
if (spanElement) {
|
|
spanElement.textContent = `A new version is available: ${currentVersion} → ${remoteVersion}`;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error('Error showing original alert box:', e);
|
|
}
|
|
|
|
// Show the floating notification (our new approach)
|
|
try {
|
|
const floatingNotification = document.getElementById('floating-update-notification');
|
|
if (floatingNotification) {
|
|
// Set text
|
|
const versionElement = document.getElementById('floating-update-version');
|
|
if (versionElement) {
|
|
versionElement.textContent = `Version ${currentVersion} → ${remoteVersion}`;
|
|
}
|
|
|
|
// Show with inline styles to force display
|
|
floatingNotification.style.display = 'block';
|
|
|
|
// Make absolutely sure it's visible
|
|
floatingNotification.setAttribute('style',
|
|
'display: block !important; ' +
|
|
'visibility: visible !important; ' +
|
|
'opacity: 1 !important; ' +
|
|
'position: fixed !important; ' +
|
|
'top: 20px !important; ' +
|
|
'right: 20px !important; ' +
|
|
'width: 300px !important; ' +
|
|
'padding: 15px !important; ' +
|
|
'background-color: #ff5555 !important; ' +
|
|
'color: white !important; ' +
|
|
'border: 3px solid #cc0000 !important; ' +
|
|
'border-radius: 5px !important; ' +
|
|
'box-shadow: 0 0 20px rgba(0,0,0,0.5) !important; ' +
|
|
'z-index: 10000 !important; ' +
|
|
'font-weight: bold !important; ' +
|
|
'text-align: center !important;'
|
|
);
|
|
|
|
// Set up update button click handler
|
|
const updateButton = document.getElementById('floating-update-button');
|
|
if (updateButton) {
|
|
// Remove any existing listeners
|
|
updateButton.removeEventListener('click', applyUpdate);
|
|
// Add new listener
|
|
updateButton.addEventListener('click', applyUpdate);
|
|
}
|
|
|
|
console.log('Floating update notification shown:', currentVersion, '->', remoteVersion);
|
|
} else {
|
|
console.error('Floating notification element not found!');
|
|
}
|
|
} catch (e) {
|
|
console.error('Error showing floating notification:', e);
|
|
}
|
|
|
|
// Store in localStorage
|
|
localStorage.setItem(UPDATE_KEY, 'true');
|
|
localStorage.setItem(CURRENT_VERSION_KEY, currentVersion);
|
|
localStorage.setItem(REMOTE_VERSION_KEY, remoteVersion);
|
|
}
|
|
|
|
// Function to hide update alert
|
|
function hideUpdateAlert() {
|
|
// Hide original alert
|
|
try {
|
|
const alertBox = updateAvailableDiv.querySelector('.alert');
|
|
if (alertBox) {
|
|
alertBox.style.display = 'none';
|
|
}
|
|
} catch (e) {
|
|
console.error('Error hiding original alert:', e);
|
|
}
|
|
|
|
// Hide floating notification
|
|
try {
|
|
const floatingNotification = document.getElementById('floating-update-notification');
|
|
if (floatingNotification) {
|
|
floatingNotification.style.display = 'none';
|
|
}
|
|
} catch (e) {
|
|
console.error('Error hiding floating notification:', e);
|
|
}
|
|
|
|
// Clear localStorage
|
|
localStorage.removeItem(UPDATE_KEY);
|
|
localStorage.removeItem(CURRENT_VERSION_KEY);
|
|
localStorage.removeItem(REMOTE_VERSION_KEY);
|
|
}
|
|
|
|
// Check localStorage on init and set up MutationObserver to prevent hiding
|
|
(function checkStoredUpdateStatus() {
|
|
const isUpdateAvailable = localStorage.getItem(UPDATE_KEY) === 'true';
|
|
if (isUpdateAvailable) {
|
|
const currentVersion = localStorage.getItem(CURRENT_VERSION_KEY);
|
|
const remoteVersion = localStorage.getItem(REMOTE_VERSION_KEY);
|
|
if (currentVersion && remoteVersion) {
|
|
showUpdateAlert(currentVersion, remoteVersion);
|
|
|
|
// Set up mutation observer to detect and revert any attempts to hide the update alert
|
|
const alertBox = updateAvailableDiv.querySelector('.alert');
|
|
if (alertBox) {
|
|
const observer = new MutationObserver(function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
if (mutation.type === 'attributes' &&
|
|
(mutation.attributeName === 'style' ||
|
|
mutation.attributeName === 'class')) {
|
|
|
|
// If display is being changed to hide the element, force it back to visible
|
|
if (alertBox.style.display !== 'block' ||
|
|
alertBox.classList.contains('d-none') ||
|
|
alertBox.style.visibility === 'hidden' ||
|
|
alertBox.style.opacity === '0') {
|
|
|
|
console.log('Detected attempt to hide update button, forcing display');
|
|
showUpdateAlert(currentVersion, remoteVersion);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Observe style and class attribute changes
|
|
observer.observe(alertBox, {
|
|
attributes: true,
|
|
attributeFilter: ['style', 'class']
|
|
});
|
|
|
|
// Store observer in window object to prevent garbage collection
|
|
window._updateButtonObserver = observer;
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
|
|
// Check for updates
|
|
function checkForUpdates() {
|
|
updateStatusElement.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> Checking...';
|
|
updateCheckInProgress = true;
|
|
|
|
// Add test=true parameter to force update availability for testing
|
|
const testMode = localStorage.getItem('showUpdateButton') === 'true';
|
|
const cacheBuster = `_=${new Date().getTime()}`;
|
|
const url = testMode
|
|
? `/api/system/check-updates?test=true&${cacheBuster}`
|
|
: `/api/system/check-updates?${cacheBuster}`;
|
|
|
|
// Set a timeout to detect network issues
|
|
const timeoutId = setTimeout(() => {
|
|
updateStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> Check timed out';
|
|
updateCheckInProgress = false;
|
|
showNotification('Update check timed out. Please try again later.', 'warning');
|
|
}, 10000); // 10 second timeout
|
|
|
|
// Create a timeout controller
|
|
const controller = new AbortController();
|
|
const timeoutId2 = setTimeout(() => controller.abort(), 15000);
|
|
|
|
fetch(url, {
|
|
headers: authHeaders(),
|
|
// Add a fetch timeout using abort controller
|
|
signal: controller.signal // 15 second timeout
|
|
})
|
|
.then(response => {
|
|
clearTimeout(timeoutId2);
|
|
clearTimeout(timeoutId);
|
|
return response;
|
|
})
|
|
.catch(error => {
|
|
clearTimeout(timeoutId2);
|
|
clearTimeout(timeoutId);
|
|
throw error;
|
|
})
|
|
.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 => {
|
|
updateCheckInProgress = false;
|
|
|
|
if (data.status === 'success') {
|
|
if (data.data && data.data.updateAvailable) {
|
|
// Show update alert with version info
|
|
showUpdateAlert(data.data.currentVersion, data.data.remoteVersion);
|
|
|
|
// Log to console for debugging
|
|
console.log('Update available detected:', data.data.currentVersion, '->', data.data.remoteVersion);
|
|
} else {
|
|
// No update available
|
|
updateStatusElement.innerHTML = '<i class="fas fa-check-circle text-success"></i> Up to date';
|
|
hideUpdateAlert();
|
|
}
|
|
} else {
|
|
// Error status but with a response
|
|
updateStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> Check failed';
|
|
showNotification(data.message || 'Failed to check for updates', 'danger');
|
|
// Don't clear update status on error - keep any previous update notification
|
|
}
|
|
})
|
|
.catch(error => {
|
|
updateCheckInProgress = false;
|
|
clearTimeout(timeoutId);
|
|
console.error('Error checking for updates:', error);
|
|
updateStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> 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');
|
|
}
|
|
|
|
// Don't clear update status on error - keep any previous update notification
|
|
});
|
|
}
|
|
|
|
// 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 on both update buttons
|
|
// Original button
|
|
if (updateButton) {
|
|
updateButton.disabled = true;
|
|
updateButton.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> Updating...';
|
|
}
|
|
|
|
// Floating notification button
|
|
const floatingButton = document.getElementById('floating-update-button');
|
|
if (floatingButton) {
|
|
floatingButton.disabled = true;
|
|
floatingButton.textContent = 'Updating...';
|
|
}
|
|
|
|
showNotification('Applying update. Please wait...', 'info');
|
|
|
|
// Set a timeout for the update process
|
|
const updateTimeoutId = setTimeout(() => {
|
|
// Re-enable original button
|
|
if (updateButton) {
|
|
updateButton.disabled = false;
|
|
updateButton.innerHTML = '<i class="fas fa-download"></i> Update Now';
|
|
}
|
|
|
|
// Re-enable floating button
|
|
if (floatingButton) {
|
|
floatingButton.disabled = false;
|
|
floatingButton.textContent = 'Update Now';
|
|
}
|
|
|
|
showNotification('Update process timed out. Please try again or check server logs.', 'warning');
|
|
}, 60000); // 60 second timeout for the entire update process
|
|
|
|
// Create a timeout controller
|
|
const updateController = new AbortController();
|
|
const updateTimeoutId2 = setTimeout(() => updateController.abort(), 45000);
|
|
|
|
fetch('/api/system/update', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...authHeaders()
|
|
},
|
|
signal: updateController.signal // 45 second timeout
|
|
})
|
|
.then(response => {
|
|
clearTimeout(updateTimeoutId2);
|
|
return response;
|
|
})
|
|
.catch(error => {
|
|
clearTimeout(updateTimeoutId2);
|
|
throw error;
|
|
})
|
|
.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') {
|
|
// Check if there's an update message to determine if an update was actually applied
|
|
const updateApplied = data.message && data.message.includes('Update applied successfully');
|
|
const noNewUpdate = data.data && data.data.output && data.data.output.includes('already have the latest version');
|
|
|
|
// Hide update notification
|
|
hideUpdateAlert();
|
|
|
|
if (noNewUpdate) {
|
|
// If no update was needed, show a different message
|
|
showNotification('You already have the latest version. No update was needed.', 'info');
|
|
|
|
// Re-enable both buttons
|
|
if (updateButton) {
|
|
updateButton.disabled = false;
|
|
updateButton.innerHTML = '<i class="fas fa-download"></i> Check Again';
|
|
}
|
|
|
|
const floatingButton = document.getElementById('floating-update-button');
|
|
if (floatingButton) {
|
|
floatingButton.disabled = false;
|
|
floatingButton.textContent = 'Check Again';
|
|
}
|
|
|
|
// Update page to show current version without reloading
|
|
loadSystemStatus();
|
|
return;
|
|
}
|
|
|
|
// Show success notification
|
|
showNotification('Update applied successfully. The page will reload in 30 seconds.', 'success');
|
|
|
|
// Update both buttons with countdown
|
|
let secondsLeft = 30;
|
|
|
|
// Function to update the countdown text
|
|
function updateCountdown() {
|
|
// Update original button if it exists
|
|
if (updateButton) {
|
|
updateButton.innerHTML = `<i class="fas fa-sync"></i> Reloading in ${secondsLeft}s...`;
|
|
}
|
|
|
|
// Update floating button if it exists
|
|
const floatingButton = document.getElementById('floating-update-button');
|
|
if (floatingButton) {
|
|
floatingButton.textContent = `Reloading in ${secondsLeft}s...`;
|
|
}
|
|
}
|
|
|
|
// Initial text update
|
|
updateCountdown();
|
|
|
|
// Start countdown
|
|
const countdownInterval = setInterval(() => {
|
|
secondsLeft--;
|
|
updateCountdown();
|
|
|
|
if (secondsLeft <= 0) {
|
|
clearInterval(countdownInterval);
|
|
|
|
// Clear localStorage to ensure a clean reload
|
|
localStorage.removeItem(UPDATE_KEY);
|
|
localStorage.removeItem(CURRENT_VERSION_KEY);
|
|
localStorage.removeItem(REMOTE_VERSION_KEY);
|
|
|
|
// Force a clean reload
|
|
window.location.href = window.location.href.split('#')[0] + '?t=' + new Date().getTime();
|
|
}
|
|
}, 1000);
|
|
|
|
// Set a timer to reload the page after the service has time to restart
|
|
setTimeout(() => {
|
|
clearInterval(countdownInterval);
|
|
|
|
// Clear localStorage to ensure a clean reload
|
|
localStorage.removeItem(UPDATE_KEY);
|
|
localStorage.removeItem(CURRENT_VERSION_KEY);
|
|
localStorage.removeItem(REMOTE_VERSION_KEY);
|
|
|
|
// Force a clean reload with cache-busting parameter
|
|
window.location.href = window.location.href.split('#')[0] + '?t=' + new Date().getTime();
|
|
}, 30000);
|
|
} else {
|
|
// Enable both buttons on failure
|
|
if (updateButton) {
|
|
updateButton.disabled = false;
|
|
updateButton.innerHTML = '<i class="fas fa-download"></i> Update Now';
|
|
}
|
|
|
|
const floatingButton = document.getElementById('floating-update-button');
|
|
if (floatingButton) {
|
|
floatingButton.disabled = false;
|
|
floatingButton.textContent = 'Update Now';
|
|
}
|
|
|
|
showNotification(data.message || 'Failed to apply update', 'danger');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
clearTimeout(updateTimeoutId);
|
|
console.error('Error applying update:', error);
|
|
|
|
// Re-enable both buttons on error
|
|
if (updateButton) {
|
|
updateButton.disabled = false;
|
|
updateButton.innerHTML = '<i class="fas fa-download"></i> Update Now';
|
|
}
|
|
|
|
const floatingButton = document.getElementById('floating-update-button');
|
|
if (floatingButton) {
|
|
floatingButton.disabled = false;
|
|
floatingButton.textContent = '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';
|
|
|
|
if (newSetting) {
|
|
// If enabling test mode, force show update button
|
|
showUpdateAlert('2.0.10', '2.1.0-test');
|
|
updateStatusElement.innerHTML = '<i class="fas fa-exclamation-circle text-warning"></i> Update available';
|
|
showNotification('Test update button enabled', 'info');
|
|
} else {
|
|
// If disabling test mode, check for real updates
|
|
hideUpdateAlert();
|
|
|
|
// Force a check without the test parameter to get real status
|
|
const realCheckUrl = '/api/system/check-updates';
|
|
fetch(realCheckUrl, { headers: authHeaders() })
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
console.log('Real update check result:', data);
|
|
if (data.status === 'success' && data.data && !data.data.updateAvailable) {
|
|
showNotification('No actual updates are available.', 'info');
|
|
} else if (data.status === 'success' && data.data && data.data.updateAvailable) {
|
|
showUpdateAlert(data.data.currentVersion, data.data.remoteVersion);
|
|
showNotification(`A real update is available: ${data.data.currentVersion} → ${data.data.remoteVersion}`, 'info');
|
|
}
|
|
})
|
|
.catch(error => console.error('Error checking for real updates:', error));
|
|
|
|
showNotification('Test update button disabled', 'info');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Persistent update button - force display every second if update is available
|
|
function forceShowUpdateButton() {
|
|
const isUpdateAvailable = localStorage.getItem(UPDATE_KEY) === 'true';
|
|
|
|
if (isUpdateAvailable) {
|
|
const currentVersion = localStorage.getItem(CURRENT_VERSION_KEY);
|
|
const remoteVersion = localStorage.getItem(REMOTE_VERSION_KEY);
|
|
|
|
if (currentVersion && remoteVersion) {
|
|
// Check floating notification
|
|
const floatingNotification = document.getElementById('floating-update-notification');
|
|
if (floatingNotification && floatingNotification.style.display !== 'block') {
|
|
console.log('Forcing floating update notification display');
|
|
|
|
// Set the version text
|
|
const versionElement = document.getElementById('floating-update-version');
|
|
if (versionElement) {
|
|
versionElement.textContent = `Version ${currentVersion} → ${remoteVersion}`;
|
|
}
|
|
|
|
// Apply strong styling
|
|
floatingNotification.setAttribute('style',
|
|
'display: block !important; ' +
|
|
'visibility: visible !important; ' +
|
|
'opacity: 1 !important; ' +
|
|
'position: fixed !important; ' +
|
|
'top: 20px !important; ' +
|
|
'right: 20px !important; ' +
|
|
'width: 300px !important; ' +
|
|
'padding: 15px !important; ' +
|
|
'background-color: #ff5555 !important; ' +
|
|
'color: white !important; ' +
|
|
'border: 3px solid #cc0000 !important; ' +
|
|
'border-radius: 5px !important; ' +
|
|
'box-shadow: 0 0 20px rgba(0,0,0,0.5) !important; ' +
|
|
'z-index: 10000 !important; ' +
|
|
'font-weight: bold !important; ' +
|
|
'text-align: center !important;'
|
|
);
|
|
|
|
// Ensure button has correct event handler
|
|
const updateButton = document.getElementById('floating-update-button');
|
|
if (updateButton) {
|
|
// Remove any existing listeners
|
|
updateButton.removeEventListener('click', applyUpdate);
|
|
// Add new listener
|
|
updateButton.addEventListener('click', applyUpdate);
|
|
}
|
|
}
|
|
|
|
// Still try the original alert as a fallback
|
|
try {
|
|
const alertBox = updateAvailableDiv.querySelector('.alert');
|
|
if (alertBox && alertBox.style.display !== 'block') {
|
|
alertBox.style.display = 'block';
|
|
updateAvailableDiv.style.display = 'block';
|
|
|
|
// Update message
|
|
const spanElement = alertBox.querySelector('span');
|
|
if (spanElement) {
|
|
spanElement.textContent = `A new version is available: ${currentVersion} → ${remoteVersion}`;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error('Error forcing original update button:', e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
loadSystemStatus();
|
|
checkForUpdates();
|
|
|
|
// Force check the update button status every second
|
|
setInterval(forceShowUpdateButton, 1000);
|
|
|
|
// Set interval to refresh uptime every minute
|
|
setInterval(loadSystemStatus, 60000);
|
|
} |