feat(k8s): 统一 YAML 查看编辑并补齐 Pod/导出能力

- 抽取 YamlCodeMirror/YamlEditorToolbar,修复弹窗滚动与固定高度布局
- 对齐集群导出精简规则(Service/Ingress/Workload/PVC 注解等)
- Deployment/Pod/Service/Ingress 分资源配置:Pod 只读,支持单文件下载
- 修复 Deployment Pod YAML 弹窗未渲染,补全 PodsTab 与详情页 YAML 入口
- 命名空间列表页新增导出 YAML(tar.gz),与集群导出 API 一致
This commit is contained in:
Logan.Li committed 2026-06-26 15:25:46 +08:00
1 parent eeba677850
commit fd7b04b9d6
15 files changed
+651 -150

No files matched your search

@@ -0,0 +1,90 @@
// YAML CodeMirror 封装:保证编辑区可滚动、撑满父容器 // Logan.Li
import { useRef, useState, useEffect, useMemo } from 'react';
import CodeMirror from '@uiw/react-codemirror';
import { yaml } from '@codemirror/lang-yaml';
import { oneDark } from '@codemirror/theme-one-dark';
import { EditorView } from '@codemirror/view';
const scrollTheme = EditorView.theme({
'&': { height: '100%' },
'.cm-scroller': { overflow: 'auto' },
});
export interface YamlCodeMirrorProps {
value: string;
onChange?: (value: string) => void;
editing?: boolean;
/** 撑满 flex 父容器(配合 flex-1 min-h-0)// Logan.Li */
fill?: boolean;
/** 固定高度,fill 时忽略 */
height?: string;
className?: string;
fontSize?: string;
}
export function YamlCodeMirror({
value,
onChange,
editing = true,
fill = false,
height = '480px',
className = '',
fontSize = '13px',
}: YamlCodeMirrorProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [fillHeight, setFillHeight] = useState(400);
useEffect(() => {
if (!fill || !containerRef.current) return;
const el = containerRef.current;
const sync = () => setFillHeight(Math.max(200, el.clientHeight));
const ro = new ResizeObserver(sync);
ro.observe(el);
sync();
return () => ro.disconnect();
}, [fill]);
const extensions = useMemo(() => [
yaml(),
EditorView.lineWrapping,
scrollTheme,
...(editing ? [] : [EditorView.editable.of(false)]),
], [editing]);
const editorHeight = fill ? `${fillHeight}px` : height;
const editor = (
<CodeMirror
value={value}
height={editorHeight}
theme={oneDark}
extensions={extensions}
onChange={onChange}
basicSetup={{
lineNumbers: true,
foldGutter: true,
highlightActiveLine: editing,
highlightActiveLineGutter: editing,
autocompletion: editing,
bracketMatching: true,
closeBrackets: editing,
indentOnInput: editing,
}}
style={{ fontSize }}
/>
);
if (fill) {
return (
<div ref={containerRef} className={`flex-1 min-h-0 h-full overflow-hidden rounded-lg border border-slate-700 ${className}`}>
{editor}
</div>
);
}
return (
<div className={`overflow-auto rounded-lg border border-slate-700 ${className}`}>
{editor}
</div>
);
}