UI: адаптив, журнал, спиннеры; docs: README и api_routes

- Навигация: выезжающее меню при узком экране (nav-mobile.js)
- Журнал: карточки <620px, компактная пагинация, время в две строки <920px
- Создание кластера: оверлей загрузки, инкрементальное обновление таблицы заданий
- Документация: полноэкранный спиннер при загрузке и навигации
- Главная: масштабирование CTA, статистика 2 колонки <520px, донаты перенос <710px
- README: env.example, новые фичи UI, автор в конце файла
- api_routes: маршрут /cluster-create, спиннеры, шаблоны; автор в конце
- env.example: автор перенесён в конец файла
This commit is contained in:
Sergey Antropoff
2026-04-05 00:18:19 +03:00
parent 4b703801e1
commit f0b24c8901
12 changed files with 2426 additions and 173 deletions

View File

@@ -2,8 +2,6 @@
Образ **kind-k8s-tools:local** и **Makefile** поднимают **веб-интерфейс** (FastAPI) на порту **8080** на хосте по умолчанию (или **`KIND_K8S_WEB_PORT`** в `.env`; внутри контейнера приложение слушает **6000**). Порт **6000 на хосте** не используем по умолчанию: Chrome и другие браузеры на Chromium отдают **ERR_UNSAFE_PORT**. Через браузер создаёте и удаляете кластеры, смотрите статистику и вывод `kubectl`. **kubeconfig** сохраняется в `clusters/<имя>/`. На хосте достаточно **Docker** (или Podman) и **make**; **kind** и **kubectl** — внутри контейнера.
**Автор:** Сергей Антропов — [devops.org.ru](https://devops.org.ru)
## Документация
| Ресурс | Описание |
@@ -11,7 +9,7 @@
| **[app/docs/api_routes.md](app/docs/api_routes.md)** | Описание REST API `/api/v1/*` с примерами JSON (для фронтенда и интеграций) |
| **`/docs`** (Swagger), **`/redoc`**, **`/api/v1/health`** | На панели открываются в **отдельном окне** браузера (`window.open`); прямой URL — тот же порт, что и UI (по умолчанию **8080**) |
Шаблона **`env.example`** в репозитории нет: переменные для `.env` задаются интерактивно скриптом **`scripts/setup_env_interactive.py`** (`make setup`; в начале — только выбор **docker** или **podman**, путь **`CONTAINER_SOCKET`** подставляется автоматически).
В корне репозитория — файл **`env.example`**: перечислены **только имена** переменных (без значений), для ориентира при ручной настройке **`.env`**. Полноценно создать **`.env`** можно интерактивно скриптом **`scripts/setup_env_interactive.py`** (`make setup`; в начале — выбор **docker** или **podman**, путь **`CONTAINER_SOCKET`** подставляется автоматически).
## Зачем это нужно
@@ -24,17 +22,21 @@
- Верхняя **единая карточка**: заголовок, краткое описание и строка **состояния среды** (`kind` / `kubectl` / Docker или Podman API).
- **Статистика**: число кластеров в kind, локальных каталогов, сумма workers из `meta.json`, счётчики фоновых заданий.
- **Создание кластера**: форма с подсказкой тегов `kindest/node` (`GET /api/v1/versions`), фоновое задание и опрос статуса (JSON в сворачиваемом блоке).
- **Кластеры** (`/clusters`): сводка ресурсов узлов (донаты), таблица кластеров — **старт**/**стоп**, скачивание kubeconfig, модалки узлов/подов, ссылка на страницу кластера; с **панели** (`/`) — быстрый переход по ссылке в карточке «Создать кластер».
- **Создание кластера** (`/cluster-create`): форма с подсказкой тегов `kindest/node` (`GET /api/v1/versions`), фоновое задание и опрос статуса (JSON в сворачиваемом блоке); блок **«Последние задания»** (журнал с диска) обновляется без полной перерисовки таблицы — новые записи добавляются сверху, раскрытый лог не сбрасывается при автообновлении.
- **Кластеры** (`/clusters`): сводка ресурсов узлов (донаты), таблица кластеров — **старт**/**стоп**, скачивание kubeconfig, модалки узлов/подов, ссылка на страницу кластера; с **панели** (`/`) — кнопка **«Перейти к созданию кластера»** (размер кнопки плавно уменьшается на узком экране).
- **Аддоны** (`/cluster-addons`): выбор кластера и установка/удаление через **Helm** в контейнере — **ingress-nginx**, **kube-prometheus-stack** (логин/пароль Grafana), **metrics-server**, **Istio + Kiali** (Kiali по умолчанию без формы входа, `auth` при необходимости в YAML values); журнал операции на странице (прогресс + вывод как при создании кластера), история в **`clusters/<имя>/helm_addon_log.json`**. Нужна **пересборка образа** после обновления Dockerfile (бинарник `helm`). Таймаут операций: **`KIND_K8S_HELM_TIMEOUT_SEC`** (по умолчанию 900 с).
- **Последние задания**: история в памяти процесса (до **200** записей; после перезапуска контейнера сбрасывается); кнопка **«Очистить завершённые»** вызывает **`DELETE /api/v1/jobs`** (из памяти удаляются только завершённые задания).
- **Журнал** (`/journal`): три режима (по кластеру, развёртывание, Helm-аддоны), пагинация; на узком экране таблица записей превращается в **карточки** (как «Последние задания» на странице создания).
- **Документация** (`/documentation`): README и `app/docs/*.md` в браузере (Markdown); при загрузке и при переходе между файлами — полноэкранный **спиннер** (как на панели).
- **Автообновление** таблиц и плашки среды каждые ~3,5 с (fetch к API без перезагрузки страницы).
- При активном задании — **прогресс-бар**, **журнал** (в т.ч. скачивание образа; для **docker** при поддержке CLI — **`pull --progress=plain`**, см. **`KIND_K8S_DOCKER_PULL_PLAIN`**), опрос статуса чаще, чем общие таблицы; кнопка **«Отменить»** — прерывание с завершением текущей дочерней команды.
- Уведомления (toast) при успехе/ошибке; в подвале — копирайт и ссылка на **devops.org.ru**.
**Шапка:** навигация в виде **пилюль** (стили `.nav-pill`); пункты **Swagger**, **ReDoc** и **Health** открывают страницу в **отдельном именованном окне** (~1240×840), чтобы не уходить с панели (см. скрипт в `base.html`).
**Шапка:** навигация в виде **пилюль** (стили `.nav-pill`); при ширине окна **меньше ~920px** — кнопка **«гамбургер»** и выезжающая панель (`app/static/js/nav-mobile.js`). Пункты **Swagger**, **ReDoc** и **Health** открывают страницу в **отдельном именованном окне** (~1240×840), чтобы не уходить с панели (см. скрипт в `base.html`).
**Структура фронтенда:** `app/templates/base.html` (шапка и меню), `app/templates/dashboard.html`, `app/static/style.css`, `app/static/js/dashboard.js` (префикс API: `data-api-base` на `<body>`, по умолчанию `/api/v1`).
**Адаптивная вёрстка (кратко):** донаты «Ресурсы узлов» переносятся на новые строки при ширине окна **меньше ~710px**; блок **«Статистика»** на главной — мини-карточки в **две колонки** при **меньше ~520px**; таблицы **кластеров** и **«Последние задания»** на `/cluster-create` при ширине **меньше ~920px** оформляются **карточками**; на **/journal** карточки записей — при **меньше ~620px**; в журнале и таблицах заданий колонка времени (UTC) — дата и время **в две строки** при **меньше ~920px**. При первой загрузке полноэкранный спиннер: **главная**, **/clusters**, **страница кластера**, **/cluster-create**, **/documentation** (`app/static/style.css` `.page-loading-overlay`).
**Структура фронтенда:** `app/templates/base.html` (шапка и меню), `app/templates/dashboard.html`, `app/templates/journal.html`, `app/templates/documentation.html`, `app/static/style.css`, `app/static/js/dashboard.js`, `app/static/js/journal.js`, `app/static/js/documentation.js`, `app/static/js/nav-mobile.js` (префикс API: `data-api-base` на `<body>`, по умолчанию `/api/v1`).
## Требования на хосте
@@ -200,7 +202,7 @@ make podman up
| `app/api/v1/` | REST API: `router.py`, `endpoints/` (`health`, `versions`, `docs_readme`, `clusters`) |
| `app/core/` | Жизненный цикл кластеров, задания, настройки, блокировки (`kind_guard`), пути |
| `app/models/schemas.py` | Pydantic-схемы запросов/ответов API |
| `app/templates/` | Jinja2: `base.html`, `dashboard.html`, `documentation.html` |
| `app/templates/` | Jinja2: `base.html`, `dashboard.html`, `clusters.html`, `cluster_create.html`, `cluster_detail.html`, `cluster_edit.html`, `cluster_addons.html`, `journal.html`, `documentation.html` |
| `app/static/` | `style.css`, `js/dashboard.js`, `js/documentation.js`, `js/vendor/` (marked, DOMPurify для README в UI) |
| `app/docs/` | `api_routes.md` (описание REST API) |
| `app/create_cluster.py`, `delete_cluster.py`, `cluster_status.py` | CLI и переиспользование из API / `compose run` |
@@ -226,3 +228,7 @@ make podman up
- **kubectl** на хосте **не обязателен**: используйте веб-UI или **`make docker kubectl`** / **`make podman kubectl`** (см. выше).
- История заданий в UI/API хранится в памяти (до **200** записей); после перезапуска контейнера очищается. Завершённые записи можно удалить из памяти кнопкой на панели или **`DELETE /api/v1/jobs`**.
- При **`exec format error`** у kind пересоберите образ: `make docker rebuild COMPOSE_BUILD_FLAGS=--platform linux/arm64` (или `make podman …`, или **`make docker build`** без `--no-cache`, или `linux/amd64`).
---
**Автор:** Сергей Антропов — [devops.org.ru](https://devops.org.ru)