mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Markdown: Replace rendering library (#17686)
* Replace remarkable with marked * Add wrapper and options for marked
This commit is contained in:
parent
6fb36e705f
commit
8541214c9e
@ -42,7 +42,6 @@
|
||||
"@types/react-transition-group": "2.0.16",
|
||||
"@types/react-virtualized": "9.18.12",
|
||||
"@types/react-window": "1.7.0",
|
||||
"@types/remarkable": "1.7.4",
|
||||
"angular-mocks": "1.6.6",
|
||||
"autoprefixer": "9.5.0",
|
||||
"axios": "0.19.0",
|
||||
@ -192,6 +191,7 @@
|
||||
"@types/angular-route": "1.7.0",
|
||||
"@types/d3-scale-chromatic": "1.3.1",
|
||||
"@types/enzyme-adapter-react-16": "1.0.5",
|
||||
"@types/marked": "0.6.5",
|
||||
"@types/react-redux": "^7.0.8",
|
||||
"@types/redux-logger": "3.0.7",
|
||||
"@types/reselect": "2.2.0",
|
||||
@ -214,6 +214,7 @@
|
||||
"immutable": "3.8.2",
|
||||
"jquery": "3.4.1",
|
||||
"lodash": "4.17.11",
|
||||
"marked": "0.6.2",
|
||||
"moment": "2.24.0",
|
||||
"mousetrap": "1.6.3",
|
||||
"mousetrap-global-bind": "1.1.0",
|
||||
@ -238,7 +239,6 @@
|
||||
"redux-logger": "3.0.6",
|
||||
"redux-observable": "1.1.0",
|
||||
"redux-thunk": "2.3.0",
|
||||
"remarkable": "1.7.1",
|
||||
"reselect": "4.0.0",
|
||||
"rst2html": "github:thoward/rst2html#990cb89",
|
||||
"rxjs": "6.4.0",
|
||||
|
@ -1 +1,2 @@
|
||||
export * from './string';
|
||||
export * from './markdown';
|
||||
|
20
packages/grafana-data/src/utils/markdown.ts
Normal file
20
packages/grafana-data/src/utils/markdown.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import marked, { MarkedOptions } from 'marked';
|
||||
|
||||
const defaultMarkedOptions: MarkedOptions = {
|
||||
renderer: new marked.Renderer(),
|
||||
pedantic: false,
|
||||
gfm: true,
|
||||
tables: true,
|
||||
sanitize: true,
|
||||
smartLists: true,
|
||||
smartypants: false,
|
||||
xhtml: false,
|
||||
};
|
||||
|
||||
export function setMarkdownOptions(optionsOverride?: MarkedOptions) {
|
||||
marked.setOptions({ ...defaultMarkedOptions, ...optionsOverride });
|
||||
}
|
||||
|
||||
export function renderMarkdown(str: string): string {
|
||||
return marked(str);
|
||||
}
|
@ -36,6 +36,7 @@ import { setupAngularRoutes } from 'app/routes/routes';
|
||||
import 'app/routes/GrafanaCtrl';
|
||||
import 'app/features/all';
|
||||
import { setLocale } from '@grafana/ui/src/utils/moment_wrapper';
|
||||
import { setMarkdownOptions } from '@grafana/data';
|
||||
|
||||
// import symlinked extensions
|
||||
const extensionsIndex = (require as any).context('.', true, /extensions\/index.ts/);
|
||||
@ -70,6 +71,8 @@ export class GrafanaApp {
|
||||
|
||||
setLocale(config.bootData.user.locale);
|
||||
|
||||
setMarkdownOptions({ sanitize: !config.disableSanitizeHtml });
|
||||
|
||||
app.config(
|
||||
(
|
||||
$locationProvider: angular.ILocationProvider,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
// @ts-ignore
|
||||
import Remarkable from 'remarkable';
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
|
||||
interface Props {
|
||||
@ -39,8 +38,7 @@ export class PluginHelp extends PureComponent<Props, State> {
|
||||
getBackendSrv()
|
||||
.get(`/api/plugins/${plugin.id}/markdown/${type}`)
|
||||
.then((response: string) => {
|
||||
const markdown = new Remarkable();
|
||||
const helpHtml = markdown.render(response);
|
||||
const helpHtml = renderMarkdown(response);
|
||||
|
||||
if (response === '' && type === 'help') {
|
||||
this.setState({
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import Remarkable from 'remarkable';
|
||||
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
import { Tooltip, ScopedVars, DataLink } from '@grafana/ui';
|
||||
|
||||
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
||||
@ -45,11 +46,12 @@ export class PanelHeaderCorner extends Component<Props> {
|
||||
const markdown = panel.description;
|
||||
const linkSrv = new LinkSrv(templateSrv, this.timeSrv);
|
||||
const interpolatedMarkdown = templateSrv.replace(markdown, panel.scopedVars);
|
||||
const remarkableInterpolatedMarkdown = new Remarkable().render(interpolatedMarkdown);
|
||||
const markedInterpolatedMarkdown = renderMarkdown(interpolatedMarkdown);
|
||||
|
||||
return (
|
||||
<div className="markdown-html panel-info-content">
|
||||
<p dangerouslySetInnerHTML={{ __html: remarkableInterpolatedMarkdown }} />
|
||||
<div className="panel-info-content markdown-html">
|
||||
<div dangerouslySetInnerHTML={{ __html: markedInterpolatedMarkdown }} />
|
||||
|
||||
{panel.links && panel.links.length > 0 && (
|
||||
<ul className="panel-info-corner-links">
|
||||
{panel.links.map((link, idx) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
import Remarkable from 'remarkable';
|
||||
import { sanitize, escapeHtml } from 'app/core/utils/text';
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
|
||||
import config from 'app/core/config';
|
||||
import { profiler } from 'app/core/core';
|
||||
@ -259,8 +259,8 @@ export class PanelCtrl {
|
||||
const interpolatedMarkdown = templateSrv.replace(markdown, this.panel.scopedVars);
|
||||
let html = '<div class="markdown-html panel-info-content">';
|
||||
|
||||
const md = new Remarkable().render(interpolatedMarkdown);
|
||||
html += sanitize(md);
|
||||
const md = renderMarkdown(interpolatedMarkdown);
|
||||
html += config.disableSanitizeHtml ? md : sanitize(md);
|
||||
|
||||
if (this.panel.links && this.panel.links.length > 0) {
|
||||
html += '<ul class="panel-info-corner-links">';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import Remarkable from 'remarkable';
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import UsersActionBar from './UsersActionBar';
|
||||
import UsersTable from './UsersTable';
|
||||
@ -38,8 +38,7 @@ export class UsersListPage extends PureComponent<Props, State> {
|
||||
super(props);
|
||||
|
||||
if (this.props.externalUserMngInfo) {
|
||||
const markdownRenderer = new Remarkable();
|
||||
this.externalUserMngInfoHtml = markdownRenderer.render(this.props.externalUserMngInfo);
|
||||
this.externalUserMngInfoHtml = renderMarkdown(this.props.externalUserMngInfo);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import _ from 'lodash';
|
||||
import { PanelCtrl } from 'app/plugins/sdk';
|
||||
import Remarkable from 'remarkable';
|
||||
|
||||
import { sanitize, escapeHtml } from 'app/core/utils/text';
|
||||
import config from 'app/core/config';
|
||||
import { auto, ISCEService } from 'angular';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
|
||||
const defaultContent = `
|
||||
# Title
|
||||
@ -19,7 +20,6 @@ export class TextPanelCtrl extends PanelCtrl {
|
||||
static templateUrl = `public/app/plugins/panel/text/module.html`;
|
||||
static scrollable = true;
|
||||
|
||||
remarkable: any;
|
||||
content: string;
|
||||
// Set and populate defaults
|
||||
panelDefaults = {
|
||||
@ -82,12 +82,8 @@ export class TextPanelCtrl extends PanelCtrl {
|
||||
}
|
||||
|
||||
renderMarkdown(content: string) {
|
||||
if (!this.remarkable) {
|
||||
this.remarkable = new Remarkable();
|
||||
}
|
||||
|
||||
this.$scope.$applyAsync(() => {
|
||||
this.updateContent(this.remarkable.render(content));
|
||||
this.updateContent(renderMarkdown(content));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
import Remarkable from 'remarkable';
|
||||
import { debounce } from 'lodash';
|
||||
import { renderMarkdown } from '@grafana/data';
|
||||
|
||||
// Utils
|
||||
import { sanitize } from 'app/core/utils/text';
|
||||
@ -17,8 +17,6 @@ interface State {
|
||||
}
|
||||
|
||||
export class TextPanel extends PureComponent<Props, State> {
|
||||
remarkable: Remarkable;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -59,10 +57,7 @@ export class TextPanel extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
prepareMarkdown(content: string): string {
|
||||
if (!this.remarkable) {
|
||||
this.remarkable = new Remarkable();
|
||||
}
|
||||
return this.prepareHTML(this.remarkable.render(content));
|
||||
return this.prepareHTML(renderMarkdown(content));
|
||||
}
|
||||
|
||||
processContent(options: TextOptions): string {
|
||||
|
41
yarn.lock
41
yarn.lock
@ -2074,6 +2074,11 @@
|
||||
version "4.14.123"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d"
|
||||
|
||||
"@types/marked@0.6.5":
|
||||
version "0.6.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.6.5.tgz#3cf2a56ef615dad24aaf99784ef90a9eba4e29d8"
|
||||
integrity sha512-6kBKf64aVfx93UJrcyEZ+OBM5nGv4RLsI6sR1Ar34bpgvGVRoyTgpxn4ZmtxOM5aDTAaaznYuYUH8bUX3Nk3YA==
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||
@ -2221,11 +2226,6 @@
|
||||
dependencies:
|
||||
redux "^3.6.0"
|
||||
|
||||
"@types/remarkable@1.7.4":
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/remarkable/-/remarkable-1.7.4.tgz#0faee73dc42cf21d718e20065a0961e53fa8e570"
|
||||
integrity sha512-fsFfCxJt0C4DvAxdMR9JcnVY6FfAQrH8ia7NT0MStVbsgR73+a7XYFRhNqRHg2/FC2Sxfbg3ekuiFuY8eMOvMQ==
|
||||
|
||||
"@types/reselect@2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/reselect/-/reselect-2.2.0.tgz#c667206cfdc38190e1d379babe08865b2288575f"
|
||||
@ -2881,13 +2881,6 @@ argparse@^1.0.2, argparse@^1.0.7:
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
argparse@~0.1.15:
|
||||
version "0.1.16"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c"
|
||||
dependencies:
|
||||
underscore "~1.7.0"
|
||||
underscore.string "~2.4.0"
|
||||
|
||||
arr-diff@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
|
||||
@ -3080,10 +3073,6 @@ atob@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
|
||||
autolinker@~0.15.0:
|
||||
version "0.15.3"
|
||||
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832"
|
||||
|
||||
autoprefixer@9.5.0:
|
||||
version "9.5.0"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.5.0.tgz#7e51d0355c11596e6cf9a0afc9a44e86d1596c70"
|
||||
@ -9748,6 +9737,11 @@ markdown-to-jsx@^6.9.1:
|
||||
prop-types "^15.6.2"
|
||||
unquote "^1.1.0"
|
||||
|
||||
marked@0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.2.tgz#c574be8b545a8b48641456ca1dbe0e37b6dccc1a"
|
||||
integrity sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==
|
||||
|
||||
marked@^0.3.12:
|
||||
version "0.3.19"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
|
||||
@ -13040,13 +13034,6 @@ relateurl@0.2.x:
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
||||
|
||||
remarkable@1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6"
|
||||
dependencies:
|
||||
argparse "~0.1.15"
|
||||
autolinker "~0.15.0"
|
||||
|
||||
remove-trailing-separator@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
||||
@ -15059,18 +15046,10 @@ undefsafe@^2.0.2:
|
||||
dependencies:
|
||||
debug "^2.2.0"
|
||||
|
||||
underscore.string@~2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"
|
||||
|
||||
underscore.string@~3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.2.3.tgz#806992633665d5e5fcb4db1fb3a862eb68e9e6da"
|
||||
|
||||
underscore@~1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
|
||||
|
||||
unicode-canonical-property-names-ecmascript@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
|
||||
|
Loading…
Reference in New Issue
Block a user