11 KiB
Этап 7: серверы и мониторинг
Подготовка 2026-09-20 по текущему коду после этапа 6. Блок 7.1 реализован 2026-09-21; остальные блоки ожидают выполнения. Основа: ReUI PRO, base-nova, Frame; переиспользовать установленные Filters/DataGrid, ServerFilters, PageHeader и Sheet. Не менять vendored-компоненты и правила сетевых операций.
Инвентаризация
| Область | Подтверждено в коде | Следующая доработка |
|---|---|---|
| Серверы | app/(main)/servers/page.tsx: URL читает только server; search/typeFilter/advancedFilters — локальный useState |
Восстановление фильтров из URL без сброса выбранного сервера |
| Filters | server-filter-fields.ts: country/status/type; apply-filter-query.ts сохраняет AND/OR, вложенность, negated и черновики |
Ограниченный валидируемый codec дерева, без уплощения |
| Формы сервера | Уже есть сохранение формы при ошибке, блокировка повторов, загрузка деталей, разделение результатов опроса и обновления списка | Проверить UX шагов и доступность, сохранить существующие гарантии |
| Мониторинг | /uptime?probe=... выбирает проверку; отдельные вкладки и фильтры пока не имеют полного URL-контракта |
Отдельный блок URL после серверов; не распространять probe на несвязанные ресурсы/speed |
| Телефон | Ping-пробы: фиксированная сетка из 11 колонок, FramePanel с overflow-hidden | Доступные имя/цель/состояние и действия на 320/390 px без обрезки |
| Права | lib/auth.ts: can/hasPermission; страницы servers/uptime не используют их для разрешений действий |
UI-доступность по фактической политике backend, с повторной обработкой 403 |
Референсы и схема
| Блок | Референс | Схема доработки |
|---|---|---|
| Список серверов | Data Grid Filtering 2 | Контекст → поиск/тип/Filters → результат → детали |
| Детали и формы | Sheet 8 | Объект → доступное действие → форма → подтверждённый API-результат |
| Проверки на телефоне | List 9 | Имя и цель → состояние → измерение → действия |
ПК: [Контекст сервера / проверки · снять выбор]
[Поиск] [Тип] [Filters] [Доступные действия]
[Таблица → детали → форма → результат]
URL ↔ фильтры; Back/reload возвращают контекст
Телефон: [Имя проверки Состояние]
[Источник → цель]
[RTT / потери] [Действия]
[Раскрыть дополнительные сведения]
Это схема иерархии, а не разрешение переписать таблицы или блоки вручную. Конкретную композицию мобильного списка выбрать из установленных компонентов после проверки текущих действий строки.
Блок 7.1 — URL серверов
Реализованный контракт:
| Параметр | Значение | Правило |
|---|---|---|
server |
Точный ID из этапа 6 | Сохранять при изменении фильтров; отсутствие объекта не подменять другим |
q |
Строка поиска | Пустое значение удалять; ввод обновлять сразу через native replaceState, без новых записей истории и повторных запросов API |
type |
jump-host / exit-node / home-router | «Все» — отсутствие параметра; дискретный выбор добавляет запись истории |
filters |
JSON {v:1, query: FilterQuery} |
URLSearchParams кодирует значение; сохранить AND/OR и структуру групп |
Сначала реализовать чистый codec в lib/data-filters/server-url-state.ts и профильные unit-тесты. Валидировать до передачи в Filters/evaluator: версию, тип узла, уникальные ID, поля из SERVER_FILTER_FIELDS, допустимые для select операторы/значения. Ограничить размер JSON 8 KiB, количество узлов 50, глубину 4. Эти числа — рабочие пределы нового контракта, не существующие ограничения ReUI. Окончательный список операторов сверить с установленной конфигурацией select.
Черновик незавершённого условия оставить локальным; не публиковать частично собранное дерево и не превращать OR в AND. При восстановлении неверного filters/type показать понятное сообщение и действие сброса; до сброса не расширять результат до всех серверов молча. Не помещать в URL пароли, ключи и поля форм.
URL — источник сохранённого состояния. Back/Forward/reload восстанавливают контролы и строки без циклов синхронизации, автозаписи и повторного открытия форм. При быстрых изменениях разных контролов читать актуальные параметры, чтобы поздняя запись поиска не затёрла type/filters/server. Сброс фильтров удаляет q/type/filters, сохраняя server и чужие параметры; «Все серверы» снимает только server.
Приёмка: прямой URL; reload; Back/Forward; смена type после ввода поиска; AND/OR; черновик; повреждённый/слишком большой JSON; неизвестное поле/оператор; сброс с сохранением server; пустой результат; отсутствие POST/PATCH/DELETE от навигации. Прогнать codec unit-тесты, servers.spec.ts, профильные URL E2E, lint/TypeScript и production build. Затем журнал и локальный коммит без push.
Блоки после 7.1
- 7.2 — мобильные проверки. Устранить обрезку Ping-проб, сохранив выбор строк, раскрытие, запуск и меню. Проверить 320/390/1440 px, клавиатуру/Escape, отсутствие скрытых обязательных действий и горизонтального скролла всей страницы.
- 7.3 — права действий. Источник политики —
backend/src/lib/permissions.ts, применение —backend/src/plugins/auth.ts. GET/api/servers*требуетmm:servers:read, запись —mm:servers:write; GET/api/uptime*—mm:uptime:read, запись —mm:uptime:write. Учитывать наследование write/admin через существующий hasPermission и режим auth disabled. Проверить конкретные маршруты опроса/теста соединения, не считать их чтением только по названию. UI не заменяет backend-проверку: серверный 403 сохраняет форму и сообщает отказ. Не выдавать доступ только по is_admin без подтверждения текущей политики. - 7.4 — формы, детали и полный контекст мониторинга. Восстановление вкладки/фильтров из URL, понятные единицы и подписи, возврат к списку после действия. Не дублировать сохранённые исправления этапа 1; проверить загрузку, отмену, 400/403/500, timeout и повторное нажатие.
- 7.5 — приёмка этапа. Сценарий «проблема → сервер/проверка → действие → возврат» с сохранением контекста; профильные E2E, права в HTTP-моках, TypeScript, lint и build. Реальные JWT/RouterOS отдельно в тестовом окружении.
Следующий исполняемый шаг: блок 7.2 — мобильные строки Ping-проб. Codec URL серверов, hook и подключение к ServersPageContent выполнены. Полную регрессию всей системы здесь не повторять без изменений общей основы или найденной регрессии.
Решение по синхронизации URL (7.1)
Поиск использует native replaceState без debounce: установленный Next App Router синхронизирует useSearchParams, не запрашивая серверные данные. Браузерный тест подтвердил быстрый посимвольный ввод и неизменное количество GET /api/servers. Это устраняет отложенную запись, способную затереть последующий выбор type/filters. Дискретные изменения используют pushState, читая актуальный window.location.search. Черновик Filters привязан к сохранённому filters и сбрасывается при popstate. Неверные type/filters блокируют выдачу до исправления/сброса; server и чужие параметры сохраняются.