1.30
This commit is contained in:
parent
4ca37a506d
commit
7e9587c6e7
@ -108,8 +108,8 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
// 展开时启动10秒轮询
|
||||
useAutoRefresh(loadPods, 10000, isExpanded);
|
||||
|
||||
const ready = deployment.readyReplicas ?? 0;
|
||||
const desired = deployment.replicas ?? 0;
|
||||
const ready = deployment.readyPodCount ?? 0;
|
||||
const desired = deployment.actualPodCount ?? 0;
|
||||
|
||||
// 重启Deployment
|
||||
const handleRestart = async () => {
|
||||
@ -186,7 +186,7 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const hasReplicas = (deployment.replicas ?? 0) > 0;
|
||||
const hasReplicas = (deployment.actualPodCount ?? 0) > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -211,15 +211,62 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
) : (
|
||||
<div className="h-6 w-6" />
|
||||
)}
|
||||
<Layers className="h-4 w-4 text-blue-600" />
|
||||
<span className="font-medium">{deployment.deploymentName}</span>
|
||||
<Layers className="h-4 w-4 text-blue-600 flex-shrink-0" />
|
||||
<span className="font-medium whitespace-nowrap">{deployment.deploymentName}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<HealthBar deployment={deployment} />
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="text-sm font-mono text-gray-700">{ready}/{desired}</span>
|
||||
<span className="text-sm font-mono text-gray-700 whitespace-nowrap">{ready}/{desired}</span>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center gap-1 whitespace-nowrap">
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">
|
||||
运行:{deployment.runningPodCount ?? 0}
|
||||
</span>
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-800">
|
||||
等待:{deployment.pendingPodCount ?? 0}
|
||||
</span>
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800">
|
||||
失败:{deployment.failedPodCount ?? 0}
|
||||
</span>
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800">
|
||||
成功:{deployment.succeededPodCount ?? 0}
|
||||
</span>
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-800">
|
||||
未知:{deployment.unknownPodCount ?? 0}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="text-xs space-y-1">
|
||||
<div>实际Pod总数: {deployment.actualPodCount ?? 0}</div>
|
||||
<div className="text-green-600">Running: {deployment.runningPodCount ?? 0}</div>
|
||||
<div className="text-yellow-600">Pending: {deployment.pendingPodCount ?? 0}</div>
|
||||
<div className="text-red-600">Failed: {deployment.failedPodCount ?? 0}</div>
|
||||
<div className="text-blue-600">Succeeded: {deployment.succeededPodCount ?? 0}</div>
|
||||
<div className="text-gray-600">Unknown: {deployment.unknownPodCount ?? 0}</div>
|
||||
<div className="border-t pt-1 mt-1">Ready: {deployment.readyPodCount ?? 0}</div>
|
||||
<div>Not Ready: {deployment.notReadyPodCount ?? 0}</div>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<div className="text-xs text-gray-600 space-y-1 whitespace-nowrap">
|
||||
<div>
|
||||
<span className="font-medium">CPU:</span> {deployment.totalCpuRequest || '-'} / {deployment.totalCpuLimit || '-'}
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-medium">内存:</span> {deployment.totalMemoryRequest || '-'} / {deployment.totalMemoryLimit || '-'}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="text-sm text-gray-600 font-mono truncate block max-w-xs" title={deployment.image}>
|
||||
@ -227,11 +274,13 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="text-sm text-gray-600">0</span>
|
||||
<span className={`text-sm font-mono ${(deployment.totalRestartCount ?? 0) > 10 ? 'text-red-600 font-bold' : 'text-gray-600'}`}>
|
||||
{deployment.totalRestartCount ?? 0}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="text-sm text-gray-600">
|
||||
{deployment.k8sUpdateTime ? dayjs(deployment.k8sUpdateTime).fromNow() : '-'}
|
||||
<span className="text-sm text-gray-600 whitespace-nowrap">
|
||||
{deployment.k8sCreateTime ? dayjs(deployment.k8sCreateTime).format('YYYY-MM-DD HH:mm:ss') : '-'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 sticky right-0 bg-background shadow-[-2px_0_4px_rgba(0,0,0,0.05)]" onClick={(e) => e.stopPropagation()}>
|
||||
@ -321,7 +370,7 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
</>
|
||||
) : pods.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={7} className="px-6 py-4 text-center text-gray-500">
|
||||
<td colSpan={9} className="px-6 py-4 text-center text-gray-500">
|
||||
此Deployment下暂无Pod
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -31,13 +31,15 @@ export const DeploymentTable: React.FC<DeploymentTableProps> = ({
|
||||
<table className="w-full caption-bottom text-sm" style={{ minWidth: '1200px' }}>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-64">名称</TableHead>
|
||||
<TableHead className="w-32">健康条</TableHead>
|
||||
<TableHead className="w-24">副本</TableHead>
|
||||
<TableHead className="w-80">镜像</TableHead>
|
||||
<TableHead className="w-24">重启</TableHead>
|
||||
<TableHead className="w-32">更新时间</TableHead>
|
||||
<TableHead className="w-20 sticky right-0 bg-background shadow-[-2px_0_4px_rgba(0,0,0,0.05)]">操作</TableHead>
|
||||
<TableHead style={{ width: '280px', minWidth: '280px' }}>名称</TableHead>
|
||||
<TableHead style={{ width: '150px', minWidth: '150px' }}>健康条</TableHead>
|
||||
<TableHead style={{ width: '80px', minWidth: '80px' }}>副本</TableHead>
|
||||
<TableHead style={{ width: '280px', minWidth: '280px' }}>Pod状态</TableHead>
|
||||
<TableHead style={{ width: '200px', minWidth: '200px' }}>资源配额</TableHead>
|
||||
<TableHead style={{ width: '350px', minWidth: '350px' }}>镜像</TableHead>
|
||||
<TableHead style={{ width: '80px', minWidth: '80px' }}>重启</TableHead>
|
||||
<TableHead style={{ width: '180px', minWidth: '180px' }}>创建时间</TableHead>
|
||||
<TableHead className="sticky right-0 bg-background shadow-[-2px_0_4px_rgba(0,0,0,0.05)]" style={{ width: '150px', minWidth: '150px' }}>操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import type { K8sDeploymentResponse } from '../types';
|
||||
import { getDeploymentHealth, HealthStatus } from '../types';
|
||||
|
||||
@ -7,8 +13,8 @@ interface HealthBarProps {
|
||||
}
|
||||
|
||||
export const HealthBar: React.FC<HealthBarProps> = ({ deployment }) => {
|
||||
const ready = deployment.readyReplicas ?? 0;
|
||||
const desired = deployment.replicas ?? 0;
|
||||
const ready = deployment.readyPodCount ?? 0;
|
||||
const desired = deployment.actualPodCount ?? 0;
|
||||
const percentage = desired > 0 ? (ready / desired) * 100 : 100;
|
||||
const health = getDeploymentHealth(deployment);
|
||||
|
||||
@ -26,13 +32,37 @@ export const HealthBar: React.FC<HealthBarProps> = ({ deployment }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="h-2 bg-gray-200 rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full ${getBarColor()} transition-all duration-300`}
|
||||
style={{ width: `${percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="w-full cursor-help">
|
||||
<div className="h-2 bg-gray-200 rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full ${getBarColor()} transition-all duration-300`}
|
||||
style={{ width: `${percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="text-xs space-y-1">
|
||||
<div className="font-semibold">Pod状态详情</div>
|
||||
<div>就绪/期望: {ready}/{desired}</div>
|
||||
{deployment.actualPodCount !== undefined && (
|
||||
<>
|
||||
<div className="border-t pt-1 mt-1">实际Pod总数: {deployment.actualPodCount}</div>
|
||||
<div className="text-green-600">Running: {deployment.runningPodCount ?? 0}</div>
|
||||
<div className="text-yellow-600">Pending: {deployment.pendingPodCount ?? 0}</div>
|
||||
<div className="text-red-600">Failed: {deployment.failedPodCount ?? 0}</div>
|
||||
<div className="text-blue-600">Succeeded: {deployment.succeededPodCount ?? 0}</div>
|
||||
<div className="text-gray-600">Unknown: {deployment.unknownPodCount ?? 0}</div>
|
||||
<div className="border-t pt-1 mt-1">Ready: {deployment.readyPodCount ?? 0}</div>
|
||||
<div>Not Ready: {deployment.notReadyPodCount ?? 0}</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -59,8 +59,8 @@ export const PodRow: React.FC<PodRowProps> = ({ pod, deploymentId, onViewLogs })
|
||||
return (
|
||||
<>
|
||||
<tr className="border-t border-gray-100 bg-gray-50/50 hover:bg-gray-100/50">
|
||||
{/* Pod信息列(占6列) */}
|
||||
<td className="px-6 py-4 bg-gray-50/50" colSpan={6}>
|
||||
{/* Pod信息列(占8列) */}
|
||||
<td className="px-6 py-4 bg-gray-50/50" colSpan={8}>
|
||||
<div className="pl-8 space-y-3">
|
||||
{/* 第一行:Pod名称 + 状态 */}
|
||||
<div className="flex items-center gap-4">
|
||||
|
||||
@ -21,6 +21,9 @@ export const StatsCards: React.FC<StatsCardsProps> = ({ deployments }) => {
|
||||
if (health === HealthStatus.HEALTHY) healthy++;
|
||||
else if (health === HealthStatus.WARNING) warning++;
|
||||
else if (health === HealthStatus.CRITICAL) critical++;
|
||||
|
||||
// 累加总重启次数
|
||||
totalRestarts += deployment.totalRestartCount ?? 0;
|
||||
});
|
||||
|
||||
return { total, healthy, warning, critical, totalRestarts };
|
||||
|
||||
@ -104,6 +104,36 @@ export interface K8sDeploymentResponse extends BaseResponse {
|
||||
k8sUpdateTime?: string;
|
||||
/** YAML配置 */
|
||||
yamlConfig?: string;
|
||||
|
||||
// Pod统计字段
|
||||
/** 总重启次数 */
|
||||
totalRestartCount?: number;
|
||||
/** 实际Pod总数 */
|
||||
actualPodCount?: number;
|
||||
/** Running状态Pod数 */
|
||||
runningPodCount?: number;
|
||||
/** Pending状态Pod数 */
|
||||
pendingPodCount?: number;
|
||||
/** Failed状态Pod数 */
|
||||
failedPodCount?: number;
|
||||
/** Succeeded状态Pod数 */
|
||||
succeededPodCount?: number;
|
||||
/** Unknown状态Pod数 */
|
||||
unknownPodCount?: number;
|
||||
/** Ready状态Pod数 */
|
||||
readyPodCount?: number;
|
||||
/** Not Ready状态Pod数 */
|
||||
notReadyPodCount?: number;
|
||||
|
||||
// Pod资源统计
|
||||
/** CPU请求总和 */
|
||||
totalCpuRequest?: string;
|
||||
/** 内存请求总和 */
|
||||
totalMemoryRequest?: string;
|
||||
/** CPU限制总和 */
|
||||
totalCpuLimit?: string;
|
||||
/** 内存限制总和 */
|
||||
totalMemoryLimit?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -392,8 +422,8 @@ export enum HealthStatus {
|
||||
* 计算Deployment健康状态
|
||||
*/
|
||||
export const getDeploymentHealth = (deployment: K8sDeploymentResponse): HealthStatus => {
|
||||
const ready = deployment.readyReplicas ?? 0;
|
||||
const desired = deployment.replicas ?? 0;
|
||||
const ready = deployment.readyPodCount ?? 0;
|
||||
const desired = deployment.actualPodCount ?? 0;
|
||||
|
||||
if (desired === 0) return HealthStatus.HEALTHY;
|
||||
if (ready === 0) return HealthStatus.CRITICAL;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user