import { useState, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Cloud, XCircle } from 'lucide-react'; import { kubernetesApi } from '@/api'; import type { JsonData } from '@/types/common'; import { computeClusterMetrics, buildTrendData } from './cluster-detail/types'; import { OverviewTab } from './cluster-detail/OverviewTab'; import { NodesTab } from './cluster-detail/NodesTab'; import { PodsTab } from './cluster-detail/PodsTab'; import { DeploymentsTab } from './cluster-detail/DeploymentsTab'; import { ServicesTab } from './cluster-detail/ServicesTab'; import { IngressesTab } from './cluster-detail/IngressesTab'; import { EventsTab } from './cluster-detail/EventsTab'; export function KubernetesClusterDetail({ cluster, onClose }: { cluster?: JsonData; onClose: () => void }) { const { t } = useTranslation(); const [nodes, setNodes] = useState([]); const [pods, setPods] = useState([]); const [deployments, setDeployments] = useState([]); const [services, setServices] = useState([]); const [ingresses, setIngresses] = useState([]); // 从节点数据计算集群级 CPU/内存使用率(实时快照) const clusterMetrics = useMemo(() => computeClusterMetrics(nodes), [nodes]); // 构造趋势数据(多点),避免单点导致"光点"效果 const trendData = useMemo(() => buildTrendData(clusterMetrics, t), [clusterMetrics, t]); const loadClusterDetail = async (clusterCode: string) => { try { // 后端 ListNodes/ListPods/etc 返回 data 直接为数组(非 {list,total}) // 统一使用 Kuboard code 路由 (ROADMAP A1) const [nodesRes, podsRes, depRes, svcRes, ingRes] = await Promise.all([ kubernetesApi.getNodes(clusterCode).catch(() => []), kubernetesApi.getPods(clusterCode).catch(() => []), kubernetesApi.getDeployments(clusterCode).catch(() => []), kubernetesApi.getServices(clusterCode).catch(() => []), kubernetesApi.getIngresses(clusterCode).catch(() => []), ]); const toArray = (v: JsonData) => (Array.isArray(v) ? v : (v?.list || [])); setNodes(toArray(nodesRes)); setPods(toArray(podsRes)); setDeployments(toArray(depRes)); setServices(toArray(svcRes)); setIngresses(toArray(ingRes)); } catch { // load failed } }; useEffect(() => { if (cluster?.code) { // eslint-disable-next-line react-hooks/set-state-in-effect loadClusterDetail(cluster.code); } }, [cluster?.code]); return (
{cluster.name} {cluster.version} · {cluster.node_count || 0} {t('k8s.cluster.nodeCount')} · {t('k8s.cluster.created')}{' '} {cluster.created_at ? new Date(cluster.created_at).toLocaleDateString() : '-'}
{t('k8s.tab.overview')} {t('k8s.tab.nodes')} ({nodes.length}) {t('k8s.tab.pods')} ({pods.length}) {t('k8s.tab.deployments')} ({deployments.length}) {t('k8s.tab.services')} ({services.length}) {t('k8s.tab.ingresses')} ({ingresses.length}) {t('k8s.tab.events')} cluster?.id && loadClusterDetail(cluster.id)} />
); }