diff --git a/frontend/templates/scp.html b/frontend/templates/scp.html index 75caf9c..69e7445 100644 --- a/frontend/templates/scp.html +++ b/frontend/templates/scp.html @@ -228,9 +228,25 @@ function scpInitPolling() { const container = document.getElementById('polling-container'); if (!container) return; const jobId = container.dataset.jobId; + const vmid = container.dataset.vmid; + const sourceFilename = container.dataset.sourceFilename; const startTime = Date.now(); 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() { try { const resp = await fetch('/session/status/' + jobId); @@ -240,18 +256,67 @@ function scpInitPolling() { 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'); if (badge) { 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 { badge.className = 'pve-badge pve-badge-running'; badge.innerHTML = ' Processing'; } + else { badge.className = 'pve-badge pve-badge-running'; badge.innerHTML = ' ' + (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) {} if (!completed) _scpPollTimer = setTimeout(poll, 2000); } _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 = '
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' ? '