Update documentation and scripts for revision tracking and cloud-init enhancements</message>

<message>Introduce a revision tracking system across project files, allowing for easier identification of changes. Update the README files to include instructions for bumping revisions and auto-bumping on commits. Additionally, enhance cloud-init scripts with revision comments for better version control. Modify the dashboard API to improve build status management, including a forced clear option for stuck statuses, enhancing user experience and operational reliability.
This commit is contained in:
nearxos
2026-02-23 10:38:24 +02:00
parent 5f05663706
commit 55b8661a2e
27 changed files with 162 additions and 7 deletions

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# Revision: 2
"""
Flask dashboard for CM4 eMMC provisioning.
Public home: deploy only (status, logs, how to connect). No login.
@@ -1632,10 +1633,12 @@ def api_build_cloudinit_cancel():
@app.route("/api/build-cloudinit-status-clear", methods=["POST"])
@require_admin
def api_build_cloudinit_status_clear():
"""Clear build status to idle (so message is cleared after cancel/done/error)."""
"""Clear build status to idle (so message is cleared after cancel/done/error).
Use ?force=1 to clear even when status is stuck (e.g. build died during finalizing)."""
st = _build_status_read()
force = request.args.get("force") in ("1", "true", "yes")
busy = st.get("phase") in ("downloading", "decompressing", "injecting", "finalizing", "resolving")
if busy:
if busy and not force:
return jsonify({"ok": False, "error": "Cannot clear while build is in progress"}), 409
_build_status_write("idle", "", None, None)
return jsonify({"ok": True})

View File

@@ -1,4 +1,5 @@
<!DOCTYPE html>
<!-- Revision: 2 -->
<html lang="en">
<head>
<meta charset="UTF-8">

View File

@@ -1,4 +1,5 @@
<!DOCTYPE html>
<!-- Revision: 2 -->
<html lang="en">
<head>
<meta charset="UTF-8">
@@ -155,7 +156,7 @@
if (!window._buildClearScheduled) {
window._buildClearScheduled = true;
setTimeout(function() {
authFetch('/api/build-cloudinit-status-clear', { method: 'POST', headers: {'Content-Type':'application/json'} }).then(function() { fetchBuildStatus(); }).finally(function() { window._buildClearScheduled = false; });
authFetch('/api/build-cloudinit-status-clear?force=1', { method: 'POST', headers: {'Content-Type':'application/json'} }).then(function() { fetchBuildStatus(); }).finally(function() { window._buildClearScheduled = false; });
}, 3000);
}
} else {
@@ -243,7 +244,7 @@
var cancelBuildBtn = document.getElementById('buildCloudInitCancelBtn');
if (cancelBuildBtn) cancelBuildBtn.onclick = cancelBuild;
var dismissBuildBtn = document.getElementById('buildCloudInitDismiss');
if (dismissBuildBtn) dismissBuildBtn.onclick = function(e) { e.preventDefault(); authFetch('/api/build-cloudinit-status-clear', { method: 'POST', headers: {'Content-Type':'application/json'} }).then(function() { fetchBuildStatus(); }); };
if (dismissBuildBtn) dismissBuildBtn.onclick = function(e) { e.preventDefault(); authFetch('/api/build-cloudinit-status-clear?force=1', { method: 'POST', headers: {'Content-Type':'application/json'} }).then(function() { fetchBuildStatus(); }); };
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 || '');

View File

@@ -1,4 +1,5 @@
<!DOCTYPE html>
<!-- Revision: 2 -->
<html lang="en">
<head>
<meta charset="UTF-8">

View File

@@ -1,4 +1,5 @@
<!DOCTYPE html>
<!-- Revision: 2 -->
<html lang="en">
<head>
<meta charset="UTF-8">
@@ -916,7 +917,7 @@
if (!window._buildClearScheduled) {
window._buildClearScheduled = true;
setTimeout(function() {
fetch('/api/build-cloudinit-status-clear', { method: 'POST', headers: { 'Content-Type': 'application/json' } }).then(function() { fetchBuildStatus(); }).finally(function() { window._buildClearScheduled = false; });
fetch('/api/build-cloudinit-status-clear?force=1', { method: 'POST', headers: { 'Content-Type': 'application/json' } }).then(function() { fetchBuildStatus(); }).finally(function() { window._buildClearScheduled = false; });
}, 3000);
}
} else {
@@ -1024,7 +1025,7 @@
var cancelBuildBtn = document.getElementById('buildCloudInitCancelBtn');
if (cancelBuildBtn) cancelBuildBtn.onclick = cancelBuildCloudInit;
var dismissBuildBtn = document.getElementById('buildCloudInitDismiss');
if (dismissBuildBtn) dismissBuildBtn.onclick = function(e) { e.preventDefault(); fetch('/api/build-cloudinit-status-clear', { method: 'POST', headers: { 'Content-Type': 'application/json' } }).then(function() { fetchBuildStatus(); }); };
if (dismissBuildBtn) dismissBuildBtn.onclick = function(e) { e.preventDefault(); fetch('/api/build-cloudinit-status-clear?force=1', { method: 'POST', headers: { 'Content-Type': 'application/json' } }).then(function() { fetchBuildStatus(); }); };
var variantSel = document.getElementById('buildVariant');
if (variantSel) variantSel.onchange = fetchRaspiosUrl;
var templateLoadBtn = document.getElementById('buildTemplateLoad');

View File

@@ -1,4 +1,5 @@
<!DOCTYPE html>
<!-- Revision: 2 -->
<html lang="en">
<head>
<meta charset="UTF-8">

View File

@@ -1,4 +1,5 @@
<!DOCTYPE html>
<!-- Revision: 2 -->
<html lang="en">
<head>
<meta charset="UTF-8">