diff --git a/frontend-modern/src/components/shared/AIInsightsPanel.tsx b/frontend-modern/src/components/shared/AIInsightsPanel.tsx new file mode 100644 index 0000000..2aa2e12 --- /dev/null +++ b/frontend-modern/src/components/shared/AIInsightsPanel.tsx @@ -0,0 +1,197 @@ +import { Component, createSignal, createEffect, Show, For } from 'solid-js'; +import { AIAPI } from '@/api/ai'; +import type { FailurePrediction, ResourceCorrelation } from '@/types/aiIntelligence'; + +/** + * AIInsightsPanel displays AI-learned predictions and correlations + * Shows failure predictions with confidence levels and resource dependencies + */ +export const AIInsightsPanel: Component<{ resourceId?: string }> = (props) => { + const [predictions, setPredictions] = createSignal([]); + const [correlations, setCorrelations] = createSignal([]); + const [loading, setLoading] = createSignal(false); + const [expanded, setExpanded] = createSignal(false); + + const loadData = async () => { + setLoading(true); + try { + const [predResp, corrResp] = await Promise.all([ + AIAPI.getPredictions(props.resourceId), + AIAPI.getCorrelations(props.resourceId), + ]); + setPredictions(predResp.predictions || []); + setCorrelations(corrResp.correlations || []); + } catch (e) { + console.error('Failed to load AI insights:', e); + } finally { + setLoading(false); + } + }; + + createEffect(() => { + loadData(); + }); + + const totalInsights = () => predictions().length + correlations().length; + + // Format days until in a human-readable way + const formatDaysUntil = (days: number) => { + if (days < 0) return 'Overdue'; + if (days < 1) return 'Today'; + if (days < 2) return 'Tomorrow'; + return `In ${Math.round(days)} days`; + }; + + // Get severity color based on days until and confidence + const getPredictionColor = (pred: FailurePrediction) => { + if (pred.is_overdue || pred.days_until < 0) return 'text-red-600 dark:text-red-400'; + if (pred.days_until < 3) return 'text-amber-600 dark:text-amber-400'; + if (pred.days_until < 7) return 'text-yellow-600 dark:text-yellow-400'; + return 'text-blue-600 dark:text-blue-400'; + }; + + // Get event type display name + const getEventDisplayName = (eventType: string) => { + const names: Record = { + high_memory: 'High Memory', + high_cpu: 'High CPU', + disk_full: 'Disk Full', + oom: 'Out of Memory', + restart: 'Restart', + unresponsive: 'Unresponsive', + backup_failed: 'Backup Failure', + }; + return names[eventType] || eventType; + }; + + return ( + 0 || loading()}> +
+ {/* Header */} + + + {/* Content */} + +
+ {/* Loading state */} + +
+ + Loading insights... +
+
+ + {/* Predictions */} + 0}> +
+

+ + + + Failure Predictions +

+
+ + {(pred) => ( +
+
+
+
+ {getEventDisplayName(pred.event_type)} + + {formatDaysUntil(pred.days_until)} + +
+

+ {pred.basis} +

+
+
+
+ {Math.round(pred.confidence * 100)}% confidence +
+
+
+
+ )} +
+
+
+
+ + {/* Correlations */} + 0}> +
+

+ + + + Resource Dependencies +

+
+ + {(corr) => ( +
+
+ + {corr.source_name || corr.source_id} + + + + + + {corr.target_name || corr.target_id} + +
+

+ {corr.description || `${corr.event_pattern} (${corr.occurrences} observations)`} +

+
+ Avg delay: {corr.avg_delay} + Confidence: {Math.round(corr.confidence * 100)}% +
+
+ )} +
+
+
+
+ + {/* Empty state */} + +

+ No predictions or correlations detected yet. The AI will learn patterns over time. +

+
+
+
+
+
+ ); +};