100 KiB
UX/UI: журнал реализации
Правила продолжения
- План: ReUI PRO, Frame, base-nova; KpiStatGrid, ServerTileRail и CodeExportSheet остаются источниками общих композиционных решений.
- Работа последовательно, без субагентов. После каждого завершённого этапа — локальный коммит на русском, без push.
- В начале этапа и после значимых проверок читать пятичасовой лимит. При остатке 25% и ниже не начинать следующий блок; закончить проверки и журнал.
- Этапы 2–4 выполнять в отдельной ветке codex/reui-v9-migration; не выпускать её до завершения миграции всех потребителей.
- Локально доступны моки. Проверки операций должны идти по обычному API-пути с подменой HTTP-ответов в тестах: встроенный mock-режим обходит запросы и не доказывает корректность live-ветки.
- Реальное применение RouterOS, сетевой опрос и экспорт сертификатов требуют отдельной приёмки в тестовом окружении. Не считать их проверенными по мокам.
- Перед продолжением читать git status и новые коммиты; сохранять изменения других задач.
Состояние этапов
| Этап | Результат | Статус |
|---|---|---|
| 0 | Исходная база, карта миграции, проверки и обзор экранов | Завершён 2026-09-13 |
| 1 | Достоверность сохранения, удаления, включения и опроса серверов | Завершён 2026-09-13 |
| 2 | Общая оболочка Data Grid/TanStack v9, Filters и эталон серверов | Завершён 2026-09-13, с перечисленными ограничениями приёмки |
| 3 | Основные таблицы и справочники | Завершён 2026-09-13, границы проверок ниже |
| 4 | Остальные таблицы, удаление старых API, общая регрессия | Завершён 2026-09-20; границы приёмки ниже |
| 5 | Состояния данных, свежесть, частичные сбои, гонки polling | Завершён 2026-09-20 для дашборда; границы проверок ниже |
| 6 | Навигация и дашборд | В работе: шапка, поиск и иерархия готовы; остаются переходы к объектам |
| 7 | Серверы и мониторинг: детали, формы, URL-контекст, права | Не начат |
| 8 | Трафик и статистика | Не начат |
| 9 | VPN, Firewall и Filters | Не начат |
| 10 | Маршрутизация, диагностика, карта и терминал | Не начат |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Не начат |
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
Этап 0 — исходная база
Исходный HEAD: f8e7437210.
На старте уже изменены 25 файлов навыков ReUI, AGENTS.md и создан .codex/config.toml. Они относятся к предыдущей настройке и не входят в коммит этого этапа. .codegraph/daemon.pid — служебный файл, не коммитить.
Изменение: в lib/format-service-path-label.test.ts убрано расширение .ts из локального импорта. Это устраняет TS5097 без ослабления tsconfig и без изменения UI или backend.
Проверки
| Проверка | Результат |
|---|---|
| tsc --noEmit --incremental false | Успешно после исправления импорта |
| tsx lib/format-service-path-label.test.ts | Успешно |
| tsx backend/src/services/ipsec-config.test.ts | Успешно |
| tsx backend/src/services/ros-file-contents.test.ts | Успешно |
| npm run build | Успешно: контракты, Next.js, TypeScript, 34 статические страницы |
| eslint . | Не проходит: 494 ошибки, 11015 предупреждений; включает артефакты .ci/docker |
| Тот же lint-отчёт без файлов .ci/docker | 81 ошибка, 134 предупреждения; это фильтрация отчёта, не отдельный запуск |
Lint hotspots: components/reui/sortable.tsx (8 ошибок), app/(main)/probes/page.tsx (8), components/reui/filters.tsx (6), app/(main)/network-map/page.tsx (5), app/(main)/firewall/page.tsx (4), components/reui/date-selector.tsx (3). Не исправлять их массово в этапе 1. Изоляцию generated-каталогов в ESLint вынести в отдельный небольшой блок перед миграцией; правила проверок не отключать.
В песочнице сборка не могла записать существующие dist-файлы (EPERM), а tsx падал в uv_os_get_passwd. Повторные запуски вне песочницы прошли; это ограничения окружения, не ошибки приложения.
Исходные экраны
Просмотрены /servers и /dashboard через локальную production-сборку на 127.0.0.1:3000, без backend, в mock-режиме. Скриншоты показаны в истории задачи; отдельные PNG в репозиторий не добавлены.
- Серверы: 9 записей, 7 онлайн; Frame/KPI, вкладки типов, фильтры и поиск работают как исходная композиция. На viewport 1280×720 KPI занимают две строки; часть правых колонок таблицы за пределами видимой области. Проверку прокрутки и мобильной компоновки выполнить на этапе 7.
- Дашборд: KPI с подписями «Флот», «Оверлей», «BGP Rx», «Здоровье»; ниже крупные быстрые переходы, затем график задержки и события. Очередь проблем не доминирует на первом экране — целевая перестройка этапа 6.
- Это исходный визуальный обзор, не сквозная проверка операций. Проверки консоли, клавиатуры, других размеров и тем остаются в профильных этапах.
Сохраняемые исправления IPsec
Последние коммиты исправляют общий IKEv2-peer с отдельными сертификатами клиентов, декодирование .p12 из RouterOS /file/get, отсутствие неподдерживаемых proposal-ключей в .sswan и горизонтальное переполнение шторки сертификата. Эти сценарии включить в регрессию этапов 4, 9, 11А. Ограничение passphrase брать из @mmapp/contracts (IPSEC_MIN_PASSPHRASE), не дублировать. Тест ipsec-config проходит отдельно, но отсутствует в общей npm test-цепочке backend; подключить его при следующей правке тестовой инфраструктуры.
Задание этапа 1 (выполнено)
Начать с app/(main)/servers/page.tsx, components/data-grids/servers-data-grid.tsx, shared/api/servers.ts и моделей серверов. Не начинать миграцию ReUI в этом этапе.
- Сохранение: блокировать повторную отправку; закрывать форму и менять список только после успеха API. На 400/403/500/сетевой ошибке сохранять значения и показывать сообщение рядом с формой.
- Редактирование: загрузить полную модель до разрешения сохранения; защитить от ответа другого сервера и закрытой формы. Не выводить enabled из online/offline. Изменение подключения сбрасывает прежний результат проверки.
- Удаление: подтверждение конкретного объекта; не удалять строку при ошибке API; блокировать повтор.
- Включение: обновлять enabled через API, фактическую доступность не подменять локальным переключением.
- Опрос: результат по устройству; массово не более четырёх запросов одновременно, повтор только неуспешных. Ошибку перечитывания списка отличать от результата самого опроса.
- Добавить проверки по HTTP-пути frontend с контролируемыми ответами, а не только встроенный mock. Успех, 403, 500, таймаут, двойное нажатие и смена объекта во время запроса обязательны.
- Типизация, lint изменённых файлов, профильные тесты и браузерная проверка; обновить журнал и сделать отдельный локальный коммит без push.
Остановка после этапа 0: на последней проверке осталось 15% пятичасовой квоты (было 35% на старте). Этап 1 не начат по согласованному правилу резерва. При продолжении сначала проверить свежие лимиты.
Этап 1 — достоверность операций
Исходный HEAD: 88326d9. Изменения предыдущей настройки ReUI и служебные файлы не входят в коммит этапа.
- В
app/(main)/servers/page.tsxсохранение закрывает форму только после подтверждения API. Ошибки остаются рядом с формой, повторные отправки блокируются синхронным замком. Пока загружаются детали, сохранение недоступно; ошибку загрузки можно повторить. Поздний ответ другого объекта игнорируется. - Удаление требует подтверждения имени и адреса, при ошибке строка и диалог остаются. Включение изменяет
enabledчерез API и не подменяет измеренный online/offline. Изменение параметров подключения сбрасывает прежний результат проверки. lib/server-operations.tsсодержит замок операций, понятные сообщения ошибок и очередь опроса максимум по четыре запроса. Результат показан по каждому серверу, повторяются только неудачные запросы. Ошибка последующего обновления списка отделена от результата опроса, прежние строки сохраняются.- В
shared/api/servers.tsожидание ограничено 30 секундами, для опроса — 60. Таймаут явно означает неизвестный результат: клиентское прерывание не отменяет действие на backend. Контракты и маршруты API не изменены. - В
components/data-grids/servers-data-grid.tsxдействия блокируются на время операции; выключенный сервер помечается отдельно от доступности. - Добавлены Playwright,
playwright.config.ts,tests/e2e/servers.spec.tsи командаnpm run test:servers. Используется установленный Microsoft Edge, свободный порт 3100 и отдельный Next dev процесс. Запросы API и health перехвачены тестами; встроенный mock-режим не используется. Отчёты исключены из Git.
Проверки этапа 1
| Проверка | Результат |
|---|---|
npm run test:servers |
14 браузерных тестов прошли: создание, сохранение 400/403/500 и повтор, двойное нажатие, удаление с повтором, enabled, загрузка деталей и смена объекта, массовый опрос и повтор, таймаут, отдельная ошибка обновления списка, запрет включения, сброс проверки подключения |
| TypeScript | Проверка без emit прошла; production build также проверяет типы |
npm run build |
Успешно: contracts, Next.js, TypeScript, 34 статические страницы |
| ESLint изменённых TS/TSX-файлов | 0 ошибок, 1 известное предупреждение React Compiler о TanStack v8 useReactTable |
ReUI get_audit_checklist |
Получен; сохранены установленные компоненты, Frame, семантические токены и типизированный API. Требование TanStack v9 остаётся этапам 2–4; полная доступность и адаптивность — профильным этапам и приёмке |
Моки достаточны для этих клиентских сценариев. Реальный backend, права реальных пользователей и применение RouterOS не проверены. Общие исходные ошибки lint перечислены в этапе 0; они не устранены этим этапом. Полную регрессию повторять после миграции общей основы.
Следующий шаг — этап 2
В новом окне проверить лимиты, git status и последние коммиты. Создать ветку codex/reui-v9-migration, перепроверить актуальный совместимый API ReUI Data Grid/TanStack и Filters. Мигрировать общую оболочку и одну таблицу серверов, закрепить зависимости и описать образец переноса. Сохранить проверки операций из этапа 1. Ветку не выпускать до завершения этапа 4. После этапа — отдельный локальный коммит без push.
Этап 2 — промежуточное сохранение 2026-09-13
Ветка codex/reui-v9-migration, исходный HEAD c30f817. Этап не завершён. На старте оставалось 51% пятичасового лимита, после основного блока — 24%; новые блоки остановлены по правилу резерва.
Выполнено
- Проверены MCP API и dry-run официального реестра base-nova; установлен Data Grid, новый Filters с Cascader и учебный
components/examples/c-data-grid-1.tsx. Пример не подключён к маршрутам приложения. 13 общих примитивов при установке не перезаписывались; итоговых изменений глобальной темы нет. - Закреплён
@tanstack/react-table9.2.4. Для поэтапной совместимости старые таблицы используют alias@tanstack/react-table-v8(8.21.3),components/reui/legacy-data-grid/иshared/legacy-data-grid-*. Это временная изоляция, не эмуляция API v8 поверх v9. Все старые импорты изменены механически; семантика старых экранов сохраняется. Удалить alias и legacy-файлы после последнего потребителя в этапе 4. - Канонические
shared/data-grid-shell.tsx,data-grid-sort-header.tsx,data-grid-layout.tsтипизированы черезDataGridFeatures.servers-data-grid.tsxиспользуетColumnDef<DataGridFeatures, Server>иuseTable({ features: dataGridFeatures, ... }). Отдельныеget*RowModelудалены.manualPagination: trueсохраняет прежний полный список: bundle включает пагинацию по умолчанию, а экран серверов её пока не показывает. СтабильныйgetRowIdи раскрытие сохранены. - Новый Filters установлен в
components/reui/filters/; старыйcomponents/reui/filters.tsxи его шесть потребителей пока работают. При переносе импортировать новый API явно из@/components/reui/filters/filters: одноимённый старый файл имеет приоритет над каталогом. Сохранить AND-семантику старых условий; не применятьflattenFilterConditionsкак вычислитель вложенных OR-групп.
Проверки и остаток
| Проверка | Результат |
|---|---|
tsc --noEmit --incremental false |
Прошла для всего проекта |
| 14 браузерных тестов операций | Прошли после миграции |
| Дополнительный тест v9 | Прошёл: 12 строк без потерь, сортировка в обе стороны, раскрытие и закрытие деталей |
| Lint адаптированной таблицы, общей оболочки и тестов | Прошёл без замечаний |
npm run build |
Прошла: contracts, типы и 34 статические страницы |
| Lint новых официальных Data Grid / Filters / Cascader | 23 ошибки и 27 предупреждений; точный список. Это незакрытая часть этапа, правила не отключались |
Следующий запуск: продолжить этап 2, не переходить к этапу 3. Проверить лимит и HEAD; разобрать замечания установленного реестра, подготовить и проверить переход старых Filters в FilterQuery на эталоне серверов, выполнить визуальную и клавиатурную проверку эталона и итоговый ReUI audit. Затем завершить этап отдельным локальным коммитом. Текущее сохранение — промежуточный коммит, без push; ветку не выпускать.
Референсы: пример пагинации, PRO-таблица, Data Grid API, Filters API.
flowchart LR
A[Серверы: реальные API] --> B[DataGridShell]
B --> C[ReUI Data Grid + TanStack v9]
D[Остальные таблицы] --> E[Временная оболочка legacy]
E --> F[TanStack v8 alias]
G[Старые Filters] -. этапы 2–4 .-> H[FilterQuery: AND / OR]
Малый блок после промежуточного сохранения
По отдельному поручению пользователя выполнить работу в пределах 10% квоты; на старте фактически оставалось 9%. В data-grid.tsx сериализация tableLayout и tableClassNames вынесена в именованные ключи зависимостей useMemo. Сравнение по содержимому сохранено, два замечания React Compiler устранены, правила не отключались.
Проверки: TypeScript всего проекта прошёл; браузерный тест v9 (12 строк, сортировка, раскрытие) прошёл. Повторный lint группы: 21 ошибка, 27 предупреждений, актуальный компактный отчёт — docs/reui-migration-lint.md. Production build не повторялся после этой локальной правки; предыдущая сборка этапа прошла. Этап 2 остаётся в работе; следующий объём прежний.
Этап 2 — завершение
Продолжение от f9a4a07 в codex/reui-v9-migration. Записи о промежуточных остановках выше — история; текущий следующий шаг — этап 3.
Результат
- Серверы используют ReUI Data Grid/TanStack 9.2.4 и новый
FilterQuery; таблица сохраняет все строки, сортировку, детали и подтверждённые операции этапа 1. Для раскрытия есть отдельная кнопка сaria-expanded, работающая с клавиатуры. При пустом результате фильтрации показывается «Нет совпадений», а не предложение добавить первый сервер. ServerFiltersповторяет контракт официальногоc-filters-1. Поляcountry/status/typeимеютtype: select, потому что данные скалярные. Варианты множественного выбора задаются операторами. Добавлены русские подписи Filters, вычислитель дереваapplyFilterQueryи временныйmigrateFilterQueryдля AND-массива старых условий. Неизвестное условие не расширяет выборку, незавершённые условия не превращают OR в истинное выражение.DataPageToolbar.filterControlпозволяет переносить потребителей по одному; старые props сохранены только на период этапов 3–4. Новые импорты Filters обязательно указывают/filters/filters, пока существует старый одноимённый файл.- Выполнены локальные исправления совместимости исходников ReUI с React Compiler. Контекст Data Grid передаёт актуальный снимок данных; императивный координатор ширины получает только закоммиченные React значения. Кэш подписей Cascader обновляется без мутации ref во время рендера; измерения запускаются через ResizeObserver/кадр браузера, отложенная навигация отменяется при смене контекста. Draft и автооткрытие Filters синхронизируются до рендера дочерних редакторов. Убраны неиспользуемые импорты и лишние вычисления. Правила lint не отключались, публичные API и композиция сохранены. При будущем обновлении реестра эти исправления сравнить с upstream, не перезаписывать автоматически.
Приёмка
| Проверка | Результат |
|---|---|
npm run test:servers |
17 браузерных тестов прошли, включая операции, сортировку 12 строк, фильтрацию AND, изменение/сброс, Escape и клавиатурное раскрытие |
npx tsx --test lib/data-filters/apply-filter-query.test.ts |
6 тестов прошли: AND/OR, отрицание, черновики, пустые/неизвестные условия, эквивалентность поддерживаемых старых операторов |
TypeScript и npm run build |
Успешно, 34 статические страницы |
| Lint изменённых участков и новой группы ReUI | 0 ошибок, 1 предупреждение react-hooks/incompatible-library для виртуализатора. React Compiler пропускает его оптимизацию; отчёт |
| Визуальная проверка | Просмотрены экраны 1440×1000 и 390×844. Page overflow отсутствует; широкая таблица сохраняет горизонтальный скролл внутри своего контейнера |
| ReUI audit | Checklist получен; проверены композиция Frame/base-nova, API, типизированные HTTP-данные, подписи, состояния и фокус эталона. Правки internals ограничены описанной совместимостью, без смены дизайна |
Границы приёмки: моки HTTP не подтверждают реальные права или применение RouterOS. Общая мобильная шапка обрезает часть действий, KPI занимают много высоты — исходные задачи этапов 6–7. Некоторые служебные объявления вложенного Cascader ещё английские — завершить локализацию на этапе 7. Все режимы DnD/виртуализации/автоподбора ширины не были проверены браузером на этом этапе; их проверять при переносе использующих их экранов. Изменённый способ публикации контекста Data Grid требует профилирования больших таблиц на этапе 12. Это не полная приёмка доступности/производительности всего приложения.
Образец следующего переноса
- В выбранном доменном grid заменить
react-table-v8наreact-table, legacy-оболочку наDataGridShellи заголовки на новыйDataGridSortHeader. - Тип колонок —
ColumnDef<DataGridFeatures, T>, таблицы —Table<DataGridFeatures, T>. ИспользоватьuseTable({ features: dataGridFeatures, ... }); удалить старыеget*RowModel. Сверить переименованные sorting/pinning/resize props с установленным API. Сохранить стабильныйgetRowId. - Явно определить пагинацию: для полного списка без панели —
manualPagination: true; для серверной — передавать реальныйrowCount; для клиентской — подключить панель и контролируемую страницу. - Для Filters перенести поля
key → id, выбрать тип по данным, сохранить AND черезmigrateFilterQuery. Вычислитель сейчас поддерживает только операторы скалярных фильтров серверов и прежние текстовые contains; перед переносом дат, чисел или массивов расширить вычисление и тесты. Нельзя просто сплющить OR-дерево. - Проверить фильтрацию, сортировку, сброс/страницу, раскрытие и действия. Старую основу удалять только после последнего потребителя в этапе 4.
Следующий шаг: проверить квоту и состояние файлов; выполнить только этап 3 (обзор, мониторинг, трафик, статистика и справочники) в этой ветке, перечислить оставшихся legacy-потребителей и сделать локальный коммит без push. Перед миграцией виртуализированных таблиц добавить профильные проверки указанного выше риска контекста. Этапы 2–4 не выпускать до общей регрессии этапа 4.
Этап 3 — основные таблицы и справочники
Перенесены десять прямых потребителей: asns-data-grid, domains-data-grid, ip-ranges-data-grid, communities-data-grid, compact-data-grid, uptime-resources-data-grid, uptime-speed-history-data-grid, traffic-flows-data-grid, traffic/flow-analytics-panel, traffic/flow-traffic-map. Через CompactDataGrid новую основу получили таблицы дашборда, статистики и снимков состояния. Серверы уже перенесены на этапе 2.
Используются useTable, dataGridFeatures и типы v9. Сохранены доменные props, стабильные идентификаторы, раскрытие и обработчики действий. Для списков без панели явно отключена клиентская пагинация; для каталогов EvoBGP она сохранена. Таблицы потоков сохраняют исходный порядок данных. Состояние выбора Communities приведено к типу v9. Общая оболочка получила русские служебные подписи через документированный i18n, без изменения установленных примитивов ReUI.
| Референс | Схема сохранённого сценария |
|---|---|
| Data Grid Filtering 2 | Поиск → страница таблицы → сортировка / выбор строки → детали |
| API Data Grid | Типизированные данные → useTable v9 → DataGridShell → таблица и опциональная пагинация |
Проверки: TypeScript и целевой ESLint — без ошибок и предупреждений. 17 браузерных тестов серверов прошли. Добавлены 6 сценариев tests/e2e/migrated-tables.spec.ts: пагинация и поиск с последней страницы в трёх справочниках, числовая сортировка через границу страницы, выбор одной из 12 Communities, все 12 строк статистики и переход в URL-срез. Первый старт Next.js превысил 120 секунд; повторный старт успешен. Два теста сначала упали из-за неточных селекторов, исправлены и повторно прошли. Все запросы перехватывались HTTP-моками.
ReUI audit checklist получен. Сохранены Frame/base-nova, композиция и типизированные источники; новые props сверены с установленными файлами. Просмотрен экран Communities: таблица и выбранная строка отображаются, но правая панель деталей обрезается при ширине 1440 px. Исправить размещение таблицы/деталей при профильной переработке экранов; общую доступность и адаптивность не считать принятой. Существующие неработающие действия справочников также не входят в приёмку миграции. Браузерные проверки всех комбинаций мониторинга, traffic-map и snapshot-деталей остаются для общей регрессии этапа 4 и профильных этапов 7–10. Виртуализатор эти десять компонентов не используют; нагрузочный профиль общей основы остаётся этапу 12.
Production build прошёл: npm run build, 34 статические страницы. Последняя проверка квоты перед завершением блока: использовано 37% пятичасового окна и 50% недельного; это общий расход аккаунта, не оценка стоимости этапа.
Остаток для этапа 4
- Доменные legacy-таблицы: backups, bgp-sessions, certificates, data-collection-scheduler, filters, firewall-rules, firewall-scenario-rules, gre-pools, gre-tunnels, ospf-bfd, ospf-neighbors, ospf-routes, probes-schedule, probes-speed-probes, recursive-routes, route-optimizer-comm-recs, route-optimizer-full-routes, route-optimizer-ospf-preview, route-optimizer-wan-matrix, subusers, users, vxlan, wireguard, wireguard-peers, ipsec-users-grid.
- Общая основа:
components/data-table.tsx,components/data-grids/shared/legacy-*,components/reui/legacy-data-grid/*; ссылки на legacy layout в DataPageCard и DataPageToolbar. Проверить отсутствие потребителей перед удалением. - Старые Filters: статистика, BGP, backups, backups-history и fallback DataPageToolbar; старые определения полей/вычислитель. Статистика передаёт в API только равенство скалярных срезов: при переносе нельзя принимать OR/отрицание и молча превращать их в равенство. Сохранять незавершённый черновик отдельно от URL.
Следующий шаг: проверить квоту и git status; начать этап 4 в codex/reui-v9-migration, переносить оставшихся потребителей ограниченными группами, затем удалить v8/старые Filters и выполнить общую регрессию. Ветку до этой проверки не выпускать. Коммит этапа 3 — только локальный, без push; настройки skills/AGENTS/.codex других работ не включать.
Этап 4 — блок 1: BGP и OSPF
Перенесены bgp-sessions-data-grid, ospf-neighbors-data-grid, ospf-routes-data-grid, ospf-bfd-data-grid. Использована установленная основа ReUI v9 (useTable, dataGridFeatures, современная оболочка и заголовки); manualPagination: true сохраняет полный список. Стабильные row ID, сортировка, раскрытие BGP и управляемый выбор OSPF сохранены. Убрано неиспользуемое извлечение onHighlight из props, сам внешний контракт не менялся.
Проверки: npx tsc --noEmit --incremental false и целевой ESLint успешны. Три сценария tests/e2e/routing-tables.spec.ts подтвердили 12 строк во всех четырёх таблицах, числовую сортировку, выбор OSPF-соседа, раскрытие/сворачивание BGP после сортировки и пустые ответы API. Один тест сначала ожидал сокращённый текст пустого BFD; после уточнения селектора прошёл. Это HTTP-моки, не подтверждение реальной работы сетевых протоколов. Общая основа не менялась, повторная полная сборка/регрессия отложены до завершения этапа 4.
ReUI checklist получен: сохранены композиция, props установленного API, источники данных и оформление. Полная клавиатурная доступность действий строк, мобильная компоновка и сценарии графа остаются профильному этапу 10 и итоговой приёмке; текущие тесты их не подтверждают.
Квота: на старте использовано 49%, после блока 58% пятичасового окна (общий расход аккаунта). Этап 4 не завершён. BGP и три OSPF-таблицы исключить из списка оставшихся выше; остальные legacy-таблицы и все перечисленные старые Filters ещё остаются.
Точный следующий шаг: проверить git status и квоту, перенести VPN-группу (wireguard-data-grid, wireguard-peers-grid, ipsec-users-grid, gre-pools-data-grid, gre-tunnels-data-grid, vxlan-data-grid) с профильными проверками. Затем перейти к оставшимся таблицам управления/диагностики и миграции Filters. Старые зависимости удалять только после последнего потребителя. Этот блок сохранить отдельным локальным коммитом без push; ветку не выпускать.
Этап 4 — блок 2: WireGuard
Перенесены wireguard-data-grid и wireguard-peers-grid на установленную основу ReUI v9. Сохранены внешние props, идентификаторы, обработчики операций и раскрытие интерфейса. Явное manualPagination: true сохраняет все строки без скрытого ограничения в десять записей. Общие примитивы и сетевые операции не менялись.
Проверки: TypeScript (--incremental false) и целевой ESLint прошли без замечаний. Два браузерных сценария tests/e2e/wireguard-tables.spec.ts прошли: 12 интерфейсов, сортировка по порту, раскрытие/сворачивание пиров выбранного интерфейса, 12 строк отдельной вкладки пиров, сортировка и пустые состояния обеих вкладок. Фикстура проверяется схемой wgListResponseSchema, ответы подменяются на HTTP-уровне. Реальные операции RouterOS и права этими тестами не проверены; их приёмка остаётся этапу 9. Применён уже полученный ReUI checklist: сохранены композиция, публичный API и оформление; полная доступность и адаптивность ещё не приняты.
Квота на старте: использовано 67% пятичасового окна; после браузерных проверок — 74% (остаток 26%). Новый блок не начинать на границе резерва. Полная сборка и общая регрессия остаются завершению этапа 4, общая основа в этом блоке не менялась.
Следующий шаг после проверки квоты: перенести оставшиеся четыре VPN-таблицы ipsec-users-grid, gre-pools-data-grid, gre-tunnels-data-grid, vxlan-data-grid. WireGuard, BGP и три OSPF-таблицы уже исключены из остатка. Остальные таблицы управления/диагностики и старые Filters ещё не перенесены; этап 4 не завершён, ветку не выпускать. Блок WireGuard сохранить локальным коммитом без push.
Этап 4 — блок 3: VXLAN
По явному поручению пользователя продолжить ниже резервного порога выполнен один небольшой блок: vxlan-data-grid перенесён на установленную ReUI v9-оболочку. Использованы useTable, dataGridFeatures, типы v9 и manualPagination: true; сохранены идентификаторы, сортировка и обработчик экспорта. Общая основа не менялась.
TypeScript (--incremental false), целевой ESLint и браузерный сценарий tests/e2e/vxlan-table.spec.ts прошли. Проверены 12 строк, числовая сортировка VNI, открытие экспорта выбранного туннеля после сортировки, поиск, пустой результат и сброс. Использованы типизированные HTTP-моки; скачивание файла, применение RouterOS и существующие пункты редактирования/включения/удаления этим тестом не проверены. По ранее полученному ReUI checklist сохранены композиция, публичный API и оформление; профильная доступность и адаптивность остаются этапу 9. Полная регрессия остаётся завершению этапа 4.
После проверок осталось 8% пятичасового лимита (общая квота аккаунта). Блок сохранить локальным коммитом без push. Следующий шаг после сброса: ipsec-users-grid, gre-pools-data-grid, gre-tunnels-data-grid; затем оставшиеся таблицы управления/диагностики и старые Filters. VXLAN исключить из предыдущего списка остатка. Этап 4 не завершён, ветку не выпускать.
Этап 4 — блок 4: IPsec и GRE (2026-09-14)
Перенесены ipsec-users-grid, gre-tunnels-data-grid, gre-pools-data-grid: useTable, dataGridFeatures, типы и общая оболочка ReUI v9. Явное manualPagination: true сохраняет полный список. Сохранены существующие идентификаторы и обработчики; ID GRE по-прежнему включает индекс исходных данных, его стабильность при переупорядочивании ответа API не улучшалась в этом блоке. Установленные примитивы и сетевые правила не менялись.
Проверки: TypeScript (--incremental false), целевой ESLint и три браузерных сценария tests/e2e/ipsec-gre-tables.spec.ts прошли. Проверены 12 клиентов IPsec, сортировка и подтверждение удаления выбранного клиента с отменой; 12 GRE-туннелей и производных пулов, числовая сортировка MTU, поиск, сортировка пулов и пустые ответы API. Селектор заголовка «Клиент» уточнён после совпадения с кнопкой панели. IPsec-фикстура валидируется контрактной схемой; GRE типизирован через доменную модель. Используются HTTP-моки: применение RouterOS, удаление клиента и экспорт сертификата этим прогоном не проверены.
ReUI checklist получен; сохранены публичный API, композиция и оформление. Полная доступность, адаптивность, работа операций и существующие декоративные действия GRE-пулов остаются профильному этапу 9 и итоговой приёмке. Общая основа не менялась; полная сборка и регрессия остаются завершению этапа 4.
Квота: в начале использовано 1%, после проверок 18% пятичасового окна (общий расход аккаунта). VPN-группа миграции завершена, этап 4 в целом ещё открыт. Следующий конкретный блок — users-data-grid, subusers-data-grid, certificates-data-grid, backups-data-grid; затем оставшиеся таблицы диагностики/управления и Filters. Только после последнего потребителя удалить legacy-основу и v8 и выполнить общую регрессию. Блок IPsec/GRE сохранить локальным коммитом без push; ветку до завершения этапа 4 не выпускать.
Этап 4 — блок 5: таблицы администрирования (2026-09-14)
Перенесены users-data-grid, subusers-data-grid, certificates-data-grid, backups-data-grid на установленный API ReUI v9 с явным manualPagination: true. Сохранены идентификаторы, обработчики и раскрытие. SubusersDataGrid сейчас не имеет потребителей в app/components; для него выполнена статическая проверка, браузерная приёмка не заявляется.
Браузерная проверка выявила сортировку размера бэкапа по форматированной строке. В Backup добавлено необязательное sizeBytes; страница сохраняет число байтов из API, таблица сортирует по нему. Отображение размера не менялось. При отсутствии исходного числа запись считается неизвестной и располагается в конце (sortUndefined: "last"), строка не превращается в выдуманное число. Старые демонстрационные объекты без sizeBytes не дают числовой сортировки; текущая страница загружает бэкапы через API.
Три сценария tests/e2e/admin-tables.spec.ts прошли: 12 пользователей и сертификатов с сортировкой/раскрытием, SAN выбранного сертификата, 12 бэкапов с числовой сортировкой и правильным файлом в подтверждении удаления с отменой. Исправлены неполные HTTP-фикстуры настроек сертификатов, вызывавшие предупреждения controlled/uncontrolled. Реальные права, удаление, восстановление и операции сертификатов этим прогоном не проверены. Общая сборка/регрессия остаётся завершению этапа 4.
Применён полученный ReUI checklist: сохранены композиция и установленный API; полная доступность и адаптивность остаются профильной приёмке. Квота: использовано 26% на старте, 50% после браузерных проверок (общий расход аккаунта). Блок сохранить локальным коммитом без push.
Следующий блок: filters-data-grid, firewall-rules-data-grid, firewall-scenario-rules-data-grid. Затем data-collection-scheduler-data-grid, probes-schedule-data-grid, probes-speed-probes-data-grid, recursive-routes-data-grid и четыре route-optimizer-*-data-grid. Также остаются общая legacy-основа, components/data-table.tsx, старые Filters и зависимость v8. Этап 4 не завершён, ветку не выпускать.
Статические проверки блока 5: TypeScript прошёл; lint четырёх таблиц, фикстур и доменной модели — без замечаний. Расширенный lint app/(main)/backups/page.tsx обнаружил исходную ошибку react-hooks/set-state-in-effect на void loadLive() в эффекте (подтверждено в HEAD до правок). Эта ошибка не исправлялась в миграции; устранить при работе над состояниями данных на этапе 5. Не считать lint всей страницы успешным.
Этап 4 — блок 6: таблица сетевых Filters (2026-09-14)
filters-data-grid перенесён на установленную ReUI v9-основу с полным списком (manualPagination: true). Сохранены props, ID, обработчики и действующее отключение сортировки в live-режиме. Кнопки поднятия/опускания правила получили доступные подписи с community. Это миграция таблицы сетевых правил; старый компонент построения Filters/FilterQuery этим блоком не затронут.
TypeScript и целевой ESLint прошли. Браузерный сценарий tests/e2e/network-filters-table.spec.ts подтвердил 12 строк, исходный порядок и отсутствие кнопки сортировки в live-режиме, блокировку перемещения за границы, поиск/пустой результат/сброс. Первый вариант теста ошибочно ожидал доступную сортировку; ожидание исправлено под существующий контракт страницы. HTTP-моки не подтверждают перестановку и применение правил к RouterOS. Применён ранее полученный ReUI checklist; профильная приёмка операций и доступности остаётся этапу 9.
Квота: на старте использовано 64%, после статических проверок — 78% (остаток 22%). Новые блоки не начинать в резерве. Firewall не переносился: firewall-rules-data-grid использует DnD и требует чтения нового API и профильного браузерного теста перетаскивания с проверкой порядка. Следующий блок после проверки квоты — обе Firewall-таблицы; далее восемь таблиц диагностики/сборщика, общие legacy-потребители, старые Filters и удаление v8. Этап 4 остаётся открытым, ветку не выпускать. Сохранить локальный коммит без push.
Этап 4 — блок 7: Firewall и DnD
Перенесены firewall-rules-data-grid и firewall-scenario-rules-data-grid. Общая основа — установленный ReUI v9; полный список сохранён через manualPagination: true. В режиме DnD применён manualSorting: reorderable, в локальном сценарии — manualSorting: true. Сохранены row ID, обработчики, формат запросов и правила допустимости перемещения. Props DataGridTableDndRows сверены с установленным исходником: dataIds, handleDragEnd. Примитивы ReUI не менялись. Действия сценария получили подписи поднятия/опускания/удаления и видимость при фокусе.
Пять браузерных сценариев tests/e2e/firewall-tables.spec.ts прошли: клавиатурное и мышиное перемещение среди 12 правил, правильные rosId/destinationRosId в API, откат при ошибке 500, Escape без запроса, 12 правил локального сценария с перестановкой и удалением выбранной строки. Начальные падения объяснялись преждевременным завершением переноса в тесте; добавлено ожидание фактической смены цели DnD через live-region. Тесты используют HTTP-моки, не подтверждают применение RouterOS. Перенос между серверами/таблицами, touch, сортируемый режим общего списка и поведение на больших наборах остаются профильной и общей регрессии.
TypeScript и целевой ESLint прошли. ReUI checklist получен: сохранены композиция и публичный API; проверены мышь/клавиатура и отмена переноса. Служебные объявления DnD пока английские — локализовать при профильной доступности, не считать её полностью принятой. Остальные ограничения предыдущих блоков сохраняются.
Квота: использовано 0% на старте обновлённого окна, 34% после профильных тестов (общая квота аккаунта). Следующий блок — data-collection-scheduler-data-grid, probes-schedule-data-grid, probes-speed-probes-data-grid; затем recursive-routes-data-grid и четыре route-optimizer-*-data-grid. После них остаются общая legacy-основа/data-table, старые Filters и удаление v8 с полной регрессией. Этап 4 ещё не завершён; локальный коммит без push, ветку не выпускать.
Production build блока 7: npm run build прошёл, 34 статические страницы. Это проверка сборки, не замена общей регрессии этапа 4.
Этап 4 — блок 8: сборщик и расписания проб (2026-09-14)
Перенесены data-collection-scheduler-data-grid, probes-schedule-data-grid, probes-speed-probes-data-grid на установленный ReUI Data Grid/TanStack v9: useTable, dataGridFeatures, общая современная оболочка и заголовки. Сохранены идентификаторы строк, обработчики и порядок задач сборщика; автоматическая пагинация отключена. Кнопка запуска задачи получила доступное имя с названием задачи.
Проверки: TypeScript без incremental и ESLint изменённых файлов; три сценария Playwright — 12 speed-probes и сортировка источника, все 11 задач сборщика и POST выбранного alert_engine/run-now, сортировка и удаление выбранного правила демонстрационного расписания. Финальный браузерный прогон: 3 passed. Исправлены неполные фоновые HTTP-фикстуры EvoBGP, GeoIP и Traffic Flow; повторный прогон без предупреждений controlled/uncontrolled. Live-ветки проверены с подменой HTTP, обычное расписание — отдельно во встроенном mock-режиме. Реальное исполнение задач и RouterOS не проверялись.
Первичная проверка TypeScript до браузерного запуска прошла. Финальная повторная проверка после Playwright заблокирована двумя TS2304 в сгенерированном .next/dev/types/validator.ts (строки 379 и 388: отсутствует RouteHandlerConfig). next typegen успешно обновил типы, но ошибку dev-кэша не устранил. Исходники и конфигурация TypeScript ради обхода ошибки не менялись. При продолжении проверить dev-кэш и повторить tsc; финальный TypeScript не считать пройденным. ESLint изменённых файлов прошёл.
Применены правила установленного ReUI и ранее полученный checklist: публичный API и существующая композиция сохранены, полная визуальная/адаптивная приёмка остаётся последующим этапам. Общая основа не менялась; полная регрессия — после завершения миграции.
Квота: использовано 46% на старте, 81% перед финальными проверками. Остаток ниже резерва 25%, новые блоки не начинать. Следующий шаг — recursive-routes-data-grid и четыре route-optimizer-*-data-grid; далее data-table, общие legacy-потребители, старые Filters и удаление v8 с общей регрессией. Этап 4 остаётся открытым; сохранить блок локальным коммитом без push, ветку не выпускать.
Этап 4 — блок 9: рекурсивные маршруты (2026-09-14)
По прямому указанию пользователя продолжена работа ниже резерва квоты (89% использовано на старте). recursive-routes-data-grid переведён на установленную общую оболочку ReUI/TanStack v9, сохранены управляемое раскрытие по ключу группы, сортировка, обработчики редактирования/удаления и отсутствие пагинации.
Проверки: Playwright recursive-routes-table.spec.ts — 1 passed (12 групп через HTTP-мок, сортировка в обе стороны, раскрытие и закрытие деталей после сортировки, отсутствие pageerror); ESLint компонента и теста — успешно. TypeScript до и после браузерного прогона — успешно. Реальные сетевые изменения не проверялись.
Уточнение блока 8: в .next/types/validator.ts присутствовала полноценная декларация RouteHandlerConfig и проверки обоих API-маршрутов. Удалён только ошибочный сгенерированный .next/dev/types/validator.ts; исходники, tsconfig и production-validator сохранены. После этого tsc прошёл, в том числе после нового запуска Playwright. Ошибка предыдущей финальной проверки снята; правка кеша не входит в Git.
После блока использовано 95% пятичасовой квоты. Следующий блок — четыре route-optimizer-*-data-grid, затем общие legacy-потребители/data-table, старые Filters и удаление v8 с полной регрессией. Этап 4 не завершён. Этот блок сохранить локальным коммитом без push.
Этап 4 — блок 10: оптимизатор маршрутов (2026-09-14)
Четыре route-optimizer-*-data-grid перенесены на установленный ReUI/TanStack v9. Сохранены динамические колонки WAN × JH, отсутствие сортировки матрицы, раскрытие списка комбинаций (5 → все), сортировка и ключи Community, состояния загрузки/ошибки/пустого OSPF preview. Удалены два неиспользуемых импорта.
Проверки: TypeScript до и после Playwright — успешно; ESLint всех четырёх компонентов и нового теста — без замечаний. route-optimizer-tables.spec.ts: 4 passed, включая 12 WAN, 12 комбинаций, сортировку и закрепление выбранной Community, 12 интерфейсов OSPF и числовую сортировку, пустой ответ и HTTP 500 preview. Первый прогон имел запрос при завершении теста к отключённому backend; добавлено ожидание загрузки основной таблицы, повторный прогон без этого сообщения. Проверки используют live-ветку с HTTP-моками; применение RouterOS не выполнялось.
Обнаруженный исходный долг для этапов 5/10: applyRec страницы имитирует успех через таймер даже в live-режиме; buildLiveOptimizerData рассчитывает вероятности Community из длины строки и использует оценочные ping/bandwidth при отсутствии замеров. Тест закрепления не подтверждает реальность применения или достоверность этих оценок. Алгоритмы в блоке миграции не менялись.
Квота: новое окно 0% на старте, 13% использовано после проверок, недельная — 91%. Остаток Data Grid: components/data-table.tsx, layout-импорты DataPageCard/DataPageToolbar и затем удаление общей legacy-основы/v8. Старые Filters остаются у BGP, statistics, backups, backups-history и в fallback DataPageToolbar. Этап 4 не завершён; сохранить блок локальным коммитом без push.
Этап 4 — блок 11: удаление старого Data Grid (2026-09-14)
Мигрирована общая DataTable с сохранением опциональной клиентской пагинации (manualPagination: !pagination). DataPageCard и DataPageToolbar используют современный layout; значения CSS-классов совпадают с прежними. Удалены 14 файлов неиспользуемой legacy-копии и обёрток, а также alias @tanstack/react-table-v8 и его вложенная зависимость из package.json/lockfile. Версия v9 остаётся 9.2.4. Поиск по app/components/lib/package.json/package-lock.json больше не находит импортов legacy Data Grid/v8.
Проверки после удаления общей основы: TypeScript и ESLint изменённых обёрток — успешно; вся браузерная регрессия — 49 passed; production build — успешно, 34 статические страницы. У DataTable сейчас нет потребителей, её generic API проверен компилятором; пагинация рабочих таблиц покрыта регрессией справочников. Next.js сообщил о восстановлении SWC lockfile, итоговый diff lockfile содержит только удаление v8 и вложенного table-core. Старый Filters ещё не удалён: этап 4 остаётся открытым, ветку не выпускать.
Следующий блок — BGP и backups/backups-history на FilterQuery, затем statistics с явным ограничением на поддерживаемые API-срезы (AND равенств) и удаление старого Filters/fallback. Сохранить текущий блок отдельным локальным коммитом без push.
Этап 4 — блок 12: Filters BGP и резервных копий (2026-09-14)
BGP, backups и BackupsHistory используют FilterQuery и современный QueryFilters через filterControl. Поля переведены на FilterField; scalar-поля с несколькими вариантами используют select и операторы выбора. Фильтрация выполняется общим рекурсивным evaluator с сохранением AND/OR и черновиков. Для текстового поля «Сервер» добавлены поддерживаемые ReUI операции starts_with/ends_with, включая отрицание и сравнение без учёта регистра.
Проверки: TypeScript — успешно; 8 профильных браузерных тестов BGP/OSPF/администрирования — passed, включая фильтрацию, изменение значения, AND и сброс; 7 unit-тестов evaluator — passed. Первый запуск tsx в sandbox завершился системной ошибкой uv_os_get_passwd ENOMEM; повтор вне sandbox прошёл. ESLint без ошибок в проверенных файлах, в BGP остаются 7 исходных предупреждений неиспользуемых импортов/StateBadge; известная исходная ошибка effect в backups/page не исправлялась этим блоком, lint всей этой страницы не заявляется чистым.
После блока использовано 42% пятичасовой и 96% недельной квоты. Остались statistics, старый fallback DataPageToolbar и старые Filters/helper; после их удаления повторить общие проверки. Сохранить блок локальным коммитом без push. Этап 4 остаётся открытым.
Этап 4 — подготовка блока 13: адаптер статистики (2026-09-14)
Добавлен независимый statistics-filter-query.ts: преобразование URL-срезов в FilterQuery и строгий обратный адаптер с результатами valid/draft/invalid. Поддерживается только AND равенств скалярным строкам; OR, отрицание, массивы, неизвестные поля и конфликтующие значения не преобразуются молча. Незавершённый черновик не возвращает частичный набор срезов. Страна нормализуется в двухбуквенный код, ASN/serverId проверяются как положительные безопасные целые; недопустимые значения не обрезаются и не очищаются до другого числа.
Проверки: 5 unit-тестов адаптера, ESLint и TypeScript — успешно. Адаптер пока не подключён к экрану: это подготовительный checkpoint, а не завершение миграции statistics.
Точный следующий шаг: создать StatisticsFilters с отдельным локальным черновиком FilterQuery и отображением ошибки адаптера; обновлять URL/запрос только при valid, сохранять прежние срезы при draft/invalid; синхронизировать внешний переход/сброс URL с черновиком. Полям дать только оператор is, остальные неподдерживаемые выражения всё равно проверять адаптером. Затем удалить старые slicesToFilters/filtersToSlices страницы, fallback DataPageToolbar, components/reui/filters.tsx и неиспользуемый старый evaluator после проверки всех импортов. Unit-тест совместимости со старым evaluator заменить самостоятельными ожидаемыми результатами. Завершить браузерными тестами URL/черновика/ошибки и общей регрессией, только затем закрывать этап 4.
Квота после подготовки: 49% пятичасовой и 97% недельной использовано. Сохранить подготовку локальным коммитом без push. Чужие изменения skill/AGENTS/.codex не включать.
Этап 4 — блок 13: подключение Filters статистики (2026-09-14)
StatisticsFilters подключён вместо старого массива Filter. Поля предлагают только is, адаптер дополнительно отклоняет неподдерживаемые выражения. Локальный черновик не изменяет URL до явного «Применить срез»; invalid/draft блокируют применение и сохраняют действующие срезы. Ключ редактора зависит от URL-срезов, поэтому внешний переход сбрасывает черновик. Старые функции slicesToFilters/filtersToSlices страницы удалены.
TypeScript до и после первого браузерного прогона и scoped ESLint прошли. Расширенный браузерный сценарий статистики прошёл: сортировка/переход в срез, восстановление фильтра из URL, редактирование без изменения URL, применение, сброс, отклонение RUS без обрезания до RU и внешняя смена страны на DE. В первом расширенном прогоне исправлен неоднозначный локатор alert; повтор — 1 passed. Проверки через HTTP-моки.
На последнем чтении использовано 62% пятичасовой и 99% недельной квоты. Старые Filters/fallback/helper ещё физически остаются, поэтому этап 4 НЕ завершён. Следующий шаг — удалить неиспользуемый fallback DataPageToolbar и старые Filters/evaluator после проверки импортов, обновить тест совместимости, затем выполнить полную регрессию и production build. Сохранить этот блок локальным коммитом без push.
Этап 4 — завершение: удаление старого Filters (2026-09-20)
Удалены components/reui/filters.tsx, apply-reui-filters.ts и временный migrate-filter-query.ts. У DataPageToolbar удалены устаревшие props filters/onFiltersChange/filterFields и их fallback; все четыре действующих потребителя используют filterControl и FilterQuery. Props filters/onFiltersChange у BackupsHistory остаются внутренним контрактом нового FilterQuery, а не старого Filters. Unit-тест сравнения двух реализаций заменён независимыми ожидаемыми результатами для шести операторов с AND.
| Финальная проверка миграции | Результат |
|---|---|
| Поиск старых FilterFieldConfig/applyReuiFilters/migrateFilterQuery, legacy-data-grid и react-table-v8 в app/components/lib/tests/package.json/package-lock.json | Совпадений нет |
| Unit-тесты дерева FilterQuery | 7 passed |
| Unit-тесты адаптера статистики | 5 passed |
| TypeScript без incremental | Успешно |
| ESLint изменённых файлов | Успешно |
| Полная браузерная регрессия | 51 passed, 2.4 минуты |
| Production build | Успешно, 34 статические страницы |
| git diff --check изменённых файлов | Успешно |
Получен актуальный ReUI MCP get_audit_checklist: в этом блоке сохранены установленная композиция, публичный API и тема, новых данных/интерактивных элементов/секретов не добавлено. Миграция Data Grid/TanStack v9 и Filters завершена; старые временные API больше не нужны. Это завершение технической миграции, а не полной UX/UI-приёмки: остаются ранее записанные ограничения адаптивности/доступности, исходные lint-долги страниц, имитация Community apply и оценки в оптимизаторе. Реальные RouterOS, права на сетевые операции и все состояния backend по мокам не подтверждены. Полный repository lint не заявляется чистым; профильные проверки изменённых участков и production build прошли.
Квота: 2% пятичасовой/0% недельной использовано на старте; после регрессии — 32%/5%. Этап 4 сохранить локальным коммитом без push. Изменения skills/AGENTS/.codex другой работы не включать. Общую регрессию этапа 4 считать выполненной; автоматический merge, push или релиз не выполнялись.
Следующий этап 5: hooks/use-dashboard-live.ts и app/(main)/dashboard/page.tsx. Подтверждено чтением: fetchSnapshot уже использует Promise.allSettled, но при ошибках очищает probes/servers/BGP/traffic/overlay, а fetchRecentEvents очищает события; обновления запускаются из нескольких effects и таймеров без защиты результатов запросов. Ввести состояния/свежесть по источникам и сохранение последних успешных данных; отличать начальную ошибку от частичного сбоя и фонового обновления. Защитить смену backend/mode и перекрывающиеся запросы от поздних результатов, включая дополнительные запросы Internet Path. Проверить HTTP-моками первоначальную ошибку, частичный сбой, повторное восстановление и гонки; профильный UX показывать без подмены неизвестных данных нулями. Зафиксировать отдельным коммитом этапа 5.
Этап 5 — состояния данных дашборда (2026-09-20)
use-dashboard-live сохраняет последние успешные servers/probes/BGP/traffic/events и отдельные GRE/WireGuard/VXLAN при сбоях. Состояние и время успешного получения ведутся по девяти источникам; Internet Path дополнительно показывает серверный sampledAt. Новый DashboardDataStatus использует существующие Alert/Button, сообщает частичный сбой, раскрывает время/ошибки источников и позволяет повторить загрузку. Неизвестные KPI отображаются как «—», пустые очереди проблем при недоступных источниках больше не утверждают «всё исправно». При фоновом обновлении сохранённые данные остаются видимыми.
Для snapshot и событий введены независимые счётчики запросов: применяются только результаты последнего запроса, включая дополнительные await Internet Path; cleanup инвалидирует незавершённые ответы при смене контекста или размонтировании. Убран дублирующий первоначальную загрузку effect по pathname. Смена backend/mode очищает данные предыдущего контекста. Это защита состояния, а не отмена уже отправленных HTTP-запросов.
Internet Path использует успешный серверный снимок независимо от сбоя списка серверов. Ошибка snapshot или обязательных данных fallback сохраняет старую модель; ошибки дополнительных lookup/wan-runtime/speed-probes не маскируются новым пустым снимком. Сами сетевые команды и правила выбора маршрутов не менялись.
Проверки: TypeScript и scoped ESLint — успешно; 5 браузерных сценариев passed: начальная ошибка и восстановление, частичный сбой с сохранением данных/событий/времени, поздний основной ответ, ошибка дополнительной загрузки Internet Path, поздний дополнительный ответ. Для проверки поздних ответов тест дожидается завершения HTTP и двух кадров отрисовки. Сценарий частичного сбоя дополнительно повторён на ширине 390; скриншоты 1440/390 просмотрены, новый блок не обрезан, восстановление доступно. Получен ReUI checklist; используются существующая композиция, семантические цвета, role=status/alert и подписанная кнопка type=button. Общая основа ReUI не менялась, полная регрессия/production build не повторялись после успешной приёмки этапа 4 в этом окне.
Границы: браузерные проверки идут через HTTP-моки; реальная свежесть RouterOS не подтверждена. Время «Получено» обозначает успешный ответ API, не новый замер устройства; sampledAt показан отдельно, где доступен. Смена backend/mode защищена cleanup, но отдельный браузерный сценарий смены backend не запускался (в e2e backend фиксирован конфигурацией). Существующие доменные допущения вроде null server.status → offline и оценочных метрик оптимизатора относятся к следующим профильным этапам.
Квота: 41% пятичасовой на старте, 73% после профильных проверок (недельная 11%). Следующий этап 6 — общая оболочка и дашборд: показать одну схему ПК/телефона по App Shell 12/Stats 12, затем улучшать навигацию, контекст и очередь проблем с переходами к объектам. Этот этап сохранить отдельным локальным коммитом без push; настройки skills/AGENTS/.codex не включать.
Этап 6 — блок 1: схема и адаптивная шапка (2026-09-20)
Схема ПК/телефона и таблица референсов сохранены в docs/ux-ui-stage-6.md. PageHeader сохраняет установленные SidebarTrigger/Breadcrumb/AppsMenu/SystemMonitorPopover: текущая страница видна на телефоне, действия переносятся, фиксированная высота снята. У Breadcrumb корректные прямые li внутри ol и русское доступное имя. Примитивы ReUI, зависимости и backend не менялись.
Проверки: TypeScript и scoped ESLint успешны. Четыре браузерных сценария шапки (320/390/1024/1440 px) прошли: геометрия заголовка/кнопок, меню с клавиатуры, Escape и возврат фокуса. Дополнительно прошли таблица рекурсивных маршрутов и мобильный сценарий серверов. Просмотрены скриншоты 320/1440. Первый запуск теста ошибочно искал banner: header внутри main этой роли не имеет; локатор исправлен без изменения семантики приложения. ReUI validate_usage/checklist получены ранее, используются установленные API и семантические цвета.
Предыдущая попытка запуска была остановлена ошибкой автоматической проверки разрешений из-за исчерпанной квоты; после сброса проверка запуска прошла. На старте этого продолжения использовано 2% пятичасовой и 16% недельной квоты. Этап 6 остаётся открытым. Следующий блок — единый список Sidebar/CommandPalette и стандартное управление фокусом поиска, затем дашборд и ссылки очереди. Локальный коммит без push; файлы настройки другой работы не включать.
Этап 6 — блок 2: навигация и поиск (2026-09-20)
lib/navigation.ts — общий каталог 30 страниц, групп, иконок и поисковых синонимов. AppSidebar и CommandPalette используют его вместо двух независимых списков. Названия «Мониторинг» и «Communities» согласованы; поисковые синонимы uptime/BGP сохранены. NavMain получил именованный nav и aria-current; мобильная шторка закрывается при клиентском переходе, включая выбор текущей страницы.
CommandPalette использует установленные Command/cmdk и Base UI Dialog вместо самописного затемнённого окна и ручной навигации. Фокус при открытии переходит в поиск, Tab удерживается внутри, Escape возвращает фокус; ввод сбрасывается при новом открытии. Поддержаны поиск по синонимам, стрелки/Enter, объявление пустой выдачи, светлая/тёмная тема. Высота списка ограничена высотой диалога и viewport. Новые зависимости и примитивы не устанавливались; данные/API и схема прав не менялись.
Профильные проверки: 4 сценария navigation passed (один проверяет каталог по реальным файлам страниц), 4 сценария шапки passed. Проверены переход на серверы и возврат браузером, пустой поиск, фокус, мобильный выбор текущей страницы, размеры 390×600 в двух темах; скриншоты просмотрены. TypeScript успешен; ESLint новых navigation/CommandPalette/NavMain/test успешен. В AppSidebar сохранилась исходная ошибка react-hooks/set-state-in-effect на сбросе liveCounts при смене режима; её наличие подтверждено чтением HEAD до изменений, логика счётчиков не менялась. Не заявлять чистый lint всего проекта.
Блок готов для локального коммита без push. Этап 6 продолжается: иерархия дашборда, затем переходы из очереди к конкретным объектам.
Этап 6 — блок 3: сводка и приоритет проблем (2026-09-20)
Дашборд сохраняет KpiStatGrid, AttentionQueue и Frame, но очередь «Требует внимания» теперь идёт сразу после сводки, до измерений. Быстрые переходы перенесены вниз. Подписи заменены на «Серверы онлайн», «Туннели работают», «Префиксы BGP», «Проверки с проблемами»; состояния в очереди названы по-русски. Длинные имена проблем переносятся вместо обрезки. Состояния пустого каталога серверов, отсутствия туннелей и активных проверок отделены от отсутствия ошибок.
useDashboardLive больше не обрезает массивы проблем до пяти до подсчёта. Счётчики учитывают все элементы; UI сначала показывает пять и раскрывает остальные через «Ещё N» с клавиатуры. Загрузка/частичные сбои/свежесть/защита от поздних ответов этапа 5 сохранены. Запросы и сетевые операции не менялись.
Приёмка текущей общей основы: 65 Playwright-тестов passed, включая 6 сценариев дашборда, 4 навигации и 4 шапки; отдельные профильные запуски также успешны. Новый сценарий проверяет 7 проблем при 5 видимых строках, раскрытие клавиатурой, порядок очереди перед измерениями, пустые активные проверки и ширину 390. Просмотрены скриншоты дашборда 1440/390 и поиска в двух темах. Production build успешен: контракты, TypeScript, 34 страницы. Scoped ESLint нового кода успешен; исходная ошибка AppSidebar описана в блоке 2. ReUI checklist получен; vendored-примитивы, зависимости и тема не менялись. Проверки используют HTTP-моки, реальный RouterOS не проверен.
Этап 6 ещё не завершён. Ссылки AttentionRow пока открывают профильный раздел (/servers, /uptime, /gre, /wireguard, /vxlan), без выбора конкретного объекта. Следующий точный шаг: спроектировать единый URL-контракт идентификатора объекта и сервера, подключить принимающие страницы и только после этого заменить href очереди. Начать с сервера и проверить «дашборд → конкретный сервер → назад», прямое открытие URL, удалённый/недоступный объект, затем адаптировать мониторинг и туннели. Не считать query-параметр рабочим, пока целевая страница его не обрабатывает. Полные формы/права/фильтры URL этапа 7 остаются следующим этапом.
Границы: текущий mapper дашборда по-прежнему трактует null server.status как offline; неизвестные состояния устройств требуют отдельного исправления и проверки. Квота при завершении общей регрессии и запуске build: использовано 65% пятичасовой и 26% недельной. Сохранить блок локальным коммитом без push; изменения skills/AGENTS/.codex не включать.
Этап 6 — блок 4: переход к серверу (2026-09-20)
Очередь серверов дашборда формирует /servers?server=<encoded id>. Страница серверов читает параметр в Suspense, ограничивает таблицу точным ID и показывает контекст перед общей сводкой. «Все серверы» снимает только параметр server, сохраняя остальные query-параметры; «К дашборду» и браузерный возврат доступны. Прямой URL и перезагрузка сохраняют выбор. При отсутствующем ID или 403/500 другой сервер не подставляется. Состояния загрузки, ошибки получения и отсутствующего объекта разделены.
При выбранном сервере верхняя кнопка «Проверить сервер» опрашивает только его через существующую очередь операций. Без параметра сохраняется прежний массовый опрос. API, права и правила мутаций не менялись. Контекст использует установленный ReUI Alert; состав общей сводки явно указан. Полная синхронизация поиска/Filters/форм с URL остаётся этапу 7.
Проверки: 27 профильных сценариев servers/dashboard passed; после переноса контекста над сводкой повторно пройден сценарий выбора/опроса/возврата и просмотрен мобильный экран 390. ESLint изменённых файлов успешен. Production build прошёл: контракты, TypeScript, 34 страницы. HTTP-фикстура дашборда дополнена и проверяется serverReadSchema: переход на сервер использует строгий API-контракт. Реальный RouterOS не проверялся.
Окружение: предыдущий запуск остановился из-за исчерпанной квоты автоматической проверки разрешений. После сброса обнаружен dev-кеш Next.js, возвращавший 404 для существующего маршрута; .next/dev сохранён как .next/dev-before-server-links, чистый кеш устранил ошибку, пять URL-сценариев и вся профильная регрессия прошли. Это игнорируемые сборочные артефакты, не исходники.
Квота нового окна: 1% использовано на старте, 26% при запуске итоговой сборки. Блок сохранить отдельным локальным коммитом без push. Этап 6 открыт: далее /uptime?probe=<id> и обработка выбранной проверки, затем туннели с идентификатором устройства и объекта.
Карта миграции (исходная инвентаризация этапа 0)
Исходная связка на этапе 0: @tanstack/react-table ^8.21.3, @tanstack/react-virtual ^3.14.4, base-nova. По итогам этапа 4 используется @tanstack/react-table 9.2.4 с useTable/dataGridFeatures и дерево FilterQuery вместо старого filters/onChange. Список ниже сохранён как историческая инвентаризация.
Источники: контракт UI, таблицы PRO, API Data Grid, API Filters.
Прямые потребители TanStack (47)
components/data-grids/asns-data-grid.tsxcomponents/data-grids/backups-data-grid.tsxcomponents/data-grids/bgp-sessions-data-grid.tsxcomponents/data-grids/certificates-data-grid.tsxcomponents/data-grids/communities-data-grid.tsxcomponents/data-grids/compact-data-grid.tsxcomponents/data-grids/data-collection-scheduler-data-grid.tsxcomponents/data-grids/domains-data-grid.tsxcomponents/data-grids/filters-data-grid.tsxcomponents/data-grids/firewall-rules-data-grid.tsxcomponents/data-grids/firewall-scenario-rules-data-grid.tsxcomponents/data-grids/gre-pools-data-grid.tsxcomponents/data-grids/gre-tunnels-data-grid.tsxcomponents/data-grids/ip-ranges-data-grid.tsxcomponents/data-grids/ospf-bfd-data-grid.tsxcomponents/data-grids/ospf-neighbors-data-grid.tsxcomponents/data-grids/ospf-routes-data-grid.tsxcomponents/data-grids/probes-schedule-data-grid.tsxcomponents/data-grids/probes-speed-probes-data-grid.tsxcomponents/data-grids/recursive-routes-data-grid.tsxcomponents/data-grids/route-optimizer-comm-recs-data-grid.tsxcomponents/data-grids/route-optimizer-full-routes-data-grid.tsxcomponents/data-grids/route-optimizer-ospf-preview-data-grid.tsxcomponents/data-grids/route-optimizer-wan-matrix-data-grid.tsxcomponents/data-grids/servers-data-grid.tsxcomponents/data-grids/shared/data-grid-shell.tsxcomponents/data-grids/shared/data-grid-sort-header.tsxcomponents/data-grids/subusers-data-grid.tsxcomponents/data-grids/traffic-flows-data-grid.tsxcomponents/data-grids/uptime-resources-data-grid.tsxcomponents/data-grids/uptime-speed-history-data-grid.tsxcomponents/data-grids/users-data-grid.tsxcomponents/data-grids/vxlan-data-grid.tsxcomponents/data-grids/wireguard-data-grid.tsxcomponents/data-grids/wireguard-peers-grid.tsxcomponents/data-table.tsxcomponents/ipsec/ipsec-users-grid.tsxcomponents/reui/data-grid/data-grid-column-filter.tsxcomponents/reui/data-grid/data-grid-column-header.tsxcomponents/reui/data-grid/data-grid-column-visibility.tsxcomponents/reui/data-grid/data-grid-table-dnd-rows.tsxcomponents/reui/data-grid/data-grid-table-dnd.tsxcomponents/reui/data-grid/data-grid-table-virtual.tsxcomponents/reui/data-grid/data-grid-table.tsxcomponents/reui/data-grid/data-grid.tsxcomponents/traffic/flow-analytics-panel.tsxcomponents/traffic/flow-traffic-map.tsx
Прямые потребители Filters (6)
app/(main)/backups/page.tsxapp/(main)/bgp/page.tsxapp/(main)/servers/page.tsxapp/(main)/statistics/page.tsxcomponents/backups/backups-history.tsxcomponents/data-page-toolbar.tsx