mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
[Feature] Support loading for mermaid. (#6004)
Co-authored-by: 靖谦 <jingqian@kaiwu.cloud>
This commit is contained in:
parent
3f0da88ff7
commit
9f16739518
|
@ -103,7 +103,7 @@ const useLazyLoad = (ref: RefObject<Element>): boolean => {
|
||||||
// visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message
|
// 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.
|
// or use the non-minified dev environment for full errors and additional helpful warnings.
|
||||||
const CodeBlock: CodeComponent = memo(({ inline, className, children, ...props }) => {
|
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 match = /language-(\w+)/.exec(className || '')
|
||||||
const language = match?.[1]
|
const language = match?.[1]
|
||||||
const languageShowName = getCorrectCapitalizationLanguageName(language || '')
|
const languageShowName = getCorrectCapitalizationLanguageName(language || '')
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import mermaid from 'mermaid'
|
import mermaid from 'mermaid'
|
||||||
import CryptoJS from 'crypto-js'
|
import CryptoJS from 'crypto-js'
|
||||||
|
import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
|
||||||
|
|
||||||
let mermaidAPI: any
|
let mermaidAPI: any
|
||||||
mermaidAPI = null
|
mermaidAPI = null
|
||||||
|
@ -23,12 +24,24 @@ const style = {
|
||||||
overflow: 'auto',
|
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: {
|
const Flowchart = React.forwardRef((props: {
|
||||||
PrimitiveCode: string
|
PrimitiveCode: string
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const [svgCode, setSvgCode] = useState(null)
|
const [svgCode, setSvgCode] = useState(null)
|
||||||
const chartId = useRef(`flowchart_${CryptoJS.MD5(props.PrimitiveCode).toString()}`)
|
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 = () => {
|
const clearFlowchartCache = () => {
|
||||||
for (let i = localStorage.length - 1; i >= 0; --i) {
|
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)
|
const cachedSvg: any = localStorage.getItem(chartId.current)
|
||||||
if (cachedSvg) {
|
if (cachedSvg) {
|
||||||
setSvgCode(cachedSvg)
|
setSvgCode(cachedSvg)
|
||||||
|
setIsLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && mermaidAPI) {
|
if (typeof window !== 'undefined' && mermaidAPI) {
|
||||||
const svgGraph = await mermaidAPI.render(chartId.current, PrimitiveCode)
|
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)
|
const base64Svg: any = await svgToBase64(svgGraph.svg)
|
||||||
setSvgCode(base64Svg)
|
setSvgCode(base64Svg)
|
||||||
|
setIsLoading(false)
|
||||||
if (chartId.current && base64Svg)
|
if (chartId.current && base64Svg)
|
||||||
localStorage.setItem(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 = () => {
|
const handleReRender = () => {
|
||||||
setIsRender(false)
|
setIsRender(false)
|
||||||
setSvgCode(null)
|
setSvgCode(null)
|
||||||
|
@ -99,10 +106,15 @@ const Flowchart = React.forwardRef((props: {
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
{
|
{
|
||||||
isRender
|
isRender
|
||||||
&& <div id={chartId.current} className="mermaid" style={style}>
|
&& <div className="mermaid" style={style}>
|
||||||
{svgCode && <img src={svgCode} style={{ width: '100%', height: 'auto' }} alt="Mermaid chart" />}
|
{svgCode && <img src={svgCode} style={{ width: '100%', height: 'auto' }} alt="Mermaid chart" />}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
{isLoading
|
||||||
|
&& <div className='py-4 px-[26px]'>
|
||||||
|
<LoadingAnim type='text' />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user