feat(k8s): 事件页简化、可视化编辑 P0、Deployment 五 Tab 修复

- 事件中心:去彩虹图表,改专业排名列表 + 主题变量
- 网络/配置/存储:ResourceVisualEditor 双向 YAML 同步、导入 YAML、新建
- vite manualChunks 减小 embed 主包体积
- run.sh:多副本强制 MODE=release + MySQL/Redis
- Deployment 编辑:共享 manifest、统一 saveDeploymentManifest
- 修复存储挂载 initContainers 混入 bug、补 Tolerations UI
- 服务 Tab:applyYAML 创建 + ResourceVisualEditor 编辑
- 基本信息:Pod 模板标签 + Selector 同步
This commit is contained in:
Logan.Li committed 2026-06-26 13:52:32 +08:00
1 parent 339b24a579
commit d0cf71b05a
17 files changed
+814 -497

No files matched your search

@@ -13,7 +13,7 @@ import {
GitBranch,
Loader2,
RefreshCw,
ExternalLink,
Pencil,
Plus,
CheckCircle,
Server,
@@ -25,13 +25,15 @@ import {
import { useToast } from '@/hooks/use-toast';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { kubernetesApi } from '@/api';
import { dumpManifest } from './k8s-manifest-utils';
import { ResourceVisualEditor } from './ResourceVisualEditor';
interface Props {
clusterCode: string;
namespace: string;
deploymentName: string;
manifest: any | null;
onSaved: () => void;
onSaved: (updated?: any) => void;
onCancel: () => void;
}
@@ -78,7 +80,7 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
const [services, setServices] = useState<SvcSummary[]>([]);
const [ingresses, setIngresses] = useState<IngSummary[]>([]);
const [selectorLabels, setSelectorLabels] = useState<Record<string, string>>({});
const [yamlModal, setYamlModal] = useState<{ kind: 'service' | 'ingress'; name: string } | null>(null);
const [visualEditor, setVisualEditor] = useState<{ resource: 'services' | 'ingresses'; name: string } | null>(null);
const [showCreate, setShowCreate] = useState<'service' | 'ingress' | null>(null);
// 创建 Service 表单 — 多端口
@@ -219,9 +221,9 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
ports: k8sPorts,
},
};
const json = JSON.stringify(svcManifest, null, 2);
try {
await kubernetesApi.updateResourceYaml(clusterCode, namespace, 'services', name, json);
const yaml = await dumpManifest(svcManifest);
await kubernetesApi.applyYAML(clusterCode, yaml);
toast({ title: 'Service 已创建', description: name });
setShowCreate(null);
load();
@@ -254,9 +256,9 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
},
};
if (!ingForm.className) delete manifest.spec.ingressClassName;
const json = JSON.stringify(manifest, null, 2);
try {
await kubernetesApi.updateResourceYaml(clusterCode, namespace, 'ingresses', name, json);
const yaml = await dumpManifest(manifest);
await kubernetesApi.applyYAML(clusterCode, yaml);
toast({ title: 'Ingress 已创建', description: name });
setShowCreate(null);
load();
@@ -355,9 +357,9 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
<Badge variant="outline" className="border-slate-700 text-slate-400 text-[10px]">{svc.type}</Badge>
{matched && <Badge className="bg-blue-500/20 text-blue-300 border-blue-500/30 text-[10px]">关联</Badge>}
<code className="text-[11px] text-slate-500 ml-auto">{svc.clusterIP}</code>
<Button size="sm" variant="ghost" className="h-6 text-xs text-slate-400"
onClick={() => setYamlModal({ kind: 'service', name: svc.name })}>
<ExternalLink className="h-3 w-3 mr-1" />YAML
<Button size="sm" variant="ghost" className="h-6 text-xs text-emerald-400"
onClick={() => setVisualEditor({ resource: 'services', name: svc.name })}>
<Pencil className="h-3 w-3 mr-1" />编辑
</Button>
<Button size="sm" variant="ghost" className="h-6 w-6 p-0 text-red-400 hover:text-red-300"
title="删除 Service" onClick={() => deleteResource('service', svc.name)}>
@@ -529,9 +531,9 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
<span className="text-sm font-semibold text-slate-200">{ing.name}</span>
<Badge variant="outline" className="border-slate-700 text-slate-400 text-[10px]">{ing.className}</Badge>
{matched && <Badge className="bg-purple-500/20 text-purple-300 border-purple-500/30 text-[10px]">关联</Badge>}
<Button size="sm" variant="ghost" className="h-6 text-xs text-slate-400 ml-auto"
onClick={() => setYamlModal({ kind: 'ingress', name: ing.name })}>
<ExternalLink className="h-3 w-3 mr-1" />YAML
<Button size="sm" variant="ghost" className="h-6 text-xs text-emerald-400 ml-auto"
onClick={() => setVisualEditor({ resource: 'ingresses', name: ing.name })}>
<Pencil className="h-3 w-3 mr-1" />编辑
</Button>
<Button size="sm" variant="ghost" className="h-6 w-6 p-0 text-red-400 hover:text-red-300"
title="删除 Ingress" onClick={() => deleteResource('ingress', ing.name)}>
@@ -604,15 +606,19 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
</CardContent>
</Card>
{/* YAML 弹窗 */}
{yamlModal && (
<div className="hidden">{/* YamlViewer can be re-added here if needed */}</div>
{visualEditor && (
<ResourceVisualEditor
clusterCode={clusterCode}
namespace={namespace}
resource={visualEditor.resource}
name={visualEditor.name}
onClose={() => setVisualEditor(null)}
onSaved={() => { setVisualEditor(null); load(); }}
/>
)}
{/* 底部操作 */}
<div className="flex justify-end gap-2 pt-2">
<Button size="sm" variant="ghost" className="h-7 text-xs text-slate-400" onClick={onCancel}>完成</Button>
<Button size="sm" className="h-7 bg-slate-600 text-xs" onClick={onSaved}>保存并关闭</Button>
<Button size="sm" variant="outline" className="h-7 text-xs border-slate-700 text-slate-400" onClick={onCancel}>返回查看</Button>
</div>
</div>
);