fix(ui): перенести таблицы WireGuard на ReUI v9
This commit is contained in:
1 parent
d3db82fd1c
commit
e7d45d194d
4 files changed
+81
-26
No files matched your search
@@ -1,13 +1,12 @@
|
||||
"use client"
|
||||
|
||||
import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid"
|
||||
|
||||
import { useMemo, type ReactNode } from "react"
|
||||
import {
|
||||
type ColumnDef,
|
||||
getCoreRowModel,
|
||||
getExpandedRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table-v8"
|
||||
useTable,
|
||||
} from "@tanstack/react-table"
|
||||
import type { WireGuardInterface } from "@/lib/data"
|
||||
import { Flag } from "@/components/flag"
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -20,13 +19,13 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
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 { WireGuardPeersDetail } from "@/components/data-grids/wireguard-peers-detail"
|
||||
import { EmptyState } from "@/components/empty-state"
|
||||
import {
|
||||
@@ -69,7 +68,7 @@ function WireguardDataGrid({
|
||||
onDeletePeer,
|
||||
onExportPeer,
|
||||
}: WireguardDataGridProps) {
|
||||
const columns = useMemo<ColumnDef<WgIfaceWithServer>[]>(
|
||||
const columns = useMemo<ColumnDef<DataGridFeatures, WgIfaceWithServer>[]>(
|
||||
() => [
|
||||
{
|
||||
id: "name",
|
||||
@@ -269,12 +268,11 @@ function WireguardDataGrid({
|
||||
[compactServer, onExport, onAddPeer, onToggle, onDelete, onDeletePeer, onExportPeer],
|
||||
)
|
||||
|
||||
const table = useReactTable({
|
||||
const table = useTable({
|
||||
features: dataGridFeatures,
|
||||
manualPagination: true,
|
||||
data: interfaces,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getExpandedRowModel: getExpandedRowModel(),
|
||||
getRowId: (row) => row.id,
|
||||
getRowCanExpand: () => true,
|
||||
})
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
"use client"
|
||||
|
||||
import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid"
|
||||
|
||||
import { useMemo, type ReactNode } from "react"
|
||||
import {
|
||||
type ColumnDef,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table-v8"
|
||||
useTable,
|
||||
} from "@tanstack/react-table"
|
||||
import type { WireGuardPeer } from "@/lib/data"
|
||||
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 { fmtBytes, truncKey } from "@/components/data-grids/wireguard-peers-detail"
|
||||
import {
|
||||
@@ -53,8 +53,8 @@ function WireguardPeersGrid({
|
||||
onDeletePeer,
|
||||
onExportPeer,
|
||||
}: WireguardPeersGridProps) {
|
||||
const columns = useMemo<ColumnDef<WgPeerRow>[]>(() => {
|
||||
const cols: ColumnDef<WgPeerRow>[] = [
|
||||
const columns = useMemo<ColumnDef<DataGridFeatures, WgPeerRow>[]>(() => {
|
||||
const cols: ColumnDef<DataGridFeatures, WgPeerRow>[] = [
|
||||
{
|
||||
id: "peer",
|
||||
accessorKey: "publicKey",
|
||||
@@ -233,11 +233,11 @@ function WireguardPeersGrid({
|
||||
return cols
|
||||
}, [compactServer, onDeletePeer, onExportPeer])
|
||||
|
||||
const table = useReactTable({
|
||||
const table = useTable({
|
||||
features: dataGridFeatures,
|
||||
manualPagination: true,
|
||||
data: peers,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getRowId: (row) => row.id,
|
||||
})
|
||||
|
||||
|
||||
+11
-1
@@ -18,7 +18,7 @@
|
||||
| 1 | Достоверность сохранения, удаления, включения и опроса серверов | Завершён 2026-09-13 |
|
||||
| 2 | Общая оболочка Data Grid/TanStack v9, Filters и эталон серверов | Завершён 2026-09-13, с перечисленными ограничениями приёмки |
|
||||
| 3 | Основные таблицы и справочники | Завершён 2026-09-13, границы проверок ниже |
|
||||
| 4 | Остальные таблицы, удаление старых API, общая регрессия | В работе: блок BGP/OSPF перенесён |
|
||||
| 4 | Остальные таблицы, удаление старых API, общая регрессия | В работе: BGP/OSPF и WireGuard перенесены |
|
||||
| 5 | Состояния данных, свежесть, частичные сбои, гонки polling | Не начат |
|
||||
| 6 | Навигация и дашборд | Не начат |
|
||||
| 7 | Серверы и мониторинг: детали, формы, URL-контекст, права | Не начат |
|
||||
@@ -218,6 +218,16 @@ ReUI checklist получен: сохранены композиция, props у
|
||||
|
||||
Точный следующий шаг: проверить git status и квоту, перенести VPN-группу (`wireguard-data-grid`, `wireguard-peers-grid`, `ipsec-users-grid`, `gre-pools-data-grid`, `gre-tunnels-data-grid`, `vxlan-data-grid`) с профильными проверками. Затем перейти к оставшимся таблицам управления/диагностики и миграции Filters. Старые зависимости удалять только после последнего потребителя. Этот блок сохранить отдельным локальным коммитом без push; ветку не выпускать.
|
||||
|
||||
## Этап 4 — блок 2: WireGuard
|
||||
|
||||
Перенесены `wireguard-data-grid` и `wireguard-peers-grid` на установленную основу ReUI v9. Сохранены внешние props, идентификаторы, обработчики операций и раскрытие интерфейса. Явное `manualPagination: true` сохраняет все строки без скрытого ограничения в десять записей. Общие примитивы и сетевые операции не менялись.
|
||||
|
||||
Проверки: TypeScript (`--incremental false`) и целевой ESLint прошли без замечаний. Два браузерных сценария `tests/e2e/wireguard-tables.spec.ts` прошли: 12 интерфейсов, сортировка по порту, раскрытие/сворачивание пиров выбранного интерфейса, 12 строк отдельной вкладки пиров, сортировка и пустые состояния обеих вкладок. Фикстура проверяется схемой `wgListResponseSchema`, ответы подменяются на HTTP-уровне. Реальные операции RouterOS и права этими тестами не проверены; их приёмка остаётся этапу 9. Применён уже полученный ReUI checklist: сохранены композиция, публичный API и оформление; полная доступность и адаптивность ещё не приняты.
|
||||
|
||||
Квота на старте: использовано 67% пятичасового окна; после браузерных проверок — 74% (остаток 26%). Новый блок не начинать на границе резерва. Полная сборка и общая регрессия остаются завершению этапа 4, общая основа в этом блоке не менялась.
|
||||
|
||||
Следующий шаг после проверки квоты: перенести оставшиеся четыре VPN-таблицы `ipsec-users-grid`, `gre-pools-data-grid`, `gre-tunnels-data-grid`, `vxlan-data-grid`. WireGuard, BGP и три OSPF-таблицы уже исключены из остатка. Остальные таблицы управления/диагностики и старые Filters ещё не перенесены; этап 4 не завершён, ветку не выпускать. Блок WireGuard сохранить локальным коммитом без 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.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { test, expect, type Page } from "@playwright/test"
|
||||
import { wgListResponseSchema } from "../../packages/contracts/src/wireguard"
|
||||
|
||||
const fixture = wgListResponseSchema.parse({ interfaces: Array.from({ length: 12 }, (_, i) => ({
|
||||
id: `wg-${i + 1}`, rosId: `*${i + 1}`, name: `wg-test-${i + 1}`, serverId: "1",
|
||||
serverName: "Тестовый роутер", serverCountry: "RU", listenPort: 13231 + i, mtu: 1420,
|
||||
comment: "Тест", enabled: true, status: "up",
|
||||
peers: [{ id: `peer-${i + 1}`, rosId: `*${i + 20}`, publicKey: `fixture-public-key-${i + 1}`,
|
||||
name: `Пир ${i + 1}`, allowedIps: [`10.0.0.${i + 1}/32`], transferRx: i + 1, transferTx: i + 1 }],
|
||||
})) })
|
||||
|
||||
async function setup(page: Page, empty = false) {
|
||||
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/wireguard" ? (empty ? { interfaces: [] } : fixture)
|
||||
: path === "/api/auth/config" ? { required: false } : path === "/api/servers" ? [] : {} })
|
||||
})
|
||||
await page.goto("/wireguard")
|
||||
}
|
||||
|
||||
test("WireGuard: 12 интерфейсов, сортировка порта, раскрытие и список пиров", async ({ page }) => {
|
||||
const errors: string[] = []
|
||||
page.on("pageerror", e => errors.push(e.message))
|
||||
await setup(page)
|
||||
const rows = page.locator("tr[data-row-id]")
|
||||
await expect(rows).toHaveCount(12)
|
||||
await page.getByRole("button", { name: "Порт", exact: true }).click()
|
||||
await expect(rows.first()).toContainText("wg-test-12")
|
||||
await rows.first().click()
|
||||
await expect(page.getByText("10.0.0.12/32", { exact: true })).toBeVisible()
|
||||
await rows.first().click()
|
||||
await expect(page.getByText("10.0.0.12/32", { exact: true })).toBeHidden()
|
||||
await page.getByRole("tab", { name: /Пиры/ }).click()
|
||||
await expect(rows).toHaveCount(12)
|
||||
await expect(rows.last()).toContainText("10.0.0.12/32")
|
||||
await page.getByRole("button", { name: "Пир", exact: true }).click()
|
||||
await expect(rows.first()).toContainText("Пир 1")
|
||||
expect(errors).toEqual([])
|
||||
})
|
||||
|
||||
test("WireGuard: пустые интерфейсы и пиры", async ({ page }) => {
|
||||
await setup(page, true)
|
||||
await expect(page.getByText("Нет WireGuard интерфейсов", { exact: true })).toBeVisible()
|
||||
await page.getByRole("tab", { name: /Пиры/ }).click()
|
||||
await expect(page.getByText("Нет пиров", { exact: true })).toBeVisible()
|
||||
})
|
||||
Reference in new issue
Block a user