fix(ui): сохранить целый CIDR в таблице маршрутов OSPF

This commit is contained in:
Denozordec committed 2026-10-09 22:26:08 +07:00
1 parent ee704a86f2
commit c9bf5abe55
13 files changed
+290 -6

No files matched your search

@@ -49,12 +49,12 @@ function OspfRoutesDataGrid({ routes, emptyTitle }: OspfRoutesDataGridProps) {
() => [
{
id: "destination",
size: 150,
size: 180,
accessorKey: "destination",
header: ({ column }) => (
<DataGridSortHeader column={column} title="Назначение" className="ml-1" />
),
cell: ({ row }) => <span className="font-mono whitespace-normal break-all">{row.original.destination}</span>,
cell: ({ row }) => <span className="font-mono whitespace-nowrap" title={row.original.destination}>{row.original.destination}</span>,
meta: {
headerTitle: "Назначение",
headerClassName: DATA_GRID_CELL_PAD_FIRST,
+12
View File
@@ -835,3 +835,15 @@ Production image не содержит dev-only jose: первый fixture impor
**Очистка.** Exact ID/name/comment/address/interface/interfaces/addresses/public key preflight; удалены только свои templates/area/instance/BFD/IP/bridge/GRE/WG peers/interfaces. Исходные IDs10 коллекций×2 совпали, public/default routes и195.195.195.195/32 сохранены. WG secret fields не включены в report. Оба CHR доступны, passwords неизменны; временных контейнеров не осталось. Backend diagnostics89/PG healthy, frontend optimizer87 сохранён. Один локальный commit без push.
Схема: primary → BFD/adjacency loss → alternate GRE over WG → проверка data plane → восстановленный primary. Транспорт подтверждён [GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE) и [WireGuard](https://help.mikrotik.com/docs/spaces/ROS/pages/69664792/WireGuard); таблицы сохраняют референсы общего плана. Продолжение91 — обрезка CIDR, затем BGP propagation/остальные внешние границы. BFD-only устойчивый запрет/physical WAN/IPv6/scale/maximum throughput/Portal SSO остаются открыты. Квота66% использовано; этап12.5 открыт.
## 12.5.91 — OSPF Data Grid: целый IPv4 CIDR (2026-10-09)
Уточнена визуальная проблема90: это не потеря API-данных, а перенос последней цифры /32 на вторую строку; первый ряд выглядел как /3. Столбец назначения расширен150→180px, span использует whitespace-nowrap и title полного значения. Установленные Data Grid/Table/ScrollArea, pinned column, theme и структура сохранены. ReUI inline API и audit checklist прочитаны; [API](https://reui.io/docs/components/base/data-grid?ref=mcp), [превью](https://reui.io/components/data-grid?ref=mcp).
**Проверки.** Новый browser test ждёт document.fonts.ready и проверяет Range rectangles: ровно одна строка, текст внутри ячейки. До исправления1280px failed: /3 и2 дали два rect. Первоначальная проверка только границ проходила и была уточнена, чтобы не пропустить разрыв CIDR. После изменения4 размера320/390/1280/1440 и IPv4 CIDR15/18 символов проходят; сортировка/количество строк/document fit/no writes сохранены. С OSPF unknown cost/disabled/inactive —7/7. Scoped TypeScript, ESLint/diff passed. Это meaningful visual regression, не проверка буквального size в исходнике.
**Live.** Backend diagnostics89 и обновлённый frontend ospf91, без mocks: два CHR×1280/320 =4/4. Свои GRE/OSPF private link198.18.93.0/30/loopbacks198.18.193.1/32↔2/32; Full/active learned route/Ping3/3. Целый /32 виден в одной строке после загрузки шрифтов; title, границы ячейки, URL/reload, document fit/pageerror0 подтверждены. [Browser отчёт](ux-ui/acceptance/browser-ospf-cidr-2026-10-09.json), [native/cleanup](ux-ui/acceptance/ospf-cidr-native-2026-10-09.json), [ПК после](ux-ui/screens/ospf-real-cidr-server1-1280-2026-10-09.png), [320px после](ux-ui/screens/ospf-real-cidr-server1-320-2026-10-09.png). PC снимок просмотрен:198.18.193.2/32 полностью читается. Проверка не обещает одновременную видимость всех колонок на телефоне: сохраняется внутренняя горизонтальная прокрутка.
**Контроль/runtime.** Свои objects удалены по exact IDs/атрибутам, baseline7 коллекций×2 совпал, оба CHR доступны, default/public/195.195.195.195/32 и credentials сохранены. Нормализованные SHA source/deployed DataGrid renderer и OSPF consumer совпадали до изменения, поэтому проблема не была вызвана отставшим компонентом стенда. Один frontend Docker build, production TypeScript/build, entry/node --check/compose --wait passed. mmapp-test/frontend:ux-ospf91/version1.0.0-test.ospf91, image sha256:b4bade515234115b3cad257ceb87ef7beb347e754ca92d6a97a25adc2199fd33. Context optimizer87 frontend +один consumer file, override SHA27a27569335c377bf8662fb5b39d200ce98d52925cafdf51dee165464c1532078, label не Git SHA. .env backup приватный, backend/migrations не менялись, полная регрессия/failover не повторялись. Один локальный commit без push.
Следующий92 — BGP propagation собственных private prefixes, withdrawal/re-advertisement и UI counters; только собственные GRE/instances/filter chains. Квота84% использовано после блока, этап12.5 и внешние границы остаются открытыми.
+1 -1
View File
@@ -1,6 +1,6 @@
# План реализации UX/UI по пятичасовым окнам
Актуальное продолжение 2026-10-09: 12.5.90 принял контролируемый OSPF/BFD failover primary GRE→alternate GRE over WireGuard→primary; steady Ping3/3×2 во всех фазах,4 UI cases. BFD/not-Full≈798ms, first alternate route≈4250ms — HTTP observations, не SLA. Отдельный переходный Ping18/40/55% loss сохранён, бесшовность не заявлена. Baseline10 коллекций×2 восстановлен. Runtime diagnostics89/optimizer87. Следующий12.5.91 — устранить обрезку IPv4 CIDR в OSPF Data Grid, выявленную live desktop снимком; затем BGP route propagation и оставшиеся внешние границы. Квота66% использовано; этап12.5 открыт.
Актуальное продолжение 2026-10-09: 12.5.91 устранил неоднозначное отображение IPv4 CIDR в OSPF: /32 больше не разбивается на /3 и2. Column180px/nowrap/title, red-before/green-after geometry test,7 E2E и4 live UI cases. Baseline7 коллекций×2 восстановлен. Backend ux-diagnostics89/frontend ux-ospf91. Следующий12.5.92 — обмен только собственным BGP prefix через GRE, отзыв и повторное объявление, API/UI контекст. Квота84% использовано; этап12.5 открыт.
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-09. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
+14 -2
View File
@@ -1,6 +1,6 @@
# UX/UI: журнал реализации
Актуальное продолжение 2026-10-09: 12.5.90 принял контролируемый OSPF/BFD failover primary GRE→alternate GRE over WireGuard→primary; steady Ping3/3×2 во всех фазах,4 UI cases. BFD/not-Full≈798ms, first alternate route≈4250ms — HTTP observations, не SLA. Отдельный переходный Ping18/40/55% loss сохранён, бесшовность не заявлена. Baseline10 коллекций×2 восстановлен. Runtime diagnostics89/optimizer87. Следующий12.5.91 — устранить обрезку IPv4 CIDR в OSPF Data Grid, выявленную live desktop снимком; затем BGP route propagation и оставшиеся внешние границы. Квота66% использовано; этап12.5 открыт.
Актуальное продолжение 2026-10-09: 12.5.91 устранил неоднозначное отображение IPv4 CIDR в OSPF: /32 больше не разбивается на /3 и2. Column180px/nowrap/title, red-before/green-after geometry test,7 E2E и4 live UI cases. Baseline7 коллекций×2 восстановлен. Backend ux-diagnostics89/frontend ux-ospf91. Следующий12.5.92 — обмен только собственным BGP prefix через GRE, отзыв и повторное объявление, API/UI контекст. Квота84% использовано; этап12.5 открыт.
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
@@ -36,7 +36,19 @@
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–90 и ограничения ниже. Runtime backend ux-diagnostics89/frontend ux-optimizer87. |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–91 и ограничения ниже. Runtime backend ux-diagnostics89/frontend ux-ospf91. |
## 12.5.91 — OSPF Data Grid: целый IPv4 CIDR (2026-10-09)
Уточнена визуальная проблема90: это не потеря API-данных, а перенос последней цифры /32 на вторую строку; первый ряд выглядел как /3. Столбец назначения расширен150→180px, span использует whitespace-nowrap и title полного значения. Установленные Data Grid/Table/ScrollArea, pinned column, theme и структура сохранены. ReUI inline API и audit checklist прочитаны; [API](https://reui.io/docs/components/base/data-grid?ref=mcp), [превью](https://reui.io/components/data-grid?ref=mcp).
**Проверки.** Новый browser test ждёт document.fonts.ready и проверяет Range rectangles: ровно одна строка, текст внутри ячейки. До исправления1280px failed: /3 и2 дали два rect. Первоначальная проверка только границ проходила и была уточнена, чтобы не пропустить разрыв CIDR. После изменения4 размера320/390/1280/1440 и IPv4 CIDR15/18 символов проходят; сортировка/количество строк/document fit/no writes сохранены. С OSPF unknown cost/disabled/inactive —7/7. Scoped TypeScript, ESLint/diff passed. Это meaningful visual regression, не проверка буквального size в исходнике.
**Live.** Backend diagnostics89 и обновлённый frontend ospf91, без mocks: два CHR×1280/320 =4/4. Свои GRE/OSPF private link198.18.93.0/30/loopbacks198.18.193.1/32↔2/32; Full/active learned route/Ping3/3. Целый /32 виден в одной строке после загрузки шрифтов; title, границы ячейки, URL/reload, document fit/pageerror0 подтверждены. [Browser отчёт](ux-ui/acceptance/browser-ospf-cidr-2026-10-09.json), [native/cleanup](ux-ui/acceptance/ospf-cidr-native-2026-10-09.json), [ПК после](ux-ui/screens/ospf-real-cidr-server1-1280-2026-10-09.png), [320px после](ux-ui/screens/ospf-real-cidr-server1-320-2026-10-09.png). PC снимок просмотрен:198.18.193.2/32 полностью читается. Проверка не обещает одновременную видимость всех колонок на телефоне: сохраняется внутренняя горизонтальная прокрутка.
**Контроль/runtime.** Свои objects удалены по exact IDs/атрибутам, baseline7 коллекций×2 совпал, оба CHR доступны, default/public/195.195.195.195/32 и credentials сохранены. Нормализованные SHA source/deployed DataGrid renderer и OSPF consumer совпадали до изменения, поэтому проблема не была вызвана отставшим компонентом стенда. Один frontend Docker build, production TypeScript/build, entry/node --check/compose --wait passed. mmapp-test/frontend:ux-ospf91/version1.0.0-test.ospf91, image sha256:b4bade515234115b3cad257ceb87ef7beb347e754ca92d6a97a25adc2199fd33. Context optimizer87 frontend +один consumer file, override SHA27a27569335c377bf8662fb5b39d200ce98d52925cafdf51dee165464c1532078, label не Git SHA. .env backup приватный, backend/migrations не менялись, полная регрессия/failover не повторялись. Один локальный commit без push.
Следующий92 — BGP propagation собственных private prefixes, withdrawal/re-advertisement и UI counters; только собственные GRE/instances/filter chains. Квота84% использовано после блока, этап12.5 и внешние границы остаются открытыми.
## 12.5.90 — OSPF/BFD: переход на резервный GRE и возврат (2026-10-09)
+12
View File
@@ -2144,3 +2144,15 @@ Production image не содержит dev-only jose: первый fixture impor
**Очистка.** Exact ID/name/comment/address/interface/interfaces/addresses/public key preflight; удалены только свои templates/area/instance/BFD/IP/bridge/GRE/WG peers/interfaces. Исходные IDs10 коллекций×2 совпали, public/default routes и195.195.195.195/32 сохранены. WG secret fields не включены в report. Оба CHR доступны, passwords неизменны; временных контейнеров не осталось. Backend diagnostics89/PG healthy, frontend optimizer87 сохранён. Один локальный commit без push.
Схема: primary → BFD/adjacency loss → alternate GRE over WG → проверка data plane → восстановленный primary. Транспорт подтверждён [GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE) и [WireGuard](https://help.mikrotik.com/docs/spaces/ROS/pages/69664792/WireGuard); таблицы сохраняют референсы общего плана. Продолжение91 — обрезка CIDR, затем BGP propagation/остальные внешние границы. BFD-only устойчивый запрет/physical WAN/IPv6/scale/maximum throughput/Portal SSO остаются открыты. Квота66% использовано; этап12.5 открыт.
## 12.5.91 — OSPF Data Grid: целый IPv4 CIDR (2026-10-09)
Уточнена визуальная проблема90: это не потеря API-данных, а перенос последней цифры /32 на вторую строку; первый ряд выглядел как /3. Столбец назначения расширен150→180px, span использует whitespace-nowrap и title полного значения. Установленные Data Grid/Table/ScrollArea, pinned column, theme и структура сохранены. ReUI inline API и audit checklist прочитаны; [API](https://reui.io/docs/components/base/data-grid?ref=mcp), [превью](https://reui.io/components/data-grid?ref=mcp).
**Проверки.** Новый browser test ждёт document.fonts.ready и проверяет Range rectangles: ровно одна строка, текст внутри ячейки. До исправления1280px failed: /3 и2 дали два rect. Первоначальная проверка только границ проходила и была уточнена, чтобы не пропустить разрыв CIDR. После изменения4 размера320/390/1280/1440 и IPv4 CIDR15/18 символов проходят; сортировка/количество строк/document fit/no writes сохранены. С OSPF unknown cost/disabled/inactive —7/7. Scoped TypeScript, ESLint/diff passed. Это meaningful visual regression, не проверка буквального size в исходнике.
**Live.** Backend diagnostics89 и обновлённый frontend ospf91, без mocks: два CHR×1280/320 =4/4. Свои GRE/OSPF private link198.18.93.0/30/loopbacks198.18.193.1/32↔2/32; Full/active learned route/Ping3/3. Целый /32 виден в одной строке после загрузки шрифтов; title, границы ячейки, URL/reload, document fit/pageerror0 подтверждены. [Browser отчёт](ux-ui/acceptance/browser-ospf-cidr-2026-10-09.json), [native/cleanup](ux-ui/acceptance/ospf-cidr-native-2026-10-09.json), [ПК после](ux-ui/screens/ospf-real-cidr-server1-1280-2026-10-09.png), [320px после](ux-ui/screens/ospf-real-cidr-server1-320-2026-10-09.png). PC снимок просмотрен:198.18.193.2/32 полностью читается. Проверка не обещает одновременную видимость всех колонок на телефоне: сохраняется внутренняя горизонтальная прокрутка.
**Контроль/runtime.** Свои objects удалены по exact IDs/атрибутам, baseline7 коллекций×2 совпал, оба CHR доступны, default/public/195.195.195.195/32 и credentials сохранены. Нормализованные SHA source/deployed DataGrid renderer и OSPF consumer совпадали до изменения, поэтому проблема не была вызвана отставшим компонентом стенда. Один frontend Docker build, production TypeScript/build, entry/node --check/compose --wait passed. mmapp-test/frontend:ux-ospf91/version1.0.0-test.ospf91, image sha256:b4bade515234115b3cad257ceb87ef7beb347e754ca92d6a97a25adc2199fd33. Context optimizer87 frontend +один consumer file, override SHA27a27569335c377bf8662fb5b39d200ce98d52925cafdf51dee165464c1532078, label не Git SHA. .env backup приватный, backend/migrations не менялись, полная регрессия/failover не повторялись. Один локальный commit без push.
Следующий92 — BGP propagation собственных private prefixes, withdrawal/re-advertisement и UI counters; только собственные GRE/instances/filter chains. Квота84% использовано после блока, этап12.5 и внешние границы остаются открытыми.
+3 -1
View File
@@ -1,6 +1,6 @@
# Тестовый сервер UX/UI — 2026-10-09
Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-diagnostics89/version1.0.0-test.diagnostics89, frontend ux-optimizer87/version1.0.0-test.optimizer87; backend/PG healthy, frontend HTTP/browser passed. Основной блок IPsec77 принят в границах журнала, own fixtures/fake DB rows удалены; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние.
Сервер161.104.46.222 предоставлен для временного тестирования. Backend ux-diagnostics89/version1.0.0-test.diagnostics89, frontend ux-ospf91/version1.0.0-test.ospf91; backend/PG healthy, frontend HTTP/browser passed. Основной блок IPsec77 принят в границах журнала, own fixtures/fake DB rows удалены; каталог flash CHR2 сохранён из-за неподтверждённого ownership. SSH/оба CHR доступны, пароли прежние.
| Параметр | Проверенное состояние |
| --- | --- |
@@ -717,3 +717,5 @@ flowchart LR
12.5.88 (2026-10-09): recursion/GRE/Ping, apply/restore и4 browser checks passed; native baseline4 коллекций×2, cache/history сохранены. Backend recursive88, frontend optimizer87.
12.5.89 (2026-10-09): терминал/диагностика/RBAC и8 live UI checks passed, baseline7 коллекций×2 сохранён. Production auth не менялся.
12.5.91 (2026-10-09): frontend ospf91; целый CIDR подтверждён4 live cases, baseline7 коллекций×2 сохранён. Backend diagnostics89 неизменён.
@@ -0,0 +1,43 @@
{
"date": "2026-10-09",
"phase": "2 320",
"cases": [
{
"serverId": 1,
"width": 1280,
"destination": "198.18.193.2/32",
"oneLine": true,
"noCellClipping": true,
"documentFits": true,
"urlRestore": true
},
{
"serverId": 1,
"width": 320,
"destination": "198.18.193.2/32",
"oneLine": true,
"noCellClipping": true,
"documentFits": true,
"urlRestore": true
},
{
"serverId": 2,
"width": 1280,
"destination": "198.18.193.1/32",
"oneLine": true,
"noCellClipping": true,
"documentFits": true,
"urlRestore": true
},
{
"serverId": 2,
"width": 320,
"destination": "198.18.193.1/32",
"oneLine": true,
"noCellClipping": true,
"documentFits": true,
"urlRestore": true
}
],
"errors": []
}
@@ -0,0 +1,161 @@
{
"date": "2026-10-09",
"name": "mm-ospf91-1791559266208",
"observations": [
{
"serverId": 1,
"nativeNeighbor": {
".id": "*F3FDDC00",
"router-id": "198.18.193.2",
"address": "198.18.93.2",
"interface": "mm-ospf91-1791559266208",
"state": "Full",
"state-changes": "6"
},
"nativeRoute": {
".id": "*2014C000",
"dst-address": "198.18.193.2/32",
"gateway": "198.18.93.2%mm-ospf91-1791559266208",
"ospf": "true",
"active": "true",
"distance": "110"
},
"catalogNeighbors": [
{
"id": "*F3FDDC00",
"serverId": 1,
"serverName": "CHR",
"serverSite": "",
"serverCountry": "",
"address": "198.18.93.2",
"routerId": "198.18.193.2",
"instance": "mm-ospf91-1791559266208",
"area": "mm-ospf91-1791559266208",
"areaId": "0.0.0.0",
"interface": "mm-ospf91-1791559266208",
"state": "Full",
"uptime": "3s",
"stateChanges": 6,
"priority": null
}
],
"catalogRoutes": [
{
"id": "*2014C000",
"serverId": 1,
"serverName": "CHR",
"serverSite": "",
"destination": "198.18.193.2/32",
"type": "Unknown",
"cost": null,
"nextHop": "198.18.93.2",
"via": "mm-ospf91-1791559266208",
"area": ""
}
],
"pingReceived": 3
},
{
"serverId": 2,
"nativeNeighbor": {
".id": "*F3FDDC00",
"router-id": "198.18.193.1",
"address": "198.18.93.1",
"interface": "mm-ospf91-1791559266208",
"state": "Full",
"state-changes": "5"
},
"nativeRoute": {
".id": "*2014C000",
"dst-address": "198.18.193.1/32",
"gateway": "198.18.93.1%mm-ospf91-1791559266208",
"ospf": "true",
"active": "true",
"distance": "110"
},
"catalogNeighbors": [
{
"id": "*F3FDDC00",
"serverId": 2,
"serverName": "CHR",
"serverSite": "",
"serverCountry": "",
"address": "198.18.93.1",
"routerId": "198.18.193.1",
"instance": "mm-ospf91-1791559266208",
"area": "mm-ospf91-1791559266208",
"areaId": "0.0.0.0",
"interface": "mm-ospf91-1791559266208",
"state": "Full",
"uptime": "3s",
"stateChanges": 5,
"priority": null
}
],
"catalogRoutes": [
{
"id": "*2014C000",
"serverId": 2,
"serverName": "CHR",
"serverSite": "",
"destination": "198.18.193.1/32",
"type": "Unknown",
"cost": null,
"nextHop": "198.18.93.1",
"via": "mm-ospf91-1791559266208",
"area": ""
}
],
"pingReceived": 3
}
],
"cleanup": [
{
"serverId": 1,
"/routing/ospf/interface-template": true,
"/routing/ospf/area": true,
"/routing/ospf/instance": true,
"/interface/gre": true,
"/interface/bridge": true,
"/ip/address": true,
"/ip/route": true
},
{
"serverId": 2,
"/routing/ospf/interface-template": true,
"/routing/ospf/area": true,
"/routing/ospf/instance": true,
"/interface/gre": true,
"/interface/bridge": true,
"/ip/address": true,
"/ip/route": true
}
],
"currentRoutes": [
{
".id": "*20145050",
"dst-address": "198.18.93.0/30",
"gateway": "mm-ospf91-1791559266208",
"active": "true",
"distance": "0",
"routing-table": "main"
},
{
".id": "*2014C000",
"dst-address": "198.18.193.1/32",
"gateway": "198.18.93.1%mm-ospf91-1791559266208",
"active": "true",
"ospf": "true",
"distance": "110",
"routing-table": "main"
},
{
".id": "*20145060",
"dst-address": "198.18.193.2/32",
"gateway": "mm-ospf91-1791559266208-loop",
"active": "true",
"distance": "0",
"routing-table": "main"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+42
View File
@@ -0,0 +1,42 @@
import { test, expect } from "@playwright/test"
for (const width of [320, 390, 1280, 1440]) test("OSPF: CIDR целиком помещается в закреплённой ячейке " + width, async ({ page }) => {
await page.setViewportSize({ width, height: 1000 })
const destinations = ["198.18.190.2/32", "255.255.255.255/32"]
const host = { serverId: 1, serverName: "CHR", serverSite: "", serverCountry: "RU" }
let writes = 0
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
await page.route("**/api/**", r => {
const path = new URL(r.request().url()).pathname
if (r.request().method() !== "GET") writes++
return r.fulfill({ json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [{ id: 1, name: "CHR", host: "192.0.2.1", enabled: true, country: "RU", status: null }] : path === "/api/ospf/catalog" ? {
neighbors: [], interfaces: [], instances: [], bfdSessions: [], failures: [],
routes: destinations.map((destination, i) => ({ ...host, id: "route-" + i, destination, type: "Unknown", cost: null, nextHop: "198.18.91.2", via: "GRE-reserve", area: "" })),
} : {} })
})
await page.goto("/ospf?server=1&tab=routes")
await expect(page.locator("tr[data-row-id]")).toHaveCount(2)
await page.evaluate(() => document.fonts.ready)
for (const destination of destinations) {
const text = page.getByText(destination, { exact: true })
await text.scrollIntoViewIfNeeded()
const bounds = await text.evaluate(element => {
const cell = element.closest("td")!, cellRect = cell.getBoundingClientRect(), style = getComputedStyle(cell)
const range = document.createRange(); range.selectNodeContents(element)
const rects = Array.from(range.getClientRects())
return { cell: { left: cellRect.left + parseFloat(style.paddingLeft), right: cellRect.right - parseFloat(style.paddingRight), top: cellRect.top, bottom: cellRect.bottom }, text: rects.map(r => ({ left: r.left, right: r.right, top: r.top, bottom: r.bottom })) }
})
// Splitting /32 into /3 + 2 makes the prefix visually ambiguous.
expect(bounds.text).toHaveLength(1)
for (const rect of bounds.text) {
expect(rect.left).toBeGreaterThanOrEqual(bounds.cell.left - 1)
expect(rect.right).toBeLessThanOrEqual(bounds.cell.right + 1)
expect(rect.top).toBeGreaterThanOrEqual(bounds.cell.top)
expect(rect.bottom).toBeLessThanOrEqual(bounds.cell.bottom)
}
}
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
await page.getByRole("button", { name: "Назначение", exact: true }).click()
await expect(page.locator("tr[data-row-id]")).toHaveCount(2)
expect(writes).toBe(0)
})