Files
Provisioning/internal/web/static/app.js
T
josh 0bf1a62897
build-and-push / test (push) Successful in 37s
build-and-push / build-and-push (push) Successful in 1m18s
Redesign frontend with clean light theme and design system
Replace prototype dark theme with a professional light-theme design
using Outfit (UI) and IBM Plex Mono (data) fonts, navy topbar, white
card surfaces, and a full CSS variable system for colors, shadows,
spacing, and radii. Add LED status indicators, panel components,
and structured tile layout with header/meta/footer sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-10 22:00:53 -04:00

119 lines
3.7 KiB
JavaScript

(function() {
var dot = document.getElementById('sse-dot');
var es;
function connect() {
es = new EventSource('/events');
es.addEventListener('hello', function() {
dot.className = 'led led-green';
});
es.addEventListener('host.state_changed', function() {
window.location.reload();
});
es.onerror = function() {
dot.className = 'led led-red';
es.close();
setTimeout(connect, 3000);
};
}
connect();
})();
(function() {
var form = document.getElementById('upload-form');
if (!form) return;
var uploadId = 'upload-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
document.getElementById('upload-id').value = uploadId;
var progressDiv = document.getElementById('upload-progress');
var progressFill = document.getElementById('progress-fill');
var progressTitle = document.getElementById('progress-title');
var progressText = document.getElementById('progress-text');
var progressDetail = document.getElementById('progress-detail');
var uploadES = new EventSource('/events');
uploadES.addEventListener('image.upload_progress', function(e) {
var data;
try { data = JSON.parse(e.data); } catch(_) { return; }
if (data.upload_id !== uploadId) return;
progressText.textContent = data.detail;
if (data.stage === 'parsing' || data.stage === 'extracting') {
progressTitle.textContent = 'Extracting boot files...';
progressDetail.textContent = 'Processing ISO on server...';
}
if (data.stage === 'complete') {
progressFill.classList.add('complete');
progressTitle.textContent = 'Complete';
progressDetail.textContent = 'Redirecting...';
}
});
form.addEventListener('submit', function(e) {
e.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
form.style.display = 'none';
progressDiv.style.display = 'block';
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(ev) {
if (ev.lengthComputable) {
var pct = Math.round((ev.loaded / ev.total) * 100);
progressFill.style.width = pct + '%';
var mb = (ev.loaded / (1024 * 1024)).toFixed(1);
var totalMb = (ev.total / (1024 * 1024)).toFixed(1);
progressText.textContent = 'Uploading: ' + mb + ' / ' + totalMb + ' MB (' + pct + '%)';
}
});
xhr.upload.addEventListener('load', function() {
progressTitle.textContent = 'Processing ISO...';
progressText.textContent = 'Upload complete. Extracting kernel and initrd...';
progressDetail.textContent = 'This may take a minute...';
});
xhr.addEventListener('load', function() {
uploadES.close();
var resp;
try { resp = JSON.parse(xhr.responseText); } catch(_) { resp = {}; }
if (xhr.status >= 200 && xhr.status < 300 && resp.ok) {
window.location.href = '/images';
} else {
progressDiv.style.display = 'none';
form.style.display = 'block';
showUploadError(resp.error || 'Upload failed');
}
});
xhr.addEventListener('error', function() {
uploadES.close();
progressDiv.style.display = 'none';
form.style.display = 'block';
showUploadError('Network error during upload');
});
xhr.open('POST', '/images/upload');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send(formData);
});
function showUploadError(msg) {
var errDiv = form.parentNode.querySelector('.error');
if (!errDiv) {
errDiv = document.createElement('div');
errDiv.className = 'error';
form.parentNode.insertBefore(errDiv, form);
}
errDiv.textContent = msg;
}
})();