Add build cancellation feature to cloud-init process</message>

<message>Implement a new API endpoint for cancelling ongoing cloud-init builds, allowing users to request a build cancellation via the dashboard. Update the dashboard UI to include a cancel button that appears during the build process, enhancing user experience by providing control over long-running operations. Modify the build script to check for cancellation requests, ensuring that builds can be stopped gracefully. This feature improves usability and responsiveness in the cloud-init image building workflow.
This commit is contained in:
nearxos
2026-02-23 10:21:06 +02:00
parent e13ad3d8f9
commit ec973cc2b3
5 changed files with 90 additions and 2 deletions

View File

@@ -76,7 +76,10 @@
<span class="mono" style="font-size:0.85rem; margin-left:0.25rem;">+ date suffix</span>
</div>
<div style="margin-bottom:0.5rem;"><label><input type="checkbox" id="buildSetGolden" /> Set as golden after build</label></div>
<div style="margin-bottom:0.75rem;"><button type="button" id="buildCloudInitBtn" class="btn btn-primary">Download &amp; build</button></div>
<div style="margin-bottom:0.75rem;">
<button type="button" id="buildCloudInitBtn" class="btn btn-primary">Download &amp; build</button>
<button type="button" id="buildCloudInitCancelBtn" class="btn btn-outline" style="display:none; margin-left:0.5rem;">Cancel build</button>
</div>
<div id="buildCloudInitStatus" class="mono" style="min-height:1.2em;"></div>
</div>
@@ -136,15 +139,27 @@
authFetch('/api/build-cloudinit-status').then(function(r) { return r.json(); }).then(function(d) {
var el = document.getElementById('buildCloudInitStatus');
var btn = document.getElementById('buildCloudInitBtn');
var cancelBtn = document.getElementById('buildCloudInitCancelBtn');
var busy = ['resolving','downloading','decompressing','injecting','finalizing'].indexOf(d.phase) >= 0;
if (btn) btn.disabled = busy;
if (cancelBtn) { cancelBtn.style.display = busy ? 'inline-block' : 'none'; cancelBtn.disabled = false; }
if (d.phase === 'idle' && !d.message) el.textContent = '';
else if (d.phase === 'done') { el.textContent = 'Done: ' + (d.output_name || '') + ' — see Admin page Cloud-init images.'; }
else if (d.phase === 'error') el.textContent = 'Error: ' + (d.error || '');
else if (d.phase === 'cancelled') el.textContent = 'Build cancelled.';
else el.textContent = (d.phase || '') + ': ' + (d.message || '');
if (busy) setTimeout(fetchBuildStatus, 5000);
}).catch(function() {});
}
function cancelBuild() {
var cancelBtn = document.getElementById('buildCloudInitCancelBtn');
if (cancelBtn) cancelBtn.disabled = true;
document.getElementById('buildCloudInitStatus').textContent = 'Cancelling…';
authFetch('/api/build-cloudinit-cancel', { method: 'POST', headers: {'Content-Type':'application/json'} }).then(function(r) { return r.json(); }).then(function(d) {
if (d.ok) setTimeout(fetchBuildStatus, 2000);
else { alert(d.error || 'Cancel failed'); if (cancelBtn) cancelBtn.disabled = false; }
}).catch(function() { if (cancelBtn) cancelBtn.disabled = false; });
}
function startBuild() {
var btn = document.getElementById('buildCloudInitBtn');
if (btn) btn.disabled = true;
@@ -211,6 +226,8 @@
}
document.getElementById('buildCloudInitBtn').onclick = startBuild;
var cancelBuildBtn = document.getElementById('buildCloudInitCancelBtn');
if (cancelBuildBtn) cancelBuildBtn.onclick = cancelBuild;
document.getElementById('buildVariant').onchange = function() {
authFetch('/api/raspios-latest-url?variant=' + encodeURIComponent(document.getElementById('buildVariant').value)).then(function(r) { return r.json(); }).then(function(d) {
document.getElementById('buildRaspiosUrl').textContent = (d.ok && d.filename) ? d.filename : (d.error || '');