PanelChrome.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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. renderPanelPlugin(loading: LoadingState, panelData: PanelData, width: number, height: number): JSX.Element {
  78. const { panel, plugin } = this.props;
  79. const { timeRange, renderCounter } = this.state;
  80. const PanelComponent = plugin.exports.Panel;
  81. // This is only done to increase a counter that is used by backend
  82. // image rendering (phantomjs/headless chrome) to know when to capture image
  83. if (loading === LoadingState.Done) {
  84. profiler.renderingCompleted(panel.id);
  85. }
  86. return (
  87. <div className="panel-content">
  88. <PanelComponent
  89. loading={loading}
  90. panelData={panelData}
  91. timeRange={timeRange}
  92. options={panel.getOptions(plugin.exports.PanelDefaults)}
  93. width={width - 2 * variables.panelHorizontalPadding}
  94. height={height - PANEL_HEADER_HEIGHT - variables.panelVerticalPadding}
  95. renderCounter={renderCounter}
  96. onInterpolate={this.onInterpolate}
  97. />
  98. </div>
  99. );
  100. }
  101. renderHelper = (width: number, height: number): JSX.Element => {
  102. const { panel, plugin } = this.props;
  103. const { refreshCounter, timeRange } = this.state;
  104. const { datasource, targets } = panel;
  105. return (
  106. <>
  107. {panel.snapshotData && panel.snapshotData.length > 0 ? (
  108. this.renderPanelPlugin(LoadingState.Done, snapshotDataToPanelData(panel), width, height)
  109. ) : (
  110. <>
  111. {plugin.noQueries === true ?
  112. this.renderPanelPlugin(LoadingState.Done, null, width, height)
  113. : (
  114. <DataPanel
  115. panelId={panel.id}
  116. datasource={datasource}
  117. queries={targets}
  118. timeRange={timeRange}
  119. isVisible={this.isVisible}
  120. widthPixels={width}
  121. refreshCounter={refreshCounter}
  122. onDataResponse={this.onDataResponse}
  123. >
  124. {({ loading, panelData }) => {
  125. return this.renderPanelPlugin(loading, panelData, width, height);
  126. }}
  127. </DataPanel>
  128. )}
  129. </>
  130. )}
  131. </>
  132. );
  133. }
  134. render() {
  135. const { dashboard, panel } = this.props;
  136. const { timeInfo } = this.state;
  137. const { transparent } = panel;
  138. const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`;
  139. return (
  140. <AutoSizer>
  141. {({ width, height }) => {
  142. if (width === 0) {
  143. return null;
  144. }
  145. return (
  146. <div className={containerClassNames}>
  147. <PanelHeader
  148. panel={panel}
  149. dashboard={dashboard}
  150. timeInfo={timeInfo}
  151. title={panel.title}
  152. description={panel.description}
  153. scopedVars={panel.scopedVars}
  154. links={panel.links}
  155. />
  156. {this.renderHelper(width, height)}
  157. </div>
  158. );
  159. }}
  160. </AutoSizer>
  161. );
  162. }
  163. }