fix(ui): восстанавливать поиск и фильтры BGP из URL

This commit is contained in:
Denozordec committed 2026-09-30 17:15:37 +07:00
1 parent 5c307a5b6c
commit aa678b9d5d
8 files changed
+220 -16

No files matched your search

+14 -15
View File
@@ -5,9 +5,8 @@ import { useRouter, useSearchParams } from "next/navigation"
import { PageHeader } from "@/components/page-header"
import { DataPageToolbar } from "@/components/data-page-toolbar"
import { BgpSessionsDataGrid } from "@/components/data-grids/bgp-sessions-data-grid"
import { createFilterQuery } from "@/components/reui/filters/filters-query"
import { useBgpUrlState } from "@/hooks/use-bgp-url-state"
import { QueryFilters } from "@/components/data-grids/query-filters"
import type { FilterQuery } from "@/components/reui/filters/filters-types"
import { applyFilterQuery } from "@/lib/data-filters/apply-filter-query"
import { BGP_FILTER_FIELDS } from "@/lib/data-filters/bgp-filter-fields"
import type { BgpSessionRow, BgpState, BgpType } from "@/lib/bgp/types"
@@ -37,8 +36,6 @@ import { ALL_SERVERS_ID, type ServerTileItem } from "@/components/server-tile-ra
type BgpSession = BgpSessionRow
type BgpTab = "sessions" | "routers" | "analytics"
type StateFilter = "all" | BgpState
type TypeFilter = "all" | BgpType
const AS_NAMES = BGP_AS_NAMES
// ─── mock data ────────────────────────────────────────────────────────────────
@@ -261,13 +258,11 @@ const BGP_FILTER_ACCESSORS = {
}
function SessionsTab({ sessions, emptyTitle, selectedSessionId, onSelectSession }: { sessions: BgpSession[]; emptyTitle?: string; selectedSessionId: string | null; onSelectSession: (id: string | null) => void }) {
const [search, setSearch] = useState("")
const [stateFilter, setStateFilter] = useState<StateFilter>("all")
const [typeFilter, setTypeFilter] = useState<TypeFilter>("all")
const [advancedFilters, setAdvancedFilters] = useState<FilterQuery>(() => createFilterQuery())
const { search, setSearch, stateFilter, setStateFilter, typeFilter, setTypeFilter, filters: advancedFilters, setFilters: setAdvancedFilters, error: urlError, hasFilters, reset } = useBgpUrlState()
const fields = useMemo(() => BGP_FILTER_FIELDS.map(field => field.id === "afi" ? { ...field, options: Array.from(new Set(sessions.map(s => s.afi))).sort().map(value => ({ value, label: value })) } : field), [sessions])
const q = search.toLowerCase()
const filtered = useMemo(() => {
if (urlError) return []
const base = sessions.filter((s) => {
if (stateFilter !== "all" && s.state !== stateFilter) return false
if (typeFilter !== "all" && s.type !== typeFilter) return false
@@ -275,7 +270,7 @@ function SessionsTab({ sessions, emptyTitle, selectedSessionId, onSelectSession
q &&
!s.peerIp.includes(q) &&
!s.description.toLowerCase().includes(q) &&
!s.serverLabel.includes(q) &&
!s.serverLabel.toLowerCase().includes(q) &&
!String(s.remoteAs).includes(q) &&
!(s.remoteAs === null ? "" : AS_NAMES[s.remoteAs] ?? "").toLowerCase().includes(q)
) {
@@ -284,10 +279,11 @@ function SessionsTab({ sessions, emptyTitle, selectedSessionId, onSelectSession
return true
})
return applyFilterQuery(base, advancedFilters, BGP_FILTER_ACCESSORS)
}, [sessions, q, stateFilter, typeFilter, advancedFilters])
}, [sessions, q, stateFilter, typeFilter, advancedFilters, urlError])
return (
<div className="flex flex-col gap-4">
{urlError && <Alert variant="warning"><AlertCircleIcon /><AlertDescription>{urlError}<Button variant="outline" size="sm" onClick={reset}>Сбросить фильтры BGP</Button></AlertDescription></Alert>}
<DataPageCard>
<DataPageToolbar
segmented={{
@@ -295,24 +291,26 @@ function SessionsTab({ sessions, emptyTitle, selectedSessionId, onSelectSession
onChange: setStateFilter,
options: [
{ value: "all", label: "Все", count: sessions.length },
{ value: "Unknown", label: "Неизвестно", count: sessions.filter(s => s.state === "Unknown").length },
{ value: "Established", label: "Established", count: sessions.filter((s) => s.state === "Established").length },
{ value: "Active", label: "Active", count: sessions.filter((s) => s.state === "Active").length },
{ value: "Idle", label: "Idle", count: sessions.filter((s) => s.state === "Idle").length },
{ value: "OpenSent", label: "OpenSent", count: sessions.filter((s) => s.state === "OpenSent").length },
],
}}
filterControl={<QueryFilters fields={BGP_FILTER_FIELDS} query={advancedFilters} onQueryChange={setAdvancedFilters} />}
filterControl={<QueryFilters fields={fields} query={advancedFilters} onQueryChange={setAdvancedFilters} />}
search={search}
onSearchChange={setSearch}
searchPlaceholder="IP, AS, описание…"
countLabel={`${filtered.length} из ${sessions.length}`}
actions={
<div className="flex items-center gap-0.5 p-0.5 rounded-md border border-border bg-muted/40">
{(["all", "eBGP", "iBGP"] as const).map((t) => (
{(["all", "eBGP", "iBGP", "Unknown"] as const).map((t) => (
<button
key={t}
type="button"
onClick={() => setTypeFilter(t)}
aria-pressed={typeFilter === t}
className={cn(
"px-2.5 py-1 text-[11px] rounded transition-colors",
typeFilter === t
@@ -320,13 +318,14 @@ function SessionsTab({ sessions, emptyTitle, selectedSessionId, onSelectSession
: "text-muted-foreground hover:text-foreground",
)}
>
{t === "all" ? "Все типы" : t}
{t === "all" ? "Все типы" : t === "Unknown" ? "Неизвестно" : t}
</button>
))}
</div>
}
/>
<BgpSessionsDataGrid sessions={filtered} emptyTitle={emptyTitle} selectedSessionId={selectedSessionId} onSelectSession={onSelectSession} />
{hasFilters && !urlError && <Button variant="ghost" size="sm" onClick={reset}>Сбросить фильтры BGP</Button>}
<BgpSessionsDataGrid sessions={filtered} emptyTitle={urlError ? "Некорректные фильтры BGP" : emptyTitle} selectedSessionId={selectedSessionId} onSelectSession={onSelectSession} />
</DataPageCard>
</div>
)