TextPanel.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import React, { Component } from 'react';
  2. import Remarkable from 'remarkable';
  3. import { sanitize } from 'app/core/utils/text';
  4. import config from 'app/core/config';
  5. import { debounce } from 'lodash';
  6. // Types
  7. import { TextOptions } from './types';
  8. import { PanelProps } from '@grafana/ui/src/types';
  9. interface Props extends PanelProps<TextOptions> {}
  10. interface State {
  11. html: string;
  12. }
  13. export class TextPanel extends Component<Props, State> {
  14. remarkable: Remarkable;
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. html: this.processContent(props.options),
  19. };
  20. }
  21. updateHTML = debounce(() => {
  22. const html = this.processContent(this.props.options);
  23. if (html !== this.state.html) {
  24. this.setState({ html });
  25. }
  26. }, 100);
  27. componentDidUpdate(prevProps: Props) {
  28. // Since any change could be referenced in a template variable,
  29. // This needs to process everything
  30. this.updateHTML();
  31. }
  32. prepareHTML(html: string): string {
  33. const { replaceVariables } = this.props;
  34. html = config.disableSanitizeHtml ? html : sanitize(html);
  35. try {
  36. return replaceVariables(html);
  37. } catch (e) {
  38. // TODO -- put the error in the header window
  39. console.log('Text panel error: ', e);
  40. return html;
  41. }
  42. }
  43. prepareText(content: string): string {
  44. return this.prepareHTML(
  45. content
  46. .replace(/&/g, '&amp;')
  47. .replace(/>/g, '&gt;')
  48. .replace(/</g, '&lt;')
  49. .replace(/\n/g, '<br/>')
  50. );
  51. }
  52. prepareMarkdown(content: string): string {
  53. if (!this.remarkable) {
  54. this.remarkable = new Remarkable();
  55. }
  56. return this.prepareHTML(this.remarkable.render(content));
  57. }
  58. processContent(options: TextOptions): string {
  59. const { mode, content } = options;
  60. if (!content) {
  61. return '';
  62. }
  63. if (mode === 'markdown') {
  64. return this.prepareMarkdown(content);
  65. }
  66. if (mode === 'html') {
  67. return this.prepareHTML(content);
  68. }
  69. return this.prepareText(content);
  70. }
  71. render() {
  72. const { html } = this.state;
  73. return <div className="markdown-html panel-text-content" dangerouslySetInnerHTML={{ __html: html }} />;
  74. }
  75. }