PanelHeader.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import React, { Component } from 'react';
  2. import classNames from 'classnames';
  3. import { isEqual } from 'lodash';
  4. import PanelHeaderCorner from './PanelHeaderCorner';
  5. import { PanelHeaderMenu } from './PanelHeaderMenu';
  6. import templateSrv from 'app/features/templating/template_srv';
  7. import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
  8. import { PanelModel } from 'app/features/dashboard/state/PanelModel';
  9. import { ClickOutsideWrapper } from 'app/core/components/ClickOutsideWrapper/ClickOutsideWrapper';
  10. export interface Props {
  11. panel: PanelModel;
  12. dashboard: DashboardModel;
  13. timeInfo: string;
  14. title?: string;
  15. description?: string;
  16. scopedVars?: string;
  17. links?: [];
  18. error?: string;
  19. isFullscreen: boolean;
  20. }
  21. interface ClickCoordinates {
  22. x: number;
  23. y: number;
  24. }
  25. interface State {
  26. panelMenuOpen: boolean;
  27. }
  28. export class PanelHeader extends Component<Props, State> {
  29. clickCoordinates: ClickCoordinates = { x: 0, y: 0 };
  30. state = {
  31. panelMenuOpen: false,
  32. clickCoordinates: { x: 0, y: 0 },
  33. };
  34. eventToClickCoordinates = (event: React.MouseEvent<HTMLDivElement>) => {
  35. return {
  36. x: event.clientX,
  37. y: event.clientY,
  38. };
  39. };
  40. onMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
  41. this.clickCoordinates = this.eventToClickCoordinates(event);
  42. };
  43. isClick = (clickCoordinates: ClickCoordinates) => {
  44. return isEqual(clickCoordinates, this.clickCoordinates);
  45. };
  46. onMenuToggle = (event: React.MouseEvent<HTMLDivElement>) => {
  47. if (this.isClick(this.eventToClickCoordinates(event))) {
  48. event.stopPropagation();
  49. this.setState(prevState => ({
  50. panelMenuOpen: !prevState.panelMenuOpen,
  51. }));
  52. }
  53. };
  54. closeMenu = () => {
  55. this.setState({
  56. panelMenuOpen: false,
  57. });
  58. };
  59. render() {
  60. const { panel, dashboard, timeInfo, scopedVars, error, isFullscreen } = this.props;
  61. const panelHeaderClass = classNames({ 'panel-header': true, 'grid-drag-handle': !isFullscreen });
  62. const title = templateSrv.replaceWithText(panel.title, scopedVars);
  63. return (
  64. <>
  65. <PanelHeaderCorner
  66. panel={panel}
  67. title={panel.title}
  68. description={panel.description}
  69. scopedVars={panel.scopedVars}
  70. links={panel.links}
  71. error={error}
  72. />
  73. <div className={panelHeaderClass}>
  74. <div className="panel-title-container" onClick={this.onMenuToggle} onMouseDown={this.onMouseDown}>
  75. <div className="panel-title">
  76. <span className="icon-gf panel-alert-icon" />
  77. <span className="panel-title-text">
  78. {title} <span className="fa fa-caret-down panel-menu-toggle" />
  79. </span>
  80. {this.state.panelMenuOpen && (
  81. <ClickOutsideWrapper onClick={this.closeMenu}>
  82. <PanelHeaderMenu panel={panel} dashboard={dashboard} />
  83. </ClickOutsideWrapper>
  84. )}
  85. {timeInfo && (
  86. <span className="panel-time-info">
  87. <i className="fa fa-clock-o" /> {timeInfo}
  88. </span>
  89. )}
  90. </div>
  91. </div>
  92. </div>
  93. </>
  94. );
  95. }
  96. }