vm-bench/frontend/templates/job_polling.html
Claus Lohmar b000641827 feat: unified configure page — VM settings + multi-disk selection with per-disk shrink
- New /session/configure/{analysis_id} page with VM config + disk table
- Each disk has radio (boot selection) + shrink checkbox + size input
- Per-disk shrink control — check to enable, set custom size
- Disks sorted smallest first, boot disk pre-selected as largest
- Submit via /session/configure/submit, then /session/status/{job_id} polling
- Landpage download/SCP flow redirects to configure after analysis completes
2026-07-27 10:22:39 +00:00

97 lines
No EOL
3.5 KiB
HTML

{% extends "base.html" %}
{% block content %}
<div class="pve-panel pve-center">
<div class="pve-panel-header">
<span class="pve-panel-title">Converting VM {{ vmid or '...' }}</span>
</div>
<div class="pve-panel-body">
<p class="pve-dim">Job: <span class="pve-code">{{ job_id }}</span> &nbsp;|&nbsp; {{ vm_name }}</p>
<div id="status-badge" class="pve-badge pve-badge-queued">
<span class="pve-spinner"></span> Queued
</div>
<div class="pve-progress">
<div class="pve-progress-bar" id="pve-progress-bar" style="width:0%">0%</div>
</div>
<p id="status-message" class="pve-dim">Waiting for backend...</p>
<p id="elapsed" class="pve-dim">Elapsed: 0s</p>
<div id="error-block" class="pve-alert pve-alert-error pve-hidden"></div>
</div>
</div>
<div id="reuse-section" class="pve-panel pve-hidden">
<div class="pve-panel-header">
<span class="pve-panel-title">Conversion Complete — VM {{ vmid or '...' }} Ready</span>
</div>
<div class="pve-panel-body">
<p style="margin-bottom:1rem;">Create another VM from this disk?</p>
<button id="btn-cleanup" class="pve-btn" onclick="finishCleanup()">Clean Up &amp; Finish</button>
</div>
</div>
<script>
var jobId = '{{ job_id }}';
var startTime = Date.now();
var completed = false;
function finishCleanup() {
fetch('/session/cleanup/' + jobId, { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ delete_staging_files: true, session_id: '{{ session_id }}' }) });
window.location.href = '/';
}
async function poll() {
try {
var resp = await fetch('/session/status/' + jobId);
var data = await resp.json();
var pct = data.progress_percentage || 0;
var fill = document.getElementById('pve-progress-bar');
if (fill) { fill.style.width = pct + '%'; fill.textContent = pct + '%'; }
var elMsg = document.getElementById('status-message');
if (elMsg) elMsg.textContent = data.message || '';
document.getElementById('elapsed').textContent = 'Elapsed: ' + Math.round((Date.now() - startTime) / 1000) + 's';
var badge = document.getElementById('status-badge');
var map = {
'queued': ['pve-badge pve-badge-queued', 'Queued'],
'processing_conversion': ['pve-badge pve-badge-running', 'Converting...'],
'importing_storage': ['pve-badge pve-badge-running', 'Importing...'],
'completed': ['pve-badge pve-badge-completed', 'Completed'],
'failed': ['pve-badge pve-badge-failed', 'Failed']
};
var clsText = map[data.status] || ['pve-badge pve-badge-queued', data.status];
if (badge) {
badge.className = 'badge ' + clsText[0];
badge.innerHTML = (data.status === 'processing_conversion' || data.status === 'importing_storage')
? '<span class="pve-spinner"></span> ' + clsText[1] : clsText[1];
}
if (data.error_details) {
var eb = document.getElementById('error-block');
if (eb) { eb.classList.remove('pve-hidden'); eb.textContent = data.error_details; }
}
if (data.status === 'completed' || data.status === 'failed') {
completed = true;
if (data.status === 'completed') {
var rs = document.getElementById('reuse-section');
if (rs) { rs.classList.remove('pve-hidden'); rs.scrollIntoView({ behavior: 'smooth' }); }
}
return;
}
} catch (err) {
var eb = document.getElementById('error-block');
if (eb) { eb.classList.remove('pve-hidden'); eb.textContent = 'Polling error: ' + err.message; }
}
if (!completed) setTimeout(poll, 2000);
}
setTimeout(poll, 3000);
</script>
{% endblock %}