From 7bb503420f0f30e1e29caf9829f2629c30fa12b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Fri, 10 Jul 2026 07:46:45 +0400 Subject: [PATCH] =?UTF-8?q?init:=20UI=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=20=E2=80=94=20inp?= =?UTF-8?q?ut[file],=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D0=B0,=20Flask?= =?UTF-8?q?=20skeleton?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/deploy.yaml | 13 ++++ .gitignore | 3 + Dockerfile | 7 +++ requirements.txt | 2 + site/app.py | 12 ++++ site/static/app.js | 93 ++++++++++++++++++++++++++++ site/templates/index.html | 115 +++++++++++++++++++++++++++++++++++ 7 files changed, 245 insertions(+) create mode 100644 .gitea/workflows/deploy.yaml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 requirements.txt create mode 100644 site/app.py create mode 100644 site/static/app.js create mode 100644 site/templates/index.html diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..bcb8662 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,13 @@ +name: Deploy loadtest +on: + push: + branches: [master] + +jobs: + validate: + runs-on: linux_amd64 + steps: + - name: Test runner + run: | + echo "OK" + python3 --version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6cf5f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c0cccca --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.12-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY site /app/site +EXPOSE 5000 +CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--timeout", "300", "--workers", "1", "site.app:app"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e4a286c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask +gunicorn diff --git a/site/app.py b/site/app.py new file mode 100644 index 0000000..632bf07 --- /dev/null +++ b/site/app.py @@ -0,0 +1,12 @@ +from flask import Flask, render_template + +app = Flask(__name__) + + +@app.route('/') +def index(): + return render_template('index.html') + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/site/static/app.js b/site/static/app.js new file mode 100644 index 0000000..fd1cb58 --- /dev/null +++ b/site/static/app.js @@ -0,0 +1,93 @@ +/** + * app.js — UI выбора файлов из локали. + * + * Выбираем файлы через , + * показываем в таблице: имя, размер, кнопка удаления. + * + * Никакой загрузки на сервер — чисто клиент. + */ + +var files = []; // [{ name, size, lastModified }] + +var fileInput = document.getElementById('fileInput'); +var fileTable = document.getElementById('fileTable'); +var fileSummary = document.getElementById('fileSummary'); +var clearBtn = document.getElementById('clearBtn'); + +fileInput.addEventListener('change', function () { + addFiles(fileInput.files); + fileInput.value = ''; +}); + +/** formatSize(bytes) → "1.2 KB", "3.4 MB", "900 B" */ +function formatSize(bytes) { + if (!bytes || bytes === 0) return '—'; + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; + if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; + return (bytes / 1073741824).toFixed(2) + ' GB'; +} + +/** addFiles(fileList) — добавить файлы в массив и перерисовать */ +function addFiles(fileList) { + for (var i = 0; i < fileList.length; i++) { + var f = fileList[i]; + files.push({ + name: f.name, + size: f.size, + lastModified: f.lastModified + }); + } + renderTable(); +} + +/** removeFile(i) — удалить файл по индексу */ +function removeFile(i) { + files.splice(i, 1); + renderTable(); +} + +/** renderTable() — перерисовать таблицу и сводку */ +function renderTable() { + if (files.length === 0) { + fileTable.innerHTML = 'Нет файлов — выберите файлы'; + fileSummary.textContent = 'Нет файлов'; + clearBtn.disabled = true; + return; + } + + var totalSize = 0; + var rows = []; + for (var i = 0; i < files.length; i++) { + var f = files[i]; + totalSize += f.size; + rows.push( + '' + + '' + escHtml(f.name) + '' + + '' + formatSize(f.size) + '' + + '' + + '' + ); + } + fileTable.innerHTML = rows.join(''); + + fileSummary.textContent = files.length + ' файл., ' + formatSize(totalSize); + clearBtn.disabled = false; +} + +/** clearAll() — очистить всё */ +function clearAll() { + files = []; + renderTable(); +} + +/** escHtml(s) — экранирование HTML */ +function escHtml(s) { + if (s == null) return ''; + var d = document.createElement('div'); + d.textContent = s; + return d.innerHTML; +} + +// Первичный рендер +renderTable(); diff --git a/site/templates/index.html b/site/templates/index.html new file mode 100644 index 0000000..9046b74 --- /dev/null +++ b/site/templates/index.html @@ -0,0 +1,115 @@ + + + + + + Loadtest — загрузка файлов + + + +
+ 📦 Loadtest — загрузка файлов +
+ +
+
+
Выбор файлов
+
+
+ +
+
+ + + + + + + + + +
ИмяРазмер
+
+ +
+
+
+ + + +