fix: Adjust mermaid chart to new types and use useAsync

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2022-11-05 18:07:49 +01:00
parent e714313011
commit 5baa7e3351
3 changed files with 36 additions and 61 deletions

View file

@ -140,7 +140,6 @@
"@types/markdown-it": "12.2.3", "@types/markdown-it": "12.2.3",
"@types/markdown-it-container": "2.0.5", "@types/markdown-it-container": "2.0.5",
"@types/markdown-it-plantuml": "1.4.1", "@types/markdown-it-plantuml": "1.4.1",
"@types/mermaid": "9.1.0",
"@types/node": "18.11.9", "@types/node": "18.11.9",
"@types/react": "18.0.25", "@types/react": "18.0.25",
"@types/react-dom": "18.0.8", "@types/react-dom": "18.0.8",

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react' import React, { Fragment, useRef } from 'react'
import { Alert } from 'react-bootstrap' import { Alert } from 'react-bootstrap'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styles from './mermaid.module.scss' import styles from './mermaid.module.scss'
@ -12,15 +12,21 @@ import type { CodeProps } from '../../../components/markdown-renderer/replace-co
import { cypressId } from '../../../utils/cypress-attribute' import { cypressId } from '../../../utils/cypress-attribute'
import { ShowIf } from '../../../components/common/show-if/show-if' import { ShowIf } from '../../../components/common/show-if/show-if'
import { Logger } from '../../../utils/logger' import { Logger } from '../../../utils/logger'
import { useAsync } from 'react-use'
const log = new Logger('MermaidChart') const log = new Logger('MermaidChart')
interface MermaidParseError {
str: string
}
let mermaidInitialized = false let mermaidInitialized = false
const loadMermaid = async (): Promise<typeof import('mermaid')> => {
try {
return import(/* webpackChunkName: "mermaid" */ 'mermaid')
} catch (error) {
log.error('Error while loading mermaid', error)
throw new Error('Error while loading mermaid')
}
}
/** /**
* Renders a mermaid diagram. * Renders a mermaid diagram.
* *
@ -29,61 +35,39 @@ let mermaidInitialized = false
*/ */
export const MermaidChart: React.FC<CodeProps> = ({ code }) => { export const MermaidChart: React.FC<CodeProps> = ({ code }) => {
const diagramContainer = useRef<HTMLDivElement>(null) const diagramContainer = useRef<HTMLDivElement>(null)
const [error, setError] = useState<string>()
const { t } = useTranslation() const { t } = useTranslation()
const { error } = useAsync(async () => {
useEffect(() => {
if (!mermaidInitialized) {
import(/* webpackChunkName: "mermaid" */ 'mermaid')
.then((mermaid) => {
mermaid.default.initialize({ startOnLoad: false })
mermaidInitialized = true
})
.catch((error: Error) => {
log.error('Error while loading mermaid', error)
})
}
}, [])
const showError = useCallback(
(error: string) => {
setError(error)
log.error(error)
if (!diagramContainer.current) {
return
}
diagramContainer.current.querySelectorAll('svg').forEach((child) => child.remove())
},
[setError]
)
useEffect(() => {
if (!diagramContainer.current) { if (!diagramContainer.current) {
return return
} }
import(/* webpackChunkName: "mermaid" */ 'mermaid')
.then((mermaid) => { const mermaid = await loadMermaid()
try {
if (!diagramContainer.current) { if (!mermaidInitialized) {
return mermaid.default.initialize({ startOnLoad: false })
} mermaidInitialized = true
mermaid.default.parse(code) }
delete diagramContainer.current.dataset.processed
diagramContainer.current.textContent = code try {
mermaid.default.init(diagramContainer.current) if (!diagramContainer.current) {
setError(undefined) return
} catch (error) { }
const message = (error as MermaidParseError).str mermaid.default.parse(code)
showError(message || t('renderer.mermaid.unknownError')) delete diagramContainer.current.dataset.processed
} diagramContainer.current.textContent = code
}) await mermaid.default.init(undefined, diagramContainer.current)
.catch(() => showError('Error while loading mermaid')) } catch (error) {
}, [code, showError, t]) const message = (error as Error).message
log.error(error)
diagramContainer.current?.querySelectorAll('svg').forEach((child) => child.remove())
throw new Error(message || t('renderer.mermaid.unknownError'))
}
}, [code, t])
return ( return (
<Fragment> <Fragment>
<ShowIf condition={!!error}> <ShowIf condition={!!error}>
<Alert variant={'warning'}>{error}</Alert> <Alert variant={'warning'}>{error?.message}</Alert>
</ShowIf> </ShowIf>
<div <div
{...cypressId('mermaid-frame')} {...cypressId('mermaid-frame')}

View file

@ -1964,7 +1964,6 @@ __metadata:
"@types/markdown-it": 12.2.3 "@types/markdown-it": 12.2.3
"@types/markdown-it-container": 2.0.5 "@types/markdown-it-container": 2.0.5
"@types/markdown-it-plantuml": 1.4.1 "@types/markdown-it-plantuml": 1.4.1
"@types/mermaid": 9.1.0
"@types/node": 18.11.9 "@types/node": 18.11.9
"@types/react": 18.0.25 "@types/react": 18.0.25
"@types/react-dom": 18.0.8 "@types/react-dom": 18.0.8
@ -3483,13 +3482,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/mermaid@npm:9.1.0":
version: 9.1.0
resolution: "@types/mermaid@npm:9.1.0"
checksum: ea3756826c89c85efd4e182c6ef025ea24a20ee70dc168673390b1125f158f57ae231f36cb2c700ef0ea6e9c322551963404759f8d019e0e48fb7cb5d6da1f96
languageName: node
linkType: hard
"@types/node@npm:*": "@types/node@npm:*":
version: 18.11.4 version: 18.11.4
resolution: "@types/node@npm:18.11.4" resolution: "@types/node@npm:18.11.4"