mirror of
https://github.com/vdsm/virtual-dsm.git
synced 2026-08-28 11:56:03 +00:00
feat: Show progress while extracting DSM image (#1362)
This commit is contained in:
@@ -227,6 +227,8 @@ fi
|
||||
MSG="Extracting installation image..."
|
||||
info "Install: $MSG" && html "$MSG"
|
||||
|
||||
/run/progress.sh "$TMP" "$SIZE" "$MSG ([P])..." &
|
||||
|
||||
# Newer PAT files are normal tar archives; older encrypted/proprietary forms
|
||||
# require the bundled extractor as a compatibility fallback.
|
||||
if { tar tf "$PAT"; } >/dev/null 2>&1; then
|
||||
@@ -238,12 +240,15 @@ else
|
||||
{ (cd "$TMP" && python3 /run/extract.py -i "$PAT" -d 2>/run/extract.log); rc=$?; } || :
|
||||
|
||||
if (( rc != 0 )); then
|
||||
fKill "progress.sh"
|
||||
cat /run/extract.log
|
||||
error "Failed to extract PAT file, reason $rc" && exit 63
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
fKill "progress.sh"
|
||||
|
||||
MSG="Preparing system partition..."
|
||||
info "Install: $MSG" && html "$MSG"
|
||||
|
||||
|
||||
@@ -17,6 +17,68 @@ body {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#progress {
|
||||
width: 0;
|
||||
min-width: 250px;
|
||||
max-width: 80vw;
|
||||
height: 15px;
|
||||
overflow: hidden;
|
||||
margin: 20px auto 0;
|
||||
border-radius: 999px;
|
||||
background: rgba(0, 0, 0, 0.17);
|
||||
box-shadow:
|
||||
inset 0 1px 2px rgba(0, 0, 0, 0.22),
|
||||
0 1px 0 rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
#progress[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#progress-fill {
|
||||
position: relative;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
transition: width 0.25s ease;
|
||||
}
|
||||
|
||||
#progress-fill:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: -40%;
|
||||
width: 34%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0),
|
||||
rgba(189, 227, 255, 0.15) 25%,
|
||||
rgba(255, 255, 255, 0.70) 50%,
|
||||
rgba(189, 227, 255, 0.15) 75%,
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
animation: progress-sheen 1.9s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes progress-sheen {
|
||||
0% {
|
||||
left: -40%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
12% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
60%,
|
||||
100% {
|
||||
left: 112%;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
width: 98%;
|
||||
position: fixed;
|
||||
|
||||
@@ -259,6 +259,210 @@ function rememberStatus(msg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseSize(value, unit) {
|
||||
|
||||
var powers = {
|
||||
"B": 0,
|
||||
"KB": 1,
|
||||
"KIB": 1,
|
||||
"MB": 2,
|
||||
"MIB": 2,
|
||||
"GB": 3,
|
||||
"GIB": 3,
|
||||
"TB": 4,
|
||||
"TIB": 4,
|
||||
"PB": 5,
|
||||
"PIB": 5,
|
||||
"EB": 6,
|
||||
"EIB": 6
|
||||
};
|
||||
|
||||
unit = unit.toUpperCase();
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(powers, unit)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var bytes = Number(value) * Math.pow(1024, powers[unit]);
|
||||
|
||||
if (!Number.isFinite(bytes) || bytes < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function estimateProgress(bytes) {
|
||||
|
||||
var boundary = 512 * 1024 * 1024;
|
||||
var previousBoundary = 0;
|
||||
|
||||
while (bytes > boundary) {
|
||||
previousBoundary = boundary;
|
||||
boundary *= 2;
|
||||
}
|
||||
|
||||
if (previousBoundary === 0) {
|
||||
return Math.min(bytes / boundary * 100, 100);
|
||||
}
|
||||
|
||||
var rangeProgress =
|
||||
(bytes - previousBoundary) /
|
||||
(boundary - previousBoundary);
|
||||
|
||||
return 30 + Math.pow(rangeProgress, 2) * 70;
|
||||
}
|
||||
|
||||
function parseProgress(msg) {
|
||||
|
||||
var container = document.createElement("div");
|
||||
container.innerHTML = msg;
|
||||
|
||||
var walker = document.createTreeWalker(
|
||||
container,
|
||||
NodeFilter.SHOW_TEXT
|
||||
);
|
||||
|
||||
var node;
|
||||
var lastNode = null;
|
||||
|
||||
while ((node = walker.nextNode())) {
|
||||
if (node.nodeValue.trim() !== "") {
|
||||
lastNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lastNode) {
|
||||
return {
|
||||
message: msg,
|
||||
progress: null,
|
||||
size: null
|
||||
};
|
||||
}
|
||||
|
||||
var percentMatch = lastNode.nodeValue.match(
|
||||
/\s+\((\d+(?:\.\d+)?)%\)\s*$/
|
||||
);
|
||||
|
||||
if (percentMatch) {
|
||||
var progress = Number(percentMatch[1]);
|
||||
|
||||
if (Number.isFinite(progress) && progress >= 0 && progress <= 100) {
|
||||
lastNode.nodeValue = lastNode.nodeValue.slice(
|
||||
0,
|
||||
percentMatch.index
|
||||
);
|
||||
|
||||
return {
|
||||
message: container.innerHTML,
|
||||
progress: progress,
|
||||
size: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var sizeMatch = lastNode.nodeValue.match(
|
||||
/\s+\((\d+(?:\.\d+)?)\s+([KMGTPE]?i?B)\)\s*$/i
|
||||
);
|
||||
|
||||
if (sizeMatch) {
|
||||
var bytes = parseSize(sizeMatch[1], sizeMatch[2]);
|
||||
|
||||
if (bytes != null) {
|
||||
var size = sizeMatch[1] + " " + sizeMatch[2];
|
||||
|
||||
return {
|
||||
message: msg,
|
||||
progress: estimateProgress(bytes),
|
||||
size: size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
message: msg,
|
||||
progress: null,
|
||||
size: null
|
||||
};
|
||||
}
|
||||
|
||||
function resizeProgress() {
|
||||
|
||||
var info = document.getElementById("info");
|
||||
var progress = document.getElementById("progress");
|
||||
|
||||
if (!info || !progress || progress.hidden) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var style = window.getComputedStyle(info);
|
||||
var measurement = document.createElement("span");
|
||||
|
||||
measurement.textContent = info.innerText;
|
||||
measurement.style.position = "fixed";
|
||||
measurement.style.left = "-9999px";
|
||||
measurement.style.top = "-9999px";
|
||||
measurement.style.visibility = "hidden";
|
||||
measurement.style.whiteSpace = "nowrap";
|
||||
measurement.style.fontFamily = style.fontFamily;
|
||||
measurement.style.fontSize = style.fontSize;
|
||||
measurement.style.fontWeight = style.fontWeight;
|
||||
measurement.style.fontStyle = style.fontStyle;
|
||||
measurement.style.letterSpacing = style.letterSpacing;
|
||||
measurement.style.textTransform = style.textTransform;
|
||||
|
||||
document.body.appendChild(measurement);
|
||||
|
||||
var textWidth = measurement.getBoundingClientRect().width;
|
||||
var loading = info.getElementsByClassName("loading").length > 0;
|
||||
var dotsWidth = 0;
|
||||
|
||||
if (loading) {
|
||||
dotsWidth = parseFloat(style.fontSize) * 0.75;
|
||||
}
|
||||
|
||||
measurement.remove();
|
||||
|
||||
var maximumWidth = window.innerWidth * 0.8;
|
||||
var width = Math.min(textWidth + dotsWidth + 100, maximumWidth);
|
||||
|
||||
progress.style.width = width + "px";
|
||||
progress.style.transform = loading
|
||||
? "translateX(" + (dotsWidth / 2) + "px)"
|
||||
: "";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function setProgress(value, size) {
|
||||
|
||||
var progress = document.getElementById("progress");
|
||||
var fill = document.getElementById("progress-fill");
|
||||
|
||||
if (value == null) {
|
||||
progress.hidden = true;
|
||||
progress.removeAttribute("title");
|
||||
progress.removeAttribute("aria-valuenow");
|
||||
progress.removeAttribute("aria-valuetext");
|
||||
fill.style.width = "0%";
|
||||
return true;
|
||||
}
|
||||
|
||||
progress.hidden = false;
|
||||
progress.title = size != null ? size : value + "%";
|
||||
progress.setAttribute("aria-valuenow", value);
|
||||
|
||||
if (size != null) {
|
||||
progress.setAttribute("aria-valuetext", size);
|
||||
} else {
|
||||
progress.removeAttribute("aria-valuetext");
|
||||
}
|
||||
|
||||
fill.style.width = value + "%";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function setInfo(msg, loading, error) {
|
||||
try {
|
||||
|
||||
@@ -266,9 +470,17 @@ function setInfo(msg, loading, error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var parsed = parseProgress(msg);
|
||||
msg = parsed.message;
|
||||
setProgress(parsed.progress, parsed.size);
|
||||
|
||||
var el = document.getElementById("info");
|
||||
|
||||
if (el.innerText == msg || el.innerHTML == msg) {
|
||||
var progressEl = document.getElementById("progress");
|
||||
if (progressEl && !progressEl.hidden && !progressEl.style.width) {
|
||||
resizeProgress();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -290,11 +502,13 @@ function setInfo(msg, loading, error) {
|
||||
if (msg.includes(p)) {
|
||||
if (el.innerHTML.includes(p)) {
|
||||
el.getElementsByClassName('loading')[0].textContent = extractContent(msg);
|
||||
resizeProgress();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
el.innerHTML = msg;
|
||||
resizeProgress();
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
@@ -413,6 +627,7 @@ function connect() {
|
||||
};
|
||||
}
|
||||
|
||||
window.addEventListener("resize", resizeProgress);
|
||||
document.addEventListener("visibilitychange", visibilityChanged);
|
||||
rememberStatus(document.getElementById("info").innerHTML);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user