fix(ui): use Promise.allSettled for resilient API loading

Changed AIOverviewTable to use Promise.allSettled instead of
Promise.all so that one failing endpoint (e.g., anomalies 404)
doesn't break the entire component.

Each API result now has a fallback for failed requests, allowing
the table to gracefully degrade when endpoints are unavailable.
This commit is contained in:
rcourtman 2025-12-21 12:31:09 +00:00
parent 60c0221a37
commit 98f3d0d48f

View file

@ -58,22 +58,25 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) =
setLoading(true); setLoading(true);
setError(''); setError('');
try { try {
// Fetch all Pro features together // Use allSettled so one failing endpoint doesn't break everything
const [predResp, corrResp, remResp, changesResp] = await Promise.all([ const results = await Promise.allSettled([
AIAPI.getPredictions(), AIAPI.getPredictions(),
AIAPI.getCorrelations(), AIAPI.getCorrelations(),
AIAPI.getRemediations({ hours: 168, limit: 6 }), AIAPI.getRemediations({ hours: 168, limit: 6 }),
AIAPI.getRecentChanges(24), AIAPI.getRecentChanges(24),
AIAPI.getAnomalies(),
]); ]);
// Fetch anomalies separately (FREE feature - don't let failures break Pro features) // Extract results with fallbacks for failed requests
try { const predResp = results[0].status === 'fulfilled' ? results[0].value : { predictions: [], license_required: false, count: 0, upgrade_url: '' };
const anomalyResp = await AIAPI.getAnomalies(); const corrResp = results[1].status === 'fulfilled' ? results[1].value : { correlations: [], license_required: false, count: 0, upgrade_url: '' };
setAnomalies(anomalyResp.anomalies || []); const remResp = results[2].status === 'fulfilled' ? results[2].value : { remediations: [], license_required: false, stats: null, upgrade_url: '' };
} catch { const changesResp = results[3].status === 'fulfilled' ? results[3].value : { changes: [], license_required: false, count: 0, upgrade_url: '' };
// Anomalies endpoint may fail if patrol not initialized - that's OK const anomalyResp = results[4].status === 'fulfilled' ? results[4].value : { anomalies: [], count: 0, severity_counts: { critical: 0, high: 0, medium: 0, low: 0 } };
setAnomalies([]);
}
// Handle anomalies (FREE - no license required)
setAnomalies(anomalyResp.anomalies || []);
// Handle insights lock // Handle insights lock