Prechádzať zdrojové kódy

Merge pull request #2477 from visuddhinanda/development

refactor(dashboard-v6): Mermaid 去掉 useState,svg 直接写 DOM 实时渲染
visuddhinanda 2 týždňov pred
rodič
commit
9a8b5a3650
1 zmenil súbory, kde vykonal 33 pridanie a 67 odobranie
  1. 33 67
      dashboard-v6/src/components/general/Mermaid.tsx

+ 33 - 67
dashboard-v6/src/components/general/Mermaid.tsx

@@ -1,93 +1,59 @@
-import { Alert } from "antd";
 import lodash from "lodash";
 import mermaid from "mermaid";
-import { useEffect, useMemo, useRef, useState } from "react";
+import { useEffect, useRef } from "react";
 import { useIntl } from "react-intl";
 
 interface IWidget {
   text?: string;
 }
 
-type RenderState =
-  | { status: "loading" }
-  | { status: "ready"; svg: string }
-  | { status: "error"; message: string };
-
 const MermaidWidget = ({ text }: IWidget) => {
   const intl = useIntl();
-  const id = useMemo(
-    () => lodash.times(20, () => lodash.random(35).toString(36)).join(""),
-    []
-  );
   const containerRef = useRef<HTMLDivElement>(null);
-  const bindFunctionsRef = useRef<((element: Element) => void) | undefined>(
-    undefined
-  );
-  const [state, setState] = useState<RenderState>({ status: "loading" });
 
   useEffect(() => {
     let cancelled = false;
-    bindFunctionsRef.current = undefined;
+    const container = containerRef.current;
+    if (!container) {
+      return;
+    }
+    container.innerHTML = "";
+
+    const id = lodash.times(20, () => lodash.random(35).toString(36)).join("");
 
     // mermaid v10+ 的 render 是异步的,返回 Promise<{svg, bindFunctions}>
-    mermaid
-      .render(`g-${id}`, text ?? "")
-      .then(({ svg, bindFunctions }) => {
-        if (cancelled) {
-          return;
+    (async () => {
+      try {
+        const { svg } = await mermaid.render(`g-${id}`, text ?? "");
+        if (!cancelled) {
+          container.innerHTML = svg;
         }
-        bindFunctionsRef.current = bindFunctions;
-        setState({ status: "ready", svg });
-      })
-      .catch((error: unknown) => {
-        if (cancelled) {
-          return;
+      } catch (error) {
+        if (!cancelled) {
+          console.error("[mermaid] render failed", error);
+          const message =
+            error instanceof Error ? error.message : String(error);
+          const title = intl.formatMessage({
+            id: "labels.error.render-failed",
+            defaultMessage: "图形渲染失败",
+          });
+          container.innerHTML = "";
+          const errorEl = document.createElement("div");
+          errorEl.setAttribute("role", "alert");
+          errorEl.style.cssText =
+            "color: #cf1322; background: #fff2f0; border: 1px solid #ffccc7; border-radius: 8px; padding: 8px 12px;";
+          errorEl.textContent = `${title}:${message}`;
+          container.appendChild(errorEl);
         }
-        const message = error instanceof Error ? error.message : String(error);
-        console.error("[mermaid] render failed", error);
-        setState({ status: "error", message });
-      });
+      }
+    })();
 
     return () => {
       cancelled = true;
     };
-  }, [id, text]);
-
-  // svg 插入 DOM 之后再绑定交互回调(点击、链接等)
-  useEffect(() => {
-    if (
-      state.status === "ready" &&
-      bindFunctionsRef.current &&
-      containerRef.current
-    ) {
-      bindFunctionsRef.current(containerRef.current);
-    }
-  }, [state]);
-
-  if (state.status === "error") {
-    return (
-      <Alert
-        type="error"
-        showIcon
-        title={intl.formatMessage({
-          id: "labels.error.render-failed",
-          defaultMessage: "图形渲染失败",
-        })}
-        description={state.message}
-      />
-    );
-  }
-
-  if (state.status === "ready") {
-    return (
-      <div
-        ref={containerRef}
-        dangerouslySetInnerHTML={{ __html: state.svg }}
-      />
-    );
-  }
+  }, [intl, text]);
 
-  return null;
+  return <div ref={containerRef} />;
 };
 
 export default MermaidWidget;