fix(ui): показывать сведения о рукопожатии без ложного статуса
This commit is contained in:
1 parent
837298a171
commit
c6702efcc4
9 files changed
+53
-16
No files matched your search
@@ -384,8 +384,8 @@ function WireGuardPageContent({ selectedServerId, selectedInterfaceId, allInterf
|
||||
}, [scopedIfaces, search])
|
||||
|
||||
const totalPeers = scopedIfaces.reduce((s, i) => s + i.peers.length, 0)
|
||||
const onlinePeers = scopedIfaces.reduce(
|
||||
(s, i) => s + i.peers.filter((p) => !!p.latestHandshake).length,
|
||||
const peersWithHandshakeData = scopedIfaces.reduce(
|
||||
(s, i) => s + i.peers.filter((p) => !!p.latestHandshake?.trim()).length,
|
||||
0,
|
||||
)
|
||||
const upIfaces = scopedIfaces.filter((i) => i.status === "up").length
|
||||
@@ -754,9 +754,10 @@ function WireGuardPageContent({ selectedServerId, selectedInterfaceId, allInterf
|
||||
iconClassName: "text-info",
|
||||
},
|
||||
{
|
||||
id: "online",
|
||||
label: "Пиров онлайн",
|
||||
value: `${onlinePeers}/${totalPeers}`,
|
||||
id: "handshake-data",
|
||||
label: "Данные рукопожатия",
|
||||
value: `${peersWithHandshakeData}/${totalPeers}`,
|
||||
hint: <span className="block text-xs text-muted-foreground">Доступность пиров не проверена</span>,
|
||||
icon: <KeyRoundIcon className="size-4" />,
|
||||
iconClassName: "text-primary",
|
||||
},
|
||||
|
||||
@@ -86,7 +86,6 @@ function WireguardDataGrid({
|
||||
cell: ({ row }) => {
|
||||
const iface = row.original
|
||||
const expanded = row.getIsExpanded()
|
||||
const onlinePeers = iface.peers.filter((p) => !!p.latestHandshake).length
|
||||
return (
|
||||
<div className="flex items-start gap-2 min-w-0">
|
||||
<Button type="button" variant="ghost" size="icon" className="size-11 shrink-0" aria-label={"Пиры: " + iface.name} aria-expanded={expanded} onClick={event => { event.stopPropagation(); row.toggleExpanded() }}>
|
||||
@@ -109,7 +108,7 @@ function WireguardDataGrid({
|
||||
</div>
|
||||
) : null}
|
||||
<p className="sr-only">
|
||||
{onlinePeers}/{iface.peers.length} пиров
|
||||
{iface.peers.length} пиров
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -164,11 +163,9 @@ function WireguardDataGrid({
|
||||
enableSorting: false,
|
||||
cell: ({ row }) => {
|
||||
const iface = row.original
|
||||
const onlinePeers = iface.peers.filter((p) => !!p.latestHandshake).length
|
||||
return (
|
||||
<span className="font-mono text-sm text-center block">
|
||||
<span className="text-success">{onlinePeers}</span>
|
||||
<span className="text-muted-foreground">/{iface.peers.length}</span>
|
||||
{iface.peers.length}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -82,10 +82,10 @@ function WireGuardPeersDetail({
|
||||
<span
|
||||
className={cn(
|
||||
"font-mono text-[11px] whitespace-nowrap",
|
||||
peer.latestHandshake ? "text-success" : "text-muted-foreground",
|
||||
"text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
<span className="sr-only">Последнее рукопожатие: </span>{peer.latestHandshake ?? "нет рукопожатия"}
|
||||
<span className="sr-only">Последнее рукопожатие: </span><span>{peer.latestHandshake?.trim() || "Нет данных"}</span>
|
||||
</span>
|
||||
<div className="flex items-center gap-2 text-muted-foreground whitespace-nowrap">
|
||||
<span aria-label="RX" className="flex items-center gap-0.5">
|
||||
@@ -97,7 +97,7 @@ function WireGuardPeersDetail({
|
||||
{fmtBytes(peer.transferTx)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="min-w-0 break-all font-mono text-muted-foreground/60 text-[11px]"><span className="sr-only">Endpoint: </span>{peer.endpoint ?? "—"}</span>
|
||||
<span className="min-w-0 break-all font-mono text-muted-foreground/60 text-[11px]"><span>Endpoint: </span>{peer.endpoint ?? "—"}</span>
|
||||
<div className="flex items-center gap-1 justify-end">
|
||||
{onExportPeer && (
|
||||
<Button
|
||||
|
||||
@@ -141,10 +141,10 @@ function WireguardPeersGrid({
|
||||
<span
|
||||
className={cn(
|
||||
"whitespace-nowrap font-mono text-[11px]",
|
||||
row.original.latestHandshake ? "text-success" : "text-muted-foreground",
|
||||
"text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{row.original.latestHandshake ?? "нет рукопожатия"}
|
||||
{row.original.latestHandshake?.trim() || "Нет данных"}
|
||||
</span>
|
||||
),
|
||||
meta: {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-04
|
||||
|
||||
Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. 12.1 принят локально: доступность оболочки/клавиатура/health в описанных сценариях. 12.2.1 принят локально: strict BGP catalog/partial/nullable counters. 12.2.2 принят локально: strict traffic DTO и агрегация без выдуманных точек. 12.2.3 принят локально: observations для server traffic от backend до dashboard. 12.2.4 принят локально: strict servers/probes и unknown server status. 12.2.5 принят локально: реальные ping samples/unknown/ось RTT/Recharts. 12.2.6 принят локально: strict GRE/WireGuard/VXLAN и device failures. 12.2.7 принят локально: strict Internet path snapshot/fallback. 12.2.8 принят локально: подтверждение полного backend сбора. 12.2.9 принят локально: метрики участков и наблюдаемый WAN без эвристической подмены. 12.3.1 принят локально:1000 серверов/штатная пагинация. 12.3.2 принят локально: пагинация CompactDataGrid/1000 строк статистики. 12.3.3 принят локально: порционный DOM очереди проблем. 12.3.4 принят локально: большой BGP каталог/страница при обновлении. Production build и123 профильных browser приняты локально на3978976. 12.2.10 принят локально: обязательные RouterOS поля. 12.3.5 принят локально: страница CompactDataGrid сохраняется при опросе,89 browser и повторный production build прошли. 12.3.6 сохранён: baseline1000 speed probes (ограничение DOM пока не выполнено). 12.3.7 принят локально:50 строк speed-проб/сохранение страницы/глобальная сортировка/1000→1; каталог1001 устройства остаётся в DOM. 12.3.8 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. 12.3.9 принят локально:порционное раскрытие1000 предупреждений ресурсов/клавиатура/axe; исходная ошибка ESLint speedDraft подтверждена. 12.3.10 принят локально:недоступные интерфейсы очищаются в обработчиках,54 browser/полный ESLint/production build прошли. 12.3.11 принят локально:ServerTileRail50 устройств/URL/поиск/клавиатура/две площадки/mobile Sheet/axe обе темы;47 browser и production build прошли. 12.3.12 принят локально:BGP ручная страница при выбранной URL сессии/refresh/reload,16 browser/build прошли. 12.4.1 записан:main1091 сценарий/1088 passed/3 устаревших fixtures; оба исправленных файла6 passed. 12.4.2 принят локально:context205/24 файла и unit28 прошли. 12.3.13 принят локально:wide pivot51×16/ScrollArea/axe/24+2 browser/builds. 12.3.14 принят локально:history200/50 DOM/54+1 browser/build. 12.3.15 принят локально:live расписание1000/page20 error cache/15 browser. 12.3.16 принят локально:certificates1000/50 DOM/refresh деталей/19+3 browser/build. 12.3.17 принят локально:pinning идентификатора/видимость значений/29 browser/build. 12.3.18 принят локально:users1000/поиск всего списка/детали и ошибка refresh/32 browser/build. 12.3.19 принят локально:backups1000/все мобильные действия/возврат focus/39+4 browser/build. 12.3.20 принят локально:независимые speed GET/cache/freshness/58+4 browser/build. 12.3.21 принят локально:strict history DTO/null rates от DB до UI/60+5 browser/unit4/builds. 12.4.3 принят локально:users/backups delta context36 на a558412. 12.3.22 принят локально:shared speed-probes DTO/context8/60+6+47 browser/unit5/builds. 12.3.23 принят локально:strict write DTO/atomic replacement/confirmed scheduler warning/65 browser/HTTP DI JWT/builds. 12.3.24 принят локально:OSPF routes1000/50 DOM/page20/cache/320px/22+1 browser/build. 12.3.25 принLine truncated
|
||||
Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. 12.1 принят локально: доступность оболочки/клавиатура/health в описанных сценариях. 12.2.1 принят локально: strict BGP catalog/partial/nullable counters. 12.2.2 принят локально: strict traffic DTO и агрегация без выдуманных точек. 12.2.3 принят локально: observations для server traffic от backend до dashboard. 12.2.4 принят локально: strict servers/probes и unknown server status. 12.2.5 принят локально: реальные ping samples/unknown/ось RTT/Recharts. 12.2.6 принят локально: strict GRE/WireGuard/VXLAN и device failures. 12.2.7 принят локально: strict Internet path snapshot/fallback. 12.2.8 принят локально: подтверждение полного backend сбора. 12.2.9 принят локально: метрики участков и наблюдаемый WAN без эвристической подмены. 12.3.1 принят локально:1000 серверов/штатная пагинация. 12.3.2 принят локально: пагинация CompactDataGrid/1000 строк статистики. 12.3.3 принят локально: порционный DOM очереди проблем. 12.3.4 принят локально: большой BGP каталог/страница при обновлении. Production build и123 профильных browser приняты локально на3978976. 12.2.10 принят локально: обязательные RouterOS поля. 12.3.5 принят локально: страница CompactDataGrid сохраняется при опросе,89 browser и повторный production build прошли. 12.3.6 сохранён: baseline1000 speed probes (ограничение DOM пока не выполнено). 12.3.7 принят локально:50 строк speed-проб/сохранение страницы/глобальная сортировка/1000→1; каталог1001 устройства остаётся в DOM. 12.3.8 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. 12.3.9 принят локально:порционное раскрытие1000 предупреждений ресурсов/клавиатура/axe; исходная ошибка ESLint speedDraft подтверждена. 12.3.10 принят локально:недоступные интерфейсы очищаются в обработчиках,54 browser/полный ESLint/production build прошли. 12.3.11 принят локально:ServerTileRail50 устройств/URL/поиск/клавиатура/две площадки/mobile Sheet/axe обе темы;47 browser и production build прошли. 12.3.12 принят локально:BGP ручная страница при выбранной URL сессии/refresh/reload,16 browser/build прошли. 12.4.1 записан:main1091 сценарий/1088 passed/3 устаревших fixtures; оба исправленных файла6 passed. 12.4.2 принят локально:context205/24 файла и unit28 прошли. 12.3.13 принят локально:wide pivot51×16/ScrollArea/axe/24+2 browser/builds. 12.3.14 принят локально:history200/50 DOM/54+1 browser/build. 12.3.15 принят локально:live расписание1000/page20 error cache/15 browser. 12.3.16 принят локально:certificates1000/50 DOM/refresh деталей/19+3 browser/build. 12.3.17 принят локально:pinning идентификатора/видимость значений/29 browser/build. 12.3.18 принят локально:users1000/поиск всего списка/детали и ошибка refresh/32 browser/build. 12.3.19 принят локально:backups1000/все мобильные действия/возврат focus/39+4 browser/build. 12.3.20 принят локально:независимые speed GET/cache/freshness/58+4 browser/build. 12.3.21 принят локально:strict history DTO/null rates от DB до UI/60+5 browser/unit4/builds. 12.4.3 принят локально:users/backups delta context36 на a558412. 12.3.22 принят локально:shared speed-probes DTO/context8/60+6+47 browser/unit5/builds. 12.3.23 принят локально:strict write DTO/atomic replacement/confirmed scheduler warning/65 browser/HTTP DI JWT/builds. 12.3.24 принят локально:OSPF routes1000/50 DOM/page20/cache/320px/22+1 browser/build. 12.3.25 принLine truncated
|
||||
|
||||
Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md).
|
||||
|
||||
|
||||
@@ -36,6 +36,14 @@
|
||||
|
||||
|
||||
|
||||
## 12.3.31 — рукопожатие не подменяет доступность WireGuard (2026-10-04)
|
||||
|
||||
Убрана оценка «пиров онлайн» по presence старого last-handshake. KPI «Данные рукопожатия» считает непустые сведения в ответе и явно сообщает, что доступность пиров не проверена. Колонка «Пиры» показывает число записей. Старое время рукопожатия отображается без зелёного вывода о доступности; отсутствующее/пустое значение — «Нет данных». В мобильных деталях видна подпись Endpoint.
|
||||
|
||||
Основание: официальный [RouterOS WireGuard](https://help.mikrotik.com/docs/spaces/ROS/pages/69664792/WireGuard), last-handshake означает время после последнего успешного рукопожатия. Порогов актуальности/новых правил сетевых операций не введено. Проверены missing/empty/1h/0s в обеих композициях и KPI2/4. Семь прежних/table/large browser прошли, новый handshake сценарий после уточнения adaptive KPI селектора1/1. TypeScript без incremental/ESLint и production frontend build прошли. [Снимок320px](ux-ui/screens/wireguard-handshake-320.png) просмотрен.
|
||||
|
||||
Следующий блок12.3.32: WireGuard URL search/tab/status — reload/история/сохранение server/interface/неверные параметры без расширения среза. Первоначально неизвестные общие KPI WireGuard и freshness/source switching требуют отдельного аудита; этот блок исправляет именно смысл handshake.17 остальных specialized grids/общая регрессия после delta/внешняя12.5 остаются. Коммит локальный без push.
|
||||
|
||||
## 12.3.30 — порционное раскрытие пиров WireGuard (2026-10-04)
|
||||
|
||||
Раскрытие интерфейса ограничено50 пирами на страницу, сохраняет страницу при refresh и ограничивает её при сокращении списка до отображения. Имена и точные IDs действий сохранены. На320px карточки имеют две колонки внутри sticky области шириной экрана; кнопки44px, пагинация доступна с клавиатуры и показывает диапазон/общий счётчик. На ПК сохраняется компактная строка полей.
|
||||
|
||||
@@ -425,3 +425,12 @@ Peer grid теперь использует client pagination50, clamp и сох
|
||||
|
||||
Следующий блок12.3.31: убрать вывод «онлайн» из наличия старого handshake, показать отсутствие данных отдельно. Официальный RouterOS last-handshake — время после последнего успешного рукопожатия: https://help.mikrotik.com/docs/spaces/ROS/pages/69664792/WireGuard. Затем WireGuard URL filters/context и оставшиеся network grids.17 manualPagination:true grids/общая регрессия после delta/внешняя12.5 остаются. Коммит локальный без push.
|
||||
|
||||
|
||||
## 12.3.31 — рукопожатие не подменяет доступность WireGuard (2026-10-04)
|
||||
|
||||
Убрана оценка «пиров онлайн» по presence старого last-handshake. KPI «Данные рукопожатия» считает непустые сведения в ответе и явно сообщает, что доступность пиров не проверена. Колонка «Пиры» показывает число записей. Старое время рукопожатия отображается без зелёного вывода о доступности; отсутствующее/пустое значение — «Нет данных». В мобильных деталях видна подпись Endpoint.
|
||||
|
||||
Основание: официальный [RouterOS WireGuard](https://help.mikrotik.com/docs/spaces/ROS/pages/69664792/WireGuard), last-handshake означает время после последнего успешного рукопожатия. Порогов актуальности/новых правил сетевых операций не введено. Проверены missing/empty/1h/0s в обеих композициях и KPI2/4. Семь прежних/table/large browser прошли, новый handshake сценарий после уточнения adaptive KPI селектора1/1. TypeScript без incremental/ESLint и production frontend build прошли. [Снимок320px](ux-ui/screens/wireguard-handshake-320.png) просмотрен.
|
||||
|
||||
Следующий блок12.3.32: WireGuard URL search/tab/status — reload/история/сохранение server/interface/неверные параметры без расширения среза. Первоначально неизвестные общие KPI WireGuard и freshness/source switching требуют отдельного аудита; этот блок исправляет именно смысл handshake.17 остальных specialized grids/общая регрессия после delta/внешняя12.5 остаются. Коммит локальный без push.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
@@ -65,3 +65,25 @@ for (const view of ["details", "peers"] as const) test("WireGuard traffic: obser
|
||||
if (view === "details") await row.click()
|
||||
}
|
||||
})
|
||||
|
||||
test("WireGuard handshake: old observation never proves online, missing remains unknown", async ({ page }, info) => {
|
||||
await setup(page)
|
||||
const interfaces = fixture.interfaces.slice(0, 1).map(row => ({ ...row, peers: Array.from({length:4}, (_, i) => ({ ...row.peers[0], id: "h"+i, rosId: "*H"+i, name: "Handshake "+i, latestHandshake: [undefined, "", "1h", "0s"][i] })) }))
|
||||
await page.route("**/api/wireguard", route => route.fulfill({json:wgListResponseSchema.parse({interfaces})}))
|
||||
await page.reload()
|
||||
await expect(page.getByText("Пиров онлайн",{exact:true})).toHaveCount(0)
|
||||
const label=page.getByText("Данные рукопожатия",{exact:true})
|
||||
await expect(label.locator("..").locator("..")).toContainText("2/4")
|
||||
await expect(page.getByText("Доступность пиров не проверена",{exact:true}).filter({visible:true})).toBeVisible()
|
||||
await page.getByRole("button",{name:"Пиры: wg-test-1",exact:true}).click()
|
||||
const detail=page.getByRole("region",{name:"Пиры: wg-test-1",exact:true})
|
||||
await expect(detail.getByText("Нет данных",{exact:true})).toHaveCount(2)
|
||||
await expect(detail.getByText("1h",{exact:true})).toBeVisible()
|
||||
await page.getByRole("tab",{name:/Пиры/}).click()
|
||||
const rows=page.locator("tr[data-row-id]")
|
||||
await expect(rows).toHaveCount(4)
|
||||
await expect(rows.nth(0)).toContainText("Нет данных");await expect(rows.nth(1)).toContainText("Нет данных")
|
||||
await expect(rows.nth(2)).toContainText("1h");await expect(rows.nth(3)).toContainText("0s")
|
||||
await page.setViewportSize({width:320,height:1000});expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)).toBe(true)
|
||||
await page.addStyleTag({content:"nextjs-portal{display:none!important}"});await page.screenshot({path:info.outputPath("wireguard-handshake-320.png"),animations:"disabled"})
|
||||
})
|
||||
Reference in new issue
Block a user