diff --git a/web/app/components/base/markdown.tsx b/web/app/components/base/markdown.tsx index 958c55a871..11db2f727c 100644 --- a/web/app/components/base/markdown.tsx +++ b/web/app/components/base/markdown.tsx @@ -103,7 +103,7 @@ const useLazyLoad = (ref: RefObject): boolean => { // visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message // or use the non-minified dev environment for full errors and additional helpful warnings. const CodeBlock: CodeComponent = memo(({ inline, className, children, ...props }) => { - const [isSVG, setIsSVG] = useState(false) + const [isSVG, setIsSVG] = useState(true) const match = /language-(\w+)/.exec(className || '') const language = match?.[1] const languageShowName = getCorrectCapitalizationLanguageName(language || '') diff --git a/web/app/components/base/mermaid/index.tsx b/web/app/components/base/mermaid/index.tsx index 86f472c06e..bef26b7a36 100644 --- a/web/app/components/base/mermaid/index.tsx +++ b/web/app/components/base/mermaid/index.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useState } from 'react' import mermaid from 'mermaid' import CryptoJS from 'crypto-js' +import LoadingAnim from '@/app/components/base/chat/chat/loading-anim' let mermaidAPI: any mermaidAPI = null @@ -23,12 +24,24 @@ const style = { overflow: 'auto', } +const svgToBase64 = (svgGraph: string) => { + const svgBytes = new TextEncoder().encode(svgGraph) + const blob = new Blob([svgBytes], { type: 'image/svg+xml;charset=utf-8' }) + return new Promise((resolve, reject) => { + const reader = new FileReader() + reader.onloadend = () => resolve(reader.result) + reader.onerror = reject + reader.readAsDataURL(blob) + }) +} + const Flowchart = React.forwardRef((props: { PrimitiveCode: string }, ref) => { const [svgCode, setSvgCode] = useState(null) const chartId = useRef(`flowchart_${CryptoJS.MD5(props.PrimitiveCode).toString()}`) - const [isRender, setIsRender] = useState(true) + const [isRender, setIsRender] = useState(false) + const [isLoading, setIsLoading] = useState(true) const clearFlowchartCache = () => { for (let i = localStorage.length - 1; i >= 0; --i) { @@ -43,14 +56,19 @@ const Flowchart = React.forwardRef((props: { const cachedSvg: any = localStorage.getItem(chartId.current) if (cachedSvg) { setSvgCode(cachedSvg) + setIsLoading(false) return } if (typeof window !== 'undefined' && mermaidAPI) { const svgGraph = await mermaidAPI.render(chartId.current, PrimitiveCode) - // eslint-disable-next-line @typescript-eslint/no-use-before-define + const dom = new DOMParser().parseFromString(svgGraph.svg, 'text/xml') + if (!dom.querySelector('g.main')) + throw new Error('empty svg') + const base64Svg: any = await svgToBase64(svgGraph.svg) setSvgCode(base64Svg) + setIsLoading(false) if (chartId.current && base64Svg) localStorage.setItem(chartId.current, base64Svg) } @@ -62,17 +80,6 @@ const Flowchart = React.forwardRef((props: { } } - const svgToBase64 = (svgGraph: string) => { - const svgBytes = new TextEncoder().encode(svgGraph) - const blob = new Blob([svgBytes], { type: 'image/svg+xml;charset=utf-8' }) - return new Promise((resolve, reject) => { - const reader = new FileReader() - reader.onloadend = () => resolve(reader.result) - reader.onerror = reject - reader.readAsDataURL(blob) - }) - } - const handleReRender = () => { setIsRender(false) setSvgCode(null) @@ -99,10 +106,15 @@ const Flowchart = React.forwardRef((props: {
{ isRender - &&
+ &&
{svgCode && Mermaid chart}
} + {isLoading + &&
+ +
+ }
) })