wrolpi/etc/raspberrypios/maintenance.html
Roland a1e0fb4e92 Creating a new Collection model for use in organizing FileGroups.
Replacing Channels and Domains with Collection.

Moving downloading relationships from Channel to Collection.

Created domains.yaml config to manage tagged domain collections.

Adding turn-key upgrade solution in the UI.
2025-12-06 15:11:37 -07:00

189 lines
5.3 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WROLPi - Upgrade in Progress</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
color: #333;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 50%, #dde4ed 100%);
}
.container {
text-align: center;
padding: 2rem;
max-width: 500px;
width: 90%;
}
.logo {
font-size: 3rem;
margin-bottom: 1rem;
}
h1 {
color: #5829bb;
font-size: 1.8rem;
margin-bottom: 0.5rem;
font-weight: 600;
}
.subtitle {
color: #666;
font-size: 1rem;
margin-bottom: 2rem;
}
.spinner-container {
margin: 2rem 0;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid #ddd;
border-top: 4px solid #4CAF50;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.status {
font-size: 1.1rem;
margin: 1.5rem 0;
min-height: 1.5em;
}
.elapsed {
color: #666;
font-size: 0.9rem;
margin-top: 1rem;
}
.warning {
background: rgba(255, 193, 7, 0.1);
border: 1px solid rgba(255, 193, 7, 0.3);
border-radius: 8px;
padding: 1rem;
margin-top: 2rem;
font-size: 0.9rem;
color: #b38600;
}
.success {
color: #4CAF50;
}
.check-icon {
font-size: 3rem;
color: #4CAF50;
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.5); }
to { opacity: 1; transform: scale(1); }
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="container">
<div class="logo">WROLPi</div>
<h1>Upgrade in Progress</h1>
<p class="subtitle">Please wait while your system is being upgraded</p>
<div class="spinner-container" id="spinnerContainer">
<div class="spinner"></div>
</div>
<div class="spinner-container hidden" id="successContainer">
<div class="check-icon">&#10003;</div>
</div>
<p class="status" id="status">Checking upgrade status...</p>
<p class="elapsed" id="elapsed">Elapsed: 0:00</p>
<div class="warning">
<strong>Do not power off</strong> your device or close this window during the upgrade.
</div>
</div>
<script>
const startTime = Date.now();
let pollInterval;
let elapsedInterval;
function updateElapsed() {
const elapsed = Math.floor((Date.now() - startTime) / 1000);
const minutes = Math.floor(elapsed / 60);
const seconds = elapsed % 60;
document.getElementById('elapsed').textContent =
`Elapsed: ${minutes}:${seconds.toString().padStart(2, '0')}`;
}
function showSuccess() {
document.getElementById('spinnerContainer').classList.add('hidden');
document.getElementById('successContainer').classList.remove('hidden');
}
async function checkApiStatus() {
try {
const response = await fetch('/api/status', {
method: 'GET',
headers: { 'Accept': 'application/json' },
// Short timeout to avoid long waits
signal: AbortSignal.timeout(5000)
});
if (response.ok) {
// API is back online!
clearInterval(pollInterval);
clearInterval(elapsedInterval);
showSuccess();
document.getElementById('status').innerHTML =
'<span class="success">Upgrade complete! Redirecting...</span>';
// Redirect to home after a short delay
setTimeout(() => {
window.location.href = '/';
}, 2000);
}
} catch (e) {
// API is still down or timeout - this is expected during upgrade
document.getElementById('status').textContent = 'Upgrade in progress...';
}
}
// Update elapsed time every second
elapsedInterval = setInterval(updateElapsed, 1000);
// Check API status every 3 seconds
pollInterval = setInterval(checkApiStatus, 3000);
// Initial check
checkApiStatus();
</script>
</body>
</html>