2019-03-08 06:30:47 -06:00
|
|
|
// Libraries
|
2022-04-22 08:33:13 -05:00
|
|
|
import { css, cx } from '@emotion/css';
|
|
|
|
import DangerouslySetHtmlContent from 'dangerously-set-html-content';
|
2019-03-08 06:30:47 -06:00
|
|
|
import { debounce } from 'lodash';
|
2022-04-22 08:33:13 -05:00
|
|
|
import React, { PureComponent } from 'react';
|
|
|
|
|
2021-12-21 10:32:48 -06:00
|
|
|
import { PanelProps, renderTextPanelMarkdown, textUtil } from '@grafana/data';
|
2019-03-08 06:30:47 -06:00
|
|
|
// Utils
|
2022-04-22 08:33:13 -05:00
|
|
|
import { CustomScrollbar, stylesFactory } from '@grafana/ui';
|
2019-02-23 23:53:20 -06:00
|
|
|
import config from 'app/core/config';
|
2022-04-22 08:33:13 -05:00
|
|
|
|
2019-02-23 23:53:20 -06:00
|
|
|
// Types
|
2021-04-29 22:12:37 -05:00
|
|
|
import { PanelOptions, TextMode } from './models.gen';
|
2019-02-23 23:53:20 -06:00
|
|
|
|
2022-07-15 04:06:16 -05:00
|
|
|
export interface Props extends PanelProps<PanelOptions> {}
|
2020-07-17 11:00:58 -05:00
|
|
|
|
2019-02-23 23:53:20 -06:00
|
|
|
interface State {
|
|
|
|
html: string;
|
|
|
|
}
|
|
|
|
|
2019-03-06 17:54:19 -06:00
|
|
|
export class TextPanel extends PureComponent<Props, State> {
|
2019-06-19 06:40:42 -05:00
|
|
|
constructor(props: Props) {
|
2019-02-23 23:53:20 -06:00
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
2019-03-05 13:14:22 -06:00
|
|
|
html: this.processContent(props.options),
|
2019-02-23 23:53:20 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
updateHTML = debounce(() => {
|
|
|
|
const html = this.processContent(this.props.options);
|
|
|
|
if (html !== this.state.html) {
|
|
|
|
this.setState({ html });
|
|
|
|
}
|
2019-03-06 17:54:19 -06:00
|
|
|
}, 150);
|
2019-02-23 23:53:20 -06:00
|
|
|
|
|
|
|
componentDidUpdate(prevProps: Props) {
|
|
|
|
// Since any change could be referenced in a template variable,
|
2020-10-07 05:29:30 -05:00
|
|
|
// This needs to process every time (with debounce)
|
2019-02-23 23:53:20 -06:00
|
|
|
this.updateHTML();
|
|
|
|
}
|
|
|
|
|
|
|
|
prepareHTML(html: string): string {
|
2022-06-29 07:26:31 -05:00
|
|
|
const result = this.interpolateString(html);
|
|
|
|
return config.disableSanitizeHtml ? result : this.sanitizeString(result);
|
2019-02-23 23:53:20 -06:00
|
|
|
}
|
|
|
|
|
2020-08-09 23:38:22 -05:00
|
|
|
prepareMarkdown(content: string): string {
|
2022-06-29 07:26:31 -05:00
|
|
|
// Always interpolate variables before converting to markdown
|
|
|
|
// because `marked` replaces '{' and '}' in URLs with '%7B' and '%7D'
|
|
|
|
// See https://marked.js.org/demo
|
|
|
|
let result = this.interpolateString(content);
|
|
|
|
|
|
|
|
if (config.disableSanitizeHtml) {
|
|
|
|
result = renderTextPanelMarkdown(result, {
|
|
|
|
noSanitize: true,
|
|
|
|
});
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = renderTextPanelMarkdown(result);
|
|
|
|
return this.sanitizeString(result);
|
2019-02-23 23:53:20 -06:00
|
|
|
}
|
|
|
|
|
2022-06-29 07:26:31 -05:00
|
|
|
interpolateString(content: string): string {
|
2020-08-09 23:38:22 -05:00
|
|
|
const { replaceVariables } = this.props;
|
2022-06-29 07:26:31 -05:00
|
|
|
return replaceVariables(content, {}, 'html');
|
|
|
|
}
|
2020-08-09 23:38:22 -05:00
|
|
|
|
2022-06-29 07:26:31 -05:00
|
|
|
sanitizeString(content: string): string {
|
|
|
|
return textUtil.sanitizeTextPanelContent(content);
|
2019-02-23 23:53:20 -06:00
|
|
|
}
|
|
|
|
|
2021-04-29 22:12:37 -05:00
|
|
|
processContent(options: PanelOptions): string {
|
2019-02-23 23:53:20 -06:00
|
|
|
const { mode, content } = options;
|
|
|
|
|
|
|
|
if (!content) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2021-04-29 22:12:37 -05:00
|
|
|
if (mode === TextMode.HTML) {
|
|
|
|
return this.prepareHTML(content);
|
2019-02-23 23:53:20 -06:00
|
|
|
}
|
|
|
|
|
2021-04-29 22:12:37 -05:00
|
|
|
return this.prepareMarkdown(content);
|
2019-02-23 23:53:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { html } = this.state;
|
2020-07-04 14:26:55 -05:00
|
|
|
const styles = getStyles();
|
2020-07-27 01:00:57 -05:00
|
|
|
return (
|
|
|
|
<CustomScrollbar autoHeightMin="100%">
|
2022-07-15 04:06:16 -05:00
|
|
|
<DangerouslySetHtmlContent
|
|
|
|
html={html}
|
|
|
|
className={cx('markdown-html', styles.content)}
|
|
|
|
data-testid="TextPanel-converted-content"
|
|
|
|
/>
|
2020-07-27 01:00:57 -05:00
|
|
|
</CustomScrollbar>
|
|
|
|
);
|
2019-02-23 23:53:20 -06:00
|
|
|
}
|
|
|
|
}
|
2020-07-04 14:26:55 -05:00
|
|
|
|
|
|
|
const getStyles = stylesFactory(() => {
|
|
|
|
return {
|
|
|
|
content: css`
|
|
|
|
height: 100%;
|
|
|
|
`,
|
|
|
|
};
|
|
|
|
});
|