- 抽取 YamlCodeMirror/YamlEditorToolbar,修复弹窗滚动与固定高度布局 - 对齐集群导出精简规则(Service/Ingress/Workload/PVC 注解等) - Deployment/Pod/Service/Ingress 分资源配置:Pod 只读,支持单文件下载 - 修复 Deployment Pod YAML 弹窗未渲染,补全 PodsTab 与详情页 YAML 入口 - 命名空间列表页新增导出 YAML(tar.gz),与集群导出 API 一致
90 lines
2.3 KiB
TypeScript
90 lines
2.3 KiB
TypeScript
// 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>
|
||
);
|
||
} |