Skip to content

Commit 73d0065

Browse files
AnshMohta-cloudansh mohtaruanyl
authored
[Explore vis] Add empty data validation to prevent visualization errors (#10801)
- Add data validation check before visualization processing - Only process visualizations when transformedData has content - Maintain error throwing for invalid visualization rules - Add comprehensive test coverage for empty data scenarios - Improve robustness of explore embeddable component Signed-off-by: Ansh Mohta <[email protected]> Signed-off-by: ansh mohta <[email protected]> Co-authored-by: ansh mohta <[email protected]> Co-authored-by: Yulong Ruan <[email protected]>
1 parent 82347d6 commit 73d0065

File tree

2 files changed

+60
-32
lines changed

2 files changed

+60
-32
lines changed

src/plugins/explore/public/embeddable/explore_embeddable.test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,4 +489,28 @@ describe('ExploreEmbeddable', () => {
489489
'Cannot load saved visualization "Test Explore" with id test-id'
490490
);
491491
});
492+
493+
test('fetch handles empty data by skipping visualization processing', async () => {
494+
const mockNormalizeResultRows = await import(
495+
'../components/visualizations/utils/normalize_result_rows'
496+
);
497+
jest.spyOn(mockNormalizeResultRows, 'normalizeResultRows').mockReturnValueOnce({
498+
transformedData: [],
499+
numericalColumns: [],
500+
categoricalColumns: [],
501+
dateColumns: [],
502+
});
503+
504+
mockSavedExplore.visualization = JSON.stringify({
505+
chartType: 'line',
506+
axesMapping: { x: 'field1', y: 'field2' },
507+
});
508+
mockSavedExplore.uiState = JSON.stringify({ activeTab: 'visualization' });
509+
510+
// @ts-ignore
511+
await embeddable.fetch();
512+
513+
expect(embeddable.getOutput().error).toBeUndefined();
514+
expect(embeddable.getOutput().loading).toBe(false);
515+
});
492516
});

src/plugins/explore/public/embeddable/explore_embeddable.tsx

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -376,40 +376,44 @@ export class ExploreEmbeddable
376376
...(categoricalColumns ?? []),
377377
...(dateColumns ?? []),
378378
];
379-
if (selectedChartType === 'table') {
380-
this.searchProps.tableData = {
381-
columns: allColumns,
382-
rows: visualizationData.transformedData ?? [],
383-
};
384-
} else {
385-
const axesMapping = convertStringsToMappings(visualization.axesMapping, allColumns);
386-
const matchedRule = visualizationRegistry.findRuleByAxesMapping(
387-
visualization.axesMapping,
388-
allColumns
389-
);
390-
if (!matchedRule || !matchedRule.toSpec) {
391-
throw new Error(
392-
`Cannot load saved visualization "${this.panelTitle}" with id ${this.savedExplore.id}`
379+
380+
// Check if there's data to visualize
381+
if (visualizationData.transformedData && visualizationData.transformedData.length > 0) {
382+
if (selectedChartType === 'table') {
383+
this.searchProps.tableData = {
384+
columns: allColumns,
385+
rows: visualizationData.transformedData ?? [],
386+
};
387+
} else {
388+
const axesMapping = convertStringsToMappings(visualization.axesMapping, allColumns);
389+
const matchedRule = visualizationRegistry.findRuleByAxesMapping(
390+
visualization.axesMapping,
391+
allColumns
392+
);
393+
if (!matchedRule || !matchedRule.toSpec) {
394+
throw new Error(
395+
`Cannot load saved visualization "${this.panelTitle}" with id ${this.savedExplore.id}`
396+
);
397+
}
398+
const searchContext = {
399+
query: this.input.query,
400+
filters: this.input.filters,
401+
timeRange: this.input.timeRange,
402+
};
403+
this.searchProps.searchContext = searchContext;
404+
const styleOptions = visualization.params;
405+
const spec = matchedRule.toSpec(
406+
visualizationData.transformedData,
407+
numericalColumns,
408+
categoricalColumns,
409+
dateColumns,
410+
styleOptions,
411+
selectedChartType,
412+
axesMapping
393413
);
414+
const exp = toExpression(searchContext, spec);
415+
this.searchProps.expression = exp;
394416
}
395-
const searchContext = {
396-
query: this.input.query,
397-
filters: this.input.filters,
398-
timeRange: this.input.timeRange,
399-
};
400-
this.searchProps.searchContext = searchContext;
401-
const styleOptions = visualization.params;
402-
const spec = matchedRule.toSpec(
403-
visualizationData.transformedData,
404-
numericalColumns,
405-
categoricalColumns,
406-
dateColumns,
407-
styleOptions,
408-
selectedChartType,
409-
axesMapping
410-
);
411-
const exp = toExpression(searchContext, spec);
412-
this.searchProps.expression = exp;
413417
}
414418
}
415419
this.updateOutput({ loading: false, error: undefined });

0 commit comments

Comments
 (0)