From 88a8b5f02fd5ce545c0cf2ab472f58ce8fcdbbc2 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Mon, 28 Sep 2026 16:47:17 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B0=D1=82=D1=8C=20=D0=BE=D0=B4=D0=B8=D0=BD=D0=BE=D1=87?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=B0=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8?= =?UTF-8?q?=D0=BA=D0=B5=20=D1=82=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/reui-kit/traffic-rx-tx-chart.tsx | 9 +++++-- docs/ux-ui-plan.md | 4 +-- docs/ux-ui-progress.md | 9 ++++++- docs/ux-ui-stage-8.md | 2 ++ tests/e2e/traffic-details.spec.ts | 28 +++++++++++++++++++++ 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/components/reui-kit/traffic-rx-tx-chart.tsx b/components/reui-kit/traffic-rx-tx-chart.tsx index 65283329..2afad04c 100644 --- a/components/reui-kit/traffic-rx-tx-chart.tsx +++ b/components/reui-kit/traffic-rx-tx-chart.tsx @@ -85,6 +85,11 @@ export function TrafficRxTxChart({ const hasRx = data.some(point => point.rx !== null) const hasTx = data.some(point => point.tx !== null) const hasData = hasRx || hasTx + const isolatedDot = (direction: "rx" | "tx") => function IsolatedDot({ cx, cy, index }: { cx?: number; cy?: number; index?: number }) { + if (index == null || cx == null || cy == null || data[index]?.[direction] == null + || data[index - 1]?.[direction] != null || data[index + 1]?.[direction] != null) return + return + } const chart = !hasData ? (

Нет исторических измерений за выбранный период

) : ( @@ -119,14 +124,14 @@ export function TrafficRxTxChart({ type="monotone" stroke="var(--chart-rx)" strokeWidth={2} - dot={false} + dot={isolatedDot("rx")} />} {hasTx && } diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 1857816d..5257d0b4 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -88,8 +88,8 @@ flowchart LR Ближайший оставшийся объём: -1. Молчащий SSE и CRLF/heartbeat проверены в блоках 8.6–8.7. Далее — одиночная точка основного графика и ожидание первого sample. -2. Итоговая приёмка этапа 8: решение по архивным серверам/месяцам, проверка единичной точки графика, ReUI/accessibility checklist. Промежуточная матрица проверок сохранена в [этапе 8](ux-ui-stage-8.md). +1. Молчащий SSE и CRLF/heartbeat проверены в блоках 8.6–8.7. Одиночные точки графика исправлены в 8.8. Далее — ожидание первого sample. +2. Итоговая приёмка этапа 8: решение по архивным серверам/месяцам, ReUI/accessibility checklist. Промежуточная матрица проверок сохранена в [этапе 8](ux-ui-stage-8.md). 3. После фиксации результата этапа 8 — этап 9. ## Порядок продолжения и журналирования diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 4997a31a..2a763c8b 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -24,13 +24,20 @@ | 5 | Состояния данных, свежесть, частичные сбои, гонки polling | Завершён 2026-09-20 для дашборда; границы проверок ниже | | 6 | Навигация и дашборд | Завершён 2026-09-20 в границах локальной приёмки; ограничения ниже | | 7 | Серверы и мониторинг: детали, формы, URL-контекст, права | Завершён в границах локальной приёмки 2026-09-23; внешние ограничения ниже | -| 8 | Трафик и статистика | В работе: выполнены блоки 8.1–8.7; CRLF/heartbeat проверены, далее оставшийся аудит | +| 8 | Трафик и статистика | В работе: выполнены блоки 8.1–8.8; одиночные точки графика исправлены, далее оставшийся аудит | | 9 | VPN, Firewall и Filters | Не начат | | 10 | Маршрутизация, диагностика, карта и терминал | Не начат | | 11А | Пользователи, контейнеры, сертификаты и резервные копии | Не начат | | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат | +## Блок 8.8 — одиночные точки основного графика (2026-09-28) + +- Общий TrafficRxTxChart показывает маркер только для валидной точки без валидных соседей в том же направлении. Одиночный ноль и точки между пропусками видны; непрерывные серии сохраняют прежний вид без маркеров. RX/TX используют одинаковое правило и существующие цвета темы. +- До финального подключения TX прошли 38 E2E деталей/flow/дашборда. Новый тест выявил пропущенное подключение TX; после исправления все 10 тестов деталей прошли, включая нулевые RX/TX, три изолированные точки и порядок координат. Снимок изолированных RX осмотрен. Итоговые ESLint, diff-check и production build/TypeScript прошли (34 страницы). +- Граница: это отображение существующих точек, без изменения временной шкалы API или правил агрегации. Полная регрессия проекта не выполнялась; реальные RouterOS/IPFIX не проверены. +- Далее: ожидание первого SSE sample, решение по месячным ограничениям и ReUI/accessibility checklist. Этап 8 ещё открыт. Пятичасовой лимит обновился; на контрольной точке использовано 18%, недельного — 18%. Локальный коммит без push. + ## Блок 8.7 — CRLF и heartbeat SSE (2026-09-28) - В обоих hook разделители событий и строк принимают LF/CRLF, включая разделитель между двумя chunk. Комментарий перед event/data больше не отбрасывает весь блок: строки комментариев пропускаются парсером, sample сохраняется. diff --git a/docs/ux-ui-stage-8.md b/docs/ux-ui-stage-8.md index e2ac8a4c..34d9b003 100644 --- a/docs/ux-ui-stage-8.md +++ b/docs/ux-ui-stage-8.md @@ -46,3 +46,5 @@ Обновление 8.6 (2026-09-28): молчащий SSE обработан в обоих hook — 15 секунд без валидного sample снимают live, сохраняя данные; следующий sample восстанавливает live. 24 прежних и 2 новых сценария прошли, как и lint/build. Следующий шаг — оставшийся аудит CRLF/heartbeat, первого sample, единичной точки графика и месячных ограничений; этап пока открыт. Обновление 8.7 (2026-09-28): LF/CRLF и комментарий перед event поддержаны в обоих hook. Два потоковых сценария проверяют разделитель между chunk и heartbeat, не продлевающий свежесть. Все 26 профильных E2E прошли; далее одиночная точка графика и остальные ограничения, перечисленные выше. + +Обновление 8.8 (2026-09-28): одиночные точки RX/TX, включая нули между пропусками, получили маркеры. Итоговые 10 тестов деталей и build/lint прошли; перед финальным подключением TX проверены 38 сценариев потребителей. Далее — первый SSE sample и оставшаяся приёмка. diff --git a/tests/e2e/traffic-details.spec.ts b/tests/e2e/traffic-details.spec.ts index f4bde26d..092f756b 100644 --- a/tests/e2e/traffic-details.spec.ts +++ b/tests/e2e/traffic-details.spec.ts @@ -147,3 +147,31 @@ test('Итоги трафика: Sparkline сохраняет разрывы и await expect(page.getByLabel('Нет истории измерений')).toHaveCount(2) await expect(page.getByRole('img', { name: 'История измерений', exact: true })).toHaveCount(0) }) + +test('История RX/TX: одиночные значения и ноль видны между пропусками', async ({ page }) => { + const control = await setup(page) + const history = page.getByRole('region', { name: 'История RX/TX' }) + control.series = [0] + control.txSeries = [] + await page.getByRole('button', { name: '24ч', exact: true }).click() + const dots = history.locator('circle[data-isolated-direction]') + await expect(dots).toHaveCount(1) + await expect(dots.first()).toBeVisible() + await expect(dots.first()).toHaveAttribute('data-isolated-direction', 'rx') + expect(await dots.first().getAttribute('cx')).not.toMatch(/NaN|Infinity/) + expect(await dots.first().getAttribute('cy')).not.toMatch(/NaN|Infinity/) + control.series = [2, null, 0, null, 3] + control.txSeries = [1, 2, 3, 4, 5] + await page.getByRole('button', { name: '15м', exact: true }).click() + await expect(history.locator('circle[data-isolated-direction="rx"]')).toHaveCount(3) + await expect(history.locator('circle[data-isolated-direction="tx"]')).toHaveCount(0) + const positions = await dots.evaluateAll(nodes => nodes.map(node => Number(node.getAttribute('cx')))) + expect(positions[0]).toBeLessThan(positions[1]) + expect(positions[1]).toBeLessThan(positions[2]) + await history.screenshot({ path: "test-results/traffic-isolated-points.png" }) + control.series = [1, 2, 3] + control.txSeries = [0] + await page.getByRole('button', { name: '4ч', exact: true }).click() + await expect(history.locator('circle[data-isolated-direction="rx"]')).toHaveCount(0) + await expect(history.locator('circle[data-isolated-direction="tx"]')).toHaveCount(1) +})