fix(ui): ограничить списки деталей OSPF без потери данных

This commit is contained in:
Denozordec committed 2026-10-04 17:32:01 +07:00
1 parent 8d86c5cbb0
commit 086f118204
9 files changed
+110 -11

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
"use client"
import { useMemo, useState, type ReactNode } from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function OspfDetailList<T>({ items, label, getSearchValue, renderItem }: {
items: T[]; label: string; getSearchValue: (item: T) => string
renderItem: (item: T, index: number) => ReactNode
}) {
const [query, setQuery] = useState("")
const [page, setPage] = useState(0)
const filtered = useMemo(() => {
const value = query.trim().toLowerCase()
return value ? items.filter(item => getSearchValue(item).toLowerCase().includes(value)) : items
}, [items, query, getSearchValue])
const pages = Math.max(1, Math.ceil(filtered.length / 50))
if (page >= pages) setPage(pages - 1)
const current = Math.min(page, pages - 1)
const controlled = items.length > 50 || !!query
return <section aria-label={label} className="min-w-0">
{controlled && <div className="flex min-w-0 flex-col gap-2 mb-2">
<Input aria-label={`Поиск: ${label}`} placeholder="Поиск во всём списке…" value={query} onChange={event => { setQuery(event.target.value); setPage(0) }} />
<p role="status" className="text-xs text-muted-foreground">Показаны {filtered.length ? current * 50 + 1 : 0}–{Math.min((current + 1) * 50, filtered.length)} из {filtered.length}. Всего {items.length}.</p>
<div className="flex flex-wrap gap-2">
<Button type="button" variant="outline" className="min-h-11" aria-label={`Предыдущая страница: ${label}`} disabled={!current} onClick={() => setPage(current - 1)}>Назад</Button>
<Button type="button" variant="outline" className="min-h-11" aria-label={`Следующая страница: ${label}`} disabled={current >= pages - 1} onClick={() => setPage(current + 1)}>Далее</Button>
</div>
{!filtered.length && <p className="text-xs text-muted-foreground">По вашему запросу ничего не найдено.</p>}
</div>}
<div className="flex flex-col gap-0 divide-y divide-border">{filtered.slice(current * 50, (current + 1) * 50).map((item, index) => renderItem(item, current * 50 + index))}</div>
</section>
}