fix(ui): ограничить строки ресурсов мониторинга
This commit is contained in:
1 parent
76a5e81fd4
commit
2762f073a0
7 files changed
+93
-13
No files matched your search
@@ -56,14 +56,12 @@ function DataGridShell<TData extends object>({
|
||||
tableClassNames={tableClassNames}
|
||||
>
|
||||
{children ?? (
|
||||
<>
|
||||
<DataGridContainer border={false} className={DATA_GRID_CONTAINER_CLASS}>
|
||||
<DataGridTable />
|
||||
</DataGridContainer>
|
||||
{pagination && recordCount > 0 && (
|
||||
<DataGridPagination className="px-5 pb-3" />
|
||||
)}
|
||||
</>
|
||||
<DataGridContainer border={false} className={DATA_GRID_CONTAINER_CLASS}>
|
||||
<DataGridTable />
|
||||
</DataGridContainer>
|
||||
)}
|
||||
{pagination && recordCount > 0 && (
|
||||
<DataGridPagination className="px-5 pb-3" />
|
||||
)}
|
||||
</DataGrid>
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { DataGridContainer, DataGridScrollArea, DataGridTable, dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid"
|
||||
|
||||
import { useMemo } from "react"
|
||||
import { useMemo, useEffect } from "react"
|
||||
import {
|
||||
type ColumnDef,
|
||||
useTable,
|
||||
@@ -349,12 +349,20 @@ function UptimeResourcesDataGrid({ rows }: UptimeResourcesDataGridProps) {
|
||||
|
||||
const table = useTable({
|
||||
features: dataGridFeatures,
|
||||
manualPagination: true,
|
||||
manualPagination: false,
|
||||
autoResetPageIndex: false,
|
||||
initialState: { pagination: { pageIndex: 0, pageSize: 50 } },
|
||||
data: rows,
|
||||
columns,
|
||||
getRowId: (row) => row.serverId,
|
||||
})
|
||||
|
||||
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 (
|
||||
<EmptyState
|
||||
@@ -369,6 +377,7 @@ function UptimeResourcesDataGrid({ rows }: UptimeResourcesDataGridProps) {
|
||||
<DataGridShell
|
||||
table={table}
|
||||
recordCount={rows.length}
|
||||
pagination={rows.length > 50 || table.state.pagination.pageSize !== 50}
|
||||
tableClassNames={{
|
||||
headerRow: "border-b border-border bg-muted/30",
|
||||
bodyRow: cn(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
| Статистика/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 |
|
||||
| Ресурсы uptime |1000 resources/CPU10% |1000 →50 |38655 →2580 |4328 →1578ms |
|
||||
| Очередь проблем |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 требует отдельной проверки. Порционное раскрытие очереди допускает постепенный полный список по запросу пользователя.
|
||||
@@ -46,8 +47,10 @@
|
||||
| [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 |
|
||||
|
||||
Осталось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).
|
||||
Осталось25 специализированных 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.
|
||||
|
||||
12.3.8: ресурсы приняты на1000 CPU10% строках; глобальный поиск/URL/сортировка/страница20/refresh/1000→1/320px. Большой список1000 предупреждений ресурсов требует отдельной проверки12.3.9.
|
||||
+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: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 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. Следующий блок12.3.9:1000 предупреждений ресурсов, затем каталог устройств/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).
|
||||
|
||||
|
||||
@@ -29,13 +29,21 @@
|
||||
| 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.3.7 приняты в описанных локальных границах |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | В работе;12.1/12.2.1–12.2.10 и12.3.1–12.3.5 и12.3.7–12.3.8 приняты в описанных локальных границах |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 12.3.8 — большой список ресурсов мониторинга (2026-10-04)
|
||||
|
||||
UptimeResourcesDataGrid использует ReUI client pagination по50 строк с сохранением страницы при обновлении и ограничением индекса при уменьшении набора. DataGridShell исправлен: pagination выводится также при собственных children/ScrollArea; раньше такой потребитель не получал панель страниц. Установленные primitives и тема сохранены.
|
||||
|
||||
1000 ресурсов: baseline1000 строк/38655 DOM nodes/4328ms dev; после50 строк/2580 nodes/1578ms. Проверены глобальная сортировка, страница20, поиск записи1000/URL/reload, обновление страницы2,1000→1,320px и отсутствие POST при чтении по ссылке.8 browser больших таблиц/collector-probes прошли после исправления оболочки;52 прежних uptime links сценария прошли. Первый large-case воспроизвёл отсутствие pagination при children; финальный прогон прошёл. Typecheck/ESLint, frontend production/contracts build (34 страницы), ReUI validate_usage/checklist прошли.
|
||||
|
||||
Полные ресурсы остаются в памяти. Этот fixture использует CPU10%, список1000 предупреждений ресурсов ещё не проверен; ServerTileRail остаётся следующим отдельным потребителем. Далее12.3.9: большой список предупреждений ресурсов, затем каталог устройств/расписания и специализированные grids.12.4/12.5 не завершены, реальная PG/RouterOS нагрузка не проверена. Локальный коммит, без push.
|
||||
|
||||
## 12.3.7 — пагинация большого списка speed-проб (2026-10-04)
|
||||
|
||||
ProbesSpeedProbesDataGrid использует штатную ReUI client pagination по50 строк; обновление сохраняет страницу, сокращение набора ограничивает индекс. Сортировка работает по всему набору. Проверено1000→1, последняя страница20 и320px; небольшой список12 записей и демо-расписание сохраняют поведение.
|
||||
|
||||
@@ -181,3 +181,11 @@ Pure/DI профиль дополнен malformed entity/error record/valid empt
|
||||
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.8 — большой список ресурсов мониторинга (2026-10-04)
|
||||
|
||||
UptimeResourcesDataGrid использует ReUI client pagination по50 строк с сохранением страницы при обновлении и ограничением индекса при уменьшении набора. DataGridShell исправлен: pagination выводится также при собственных children/ScrollArea; раньше такой потребитель не получал панель страниц. Установленные primitives и тема сохранены.
|
||||
|
||||
1000 ресурсов: baseline1000 строк/38655 DOM nodes/4328ms dev; после50 строк/2580 nodes/1578ms. Проверены глобальная сортировка, страница20, поиск записи1000/URL/reload, обновление страницы2,1000→1,320px и отсутствие POST при чтении по ссылке.8 browser больших таблиц/collector-probes прошли после исправления оболочки;52 прежних uptime links сценария прошли. Первый large-case воспроизвёл отсутствие pagination при children; финальный прогон прошёл. Typecheck/ESLint, frontend production/contracts build (34 страницы), ReUI validate_usage/checklist прошли.
|
||||
|
||||
Полные ресурсы остаются в памяти. Этот fixture использует CPU10%, список1000 предупреждений ресурсов ещё не проверен; ServerTileRail остаётся следующим отдельным потребителем. Далее12.3.9: большой список предупреждений ресурсов, затем каталог устройств/расписания и специализированные grids.12.4/12.5 не завершены, реальная PG/RouterOS нагрузка не проверена. Локальный коммит, без push.
|
||||
@@ -0,0 +1,54 @@
|
||||
import { test, expect } from "@playwright/test"
|
||||
|
||||
test("1000 ресурсов: страницы, поиск, обновление и уменьшение списка", async ({ page }, info) => {
|
||||
test.setTimeout(90000)
|
||||
const servers = Array.from({ length: 1000 }, (_, i) => ({ id: i + 1, name: "Ресурс " + String(i + 1).padStart(4, "0"), host: "192.0.2." + (i % 250 + 1), type: "exit-node", enabled: true, country: "RU", site: "TEST", asn: "64512", status: "online", latency: 1, os: "7", model: "CHR", sessions: 0, wanUplinks: [] }))
|
||||
let resources = servers.map(s => ({ serverId: String(s.id), hasData: true, cpu: 10, cpuHistory: [10], ramUsed: 100, ramTotal: 1000, hddUsed: 10, hddTotal: 100, uptimeSeconds: 60, boardName: "CHR" }))
|
||||
let calls = 0
|
||||
const writes: string[] = []
|
||||
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
|
||||
await page.route("**/api/**", route => {
|
||||
const path = new URL(route.request().url()).pathname
|
||||
if (!["GET", "HEAD"].includes(route.request().method())) writes.push(path)
|
||||
if (path === "/api/uptime/overview") calls++
|
||||
return route.fulfill({ json: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? servers : path === "/api/uptime/overview" ? { probes: [], resources } : path === "/api/uptime/speed-probes" ? { probes: [] } : path === "/api/uptime/speed-test/runs" ? { runs: [] } : {} })
|
||||
})
|
||||
const start = Date.now()
|
||||
await page.goto("/uptime?tab=resources&probe=p1&keep=1")
|
||||
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(), readyMs: Date.now() - start }
|
||||
console.log(JSON.stringify(sample))
|
||||
await info.attach("large-uptime-resources-metrics", { body: JSON.stringify(sample), contentType: "application/json" })
|
||||
expect(sample.domNodes).toBeLessThan(4000)
|
||||
await page.getByRole("button", { name: "Следующая страница", exact: true }).click()
|
||||
await expect(rows.first()).toHaveAttribute("data-row-id", "51")
|
||||
const before = calls
|
||||
await page.getByRole("button", { name: "Обновить данные", exact: true }).click()
|
||||
await expect.poll(() => calls).toBeGreaterThan(before)
|
||||
await expect(page.getByRole("button", { name: "Обновить данные", exact: true })).toBeEnabled()
|
||||
await expect(page.getByText("51–100 из 1000", { exact: true })).toBeVisible()
|
||||
const search = page.getByPlaceholder("Поиск по имени, площадке…")
|
||||
await search.fill("Ресурс 1000")
|
||||
await expect(rows).toHaveCount(1)
|
||||
await expect(rows.first()).toHaveAttribute("data-row-id", "1000")
|
||||
await expect(page).toHaveURL(url => url.searchParams.get("rq") === "Ресурс 1000" && url.searchParams.get("probe") === "p1" && url.searchParams.get("keep") === "1")
|
||||
await page.reload()
|
||||
await expect(search).toHaveValue("Ресурс 1000")
|
||||
await expect(rows).toHaveCount(1)
|
||||
await search.fill("")
|
||||
await expect(rows).toHaveCount(50)
|
||||
await page.getByRole("button", { name: "Сервер", exact: true }).click()
|
||||
await page.getByRole("button", { name: "Сервер", 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)
|
||||
resources = resources.slice(0, 1)
|
||||
await page.getByRole("button", { name: "Обновить данные", exact: true }).click()
|
||||
await expect(rows).toHaveCount(1)
|
||||
await expect(rows.first()).toHaveAttribute("data-row-id", "1")
|
||||
expect(writes).toEqual([])
|
||||
})
|
||||
Reference in new issue
Block a user