Spaces:
Sleeping
Sleeping
File size: 6,824 Bytes
8fa21e1 a88344b 8fa21e1 a88344b 8fa21e1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | import { useState } from 'react';
import axios from 'axios';
const API = '';
const SEVERITY_COLORS = {
Critical: 'var(--critical)',
High: 'var(--high)',
Medium: 'var(--medium)',
Low: 'var(--low)',
};
export default function ReportPanel({ clusters, anomalies, stats }) {
const [report, setReport] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
async function generateReport() {
setLoading(true);
setError(null);
try {
const response = await axios.post(`/api/cluster/report`, {
clusters, anomalies, stats
});
setReport(response.data);
} catch (err) {
setError('Failed to generate report');
} finally {
setLoading(false);
}
}
function downloadMarkdown() {
if (!report) return;
const md = buildMarkdown(report);
const blob = new Blob([md], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'incident-report.md';
a.click();
URL.revokeObjectURL(url);
}
function buildMarkdown(r) {
return `# Incident Report
## Executive Summary
${r.executive_summary}
**Overall Severity:** ${r.overall_severity}
**Affected Systems:** ${r.estimated_affected_systems?.join(', ') || 'Unknown'}
## Top Issues
${r.top_issues?.map(issue => `
### ${issue.rank}. ${issue.label} — ${issue.severity}
- **Impact:** ${issue.impact}
- **Suggested Fix:** ${issue.suggested_fix}
`).join('\n')}
## Anomaly Assessment
${r.anomaly_assessment}
---
*Generated by Error Clustering Engine*
`;
}
return (
<div className="panel fade-in">
<div className="panel-header">
<span className="panel-title">ROOT CAUSE REPORT</span>
<div className="panel-actions">
{report && (
<button className="btn-ghost" onClick={downloadMarkdown}>
Download .md
</button>
)}
<button
className="btn-primary"
onClick={generateReport}
disabled={loading}
>
{loading ? 'Generating...' : report ? 'Regenerate' : 'Generate Report'}
</button>
</div>
</div>
{error && (
<div style={{ padding: '12px 16px', color: 'var(--critical)', fontFamily: 'var(--font-mono)', fontSize: 12 }}>
⚠ {error}
</div>
)}
{loading && (
<div style={{ padding: '16px', color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', fontSize: 12 }}>
Analyzing clusters and generating report...
</div>
)}
{report && !loading && (
<div className="report-body">
{/* Header */}
<div className="report-section">
<div className="report-meta">
<span
className="severity-badge"
style={{ color: SEVERITY_COLORS[report.overall_severity] }}
>
{report.overall_severity?.toUpperCase()} SEVERITY
</span>
{report.estimated_affected_systems?.length > 0 && (
<div className="formats-list" style={{ marginTop: 8 }}>
{report.estimated_affected_systems.map(s => (
<div key={s} className="format-badge">
<span className="format-name">{s}</span>
</div>
))}
</div>
)}
</div>
<p className="report-summary">{report.executive_summary}</p>
</div>
{/* Top issues */}
<div className="report-section">
<div className="report-section-title">TOP ISSUES</div>
{report.top_issues?.map(issue => (
<div key={issue.rank} className="report-issue">
<div className="report-issue-header">
<span className="report-rank">#{issue.rank}</span>
<span className="report-issue-label">{issue.label}</span>
<span
className="severity-badge"
style={{ color: SEVERITY_COLORS[issue.severity], marginLeft: 'auto' }}
>
{issue.severity?.toUpperCase()}
</span>
</div>
<div className="report-issue-detail">
<span style={{ color: 'var(--text-dim)' }}>Impact: </span>
{issue.impact}
</div>
<div className="report-issue-detail">
<span style={{ color: 'var(--text-dim)' }}>Fix: </span>
{issue.suggested_fix}
</div>
</div>
))}
</div>
{/* Anomalies */}
{report.anomaly_assessment && (
<div className="report-section">
<div className="report-section-title">ANOMALY ASSESSMENT</div>
<p style={{ color: 'var(--text-mid)', fontSize: 13 }}>
{report.anomaly_assessment}
</p>
</div>
)}
</div>
)}
{!report && !loading && (
<div style={{
padding: '24px 16px',
color: 'var(--text-dim)',
fontFamily: 'var(--font-mono)',
fontSize: 12,
textAlign: 'center'
}}>
Click "Generate Report" to get an AI-powered incident analysis
</div>
)}
</div>
);
} |