From fe2f7403aa429e7bc1923e7d17f7e9ffa454c09c Mon Sep 17 00:00:00 2001 From: Jakob Klepp Date: Tue, 4 Aug 2020 11:15:23 +0200 Subject: [PATCH] Add plantuml support (#327) * Add plantuml support * Enable PlantUML rendering only if plantumlServer config is set * Show warning box when plantuml is enabled but no server is configured --- package.json | 1 + public/api/v2/config | 1 + src/api/config/types.ts | 1 + src/components/editor/editorTestContent.ts | 34 +++++++++++++++++++ .../markdown-it-plugins/plantuml-error.ts | 18 ++++++++++ .../markdown-renderer/markdown-renderer.scss | 5 +++ .../markdown-renderer/markdown-renderer.tsx | 17 +++++++++- .../markdown-it-plantuml/index.d.ts | 6 ++++ .../markdown-it-plantuml/interface.d.ts | 8 +++++ src/redux/config/reducers.ts | 1 + yarn.lock | 5 +++ 11 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/components/editor/markdown-renderer/markdown-it-plugins/plantuml-error.ts create mode 100644 src/external-types/markdown-it-plantuml/index.d.ts create mode 100644 src/external-types/markdown-it-plantuml/interface.d.ts diff --git a/package.json b/package.json index 8c74782e2..1962064ad 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "markdown-it-ins": "3.0.0", "markdown-it-mark": "3.0.0", "markdown-it-mathjax": "2.0.0", + "markdown-it-plantuml": "1.4.1", "markdown-it-regex": "0.2.0", "markdown-it-sub": "1.0.0", "markdown-it-sup": "1.0.0", diff --git a/public/api/v2/config b/public/api/v2/config index 30ab2aa80..dcc4a4568 100644 --- a/public/api/v2/config +++ b/public/api/v2/config @@ -27,6 +27,7 @@ "saml": "aufSAMLn.de" }, "useImageProxy": false, + "plantumlServer": "http://www.plantuml.com/plantuml", "specialLinks": { "privacy": "https://example.com/privacy", "termsOfUse": "https://example.com/termsOfUse", diff --git a/src/api/config/types.ts b/src/api/config/types.ts index f69a53c99..75a088b5a 100644 --- a/src/api/config/types.ts +++ b/src/api/config/types.ts @@ -7,6 +7,7 @@ export interface Config { useImageProxy: boolean, specialLinks: SpecialLinks, version: BackendVersion, + plantumlServer: string | null, } export interface BrandingConfig { diff --git a/src/components/editor/editorTestContent.ts b/src/components/editor/editorTestContent.ts index c47465897..251464fd6 100644 --- a/src/components/editor/editorTestContent.ts +++ b/src/components/editor/editorTestContent.ts @@ -52,4 +52,38 @@ https://asciinema.org/a/117928 let a = 1 \`\`\` + +## PlantUML +\`\`\`plantuml +@startuml +participant Alice +participant "The **Famous** Bob" as Bob + +Alice -> Bob : hello --there-- +... Some ~~long delay~~ ... +Bob -> Alice : ok +note left + This is **bold** + This is //italics// + This is ""monospaced"" + This is --stroked-- + This is __underlined__ + This is ~~waved~~ +end note + +Alice -> Bob : A //well formatted// message +note right of Alice + This is displayed + __left of__ Alice. +end note +note left of Bob + This is displayed + **left of Alice Bob**. +end note +note over Alice, Bob + This is hosted by +end note +@enduml +\`\`\` + ` diff --git a/src/components/editor/markdown-renderer/markdown-it-plugins/plantuml-error.ts b/src/components/editor/markdown-renderer/markdown-it-plugins/plantuml-error.ts new file mode 100644 index 000000000..355d3d827 --- /dev/null +++ b/src/components/editor/markdown-renderer/markdown-it-plugins/plantuml-error.ts @@ -0,0 +1,18 @@ +import MarkdownIt, { Options } from 'markdown-it/lib' +import Renderer, { RenderRule } from 'markdown-it/lib/renderer' +import Token from 'markdown-it/lib/token' + +export const plantumlError: MarkdownIt.PluginSimple = (md) => { + const defaultRenderer: RenderRule = md.renderer.rules.fence || (() => '') + md.renderer.rules.fence = (tokens: Token[], idx: number, options: Options, env, slf: Renderer) => { + const token = tokens[idx] + if (token.info === 'plantuml') { + return ` +

+ PlantUML plugin is enabled but not properly configured. +

+ ` + } + return defaultRenderer(tokens, idx, options, env, slf) + } +} diff --git a/src/components/editor/markdown-renderer/markdown-renderer.scss b/src/components/editor/markdown-renderer/markdown-renderer.scss index c76cf9a96..f472898d4 100644 --- a/src/components/editor/markdown-renderer/markdown-renderer.scss +++ b/src/components/editor/markdown-renderer/markdown-renderer.scss @@ -14,6 +14,11 @@ max-width: 900px; } + & > img { + width: unset; + background-color: unset; + } + &.wider { max-width: 1500px; diff --git a/src/components/editor/markdown-renderer/markdown-renderer.tsx b/src/components/editor/markdown-renderer/markdown-renderer.tsx index 797e66b4a..678b2fd12 100644 --- a/src/components/editor/markdown-renderer/markdown-renderer.tsx +++ b/src/components/editor/markdown-renderer/markdown-renderer.tsx @@ -14,6 +14,7 @@ import inserted from 'markdown-it-ins' import marked from 'markdown-it-mark' import mathJax from 'markdown-it-mathjax' import markdownItRegex from 'markdown-it-regex' +import plantuml from 'markdown-it-plantuml' import subscript from 'markdown-it-sub' import superscript from 'markdown-it-sup' import taskList from 'markdown-it-task-lists' @@ -23,7 +24,9 @@ import { Alert } from 'react-bootstrap' import ReactHtmlParser, { convertNodeToElement, Transform } from 'react-html-parser' import { Trans } from 'react-i18next' import MathJaxReact from 'react-mathjax' +import { useSelector } from 'react-redux' import { TocAst } from '../../../external-types/markdown-it-toc-done-right/interface' +import { ApplicationState } from '../../../redux' import { slugify } from '../../../utils/slugify' import { InternalLink } from '../../common/links/internal-link' import { ShowIf } from '../../common/show-if/show-if' @@ -33,6 +36,7 @@ import { highlightedCode } from './markdown-it-plugins/highlighted-code' import { linkifyExtra } from './markdown-it-plugins/linkify-extra' import { MarkdownItParserDebugger } from './markdown-it-plugins/parser-debugger' import './markdown-renderer.scss' +import { plantumlError } from './markdown-it-plugins/plantuml-error' import { replaceAsciinemaLink } from './regex-plugins/replace-asciinema-link' import { replaceGistLink } from './regex-plugins/replace-gist-link' import { replaceLegacyGistShortCode } from './regex-plugins/replace-legacy-gist-short-code' @@ -93,6 +97,8 @@ export const MarkdownRenderer: React.FC = ({ content, onM } }) + const plantumlServer = useSelector((state: ApplicationState) => state.config.plantumlServer) + const markdownIt = useMemo(() => { const md = new MarkdownIt('default', { html: true, @@ -127,6 +133,15 @@ export const MarkdownRenderer: React.FC = ({ content, onM }) } md.use(taskList) + if (plantumlServer) { + md.use(plantuml, { + openMarker: '```plantuml', + closeMarker: '```', + server: plantumlServer + }) + } else { + md.use(plantumlError) + } md.use(emoji) md.use(abbreviation) md.use(definitionList) @@ -195,7 +210,7 @@ export const MarkdownRenderer: React.FC = ({ content, onM }) return md - }, [onMetaDataChange, onFirstHeadingChange]) + }, [onMetaDataChange, onFirstHeadingChange, plantumlServer]) useEffect(() => { if (onTocChange && tocAst && !equal(tocAst, lastTocAst)) { diff --git a/src/external-types/markdown-it-plantuml/index.d.ts b/src/external-types/markdown-it-plantuml/index.d.ts new file mode 100644 index 000000000..5b432ffeb --- /dev/null +++ b/src/external-types/markdown-it-plantuml/index.d.ts @@ -0,0 +1,6 @@ +declare module 'markdown-it-plantuml' { + import MarkdownIt from 'markdown-it/lib' + import { PlantumlOptions } from './interface' + const markdownItPlantuml: MarkdownIt.PluginWithOptions + export = markdownItPlantuml +} diff --git a/src/external-types/markdown-it-plantuml/interface.d.ts b/src/external-types/markdown-it-plantuml/interface.d.ts new file mode 100644 index 000000000..fcccb36f6 --- /dev/null +++ b/src/external-types/markdown-it-plantuml/interface.d.ts @@ -0,0 +1,8 @@ +import Renderer from 'markdown-it/lib/renderer' + +export interface PlantumlOptions { + openMarker: string + closeMarker: string + render: Renderer + generateSource: (umlCode: string, pluginOptions: PlantumlOptions) => string +} diff --git a/src/redux/config/reducers.ts b/src/redux/config/reducers.ts index 82eb94e90..d99d5210d 100644 --- a/src/redux/config/reducers.ts +++ b/src/redux/config/reducers.ts @@ -31,6 +31,7 @@ export const initialState: Config = { saml: '' }, useImageProxy: false, + plantumlServer: null, specialLinks: { privacy: '', termsOfUse: '', diff --git a/yarn.lock b/yarn.lock index 56e88951d..3e2354eb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8096,6 +8096,11 @@ markdown-it-mathjax@2.0.0: resolved "https://registry.yarnpkg.com/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz#ae2b4f4c5c719a03f9e475c664f7b2685231d9e9" integrity sha1-ritPTFxxmgP55HXGZPeyaFIx2ek= +markdown-it-plantuml@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/markdown-it-plantuml/-/markdown-it-plantuml-1.4.1.tgz#3bd5e7d92eaa5c6c68eb29802f7b46a8e05ca998" + integrity sha512-13KgnZaGYTHBp4iUmGofzZSBz+Zj6cyqfR0SXUIc9wgWTto5Xhn7NjaXYxY0z7uBeTUMlc9LMQq5uP4OM5xCHg== + markdown-it-regex@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/markdown-it-regex/-/markdown-it-regex-0.2.0.tgz#e09ad2d75209720d591d3949e1142c75c0fbecf6"