import { createFileRoute } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' import { Bird, RefreshCw } from 'lucide-react' import { Button } from '@evobgp/ui/components/button' import { Progress } from '@evobgp/ui/components/progress' import { MonitoringHealthCard } from '@/components/analytics' import { MonitoringReadyGrid } from '@/components/monitoring/monitoring-ready-grid' import { PageHeader } from '@/components/page-header' import { QueryState } from '@/components/query-state' import { FrameSection } from '@/components/reui-kit' import { StatusBadge } from '@/components/status-badge' import { jobKindRu } from '@/lib/ui-labels' import { monitoringHealthQueryOptions, monitoringReadyQueryOptions, monitoringVersionQueryOptions, type VersionInfo, } from '@/queries/monitoring' import { networkBirdQueryOptions } from '@/queries/network' import { operationsJobsQueryOptions } from '@/queries/operations' export const Route = createFileRoute('/_auth/monitoring')({ component: MonitoringComponent, }) function MonitoringComponent() { const healthQ = useQuery(monitoringHealthQueryOptions()) const readyQ = useQuery(monitoringReadyQueryOptions()) const versionQ = useQuery(monitoringVersionQueryOptions()) const birdQ = useQuery(networkBirdQueryOptions()) const jobsQ = useQuery(operationsJobsQueryOptions()) const refreshing = healthQ.isFetching || readyQ.isFetching || versionQ.isFetching || birdQ.isFetching || jobsQ.isFetching const jobs = jobsQ.data?.items ?? [] const versionText = formatVersion(versionQ.data) function refetchAll() { void healthQ.refetch() void readyQ.refetch() void versionQ.refetch() void birdQ.refetch() void jobsQ.refetch() } const failedJobs = jobs .filter((j) => ['failed', 'error', 'cancelled'].includes(j.status.toLowerCase())) .slice(0, 5) return (
Обновить } />
BGP на API-хосте } description="Статус BIRD на хосте API" className="h-full" contentClassName="px-5 py-4" > } onRetry={() => birdQ.refetch()} > {(bird) => }
} onRetry={() => readyQ.refetch()} > {(ready) => } {failedJobs.length > 0 ? (
    {failedJobs.map((job) => (
  • {jobKindRu(job.kind)}

    {job.error ? (

    {job.error.slice(0, 120)} {job.error.length > 120 ? '…' : ''}

    ) : null}
  • ))}
) : null}
) } function formatVersion(version?: VersionInfo | null): string { if (!version) return '—' return version.version ?? version.app ?? '—' } function BirdSummary({ bird }: { bird: import('@/types/api').BirdStatus }) { if (!bird.birdc_configured) { return (

{bird.message ?? 'birdc не настроен на API-хосте (EVOBGP_BIRDC_SOCKET).'}

) } const ratio = bird.bgp_sessions_total > 0 ? Math.round((bird.bgp_established / bird.bgp_sessions_total) * 100) : null return (
Установлено / всего {bird.bgp_established} / {bird.bgp_sessions_total} {ratio !== null ? ({ratio}%) : null}
{ratio !== null ? ( = 100 ? '[&_[data-slot=progress-indicator]]:bg-success' : ratio >= 50 ? '[&_[data-slot=progress-indicator]]:bg-warning' : '[&_[data-slot=progress-indicator]]:bg-destructive' } /> ) : null} {bird.error ?

{bird.error}

: null}
) }