Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
import { Download, FileText, FileJson, FileSpreadsheet } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { exportToCSV, exportToJSON, exportToPDF, generateReportData } from '@/lib/exportUtils';
import { toast } from '@/hooks/use-toast';
interface ExportMenuProps {
elementId?: string;
filename?: string;
}
const ExportMenu = ({ elementId = 'export-content', filename = 'cyber-report' }: ExportMenuProps) => {
const handleExportCSV = () => {
const data = generateReportData();
exportToCSV(data.threats, `${filename}-threats`);
toast({ title: "CSV eksporteret", description: "Threats data er downloadet" });
};
const handleExportJSON = () => {
const data = generateReportData();
exportToJSON(data, filename);
toast({ title: "JSON eksporteret", description: "Fuld rapport er downloadet" });
};
const handleExportPDF = () => {
exportToPDF(elementId, filename);
toast({ title: "PDF eksporteret", description: "Print dialog åbnet" });
};
const handleExportFullReport = () => {
const data = generateReportData();
// Create a comprehensive report
const reportHTML = `
<div id="full-report">
<h2>Sikkerhedsoversigt</h2>
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin: 20px 0;">
<div class="metric">
<div class="metric-value">${data.summary.totalThreats}</div>
<div class="metric-label">Total Trusler</div>
</div>
<div class="metric">
<div class="metric-value">${data.summary.criticalAlerts}</div>
<div class="metric-label">Kritiske Alerts</div>
</div>
<div class="metric">
<div class="metric-value">${data.summary.resolvedIncidents}</div>
<div class="metric-label">Løste Incidents</div>
</div>
<div class="metric">
<div class="metric-value">${data.summary.activeMonitors}</div>
<div class="metric-label">Aktive Monitors</div>
</div>
</div>
<h2>Seneste Trusler</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Navn</th>
<th>Severity</th>
<th>Status</th>
<th>Tidspunkt</th>
</tr>
</thead>
<tbody>
${data.threats.map(t => `
<tr>
<td>${t.id}</td>
<td>${t.name}</td>
<td>${t.severity}</td>
<td>${t.status}</td>
<td>${new Date(t.timestamp).toLocaleString('da-DK')}</td>
</tr>
`).join('')}
</tbody>
</table>
<h2>Regional Oversigt</h2>
<table>
<thead>
<tr>
<th>Region</th>
<th>Trusler</th>
<th>Incidents</th>
</tr>
</thead>
<tbody>
${data.regions.map(r => `
<tr>
<td>${r.region}</td>
<td>${r.threats}</td>
<td>${r.incidents}</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
`;
// Create temp element for PDF export
const tempDiv = document.createElement('div');
tempDiv.id = 'temp-export-content';
tempDiv.innerHTML = reportHTML;
tempDiv.style.position = 'absolute';
tempDiv.style.left = '-9999px';
document.body.appendChild(tempDiv);
exportToPDF('temp-export-content', `${filename}-full`);
setTimeout(() => {
document.body.removeChild(tempDiv);
}, 1000);
};
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm">
<Download className="w-4 h-4 mr-2" />
Eksporter
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="bg-card border-border">
<DropdownMenuItem onClick={handleExportCSV} className="cursor-pointer">
<FileSpreadsheet className="w-4 h-4 mr-2" />
Eksporter CSV
</DropdownMenuItem>
<DropdownMenuItem onClick={handleExportJSON} className="cursor-pointer">
<FileJson className="w-4 h-4 mr-2" />
Eksporter JSON
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleExportPDF} className="cursor-pointer">
<FileText className="w-4 h-4 mr-2" />
Eksporter PDF (denne side)
</DropdownMenuItem>
<DropdownMenuItem onClick={handleExportFullReport} className="cursor-pointer">
<FileText className="w-4 h-4 mr-2" />
Fuld rapport (PDF)
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};
export default ExportMenu;