fix: SCP polling page now shows reuse section + clone/copy/cleanup buttons work

This commit is contained in:
Claus Lohmar 2026-07-27 07:33:05 +00:00
parent 9bab8e95a1
commit 631f08fc31

View file

@ -228,9 +228,25 @@ function scpInitPolling() {
const container = document.getElementById('polling-container'); const container = document.getElementById('polling-container');
if (!container) return; if (!container) return;
const jobId = container.dataset.jobId; const jobId = container.dataset.jobId;
const vmid = container.dataset.vmid;
const sourceFilename = container.dataset.sourceFilename;
const startTime = Date.now(); const startTime = Date.now();
var completed = false; var completed = false;
document.getElementById('btn-clone').onclick = () => scpCloneVM(jobId, vmid);
document.getElementById('btn-cleanup').onclick = () => {
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 = '/';
};
document.getElementById('btn-copy').onclick = () => {
document.getElementById('copy-options').classList.remove('pve-hidden');
};
var prev = parseInt(vmid) || 21000;
document.getElementById('reuse-vmid').value = prev + 1;
document.getElementById('reuse-vmname').value = (sourceFilename.split('.')[0] || 'vm') + '-2';
document.getElementById('btn-copy-start').onclick = () => scpCopyVM(jobId, vmid, sourceFilename);
async function poll() { async function poll() {
try { try {
const resp = await fetch('/session/status/' + jobId); const resp = await fetch('/session/status/' + jobId);
@ -240,18 +256,67 @@ function scpInitPolling() {
if (fill) { fill.style.width = pct + '%'; fill.textContent = pct + '%'; } if (fill) { fill.style.width = pct + '%'; fill.textContent = pct + '%'; }
var elMsg = document.getElementById('status-message'); var elMsg = document.getElementById('status-message');
if (elMsg) elMsg.textContent = data.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 badge = document.getElementById('status-badge');
if (badge) { if (badge) {
if (data.status === 'completed') { badge.className = 'pve-badge pve-badge-completed'; badge.textContent = 'Completed'; } if (data.status === 'completed') { badge.className = 'pve-badge pve-badge-completed'; badge.textContent = 'Completed'; }
else if (data.status === 'failed') { badge.className = 'pve-badge pve-badge-failed'; badge.textContent = 'Failed'; } else if (data.status === 'failed') { badge.className = 'pve-badge pve-badge-failed'; badge.textContent = 'Failed'; }
else { badge.className = 'pve-badge pve-badge-running'; badge.innerHTML = '<span class="pve-spinner"></span> Processing'; } else { badge.className = 'pve-badge pve-badge-running'; badge.innerHTML = '<span class="pve-spinner"></span> ' + (data.status === 'queued' ? 'Queued' : 'Processing'); }
}
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;
} }
if (data.status === 'completed' || data.status === 'failed') { completed = true; return; }
} catch (err) {} } catch (err) {}
if (!completed) _scpPollTimer = setTimeout(poll, 2000); if (!completed) _scpPollTimer = setTimeout(poll, 2000);
} }
_scpPollTimer = setTimeout(poll, 3000); _scpPollTimer = setTimeout(poll, 3000);
} }
async function scpCloneVM(jobId, sourceVmid) {
var newVmid = parseInt(document.getElementById('reuse-vmid').value) || 0;
var newName = document.getElementById('reuse-vmname').value.trim();
if (!newVmid || !newName) { alert('Please fill VM Name and ID.'); return; }
var status = document.getElementById('reuse-submit-status');
status.classList.remove('pve-hidden');
status.innerHTML = '<div class="pve-spinner"></div> Cloning VM...';
try {
var resp = await fetch('/session/clone', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ source_vmid: sourceVmid, target_vmid: newVmid, target_name: newName }) });
var data = await resp.json();
status.innerHTML = data.status === 'completed' ? '<div class="pve-alert pve-alert-success">VM ' + newVmid + ' cloned!</div>' : '<div class="pve-alert pve-alert-error">Clone failed: ' + (data.error_details || 'Unknown') + '</div>';
} catch (err) { status.innerHTML = '<div class="pve-alert pve-alert-error">Clone failed: ' + err.message + '</div>'; }
}
async function scpCopyVM(jobId, vmid, sourceFilename) {
var newVmid = parseInt(document.getElementById('reuse-vmid').value) || 0;
var newName = document.getElementById('reuse-vmname').value.trim();
if (!newVmid || !newName) { alert('Please fill VM Name and ID.'); return; }
var status = document.getElementById('copy-status');
status.classList.remove('pve-hidden');
status.innerHTML = '<div class="pve-spinner"></div> Submitting job...';
var payload = new FormData();
payload.append('vmid', newVmid); payload.append('vm_name', newName);
payload.append('source_filename', sourceFilename);
payload.append('disk_format', 'vmdk');
payload.append('cpu_cores', document.getElementById('copy-cores').value || '2');
payload.append('ram_mb', document.getElementById('copy-ram').value || '4096');
payload.append('target_storage', document.getElementById('copy-storage').value || 'local-lvm');
var diskGb = document.getElementById('copy-disk').value;
if (diskGb) payload.append('target_disk_size_gb', diskGb);
payload.append('auto_detect_boot', 'true');
payload.append('boot_type', 'legacy');
payload.append('session_id', SESSION_ID);
try {
var resp = await fetch('/session/confirm', { method: 'POST', body: payload });
document.getElementById('scp-analysis-section').innerHTML = await resp.text();
scpInitPolling();
} catch (err) { status.innerHTML = '<div class="pve-alert pve-alert-error">Failed: ' + err.message + '</div>'; }
}
</script> </script>
{% endblock %} {% endblock %}