diff --git a/app/(main)/dashboard/page.tsx b/app/(main)/dashboard/page.tsx
index 9fc314f5..f5750db5 100644
--- a/app/(main)/dashboard/page.tsx
+++ b/app/(main)/dashboard/page.tsx
@@ -1,5 +1,7 @@
"use client"
+import { useState } from "react"
+import { Button } from "@/components/ui/button"
import Link from "next/link"
import {
ActivityIcon,
@@ -36,6 +38,8 @@ function fmtIntRu(n: number): string {
}
function AttentionRows({ rows }: { rows: AttentionRow[] }) {
+ const [expanded,setExpanded]=useState(false)
+ const [visible,setVisible]=useState(55)
function renderRow(row: AttentionRow) {
return (
{rows.slice(0, 5).map(renderRow)}
{rows.length > 5 && (
-
+ {setExpanded(event.currentTarget.open);if(!event.currentTarget.open)setVisible(55)}}>
Ещё {rows.length - 5}
- {rows.slice(5).map(renderRow)}
+ {expanded && rows.slice(5,visible).map(renderRow)}
+ {expanded && rows.length>visible && }
)}
diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md
index 61252fe6..f549a897 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/1000 строк статистики. Следующий блок12.3.3: DOM очереди проблем; затем специализированные grids и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 очереди проблем. Следующий блок12.3.4: большой BGP каталог/сохранение страницы при обновлении; затем остальные специализированные grids и12.4 регрессия/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 b80efc0b..ca273f49 100644
--- a/docs/ux-ui-progress.md
+++ b/docs/ux-ui-progress.md
@@ -36,6 +36,14 @@
+## 12.3.3 — DOM очереди проблем дашборда (2026-10-04)
+
+AttentionRows больше не создаёт весь скрытый список: первые5 всегда видны, native details монтирует следующие50 по запросу, кнопка добавляет по50. Закрытие удаляет скрытые строки и сбрасывает порцию; полный счётчик/ссылки сохраняются. Нет скрытых1000 anchors до действия пользователя. Раскрытие выполняется обычным summary и клавиатурой, используется существующий Button; Frame/AttentionQueue primitives unchanged.
+
+Проверки:62 dashboard/permissions browser (включая1000 проблем: DOM5→55→105→5→55, переход к серверу,320px),20 dashboard unit, typecheck/ESLint прошли. На fixture1000 offline servers начальный dashboard:831 DOM nodes,1081ms ready в одном dev прогоне. Порционное раскрытие может по запросу пользователя постепенно создать весь список; полноценная виртуализация очереди не заявляется.
+
+Далее12.3.4: большой каталог BGP, учитывая сохранение страницы при фоновом обновлении. Другие27 специализированных manualPagination grids и wide pivot остаются отдельными ограничениями.12.4 сводные проверки/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 по-прежнему находятся в памяти.
diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md
index 520b6ab8..ca875e1d 100644
--- a/docs/ux-ui-stage-12.md
+++ b/docs/ux-ui-stage-12.md
@@ -118,3 +118,11 @@ Active WAN выбирается только по наблюдаемому defau
Проверки: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.3 — DOM очереди проблем дашборда (2026-10-04)
+
+AttentionRows больше не создаёт весь скрытый список: первые5 всегда видны, native details монтирует следующие50 по запросу, кнопка добавляет по50. Закрытие удаляет скрытые строки и сбрасывает порцию; полный счётчик/ссылки сохраняются. Нет скрытых1000 anchors до действия пользователя. Раскрытие выполняется обычным summary и клавиатурой, используется существующий Button; Frame/AttentionQueue primitives unchanged.
+
+Проверки:62 dashboard/permissions browser (включая1000 проблем: DOM5→55→105→5→55, переход к серверу,320px),20 dashboard unit, typecheck/ESLint прошли. На fixture1000 offline servers начальный dashboard:831 DOM nodes,1081ms ready в одном dev прогоне. Порционное раскрытие может по запросу пользователя постепенно создать весь список; полноценная виртуализация очереди не заявляется.
+
+Далее12.3.4: большой каталог BGP, учитывая сохранение страницы при фоновом обновлении. Другие27 специализированных manualPagination grids и wide pivot остаются отдельными ограничениями.12.4 сводные проверки/production build ещё не приняты; внешняя приёмка не заменяется локальными данными.
diff --git a/tests/e2e/dashboard-data.spec.ts b/tests/e2e/dashboard-data.spec.ts
index a15f9fd1..a08e361a 100644
--- a/tests/e2e/dashboard-data.spec.ts
+++ b/tests/e2e/dashboard-data.spec.ts
@@ -265,3 +265,7 @@ for(const state of ["unmeasured","measured","failed","unknown"])test("Dashboard
if(state==="unknown"){await expect(strip.getByText("Неизвестно",{exact:true})).toBeVisible();await expect(strip.getByText("Оффлайн",{exact:true})).toHaveCount(0)}
await page.setViewportSize({width:320,height:900});await expect(strip).toBeVisible();expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)).toBe(true)
})
+
+test("Dashboard large attention queue mounts rows on demand",async({page},info)=>{
+ test.setTimeout(90000);const start=Date.now();await setup(page,false,1000);await expect(refresh(page)).toBeEnabled();const queue=page.getByRole("region",{name:"Требует внимания",exact:true});const links=queue.locator('a[href^="/servers?server="]');await expect(links).toHaveCount(5);const sample={fixtureRows:1000,readyMs:Date.now()-start,renderedAttentionRows:await links.count(),domNodes:await page.locator("*").count()};console.log(JSON.stringify(sample));await info.attach("large-attention-metrics",{body:JSON.stringify(sample),contentType:"application/json"});const summary=queue.locator("summary").filter({hasText:"Ещё 995"});await summary.focus();await summary.press("Enter");await expect(links).toHaveCount(55);await queue.getByRole("button",{name:"Показать ещё 50",exact:true}).click();await expect(links).toHaveCount(105);await summary.focus();await summary.press("Enter");await expect(links).toHaveCount(5);await summary.press("Enter");await expect(links).toHaveCount(55);await page.setViewportSize({width:320,height:900});expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)).toBe(true);await links.first().click();await expect(page).toHaveURL(/servers\?server=1$/);await expect(page.getByRole("status",{name:"Сервер по ссылке"})).toContainText("Узел 1")
+})