config-viewer.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import {
  2. forwardRef,
  3. useEffect,
  4. useImperativeHandle,
  5. useRef,
  6. useState,
  7. } from "react";
  8. import { useTranslation } from "react-i18next";
  9. import { useRecoilValue } from "recoil";
  10. import {
  11. Button,
  12. Dialog,
  13. DialogActions,
  14. DialogContent,
  15. DialogTitle,
  16. Chip,
  17. } from "@mui/material";
  18. import { atomThemeMode } from "@/services/states";
  19. import { getRuntimeYaml } from "@/services/cmds";
  20. import { DialogRef } from "@/components/base";
  21. import { editor } from "monaco-editor/esm/vs/editor/editor.api";
  22. import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js";
  23. import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js";
  24. import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js";
  25. export const ConfigViewer = forwardRef<DialogRef>((props, ref) => {
  26. const { t } = useTranslation();
  27. const [open, setOpen] = useState(false);
  28. const editorRef = useRef<any>();
  29. const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
  30. const themeMode = useRecoilValue(atomThemeMode);
  31. useEffect(() => {
  32. return () => {
  33. if (instanceRef.current) {
  34. instanceRef.current.dispose();
  35. instanceRef.current = null;
  36. }
  37. };
  38. }, []);
  39. useImperativeHandle(ref, () => ({
  40. open: () => {
  41. setOpen(true);
  42. getRuntimeYaml().then((data) => {
  43. const dom = editorRef.current;
  44. if (!dom) return;
  45. if (instanceRef.current) instanceRef.current.dispose();
  46. instanceRef.current = editor.create(editorRef.current, {
  47. value: data ?? "# Error\n",
  48. language: "yaml",
  49. tabSize: 2,
  50. theme: themeMode === "light" ? "vs" : "vs-dark",
  51. minimap: { enabled: dom.clientWidth >= 1000 }, // 超过一定宽度显示minimap滚动条
  52. mouseWheelZoom: true, // Ctrl+滚轮调节缩放
  53. readOnly: true, // 只读
  54. readOnlyMessage: { value: t("ReadOnlyMessage") },
  55. padding: {
  56. top: 33, // 顶部padding防止遮挡snippets
  57. },
  58. fontFamily:
  59. "Fira Code, Roboto Mono, Source Code Pro, Menlo, Monaco, Consolas, Courier New, monospace",
  60. });
  61. });
  62. },
  63. close: () => setOpen(false),
  64. }));
  65. return (
  66. <Dialog open={open} onClose={() => setOpen(false)} maxWidth="xl" fullWidth>
  67. <DialogTitle>
  68. {t("Runtime Config")} <Chip label={t("ReadOnly")} size="small" />
  69. </DialogTitle>
  70. <DialogContent
  71. sx={{ width: "94%", height: "100vh", pb: 1, userSelect: "text" }}
  72. >
  73. <div style={{ width: "100%", height: "100%" }} ref={editorRef} />
  74. </DialogContent>
  75. <DialogActions>
  76. <Button onClick={() => setOpen(false)} variant="outlined">
  77. {t("Back")}
  78. </Button>
  79. </DialogActions>
  80. </Dialog>
  81. );
  82. });