mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
GraphNG: make sure dataset and config are in sync when initializing and re-initializing uPlot (#32106)
* Make sure dataset and uPlot config are in sync when rendering uPlot * Tests * Fix TS
This commit is contained in:
@@ -7,6 +7,7 @@ import uPlot from 'uplot';
|
||||
import createMockRaf from 'mock-raf';
|
||||
import { UPlotConfigBuilder } from './config/UPlotConfigBuilder';
|
||||
import { preparePlotData } from './utils';
|
||||
import { SeriesProps } from './config/UPlotSeriesBuilder';
|
||||
|
||||
const mockRaf = createMockRaf();
|
||||
const setDataMock = jest.fn();
|
||||
@@ -52,7 +53,9 @@ const mockData = () => {
|
||||
raw: { from: '1602673200000', to: '1602680400000' },
|
||||
};
|
||||
|
||||
return { data, timeRange, config: new UPlotConfigBuilder() };
|
||||
const config = new UPlotConfigBuilder();
|
||||
config.addSeries({} as SeriesProps);
|
||||
return { data, timeRange, config };
|
||||
};
|
||||
|
||||
describe('UPlotChart', () => {
|
||||
@@ -159,14 +162,11 @@ describe('UPlotChart', () => {
|
||||
|
||||
expect(uPlot).toBeCalledTimes(1);
|
||||
|
||||
const nextConfig = new UPlotConfigBuilder();
|
||||
nextConfig.addSeries({} as SeriesProps);
|
||||
|
||||
rerender(
|
||||
<UPlotChart
|
||||
data={preparePlotData(data)}
|
||||
config={new UPlotConfigBuilder()}
|
||||
timeRange={timeRange}
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
<UPlotChart data={preparePlotData(data)} config={nextConfig} timeRange={timeRange} width={100} height={100} />
|
||||
);
|
||||
|
||||
expect(destroyMock).toBeCalledTimes(1);
|
||||
@@ -190,11 +190,13 @@ describe('UPlotChart', () => {
|
||||
act(() => {
|
||||
mockRaf.step({ count: 1 });
|
||||
});
|
||||
const nextConfig = new UPlotConfigBuilder();
|
||||
nextConfig.addSeries({} as SeriesProps);
|
||||
|
||||
rerender(
|
||||
<UPlotChart
|
||||
data={preparePlotData(data)} // frame
|
||||
config={new UPlotConfigBuilder()}
|
||||
config={nextConfig}
|
||||
timeRange={timeRange}
|
||||
width={200}
|
||||
height={200}
|
||||
@@ -205,5 +207,68 @@ describe('UPlotChart', () => {
|
||||
expect(uPlot).toBeCalledTimes(1);
|
||||
expect(setSizeMock).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not initialize plot when config and data are not in sync', () => {
|
||||
const { data, timeRange, config } = mockData();
|
||||
|
||||
// 1 series in data, 2 series in config
|
||||
config.addSeries({} as SeriesProps);
|
||||
|
||||
render(
|
||||
<UPlotChart
|
||||
data={preparePlotData(data)} // frame
|
||||
config={config}
|
||||
timeRange={timeRange}
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
);
|
||||
|
||||
// we wait 1 frame for plugins initialisation logic to finish
|
||||
act(() => {
|
||||
mockRaf.step({ count: 1 });
|
||||
});
|
||||
|
||||
expect(destroyMock).toBeCalledTimes(0);
|
||||
expect(uPlot).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it('does not reinitialize plot when config and data are not in sync', () => {
|
||||
const { data, timeRange, config } = mockData();
|
||||
|
||||
// 1 series in data, 1 series in config
|
||||
const { rerender } = render(
|
||||
<UPlotChart
|
||||
data={preparePlotData(data)} // frame
|
||||
config={config}
|
||||
timeRange={timeRange}
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
);
|
||||
|
||||
// we wait 1 frame for plugins initialisation logic to finish
|
||||
act(() => {
|
||||
mockRaf.step({ count: 1 });
|
||||
});
|
||||
|
||||
const nextConfig = new UPlotConfigBuilder();
|
||||
nextConfig.addSeries({} as SeriesProps);
|
||||
nextConfig.addSeries({} as SeriesProps);
|
||||
|
||||
// 1 series in data, 2 series in config
|
||||
rerender(
|
||||
<UPlotChart
|
||||
data={preparePlotData(data)} // frame
|
||||
config={nextConfig}
|
||||
timeRange={timeRange}
|
||||
width={200}
|
||||
height={200}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(destroyMock).toBeCalledTimes(0);
|
||||
expect(uPlot).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,6 +31,14 @@ export const UPlotChart: React.FC<PlotProps> = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 0. Exit if the data set length is different than number of series expected to render
|
||||
// This may happen when GraphNG has not synced config yet with the aligned frame. Alignment happens before the render
|
||||
// in the getDerivedStateFromProps, while the config creation happens in componentDidUpdate, causing one more render
|
||||
// of the UPlotChart if the config needs to be updated.
|
||||
if (currentConfig.current.series.length !== props.data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. When config is ready and there is no uPlot instance, create new uPlot and return
|
||||
if (isConfigReady && !plotInstance.current) {
|
||||
plotInstance.current = initializePlot(props.data, currentConfig.current, canvasRef.current);
|
||||
|
||||
Reference in New Issue
Block a user