FunctionEditor.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import React, { Suspense } from 'react';
  2. import { PopoverController, Popover } from '@grafana/ui';
  3. import { FunctionDescriptor, FunctionEditorControls, FunctionEditorControlsProps } from './FunctionEditorControls';
  4. interface FunctionEditorProps extends FunctionEditorControlsProps {
  5. func: FunctionDescriptor;
  6. }
  7. interface FunctionEditorState {
  8. showingDescription: boolean;
  9. }
  10. const FunctionDescription = React.lazy(async () => {
  11. // @ts-ignore
  12. const { default: rst2html } = await import(/* webpackChunkName: "rst2html" */ 'rst2html');
  13. return {
  14. default: (props: { description: string }) => (
  15. <div dangerouslySetInnerHTML={{ __html: rst2html(props.description) }} />
  16. ),
  17. };
  18. });
  19. class FunctionEditor extends React.PureComponent<FunctionEditorProps, FunctionEditorState> {
  20. private triggerRef = React.createRef<HTMLSpanElement>();
  21. constructor(props: FunctionEditorProps) {
  22. super(props);
  23. this.state = {
  24. showingDescription: false,
  25. };
  26. }
  27. renderContent = ({ updatePopperPosition }: any) => {
  28. const {
  29. onMoveLeft,
  30. onMoveRight,
  31. func: {
  32. def: { name, description },
  33. },
  34. } = this.props;
  35. const { showingDescription } = this.state;
  36. if (showingDescription) {
  37. return (
  38. <div style={{ overflow: 'auto', maxHeight: '30rem', textAlign: 'left', fontWeight: 'normal' }}>
  39. <h4 style={{ color: 'white' }}> {name} </h4>
  40. <Suspense fallback={<span>Loading description...</span>}>
  41. <FunctionDescription description={description} />
  42. </Suspense>
  43. </div>
  44. );
  45. }
  46. return (
  47. <FunctionEditorControls
  48. {...this.props}
  49. onMoveLeft={() => {
  50. onMoveLeft(this.props.func);
  51. updatePopperPosition();
  52. }}
  53. onMoveRight={() => {
  54. onMoveRight(this.props.func);
  55. updatePopperPosition();
  56. }}
  57. onDescriptionShow={() => {
  58. this.setState({ showingDescription: true }, () => {
  59. updatePopperPosition();
  60. });
  61. }}
  62. />
  63. );
  64. };
  65. render() {
  66. return (
  67. <PopoverController content={this.renderContent} placement="top" hideAfter={300}>
  68. {(showPopper, hidePopper, popperProps) => {
  69. return (
  70. <>
  71. {this.triggerRef && (
  72. <Popover
  73. {...popperProps}
  74. referenceElement={this.triggerRef.current}
  75. wrapperClassName="popper"
  76. className="popper__background"
  77. onMouseLeave={() => {
  78. this.setState({ showingDescription: false });
  79. hidePopper();
  80. }}
  81. onMouseEnter={showPopper}
  82. renderArrow={({ arrowProps, placement }) => (
  83. <div className="popper__arrow" data-placement={placement} {...arrowProps} />
  84. )}
  85. />
  86. )}
  87. <span
  88. ref={this.triggerRef}
  89. onClick={popperProps.show ? hidePopper : showPopper}
  90. onMouseLeave={() => {
  91. hidePopper();
  92. this.setState({ showingDescription: false });
  93. }}
  94. style={{ cursor: 'pointer' }}
  95. >
  96. {this.props.func.def.name}
  97. </span>
  98. </>
  99. );
  100. }}
  101. </PopoverController>
  102. );
  103. }
  104. }
  105. export { FunctionEditor };