Suggestions: Handle errors (#114868)

Co-authored-by: Paul Marbach <paul.marbach@grafana.com>
This commit is contained in:
Adela Almasan
2025-12-10 12:17:24 -06:00
committed by GitHub
parent a46f0a222e
commit 7ae9f94de7
2 changed files with 30 additions and 29 deletions

View File

@@ -30,7 +30,17 @@ export interface Props {
export function VisualizationSuggestions({ onChange, data, panel }: Props) {
const styles = useStyles2(getStyles);
const { value: suggestions, loading, error } = useAsync(() => getAllSuggestions(data), [data]);
const {
value: suggestions,
loading,
error,
} = useAsync(async () => {
if (!hasData(data)) {
return [];
}
return await getAllSuggestions(data);
}, [data]);
const [suggestionHash, setSuggestionHash] = useState<string | null>(null);
const [firstCardRef, { width }] = useMeasure<HTMLDivElement>();
const [firstCardHash, setFirstCardHash] = useState<string | null>(null);
@@ -89,7 +99,7 @@ export function VisualizationSuggestions({ onChange, data, panel }: Props) {
}
}, [suggestions, suggestionHash, firstCardHash, isNewVizSuggestionsEnabled, isUnconfiguredPanel, applySuggestion]);
if (loading) {
if (loading || !data) {
return (
<div className={styles.loadingContainer}>
<Spinner size="xxl" />
@@ -120,10 +130,6 @@ export function VisualizationSuggestions({ onChange, data, panel }: Props) {
);
}
if (!data) {
return null;
}
return (
<div className={styles.grid}>
{isNewVizSuggestionsEnabled

View File

@@ -17,35 +17,31 @@ import { panelsToCheckFirst } from './consts';
/**
* gather and cache the plugins which provide visualization suggestions so they can be invoked to build suggestions
*/
let _pluginCache: PanelPlugin[] | null = null;
async function getPanelsWithSuggestions(): Promise<PanelPlugin[]> {
if (!_pluginCache) {
_pluginCache = [];
// list of plugins to load is determined by the feature flag
const pluginIds: string[] = config.featureToggles.externalVizSuggestions
? getAllPanelPluginMeta()
.filter((panel) => panel.suggestions)
.map((m) => m.id)
: panelsToCheckFirst;
// list of plugins to load is determined by the feature flag
const pluginIds: string[] = config.featureToggles.externalVizSuggestions
? getAllPanelPluginMeta()
.filter((panel) => panel.suggestions)
.map((m) => m.id)
: panelsToCheckFirst;
// import the plugins in parallel using Promise.allSettled
const plugins: PanelPlugin[] = [];
const settledPromises = await Promise.allSettled(pluginIds.map((id) => importPanelPlugin(id)));
for (let i = 0; i < settledPromises.length; i++) {
const settled = settledPromises[i];
// import the plugins in parallel using Promise.allSettled
const settledPromises = await Promise.allSettled(pluginIds.map((id) => importPanelPlugin(id)));
for (let i = 0; i < settledPromises.length; i++) {
const settled = settledPromises[i];
if (settled.status === 'fulfilled') {
_pluginCache.push(settled.value);
}
// TODO: do we want to somehow log if there were errors loading some of the plugins?
if (settled.status === 'fulfilled') {
plugins.push(settled.value);
}
// TODO: do we want to somehow log if there were errors loading some of the plugins?
}
if (_pluginCache.length === 0) {
if (plugins.length === 0) {
throw new Error('No panel plugins with visualization suggestions found');
}
return _pluginCache;
return plugins;
}
/**
@@ -83,7 +79,7 @@ export function sortSuggestions(suggestions: PanelPluginVisualizationSuggestion[
if (mappedA && dataSummary.hasPreferredVisualisationType(mappedA)) {
return -1;
}
const mappedB = mapPreferredVisualisationTypeToPlugin(a.pluginId);
const mappedB = mapPreferredVisualisationTypeToPlugin(b.pluginId);
if (mappedB && dataSummary.hasPreferredVisualisationType(mappedB)) {
return 1;
}
@@ -101,9 +97,8 @@ export function sortSuggestions(suggestions: PanelPluginVisualizationSuggestion[
export async function getAllSuggestions(data?: PanelData): Promise<PanelPluginVisualizationSuggestion[]> {
const dataSummary = getPanelDataSummary(data?.series);
const list: PanelPluginVisualizationSuggestion[] = [];
const plugins = await getPanelsWithSuggestions();
for (const plugin of plugins) {
for (const plugin of await getPanelsWithSuggestions()) {
const suggestions = plugin.getSuggestions(dataSummary);
if (suggestions) {
list.push(...suggestions);