From 76a5e81fd48c21cee82e6f571b3b00c6b03a056e Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 4 Oct 2026 02:44:52 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=BE=D0=B3=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D1=8C=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8?= =?UTF-8?q?=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B1=20=D1=81=D0=BA=D0=BE=D1=80=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../probes-speed-probes-data-grid.tsx | 13 ++++++-- docs/ux-ui-performance.md | 5 ++- docs/ux-ui-plan.md | 2 +- docs/ux-ui-progress.md | 8 ++++- docs/ux-ui-stage-12.md | 6 ++++ tests/e2e/collector-probes-tables.spec.ts | 32 +++++++++++++++++-- 6 files changed, 59 insertions(+), 7 deletions(-) diff --git a/components/data-grids/probes-speed-probes-data-grid.tsx b/components/data-grids/probes-speed-probes-data-grid.tsx index 341b0533..b3bc4d16 100644 --- a/components/data-grids/probes-speed-probes-data-grid.tsx +++ b/components/data-grids/probes-speed-probes-data-grid.tsx @@ -2,7 +2,7 @@ import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" -import { useMemo } from "react" +import { useMemo, useEffect } from "react" import { type ColumnDef, useTable, @@ -132,12 +132,20 @@ function ProbesSpeedProbesDataGrid({ rows, serverName }: ProbesSpeedProbesDataGr const table = useTable({ features: dataGridFeatures, - manualPagination: true, + manualPagination: false, + autoResetPageIndex: false, + initialState: { pagination: { pageIndex: 0, pageSize: 50 } }, data: rows, columns, getRowId: (row) => row.id, }) + const { pageIndex, pageSize } = table.state.pagination + useEffect(() => { + const lastPage = Math.max(0, Math.ceil(rows.length / pageSize) - 1) + if (pageIndex > lastPage) table.setPageIndex(lastPage) + }, [rows.length, pageSize, pageIndex, table]) + if (rows.length === 0) { return ( 50 || table.state.pagination.pageSize !== 50} tableClassNames={{ headerRow: "border-b border-border", bodyRow: cn("group/row", "[&[data-disabled=true]]:opacity-50"), diff --git a/docs/ux-ui-performance.md b/docs/ux-ui-performance.md index e78d87e2..413bc231 100644 --- a/docs/ux-ui-performance.md +++ b/docs/ux-ui-performance.md @@ -7,6 +7,7 @@ | Серверы |1000 ServerRead,501462 JSON bytes |1000 →50 |41569 →2644 |3345 →1058/1543ms | | Статистика/CompactDataGrid |1000 users,88894 JSON bytes массива |1000 →50 |12585 →1210 |5195 →2928/1195ms | | BGP |1000 полных сессий |1000 →50 |25657 →1932 |2990 →898ms | +| Speed-пробы |1000 probes/1001 devices |1000 →50 |23590 →11265 (секция739) |3741 →2310ms | | Очередь проблем |1000 offline servers |5 начальных,55 после раскрытия,105 после кнопки |831 начальный dashboard |1081ms; baseline до не замерялся | Профили: large-servers.spec.ts, large-statistics.spec.ts, large-bgp.spec.ts, dashboard-data.spec.ts. Измерения приложены к Playwright test results как JSON. Полные массивы всё ещё загружаются/валидируются/фильтруются на клиенте. Pagination ограничивает строки DOM, но не число pivot колонок; широкая pivot требует отдельной проверки. Порционное раскрытие очереди допускает постепенный полный список по запросу пользователя. @@ -45,6 +46,8 @@ | [wireguard-data-grid.tsx](../components/data-grids/wireguard-data-grid.tsx) | Потребитель API, контекст/детали и fixture1000 | | [wireguard-peers-grid.tsx](../components/data-grids/wireguard-peers-grid.tsx) | Потребитель API, контекст/детали и fixture1000 | -Всего27 специализированных grids; ни один из этого перечня не принят этим документом на больших данных. CompactDataGrid дополнительно проверен на повторном получении100 active probes: страница сохраняется; сокращение100→1 ограничивает индекс. Следующая группа12.3.6 — uptime-resources/probes-speed/probes-schedule, затем сетевые/admin grids по профилям. Общий журнал: [ux-ui-progress.md](ux-ui-progress.md). +Осталось26 специализированных grids; ни один из оставшегося перечня не принят этим документом на больших данных. CompactDataGrid дополнительно проверен на повторном получении100 active probes: страница сохраняется; сокращение100→1 ограничивает индекс. Следующая группа12.3.6 — uptime-resources/probes-speed/probes-schedule, затем сетевые/admin grids по профилям. Общий журнал: [ux-ui-progress.md](ux-ui-progress.md). 12.3.6:1000 speed probes baseline —1000 rendered rows/23590 DOM nodes/3741ms dev ready; профиль collector-probes4 cases и ESLint прошли. Далее12.3.7 ограничение DOM speed grid; этот baseline не означает принятую производительность. + +12.3.7: speed grid принят на1000 строках в описанных локальных границах.50 строк/739 nodes секции; вся страница11265 nodes из-за полного каталога устройств. ServerTileRail требует отдельного ограничения DOM с проверкой поиска, выбора и клавиатуры. Следующий блок12.3.8 — uptime resources. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index ab690dd3..02be2843 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -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: probes-speed-probes-data-grid pagination/контекст, затем1000 uptime resources/schedule entries, затем остальные grids;12.4/12.5 ещё не завершены. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются. +Этап 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:1000 uptime resources, затем каталог устройств/schedule entries и остальные grids;12.4/12.5 ещё не завершены. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются. Реальные 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 5edc093e..11d8ecb7 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -29,13 +29,19 @@ | 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 | | 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 | | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | -| 12 | Итоговая доступность, адаптивность, производительность и регрессия | В работе;12.1/12.2.1–12.2.10 и12.3.1–12.3.5 приняты в описанных локальных границах | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | В работе;12.1/12.2.1–12.2.10 и12.3.1–12.3.5 и12.3.7 приняты в описанных локальных границах | +## 12.3.7 — пагинация большого списка speed-проб (2026-10-04) + +ProbesSpeedProbesDataGrid использует штатную ReUI client pagination по50 строк; обновление сохраняет страницу, сокращение набора ограничивает индекс. Сортировка работает по всему набору. Проверено1000→1, последняя страница20 и320px; небольшой список12 записей и демо-расписание сохраняют поведение. + +4 browser collector-probes прошли.1000 строк дают50 rendered rows/739 узлов внутри секции speed-проб,11265 DOM nodes всей страницы,2310ms ready в одном dev прогоне против baseline23590 nodes/3741ms. Каталог1001 устройства в ServerTileRail остаётся полностью в DOM: общая производительность страницы ещё не принята. Полные DTO остаются в памяти; API и правила сетевых операций не менялись. Следующий блок12.3.8:1000 uptime resources; затем каталог устройств/расписания и остальные grids.12.4/12.5 не завершены. + ## 12.3.6 — исходный замер1000 speed probes (2026-10-04) Штатная fixture collector-probes обновлена под numeric device IDs и каталог имён; старая использовала названия вместо ID, строгий reader правильно отклонял её. Новый large-case измерил1000 строк/23590 DOM nodes,3741ms ready в одном dev прогоне.4 browser профиля (12 speed/sort,11 scheduler jobs/run, demo schedule,1000 speed baseline) и ESLint прошли. Это исходный замер, ограничение DOM speed grid ещё НЕ реализовано; production UI этим блоком не изменён. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index e3f3cbc0..1922c842 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -175,3 +175,9 @@ Pure/DI профиль дополнен malformed entity/error record/valid empt Штатная fixture collector-probes обновлена под numeric device IDs и каталог имён; старая использовала названия вместо ID, строгий reader правильно отклонял её. Новый large-case измерил1000 строк/23590 DOM nodes,3741ms ready в одном dev прогоне.4 browser профиля (12 speed/sort,11 scheduler jobs/run, demo schedule,1000 speed baseline) и ESLint прошли. Это исходный замер, ограничение DOM speed grid ещё НЕ реализовано; production UI этим блоком не изменён. Следующий шаг12.3.7: probes-speed-probes-data-grid client pagination/сохранение страницы и URL/операции на1000 пробах; затем1000 uptime resources и расписаний, остальные27 grids из ux-ui-performance.md.12.3/12.4/12.5 не завершены. Последние production frontend/contracts и backend builds прошли в12.3.5/12.2.10. Локальные коммиты, без push. + +## 12.3.7 — пагинация большого списка speed-проб (2026-10-04) + +ProbesSpeedProbesDataGrid использует штатную ReUI client pagination по50 строк; обновление сохраняет страницу, сокращение набора ограничивает индекс. Сортировка работает по всему набору. Проверено1000→1, последняя страница20 и320px; небольшой список12 записей и демо-расписание сохраняют поведение. + +4 browser collector-probes прошли.1000 строк дают50 rendered rows/739 узлов внутри секции speed-проб,11265 DOM nodes всей страницы,2310ms ready в одном dev прогоне против baseline23590 nodes/3741ms. Каталог1001 устройства в ServerTileRail остаётся полностью в DOM: общая производительность страницы ещё не принята. Полные DTO остаются в памяти; API и правила сетевых операций не менялись. Следующий блок12.3.8:1000 uptime resources; затем каталог устройств/расписания и остальные grids.12.4/12.5 не завершены. diff --git a/tests/e2e/collector-probes-tables.spec.ts b/tests/e2e/collector-probes-tables.spec.ts index a982a9b8..824b3082 100644 --- a/tests/e2e/collector-probes-tables.spec.ts +++ b/tests/e2e/collector-probes-tables.spec.ts @@ -72,6 +72,34 @@ test("Демо-расписание: сортировка интервала и await expect(page.locator('tr[data-row-id="r3"]')).toHaveCount(0) }) -test("Large speed probes: фиксированный baseline1000 до ограничения DOM",async({page},info)=>{ - test.setTimeout(90000);const start=Date.now();await setup(page,"/probes",1000);await page.getByRole("button",{name:"Расписание",exact:true}).click();await expect(page.locator("tr[data-row-id]")).toHaveCount(1000);const sample={fixtureRows:1000,renderedRows:await page.locator("tr[data-row-id]").count(),domNodes:await page.locator("*").count(),readyMs:Date.now()-start};console.log(JSON.stringify(sample));await info.attach("large-speed-probes-baseline",{body:JSON.stringify(sample),contentType:"application/json"}) +test("Large speed probes: 50 строк, глобальная сортировка и контекст обновления", async ({ page }, info) => { + test.setTimeout(90000) + const start = Date.now() + await setup(page, "/probes", 1000) + await page.getByRole("button", { name: "Расписание", exact: true }).click() + const rows = page.locator("tr[data-row-id]") + await expect(rows).toHaveCount(50) + const sample = { fixtureRows: 1000, renderedRows: await rows.count(), domNodes: await page.locator("*").count(), scheduleNodes: await page.getByRole("region", { name: "Пробы скорости", exact: true }).locator("*").count(), readyMs: Date.now() - start } + console.log(JSON.stringify(sample)) + await info.attach("large-speed-probes-metrics", { body: JSON.stringify(sample), contentType: "application/json" }) + expect(sample.scheduleNodes).toBeLessThan(2000) + expect(sample.domNodes).toBeLessThan(12000) + await page.getByRole("button", { name: "Следующая страница", exact: true }).click() + await expect(rows.first()).toHaveAttribute("data-row-id", "51") + await page.getByRole("button", { name: "Обновить пробы скорости", exact: true }).click() + await expect(page.getByRole("button", { name: "Обновить пробы скорости", exact: true })).toBeEnabled() + await expect(page.getByText("51–100 из 1000", { exact: true })).toBeVisible() + await page.getByRole("button", { name: "Источник", exact: true }).click() + await page.getByRole("button", { name: "Источник", exact: true }).click() + await page.getByRole("button", { name: "Перейти на страницу 1", exact: true }).click() + await expect(rows.first()).toHaveAttribute("data-row-id", "1000") + for (let i = 0; i < 3; i++) await page.getByRole("button", { name: "…", exact: true }).last().click() + await page.getByRole("button", { name: "Перейти на страницу 20", exact: true }).click() + await expect(page.getByText("951–1000 из 1000", { exact: true })).toBeVisible() + await page.setViewportSize({ width: 320, height: 900 }) + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) + await page.route("**/api/uptime/speed-probes", route => route.fulfill({ json: { probes: [{ id: "1", srcServerId: "1", dstServerId: "1001", srcInterface: "ether1", dstInterface: "ether1", protocol: "tcp", direction: "both", durationSec: "10", enabled: true, lastRunAt: null, lastTxAvgMbps: null, lastRxAvgMbps: null, lastStatus: null, lastError: null }] } })) + await page.getByRole("button", { name: "Обновить пробы скорости", exact: true }).click() + await expect(rows).toHaveCount(1) + await expect(rows.first()).toHaveAttribute("data-row-id", "1") })