fix(evolution): исключить моковые данные из живого каталога
This commit is contained in:
1 parent
118cd31d65
commit
d272ef57f0
17 files changed
+155
-136
No files matched your search
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useMemo, useEffect } from "react"
|
||||
import { useState, useMemo } from "react"
|
||||
import { PageHeader } from "@/components/page-header"
|
||||
import { DataPageCard } from "@/components/data-page-card"
|
||||
import {
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
type CommunityRow,
|
||||
TYPE_LABELS,
|
||||
ACTION_LABELS,
|
||||
ACTION_COLOR,
|
||||
} from "@/components/data-grids/communities-data-grid"
|
||||
import { Frame, FramePanel } from "@/components/reui/frame"
|
||||
import { KpiStatGrid } from "@/components/reui-kit/kpi-stat-grid"
|
||||
@@ -18,11 +17,10 @@ import { Input } from "@/components/ui/input"
|
||||
import {
|
||||
PlusIcon, SearchIcon, TagIcon, FilterIcon,
|
||||
CopyIcon, CheckIcon, TrashIcon, PencilIcon,
|
||||
LoaderCircleIcon,
|
||||
} from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { filters } from "@/lib/data"
|
||||
import { useDataSource } from "@/lib/data-source"
|
||||
import { useEvoCatalogView, EvoBgpCatalogStatus, EvoBgpCatalogUnavailable } from "@/components/settings/evobgp-catalog-status"
|
||||
import { useEvoBGP } from "@/lib/evobgp-context"
|
||||
|
||||
// ─── types ────────────────────────────────────────────────────────────────────
|
||||
@@ -98,24 +96,24 @@ const COMMUNITIES: Community[] = [
|
||||
// ─── page ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
export default function CommunitiesPage() {
|
||||
const { mode } = useDataSource()
|
||||
const { enabled, snapshot, loading, error } = useEvoBGP()
|
||||
const useEvoCatalog = mode === "live" && enabled
|
||||
const { sourceKey } = useEvoBGP()
|
||||
return <CommunitiesContent key={sourceKey} />
|
||||
}
|
||||
function CommunitiesContent() {
|
||||
const { mode, snapshot, loading, known } = useEvoCatalogView()
|
||||
|
||||
const [search, setSearch] = useState("")
|
||||
const [typeFilter, setTypeFilter] = useState<CommType | "all">("all")
|
||||
const [copied, setCopied] = useState<string | null>(null)
|
||||
const [selected, setSelected] = useState<Community | null>(null)
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
|
||||
const listData = useMemo((): Community[] => {
|
||||
if (!useEvoCatalog) return COMMUNITIES
|
||||
if (mode === "mock") return COMMUNITIES
|
||||
if (loading && !snapshot) return []
|
||||
return snapshot?.communities ?? []
|
||||
}, [useEvoCatalog, loading, snapshot])
|
||||
}, [mode, loading, snapshot])
|
||||
|
||||
useEffect(() => {
|
||||
setSelected(null)
|
||||
}, [useEvoCatalog])
|
||||
const selected = known ? listData.find(row => row.id === selectedId) ?? null : null
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
const q = search.toLowerCase()
|
||||
@@ -138,8 +136,7 @@ export default function CommunitiesPage() {
|
||||
<div className="flex flex-col h-full">
|
||||
<PageHeader
|
||||
crumbs={[{ label: "Данные" }, { label: "Communities" }]}
|
||||
actions={
|
||||
<Button size="sm">
|
||||
actions={mode === "live" ? null : <Button size="sm">
|
||||
<PlusIcon className="size-4" />Добавить
|
||||
</Button>
|
||||
}
|
||||
@@ -147,19 +144,7 @@ export default function CommunitiesPage() {
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-6">
|
||||
<div className="flex flex-col gap-5">
|
||||
{useEvoCatalog && (
|
||||
<p className={cn(
|
||||
"text-xs flex items-center gap-1.5 -mt-1",
|
||||
error ? "text-destructive" : "text-muted-foreground",
|
||||
)}>
|
||||
{loading && <LoaderCircleIcon className="size-3.5 animate-spin shrink-0" />}
|
||||
{error
|
||||
? `EvoBGP: ${error}`
|
||||
: snapshot?.fetchedAt
|
||||
? `Источник: EvoBGP, обновлено ${new Date(snapshot.fetchedAt).toLocaleString("ru-RU")}`
|
||||
: loading ? "Загрузка EvoBGP…" : "EvoBGP"}
|
||||
</p>
|
||||
)}
|
||||
<EvoBgpCatalogStatus />
|
||||
|
||||
<KpiStatGrid
|
||||
aria-label="Сводка communities"
|
||||
@@ -167,35 +152,35 @@ export default function CommunitiesPage() {
|
||||
{
|
||||
id: "all",
|
||||
label: "Всего communities",
|
||||
value: String(listData.length),
|
||||
value: known ? String(listData.length) : "—",
|
||||
icon: <TagIcon className="size-4" />,
|
||||
iconClassName: "text-muted-foreground",
|
||||
},
|
||||
{
|
||||
id: "enabled",
|
||||
label: "Активных",
|
||||
value: String(listData.filter((c) => c.enabled).length),
|
||||
value: known ? String(listData.filter((c) => c.enabled).length) : "—",
|
||||
icon: <CheckIcon className="size-4" />,
|
||||
iconClassName: "text-success",
|
||||
},
|
||||
{
|
||||
id: "standard",
|
||||
label: "Стандартных",
|
||||
value: String(listData.filter((c) => c.type === "standard").length),
|
||||
value: known ? String(listData.filter((c) => c.type === "standard").length) : "—",
|
||||
icon: <TagIcon className="size-4" />,
|
||||
iconClassName: "text-info",
|
||||
},
|
||||
{
|
||||
id: "filters",
|
||||
label: "Использует фильтры",
|
||||
value: String(new Set(listData.flatMap((c) => c.filterIds)).size),
|
||||
value: mode === "mock" ? String(new Set(listData.flatMap((c) => c.filterIds)).size) : "—",
|
||||
icon: <FilterIcon className="size-4" />,
|
||||
iconClassName: "text-primary",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-[1fr_320px] gap-5">
|
||||
<div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_320px] gap-5">
|
||||
{/* ── main table ── */}
|
||||
<div className="flex flex-col gap-3">
|
||||
{/* toolbar */}
|
||||
@@ -204,7 +189,7 @@ export default function CommunitiesPage() {
|
||||
<SearchIcon className="absolute left-2.5 top-2 size-4 text-muted-foreground" />
|
||||
<Input className="pl-8 h-8 text-sm" placeholder="Поиск community…" value={search} onChange={e => setSearch(e.target.value)} />
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{(["all", "standard", "no-export", "no-advertise", "custom"] as const).map(t => (
|
||||
<Button key={t} size="sm" variant={typeFilter === t ? "default" : "outline"}
|
||||
className="h-8 text-xs px-2.5" onClick={() => setTypeFilter(t)}>
|
||||
@@ -216,13 +201,13 @@ export default function CommunitiesPage() {
|
||||
|
||||
{/* list */}
|
||||
<DataPageCard>
|
||||
<CommunitiesDataGrid
|
||||
{known ? <CommunitiesDataGrid
|
||||
communities={filtered}
|
||||
selectedId={selected?.id}
|
||||
copiedValue={copied}
|
||||
onSelect={setSelected}
|
||||
onSelect={row => setSelectedId(row.id)}
|
||||
onCopy={handleCopy}
|
||||
/>
|
||||
/> : <EvoBgpCatalogUnavailable />}
|
||||
</DataPageCard>
|
||||
</div>
|
||||
|
||||
@@ -234,8 +219,8 @@ export default function CommunitiesPage() {
|
||||
description={selected.name}
|
||||
headerRight={
|
||||
<div className="flex gap-1 shrink-0">
|
||||
<Button size="sm" variant="ghost" className="size-7 p-0"><PencilIcon className="size-3.5" /></Button>
|
||||
<Button size="sm" variant="ghost" className="size-7 p-0 text-destructive hover:text-destructive"><TrashIcon className="size-3.5" /></Button>
|
||||
<Button size="sm" variant="ghost" aria-label="Изменить community" disabled className="size-7 p-0"><PencilIcon className="size-3.5" /></Button>
|
||||
<Button size="sm" variant="ghost" aria-label="Удалить community" disabled className="size-7 p-0 text-destructive hover:text-destructive"><TrashIcon className="size-3.5" /></Button>
|
||||
</div>
|
||||
}
|
||||
contentClassName="flex flex-col gap-4 text-sm px-5 pb-5"
|
||||
|
||||
Reference in new issue
Block a user