diff --git a/components/data-grids/compact-data-grid.tsx b/components/data-grids/compact-data-grid.tsx index e5b547f1..b5304cca 100644 --- a/components/data-grids/compact-data-grid.tsx +++ b/components/data-grids/compact-data-grid.tsx @@ -82,7 +82,8 @@ function CompactDataGrid({ const table = useTable({ features: dataGridFeatures, - manualPagination: true, + manualPagination: false, + initialState: { pagination: { pageIndex: 0, pageSize: 50 } }, data, columns: columnDefs, getRowId: (row) => row.id, @@ -93,6 +94,7 @@ function CompactDataGrid({ 50 || table.state.pagination.pageSize !== 50} isLoading={isLoading} loadingMode="skeleton" onRowClick={ diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index e64a706f..61252fe6 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -4,7 +4,7 @@ ## Актуальная точка продолжения — 2026-10-03 -Этап 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/статистика и ограничения специализированных таблиц; затем12.4 сводная регрессия и production build. См. 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 очереди проблем; затем специализированные grids и12.4 сводная регрессия/production build. См. 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 d29fec08..b80efc0b 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -36,6 +36,14 @@ +## 12.3.2 — ограничение DOM общего CompactDataGrid (2026-10-04) + +Общая компактная таблица теперь использует штатную client pagination50 строк; сохранены исходные data/columns/row callbacks и загрузка/empty/detail. Навигация сохраняется при выбранном меньшем размере. На1000 строк статистики (88894 JSON bytes массива users) DOM уменьшился12585→1210 nodes, rendered rows1000→50. Доready5195ms, после2928/1195ms в отдельных dev прогонах; прогретость отличается, production SLA не заявляется. Полный ответ и pivot columns по-прежнему находятся в памяти. + +Проверки:25 statistics/migrated/catalog/snapshot browser прошли; large-case сначала ошибочно ожидал прямую кнопку последней страницы из нового upstream API, установленная версия использует группы. Тест исправлен под фактические штатные ellipsis controls, повтор1 large-case прошёл (последняя страница, назад, сортировка всего1000 набора,320px). Typecheck/ESLint прошли; ReUI API/checklist изучены, установленный primitive не переписан. + +Не считать12.3 завершённым:28 специализированных grids используют manualPagination:true и требуют раздельного разбора (часть получает server page/limit). Скрытые строки AttentionRows тоже всё ещё создаются в DOM. Далее12.3.3: управляемое раскрытие большой очереди проблем, затем профильный разбор специализированных grids/ограничений и12.4 регрессия/build. + ## 12.3.1 — ограничение DOM таблицы серверов (2026-10-04) На фиксированном каталоге1000 ServerRead (501462 JSON bytes) прежняя таблица выводила1000 строк/41569 DOM nodes. Штатная client pagination ReUI/TanStack теперь выводит50 строк (initial page size50),2644 DOM nodes; поиск/сортировка выполняются по всему каталогу. При выбранном меньшем page size навигация остаётся доступной даже если фильтр даёт менее50 результатов. Малые каталоги при default50 сохраняют прежний вид. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 233dde21..520b6ab8 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -110,3 +110,11 @@ Active WAN выбирается только по наблюдаемому defau Проверки:36 browser large-servers+servers (права, формы, операции, URL/filters), затем1 расширенный large-case (page size5/фильтр9 результатов/вторая страница/возврат50), typecheck/ESLint прошли. Дев-замеры одного локального Edge прогона: доready3345ms, после1058ms и1543ms; это наблюдение с разной прогретостью dev compiler, не production SLA/статистическая оценка. Полный JSON всё ещё загружается/валидируется на клиенте. ReUI MCP DataGridPagination API и checklist прочитаны; primitives/shared theme unchanged. Следующий блок12.3.2: большие списки CompactDataGrid/статистика и явная карта оставшихся специализированных таблиц. Этап12.3 целиком ещё не принят;12.4 требует сводной browser/context проверки и production build. + +## 12.3.2 — ограничение DOM общего CompactDataGrid (2026-10-04) + +Общая компактная таблица теперь использует штатную client pagination50 строк; сохранены исходные data/columns/row callbacks и загрузка/empty/detail. Навигация сохраняется при выбранном меньшем размере. На1000 строк статистики (88894 JSON bytes массива users) DOM уменьшился12585→1210 nodes, rendered rows1000→50. Доready5195ms, после2928/1195ms в отдельных dev прогонах; прогретость отличается, production SLA не заявляется. Полный ответ и pivot columns по-прежнему находятся в памяти. + +Проверки:25 statistics/migrated/catalog/snapshot browser прошли; large-case сначала ошибочно ожидал прямую кнопку последней страницы из нового upstream API, установленная версия использует группы. Тест исправлен под фактические штатные ellipsis controls, повтор1 large-case прошёл (последняя страница, назад, сортировка всего1000 набора,320px). Typecheck/ESLint прошли; ReUI API/checklist изучены, установленный primitive не переписан. + +Не считать12.3 завершённым:28 специализированных grids используют manualPagination:true и требуют раздельного разбора (часть получает server page/limit). Скрытые строки AttentionRows тоже всё ещё создаются в DOM. Далее12.3.3: управляемое раскрытие большой очереди проблем, затем профильный разбор специализированных grids/ограничений и12.4 регрессия/build. diff --git a/tests/e2e/large-statistics.spec.ts b/tests/e2e/large-statistics.spec.ts new file mode 100644 index 00000000..1a2aa06f --- /dev/null +++ b/tests/e2e/large-statistics.spec.ts @@ -0,0 +1,9 @@ +import {test,expect} from "@playwright/test" +import {statisticsDtoSchema} from "../../packages/contracts/src/statistics" +test("large statistics pagination bounds DOM and sorts the whole catalog",async({page},info)=>{ + test.setTimeout(90000) + const users=Array.from({length:1000},(_,i)=>({id:String(i+1),label:"Large user "+String(i+1).padStart(4,"0"),bytes:1000,packets:10,bps:100,percent:0.1})) + await page.route("**/health",r=>r.fulfill({json:{ok:true}}));await page.route("**/api/**",r=>{const url=new URL(r.request().url());return r.fulfill({json:url.pathname==="/api/statistics"?statisticsDtoSchema.parse({from:url.searchParams.get("from"),to:url.searchParams.get("to"),grain:"day",kpis:{bytes:1000000,packets:10000,avgBps:100000,users:1000,servers:0,ifaces:0,topCountry:"",topService:""},series:[],servers:[],interfaces:[],countries:[],services:[],asns:[],users}):url.pathname==="/api/auth/config"?{required:false}:url.pathname==="/api/servers"?[]:{}})}) + const start=Date.now();await page.goto("/statistics?from=2026-09-01&to=2026-09-03&dim=users");await expect(page.getByText("Large user 0001",{exact:true})).toBeVisible({timeout:60000});const sample={fixtureRows:1000,fixtureBytes:Buffer.byteLength(JSON.stringify(users)),readyMs:Date.now()-start,renderedRows:await page.locator("tr[data-row-id]").count(),domNodes:await page.locator("*").count()};console.log(JSON.stringify(sample));await info.attach("large-statistics-metrics",{body:JSON.stringify(sample),contentType:"application/json"});expect(sample.renderedRows).toBe(50);expect(sample.domNodes).toBeLessThan(2500) + await expect(page.getByText("1–50 из 1000",{exact:true})).toBeVisible();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("Large user 1000",{exact:true})).toBeVisible();await expect(page.getByText("951–1000 из 1000",{exact:true})).toBeVisible();for(let i=0;i<3;i++)await page.getByRole("button",{name:"…",exact:true}).first().click();await page.getByRole("button",{name:"Перейти на страницу 1",exact:true}).click();await page.getByRole("button",{name:"Имя",exact:true}).click();await page.getByRole("button",{name:"Имя",exact:true}).click();await expect(page.locator("tr[data-row-id]").first()).toContainText("Large user 1000");await page.setViewportSize({width:320,height:900});expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)).toBe(true);await expect(page.getByRole("button",{name:"Следующая страница",exact:true})).toBeVisible() +})