PanelHeader.tsx 3.4 KB

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