1.32
This commit is contained in:
parent
a19b4b8ec8
commit
e70f6c5d41
@ -35,7 +35,7 @@ import { PodRowSkeleton } from './PodRowSkeleton';
|
||||
import { YamlViewerDialog } from './YamlViewerDialog';
|
||||
import { restartK8sDeployment, scaleK8sDeployment, deleteK8sDeployment } from '../service';
|
||||
import type { K8sDeploymentResponse, K8sPodResponse } from '../types';
|
||||
import { getDeploymentHealth, HealthStatusLabels } from '../types';
|
||||
import { getDeploymentHealth } from '../types';
|
||||
import { getK8sPodsByDeployment } from '../service';
|
||||
import { useAutoRefresh } from '../hooks/useAutoRefresh';
|
||||
import { formatCpuPair } from '../utils/resourceFormatter';
|
||||
@ -64,6 +64,7 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
const { toast } = useToast();
|
||||
const [pods, setPods] = useState<K8sPodResponse[]>([]);
|
||||
const [initialLoading, setInitialLoading] = useState(true);
|
||||
const [restartDialogOpen, setRestartDialogOpen] = useState(false);
|
||||
const [scaleDialogOpen, setScaleDialogOpen] = useState(false);
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [yamlDialogOpen, setYamlDialogOpen] = useState(false);
|
||||
@ -130,6 +131,7 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setRestartDialogOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
@ -292,8 +294,7 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleRestart}
|
||||
disabled={loading}
|
||||
onClick={() => setRestartDialogOpen(true)}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<RotateCw className="h-4 w-4" />
|
||||
@ -388,6 +389,28 @@ export const DeploymentRow: React.FC<DeploymentRowProps> = ({
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 重启确认对话框 */}
|
||||
<Dialog open={restartDialogOpen} onOpenChange={setRestartDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>确认重启</DialogTitle>
|
||||
<DialogDescription>
|
||||
确定要重启 Deployment <strong>{deployment.deploymentName}</strong> 吗?
|
||||
这将触发滚动更新,Pod会逐个重启。
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setRestartDialogOpen(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={handleRestart} disabled={loading}>
|
||||
{loading && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
|
||||
确认重启
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 扩缩容对话框 */}
|
||||
<Dialog open={scaleDialogOpen} onOpenChange={setScaleDialogOpen}>
|
||||
<DialogContent>
|
||||
|
||||
129
frontend/src/pages/Resource/K8s/List/utils/resourceFormatter.ts
Normal file
129
frontend/src/pages/Resource/K8s/List/utils/resourceFormatter.ts
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 解析CPU值为核数
|
||||
* @param value CPU字符串,如 "500m" 或 "1" 或 "1.5"
|
||||
* @returns 核数(浮点数)
|
||||
*/
|
||||
export function parseCpu(value: string): number {
|
||||
if (!value) return 0;
|
||||
|
||||
const trimmed = value.trim();
|
||||
|
||||
// 处理毫核(如 "500m")
|
||||
if (trimmed.endsWith('m')) {
|
||||
const milliCores = parseFloat(trimmed.slice(0, -1));
|
||||
return milliCores / 1000;
|
||||
}
|
||||
|
||||
// 处理纯数字(如 "1" 或 "1.5")
|
||||
return parseFloat(trimmed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析内存值为字节数
|
||||
* @param value 内存字符串,如 "512Mi" 或 "1Gi"
|
||||
* @returns 字节数
|
||||
*/
|
||||
export function parseMemory(value: string): number {
|
||||
if (!value) return 0;
|
||||
|
||||
const trimmed = value.trim();
|
||||
const units: Record<string, number> = {
|
||||
'Ki': 1024,
|
||||
'Mi': 1024 * 1024,
|
||||
'Gi': 1024 * 1024 * 1024,
|
||||
'Ti': 1024 * 1024 * 1024 * 1024,
|
||||
'K': 1000,
|
||||
'M': 1000 * 1000,
|
||||
'G': 1000 * 1000 * 1000,
|
||||
'T': 1000 * 1000 * 1000 * 1000,
|
||||
};
|
||||
|
||||
for (const [unit, multiplier] of Object.entries(units)) {
|
||||
if (trimmed.endsWith(unit)) {
|
||||
const value = parseFloat(trimmed.slice(0, -unit.length));
|
||||
return value * multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
// 纯数字,默认为字节
|
||||
return parseFloat(trimmed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化CPU显示(智能统一单位)
|
||||
* @param request CPU请求值
|
||||
* @param limit CPU限制值
|
||||
* @returns 格式化后的字符串,如 "0.5 / 1" 或 "500m / 800m"
|
||||
*/
|
||||
export function formatCpuPair(request?: string, limit?: string): string {
|
||||
if (!request && !limit) return '- / -';
|
||||
if (!request) return `- / ${limit}`;
|
||||
if (!limit) return `${request} / -`;
|
||||
|
||||
const reqCores = parseCpu(request);
|
||||
const limitCores = parseCpu(limit);
|
||||
|
||||
// 如果都小于1核,使用毫核显示
|
||||
if (reqCores < 1 && limitCores < 1) {
|
||||
const reqMilli = Math.round(reqCores * 1000);
|
||||
const limitMilli = Math.round(limitCores * 1000);
|
||||
return `${reqMilli}m / ${limitMilli}m`;
|
||||
}
|
||||
|
||||
// 否则统一使用核数显示
|
||||
const formatCore = (cores: number) => {
|
||||
// 如果是整数,不显示小数点
|
||||
if (cores === Math.floor(cores)) {
|
||||
return cores.toString();
|
||||
}
|
||||
// 保留最多2位小数
|
||||
return cores.toFixed(2).replace(/\.?0+$/, '');
|
||||
};
|
||||
|
||||
return `${formatCore(reqCores)} / ${formatCore(limitCores)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化内存显示(智能统一单位)
|
||||
* @param request 内存请求值
|
||||
* @param limit 内存限制值
|
||||
* @returns 格式化后的字符串,如 "0.5Gi / 1Gi" 或 "512Mi / 1024Mi"
|
||||
*/
|
||||
export function formatMemoryPair(request?: string, limit?: string): string {
|
||||
if (!request && !limit) return '- / -';
|
||||
if (!request) return `- / ${limit}`;
|
||||
if (!limit) return `${request} / -`;
|
||||
|
||||
const reqBytes = parseMemory(request);
|
||||
const limitBytes = parseMemory(limit);
|
||||
|
||||
const units = [
|
||||
{ name: 'Ti', value: 1024 * 1024 * 1024 * 1024 },
|
||||
{ name: 'Gi', value: 1024 * 1024 * 1024 },
|
||||
{ name: 'Mi', value: 1024 * 1024 },
|
||||
{ name: 'Ki', value: 1024 },
|
||||
];
|
||||
|
||||
// 选择合适的单位(以较大值为准)
|
||||
const maxBytes = Math.max(reqBytes, limitBytes);
|
||||
let selectedUnit = units[units.length - 1]; // 默认Ki
|
||||
|
||||
for (const unit of units) {
|
||||
if (maxBytes >= unit.value) {
|
||||
selectedUnit = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const formatValue = (bytes: number) => {
|
||||
const value = bytes / selectedUnit.value;
|
||||
// 如果是整数,不显示小数点
|
||||
if (value === Math.floor(value)) {
|
||||
return value.toString();
|
||||
}
|
||||
// 保留最多2位小数
|
||||
return value.toFixed(2).replace(/\.?0+$/, '');
|
||||
};
|
||||
|
||||
return `${formatValue(reqBytes)}${selectedUnit.name} / ${formatValue(limitBytes)}${selectedUnit.name}`;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user