Files
ayurishchevandClaude Opus 5.5 d1a2efd683 Задача 042: свёртка свободных адресов в раскрывающиеся диапазоны
В списке адресов префикса подряд идущие свободные адреса сворачиваются в строку
«начало – конец · Свободно: N» (параметр group_free, группировка на сервере — пагинация
по строкам после свёртки); раскрытие — существующим status=free&offset=free_offset
порциями по 500. Без group_free ответ API прежний.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 19:40:22 +03:00

53 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Свёртка свободных адресов в раскрывающиеся диапазоны (изменение 042)
## Context
В списке адресов префикса (`screens.address`) для подсетей до /20 занятые и свободные адреса идут вперемешку, каждый свободный — отдельной строкой.
В почти пустой /24 это ~250 строк «Свободен», которые оттесняют занятые адреса. Нужно сворачивать **подряд идущие свободные адреса**
в одну строку-диапазон: «10.0.0.5 – 10.0.0.20 · свободно 16». По клику строка раскрывается в отдельные адреса, повторный клик сворачивает.
## Решение
Группировка на сервере. Если сворачивать на клиенте в пределах страницы, диапазоны рвутся на границе пагинации,
а страница в 100 строк почти целиком занята свободными. С группировкой на сервере страница из 100 строк показывает 100 занятых адресов или диапазонов.
### API — `app/api/v1/prefixes.py::list_addresses`
- Новый параметр `group_free: bool = False`: по умолчанию поведение прежнее (совместимость, тесты).
Действует только в смешанном режиме (`mixed`: без фильтра статуса и поиска, подсеть до `FREE_LISTING_LIMIT`).
- Подряд идущие свободные адреса (серия ≥ 2) сворачиваются в одну строку `AddressOut`:
- `status="free_range"`, `address` — первый адрес, `range_end` — последний;
- `range_count` — число адресов;
- `free_offset` — сколько свободных адресов подсети идёт до начала диапазона.
Одиночный свободный адрес остаётся обычной строкой `free`. `total` и пагинация считаются по строкам после свёртки.
- `app/schemas.py::AddressOut`: `range_end: str | None = None`, `range_count: int | None = None`, `free_offset: int | None = None`.
- Раскрытие диапазона — существующий `GET …/addresses?status=free&offset=<free_offset>&limit=<n>`:
`free_page` уже считает страницу свободных арифметически, новых эндпоинтов не нужно.
### UI — `web/app.js::screens.address`
- Запрос списка — с `group_free: true`.
- Строка `free_range`: шеврон ▸/▾, текст «<начало> – <конец>», в колонке статуса — бейдж «Свободно: N». Остальные колонки — «—».
Действия «Назначить адрес» у свёрнутой строки нет: назначают из раскрытых строк. Строка не выбирается чекбоксом.
- Клик по строке диапазона раскрывает или сворачивает её. Раскрытое состояние — `S.freeOpen`: множество начальных адресов,
сбрасывается при смене префикса, фильтра или поиска.
При раскрытии: `api(…/addresses, {status: "free", offset: free_offset, limit: min(range_count, 500)})`, строки вставляются под диапазоном
с отступом, как обычные строки «Свободен», с действием «Назначить адрес».
Если в диапазоне больше 500 адресов, после первых 500 показывается строка «ещё N — показать», она подгружает следующую порцию.
- «Показано X из Y» учитывает строки после свёртки.
- Стиль — существующие классы и токены (`.tr.free`, `badge`, `I.chevR`/`I.chevD` как в дереве префиксов); литеральных цветов нет, тёмная тема работает.
## Тест (минимально)
В существующем тесте `tests/test_api.py`, работающем с адресами малой подсети (например, `test_tree_utilization_and_next_free`), проверить:
`GET /prefixes/{leaf}/addresses?group_free=true` → строка `free_range` с корректными `address`, `range_end`, `range_count`, `free_offset`;
`status=free&offset=<free_offset>&limit=<range_count>` возвращает ровно адреса этого диапазона.
## Документация
- `README.md`: «Адреса» и «Интерфейс» — свёртка свободных; строка 042 в истории.
- `SUMMARY.md` — по завершении.
## Исполнение
По принятой схеме: код и тест пишет агент на Sonnet, он же пересобирает стенд с `--force-recreate`. Моя часть — ревью и `pytest`.
UI проверяет пользователь.
## Проверка
- `pytest -q` — все зелёные.
- API: `/24` с парой назначенных адресов → 3–5 строк вместо ~254; `free_offset` и раскрытие дают ровно адреса диапазона; IPv6 `/120` — тоже.
- Без `group_free` ответ идентичен прежнему.