diff --git a/app/(main)/bgp/page.tsx b/app/(main)/bgp/page.tsx index 2a377b1f..551b6574 100644 --- a/app/(main)/bgp/page.tsx +++ b/app/(main)/bgp/page.tsx @@ -456,7 +456,6 @@ function AnalyticsTab({ sessions }: { sessions: BgpSession[] }) { return (
+ {type === "jump-host" ? "JH" : type === "home-router" ? "HR" : "EN"} - + ) } diff --git a/app/(main)/route-optimizer/page.tsx b/app/(main)/route-optimizer/page.tsx index 41ee3aa1..e76ee731 100644 --- a/app/(main)/route-optimizer/page.tsx +++ b/app/(main)/route-optimizer/page.tsx @@ -949,7 +949,8 @@ function RouteOptimizerContent({requestedServer,onSelectServer}:{requestedServer contentClassName="px-5 py-4 flex flex-col gap-4" > -
+
+ Параметры черновика ECMP
Макс. путей
@@ -966,7 +967,7 @@ function RouteOptimizerContent({requestedServer,onSelectServer}:{requestedServer {([["per-dst","По dst"],["per-conn","По conn"],["per-packet","По пакет"]] as const).map(([v, l]) => ( ))} @@ -977,7 +978,7 @@ function RouteOptimizerContent({requestedServer,onSelectServer}:{requestedServer
-
+
{/* RPF Card */} diff --git a/app/(main)/vxlan/page.tsx b/app/(main)/vxlan/page.tsx index 5c14265a..901e9e1e 100644 --- a/app/(main)/vxlan/page.tsx +++ b/app/(main)/vxlan/page.tsx @@ -298,7 +298,6 @@ function VxlanPageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, elements.filter(el => el.getClientRects().length).map(el => ({ label: el.textContent.trim(), clipped: el.scrollWidth > el.clientWidth + 1 }))); + } item.performance = await page.evaluate(() => { const n = performance.getEntriesByType('navigation')[0]; return { ...window.__acceptanceMetrics, ttfbMs: n.responseStart - n.requestStart, domInteractiveMs: n.domInteractive, durationMs: n.duration }; @@ -129,7 +132,7 @@ try { await context.close(); } report.completed = true; - report.passed = report.blockedWrites.length === 0 && report.cases.every(c => c.auditCompleted && !c.layout.overflow && !c.layout.mainOverflow && c.violations.length === 0 && c.pageErrors.length === 0 && c.apiErrors.length === 0); + report.passed = report.blockedWrites.length === 0 && report.cases.every(c => c.auditCompleted && !c.layout.overflow && !c.layout.mainOverflow && c.violations.length === 0 && c.pageErrors.length === 0 && c.apiErrors.length === 0 && !c.kpiLabels?.some(label => label.clipped)); if (!report.passed) process.exitCode = 1; } finally { fs.writeFileSync(output, JSON.stringify(report, null, 2) + '\n'); diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index c7321332..8bc63286 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -1,6 +1,6 @@ # UX/UI: протокол внешней приёмки 12.5 -Актуальное продолжение 2026-10-15: 260 — исправлены общие focus/target-size/contrast и BGP320 tabs; production frontend ux-accessibility260-final развёрнут, backend258 healthy.72 live WCAG/layout состояния прошли,59 уникальных E2E прошли в записанных итерациях; synthetic timing сохранён. Следующий261 — оставшиеся12 экранов и точные границы приёмки; этап12.5 открыт. +Актуальное продолжение 2026-10-15: 261 — оставшиеся12 default screens проверены; контраст recursive/ECMP исправлен, KPI BGP/GRE/VXLAN/OSPF используют штатную адаптивную сетку.64 unique live states261, вместе с260 —120 состояний30 экранов с явным происхождением;40 локальных E2E приняты. Runtime backend258/frontend261. Следующий262 — оформить десятиминутный REST-протокол, затем263 — итоговая UI-регрессия; этап12.5 открыт. IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md). @@ -18,6 +18,25 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json). +## 12.5.261 — оставшиеся экраны и читаемые сетевые KPI (2026-10-15) + +Baseline12 разделов×2 темы×1440/320px:48 live states, API/JS errors0, overflow0, blocked configuration writes0. Четыре проверенных read-only POST OSPF preview разрешены явно после чтения backend handler; они рассчитывают план, не применяют его. DNS resolution/catalog read POST также имеют точный opt-in allowlist в helper, остальные non-GET блокируются. EvoBGP на стенде disabled, URL/key не настроены: каталоги здесь проверены в состоянии недоступной интеграции, не с реальными внешними данными. [Baseline](ux-ui/acceptance/ui261-baseline.json). + +Найдены4 contrast failures: TypeChip в recursive-routes/light и opacity40 всего ECMP disabled section в двух темах на ПК. TypeChip теперь использует установленный ReUI Badge light variants/text-foreground; ECMP — native disabled fieldset с legend вместо затемнения всех подписей. Профильная проверка включённого ECMP дополнительно выявила неконтрастный выбранный алгоритм; применены bg-muted/text-foreground. Это локальный черновик, серверная логика/применение маршрутов не менялись. + +В BGP summary/analytics, GRE, VXLAN, OSPF summary/BFD убраны принудительные grid-cols2 overrides. Используются существующие kpiCols и неизменённые Frame/IconTile/KpiStatGrid: одна колонка в узком контейнере, прежние container breakpoints для плотного ПК. Шрифты, vendor компоненты, theme tokens и motion не менялись. В8 локальных geometry cases320/390 и16 live theme/width cases подписи KPI не обрезаются; explicit краткая подпись Интерф. в OSPF сохранена. [Снимок BGP320 после загрузки](ux-ui/screens/ui261-bgp320.png). + +Локальные40 E2E: initial38 passed/2 ECMP contrast failed; после исправления повторены только2 affected cases, passed. Geometry8, ECMP2, recursive route contracts15 и OSPF preview15; разные прогоны не суммируются в42 сценария. ECMP false/true проверены также в настоящем Portal/UI, scoped axe0, configuration writes0, draft возвращён off. [Live ECMP](ux-ui/acceptance/ui261-live-ecmp.json). TypeScript/scoped ESLint и production build passed, source528 matched. Runtime frontend ux-accessibility261, backend ux-certificates258 healthy; DB/Portal сохранены. [Deployment](ux-ui/acceptance/ui261-deployment.json). + +Повторены только6 изменённых страниц:24 live states, WCAG-tagged axe violations0/API/JS errors0/overflow0/clipped KPI labels0. С48 baseline это64 уникальных состояния16 страниц: восемь состояний двух изменённых baseline страниц заменены повторными, четыре сетевых KPI страницы добавлены. Вместе с260 —120 уникальных default states30 экранов. Report сохраняет фазу/образ каждого результата: остальные страницы не выданы за повторный прогон на261. [Changed24](ux-ui/acceptance/ui261-changed-final.json), [итог64](ux-ui/acceptance/ui261-final.json), [сводка](ux-ui/acceptance/ui261-summary.json). Во время части замеров шла контролируемая REST-нагрузка262, timings не field CWV и не сравнение независимых бенчмарков. + +| Референс | Схема доработки | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Узкий контейнер → штатная одна колонка → полная подпись KPI; [BGP320](ux-ui/screens/ui261-bgp320.png) | +| [ReUI Badge](https://reui.io/components/badge?ref=mcp) | Тип устройства → light variant → semantic foreground | + +Настройки CHR, DNS, сертификаты и пароли не менялись. Native/background telemetry reads не объявляются отсутствием всех DB metadata updates. Manual screen-reader, новые клиентские ОС/WAN/public IPv6/multi-instance, CA revoke и внешняя публикация остаются отдельными границами. Следующий262 — оформить завершённый ten-minute REST soak, затем263 — актуальная полная локальная UI-регрессия после общего keyboard adapter260 и responsive delta261. Автоматическая120-state проверка не заменяет сквозные сценарии и не является полной WCAG сертификацией. + ## 12.5.260 — общая доступность, клавиатура и профильная скорость UI (2026-10-15) Проведён read-only аудит18 разделов×2 темы×1440/320px:72 состояния текущего стенда/настоящий Portal UI, без response mocks. Baseline выявил23 состояния с axe нарушениями: недостаточная независимая pointer-area у focusable listbox-контейнера, контраст счётчиков SegmentedControl, raw type badges серверов и заголовка VXLAN. Document overflow0/JS errors0/API errors0; BGP320 имел2 внутренних переполнения main. Dashboard в baseline ещё содержал skeleton: его ранние timings не считаются готовностью данных. [Baseline](ux-ui/acceptance/ui260-baseline.json). diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 5cf697f8..22537c22 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,9 +1,28 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-15: 260 — исправлены общие focus/target-size/contrast и BGP320 tabs; production frontend ux-accessibility260-final развёрнут, backend258 healthy.72 live WCAG/layout состояния прошли,59 уникальных E2E прошли в записанных итерациях; synthetic timing сохранён. Следующий261 — оставшиеся12 экранов и точные границы приёмки; этап12.5 открыт. +Актуальное продолжение 2026-10-15: 261 — оставшиеся12 default screens проверены; контраст recursive/ECMP исправлен, KPI BGP/GRE/VXLAN/OSPF используют штатную адаптивную сетку.64 unique live states261, вместе с260 —120 состояний30 экранов с явным происхождением;40 локальных E2E приняты. Runtime backend258/frontend261. Следующий262 — оформить десятиминутный REST-протокол, затем263 — итоговая UI-регрессия; этап12.5 открыт. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-15. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. +## 12.5.261 — оставшиеся экраны и читаемые сетевые KPI (2026-10-15) + +Baseline12 разделов×2 темы×1440/320px:48 live states, API/JS errors0, overflow0, blocked configuration writes0. Четыре проверенных read-only POST OSPF preview разрешены явно после чтения backend handler; они рассчитывают план, не применяют его. DNS resolution/catalog read POST также имеют точный opt-in allowlist в helper, остальные non-GET блокируются. EvoBGP на стенде disabled, URL/key не настроены: каталоги здесь проверены в состоянии недоступной интеграции, не с реальными внешними данными. [Baseline](ux-ui/acceptance/ui261-baseline.json). + +Найдены4 contrast failures: TypeChip в recursive-routes/light и opacity40 всего ECMP disabled section в двух темах на ПК. TypeChip теперь использует установленный ReUI Badge light variants/text-foreground; ECMP — native disabled fieldset с legend вместо затемнения всех подписей. Профильная проверка включённого ECMP дополнительно выявила неконтрастный выбранный алгоритм; применены bg-muted/text-foreground. Это локальный черновик, серверная логика/применение маршрутов не менялись. + +В BGP summary/analytics, GRE, VXLAN, OSPF summary/BFD убраны принудительные grid-cols2 overrides. Используются существующие kpiCols и неизменённые Frame/IconTile/KpiStatGrid: одна колонка в узком контейнере, прежние container breakpoints для плотного ПК. Шрифты, vendor компоненты, theme tokens и motion не менялись. В8 локальных geometry cases320/390 и16 live theme/width cases подписи KPI не обрезаются; explicit краткая подпись Интерф. в OSPF сохранена. [Снимок BGP320 после загрузки](ux-ui/screens/ui261-bgp320.png). + +Локальные40 E2E: initial38 passed/2 ECMP contrast failed; после исправления повторены только2 affected cases, passed. Geometry8, ECMP2, recursive route contracts15 и OSPF preview15; разные прогоны не суммируются в42 сценария. ECMP false/true проверены также в настоящем Portal/UI, scoped axe0, configuration writes0, draft возвращён off. [Live ECMP](ux-ui/acceptance/ui261-live-ecmp.json). TypeScript/scoped ESLint и production build passed, source528 matched. Runtime frontend ux-accessibility261, backend ux-certificates258 healthy; DB/Portal сохранены. [Deployment](ux-ui/acceptance/ui261-deployment.json). + +Повторены только6 изменённых страниц:24 live states, WCAG-tagged axe violations0/API/JS errors0/overflow0/clipped KPI labels0. С48 baseline это64 уникальных состояния16 страниц: восемь состояний двух изменённых baseline страниц заменены повторными, четыре сетевых KPI страницы добавлены. Вместе с260 —120 уникальных default states30 экранов. Report сохраняет фазу/образ каждого результата: остальные страницы не выданы за повторный прогон на261. [Changed24](ux-ui/acceptance/ui261-changed-final.json), [итог64](ux-ui/acceptance/ui261-final.json), [сводка](ux-ui/acceptance/ui261-summary.json). Во время части замеров шла контролируемая REST-нагрузка262, timings не field CWV и не сравнение независимых бенчмарков. + +| Референс | Схема доработки | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Узкий контейнер → штатная одна колонка → полная подпись KPI; [BGP320](ux-ui/screens/ui261-bgp320.png) | +| [ReUI Badge](https://reui.io/components/badge?ref=mcp) | Тип устройства → light variant → semantic foreground | + +Настройки CHR, DNS, сертификаты и пароли не менялись. Native/background telemetry reads не объявляются отсутствием всех DB metadata updates. Manual screen-reader, новые клиентские ОС/WAN/public IPv6/multi-instance, CA revoke и внешняя публикация остаются отдельными границами. Следующий262 — оформить завершённый ten-minute REST soak, затем263 — актуальная полная локальная UI-регрессия после общего keyboard adapter260 и responsive delta261. Автоматическая120-state проверка не заменяет сквозные сценарии и не является полной WCAG сертификацией. + ## 12.5.260 — общая доступность, клавиатура и профильная скорость UI (2026-10-15) Проведён read-only аудит18 разделов×2 темы×1440/320px:72 состояния текущего стенда/настоящий Portal UI, без response mocks. Baseline выявил23 состояния с axe нарушениями: недостаточная независимая pointer-area у focusable listbox-контейнера, контраст счётчиков SegmentedControl, raw type badges серверов и заголовка VXLAN. Document overflow0/JS errors0/API errors0; BGP320 имел2 внутренних переполнения main. Dashboard в baseline ещё содержал skeleton: его ранние timings не считаются готовностью данных. [Baseline](ux-ui/acceptance/ui260-baseline.json). @@ -352,7 +371,7 @@ Production backend/frontend ux-backups237 собраны и развёрнуты | Масштаб и устойчивость | Контролируемые PG lock/dedupe/loss/recovery, отдельные multi-process сценарии194/200/201 | Несколько полноценных backend/worker со всеми writers, длительный rekey/traffic, физические потери WAN/DB и maximum throughput | | Хранилища и внешние jobs | Реальные Portal/Telegram195–201, Selectel S3/limited bridge restore/retention228–240, GeoIP mirror242; контейнеры248; production ACME250 и реальное renewal/rotation259 с trusted TLS/cleanup | Large native export/migration buckets/multi-instance S3; CA revocation отдельно не принят. Gitea publishing CI не запускался: действует no push. Direct licensed MaxMind отсутствует в текущей реализации | | Расширенные сетевые конфигурации | GRE/WG/VXLAN/IPsec/OSPF/BFD/BGP в записанных сценариях, включая private IPv6 | from-pool/EUI-64/multiple-address import/export, outer IPv6, произвольная PKI/OID/path-length, независимые внешние peers и длительные переходы. BFD-only gate не гарантирован | -| UX, доступность и производительность | UI226, ARIA мастеров251, новая проверка260 текущего runtime описана выше | Исправления260 и72 live состояния приняты; оставшиеся12 экранов и ручная screen-reader приёмка отдельно. Synthetic timing не field CWV, scoped axe не полная WCAG сертификация | +| UX, доступность и производительность | UI226, ARIA мастеров251, новая проверка260 текущего runtime описана выше | Default UI260/261:120 unique states30 экранов приняты в автоматическом scope; актуальная полная UI-регрессия263 и ручная screen-reader приёмка отдельно. Synthetic timing не field CWV, scoped axe не полная WCAG сертификация | | Границы выпуска | Датированный журнал, протоколы и локальные коммиты без push | Подготовить итоговый перечень принятых конфигураций/исключений для решения о выпуске; лабораторный успех не объявлять приёмкой всех конфигураций | Portal offline JWT действует доexp после logout/role change; это записанная граница198, не мгновенная revocation. Controlled Telegram unknown/retry201 не доказывает физическую потерю ACK в WAN. Архивные записи ниже отражают состояние на свою дату; актуальный статус задают эта таблица и верхняя точка продолжения. diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 1a7d79d9..e9d81a06 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-15: 260 — исправлены общие focus/target-size/contrast и BGP320 tabs; production frontend ux-accessibility260-final развёрнут, backend258 healthy.72 live WCAG/layout состояния прошли,59 уникальных E2E прошли в записанных итерациях; synthetic timing сохранён. Следующий261 — оставшиеся12 экранов и точные границы приёмки; этап12.5 открыт. +Актуальное продолжение 2026-10-15: 261 — оставшиеся12 default screens проверены; контраст recursive/ECMP исправлен, KPI BGP/GRE/VXLAN/OSPF используют штатную адаптивную сетку.64 unique live states261, вместе с260 —120 состояний30 экранов с явным происхождением;40 локальных E2E приняты. Runtime backend258/frontend261. Следующий262 — оформить десятиминутный REST-протокол, затем263 — итоговая UI-регрессия; этап12.5 открыт. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -36,7 +36,26 @@ | 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–260 в записанных границах. Ротация/renewal259 и откат приняты; общий UI260:72 live states passed. Runtime backend258/frontend260. Следующий261 — оставшиеся12 экранов и итоговые границы. | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная12.3.83; внешняя12.5 открыта, блоки1–261 в записанных границах. ACME259; default UI260/261:120 unique states30 экранов. Runtime backend258/frontend261. Следующий262 — REST, затем263 — полная актуальная UI-регрессия. | + +## 12.5.261 — оставшиеся экраны и читаемые сетевые KPI (2026-10-15) + +Baseline12 разделов×2 темы×1440/320px:48 live states, API/JS errors0, overflow0, blocked configuration writes0. Четыре проверенных read-only POST OSPF preview разрешены явно после чтения backend handler; они рассчитывают план, не применяют его. DNS resolution/catalog read POST также имеют точный opt-in allowlist в helper, остальные non-GET блокируются. EvoBGP на стенде disabled, URL/key не настроены: каталоги здесь проверены в состоянии недоступной интеграции, не с реальными внешними данными. [Baseline](ux-ui/acceptance/ui261-baseline.json). + +Найдены4 contrast failures: TypeChip в recursive-routes/light и opacity40 всего ECMP disabled section в двух темах на ПК. TypeChip теперь использует установленный ReUI Badge light variants/text-foreground; ECMP — native disabled fieldset с legend вместо затемнения всех подписей. Профильная проверка включённого ECMP дополнительно выявила неконтрастный выбранный алгоритм; применены bg-muted/text-foreground. Это локальный черновик, серверная логика/применение маршрутов не менялись. + +В BGP summary/analytics, GRE, VXLAN, OSPF summary/BFD убраны принудительные grid-cols2 overrides. Используются существующие kpiCols и неизменённые Frame/IconTile/KpiStatGrid: одна колонка в узком контейнере, прежние container breakpoints для плотного ПК. Шрифты, vendor компоненты, theme tokens и motion не менялись. В8 локальных geometry cases320/390 и16 live theme/width cases подписи KPI не обрезаются; explicit краткая подпись Интерф. в OSPF сохранена. [Снимок BGP320 после загрузки](ux-ui/screens/ui261-bgp320.png). + +Локальные40 E2E: initial38 passed/2 ECMP contrast failed; после исправления повторены только2 affected cases, passed. Geometry8, ECMP2, recursive route contracts15 и OSPF preview15; разные прогоны не суммируются в42 сценария. ECMP false/true проверены также в настоящем Portal/UI, scoped axe0, configuration writes0, draft возвращён off. [Live ECMP](ux-ui/acceptance/ui261-live-ecmp.json). TypeScript/scoped ESLint и production build passed, source528 matched. Runtime frontend ux-accessibility261, backend ux-certificates258 healthy; DB/Portal сохранены. [Deployment](ux-ui/acceptance/ui261-deployment.json). + +Повторены только6 изменённых страниц:24 live states, WCAG-tagged axe violations0/API/JS errors0/overflow0/clipped KPI labels0. С48 baseline это64 уникальных состояния16 страниц: восемь состояний двух изменённых baseline страниц заменены повторными, четыре сетевых KPI страницы добавлены. Вместе с260 —120 уникальных default states30 экранов. Report сохраняет фазу/образ каждого результата: остальные страницы не выданы за повторный прогон на261. [Changed24](ux-ui/acceptance/ui261-changed-final.json), [итог64](ux-ui/acceptance/ui261-final.json), [сводка](ux-ui/acceptance/ui261-summary.json). Во время части замеров шла контролируемая REST-нагрузка262, timings не field CWV и не сравнение независимых бенчмарков. + +| Референс | Схема доработки | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Узкий контейнер → штатная одна колонка → полная подпись KPI; [BGP320](ux-ui/screens/ui261-bgp320.png) | +| [ReUI Badge](https://reui.io/components/badge?ref=mcp) | Тип устройства → light variant → semantic foreground | + +Настройки CHR, DNS, сертификаты и пароли не менялись. Native/background telemetry reads не объявляются отсутствием всех DB metadata updates. Manual screen-reader, новые клиентские ОС/WAN/public IPv6/multi-instance, CA revoke и внешняя публикация остаются отдельными границами. Следующий262 — оформить завершённый ten-minute REST soak, затем263 — актуальная полная локальная UI-регрессия после общего keyboard adapter260 и responsive delta261. Автоматическая120-state проверка не заменяет сквозные сценарии и не является полной WCAG сертификацией. ## 12.5.260 — общая доступность, клавиатура и профильная скорость UI (2026-10-15) diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index ae3a89b6..ec4d43c8 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,10 +1,29 @@ # Оставшаяся внешняя приёмка — 2026-10-15 -Актуальное продолжение 2026-10-15: 260 — исправлены общие focus/target-size/contrast и BGP320 tabs; production frontend ux-accessibility260-final развёрнут, backend258 healthy.72 live WCAG/layout состояния прошли,59 уникальных E2E прошли в записанных итерациях; synthetic timing сохранён. Следующий261 — оставшиеся12 экранов и точные границы приёмки; этап12.5 открыт. +Актуальное продолжение 2026-10-15: 261 — оставшиеся12 default screens проверены; контраст recursive/ECMP исправлен, KPI BGP/GRE/VXLAN/OSPF используют штатную адаптивную сетку.64 unique live states261, вместе с260 —120 состояний30 экранов с явным происхождением;40 локальных E2E приняты. Runtime backend258/frontend261. Следующий262 — оформить десятиминутный REST-протокол, затем263 — итоговая UI-регрессия; этап12.5 открыт. -Это актуальная матрица после 12.5.260. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. +Это актуальная матрица после 12.5.261. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. -Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-certificates258`, frontend `ux-accessibility260-final`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. +Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-certificates258`, frontend `ux-accessibility261`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. + +## 12.5.261 — оставшиеся экраны и читаемые сетевые KPI (2026-10-15) + +Baseline12 разделов×2 темы×1440/320px:48 live states, API/JS errors0, overflow0, blocked configuration writes0. Четыре проверенных read-only POST OSPF preview разрешены явно после чтения backend handler; они рассчитывают план, не применяют его. DNS resolution/catalog read POST также имеют точный opt-in allowlist в helper, остальные non-GET блокируются. EvoBGP на стенде disabled, URL/key не настроены: каталоги здесь проверены в состоянии недоступной интеграции, не с реальными внешними данными. [Baseline](ux-ui/acceptance/ui261-baseline.json). + +Найдены4 contrast failures: TypeChip в recursive-routes/light и opacity40 всего ECMP disabled section в двух темах на ПК. TypeChip теперь использует установленный ReUI Badge light variants/text-foreground; ECMP — native disabled fieldset с legend вместо затемнения всех подписей. Профильная проверка включённого ECMP дополнительно выявила неконтрастный выбранный алгоритм; применены bg-muted/text-foreground. Это локальный черновик, серверная логика/применение маршрутов не менялись. + +В BGP summary/analytics, GRE, VXLAN, OSPF summary/BFD убраны принудительные grid-cols2 overrides. Используются существующие kpiCols и неизменённые Frame/IconTile/KpiStatGrid: одна колонка в узком контейнере, прежние container breakpoints для плотного ПК. Шрифты, vendor компоненты, theme tokens и motion не менялись. В8 локальных geometry cases320/390 и16 live theme/width cases подписи KPI не обрезаются; explicit краткая подпись Интерф. в OSPF сохранена. [Снимок BGP320 после загрузки](ux-ui/screens/ui261-bgp320.png). + +Локальные40 E2E: initial38 passed/2 ECMP contrast failed; после исправления повторены только2 affected cases, passed. Geometry8, ECMP2, recursive route contracts15 и OSPF preview15; разные прогоны не суммируются в42 сценария. ECMP false/true проверены также в настоящем Portal/UI, scoped axe0, configuration writes0, draft возвращён off. [Live ECMP](ux-ui/acceptance/ui261-live-ecmp.json). TypeScript/scoped ESLint и production build passed, source528 matched. Runtime frontend ux-accessibility261, backend ux-certificates258 healthy; DB/Portal сохранены. [Deployment](ux-ui/acceptance/ui261-deployment.json). + +Повторены только6 изменённых страниц:24 live states, WCAG-tagged axe violations0/API/JS errors0/overflow0/clipped KPI labels0. С48 baseline это64 уникальных состояния16 страниц: восемь состояний двух изменённых baseline страниц заменены повторными, четыре сетевых KPI страницы добавлены. Вместе с260 —120 уникальных default states30 экранов. Report сохраняет фазу/образ каждого результата: остальные страницы не выданы за повторный прогон на261. [Changed24](ux-ui/acceptance/ui261-changed-final.json), [итог64](ux-ui/acceptance/ui261-final.json), [сводка](ux-ui/acceptance/ui261-summary.json). Во время части замеров шла контролируемая REST-нагрузка262, timings не field CWV и не сравнение независимых бенчмарков. + +| Референс | Схема доработки | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Узкий контейнер → штатная одна колонка → полная подпись KPI; [BGP320](ux-ui/screens/ui261-bgp320.png) | +| [ReUI Badge](https://reui.io/components/badge?ref=mcp) | Тип устройства → light variant → semantic foreground | + +Настройки CHR, DNS, сертификаты и пароли не менялись. Native/background telemetry reads не объявляются отсутствием всех DB metadata updates. Manual screen-reader, новые клиентские ОС/WAN/public IPv6/multi-instance, CA revoke и внешняя публикация остаются отдельными границами. Следующий262 — оформить завершённый ten-minute REST soak, затем263 — актуальная полная локальная UI-регрессия после общего keyboard adapter260 и responsive delta261. Автоматическая120-state проверка не заменяет сквозные сценарии и не является полной WCAG сертификацией. ## 12.5.260 — общая доступность, клавиатура и профильная скорость UI (2026-10-15) @@ -348,7 +367,7 @@ Production backend/frontend ux-backups237 собраны и развёрнуты | Масштаб и устойчивость | Контролируемые PG lock/dedupe/loss/recovery, отдельные multi-process сценарии194/200/201 | Несколько полноценных backend/worker со всеми writers, длительный rekey/traffic, физические потери WAN/DB и maximum throughput | | Хранилища и внешние jobs | Реальные Portal/Telegram195–201, Selectel S3/limited bridge restore/retention228–240, GeoIP mirror242; контейнеры248; production ACME250 и реальное renewal/rotation259 с trusted TLS/cleanup | Large native export/migration buckets/multi-instance S3; CA revocation отдельно не принят. Gitea publishing CI не запускался: действует no push. Direct licensed MaxMind отсутствует в текущей реализации | | Расширенные сетевые конфигурации | GRE/WG/VXLAN/IPsec/OSPF/BFD/BGP в записанных сценариях, включая private IPv6 | from-pool/EUI-64/multiple-address import/export, outer IPv6, произвольная PKI/OID/path-length, независимые внешние peers и длительные переходы. BFD-only gate не гарантирован | -| UX, доступность и производительность | UI226, ARIA мастеров251, новая проверка260 текущего runtime описана выше | Исправления260 и72 live состояния приняты; оставшиеся12 экранов и ручная screen-reader приёмка отдельно. Synthetic timing не field CWV, scoped axe не полная WCAG сертификация | +| UX, доступность и производительность | UI226, ARIA мастеров251, новая проверка260 текущего runtime описана выше | Default UI260/261:120 unique states30 экранов приняты в автоматическом scope; актуальная полная UI-регрессия263 и ручная screen-reader приёмка отдельно. Synthetic timing не field CWV, scoped axe не полная WCAG сертификация | | Границы выпуска | Датированный журнал, протоколы и локальные коммиты без push | Подготовить итоговый перечень принятых конфигураций/исключений для решения о выпуске; лабораторный успех не объявлять приёмкой всех конфигураций | Portal offline JWT действует доexp после logout/role change; это записанная граница198, не мгновенная revocation. Controlled Telegram unknown/retry201 не доказывает физическую потерю ACK в WAN. Архивные записи ниже отражают состояние на свою дату; актуальный статус задают эта таблица и верхняя точка продолжения. @@ -373,7 +392,7 @@ Portal offline JWT действует доexp после logout/role change; э ## Следующая последовательность — 2026-10-15 -1. **Приёмка261:**12 оставшихся default screens с real Portal/API и точным read-only guard; профильный audit/layout/performance. Сертификаты259 и UI260 приняты в записанных границах. +1. **REST262 и регрессия263:** оформить десятиминутную стабильность backend258; один полный локальный UI-набор после shared keyboard260/responsive261 с сохранением исходных screenshots и недоступным proxy backend, без native writes. 2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания. 3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 3868ea1a..790d4ccf 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-15: 260 — исправлены общие focus/target-size/contrast и BGP320 tabs; production frontend ux-accessibility260-final развёрнут, backend258 healthy.72 live WCAG/layout состояния прошли,59 уникальных E2E прошли в записанных итерациях; synthetic timing сохранён. Следующий261 — оставшиеся12 экранов и точные границы приёмки; этап12.5 открыт. +Актуальное продолжение 2026-10-15: 261 — оставшиеся12 default screens проверены; контраст recursive/ECMP исправлен, KPI BGP/GRE/VXLAN/OSPF используют штатную адаптивную сетку.64 unique live states261, вместе с260 —120 состояний30 экранов с явным происхождением;40 локальных E2E приняты. Runtime backend258/frontend261. Следующий262 — оформить десятиминутный REST-протокол, затем263 — итоговая UI-регрессия; этап12.5 открыт. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -4152,6 +4152,25 @@ Real Portal/browser API, provider local verified: создан один job ро Runtime backend ux-backup234/frontend ux-routing218 healthy; новое application image для volume-only fix не требовалось. Пароли CHR не менялись, S3 mutations0 в235, configs body/JWT не опубликованы, private local manifest удалён. Исходные10 missing local files не восстановлены и records не удалены. Force-recreate — не host reboot/power loss/fsync/DR приёмка. Далее236 — UX недоступных local files, затем version retention границы и оставшиеся7 группы матрицы; multi-instance guard не принимается. Этап12.5 открыт. +## 12.5.261 — оставшиеся экраны и читаемые сетевые KPI (2026-10-15) + +Baseline12 разделов×2 темы×1440/320px:48 live states, API/JS errors0, overflow0, blocked configuration writes0. Четыре проверенных read-only POST OSPF preview разрешены явно после чтения backend handler; они рассчитывают план, не применяют его. DNS resolution/catalog read POST также имеют точный opt-in allowlist в helper, остальные non-GET блокируются. EvoBGP на стенде disabled, URL/key не настроены: каталоги здесь проверены в состоянии недоступной интеграции, не с реальными внешними данными. [Baseline](ux-ui/acceptance/ui261-baseline.json). + +Найдены4 contrast failures: TypeChip в recursive-routes/light и opacity40 всего ECMP disabled section в двух темах на ПК. TypeChip теперь использует установленный ReUI Badge light variants/text-foreground; ECMP — native disabled fieldset с legend вместо затемнения всех подписей. Профильная проверка включённого ECMP дополнительно выявила неконтрастный выбранный алгоритм; применены bg-muted/text-foreground. Это локальный черновик, серверная логика/применение маршрутов не менялись. + +В BGP summary/analytics, GRE, VXLAN, OSPF summary/BFD убраны принудительные grid-cols2 overrides. Используются существующие kpiCols и неизменённые Frame/IconTile/KpiStatGrid: одна колонка в узком контейнере, прежние container breakpoints для плотного ПК. Шрифты, vendor компоненты, theme tokens и motion не менялись. В8 локальных geometry cases320/390 и16 live theme/width cases подписи KPI не обрезаются; explicit краткая подпись Интерф. в OSPF сохранена. [Снимок BGP320 после загрузки](ux-ui/screens/ui261-bgp320.png). + +Локальные40 E2E: initial38 passed/2 ECMP contrast failed; после исправления повторены только2 affected cases, passed. Geometry8, ECMP2, recursive route contracts15 и OSPF preview15; разные прогоны не суммируются в42 сценария. ECMP false/true проверены также в настоящем Portal/UI, scoped axe0, configuration writes0, draft возвращён off. [Live ECMP](ux-ui/acceptance/ui261-live-ecmp.json). TypeScript/scoped ESLint и production build passed, source528 matched. Runtime frontend ux-accessibility261, backend ux-certificates258 healthy; DB/Portal сохранены. [Deployment](ux-ui/acceptance/ui261-deployment.json). + +Повторены только6 изменённых страниц:24 live states, WCAG-tagged axe violations0/API/JS errors0/overflow0/clipped KPI labels0. С48 baseline это64 уникальных состояния16 страниц: восемь состояний двух изменённых baseline страниц заменены повторными, четыре сетевых KPI страницы добавлены. Вместе с260 —120 уникальных default states30 экранов. Report сохраняет фазу/образ каждого результата: остальные страницы не выданы за повторный прогон на261. [Changed24](ux-ui/acceptance/ui261-changed-final.json), [итог64](ux-ui/acceptance/ui261-final.json), [сводка](ux-ui/acceptance/ui261-summary.json). Во время части замеров шла контролируемая REST-нагрузка262, timings не field CWV и не сравнение независимых бенчмарков. + +| Референс | Схема доработки | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Узкий контейнер → штатная одна колонка → полная подпись KPI; [BGP320](ux-ui/screens/ui261-bgp320.png) | +| [ReUI Badge](https://reui.io/components/badge?ref=mcp) | Тип устройства → light variant → semantic foreground | + +Настройки CHR, DNS, сертификаты и пароли не менялись. Native/background telemetry reads не объявляются отсутствием всех DB metadata updates. Manual screen-reader, новые клиентские ОС/WAN/public IPv6/multi-instance, CA revoke и внешняя публикация остаются отдельными границами. Следующий262 — оформить завершённый ten-minute REST soak, затем263 — актуальная полная локальная UI-регрессия после общего keyboard adapter260 и responsive delta261. Автоматическая120-state проверка не заменяет сквозные сценарии и не является полной WCAG сертификацией. + ## 12.5.260 — общая доступность, клавиатура и профильная скорость UI (2026-10-15) Проведён read-only аудит18 разделов×2 темы×1440/320px:72 состояния текущего стенда/настоящий Portal UI, без response mocks. Baseline выявил23 состояния с axe нарушениями: недостаточная независимая pointer-area у focusable listbox-контейнера, контраст счётчиков SegmentedControl, raw type badges серверов и заголовка VXLAN. Document overflow0/JS errors0/API errors0; BGP320 имел2 внутренних переполнения main. Dashboard в baseline ещё содержал skeleton: его ранние timings не считаются готовностью данных. [Baseline](ux-ui/acceptance/ui260-baseline.json). diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index dd636915..2eda037e 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -1,6 +1,6 @@ # Тестовый сервер UX/UI — 2026-10-10 -Актуальное продолжение 2026-10-15: 260 — исправлены общие focus/target-size/contrast и BGP320 tabs; production frontend ux-accessibility260-final развёрнут, backend258 healthy.72 live WCAG/layout состояния прошли,59 уникальных E2E прошли в записанных итерациях; synthetic timing сохранён. Следующий261 — оставшиеся12 экранов и точные границы приёмки; этап12.5 открыт. +Актуальное продолжение 2026-10-15: 261 — оставшиеся12 default screens проверены; контраст recursive/ECMP исправлен, KPI BGP/GRE/VXLAN/OSPF используют штатную адаптивную сетку.64 unique live states261, вместе с260 —120 состояний30 экранов с явным происхождением;40 локальных E2E приняты. Runtime backend258/frontend261. Следующий262 — оформить десятиминутный REST-протокол, затем263 — итоговая UI-регрессия; этап12.5 открыт. | Параметр | Проверенное состояние | | --- | --- | @@ -14,7 +14,7 @@ | PostgreSQL | postgres:18-alpine,18.6;mmapp-test-postgres healthy;SELECT version() passed | | Данные | Отдельный Compose project mmapp-test,том mmapp-test_mmapp-pgdata и каталог ./data | | Доступ | PostgreSQL не публикуется;frontend3000/backend8000 привязаны к127.0.0.1 после запуска | -| Образы приложения | mmapp-test/backend:ux-certificates258 и mmapp-test/frontend:ux-accessibility260-final; backend healthy, проверено2026-10-15 в260 | +| Образы приложения | mmapp-test/backend:ux-certificates258 и mmapp-test/frontend:ux-accessibility261; backend healthy, проверено2026-10-15 в261 | Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example). @@ -34,6 +34,25 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json). +## 12.5.261 — оставшиеся экраны и читаемые сетевые KPI (2026-10-15) + +Baseline12 разделов×2 темы×1440/320px:48 live states, API/JS errors0, overflow0, blocked configuration writes0. Четыре проверенных read-only POST OSPF preview разрешены явно после чтения backend handler; они рассчитывают план, не применяют его. DNS resolution/catalog read POST также имеют точный opt-in allowlist в helper, остальные non-GET блокируются. EvoBGP на стенде disabled, URL/key не настроены: каталоги здесь проверены в состоянии недоступной интеграции, не с реальными внешними данными. [Baseline](ux-ui/acceptance/ui261-baseline.json). + +Найдены4 contrast failures: TypeChip в recursive-routes/light и opacity40 всего ECMP disabled section в двух темах на ПК. TypeChip теперь использует установленный ReUI Badge light variants/text-foreground; ECMP — native disabled fieldset с legend вместо затемнения всех подписей. Профильная проверка включённого ECMP дополнительно выявила неконтрастный выбранный алгоритм; применены bg-muted/text-foreground. Это локальный черновик, серверная логика/применение маршрутов не менялись. + +В BGP summary/analytics, GRE, VXLAN, OSPF summary/BFD убраны принудительные grid-cols2 overrides. Используются существующие kpiCols и неизменённые Frame/IconTile/KpiStatGrid: одна колонка в узком контейнере, прежние container breakpoints для плотного ПК. Шрифты, vendor компоненты, theme tokens и motion не менялись. В8 локальных geometry cases320/390 и16 live theme/width cases подписи KPI не обрезаются; explicit краткая подпись Интерф. в OSPF сохранена. [Снимок BGP320 после загрузки](ux-ui/screens/ui261-bgp320.png). + +Локальные40 E2E: initial38 passed/2 ECMP contrast failed; после исправления повторены только2 affected cases, passed. Geometry8, ECMP2, recursive route contracts15 и OSPF preview15; разные прогоны не суммируются в42 сценария. ECMP false/true проверены также в настоящем Portal/UI, scoped axe0, configuration writes0, draft возвращён off. [Live ECMP](ux-ui/acceptance/ui261-live-ecmp.json). TypeScript/scoped ESLint и production build passed, source528 matched. Runtime frontend ux-accessibility261, backend ux-certificates258 healthy; DB/Portal сохранены. [Deployment](ux-ui/acceptance/ui261-deployment.json). + +Повторены только6 изменённых страниц:24 live states, WCAG-tagged axe violations0/API/JS errors0/overflow0/clipped KPI labels0. С48 baseline это64 уникальных состояния16 страниц: восемь состояний двух изменённых baseline страниц заменены повторными, четыре сетевых KPI страницы добавлены. Вместе с260 —120 уникальных default states30 экранов. Report сохраняет фазу/образ каждого результата: остальные страницы не выданы за повторный прогон на261. [Changed24](ux-ui/acceptance/ui261-changed-final.json), [итог64](ux-ui/acceptance/ui261-final.json), [сводка](ux-ui/acceptance/ui261-summary.json). Во время части замеров шла контролируемая REST-нагрузка262, timings не field CWV и не сравнение независимых бенчмарков. + +| Референс | Схема доработки | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Узкий контейнер → штатная одна колонка → полная подпись KPI; [BGP320](ux-ui/screens/ui261-bgp320.png) | +| [ReUI Badge](https://reui.io/components/badge?ref=mcp) | Тип устройства → light variant → semantic foreground | + +Настройки CHR, DNS, сертификаты и пароли не менялись. Native/background telemetry reads не объявляются отсутствием всех DB metadata updates. Manual screen-reader, новые клиентские ОС/WAN/public IPv6/multi-instance, CA revoke и внешняя публикация остаются отдельными границами. Следующий262 — оформить завершённый ten-minute REST soak, затем263 — актуальная полная локальная UI-регрессия после общего keyboard adapter260 и responsive delta261. Автоматическая120-state проверка не заменяет сквозные сценарии и не является полной WCAG сертификацией. + ## 12.5.260 — общая доступность, клавиатура и профильная скорость UI (2026-10-15) Проведён read-only аудит18 разделов×2 темы×1440/320px:72 состояния текущего стенда/настоящий Portal UI, без response mocks. Baseline выявил23 состояния с axe нарушениями: недостаточная независимая pointer-area у focusable listbox-контейнера, контраст счётчиков SegmentedControl, raw type badges серверов и заголовка VXLAN. Document overflow0/JS errors0/API errors0; BGP320 имел2 внутренних переполнения main. Dashboard в baseline ещё содержал skeleton: его ранние timings не считаются готовностью данных. [Baseline](ux-ui/acceptance/ui260-baseline.json). diff --git a/docs/ux-ui/acceptance/ui261-baseline.json b/docs/ux-ui/acceptance/ui261-baseline.json new file mode 100644 index 00000000..1b551e91 --- /dev/null +++ b/docs/ux-ui/acceptance/ui261-baseline.json @@ -0,0 +1,1484 @@ +{ + "date": "2026-10-15", + "block": "12.5.261", + "origin": "http://localhost:3000", + "realPortalUiLogin": true, + "responseMocks": false, + "deviceWritesPermitted": false, + "cases": [ + { + "theme": "dark", + "path": "/users", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1180, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 1180, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 1052, + "cls": 0.06308886127989968, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 110.90000000223517, + "domInteractiveMs": 349.8999999985099, + "durationMs": 666.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/users", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 533, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 635, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 576, + "cls": 0.096197790625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.30000000074506, + "domInteractiveMs": 207.39999999850988, + "durationMs": 415.30000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/firewall", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 551, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1414, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 540, + "cls": 0.09758711492091049, + "longTasks": 1, + "longTaskMs": 57, + "ttfbMs": 90.69999999925494, + "domInteractiveMs": 224, + "durationMs": 445.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/firewall", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 562, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1424, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 512, + "cls": 0.238883196875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 95, + "domInteractiveMs": 246.89999999850988, + "durationMs": 462.79999999701977 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/probes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 640, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 993, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 808, + "cls": 0.000031850405092592596, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 111.19999999925494, + "domInteractiveMs": 296, + "durationMs": 557.6999999992549 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/probes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 540, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 908, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 712, + "cls": 0.00012464375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.30000000074506, + "domInteractiveMs": 219.70000000298023, + "durationMs": 446.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/terminal", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 587, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 937, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 576, + "cls": 0.001050857536410108, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 106.5, + "domInteractiveMs": 275.80000000074506, + "durationMs": 475.30000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/terminal", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 456, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 561, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 400, + "cls": 0.004743726171875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.600000001490116, + "domInteractiveMs": 138.30000000074506, + "durationMs": 318.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/data-collection", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 621, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 2484, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 600, + "cls": 0.030615641939139664, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 135.5, + "domInteractiveMs": 284.1000000014901, + "durationMs": 507.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/data-collection", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 973, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 2860, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 608, + "cls": 0.086460921875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.400000002235174, + "domInteractiveMs": 142.5, + "durationMs": 514.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/recursive-routes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 546, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 656, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 528, + "cls": 0.050287300588348766, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 59.600000001490116, + "domInteractiveMs": 230.10000000149012, + "durationMs": 450.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/recursive-routes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 502, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 606, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 456, + "cls": 0.08047623984374999, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.19999999925494, + "domInteractiveMs": 187.29999999701977, + "durationMs": 397.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/route-optimizer", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 502, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 874, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 504, + "cls": 0.633712198591821, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 51.100000001490116, + "domInteractiveMs": 188.09999999776483, + "durationMs": 397.5999999977648 + }, + "violations": [ + { + "id": "color-contrast", + "impact": "serious", + "targets": [ + [ + ".transition-opacity > .gap-1\\.5.flex-col.flex:nth-child(1) > .text-xs.text-muted-foreground" + ] + ] + } + ], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/route-optimizer", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 517, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 875, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 752, + "cls": 0.06558586474609375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 56.30000000074506, + "domInteractiveMs": 201.19999999925494, + "durationMs": 410.69999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/network-map", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 548, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 913, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 760, + "cls": 0.4066049501470872, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.30000000074506, + "domInteractiveMs": 229.89999999850988, + "durationMs": 423.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/network-map", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 450, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 816, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 748, + "cls": 0.2168260953125, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.600000001490116, + "domInteractiveMs": 135.80000000074506, + "durationMs": 320 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ip-ranges", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1085, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1085, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 668, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 96.90000000223517, + "domInteractiveMs": 255.09999999776483, + "durationMs": 594.1999999992549 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ip-ranges", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1010, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1010, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 628, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 72.69999999925494, + "domInteractiveMs": 187, + "durationMs": 543.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/asns", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 504, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 870, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 488, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.80000000074506, + "domInteractiveMs": 187.80000000074506, + "durationMs": 383.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/asns", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 453, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 814, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 380, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.19999999925494, + "domInteractiveMs": 139.10000000149012, + "durationMs": 325.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/communities", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 497, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 851, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 464, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.600000001490116, + "domInteractiveMs": 188.39999999850988, + "durationMs": 373.5999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/communities", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 484, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 848, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 420, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.20000000298023, + "domInteractiveMs": 166.39999999850988, + "durationMs": 343.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/domains", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1065, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1065, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 568, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.80000000074506, + "domInteractiveMs": 218.80000000074506, + "durationMs": 473.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/domains", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 484, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 588, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 404, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.19999999925494, + "domInteractiveMs": 167.79999999701977, + "durationMs": 352.69999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/users", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 625, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 978, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 748, + "cls": 0.06308886127989968, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 95.69999999925494, + "domInteractiveMs": 286.8999999985099, + "durationMs": 494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/users", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 521, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 624, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 544, + "cls": 0.096197790625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.89999999850988, + "domInteractiveMs": 190.89999999850988, + "durationMs": 404.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/firewall", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 530, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1387, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 512, + "cls": 0.09758711492091049, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 88.59999999776483, + "domInteractiveMs": 217.90000000223517, + "durationMs": 437.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/firewall", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 533, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1406, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 476, + "cls": 0.238883196875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.69999999925494, + "domInteractiveMs": 203.40000000223517, + "durationMs": 418.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/probes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 561, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 926, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 724, + "cls": 0.000031850405092592596, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.79999999701977, + "domInteractiveMs": 238.39999999850988, + "durationMs": 532.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/probes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 503, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 616, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 576, + "cls": 0.00012464375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.100000001490116, + "domInteractiveMs": 186.59999999776483, + "durationMs": 403.29999999701977 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/terminal", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 567, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 923, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 540, + "cls": 0.0009951179711612656, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 99, + "domInteractiveMs": 248.59999999776483, + "durationMs": 437 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/terminal", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 526, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 637, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 520, + "cls": 0.004671481640625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 58.600000001490116, + "domInteractiveMs": 211.59999999776483, + "durationMs": 500.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/data-collection", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 570, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 1440, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 544, + "cls": 0.030611679808063275, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 93, + "domInteractiveMs": 222.39999999850988, + "durationMs": 437.79999999701977 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/data-collection", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 514, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 2392, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 500, + "cls": 0.086460921875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 49.5, + "domInteractiveMs": 180.19999999925494, + "durationMs": 391.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/recursive-routes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 607, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 707, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 560, + "cls": 0.050287300588348766, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.29999999701977, + "domInteractiveMs": 288.30000000074506, + "durationMs": 492.8999999985099 + }, + "violations": [ + { + "id": "color-contrast", + "impact": "serious", + "targets": [ + [ + ".rounded" + ] + ] + } + ], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/recursive-routes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 556, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 665, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 500, + "cls": 0.08047623984374999, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 71.89999999850988, + "domInteractiveMs": 235.59999999776483, + "durationMs": 439.3999999985099 + }, + "violations": [ + { + "id": "color-contrast", + "impact": "serious", + "targets": [ + [ + ".rounded" + ] + ] + } + ], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/route-optimizer", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 553, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 903, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 552, + "cls": 0.633712198591821, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.69999999925494, + "domInteractiveMs": 185.80000000074506, + "durationMs": 438.20000000298023 + }, + "violations": [ + { + "id": "color-contrast", + "impact": "serious", + "targets": [ + [ + ".transition-opacity > .gap-1\\.5.flex-col.flex:nth-child(1) > .text-xs.text-muted-foreground" + ] + ] + } + ], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/route-optimizer", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 512, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 868, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 716, + "cls": 0.06558586474609375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 58.599999997764826, + "domInteractiveMs": 199, + "durationMs": 409.30000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/network-map", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 589, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 948, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 808, + "cls": 0.41068980028694063, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.5, + "domInteractiveMs": 236.89999999850988, + "durationMs": 464.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/network-map", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1052, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 1052, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 796, + "cls": 0.2168260953125, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 51.80000000074506, + "domInteractiveMs": 210.09999999776483, + "durationMs": 486 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ip-ranges", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1108, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1109, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 640, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 109.69999999925494, + "domInteractiveMs": 290.30000000074506, + "durationMs": 540.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ip-ranges", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 448, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 802, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 396, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.599999997764826, + "domInteractiveMs": 135.69999999925494, + "durationMs": 316.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/asns", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 625, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 975, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 572, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.399999998509884, + "domInteractiveMs": 301.6000000014901, + "durationMs": 489.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/asns", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 464, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 571, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 380, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 61.30000000074506, + "domInteractiveMs": 151.30000000074506, + "durationMs": 333.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/communities", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 516, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 887, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 504, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.900000002235174, + "domInteractiveMs": 185, + "durationMs": 463.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/communities", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 450, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 818, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 416, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.5, + "domInteractiveMs": 137.89999999850988, + "durationMs": 330.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/domains", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 499, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 859, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 448, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.600000001490116, + "domInteractiveMs": 183, + "durationMs": 384.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/domains", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 589, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 948, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 588, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 72.90000000223517, + "domInteractiveMs": 264.6000000014901, + "durationMs": 520 + }, + "violations": [], + "auditCompleted": true + } + ], + "blockedWrites": [], + "readOnlyPosts": [ + { + "theme": "dark", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "dark", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "light", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "light", + "path": "/api/servers/1/ospf/optimize/preview" + } + ], + "bounds": [ + "Default rendered state only; data can still be refreshing", + "Synthetic lab timing over SSH, no CPU/network throttling; not field Core Web Vitals", + "Automated WCAG-tagged checks, not manual screen-reader certification" + ], + "completed": true, + "passed": false +} diff --git a/docs/ux-ui/acceptance/ui261-changed-final.json b/docs/ux-ui/acceptance/ui261-changed-final.json new file mode 100644 index 00000000..53b9b46a --- /dev/null +++ b/docs/ux-ui/acceptance/ui261-changed-final.json @@ -0,0 +1,1088 @@ +{ + "date": "2026-10-15", + "block": "12.5.261", + "origin": "http://localhost:3000", + "realPortalUiLogin": true, + "responseMocks": false, + "deviceWritesPermitted": false, + "cases": [ + { + "theme": "dark", + "path": "/recursive-routes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1174, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 1175, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 816, + "cls": 0.050188635947145066, + "longTasks": 2, + "longTaskMs": 136, + "ttfbMs": 124.80000000074506, + "domInteractiveMs": 331.0999999977648, + "durationMs": 618.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/recursive-routes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 564, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 666, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 516, + "cls": 0.08016383984375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.20000000298023, + "domInteractiveMs": 213.30000000074506, + "durationMs": 423.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/route-optimizer", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 639, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 991, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 680, + "cls": 0.633712198591821, + "longTasks": 2, + "longTaskMs": 140, + "ttfbMs": 54.900000002235174, + "domInteractiveMs": 223.90000000223517, + "durationMs": 451.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/route-optimizer", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1110, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 1111, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 1080, + "cls": 0.06558586474609375, + "longTasks": 1, + "longTaskMs": 69, + "ttfbMs": 59.399999998509884, + "domInteractiveMs": 246.19999999925494, + "durationMs": 559.2999999970198 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/bgp", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 633, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 988, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 648, + "cls": 0.008227206790123459, + "longTasks": 1, + "longTaskMs": 87, + "ttfbMs": 121.89999999850988, + "domInteractiveMs": 273.4000000022352, + "durationMs": 505.4000000022352 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/bgp", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 606, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 969, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 808, + "cls": 0.045822321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 75.80000000074506, + "domInteractiveMs": 267.9000000022352, + "durationMs": 538 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/gre", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 652, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 1009, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 644, + "cls": 0.06258026005497686, + "longTasks": 1, + "longTaskMs": 67, + "ttfbMs": 96, + "domInteractiveMs": 303.19999999925494, + "durationMs": 533.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/gre", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 507, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 872, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 512, + "cls": 0.107477715625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 56.19999999925494, + "domInteractiveMs": 171.30000000074506, + "durationMs": 402.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/vxlan", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 655, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 2509, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 680, + "cls": 0.12087190923996914, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 98.10000000149012, + "domInteractiveMs": 248.19999999925494, + "durationMs": 738.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/vxlan", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1107, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 1108, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 712, + "cls": 0.24378085312499997, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 56.5, + "domInteractiveMs": 240, + "durationMs": 613.8000000007451 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ospf", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 732, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1608, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 728, + "cls": 0.0054106802782600315, + "longTasks": 1, + "longTaskMs": 118, + "ttfbMs": 108.29999999701977, + "domInteractiveMs": 274.5999999977648, + "durationMs": 561.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ospf", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 499, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1366, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 492, + "cls": 0.027072464453125004, + "longTasks": 1, + "longTaskMs": 79, + "ttfbMs": 50.899999998509884, + "domInteractiveMs": 159.30000000074506, + "durationMs": 384.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/recursive-routes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1176, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 1176, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 736, + "cls": 0.05015528669945988, + "longTasks": 1, + "longTaskMs": 60, + "ttfbMs": 97.59999999776483, + "domInteractiveMs": 331.80000000074506, + "durationMs": 620.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/recursive-routes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 553, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 663, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 492, + "cls": 0.08016383984375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53, + "domInteractiveMs": 215.10000000149012, + "durationMs": 417 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/route-optimizer", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 633, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 986, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 628, + "cls": 0.633712198591821, + "longTasks": 2, + "longTaskMs": 131, + "ttfbMs": 57.399999998509884, + "domInteractiveMs": 243, + "durationMs": 458.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/route-optimizer", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 629, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 984, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 920, + "cls": 0.06558586474609375, + "longTasks": 1, + "longTaskMs": 64, + "ttfbMs": 51.899999998509884, + "domInteractiveMs": 204.20000000298023, + "durationMs": 464 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/bgp", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 763, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 2622, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 752, + "cls": 0.008227206790123459, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 103.5, + "domInteractiveMs": 299.80000000074506, + "durationMs": 649.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/bgp", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 555, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 918, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 764, + "cls": 0.045822321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53, + "domInteractiveMs": 223.89999999850988, + "durationMs": 501.69999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/gre", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 631, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 997, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 608, + "cls": 0.06258026005497686, + "longTasks": 1, + "longTaskMs": 69, + "ttfbMs": 104.40000000223517, + "domInteractiveMs": 267.80000000074506, + "durationMs": 494.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/gre", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 521, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 887, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 476, + "cls": 0.107477715625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.30000000074506, + "domInteractiveMs": 175.60000000149012, + "durationMs": 396.4000000022352 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/vxlan", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 635, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 2502, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 620, + "cls": 0.12087190923996914, + "longTasks": 1, + "longTaskMs": 71, + "ttfbMs": 117.60000000149012, + "domInteractiveMs": 285, + "durationMs": 509.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/vxlan", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 557, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 922, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 548, + "cls": 0.24378085312499997, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.19999999925494, + "domInteractiveMs": 227, + "durationMs": 437.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ospf", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1221, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1221, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 712, + "cls": 0.0054106802782600315, + "longTasks": 1, + "longTaskMs": 109, + "ttfbMs": 95.10000000149012, + "domInteractiveMs": 246.19999999925494, + "durationMs": 543.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ospf", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 509, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1395, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 500, + "cls": 0.027072464453125004, + "longTasks": 1, + "longTaskMs": 66, + "ttfbMs": 54.399999998509884, + "domInteractiveMs": 160.19999999925494, + "durationMs": 409.5 + }, + "violations": [], + "auditCompleted": true + } + ], + "blockedWrites": [], + "readOnlyPosts": [ + { + "theme": "dark", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "dark", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "light", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "light", + "path": "/api/servers/1/ospf/optimize/preview" + } + ], + "bounds": [ + "Default rendered state only; data can still be refreshing", + "Synthetic lab timing over SSH, no CPU/network throttling; not field Core Web Vitals", + "Automated WCAG-tagged checks, not manual screen-reader certification" + ], + "completed": true, + "passed": true +} diff --git a/docs/ux-ui/acceptance/ui261-deployment.json b/docs/ux-ui/acceptance/ui261-deployment.json new file mode 100644 index 00000000..98982956 --- /dev/null +++ b/docs/ux-ui/acceptance/ui261-deployment.json @@ -0,0 +1,20 @@ +{ + "date": "2026-10-15", + "block": "12.5.261", + "productionBuild": "passed", + "sourceMatched": 528, + "services": { + "backend": { + "image": "mmapp-test/backend:ux-certificates258", + "imageId": "sha256:984684709e619972bae8657208e3150d12f1c4f2b5642fecf5286a5d87e9fe71", + "status": "running", + "health": "healthy" + }, + "frontend": { + "image": "mmapp-test/frontend:ux-accessibility261", + "imageId": "sha256:eec4410f1109a46e864d695cfb4311fdb9a224247549c8a9e78e44c6c0e455cb", + "status": "running", + "health": null + } + } +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/ui261-final.json b/docs/ux-ui/acceptance/ui261-final.json new file mode 100644 index 00000000..bf8246c9 --- /dev/null +++ b/docs/ux-ui/acceptance/ui261-final.json @@ -0,0 +1,2286 @@ +{ + "date": "2026-10-15", + "block": "12.5.261", + "origin": "http://localhost:3000", + "realPortalUiLogin": true, + "responseMocks": false, + "deviceWritesPermitted": false, + "cases": [ + { + "theme": "dark", + "path": "/users", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1180, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 1180, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 1052, + "cls": 0.06308886127989968, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 110.90000000223517, + "domInteractiveMs": 349.8999999985099, + "durationMs": 666.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/users", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 533, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 635, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 576, + "cls": 0.096197790625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.30000000074506, + "domInteractiveMs": 207.39999999850988, + "durationMs": 415.30000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/firewall", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 551, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1414, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 540, + "cls": 0.09758711492091049, + "longTasks": 1, + "longTaskMs": 57, + "ttfbMs": 90.69999999925494, + "domInteractiveMs": 224, + "durationMs": 445.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/firewall", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 562, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1424, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 512, + "cls": 0.238883196875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 95, + "domInteractiveMs": 246.89999999850988, + "durationMs": 462.79999999701977 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/probes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 640, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 993, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 808, + "cls": 0.000031850405092592596, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 111.19999999925494, + "domInteractiveMs": 296, + "durationMs": 557.6999999992549 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/probes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 540, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 908, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 712, + "cls": 0.00012464375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.30000000074506, + "domInteractiveMs": 219.70000000298023, + "durationMs": 446.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/terminal", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 587, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 937, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 576, + "cls": 0.001050857536410108, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 106.5, + "domInteractiveMs": 275.80000000074506, + "durationMs": 475.30000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/terminal", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 456, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 561, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 400, + "cls": 0.004743726171875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.600000001490116, + "domInteractiveMs": 138.30000000074506, + "durationMs": 318.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/data-collection", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 621, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 2484, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 600, + "cls": 0.030615641939139664, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 135.5, + "domInteractiveMs": 284.1000000014901, + "durationMs": 507.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/data-collection", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 973, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 2860, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 608, + "cls": 0.086460921875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.400000002235174, + "domInteractiveMs": 142.5, + "durationMs": 514.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/recursive-routes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1174, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 1175, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 816, + "cls": 0.050188635947145066, + "longTasks": 2, + "longTaskMs": 136, + "ttfbMs": 124.80000000074506, + "domInteractiveMs": 331.0999999977648, + "durationMs": 618.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/recursive-routes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 564, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 666, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 516, + "cls": 0.08016383984375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.20000000298023, + "domInteractiveMs": 213.30000000074506, + "durationMs": 423.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/route-optimizer", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 639, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 991, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 680, + "cls": 0.633712198591821, + "longTasks": 2, + "longTaskMs": 140, + "ttfbMs": 54.900000002235174, + "domInteractiveMs": 223.90000000223517, + "durationMs": 451.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/route-optimizer", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1110, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 1111, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 1080, + "cls": 0.06558586474609375, + "longTasks": 1, + "longTaskMs": 69, + "ttfbMs": 59.399999998509884, + "domInteractiveMs": 246.19999999925494, + "durationMs": 559.2999999970198 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/network-map", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 548, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 913, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 760, + "cls": 0.4066049501470872, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.30000000074506, + "domInteractiveMs": 229.89999999850988, + "durationMs": 423.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/network-map", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 450, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 816, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 748, + "cls": 0.2168260953125, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.600000001490116, + "domInteractiveMs": 135.80000000074506, + "durationMs": 320 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ip-ranges", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1085, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1085, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 668, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 96.90000000223517, + "domInteractiveMs": 255.09999999776483, + "durationMs": 594.1999999992549 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ip-ranges", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1010, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1010, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 628, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 72.69999999925494, + "domInteractiveMs": 187, + "durationMs": 543.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/asns", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 504, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 870, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 488, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.80000000074506, + "domInteractiveMs": 187.80000000074506, + "durationMs": 383.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/asns", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 453, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 814, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 380, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.19999999925494, + "domInteractiveMs": 139.10000000149012, + "durationMs": 325.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/communities", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 497, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 851, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 464, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.600000001490116, + "domInteractiveMs": 188.39999999850988, + "durationMs": 373.5999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/communities", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 484, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 848, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 420, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.20000000298023, + "domInteractiveMs": 166.39999999850988, + "durationMs": 343.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/domains", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1065, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1065, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 568, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 54.80000000074506, + "domInteractiveMs": 218.80000000074506, + "durationMs": 473.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/domains", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 484, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 588, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 404, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.19999999925494, + "domInteractiveMs": 167.79999999701977, + "durationMs": 352.69999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/users", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 625, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 978, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 748, + "cls": 0.06308886127989968, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 95.69999999925494, + "domInteractiveMs": 286.8999999985099, + "durationMs": 494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/users", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 521, + "requiredReads": [ + "/api/users" + ], + "dataResponsesMs": 624, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 544, + "cls": 0.096197790625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.89999999850988, + "domInteractiveMs": 190.89999999850988, + "durationMs": 404.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/firewall", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 530, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1387, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 512, + "cls": 0.09758711492091049, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 88.59999999776483, + "domInteractiveMs": 217.90000000223517, + "durationMs": 437.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/firewall", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 533, + "requiredReads": [ + "/api/firewall/all" + ], + "dataResponsesMs": 1406, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 476, + "cls": 0.238883196875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.69999999925494, + "domInteractiveMs": 203.40000000223517, + "durationMs": 418.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/probes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 561, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 926, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 724, + "cls": 0.000031850405092592596, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.79999999701977, + "domInteractiveMs": 238.39999999850988, + "durationMs": 532.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/probes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 503, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 616, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 576, + "cls": 0.00012464375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.100000001490116, + "domInteractiveMs": 186.59999999776483, + "durationMs": 403.29999999701977 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/terminal", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 567, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 923, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 540, + "cls": 0.0009951179711612656, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 99, + "domInteractiveMs": 248.59999999776483, + "durationMs": 437 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/terminal", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 526, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 637, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 520, + "cls": 0.004671481640625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 58.600000001490116, + "domInteractiveMs": 211.59999999776483, + "durationMs": 500.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/data-collection", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 570, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 1440, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 544, + "cls": 0.030611679808063275, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 93, + "domInteractiveMs": 222.39999999850988, + "durationMs": 437.79999999701977 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/data-collection", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 514, + "requiredReads": [ + "/api/scheduler/status" + ], + "dataResponsesMs": 2392, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 500, + "cls": 0.086460921875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 49.5, + "domInteractiveMs": 180.19999999925494, + "durationMs": 391.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/recursive-routes", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1176, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 1176, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 736, + "cls": 0.05015528669945988, + "longTasks": 1, + "longTaskMs": 60, + "ttfbMs": 97.59999999776483, + "domInteractiveMs": 331.80000000074506, + "durationMs": 620.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/recursive-routes", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 553, + "requiredReads": [ + "/api/servers" + ], + "dataResponsesMs": 663, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [], + "performance": { + "lcp": 492, + "cls": 0.08016383984375, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53, + "domInteractiveMs": 215.10000000149012, + "durationMs": 417 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/route-optimizer", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 633, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 986, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 628, + "cls": 0.633712198591821, + "longTasks": 2, + "longTaskMs": 131, + "ttfbMs": 57.399999998509884, + "domInteractiveMs": 243, + "durationMs": 458.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/route-optimizer", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 629, + "requiredReads": [ + "/api/servers", + "/api/filters/rules", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 984, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Home", + "clipped": false + }, + { + "label": "JumpHost", + "clipped": false + }, + { + "label": "Exit Node", + "clipped": false + }, + { + "label": "Рекомендации", + "clipped": false + } + ], + "performance": { + "lcp": 920, + "cls": 0.06558586474609375, + "longTasks": 1, + "longTaskMs": 64, + "ttfbMs": 51.899999998509884, + "domInteractiveMs": 204.20000000298023, + "durationMs": 464 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/network-map", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 589, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 948, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 808, + "cls": 0.41068980028694063, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 97.5, + "domInteractiveMs": 236.89999999850988, + "durationMs": 464.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/network-map", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1052, + "requiredReads": [ + "/api/servers", + "/api/filters/gre-tunnels", + "/api/uptime/speed-probes" + ], + "dataResponsesMs": 1052, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 796, + "cls": 0.2168260953125, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 51.80000000074506, + "domInteractiveMs": 210.09999999776483, + "durationMs": 486 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ip-ranges", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1108, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 1109, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 640, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 109.69999999925494, + "domInteractiveMs": 290.30000000074506, + "durationMs": 540.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ip-ranges", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 448, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 802, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 396, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 50.599999997764826, + "domInteractiveMs": 135.69999999925494, + "durationMs": 316.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/asns", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 625, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 975, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 572, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 55.399999998509884, + "domInteractiveMs": 301.6000000014901, + "durationMs": 489.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/asns", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 464, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 571, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 380, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 61.30000000074506, + "domInteractiveMs": 151.30000000074506, + "durationMs": 333.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/communities", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 516, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 887, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 504, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.900000002235174, + "domInteractiveMs": 185, + "durationMs": 463.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/communities", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 450, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 818, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 416, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.5, + "domInteractiveMs": 137.89999999850988, + "durationMs": 330.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/domains", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 499, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 859, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 448, + "cls": 0.000013114872685185185, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.600000001490116, + "domInteractiveMs": 183, + "durationMs": 384.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/domains", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 589, + "requiredReads": [ + "/api/evobgp/settings" + ], + "dataResponsesMs": 948, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "performance": { + "lcp": 588, + "cls": 0.000062321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 72.90000000223517, + "domInteractiveMs": 264.6000000014901, + "durationMs": 520 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/bgp", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 633, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 988, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 648, + "cls": 0.008227206790123459, + "longTasks": 1, + "longTaskMs": 87, + "ttfbMs": 121.89999999850988, + "domInteractiveMs": 273.4000000022352, + "durationMs": 505.4000000022352 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/bgp", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 606, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 969, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 808, + "cls": 0.045822321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 75.80000000074506, + "domInteractiveMs": 267.9000000022352, + "durationMs": 538 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/gre", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 652, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 1009, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 644, + "cls": 0.06258026005497686, + "longTasks": 1, + "longTaskMs": 67, + "ttfbMs": 96, + "domInteractiveMs": 303.19999999925494, + "durationMs": 533.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/gre", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 507, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 872, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 512, + "cls": 0.107477715625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 56.19999999925494, + "domInteractiveMs": 171.30000000074506, + "durationMs": 402.80000000074506 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/vxlan", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 655, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 2509, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 680, + "cls": 0.12087190923996914, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 98.10000000149012, + "domInteractiveMs": 248.19999999925494, + "durationMs": 738.3999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/vxlan", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1107, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 1108, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 712, + "cls": 0.24378085312499997, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 56.5, + "domInteractiveMs": 240, + "durationMs": 613.8000000007451 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ospf", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 732, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1608, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 728, + "cls": 0.0054106802782600315, + "longTasks": 1, + "longTaskMs": 118, + "ttfbMs": 108.29999999701977, + "domInteractiveMs": 274.5999999977648, + "durationMs": 561.5 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "dark", + "path": "/ospf", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 499, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1366, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "dark", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 492, + "cls": 0.027072464453125004, + "longTasks": 1, + "longTaskMs": 79, + "ttfbMs": 50.899999998509884, + "domInteractiveMs": 159.30000000074506, + "durationMs": 384.19999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/bgp", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 763, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 2622, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 752, + "cls": 0.008227206790123459, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 103.5, + "domInteractiveMs": 299.80000000074506, + "durationMs": 649.0999999977648 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/bgp", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 555, + "requiredReads": [ + "/api/bgp/catalog" + ], + "dataResponsesMs": 918, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Сессий", + "clipped": false + }, + { + "label": "Established", + "clipped": false + }, + { + "label": "Не поднято", + "clipped": false + }, + { + "label": "Префиксы", + "clipped": false + } + ], + "performance": { + "lcp": 764, + "cls": 0.045822321875, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53, + "domInteractiveMs": 223.89999999850988, + "durationMs": 501.69999999925494 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/gre", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 631, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 997, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 608, + "cls": 0.06258026005497686, + "longTasks": 1, + "longTaskMs": 69, + "ttfbMs": 104.40000000223517, + "domInteractiveMs": 267.80000000074506, + "durationMs": 494.8999999985099 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/gre", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 521, + "requiredReads": [ + "/api/gre/tunnels" + ], + "dataResponsesMs": 887, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активно", + "clipped": false + }, + { + "label": "С IPsec", + "clipped": false + }, + { + "label": "IP-пулов", + "clipped": false + } + ], + "performance": { + "lcp": 476, + "cls": 0.107477715625, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 53.30000000074506, + "domInteractiveMs": 175.60000000149012, + "durationMs": 396.4000000022352 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/vxlan", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 635, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 2502, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 620, + "cls": 0.12087190923996914, + "longTasks": 1, + "longTaskMs": 71, + "ttfbMs": 117.60000000149012, + "domInteractiveMs": 285, + "durationMs": 509.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/vxlan", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 557, + "requiredReads": [ + "/api/vxlan" + ], + "dataResponsesMs": 922, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Туннелей", + "clipped": false + }, + { + "label": "Активных", + "clipped": false + }, + { + "label": "VNI", + "clipped": false + }, + { + "label": "Серверов", + "clipped": false + } + ], + "performance": { + "lcp": 548, + "cls": 0.24378085312499997, + "longTasks": 0, + "longTaskMs": 0, + "ttfbMs": 52.19999999925494, + "domInteractiveMs": 227, + "durationMs": 437.1000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ospf", + "width": 1440, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 1221, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1221, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 712, + "cls": 0.0054106802782600315, + "longTasks": 1, + "longTaskMs": 109, + "ttfbMs": 95.10000000149012, + "domInteractiveMs": 246.19999999925494, + "durationMs": 543.6000000014901 + }, + "violations": [], + "auditCompleted": true + }, + { + "theme": "light", + "path": "/ospf", + "width": 320, + "pageErrors": [], + "apiErrors": [], + "mainVisibleMs": 509, + "requiredReads": [ + "/api/ospf/catalog" + ], + "dataResponsesMs": 1395, + "layout": { + "overflow": false, + "mainOverflow": false, + "theme": "light", + "pendingSkeletons": 0 + }, + "kpiLabels": [ + { + "label": "Роутеры", + "clipped": false + }, + { + "label": "Интерф.", + "clipped": false + }, + { + "label": "Зоны", + "clipped": false + } + ], + "performance": { + "lcp": 500, + "cls": 0.027072464453125004, + "longTasks": 1, + "longTaskMs": 66, + "ttfbMs": 54.399999998509884, + "domInteractiveMs": 160.19999999925494, + "durationMs": 409.5 + }, + "violations": [], + "auditCompleted": true + } + ], + "blockedWrites": [], + "readOnlyPosts": [ + { + "theme": "dark", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "dark", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "light", + "path": "/api/servers/1/ospf/optimize/preview" + }, + { + "theme": "light", + "path": "/api/servers/1/ospf/optimize/preview" + } + ], + "bounds": [ + "Default rendered state only; data can still be refreshing", + "Synthetic lab timing over SSH, no CPU/network throttling; not field Core Web Vitals", + "Automated WCAG-tagged checks, not manual screen-reader certification", + "Results retain phase provenance; unchanged pages are not claimed to have been rerun on261", + "Performance recorded while a controlled REST soak and normal collectors could run" + ], + "completed": true, + "passed": true, + "phases": [ + { + "file": "ui261-baseline.json", + "cases": 48, + "violating": 4, + "frontend": "ux-accessibility260-final" + }, + { + "file": "ui261-changed-final.json", + "cases": 24, + "violating": 0, + "frontend": "ux-accessibility261", + "changedPages": [ + "/recursive-routes", + "/route-optimizer", + "/bgp", + "/gre", + "/vxlan", + "/ospf" + ] + } + ], + "coverage": { + "uniqueStates": 64, + "uniqueRoutes": 16, + "unionWith260UniqueStates": 120, + "unionWith260Routes": 30 + } +} diff --git a/docs/ux-ui/acceptance/ui261-live-ecmp.json b/docs/ux-ui/acceptance/ui261-live-ecmp.json new file mode 100644 index 00000000..8454ec09 --- /dev/null +++ b/docs/ux-ui/acceptance/ui261-live-ecmp.json @@ -0,0 +1,17 @@ +{ + "date": "2026-10-15", + "block": "12.5.261", + "writes": [], + "states": [ + { + "enabled": false, + "disabled": true, + "violations": [] + }, + { + "enabled": true, + "disabled": false, + "violations": [] + } + ] +} diff --git a/docs/ux-ui/acceptance/ui261-summary.json b/docs/ux-ui/acceptance/ui261-summary.json new file mode 100644 index 00000000..3732daf4 --- /dev/null +++ b/docs/ux-ui/acceptance/ui261-summary.json @@ -0,0 +1,58 @@ +{ + "date": "2026-10-15", + "block": "12.5.261", + "runtime": { + "backend": "ux-certificates258", + "frontend": "ux-accessibility261" + }, + "baseline": { + "cases": 48, + "violatingCases": 4, + "blockedWrites": 0, + "readQueries": 4 + }, + "final": { + "uniqueStates": 64, + "newRoutes": 12, + "unionWith260UniqueStates": 120, + "unionWith260Routes": 30, + "axeViolations": 0, + "jsErrors": 0, + "apiErrors": 0, + "overflow": 0, + "clippedKpiLabels": 0 + }, + "local": { + "initial": { + "passed": 38, + "failed": 2 + }, + "ecmpRetest": { + "passed": 2, + "failed": 0 + }, + "uniqueTestsThatPassed": 40, + "apiMutationsFromEcmpDraft": 0, + "typecheck": "passed", + "scopedLint": "passed", + "productionBuild": "passed", + "sourceMatched": 528 + }, + "liveEcmp": { + "date": "2026-10-15", + "block": "12.5.261", + "writes": [], + "states": [ + { + "enabled": false, + "disabled": true, + "violations": [] + }, + { + "enabled": true, + "disabled": false, + "violations": [] + } + ] + } +} diff --git a/docs/ux-ui/screens/ui261-bgp320.png b/docs/ux-ui/screens/ui261-bgp320.png new file mode 100644 index 00000000..c0ed5a35 Binary files /dev/null and b/docs/ux-ui/screens/ui261-bgp320.png differ diff --git a/tests/e2e/network-kpi-readability.spec.ts b/tests/e2e/network-kpi-readability.spec.ts new file mode 100644 index 00000000..11d647e8 --- /dev/null +++ b/tests/e2e/network-kpi-readability.spec.ts @@ -0,0 +1,56 @@ +import { test, expect } from "@playwright/test" +import axe from "axe-core" + +for (const path of ["/bgp", "/gre", "/vxlan", "/ospf"]) for (const width of [320, 390]) test(`Network KPI labels remain readable ${path}/${width}`, async ({ page }) => { + await page.setViewportSize({ width, height: 1000 }) + await page.route("**/health", r => r.fulfill({ json: { ok: true } })) + await page.route("**/api/**", r => { + const endpoint = new URL(r.request().url()).pathname + return r.fulfill({ json: endpoint === "/api/auth/config" ? { required: false } + : endpoint === "/api/servers" ? [{ id: 1, name: "Роутер", host: "192.0.2.1", enabled: true, country: "RU", status: null }] + : endpoint === "/api/bgp/catalog" ? { sessions: [], failures: [] } + : endpoint === "/api/ospf/catalog" ? { interfaces: [], neighbors: [], instances: [], bfdSessions: [], routes: [], failures: [] } + : endpoint === "/api/gre/tunnels" ? { tunnels: [], failures: [] } + : endpoint === "/api/vxlan" ? { tunnels: [], failures: [] } : {} }) + }) + await page.goto(path) + const title = path === "/bgp" ? "Сводка BGP" : path === "/gre" ? "Сводка GRE" : path === "/vxlan" ? "Сводка VXLAN" : "Сводка OSPF" + const summary = page.getByLabel(title, { exact: true }) + await expect(summary).toBeVisible() + const labels = summary.locator('.text-muted-foreground.truncate') + await expect.poll(() => labels.count()).toBeGreaterThan(0) + // Compare actual rendered text bounds, rather than testing particular grid classes. + await expect.poll(() => labels.evaluateAll(elements => elements.every(el => el.scrollWidth <= el.clientWidth + 1))).toBe(true) + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) +}) + +for (const theme of ["light", "dark"]) test(`ECMP draft: disabled instructions remain readable and enable is local/${theme}`, async ({ page }) => { + await page.addInitScript(value => localStorage.setItem("rl-theme", value), theme) + 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" && !path.endsWith("/preview")) writes++ + return r.fulfill({ json: path === "/api/auth/config" ? { required: false } + : path === "/api/servers" ? [{ id: 1, name: "Роутер", host: "192.0.2.1", type: "home-router", country: "RU", enabled: true, status: null }] + : path === "/api/filters/rules" ? { rulesets: [] } : path === "/api/uptime/speed-probes" ? { probes: [] } + : path === "/api/ospf/catalog" ? { interfaces: [], instances: [], neighbors: [], bfdSessions: [], routes: [], failures: [] } + : path.endsWith("/preview") ? { serverId: 1, serverName: "Роутер", pingWeight: 60, interfacesTotal: 0, changedCount: 0, unchangedCount: 0, interfaces: [], changes: [] } : {} }) + }) + await page.goto("/route-optimizer") + const toggle = page.getByRole("switch", { name: "Черновик ECMP", exact: true }) + const group = page.getByRole("group", { name: "Параметры черновика ECMP", exact: true }) + await expect(toggle).toHaveAttribute("aria-checked", "false") + const range = group.getByRole("slider", { name: "Максимальное число путей ECMP", exact: true }) + await expect(range).toBeDisabled() + await group.scrollIntoViewIfNeeded() + await page.addScriptTag({ content: axe.source }) + for (const enabled of [false, true]) { + if (enabled) { await toggle.click(); await expect(range).toBeEnabled(); await range.focus(); await range.press("ArrowRight"); await expect(range).toHaveValue("5") } + const violations = await group.evaluate(async element => (await (window as unknown as { axe: typeof axe }).axe.run(element, { + runOnly: { type: "tag", values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"] }, + })).violations.map(v => ({ id: v.id, targets: v.nodes.map(n => n.target) }))) + expect(violations).toEqual([]) + } + expect(writes).toBe(0) +})