diff --git a/web/templates/disk_images.html b/web/templates/disk_images.html index 2610dd4..861c14c 100644 --- a/web/templates/disk_images.html +++ b/web/templates/disk_images.html @@ -11,7 +11,7 @@
Диски
-
Готовые образы установленных систем: .img / .raw / .qcow2, а также архивы .zip / .tar.gz / .tgz
+
Готовые образы установленных систем: .img / .raw / .qcow2 / .img.xz, а также архивы .zip / .tar.gz / .tgz
user: {{ user }} @@ -30,14 +30,15 @@

Загрузить образ установленной системы

- .img .raw .qcow2 .zip .tar.gz + .img .raw .qcow2 .img.xz .zip .tar.gz
-
Файл ещё не выбран. Разрешены .img, .raw, .qcow2, .zip, .tar.gz и .tgz.
+
Файл ещё не выбран. Разрешены .img, .raw, .qcow2, .img.xz, .zip, .tar.gz и .tgz.
+
@@ -62,11 +63,11 @@
Raspberry / Orange Pi images - Загрузи .img или архив с .img, дождись распаковки/конвертации, затем в “Создать VM” выбери режим “Готовый диск”. + Загрузи .img, .img.xz или архив с .img, дождись распаковки/конвертации, затем в “Создать VM” выбери режим “Готовый диск”.
Архивы безопасно распаковываются - Поддерживаются .zip, .tar.gz и .tgz. Из архива берём только .img/.raw/.qcow2. + Поддерживаются .zip, .tar.gz, .tgz и .img.xz. Из обычных архивов берём только .img/.raw/.qcow2.
qemu-img convert -p -f raw -O qcow2 source.img source.qcow2
@@ -97,7 +98,7 @@ {% else %} - Образов пока нет. Загрузи .img, .raw, .qcow2 или архив .zip/.tar.gz/.tgz. + Образов пока нет. Загрузи .img, .raw, .qcow2, .img.xz или архив .zip/.tar.gz/.tgz. {% endfor %} @@ -109,13 +110,14 @@ const fileInput = document.getElementById('disk-file-input'); const button = document.getElementById('disk-upload-button'); const hint = document.getElementById('disk-file-hint'); + const errorBox = document.getElementById('disk-file-error'); const box = document.getElementById('upload-progress-wrap'); const bar = document.getElementById('upload-progress-bar'); const percent = document.getElementById('upload-percent'); const statusLine = document.getElementById('upload-status'); const loadedLine = document.getElementById('upload-loaded'); const speedLine = document.getElementById('upload-speed'); - const allowedExtensions = ['.img', '.raw', '.qcow2', '.zip', '.tar.gz', '.tgz']; + const allowedExtensions = ['.img', '.raw', '.qcow2', '.img.xz', '.zip', '.tar.gz', '.tgz']; function bytesText(bytes) { if (!bytes) return '0 MB'; @@ -132,6 +134,12 @@ return allowedExtensions.some(ext => lower.endsWith(ext)); } + function setFileError(message) { + if (!errorBox) return; + errorBox.textContent = message || ''; + errorBox.hidden = !message; + } + function resetProgress(title, detail) { bar.style.width = '0%'; percent.textContent = '0%'; @@ -172,23 +180,32 @@ fileInput.addEventListener('change', function () { const file = fileInput.files[0]; + setFileError(''); if (!file) { - hint.textContent = 'Файл ещё не выбран. Разрешены .img, .raw, .qcow2, .zip, .tar.gz и .tgz.'; + hint.textContent = 'Файл ещё не выбран. Разрешены .img, .raw, .qcow2, .img.xz, .zip, .tar.gz и .tgz.'; + button.disabled = false; return; } if (!validDiskFile(file)) { - hint.textContent = 'Неверный тип файла. Здесь можно выбрать только .img, .raw, .qcow2, .zip, .tar.gz или .tgz.'; + const message = 'Неверное расширение: ' + file.name + '. Разрешены только .img, .raw, .qcow2, .img.xz, .zip, .tar.gz и .tgz.'; + hint.textContent = message; + setFileError(message); fileInput.value = ''; + button.disabled = true; return; } + button.disabled = false; hint.textContent = file.name + ' · ' + bytesText(file.size); }); form.addEventListener('submit', function (event) { event.preventDefault(); const file = fileInput.files[0]; + setFileError(''); if (!validDiskFile(file)) { - hint.textContent = 'Выбери образ установленной системы или архив: .img, .raw, .qcow2, .zip, .tar.gz или .tgz.'; + const message = 'Выбери образ установленной системы или архив: .img, .raw, .qcow2, .img.xz, .zip, .tar.gz или .tgz.'; + hint.textContent = message; + setFileError(message); return; }