Отмена загрузки дискового образа была добавлена
Этот коммит содержится в:
@@ -118,6 +118,8 @@
|
|||||||
const loadedLine = document.getElementById('upload-loaded');
|
const loadedLine = document.getElementById('upload-loaded');
|
||||||
const speedLine = document.getElementById('upload-speed');
|
const speedLine = document.getElementById('upload-speed');
|
||||||
const allowedExtensions = ['.img', '.raw', '.qcow2', '.img.xz', '.zip', '.tar.gz', '.tgz'];
|
const allowedExtensions = ['.img', '.raw', '.qcow2', '.img.xz', '.zip', '.tar.gz', '.tgz'];
|
||||||
|
let activeXhr = null;
|
||||||
|
let uploadActive = false;
|
||||||
|
|
||||||
function bytesText(bytes) {
|
function bytesText(bytes) {
|
||||||
if (!bytes) return '0 MB';
|
if (!bytes) return '0 MB';
|
||||||
@@ -140,6 +142,26 @@
|
|||||||
errorBox.hidden = !message;
|
errorBox.hidden = !message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setUploadMode(active) {
|
||||||
|
uploadActive = active;
|
||||||
|
if (active) {
|
||||||
|
button.disabled = false;
|
||||||
|
button.type = 'button';
|
||||||
|
button.textContent = 'Отменить загрузку';
|
||||||
|
button.classList.remove('primary');
|
||||||
|
button.classList.add('danger');
|
||||||
|
fileInput.disabled = true;
|
||||||
|
} else {
|
||||||
|
activeXhr = null;
|
||||||
|
button.type = 'submit';
|
||||||
|
button.textContent = 'Загрузить образ диска';
|
||||||
|
button.classList.add('primary');
|
||||||
|
button.classList.remove('danger');
|
||||||
|
fileInput.disabled = false;
|
||||||
|
button.disabled = !validDiskFile(fileInput.files[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function resetProgress(title, detail) {
|
function resetProgress(title, detail) {
|
||||||
bar.style.width = '0%';
|
bar.style.width = '0%';
|
||||||
percent.textContent = '0%';
|
percent.textContent = '0%';
|
||||||
@@ -149,6 +171,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function pollConvert(operationId) {
|
async function pollConvert(operationId) {
|
||||||
|
setUploadMode(false);
|
||||||
|
fileInput.disabled = true;
|
||||||
|
button.disabled = true;
|
||||||
|
button.textContent = 'Идёт конвертация…';
|
||||||
resetProgress('Конвертация образа в qcow2…', '0%');
|
resetProgress('Конвертация образа в qcow2…', '0%');
|
||||||
while (true) {
|
while (true) {
|
||||||
const response = await fetch('/api/operations/' + operationId, {cache: 'no-store'});
|
const response = await fetch('/api/operations/' + operationId, {cache: 'no-store'});
|
||||||
@@ -171,6 +197,10 @@
|
|||||||
if (op.status === 'error') {
|
if (op.status === 'error') {
|
||||||
statusLine.textContent = 'Ошибка конвертации: ' + (op.message || 'см. журнал операций');
|
statusLine.textContent = 'Ошибка конвертации: ' + (op.message || 'см. журнал операций');
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
|
button.type = 'submit';
|
||||||
|
button.textContent = 'Загрузить образ диска';
|
||||||
|
button.classList.add('primary');
|
||||||
|
button.classList.remove('danger');
|
||||||
fileInput.disabled = false;
|
fileInput.disabled = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -198,8 +228,14 @@
|
|||||||
hint.textContent = file.name + ' · ' + bytesText(file.size);
|
hint.textContent = file.name + ' · ' + bytesText(file.size);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
button.addEventListener('click', function () {
|
||||||
|
if (!uploadActive) return;
|
||||||
|
if (activeXhr) activeXhr.abort();
|
||||||
|
});
|
||||||
|
|
||||||
form.addEventListener('submit', function (event) {
|
form.addEventListener('submit', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
if (uploadActive) return;
|
||||||
const file = fileInput.files[0];
|
const file = fileInput.files[0];
|
||||||
setFileError('');
|
setFileError('');
|
||||||
if (!validDiskFile(file)) {
|
if (!validDiskFile(file)) {
|
||||||
@@ -210,12 +246,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
|
activeXhr = xhr;
|
||||||
const data = new FormData(form);
|
const data = new FormData(form);
|
||||||
const started = Date.now();
|
const started = Date.now();
|
||||||
|
|
||||||
box.hidden = false;
|
box.hidden = false;
|
||||||
button.disabled = true;
|
setUploadMode(true);
|
||||||
fileInput.disabled = true;
|
|
||||||
resetProgress('Передача файла на сервер…', '0 MB из ' + bytesText(file.size));
|
resetProgress('Передача файла на сервер…', '0 MB из ' + bytesText(file.size));
|
||||||
|
|
||||||
xhr.upload.onprogress = function (event) {
|
xhr.upload.onprogress = function (event) {
|
||||||
@@ -247,15 +283,22 @@
|
|||||||
window.location.href = '/disk-images';
|
window.location.href = '/disk-images';
|
||||||
} else {
|
} else {
|
||||||
statusLine.textContent = 'Ошибка загрузки: HTTP ' + xhr.status;
|
statusLine.textContent = 'Ошибка загрузки: HTTP ' + xhr.status;
|
||||||
button.disabled = false;
|
setUploadMode(false);
|
||||||
fileInput.disabled = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xhr.onabort = function () {
|
||||||
|
statusLine.textContent = 'Загрузка отменена пользователем.';
|
||||||
|
bar.style.width = '0%';
|
||||||
|
percent.textContent = '0%';
|
||||||
|
loadedLine.textContent = '0 MB';
|
||||||
|
speedLine.textContent = 'отменено';
|
||||||
|
setUploadMode(false);
|
||||||
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
statusLine.textContent = 'Ошибка сети во время загрузки.';
|
statusLine.textContent = 'Ошибка сети во время загрузки.';
|
||||||
button.disabled = false;
|
setUploadMode(false);
|
||||||
fileInput.disabled = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.open('POST', form.action);
|
xhr.open('POST', form.action);
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user