fix(evolution): исключить моковые данные из живого каталога

This commit is contained in:
Denozordec committed 2026-10-03 14:08:44 +07:00
1 parent 118cd31d65
commit d272ef57f0
17 files changed
+155 -136

No files matched your search

+3 -2
View File
@@ -12,6 +12,7 @@ import {
} from "@/components/ui/sidebar"
import { navigationGroups } from "@/lib/navigation"
import { useDataSource } from "@/lib/data-source"
import { can } from "@/lib/auth"
import { useEvoBGP } from "@/lib/evobgp-context"
import { requestJson } from "@/shared/api/http-client"
import {
@@ -78,7 +79,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
if (mode !== "live") return mockBadges[url]
if (url === "/domains" || url === "/ip-ranges" || url === "/asns") {
if (!evo.enabled) return undefined
if (!evo.settingsLoaded || !evo.enabled || !can("mm:settings:admin")) return undefined
if (!evo.snapshot) return undefined
if (url === "/domains") return formatSidebarBadgeCount(evo.snapshot.domains.length)
if (url === "/ip-ranges") return formatSidebarBadgeCount(evo.snapshot.ipRanges.length)
@@ -111,7 +112,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
badge: mounted ? badgeFor(it.url) : undefined,
})),
}))
}, [mounted, mode, liveCounts, mockBadges, evo.enabled, evo.snapshot])
}, [mounted, mode, liveCounts, mockBadges, evo.settingsLoaded, evo.enabled, evo.snapshot])
return (
<Sidebar collapsible="icon" {...props}>
+3 -2
View File
@@ -21,10 +21,11 @@ import { FilterIcon, NetworkIcon } from "lucide-react"
interface AsnsDataGridProps {
asns: Asn[]
isLoading?: boolean
emptyDescription?: string
pagination?: boolean
}
function AsnsDataGrid({ asns, isLoading, pagination = false }: AsnsDataGridProps) {
function AsnsDataGrid({ asns, isLoading, pagination = false, emptyDescription }: AsnsDataGridProps) {
const columns = useMemo<ColumnDef<DataGridFeatures, Asn>[]>(
() => [
{
@@ -133,7 +134,7 @@ function AsnsDataGrid({ asns, isLoading, pagination = false }: AsnsDataGridProps
<EmptyState
icon={<NetworkIcon className="size-4" />}
title="Нет ASN"
description="Добавьте автономные системы или импортируйте каталог"
description={emptyDescription ?? "Добавьте автономные системы или импортируйте каталог"}
className="border-0 py-12"
/>
}
+3 -2
View File
@@ -21,10 +21,11 @@ import { FilterIcon, GlobeIcon } from "lucide-react"
interface DomainsDataGridProps {
domains: Domain[]
isLoading?: boolean
emptyDescription?: string
pagination?: boolean
}
function DomainsDataGrid({ domains, isLoading, pagination = false }: DomainsDataGridProps) {
function DomainsDataGrid({ domains, isLoading, pagination = false, emptyDescription }: DomainsDataGridProps) {
const columns = useMemo<ColumnDef<DataGridFeatures, Domain>[]>(
() => [
{
@@ -142,7 +143,7 @@ function DomainsDataGrid({ domains, isLoading, pagination = false }: DomainsData
<EmptyState
icon={<GlobeIcon className="size-4" />}
title="Нет доменов"
description="Добавьте домены или импортируйте каталог"
description={emptyDescription ?? "Добавьте домены или импортируйте каталог"}
className="border-0 py-12"
/>
}
@@ -21,10 +21,11 @@ import { FilterIcon, NetworkIcon } from "lucide-react"
interface IpRangesDataGridProps {
ipRanges: IpRange[]
isLoading?: boolean
emptyDescription?: string
pagination?: boolean
}
function IpRangesDataGrid({ ipRanges, isLoading, pagination = false }: IpRangesDataGridProps) {
function IpRangesDataGrid({ ipRanges, isLoading, pagination = false, emptyDescription }: IpRangesDataGridProps) {
const columns = useMemo<ColumnDef<DataGridFeatures, IpRange>[]>(
() => [
{
@@ -144,7 +145,7 @@ function IpRangesDataGrid({ ipRanges, isLoading, pagination = false }: IpRangesD
<EmptyState
icon={<NetworkIcon className="size-4" />}
title="Нет IP-диапазонов"
description="Добавьте CIDR-блоки или импортируйте каталог"
description={emptyDescription ?? "Добавьте CIDR-блоки или импортируйте каталог"}
className="border-0 py-12"
/>
}
@@ -0,0 +1,29 @@
"use client"
import Link from "next/link"
import {useDataSource} from "@/lib/data-source"
import {useEvoBGP} from "@/lib/evobgp-context"
import {can} from "@/lib/auth"
import {Alert,AlertTitle,AlertDescription} from "@/components/reui/alert"
import {Button} from "@/components/ui/button"
import {EmptyState} from "@/components/empty-state"
import {AlertCircleIcon} from "lucide-react"
export function useEvoCatalogView(){
const {mode,backendStatus}=useDataSource(),evo=useEvoBGP()
const allowed=can("mm:settings:admin")
const snapshot=mode==="live"&&allowed&&evo.enabled?evo.snapshot:null
return {evo,mode,backendStatus,allowed,snapshot,known:mode==="mock"||!!snapshot,loading:mode==="live"&&allowed&&!snapshot&&(evo.settingsLoading||evo.loading)}
}
export function EvoBgpCatalogStatus(){
const {evo,mode,backendStatus,allowed,snapshot}=useEvoCatalogView()
if(mode==="mock")return <p role="status" className="text-xs text-muted-foreground">Демонстрационный каталог</p>
const reason=!allowed?"Нет доступа к каталогу EvoBGP":!evo.settingsLoaded?evo.settingsLoading?"Загрузка настроек EvoBGP…":"Настройки EvoBGP неизвестны":!evo.enabled?"Интеграция EvoBGP выключена":!snapshot?evo.loading?"Загрузка каталога EvoBGP…":"Каталог EvoBGP не получен":null
const error=evo.settingsError||evo.catalogError
return <div className="flex min-w-0 flex-col gap-3">
{reason?<p role="status" className="text-sm">{reason}</p>:null}
{snapshot?<p role="status" className="text-xs text-muted-foreground">Каталог EvoBGP получен: {evo.catalogReceivedAt?new Date(evo.catalogReceivedAt).toLocaleString("ru-RU"):"—"}{evo.loading?" · обновление…":""}</p>:null}
{error?<Alert variant="warning"><AlertCircleIcon aria-hidden="true"/><AlertTitle>{snapshot?"Каталог не обновлён; показаны последние данные":"Каталог EvoBGP недоступен"}</AlertTitle><AlertDescription>{[evo.settingsError,evo.catalogError].filter(Boolean).join("; ")}</AlertDescription></Alert>:null}
{allowed?<div className="flex flex-wrap gap-2"><Button size="sm" variant="outline" disabled={backendStatus!==true||evo.settingsLoading||evo.loading||evo.operationBusy} onClick={()=>{if(!evo.settingsLoaded||!evo.enabled||evo.settingsError)void evo.loadSettings();else void evo.refresh()}}>Обновить каталог EvoBGP</Button><Link className="text-sm underline underline-offset-4" href="/settings">Настройки → EvoBGP</Link></div>:null}
</div>
}
export function EvoBgpCatalogUnavailable(){return <EmptyState title="Данные каталога не получены" description="Состояние загрузки указано выше. Число записей пока неизвестно." className="py-10"/>}