Показать второй прогресс конвертации после загрузки образа

Этот коммит содержится в:
Виктор
2026-05-07 02:03:43 +09:00
родитель 034ba9fe4a
Коммит af64ad468f
+52 -11
Просмотреть файл
@@ -51,7 +51,7 @@
</div>
<button id="disk-upload-button" type="submit" class="primary wide">Загрузить образ диска</button>
</form>
<p class="muted small-note">Файл попадёт в <b>/var/lib/virtuality/disk-images</b>. При создании VM образ будет скопирован/сконвертирован в отдельный <b>qcow2</b>-диск VM.</p>
<p class="muted small-note">После загрузки .img/.raw прогресс начнётся заново и покажет конвертацию в qcow2. Уже готовый .qcow2 сохраняется без конвертации.</p>
</article>
<article class="card">
@@ -62,15 +62,14 @@
<div class="quick-actions">
<div class="big-action static">
<strong>Raspberry / Orange Pi images</strong>
<span>Загрузи .img, затем в “Создать VM” выбери режим “Готовый диск”.</span>
<span>Загрузи .img, дождись конвертации, затем в “Создать VM” выбери режим “Готовый диск”.</span>
</div>
<div class="big-action static">
<strong>Оригинал не трогаем</strong>
<span>Virtuality делает отдельный диск VM, чтобы загруженный образ оставался шаблоном.</span>
<span>Virtuality сохраняет исходник и создаёт рядом готовый qcow2-шаблон.</span>
</div>
</div>
<pre>qemu-img convert -O qcow2 source.img VM.qcow2
virt-install --import --disk path=VM.qcow2</pre>
<pre>qemu-img convert -p -f raw -O qcow2 source.img source.qcow2</pre>
</article>
</section>
@@ -126,6 +125,44 @@ virt-install --import --disk path=VM.qcow2</pre>
return value.toFixed(value >= 10 || i === 0 ? 0 : 1) + ' ' + units[i];
}
function resetProgress(title, detail) {
bar.style.width = '0%';
percent.textContent = '0%';
statusLine.textContent = title;
loadedLine.textContent = detail || '0%';
speedLine.textContent = 'ожидание…';
}
async function pollConvert(operationId) {
resetProgress('Конвертация образа в qcow2…', '0%');
while (true) {
const response = await fetch('/api/operations/' + operationId, {cache: 'no-store'});
const payload = await response.json();
if (!payload.ok) throw new Error(payload.error || 'operation error');
const op = payload.operation;
const progress = Math.max(0, Math.min(100, Number(op.progress || 0)));
bar.style.width = progress + '%';
percent.textContent = progress + '%';
loadedLine.textContent = 'Конвертация: ' + progress + '%';
speedLine.textContent = op.status;
statusLine.textContent = op.message || 'Конвертация образа…';
if (op.status === 'success') {
bar.style.width = '100%';
percent.textContent = '100%';
statusLine.textContent = 'Конвертация завершена. Обновляем список образов…';
setTimeout(() => { window.location.href = '/disk-images'; }, 650);
return;
}
if (op.status === 'error') {
statusLine.textContent = 'Ошибка конвертации: ' + (op.message || 'см. журнал операций');
button.disabled = false;
fileInput.disabled = false;
return;
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
fileInput.addEventListener('change', function () {
const file = fileInput.files[0];
hint.textContent = file ? file.name + ' · ' + bytesText(file.size) : 'Файл ещё не выбран.';
@@ -143,11 +180,7 @@ virt-install --import --disk path=VM.qcow2</pre>
box.hidden = false;
button.disabled = true;
fileInput.disabled = true;
statusLine.textContent = 'Передача образа на сервер…';
bar.style.width = '0%';
percent.textContent = '0%';
loadedLine.textContent = '0 MB из ' + bytesText(file.size);
speedLine.textContent = 'скорость считается…';
resetProgress('Передача образа на сервер…', '0 MB из ' + bytesText(file.size));
xhr.upload.onprogress = function (event) {
if (!event.lengthComputable) {
@@ -164,8 +197,14 @@ virt-install --import --disk path=VM.qcow2</pre>
if (pct >= 100) statusLine.textContent = 'Файл передан. Сервер сохраняет образ…';
};
xhr.onload = function () {
xhr.onload = async function () {
if (xhr.status >= 200 && xhr.status < 400) {
let payload = null;
try { payload = JSON.parse(xhr.responseText); } catch (error) {}
if (payload && payload.mode === 'converting' && payload.operation_id) {
await pollConvert(payload.operation_id);
return;
}
bar.style.width = '100%';
percent.textContent = '100%';
statusLine.textContent = 'Готово. Обновляем список образов…';
@@ -184,6 +223,8 @@ virt-install --import --disk path=VM.qcow2</pre>
};
xhr.open('POST', form.action);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send(data);
});
</script>