Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
// CSV Export utility
export const exportToCSV = (data: any[], filename: string) => {
if (!data.length) return;
const headers = Object.keys(data[0]);
const csvContent = [
headers.join(','),
...data.map(row =>
headers.map(header => {
const value = row[header];
// Escape quotes and wrap in quotes if contains comma
if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
return `"${value.replace(/"/g, '""')}"`;
}
return value ?? '';
}).join(',')
)
].join('\n');
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
downloadBlob(blob, `${filename}.csv`);
};
// JSON Export utility
export const exportToJSON = (data: any, filename: string) => {
const jsonContent = JSON.stringify(data, null, 2);
const blob = new Blob([jsonContent], { type: 'application/json' });
downloadBlob(blob, `${filename}.json`);
};
// PDF Export utility (basic HTML to PDF using print)
export const exportToPDF = (elementId: string, filename: string) => {
const element = document.getElementById(elementId);
if (!element) return;
const printWindow = window.open('', '_blank');
if (!printWindow) return;
const styles = `
<style>
* { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
body { padding: 20px; background: white; color: black; }
h1, h2, h3 { color: #0891b2; }
table { border-collapse: collapse; width: 100%; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background: #0891b2; color: white; }
tr:nth-child(even) { background: #f9f9f9; }
.metric { display: inline-block; padding: 10px 20px; margin: 5px; border: 1px solid #ddd; border-radius: 8px; }
.metric-value { font-size: 24px; font-weight: bold; color: #0891b2; }
.metric-label { font-size: 12px; color: #666; }
@media print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
</style>
`;
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>${filename}</title>
${styles}
</head>
<body>
<h1>${filename}</h1>
<p>Eksporteret: ${new Date().toLocaleString('da-DK')}</p>
<hr/>
${element.innerHTML}
</body>
</html>
`);
printWindow.document.close();
printWindow.focus();
setTimeout(() => {
printWindow.print();
printWindow.close();
}, 250);
};
// Generate report data from dashboard
export const generateReportData = () => {
// Simulated data - in real app this would come from actual data sources
return {
summary: {
totalThreats: 1247,
criticalAlerts: 23,
resolvedIncidents: 892,
activeMonitors: 156,
},
threats: [
{ id: 'T001', name: 'Ransomware Attack', severity: 'Critical', status: 'Active', timestamp: new Date().toISOString() },
{ id: 'T002', name: 'DDoS Attempt', severity: 'High', status: 'Mitigated', timestamp: new Date().toISOString() },
{ id: 'T003', name: 'Phishing Campaign', severity: 'Medium', status: 'Investigating', timestamp: new Date().toISOString() },
{ id: 'T004', name: 'SQL Injection', severity: 'High', status: 'Blocked', timestamp: new Date().toISOString() },
{ id: 'T005', name: 'Brute Force', severity: 'Low', status: 'Monitored', timestamp: new Date().toISOString() },
],
regions: [
{ region: 'Nord Amerika', threats: 423, incidents: 34 },
{ region: 'Europa', threats: 312, incidents: 28 },
{ region: 'Asien', threats: 287, incidents: 41 },
{ region: 'Sydamerika', threats: 125, incidents: 12 },
{ region: 'Afrika', threats: 67, incidents: 8 },
{ region: 'Oceanien', threats: 33, incidents: 5 },
],
generatedAt: new Date().toISOString(),
};
};
// Helper to download blob
const downloadBlob = (blob: Blob, filename: string) => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};