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:
parent
d9aa466758
commit
35e1b25dde
@ -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>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user