Обновлены переводы на русский язык для различных компонентов, включая KPI, карточки сети и панели управления. Исправлены описания и метки для улучшения пользовательского интерфейса. Также добавлены новые элементы для поддержки локализации в компонентах, таких как DataGrid и ResourcePage. Co-authored-by: Cursor <[email protected]>
81 lines
2.5 KiB
TypeScript
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}`
|
|
}
|
|
/>
|
|
)
|
|
}
|