From 1ea07f65b2823bcb20fb4cd0b1d4baa0872a89c4 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Mon, 14 Sep 2026 13:54:05 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20=D1=80=D0=B5=D0=BA=D1=83=D1=80=D1=81=D0=B8=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BC=D0=B0=D1=80=D1=88=D1=80=D1=83=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BD=D0=B0=20ReUI=20v9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data-grids/recursive-routes-data-grid.tsx | 24 +++++++------- docs/ux-ui-progress.md | 10 ++++++ tests/e2e/recursive-routes-table.spec.ts | 33 +++++++++++++++++++ 3 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 tests/e2e/recursive-routes-table.spec.ts diff --git a/components/data-grids/recursive-routes-data-grid.tsx b/components/data-grids/recursive-routes-data-grid.tsx index 67bc3ab5..f79ec4c0 100644 --- a/components/data-grids/recursive-routes-data-grid.tsx +++ b/components/data-grids/recursive-routes-data-grid.tsx @@ -1,23 +1,22 @@ "use client" +import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" + import { useMemo, useState } from "react" import { type ColumnDef, - getCoreRowModel, - getExpandedRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table-v8" + useTable, +} from "@tanstack/react-table" import { Flag } from "@/components/flag" import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" -import { DataGridShell } from "@/components/data-grids/shared/legacy-data-grid-shell" +import { DataGridShell } from "@/components/data-grids/shared/data-grid-shell" import { DATA_GRID_CELL_PAD, DATA_GRID_CELL_PAD_FIRST, DATA_GRID_CELL_PAD_LAST, -} from "@/components/data-grids/shared/legacy-data-grid-layout" -import { DataGridSortHeader } from "@/components/data-grids/shared/legacy-data-grid-sort-header" +} from "@/components/data-grids/shared/data-grid-layout" +import { DataGridSortHeader } from "@/components/data-grids/shared/data-grid-sort-header" import { EmptyState } from "@/components/empty-state" import { AlertCircleIcon, @@ -131,7 +130,7 @@ function RecursiveRoutesDataGrid({ return g ? { [(g.id ?? g.key)]: true } : {} }, [expandedKey, groups]) - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ { id: "route", @@ -289,12 +288,11 @@ function RecursiveRoutesDataGrid({ [confirmDeleteKey, expandedKey, onDelete, onEdit], ) - const table = useReactTable({ + const table = useTable({ + features: dataGridFeatures, + manualPagination: true, data: groups, columns, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - getExpandedRowModel: getExpandedRowModel(), getRowId: (row) => row.id ?? row.key, getRowCanExpand: () => true, state: { expanded }, diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 57ee9da6..588abf60 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -292,6 +292,16 @@ Production build блока 7: `npm run build` прошёл, 34 статичес Квота: использовано 46% на старте, 81% перед финальными проверками. Остаток ниже резерва 25%, новые блоки не начинать. Следующий шаг — `recursive-routes-data-grid` и четыре `route-optimizer-*-data-grid`; далее `data-table`, общие legacy-потребители, старые Filters и удаление v8 с общей регрессией. Этап 4 остаётся открытым; сохранить блок локальным коммитом без push, ветку не выпускать. +## Этап 4 — блок 9: рекурсивные маршруты (2026-09-14) + +По прямому указанию пользователя продолжена работа ниже резерва квоты (89% использовано на старте). `recursive-routes-data-grid` переведён на установленную общую оболочку ReUI/TanStack v9, сохранены управляемое раскрытие по ключу группы, сортировка, обработчики редактирования/удаления и отсутствие пагинации. + +Проверки: Playwright `recursive-routes-table.spec.ts` — 1 passed (12 групп через HTTP-мок, сортировка в обе стороны, раскрытие и закрытие деталей после сортировки, отсутствие pageerror); ESLint компонента и теста — успешно. TypeScript до и после браузерного прогона — успешно. Реальные сетевые изменения не проверялись. + +Уточнение блока 8: в `.next/types/validator.ts` присутствовала полноценная декларация `RouteHandlerConfig` и проверки обоих API-маршрутов. Удалён только ошибочный сгенерированный `.next/dev/types/validator.ts`; исходники, tsconfig и production-validator сохранены. После этого tsc прошёл, в том числе после нового запуска Playwright. Ошибка предыдущей финальной проверки снята; правка кеша не входит в Git. + +После блока использовано 95% пятичасовой квоты. Следующий блок — четыре `route-optimizer-*-data-grid`, затем общие legacy-потребители/`data-table`, старые Filters и удаление v8 с полной регрессией. Этап 4 не завершён. Этот блок сохранить локальным коммитом без push. + ## Карта миграции (исходная инвентаризация этапа 0) Текущая связка: @tanstack/react-table ^8.21.3, @tanstack/react-virtual ^3.14.4, base-nova. Актуальный ReUI MCP ранее подтвердил useTable/dataGridFeatures для Data Grid и дерево FilterQuery вместо filters/onChange для Filters. Перед установкой перепроверить совместимые версии, сохранить семантику существующих фильтров (простые условия → AND) и закрепить lockfile. diff --git a/tests/e2e/recursive-routes-table.spec.ts b/tests/e2e/recursive-routes-table.spec.ts new file mode 100644 index 00000000..6a90f9b7 --- /dev/null +++ b/tests/e2e/recursive-routes-table.spec.ts @@ -0,0 +1,33 @@ +import { test, expect } from "@playwright/test" + +test("Рекурсивные маршруты: все группы и раскрытие после сортировки", async ({ page }) => { + const errors: string[] = [] + page.on("pageerror", error => errors.push(error.message)) + const routes = Array.from({ length: 12 }, (_, i) => ({ + id: String(i + 1), dstAddress: `10.0.${i + 1}.0/24`, gateway: `192.0.2.${i + 1}`, + distance: 1, scope: 30, targetScope: 10, routingTable: "main", checkGateway: "ping", + comment: `Маршрут ${i + 1}`, disabled: false, country: "RU", + })) + await page.route("**/health", route => route.fulfill({ json: { ok: true } })) + await page.route("**/api/**", route => { + const path = new URL(route.request().url()).pathname + return route.fulfill({ json: path === "/api/recursive-routes" ? { routes } + : path === "/api/recursive-routes/gateways" ? { gateways: [] } + : path === "/api/auth/config" ? { required: false } + : path === "/api/servers" ? [{ id: 1, name: "Роутер", host: "192.0.2.100", type: "exit-node", site: "TEST", country: "RU", asn: "64512", enabled: true, status: "online", latency: 1 }] + : path === "/api/evobgp/settings" ? { enabled: false, baseUrl: "", secretConfigured: false } : {} }) + }) + await page.goto("/recursive-routes") + const rows = page.locator("tr[data-row-id]") + await expect(rows).toHaveCount(12) + await page.getByRole("button", { name: "Route / Comment", exact: true }).click() + await expect(rows.first()).toContainText("10.0.1.0/24") + await page.getByRole("button", { name: "Route / Comment", exact: true }).click() + await expect(rows.first()).toContainText("10.0.12.0/24") + await rows.first().click() + await expect(page.getByText("Endpoint 1", { exact: true })).toBeVisible() + await expect(page.getByText("check: ping", { exact: true })).toBeVisible() + await rows.first().click() + await expect(page.getByText("Endpoint 1", { exact: true })).toBeHidden() + expect(errors).toEqual([]) +})