import React, { Component } from 'react'; import { compareArrayValues, compareDataFrameStructures, fieldReducers, getFieldDisplayName, getFrameDisplayName, PanelProps, ReducerID, } from '@grafana/data'; import { IconButton } from '@grafana/ui'; import { DebugPanelOptions, UpdateCounters, UpdateConfig } from './types'; type Props = PanelProps; export class RenderInfoViewer extends Component { // Intentionally not state to avoid overhead -- yes, things will be 1 tick behind lastRender = Date.now(); counters: UpdateCounters = { render: 0, dataChanged: 0, schemaChanged: 0, }; shouldComponentUpdate(prevProps: Props) { const { data, options } = this.props; if (prevProps.data !== data) { this.counters.dataChanged++; if (options.counters?.schemaChanged) { const oldSeries = prevProps.data?.series; const series = data.series; if (series && oldSeries) { const sameStructure = compareArrayValues(series, oldSeries, compareDataFrameStructures); if (!sameStructure) { this.counters.schemaChanged++; } } } } return true; // always render? } resetCounters = () => { this.counters = { render: 0, dataChanged: 0, schemaChanged: 0, }; this.forceUpdate(); }; render() { const { data, options } = this.props; const showCounters = options.counters ?? ({} as UpdateConfig); this.counters.render++; const now = Date.now(); const elapsed = now - this.lastRender; this.lastRender = now; const reducer = fieldReducers.get(ReducerID.lastNotNull); return (
{showCounters.render && Render: {this.counters.render} } {showCounters.dataChanged && Data: {this.counters.dataChanged} } {showCounters.schemaChanged && Schema: {this.counters.schemaChanged} } TIME: {elapsed}ms
{data.series && data.series.map((frame, idx) => (

{getFrameDisplayName(frame, idx)} ({frame.length})

{frame.fields.map((field, idx) => { const v = reducer.reduce!(field, false, false)[reducer.id]; return ( ); })}
Field Type Last
{getFieldDisplayName(field, frame, data.series)} {field.type} {`${v}`}
))}
); } }