Improve detection filtering and add whitelist functionality

Add filtering options for anomaly type and risk score to the detections page, increase the default limit to 500, and implement a button to add IPs to the whitelist.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 7a657272-55ba-4a79-9a2e-f1ed9bc7a528
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: d66f597d-96c6-4844-945e-ceefb30e71c8
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/449cf7c4-c97a-45ae-8234-e5c5b8d6a84f/7a657272-55ba-4a79-9a2e-f1ed9bc7a528/1zhedLT
This commit is contained in:
marco370 2025-11-25 09:56:59 +00:00
parent d9aa466758
commit 35e1b25dde

View File

@ -1,18 +1,41 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery, useMutation } from "@tanstack/react-query";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { AlertTriangle, Search, Shield, Eye, Globe, MapPin, Building2 } from "lucide-react"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Slider } from "@/components/ui/slider";
import { AlertTriangle, Search, Shield, Eye, Globe, MapPin, Building2, ShieldPlus } from "lucide-react";
import { format } from "date-fns"; import { format } from "date-fns";
import { useState } from "react"; import { useState } from "react";
import type { Detection } from "@shared/schema"; import type { Detection } from "@shared/schema";
import { getFlag } from "@/lib/country-flags"; import { getFlag } from "@/lib/country-flags";
import { apiRequest, queryClient } from "@/lib/queryClient";
import { useToast } from "@/hooks/use-toast";
export default function Detections() { export default function Detections() {
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [anomalyTypeFilter, setAnomalyTypeFilter] = useState<string>("all");
const [minScore, setMinScore] = useState(0);
const [maxScore, setMaxScore] = useState(100);
const { toast } = useToast();
// Build query params
const queryParams = new URLSearchParams();
queryParams.set("limit", "500");
if (anomalyTypeFilter !== "all") {
queryParams.set("anomalyType", anomalyTypeFilter);
}
if (minScore > 0) {
queryParams.set("minScore", minScore.toString());
}
if (maxScore < 100) {
queryParams.set("maxScore", maxScore.toString());
}
const { data: detections, isLoading } = useQuery<Detection[]>({ const { data: detections, isLoading } = useQuery<Detection[]>({
queryKey: ["/api/detections?limit=100"], queryKey: ["/api/detections", anomalyTypeFilter, minScore, maxScore],
queryFn: () => fetch(`/api/detections?${queryParams.toString()}`).then(r => r.json()),
refetchInterval: 5000, refetchInterval: 5000,
}); });
@ -53,20 +76,58 @@ export default function Detections() {
{/* Search and Filters */} {/* Search and Filters */}
<Card data-testid="card-filters"> <Card data-testid="card-filters">
<CardContent className="pt-6"> <CardContent className="pt-6">
<div className="flex items-center gap-4"> <div className="flex flex-col gap-4">
<div className="relative flex-1"> <div className="flex items-center gap-4 flex-wrap">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <div className="relative flex-1 min-w-[200px]">
<Input <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
placeholder="Cerca per IP o tipo anomalia..." <Input
value={searchQuery} placeholder="Cerca per IP o tipo anomalia..."
onChange={(e) => setSearchQuery(e.target.value)} value={searchQuery}
className="pl-9" onChange={(e) => setSearchQuery(e.target.value)}
data-testid="input-search" className="pl-9"
/> data-testid="input-search"
/>
</div>
<Select value={anomalyTypeFilter} onValueChange={setAnomalyTypeFilter}>
<SelectTrigger className="w-[200px]" data-testid="select-anomaly-type">
<SelectValue placeholder="Tipo attacco" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Tutti i tipi</SelectItem>
<SelectItem value="ddos">DDoS Attack</SelectItem>
<SelectItem value="port_scan">Port Scanning</SelectItem>
<SelectItem value="brute_force">Brute Force</SelectItem>
<SelectItem value="botnet">Botnet Activity</SelectItem>
<SelectItem value="suspicious">Suspicious Activity</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between text-sm">
<span className="text-muted-foreground">Risk Score:</span>
<span className="font-medium" data-testid="text-score-range">
{minScore} - {maxScore}
</span>
</div>
<div className="flex items-center gap-4">
<span className="text-xs text-muted-foreground w-8">0</span>
<Slider
min={0}
max={100}
step={5}
value={[minScore, maxScore]}
onValueChange={([min, max]) => {
setMinScore(min);
setMaxScore(max);
}}
className="flex-1"
data-testid="slider-risk-score"
/>
<span className="text-xs text-muted-foreground w-8">100</span>
</div>
</div> </div>
<Button variant="outline" data-testid="button-refresh">
Aggiorna
</Button>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>