RenderInfoViewer.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import React, { Component } from 'react';
  2. import {
  3. compareArrayValues,
  4. compareDataFrameStructures,
  5. fieldReducers,
  6. getFieldDisplayName,
  7. getFrameDisplayName,
  8. PanelProps,
  9. ReducerID,
  10. } from '@grafana/data';
  11. import { IconButton } from '@grafana/ui';
  12. import { DebugPanelOptions, UpdateCounters, UpdateConfig } from './types';
  13. type Props = PanelProps<DebugPanelOptions>;
  14. export class RenderInfoViewer extends Component<Props> {
  15. // Intentionally not state to avoid overhead -- yes, things will be 1 tick behind
  16. lastRender = Date.now();
  17. counters: UpdateCounters = {
  18. render: 0,
  19. dataChanged: 0,
  20. schemaChanged: 0,
  21. };
  22. shouldComponentUpdate(prevProps: Props) {
  23. const { data, options } = this.props;
  24. if (prevProps.data !== data) {
  25. this.counters.dataChanged++;
  26. if (options.counters?.schemaChanged) {
  27. const oldSeries = prevProps.data?.series;
  28. const series = data.series;
  29. if (series && oldSeries) {
  30. const sameStructure = compareArrayValues(series, oldSeries, compareDataFrameStructures);
  31. if (!sameStructure) {
  32. this.counters.schemaChanged++;
  33. }
  34. }
  35. }
  36. }
  37. return true; // always render?
  38. }
  39. resetCounters = () => {
  40. this.counters = {
  41. render: 0,
  42. dataChanged: 0,
  43. schemaChanged: 0,
  44. };
  45. this.forceUpdate();
  46. };
  47. render() {
  48. const { data, options } = this.props;
  49. const showCounters = options.counters ?? ({} as UpdateConfig);
  50. this.counters.render++;
  51. const now = Date.now();
  52. const elapsed = now - this.lastRender;
  53. this.lastRender = now;
  54. const reducer = fieldReducers.get(ReducerID.lastNotNull);
  55. return (
  56. <div>
  57. <div>
  58. <IconButton name="step-backward" title="reset counters" onClick={this.resetCounters} />
  59. <span>
  60. {showCounters.render && <span>Render: {this.counters.render}&nbsp;</span>}
  61. {showCounters.dataChanged && <span>Data: {this.counters.dataChanged}&nbsp;</span>}
  62. {showCounters.schemaChanged && <span>Schema: {this.counters.schemaChanged}&nbsp;</span>}
  63. <span>TIME: {elapsed}ms</span>
  64. </span>
  65. </div>
  66. {data.series &&
  67. data.series.map((frame, idx) => (
  68. <div key={`${idx}/${frame.refId}`}>
  69. <h4>
  70. {getFrameDisplayName(frame, idx)} ({frame.length})
  71. </h4>
  72. <table className="filter-table">
  73. <thead>
  74. <tr>
  75. <td>Field</td>
  76. <td>Type</td>
  77. <td>Last</td>
  78. </tr>
  79. </thead>
  80. <tbody>
  81. {frame.fields.map((field, idx) => {
  82. const v = reducer.reduce!(field, false, false)[reducer.id];
  83. return (
  84. <tr key={`${idx}/${field.name}`}>
  85. <td>{getFieldDisplayName(field, frame, data.series)}</td>
  86. <td>{field.type}</td>
  87. <td>{`${v}`}</td>
  88. </tr>
  89. );
  90. })}
  91. </tbody>
  92. </table>
  93. </div>
  94. ))}
  95. </div>
  96. );
  97. }
  98. }