Files
EvoBGP/apps/web/src/components/dashboard/dashboard-network-health.tsx
T
DenozordecandCursor 35e262b5ae
CI / changes (push) Successful in 9s
CI / commitlint (push) Skipped
CI / go (push) Skipped
CI / bird2 (push) Skipped
CI / openapi (push) Successful in 47s
CI / web (push) Successful in 1m4s
CI / release (push) Successful in 5m19s
fix(web): update Russian translations and improve UI components
Обновлены переводы на русский язык для различных компонентов, включая KPI, карточки сети и панели управления. Исправлены описания и метки для улучшения пользовательского интерфейса. Также добавлены новые элементы для поддержки локализации в компонентах, таких как DataGrid и ResourcePage.

Co-authored-by: Cursor <[email protected]>
2026-08-18 00:32:00 +07:00

81 lines
2.5 KiB
TypeScript

import { useMemo, useState } from 'react'
import { AnalyticsSegmentControl } from '@/components/analytics/analytics-segment-control'
import { SegmentedProgressCard } from '@/components/patterns/segmented-progress-card'
import { Badge } from '@/components/reui/badge'
import {
capacityUtilization,
peerCapacityBars,
speakerCapacityBars,
} from '@/lib/metrics'
import { runningJobCount } from '@/queries/overview'
import type { JobRow, PeerRow, SpeakerRow } from '@/types/api'
type CapacityMode = 'peers' | 'speakers'
export function DashboardNetworkHealth({
peers,
speakers,
jobs,
loading,
}: {
peers: PeerRow[]
speakers: SpeakerRow[]
jobs: JobRow[]
loading?: boolean
}) {
const [mode, setMode] = useState<CapacityMode>('peers')
const bars = useMemo(
() => (mode === 'peers' ? peerCapacityBars(peers) : speakerCapacityBars(speakers)),
[mode, peers, speakers],
)
const utilization = capacityUtilization(bars)
const queued = runningJobCount(jobs)
const established =
mode === 'peers'
? peers.filter((p) => p.enabled !== false && p.session_state === 'Established').length
: speakers.filter((s) => s.live?.agent_ok).length
const total =
mode === 'peers' ? peers.filter((p) => p.enabled !== false).length : speakers.length
const offline = Math.max(0, total - established)
return (
<SegmentedProgressCard
title="Загрузка BGP"
description="Утилизация сессий по пирам и спикерам"
actions={
<AnalyticsSegmentControl
value={mode}
onChange={setMode}
options={[
{ value: 'peers', label: 'Пиры' },
{ value: 'speakers', label: 'Спикеры' },
]}
/>
}
primary={{
value: loading ? '—' : `${utilization}%`,
label: mode === 'peers' ? 'Утилизация пиров' : 'Спикеры в сети',
percent: loading ? 0 : utilization,
badge: (
<Badge variant="outline" radius="full" className="h-6 px-2 text-[10px]">
{loading ? '…' : `${established}/${total}`}
</Badge>
),
}}
secondary={{
value: loading ? '—' : offline,
label: mode === 'peers' ? 'Не установлены' : 'Не в сети',
percent: total > 0 ? Math.round((offline / total) * 100) : 0,
}}
footer={
loading
? 'Загрузка…'
: `Активных задач: ${queued} · сегментов в графике: ${bars.length}`
}
/>
)
}