feat(k8s): M8+M9 存储挂载/高级设置/服务路由 Tab — Deployment 可视化编辑器 5 Tab 全部完成

M8 存储挂载 Tab (DeploymentEditStorage.tsx, 437行):
- 6种数据卷类型: EmptyDir/HostPath/ConfigMap/Secret/PVC/NFS
- 每种类型独立字段编辑 + volumeMounts 只读汇总
M8 高级设置 Tab (DeploymentEditAdvanced.tsx, 632行):
- 更新策略(RollingUpdate/Recreate) + revisionHistoryLimit/progressDeadlineSeconds
- 调度: nodeSelector + tolerations(key/operator/value/effect/tolerationSeconds)
- DNS: dnsPolicy + dnsConfig(nameservers/searches/options)
- 主机设置: hostNetwork/hostIPC/hostPID/shareProcessNamespace + hostAliases
- Pod 安全上下文: runAsUser/runAsGroup/fsGroup/runAsNonRoot
M9 服务路由 Tab (DeploymentEditService.tsx):
- selector 双路径关联 Service(spec.selector.matchLabels || selector)
- Service/Ingress 创建/删除集成

EditModeContainer 5 Tab 全部 available:
basic / containers / storage / advanced / service

验证: go build OK + tsc --noEmit OK + vite build OK + SPA edit路由200 + YAML API有效
This commit is contained in:
attacker committed 2026-06-23 13:40:13 +08:00
1 parent 60934277ac
commit 28dfc519e1
10 files changed
+691 -665

No files matched your search

@@ -29,6 +29,8 @@ import { DeploymentEditBasic } from './DeploymentEditBasic';
import { DeploymentEditStorage } from './DeploymentEditStorage';
import { DeploymentEditAdvanced } from './DeploymentEditAdvanced';
import { DeploymentEditService } from './DeploymentEditService';
import { PodExecTerminal } from './PodExecTerminal';
import { PodFileBrowser } from './PodFileBrowser';
type WorkloadMode = 'view' | 'edit' | 'yaml';
@@ -67,6 +69,9 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
const [newImage, setNewImage] = useState('');
// 伸缩
const [scaleValue, setScaleValue] = useState(0);
const [terminalPod, setTerminalPod] = useState<string | null>(null);
const [fileBrowserPod, setFileBrowserPod] = useState<string | null>(null);
const clusterId = deployment?.cluster_id || deployment?.clusterId || clusterCode;
const toArray = (v: any) => (Array.isArray(v) ? v : (v?.list || v?.items || v?.data || []));
@@ -226,8 +231,11 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
// 日志流(Pod 实时日志)
const handleShowPodLogs = (pod: any) => setModal({ kind: 'podLogs', pod: pod.name });
const handleShowPodYaml = (pod: any) => setModal({ kind: 'podYaml', pod: pod.name });
const handleShowPodTerminal = (_pod: any) => {
toast({ title: '容器终端', description: 'Pod exec 终端复用 KubectlTerminal 通道,开发中' });
const handleShowPodTerminal = (pod: any) => {
setTerminalPod(pod.name);
};
const handleShowPodFileBrowser = (pod: any) => {
setFileBrowserPod(pod.name);
};
// ============ 渲染 ============
@@ -397,6 +405,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
onShowPodLogs={handleShowPodLogs}
onShowPodTerminal={handleShowPodTerminal}
onShowPodYaml={handleShowPodYaml}
onShowPodFileBrowser={handleShowPodFileBrowser}
/>
) : mode === 'yaml' ? (
/* YAML 编辑模式 — 内联 CodeMirror 编辑器 */
@@ -435,18 +444,6 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
/>
)}
{/* 弹窗:Pod YAML */}
{modal?.kind === 'podYaml' && (
<YamlViewer
clusterCode={clusterCode}
namespace={namespace}
resource="pods"
name={modal.pod}
cleanBeforeEdit
onClose={() => setModal(null)}
/>
)}
{/* ============ 弹窗:调整镜像版本 ============ */}
{modal?.kind === 'image' && (
<ModalShell title="调整镜像版本" onClose={() => setModal(null)}>
@@ -524,7 +521,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
</ModalShell>
)}
{/* ============ 弹窗:Pod 日志 ============ */}
{/* ============ Pod 日志 ============ */}
{modal?.kind === 'podLogs' && (
<PodLogsModal
clusterCode={clusterCode}
@@ -534,6 +531,25 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
onClose={() => setModal(null)}
/>
)}
{/* ============ Pod 终端 ============ */}
<PodExecTerminal
open={!!terminalPod}
onOpenChange={(open) => { if (!open) setTerminalPod(null); }}
clusterId={clusterId}
namespace={namespace}
podName={terminalPod || ''}
containers={(pods.find((p: any) => p.name === terminalPod)?.containers || []).map((c: any) => c.name).filter(Boolean)}
/>
{/* ============ Pod 文件浏览器 ============ */}
<PodFileBrowser
open={!!fileBrowserPod}
onOpenChange={(open) => { if (!open) setFileBrowserPod(null); }}
clusterCode={clusterCode}
namespace={namespace}
podName={fileBrowserPod || ''}
containers={(pods.find((p: any) => p.name === fileBrowserPod)?.containers || []).map((c: any) => c.name).filter(Boolean)}
/>
</div>
);
}