refactor(frontend): P3 — K8s 组件拆分、AlertCenter Query、permission utils

- 拆分 DeploymentView / DeploymentDetail 至子目录(<700 行红线)
- AlertCenter 接入 useAlerts / useAgentAlertRules / useAlertMutations
- 新增 utils/permission.ts,usePermission 复用纯函数
- useAlerts 增强分页统计与 Agent 规则 hooks
This commit is contained in:
Logan.Li committed 2026-06-26 10:51:15 +08:00
1 parent 37c657987b
commit 521bfd356f
24 files changed
+1454 -1221

No files matched your search

@@ -0,0 +1,88 @@
// deployment-view/PodsTab.tsx — 容器组 Tab // Logan.Li
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import {
ChevronDown, ChevronRight, Terminal, FileText, HardDrive,
} from 'lucide-react';
import { formatK8sTime, statusColor } from '../k8s-yaml-utils';
import { getPodTimeline, PodConditionsRow } from './helpers';
import type { DeploymentViewProps } from './types';
export function PodsTab({
clusterCode, pods, onShowPodLogs, onShowPodTerminal, onShowPodFileBrowser,
expandedPod, setExpandedPod,
}: DeploymentViewProps & { expandedPod: string | null; setExpandedPod: (v: string | null) => void }) {
if (pods.length === 0) {
return <div className="text-center text-[var(--dg-text-muted)] py-12">暂无容器组</div>;
}
return (
<div className="space-y-2">
{pods.map(pod => {
const tl = getPodTimeline(pod);
const expanded = expandedPod === pod.name;
const nodeName = pod.node_name || pod.node;
return (
<Card key={pod.name} className="dg-card">
<CardContent className="p-4">
{/* Pod header row */}
<div className="flex items-center gap-3">
<Button variant="ghost" size="icon" className="h-6 w-6 text-[var(--dg-text-muted)]" onClick={() => setExpandedPod(expanded ? null : pod.name)}>
{expanded ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
</Button>
<span className="font-mono text-sm text-[var(--dg-text-primary)]">{pod.name}</span>
<Badge style={{ background: `${statusColor(pod.status)}22`, color: statusColor(pod.status), border: `1px solid ${statusColor(pod.status)}44` }}>
{pod.status || 'Unknown'}
</Badge>
<span className="text-xs text-[var(--dg-text-muted)]">
<button className="text-[var(--dg-blue)] hover:underline mr-2" onClick={() => window.open(`/kubernetes/${clusterCode}/nodes/${nodeName}`, '_blank')}>
{nodeName || '-'}
</button>
</span>
<span className="text-xs font-mono text-[var(--dg-text-muted)]">{pod.ip || pod.pod_ip || '-'}</span>
<span className="text-xs text-[var(--dg-text-muted)]">重启 {pod.restart_count || 0} 次</span>
<span className="text-xs text-[var(--dg-text-muted)]">{formatK8sTime(tl.startTime || pod.created_at)}</span>
<div className="flex-1" />
<Button variant="ghost" size="sm" className="h-7 text-xs text-[var(--dg-blue)]" onClick={() => onShowPodLogs(pod)}>
<FileText className="h-3.5 w-3.5 mr-1" />日志
</Button>
<Button variant="ghost" size="sm" className="h-7 text-xs text-emerald-400" onClick={() => onShowPodTerminal(pod)}>
<Terminal className="h-3.5 w-3.5 mr-1" />终端
</Button>
<Button variant="ghost" size="sm" className="h-7 text-xs text-amber-400" onClick={() => onShowPodFileBrowser(pod)}>
<HardDrive className="h-3.5 w-3.5 mr-1" />文件
</Button>
</div>
{/* Expanded: timeline */}
{expanded && (
<div className="mt-3 pt-3 border-t border-[var(--dg-border)]">
<PodConditionsRow pod={pod} />
{/* Container details */}
{(pod as Record<string, any>).containers && ((pod as Record<string, any>).containers as any[]).length > 0 && (
<div className="mt-3 grid grid-cols-1 md:grid-cols-2 gap-2">
{((pod as Record<string, any>).containers as any[]).map((c: any, idx: number) => (
<div key={idx} className="p-2 rounded bg-[var(--dg-bg-tertiary)] text-xs">
<div className="flex items-center justify-between">
<span className="font-medium text-[var(--dg-text-primary)]">{c.name}</span>
<span className={c.ready ? 'text-emerald-400' : 'text-[var(--dg-text-muted)]'}>{c.ready ? 'Ready' : 'Pending'}</span>
</div>
<div className="text-[var(--dg-text-muted)] mt-1">{c.image}</div>
{c.resources && (
<div className="mt-1 flex gap-3">
<span>CPU: {c.resources?.requests?.cpu || '0'}/{c.resources?.limits?.cpu || '-'} m</span>
<span>内存: {c.resources?.requests?.memory || '0'}/{c.resources?.limits?.memory || '-'}</span>
</div>
)}
</div>
))}
</div>
)}
</div>
)}
</CardContent>
</Card>
);
})}
</div>
);
}