mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 09:46:16 +01:00
add markdown codeblock renderer extension point (#1492)
Introduces a new extension point that allows developers to overwrite the default syntax highlighting renderer for specific code blocks defined in markdown. The extension point is dynamic and follows the pattern "markdown-renderer.code.{language}".
This feature lays the groundwork for the scm-markdown-plantuml-plugin.
This commit is contained in:
committed by
GitHub
parent
8eb599ff94
commit
831c8b0271
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
### Added
|
||||||
|
- add markdown codeblock renderer extension point ([#1492](https://github.com/scm-manager/scm-manager/pull/1492))
|
||||||
|
|
||||||
## [2.12.0] - 2020-12-17
|
## [2.12.0] - 2020-12-17
|
||||||
### Added
|
### Added
|
||||||
- Add repository import via dump file for Subversion ([#1471](https://github.com/scm-manager/scm-manager/pull/1471))
|
- Add repository import via dump file for Subversion ([#1471](https://github.com/scm-manager/scm-manager/pull/1471))
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ The following extension points are provided for the frontend:
|
|||||||
### roles.route
|
### roles.route
|
||||||
### user.route
|
### user.route
|
||||||
### user.setting
|
### user.setting
|
||||||
|
### markdown-renderer.code.{language}
|
||||||
|
- Dynamic extension point for custom language-specific renderers
|
||||||
|
- Overrides the default Syntax Highlighter
|
||||||
|
- Used by the Markdown Plantuml Plugin
|
||||||
|
|
||||||
# Deprecated
|
# Deprecated
|
||||||
|
|
||||||
|
|||||||
54
scm-ui/ui-components/src/MarkdownCodeRenderer.tsx
Normal file
54
scm-ui/ui-components/src/MarkdownCodeRenderer.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import SyntaxHighlighter from "./SyntaxHighlighter";
|
||||||
|
import { ExtensionPoint, useBinder } from "@scm-manager/ui-extensions";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
language?: string;
|
||||||
|
value: string;
|
||||||
|
indexLinks: { [key: string]: any };
|
||||||
|
};
|
||||||
|
|
||||||
|
const MarkdownCodeRenderer: FC<Props> = (props) => {
|
||||||
|
const binder = useBinder();
|
||||||
|
const { language, indexLinks } = props;
|
||||||
|
const extensionKey = `markdown-renderer.code.${language}`;
|
||||||
|
if (binder.hasExtension(extensionKey, props)) {
|
||||||
|
return <ExtensionPoint name={extensionKey} props={{ ...props, indexLinks }} />;
|
||||||
|
}
|
||||||
|
return <SyntaxHighlighter {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state: any) => {
|
||||||
|
const indexLinks = state.indexResources.links;
|
||||||
|
|
||||||
|
return {
|
||||||
|
indexLinks,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(MarkdownCodeRenderer);
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React from "react";
|
import React, { FC } from "react";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import MarkdownView from "./MarkdownView";
|
import MarkdownView from "./MarkdownView";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
@@ -29,20 +29,22 @@ import styled from "styled-components";
|
|||||||
import TestPage from "./__resources__/test-page.md";
|
import TestPage from "./__resources__/test-page.md";
|
||||||
import MarkdownWithoutLang from "./__resources__/markdown-without-lang.md";
|
import MarkdownWithoutLang from "./__resources__/markdown-without-lang.md";
|
||||||
import MarkdownXmlCodeBlock from "./__resources__/markdown-xml-codeblock.md";
|
import MarkdownXmlCodeBlock from "./__resources__/markdown-xml-codeblock.md";
|
||||||
|
import MarkdownUmlCodeBlock from "./__resources__/markdown-uml-codeblock.md";
|
||||||
import MarkdownInlineXml from "./__resources__/markdown-inline-xml.md";
|
import MarkdownInlineXml from "./__resources__/markdown-inline-xml.md";
|
||||||
import MarkdownLinks from "./__resources__/markdown-links.md";
|
import MarkdownLinks from "./__resources__/markdown-links.md";
|
||||||
import MarkdownCommitLinks from "./__resources__/markdown-commit-link.md";
|
import MarkdownCommitLinks from "./__resources__/markdown-commit-link.md";
|
||||||
import Title from "./layout/Title";
|
import Title from "./layout/Title";
|
||||||
import { Subtitle } from "./layout";
|
import { Subtitle } from "./layout";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
|
import { Binder, BinderContext } from "@scm-manager/ui-extensions";
|
||||||
|
|
||||||
const Spacing = styled.div`
|
const Spacing = styled.div`
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
storiesOf("MarkdownView", module)
|
storiesOf("MarkdownView", module)
|
||||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||||
.addDecorator(story => <Spacing>{story()}</Spacing>)
|
.addDecorator((story) => <Spacing>{story()}</Spacing>)
|
||||||
.add("Default", () => <MarkdownView content={TestPage} skipHtml={false} />)
|
.add("Default", () => <MarkdownView content={TestPage} skipHtml={false} />)
|
||||||
.add("Code without Lang", () => <MarkdownView content={MarkdownWithoutLang} skipHtml={false} />)
|
.add("Code without Lang", () => <MarkdownView content={MarkdownWithoutLang} skipHtml={false} />)
|
||||||
.add("Xml Code Block", () => <MarkdownView content={MarkdownXmlCodeBlock} />)
|
.add("Xml Code Block", () => <MarkdownView content={MarkdownXmlCodeBlock} />)
|
||||||
@@ -54,4 +56,23 @@ storiesOf("MarkdownView", module)
|
|||||||
</>
|
</>
|
||||||
))
|
))
|
||||||
.add("Links", () => <MarkdownView content={MarkdownLinks} basePath="/" />)
|
.add("Links", () => <MarkdownView content={MarkdownLinks} basePath="/" />)
|
||||||
.add("Commit Links", () => <MarkdownView content={MarkdownCommitLinks} />);
|
.add("Commit Links", () => <MarkdownView content={MarkdownCommitLinks} />)
|
||||||
|
.add("Custom code renderer", () => {
|
||||||
|
const binder = new Binder("custom code renderer");
|
||||||
|
const Container: FC<{ value: string }> = ({ value }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4 style={{ border: "1px dashed lightgray", padding: "2px" }}>
|
||||||
|
To render plantuml as images within markdown, please install the scm-markdown-plantuml-plguin
|
||||||
|
</h4>
|
||||||
|
<pre>{value}</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
binder.bind("markdown-renderer.code.uml", Container);
|
||||||
|
return (
|
||||||
|
<BinderContext.Provider value={binder}>
|
||||||
|
<MarkdownView content={MarkdownUmlCodeBlock} />
|
||||||
|
</BinderContext.Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ import { RouteComponentProps, withRouter } from "react-router-dom";
|
|||||||
import Markdown from "react-markdown/with-html";
|
import Markdown from "react-markdown/with-html";
|
||||||
import { binder } from "@scm-manager/ui-extensions";
|
import { binder } from "@scm-manager/ui-extensions";
|
||||||
import ErrorBoundary from "./ErrorBoundary";
|
import ErrorBoundary from "./ErrorBoundary";
|
||||||
import SyntaxHighlighter from "./SyntaxHighlighter";
|
|
||||||
import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer";
|
import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer";
|
||||||
import { create } from "./MarkdownLinkRenderer";
|
import { create } from "./MarkdownLinkRenderer";
|
||||||
import { useTranslation, WithTranslation, withTranslation } from "react-i18next";
|
import { useTranslation, WithTranslation, withTranslation } from "react-i18next";
|
||||||
import Notification from "./Notification";
|
import Notification from "./Notification";
|
||||||
import { createTransformer } from "./remarkChangesetShortLinkParser";
|
import { createTransformer } from "./remarkChangesetShortLinkParser";
|
||||||
|
import MarkdownCodeRenderer from "./MarkdownCodeRenderer";
|
||||||
|
|
||||||
type Props = RouteComponentProps &
|
type Props = RouteComponentProps &
|
||||||
WithTranslation & {
|
WithTranslation & {
|
||||||
@@ -81,13 +81,13 @@ const MarkdownErrorNotification: FC = () => {
|
|||||||
class MarkdownView extends React.Component<Props, State> {
|
class MarkdownView extends React.Component<Props, State> {
|
||||||
static defaultProps: Partial<Props> = {
|
static defaultProps: Partial<Props> = {
|
||||||
enableAnchorHeadings: false,
|
enableAnchorHeadings: false,
|
||||||
skipHtml: false
|
skipHtml: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
contentRef: null
|
contentRef: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,12 +137,12 @@ class MarkdownView extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rendererList.code) {
|
if (!rendererList.code) {
|
||||||
rendererList.code = SyntaxHighlighter;
|
rendererList.code = MarkdownCodeRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary fallback={MarkdownErrorNotification}>
|
<ErrorBoundary fallback={MarkdownErrorNotification}>
|
||||||
<div ref={el => this.setState({ contentRef: el })}>
|
<div ref={(el) => this.setState({ contentRef: el })}>
|
||||||
<Markdown
|
<Markdown
|
||||||
className="content is-word-break"
|
className="content is-word-break"
|
||||||
skipHtml={skipHtml}
|
skipHtml={skipHtml}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
export default `# Uml Code Block in Markdown
|
||||||
|
\`\`\`uml
|
||||||
|
actor Foo1
|
||||||
|
boundary Foo2
|
||||||
|
control Foo3
|
||||||
|
entity Foo4
|
||||||
|
database Foo5
|
||||||
|
collections Foo6
|
||||||
|
Foo1 -> Foo2 : To boundary
|
||||||
|
Foo1 -> Foo3 : To control
|
||||||
|
Foo1 -> Foo4 : To entity
|
||||||
|
Foo1 -> Foo5 : To database
|
||||||
|
Foo1 -> Foo6 : To collections
|
||||||
|
\`\`\``;
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user