From 9680a6422ba951a1737207663acbd6d562710b62 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Wed, 7 Oct 2026 17:58:11 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=BE=D1=82=D0=BB=D0=B8=D1=87=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=B5=D0=B8=D0=B7=D0=B2=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20RTT=20=D0=BE=D1=82=20=D0=BE=D1=82=D1=81?= =?UTF-8?q?=D1=83=D1=82=D1=81=D1=82=D0=B2=D0=B8=D1=8F=20=D0=BE=D1=82=D0=B2?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B2=20Ping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(main)/uptime/page.tsx | 6 ++-- .../uptime-speed-history-data-grid.tsx | 5 ++-- docs/ux-ui-plan.md | 4 +-- docs/ux-ui-progress.md | 12 ++++++-- docs/ux-ui-stage-12.md | 10 ++++++- tests/e2e/uptime-speed-data.spec.ts | 28 +++++++++++++++++++ 6 files changed, 55 insertions(+), 10 deletions(-) diff --git a/app/(main)/uptime/page.tsx b/app/(main)/uptime/page.tsx index 33f96d5e..5ee4357e 100644 --- a/app/(main)/uptime/page.tsx +++ b/app/(main)/uptime/page.tsx @@ -2279,7 +2279,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId )} style={{ width: viewAfterBtPing.rttMs == null - ? "100%" + ? "0%" : `${Math.max(Math.min((viewAfterBtPing.rttMs / 120) * 100, 100), 4)}%`, }} /> @@ -2290,7 +2290,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId ? "text-amber-600 dark:text-amber-400" : "text-violet-600 dark:text-violet-400", )}> - {viewAfterBtPing.rttMs == null ? "timeout" : `${viewAfterBtPing.rttMs} мс`} + {viewAfterBtPing.rttMs == null ? (viewAfterBtPing.lossPct === 100 ? "Нет ответов" : "RTT неизвестен") : `${viewAfterBtPing.rttMs} мс`} ) @@ -2581,7 +2581,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId ) : linkedSp.lastPingAt ? ( - ping timeout + {linkedSp.lastPingLossPct === 100 ? "ping: нет ответов" : "ping: RTT неизвестен"} {linkedSp.lastPingLossPct != null && · {linkedSp.lastPingLossPct}%} ) : null} diff --git a/components/data-grids/uptime-speed-history-data-grid.tsx b/components/data-grids/uptime-speed-history-data-grid.tsx index 9bc8c986..9122e073 100644 --- a/components/data-grids/uptime-speed-history-data-grid.tsx +++ b/components/data-grids/uptime-speed-history-data-grid.tsx @@ -191,7 +191,8 @@ function UptimeSpeedHistoryDataGrid({ runs, servers }: UptimeSpeedHistoryDataGri cell: ({ row }) => { const run = row.original if (run.status !== "done") return — - if (run.afterBtPing?.error) { + if (!run.afterBtPing) return Нет данных + if (run.afterBtPing.error) { return ( ошибка @@ -210,7 +211,7 @@ function UptimeSpeedHistoryDataGrid({ runs, servers }: UptimeSpeedHistoryDataGri } return ( - timeout + {run.afterBtPing.lossPct === 100 ? "Нет ответов" : "RTT неизвестен"} {run.afterBtPing?.lossPct != null && · {run.afterBtPing.lossPct}%} ) diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index c1eb774f..a58c5f3c 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-07: 12.3.82 завершён: server createdAt в POST receipt, отсутствие Ping не получает дату и старый результат; 76browser,4pure,HTTP/RBAC,types/lint и builds прошли. Следующий12.3.83: неизвестный RTT не считать timeout. Общие main1176/context221 относятся к прежним HEAD. Внешняя12.5 не выполнена. +Актуальное продолжение 2026-10-07: 12.3.83 завершён: missing/unknown/loss100/zero/error Ping разделены;81browser,types/lint и frontend build прошли. Следующий12.4.10: общая main регрессия на новом HEAD после speed API/UI delta, затем12.4.11 context. Внешняя12.5 не выполнена. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-07. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-07 -Этапы0–11 завершены в описанных локальных границах. Этап12 продолжается; блоки до12.3.82 отражены в журнале. Общие main12.4.8 на579e816:1176/1176 и context12.4.9 наa3fcba0:221/221 passed. Последующие изменения speed-test проверены профильными тестами; эти общие прогоны не относятся к новому HEAD. Внешняя12.5 и реальные интеграции не приняты. Точные результаты и ограничения: [ux-ui-stage-12.md](ux-ui-stage-12.md). +Этапы0–11 завершены в описанных локальных границах. Этап12 продолжается; блоки до12.3.83 отражены в журнале. Общие main12.4.8 на579e816:1176/1176 и context12.4.9 наa3fcba0:221/221 passed. Последующие изменения speed-test проверены профильными тестами; эти общие прогоны не относятся к новому HEAD. Внешняя12.5 и реальные интеграции не приняты. Точные результаты и ограничения: [ux-ui-stage-12.md](ux-ui-stage-12.md). Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 866afaf3..90ca34fb 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-07: 12.3.82 завершён: server createdAt в POST receipt, отсутствие Ping не получает дату и старый результат; 76browser,4pure,HTTP/RBAC,types/lint и builds прошли. Следующий12.3.83: неизвестный RTT не считать timeout. Общие main1176/context221 относятся к прежним HEAD. Внешняя12.5 не выполнена. +Актуальное продолжение 2026-10-07: 12.3.83 завершён: missing/unknown/loss100/zero/error Ping разделены;81browser,types/lint и frontend build прошли. Следующий12.4.10: общая main регрессия на новом HEAD после speed API/UI delta, затем12.4.11 context. Внешняя12.5 не выполнена. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -32,7 +32,15 @@ | 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.82 завершены. Общая main1176/1176 на579e816 и context221/221 наa3fcba0 прошли; последующий функциональный delta проверен73browser/8context. Следующий12.3.83; внешняя12.5 не выполнена. | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | В работе. Локальные блоки до12.3.83 завершены. Общая main1176/1176 на579e816 и context221/221 наa3fcba0 прошли; последующий функциональный delta проверен73browser/8context. Следующий12.4.10; внешняя12.5 не выполнена. | + +## 12.3.83 — неизвестный RTT и отсутствие ответов Ping (2026-10-07) + +История показывает «Нет данных» без afterBtPing, «RTT неизвестен» при null RTT и неопределённых/частичных потерях, «Нет ответов» при подтверждённых100% потерь. Ошибка и измеренный0 остаются отдельными состояниями. Карточка speed-пробы и связанная Ping-проба используют те же смыслы. Для null RTT шкала не заполнена как измерение. ReUI Data Grid/Frame и сетевые команды сохранены. + +81/81 browser uptime/large history passed, включая5 новых состояний missing/unknown/loss100/zero/error в истории и карточке, отсутствие старого99 и reflow320px. Targeted ESLint0errors/0warnings, non-incremental TypeScript и contracts/frontend production build прошли. Для простой подписи не добавлены повторяющие реализацию unit tests. Исторические3 PNG восстановлены. Backend/native parsing не изменены; реальные native loss/status требуют12.5. + +Следующий12.4.10: общая main матрица на новом HEAD после блоков79–83; затем12.4.11context. Предыдущие main1176(579e816)/context221(a3fcba0) сохраняются как отдельные результаты, не доказательство нового HEAD. Внешняя12.5 остаётся открытой. ## 12.3.82 — серверное время результата и отсутствующий Ping (2026-10-07) diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index ae2b71a1..ea123eb2 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-07: 12.3.82 завершён: server createdAt в POST receipt, отсутствие Ping не получает дату и старый результат; 76browser,4pure,HTTP/RBAC,types/lint и builds прошли. Следующий12.3.83: неизвестный RTT не считать timeout. Общие main1176/context221 относятся к прежним HEAD. Внешняя12.5 не выполнена. +Актуальное продолжение 2026-10-07: 12.3.83 завершён: missing/unknown/loss100/zero/error Ping разделены;81browser,types/lint и frontend build прошли. Следующий12.4.10: общая main регрессия на новом HEAD после speed API/UI delta, затем12.4.11 context. Внешняя12.5 не выполнена. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -928,3 +928,11 @@ Backend возвращает createdAt из того же pingNow, которы Без afterBtPing новая операция не получает lastPingAt; выбор нового done run не подставляет прежний Ping snapshot. Явный0 сохранён. 4 pure receipt проверки, HTTP/RBAC с server timestamp passthrough, types/lint и contracts/backend/frontend builds прошли. Финальный76/76 browser прошёл. Первый прогон остановлен после ошибки нового селектора: в selected-probe scope кнопка называется «Обновить данные»; исправлены только новые тесты, отдельно2/2 и затем полный76/76 passed. Проверены дата из сервера в таблице, старый99 не наложен, отсутствующий Ping и новый0. Исторические3 PNG восстановлены. Проверка согласованности журналов до этого блока:104 одинаковых numbered records в обоих документах, все с датами, без пропусков/дублей. Следующий12.3.83: таблица и карточки пока выводят timeout при любом null RTT; неизвестный/отсутствующий результат должен быть отделён от подтверждённого отсутствия ответов. Внешняя12.5 открыта; общий main/context не объявлен проверкой нового HEAD. + +## 12.3.83 — неизвестный RTT и отсутствие ответов Ping (2026-10-07) + +История показывает «Нет данных» без afterBtPing, «RTT неизвестен» при null RTT и неопределённых/частичных потерях, «Нет ответов» при подтверждённых100% потерь. Ошибка и измеренный0 остаются отдельными состояниями. Карточка speed-пробы и связанная Ping-проба используют те же смыслы. Для null RTT шкала не заполнена как измерение. ReUI Data Grid/Frame и сетевые команды сохранены. + +81/81 browser uptime/large history passed, включая5 новых состояний missing/unknown/loss100/zero/error в истории и карточке, отсутствие старого99 и reflow320px. Targeted ESLint0errors/0warnings, non-incremental TypeScript и contracts/frontend production build прошли. Для простой подписи не добавлены повторяющие реализацию unit tests. Исторические3 PNG восстановлены. Backend/native parsing не изменены; реальные native loss/status требуют12.5. + +Следующий12.4.10: общая main матрица на новом HEAD после блоков79–83; затем12.4.11context. Предыдущие main1176(579e816)/context221(a3fcba0) сохраняются как отдельные результаты, не доказательство нового HEAD. Внешняя12.5 остаётся открытой. diff --git a/tests/e2e/uptime-speed-data.spec.ts b/tests/e2e/uptime-speed-data.spec.ts index 560e6e47..354df43e 100644 --- a/tests/e2e/uptime-speed-data.spec.ts +++ b/tests/e2e/uptime-speed-data.spec.ts @@ -54,3 +54,31 @@ test("Speed-пробы: malformed каталог, cache/freshness и блоки await page.addStyleTag({content:"nextjs-portal{display:none!important}"});await page.screenshot({path:"docs/ux-ui/screens/speed-probes-error-320.png",fullPage:true,animations:"disabled"}) raw={probes:[probe]};await refresh.click();await expect(alert).toHaveCount(0);await expect(toggle).toBeEnabled();expect(writes).toEqual([]) }) + +const pingCases = [ + { name: "missing", value: undefined, label: "Нет данных" }, + { name: "unknown", value: { rttMs: null, lossPct: null, error: null }, label: "RTT неизвестен" }, + { name: "loss100", value: { rttMs: null, lossPct: 100, error: null }, label: "Нет ответов" }, + { name: "zero", value: { rttMs: 0, lossPct: 0, error: null }, label: "0 мс" }, + { name: "error", value: { rttMs: null, lossPct: null, error: "Ошибка Ping" }, label: "ошибка" }, +] +for (const sample of pingCases) test("Ping после BT: данные, неизвестный RTT, отсутствие ответов и ошибка/" + sample.name, async ({ page }) => { + await page.route("**/health", route => route.fulfill({ json: { ok: true } })) + await page.route("**/api/**", route => { + const path = new URL(route.request().url()).pathname + return route.fulfill({ json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [server] : path === "/api/uptime/overview" ? { probes: [], resources: [] } : path === "/api/uptime/speed-probes" ? { probes: [{ id: "probe-1", srcServerId: "1", dstServerId: "2", srcInterface: "ether1", dstInterface: "ether1", protocol: "tcp", direction: "both", durationSec: "10", enabled: true, lastStatus: "done", lastRunAt: "2026-10-03T00:00:00Z", lastTxAvgMbps: 999, lastRxAvgMbps: 0, lastError: null, lastPingRttMs: 99, lastPingLossPct: 0, lastPingAt: "2026-10-03T00:00:00Z", lastPingError: null }] } : path === "/api/uptime/speed-test/runs" ? { runs: [{ ...run, afterBtPing: sample.value }] } : {} }) + }) + await page.goto("/uptime?tab=speed") + await page.getByRole("button", { name: "Пауза", exact: true }).click() + const history = page.locator('tr[data-row-id="history-1"]') + await expect(history).toContainText(sample.label) + const probe = page.getByRole("button", { name: "Запустить", exact: true }).locator("xpath=../../..") + await expect(probe).not.toContainText("99 мс") + if (sample.name === "missing") await expect(probe.getByText("Ping", { exact: true })).toHaveCount(0) + else await expect(probe).toContainText(sample.name === "error" ? "Ошибка Ping" : sample.label) + await expect(history).not.toContainText("timeout") + await expect(probe).not.toContainText("timeout") + if (sample.name === "loss100") await expect(history).toContainText("100%") + await page.setViewportSize({ width: 320, height: 1000 }) + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) +})