193 lines
6.8 KiB
HTML
193 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link rel="stylesheet" type="text/css" href="/css/nav.css">
|
|
<title>Firmware Upgrade</title>
|
|
<style>
|
|
.status-circle {
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
margin-right: 10px;
|
|
}
|
|
.connected { background-color: #4CAF50; }
|
|
.disconnected { background-color: #f44336; }
|
|
|
|
.container {
|
|
max-width: 600px;
|
|
margin: 20px auto;
|
|
padding: 20px;
|
|
background-color: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.version-info {
|
|
margin: 20px 0;
|
|
padding: 10px;
|
|
background-color: #f5f5f5;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.progress-box {
|
|
height: 200px;
|
|
margin: 20px 0;
|
|
padding: 10px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
overflow-y: auto;
|
|
font-family: monospace;
|
|
}
|
|
|
|
button {
|
|
background-color: #2196F3;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
|
|
button:disabled {
|
|
background-color: #cccccc;
|
|
cursor: not-allowed;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="navbar"></div>
|
|
<div class="container">
|
|
<h1>Firmware Upgrade</h1>
|
|
|
|
<div>
|
|
<span class="status-circle disconnected" id="status-indicator"></span>
|
|
<span id="connection-status">Disconnected</span>
|
|
</div>
|
|
|
|
<div class="version-info">
|
|
<p>Current Version: <span id="current-version">-</span></p>
|
|
<p>Latest Version: <span id="latest-version">-</span></p>
|
|
</div>
|
|
|
|
<div>
|
|
<button id="check-upgrades" onclick="checkUpdates()">Check for Upgrades</button>
|
|
<button id="start-upgrade" onclick="startUpdate()" disabled>Start upgrade</button>
|
|
</div>
|
|
|
|
<div class="progress-box" id="progress-log"></div>
|
|
</div>
|
|
|
|
<script>
|
|
// Load the navigation bar from an external HTML file and insert it into the page
|
|
fetch('/www/navbar.html')
|
|
.then(response => response.text())
|
|
.then(data => {
|
|
document.getElementById('navbar').innerHTML = data;
|
|
});
|
|
|
|
// Flag to track if a firmware upgrade is available
|
|
let updateAvailable = false;
|
|
|
|
// Updates the UI to show connection status
|
|
// Changes the color and text of the status indicator
|
|
function updateStatus(connected) {
|
|
const indicator = document.getElementById('status-indicator');
|
|
const status = document.getElementById('connection-status');
|
|
|
|
indicator.className = `status-circle ${connected ? 'connected' : 'disconnected'}`;
|
|
status.textContent = connected ? 'Connected' : 'Disconnected';
|
|
}
|
|
|
|
// Adds a message to the progress log box
|
|
// Auto-scrolls to the bottom to show latest messages
|
|
function log(message) {
|
|
const logBox = document.getElementById('progress-log');
|
|
logBox.innerHTML += `${message}<br>`;
|
|
logBox.scrollTop = logBox.scrollHeight;
|
|
}
|
|
|
|
// Checks for firmware updates by calling the server API
|
|
// Updates the UI with version information and enables/disables upgrade button
|
|
async function checkUpdates() {
|
|
const checkButton = document.getElementById('check-updates');
|
|
checkButton.disabled = true; // Disable button while checking
|
|
|
|
try {
|
|
const response = await fetch('/upgrade/check');
|
|
const data = await response.json();
|
|
|
|
// Upgrade version information in the UI
|
|
document.getElementById('current-version').textContent = data.currentVersion;
|
|
document.getElementById('latest-version').textContent = data.latestVersion;
|
|
|
|
// Enable/disable upgrade button based on availability
|
|
updateAvailable = data.updateAvailable;
|
|
document.getElementById('start-upgrade').disabled = !updateAvailable;
|
|
|
|
log(updateAvailable ? 'Upgrade available!' : 'No updates available');
|
|
} catch (error) {
|
|
log('Error checking for updates: ' + error);
|
|
} finally {
|
|
checkButton.disabled = false; // Re-enable button when done
|
|
}
|
|
}
|
|
|
|
// Initiates the firmware upgrade process
|
|
// Uses Server-Sent Events (SSE) to receive progress updates
|
|
async function startUpdate() {
|
|
const startButton = document.getElementById('start-upgrade');
|
|
const checkButton = document.getElementById('check-upgrades');
|
|
// Disable both buttons during upgrade
|
|
startButton.disabled = true;
|
|
checkButton.disabled = true;
|
|
|
|
try {
|
|
// Start the upgrade process
|
|
const response = await fetch('/upgrade/start', { method: 'POST' });
|
|
// Create SSE connection to receive progress updates
|
|
const eventSource = new EventSource('/upgrade/progress');
|
|
|
|
// Handle incoming progress messages
|
|
eventSource.onmessage = (event) => {
|
|
const data = JSON.parse(event.data);
|
|
log(data.message);
|
|
|
|
// If upgrade is complete, close connection and reload page
|
|
if (data.complete) {
|
|
eventSource.close();
|
|
log('Upgrade complete! Rebooting...');
|
|
setTimeout(() => window.location.reload(), 5000);
|
|
}
|
|
};
|
|
|
|
// Handle SSE connection errors
|
|
eventSource.onerror = () => {
|
|
eventSource.close();
|
|
log('Upgrade stream disconnected');
|
|
startButton.disabled = false;
|
|
checkButton.disabled = false;
|
|
};
|
|
|
|
} catch (error) {
|
|
log('Error starting upgrade: ' + error);
|
|
startButton.disabled = false;
|
|
checkButton.disabled = false;
|
|
}
|
|
}
|
|
|
|
// Poll server every 5 seconds to check if device is still connected
|
|
// Updates the status indicator accordingly
|
|
setInterval(async () => {
|
|
try {
|
|
const response = await fetch('/api/status');
|
|
updateStatus(response.ok);
|
|
} catch {
|
|
updateStatus(false);
|
|
}
|
|
}, 5000);
|
|
</script>
|
|
</body>
|
|
</html> |