mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-08 12:36:52 +03:00
141 lines
3.4 KiB
HTML
141 lines
3.4 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
|
<title>Backup/Restore Configuration</title>
|
|
<meta charset="utf-8">
|
|
|
|
<style>
|
|
h1 {font-size: 2em;}
|
|
h2 {font-size: 1.5em;}
|
|
h3 {font-size: 1.2em;}
|
|
p {font-size: 1em;}
|
|
|
|
input[type=number] {
|
|
width: 138px;
|
|
padding: 10px 5px;
|
|
display: inline-block;
|
|
border: 1px solid #ccc;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.button {
|
|
padding: 10px 20px;
|
|
width: 211px;
|
|
font-size: 16px;
|
|
}
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body style="font-family: arial; padding: 0px 10px;">
|
|
<h2>Backup Configuration</h2>
|
|
<p>With the following action the <a href="/fileserver/config/" target="_self">config</a> folder on the SD-card gets zipped and provided as a download.</p>
|
|
|
|
<table border="0">
|
|
</tr>
|
|
<td>
|
|
<button class="button" id="doBackup" type="button" onclick="doBackup()">Create Config backup</button>
|
|
</td>
|
|
<td>
|
|
<p id=progress></p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<hr>
|
|
<h2>Restore Configuration</h2>
|
|
<p>Use the <a href="/fileserver/config/" target="_self">File Server</a> to upload individual files.</p>
|
|
</body>
|
|
|
|
|
|
<script src="jszip.min.js"></script>
|
|
<script src="FileSaver.min.js"></script>
|
|
<script>
|
|
|
|
function doBackup() {
|
|
document.getElementById("progress").innerHTML = "Creating backup...";
|
|
|
|
// Get hostname
|
|
try {
|
|
var xhttp = new XMLHttpRequest();
|
|
xhttp.open("GET", "/version?type=Hostname", false);
|
|
xhttp.send();
|
|
hostname = xhttp.responseText;
|
|
}
|
|
catch(err) {
|
|
alert("Failed to fetch hostname: " + err.message);
|
|
return;
|
|
}
|
|
|
|
// get date/time
|
|
var dateTime = new Date().toJSON().slice(0,10) + "_" + new Date().toJSON().slice(11,19).replaceAll(":", "-");
|
|
|
|
zipFilename = hostname + "_" + dateTime + ".zip";
|
|
console.log(zipFilename);
|
|
|
|
// Get files list
|
|
try {
|
|
var xhttp = new XMLHttpRequest();
|
|
xhttp.open("GET", "/fileserver/config/", false);
|
|
xhttp.send();
|
|
|
|
var parser = new DOMParser();
|
|
var content = parser.parseFromString(xhttp.responseText, 'text/html'); }
|
|
catch(err) {
|
|
alert("Failed to fetch files list: " + err.message);
|
|
return;
|
|
}
|
|
|
|
const list = content.querySelectorAll("a");
|
|
|
|
var urls = [];
|
|
|
|
for (a of list) {
|
|
url = a.getAttribute("href");
|
|
urls.push(url);
|
|
}
|
|
|
|
// Pack as zip and download
|
|
try {
|
|
saveZip(zipFilename, urls);
|
|
}
|
|
catch(err) {
|
|
alert("Failed to zip files: " + err.message);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
const saveZip = (filename, urls) => {
|
|
if(!urls) return;
|
|
|
|
const zip = new JSZip();
|
|
const folder = zip.folder("");
|
|
|
|
var i = 0;
|
|
urls.forEach((url) => {
|
|
const blobPromise = fetch(url).then((r) => {
|
|
if (r.status === 200) return r.blob();
|
|
return Promise.reject(new Error(r.statusText));
|
|
});
|
|
const name = url.substring(url.lastIndexOf("/") + 1);
|
|
folder.file(name, blobPromise);
|
|
});
|
|
|
|
zip.generateAsync({ type: "blob" },
|
|
function updateCallback(metadata) {
|
|
var msg = "Progress: " + metadata.percent.toFixed(0) + "%";
|
|
if(metadata.currentFile) {
|
|
msg += ", " + metadata.currentFile;
|
|
}
|
|
|
|
console.log(msg);
|
|
document.getElementById("progress").innerHTML = msg;
|
|
}
|
|
).then((blob) => saveAs(blob, filename));
|
|
};
|
|
|
|
</script>
|
|
|
|
</html>
|