Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
import {
Rss, Activity, TrendingUp, AlertTriangle, Globe,
Database, Zap, BarChart3, LineChart, Map, Target, Radar, Grid3X3
} from 'lucide-react';
interface WidgetContentProps {
type: string;
}
// Mini widget components for dashboard
const NewsWidget = () => {
const news = [
{ title: "Critical Zero-Day Exploit", severity: "critical", time: "2m" },
{ title: "APT Group Activity Detected", severity: "high", time: "15m" },
{ title: "New Ransomware Variant", severity: "high", time: "32m" },
];
return (
<div className="space-y-2">
{news.map((item, i) => (
<div key={i} className="p-2 bg-secondary/30 border-l-2 border-primary/50 text-xs">
<span className="text-foreground">{item.title}</span>
<div className="flex gap-2 mt-1 text-muted-foreground">
<span className={item.severity === 'critical' ? 'text-destructive' : 'text-orange-400'}>
{item.severity}
</span>
<span>• {item.time}</span>
</div>
</div>
))}
</div>
);
};
const DataStreamsWidget = () => {
const streams = [
{ name: "Network Traffic", rate: "2.4 GB/s", ok: true },
{ name: "Log Ingestion", rate: "12K/s", ok: true },
{ name: "Alert Pipeline", rate: "847/min", ok: false },
];
return (
<div className="space-y-2">
{streams.map((s, i) => (
<div key={i} className="flex justify-between items-center p-2 bg-secondary/30 text-xs">
<span className="text-foreground">{s.name}</span>
<div className="flex items-center gap-2">
<span className="font-mono text-primary">{s.rate}</span>
<div className={`w-2 h-2 rounded-full ${s.ok ? 'bg-green-400' : 'bg-orange-400 animate-pulse'}`} />
</div>
</div>
))}
</div>
);
};
const MetricsWidget = () => (
<div className="grid grid-cols-2 gap-2">
{[
{ label: "Threats", value: "127", change: "+12%" },
{ label: "Blocked", value: "8,432", change: "+23%" },
{ label: "Vulns", value: "45", change: "-8%" },
{ label: "Risk", value: "72", change: "+5" },
].map((m, i) => (
<div key={i} className="p-2 bg-secondary/30 text-center">
<div className="text-lg font-mono text-primary">{m.value}</div>
<div className="text-xs text-muted-foreground">{m.label}</div>
</div>
))}
</div>
);
const AlertsWidget = () => {
const alerts = [
{ type: "CRITICAL", msg: "Unauthorized access attempt", time: "Now" },
{ type: "WARNING", msg: "Unusual outbound traffic", time: "5m" },
];
return (
<div className="space-y-2">
{alerts.map((a, i) => (
<div key={i} className={`p-2 border-l-2 text-xs ${
a.type === 'CRITICAL' ? 'border-destructive bg-destructive/10' : 'border-orange-400 bg-orange-400/10'
}`}>
<span className={a.type === 'CRITICAL' ? 'text-destructive' : 'text-orange-400'}>{a.type}</span>
<span className="text-muted-foreground ml-2">{a.time}</span>
<p className="text-foreground mt-1">{a.msg}</p>
</div>
))}
</div>
);
};
const GlobalWidget = () => (
<div className="space-y-2">
{[
{ region: "North America", threats: 234, up: true },
{ region: "Europe", threats: 189, up: false },
{ region: "Asia Pacific", threats: 412, up: true },
].map((r, i) => (
<div key={i} className="flex justify-between p-2 bg-secondary/30 text-xs">
<span className="text-foreground">{r.region}</span>
<span className="text-primary">
{r.threats} {r.up ? '↑' : '↓'}
</span>
</div>
))}
</div>
);
const DatabaseWidget = () => (
<div className="space-y-2">
{[
{ name: "Threat Intel DB", status: "online" },
{ name: "Log Archive", status: "online" },
{ name: "IOC Database", status: "syncing" },
].map((db, i) => (
<div key={i} className="flex justify-between p-2 bg-secondary/30 text-xs">
<span className="text-foreground">{db.name}</span>
<span className={db.status === 'online' ? 'text-green-400' : 'text-primary'}>{db.status}</span>
</div>
))}
</div>
);
const EventsWidget = () => (
<div className="space-y-1 font-mono text-xs">
{[
{ type: "AUTH", msg: "Failed login from 192.168.1.45" },
{ type: "NET", msg: "Unknown IP connection" },
{ type: "FILE", msg: "Suspicious file quarantined" },
].map((e, i) => (
<div key={i} className="flex gap-2 p-1 bg-secondary/20">
<span className="text-primary">[{e.type}]</span>
<span className="text-foreground truncate">{e.msg}</span>
</div>
))}
</div>
);
const StatisticsWidget = () => (
<div className="space-y-2">
{[
{ label: "Malware", value: 89 },
{ label: "Phishing", value: 67 },
{ label: "Brute Force", value: 45 },
].map((s, i) => (
<div key={i} className="space-y-1">
<div className="flex justify-between text-xs">
<span className="text-muted-foreground">{s.label}</span>
<span className="text-foreground">{s.value}%</span>
</div>
<div className="h-1.5 bg-secondary rounded-full overflow-hidden">
<div className="h-full bg-primary rounded-full" style={{ width: `${s.value}%` }} />
</div>
</div>
))}
</div>
);
const TrendsWidget = () => {
const data = [20, 35, 45, 80, 65, 90, 70];
return (
<div className="h-20 flex items-end justify-between gap-1">
{data.map((v, i) => (
<div key={i} className="flex-1 bg-primary/60 hover:bg-primary rounded-t transition-colors" style={{ height: `${v}%` }} />
))}
</div>
);
};
const ThreatMapWidget = () => (
<div className="aspect-video bg-secondary/30 border border-border/50 relative">
{[
{ x: 20, y: 30, pulse: true },
{ x: 45, y: 25, pulse: false },
{ x: 70, y: 40, pulse: true },
].map((p, i) => (
<div
key={i}
className={`absolute w-2 h-2 rounded-full bg-destructive ${p.pulse ? 'animate-ping' : ''}`}
style={{ left: `${p.x}%`, top: `${p.y}%` }}
/>
))}
<div className="absolute bottom-1 right-2 text-xs text-muted-foreground">3 hotspots</div>
</div>
);
const TargetWidget = () => (
<div className="aspect-square max-w-24 mx-auto relative">
{[100, 75, 50, 25].map((size, i) => (
<div
key={i}
className="absolute rounded-full border border-destructive/30"
style={{
width: `${size}%`,
height: `${size}%`,
left: `${(100 - size) / 2}%`,
top: `${(100 - size) / 2}%`,
}}
/>
))}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-2 h-2 bg-destructive rounded-full animate-pulse" />
</div>
);
const RadarWidget = () => (
<div className="aspect-square max-w-24 mx-auto relative bg-secondary/30 rounded-full overflow-hidden">
{[100, 66, 33].map((size, i) => (
<div
key={i}
className="absolute rounded-full border border-primary/20"
style={{
width: `${size}%`,
height: `${size}%`,
left: `${(100 - size) / 2}%`,
top: `${(100 - size) / 2}%`,
}}
/>
))}
<div
className="absolute top-1/2 left-1/2 w-1/2 h-0.5 bg-gradient-to-r from-primary to-transparent origin-left animate-spin"
style={{ animationDuration: '3s' }}
/>
<div className="absolute top-1/4 left-1/3 w-1.5 h-1.5 bg-destructive rounded-full animate-pulse" />
</div>
);
const GridWidget = () => {
const grid = Array.from({ length: 16 }).map(() => Math.random() > 0.75);
return (
<div className="grid grid-cols-4 gap-0.5">
{grid.map((active, i) => (
<div
key={i}
className={`aspect-square ${active ? 'bg-destructive/60 animate-pulse' : 'bg-secondary/30'}`}
/>
))}
</div>
);
};
const WidgetContent = ({ type }: WidgetContentProps) => {
const widgets: Record<string, JSX.Element> = {
news: <NewsWidget />,
datastreams: <DataStreamsWidget />,
metrics: <MetricsWidget />,
alerts: <AlertsWidget />,
global: <GlobalWidget />,
database: <DatabaseWidget />,
events: <EventsWidget />,
statistics: <StatisticsWidget />,
trends: <TrendsWidget />,
threatmap: <ThreatMapWidget />,
target: <TargetWidget />,
radar: <RadarWidget />,
grid: <GridWidget />,
};
return widgets[type] || <div className="text-muted-foreground text-sm">Widget not found</div>;
};
export default WidgetContent;