PanelChrome.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Libraries
  2. import React, { PureComponent } from 'react';
  3. import { AutoSizer } from 'react-virtualized';
  4. // Services
  5. import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
  6. // Components
  7. import { PanelHeader } from './PanelHeader/PanelHeader';
  8. import { DataPanel } from './DataPanel';
  9. // Utils
  10. import { applyPanelTimeOverrides, snapshotDataToPanelData } from 'app/features/dashboard/utils/panel';
  11. import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
  12. import { profiler } from 'app/core/profiler';
  13. // Types
  14. import { DashboardModel, PanelModel } from '../state';
  15. import { PanelPlugin } from 'app/types';
  16. import { TimeRange, LoadingState, PanelData } from '@grafana/ui';
  17. import variables from 'sass/_variables.scss';
  18. import templateSrv from 'app/features/templating/template_srv';
  19. import { DataQueryResponse } from '@grafana/ui/src';
  20. export interface Props {
  21. panel: PanelModel;
  22. dashboard: DashboardModel;
  23. plugin: PanelPlugin;
  24. }
  25. export interface State {
  26. refreshCounter: number;
  27. renderCounter: number;
  28. timeInfo?: string;
  29. timeRange?: TimeRange;
  30. }
  31. export class PanelChrome extends PureComponent<Props, State> {
  32. timeSrv: TimeSrv = getTimeSrv();
  33. constructor(props) {
  34. super(props);
  35. this.state = {
  36. refreshCounter: 0,
  37. renderCounter: 0,
  38. };
  39. }
  40. componentDidMount() {
  41. this.props.panel.events.on('refresh', this.onRefresh);
  42. this.props.panel.events.on('render', this.onRender);
  43. this.props.dashboard.panelInitialized(this.props.panel);
  44. }
  45. componentWillUnmount() {
  46. this.props.panel.events.off('refresh', this.onRefresh);
  47. }
  48. onRefresh = () => {
  49. console.log('onRefresh');
  50. if (!this.isVisible) {
  51. return;
  52. }
  53. const { panel } = this.props;
  54. const timeData = applyPanelTimeOverrides(panel, this.timeSrv.timeRange());
  55. this.setState({
  56. refreshCounter: this.state.refreshCounter + 1,
  57. timeRange: timeData.timeRange,
  58. timeInfo: timeData.timeInfo,
  59. });
  60. };
  61. onRender = () => {
  62. this.setState({
  63. renderCounter: this.state.renderCounter + 1,
  64. });
  65. };
  66. onInterpolate = (value: string, format?: string) => {
  67. return templateSrv.replace(value, this.props.panel.scopedVars, format);
  68. };
  69. onDataResponse = (dataQueryResponse: DataQueryResponse) => {
  70. if (this.props.dashboard.isSnapshot()) {
  71. this.props.panel.snapshotData = dataQueryResponse.data;
  72. }
  73. };
  74. get isVisible() {
  75. return !this.props.dashboard.otherPanelInFullscreen(this.props.panel);
  76. }
  77. get hasPanelSnapshot() {
  78. const { panel } = this.props;
  79. return panel.snapshotData && panel.snapshotData.length;
  80. }
  81. get needsQueryExecution() {
  82. return this.hasPanelSnapshot || this.props.plugin.dataFormats.length > 0;
  83. }
  84. get getDataForPanel() {
  85. return this.hasPanelSnapshot ? snapshotDataToPanelData(this.props.panel) : null;
  86. }
  87. renderPanelPlugin(loading: LoadingState, panelData: PanelData, width: number, height: number): JSX.Element {
  88. const { panel, plugin } = this.props;
  89. const { timeRange, renderCounter } = this.state;
  90. const PanelComponent = plugin.exports.Panel;
  91. // This is only done to increase a counter that is used by backend
  92. // image rendering (phantomjs/headless chrome) to know when to capture image
  93. if (loading === LoadingState.Done) {
  94. profiler.renderingCompleted(panel.id);
  95. }
  96. return (
  97. <div className="panel-content">
  98. <PanelComponent
  99. loading={loading}
  100. panelData={panelData}
  101. timeRange={timeRange}
  102. options={panel.getOptions(plugin.exports.PanelDefaults)}
  103. width={width - 2 * variables.panelHorizontalPadding}
  104. height={height - PANEL_HEADER_HEIGHT - variables.panelVerticalPadding}
  105. renderCounter={renderCounter}
  106. onInterpolate={this.onInterpolate}
  107. />
  108. </div>
  109. );
  110. }
  111. renderPanelBody = (width: number, height: number): JSX.Element => {
  112. const { panel } = this.props;
  113. const { refreshCounter, timeRange } = this.state;
  114. const { datasource, targets } = panel;
  115. return (
  116. <>
  117. {this.needsQueryExecution ? (
  118. <DataPanel
  119. panelId={panel.id}
  120. datasource={datasource}
  121. queries={targets}
  122. timeRange={timeRange}
  123. isVisible={this.isVisible}
  124. widthPixels={width}
  125. refreshCounter={refreshCounter}
  126. onDataResponse={this.onDataResponse}
  127. >
  128. {({ loading, panelData }) => {
  129. return this.renderPanelPlugin(loading, panelData, width, height);
  130. }}
  131. </DataPanel>
  132. ) : (
  133. this.renderPanelPlugin(LoadingState.Done, this.getDataForPanel, width, height)
  134. )}
  135. </>
  136. );
  137. };
  138. render() {
  139. const { dashboard, panel } = this.props;
  140. const { timeInfo } = this.state;
  141. const { transparent } = panel;
  142. const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`;
  143. return (
  144. <AutoSizer>
  145. {({ width, height }) => {
  146. if (width === 0) {
  147. return null;
  148. }
  149. return (
  150. <div className={containerClassNames}>
  151. <PanelHeader
  152. panel={panel}
  153. dashboard={dashboard}
  154. timeInfo={timeInfo}
  155. title={panel.title}
  156. description={panel.description}
  157. scopedVars={panel.scopedVars}
  158. links={panel.links}
  159. />
  160. {this.renderPanelBody(width, height)}
  161. </div>
  162. );
  163. }}
  164. </AutoSizer>
  165. );
  166. }
  167. }