diff --git a/client/src/pages/Detections.tsx b/client/src/pages/Detections.tsx index 0df1c32..a6ab5a4 100644 --- a/client/src/pages/Detections.tsx +++ b/client/src/pages/Detections.tsx @@ -5,10 +5,10 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Slider } from "@/components/ui/slider"; -import { AlertTriangle, Search, Shield, Globe, MapPin, Building2, ShieldPlus } from "lucide-react"; +import { AlertTriangle, Search, Shield, Globe, MapPin, Building2, ShieldPlus, ShieldCheck } from "lucide-react"; import { format } from "date-fns"; import { useState } from "react"; -import type { Detection } from "@shared/schema"; +import type { Detection, Whitelist } from "@shared/schema"; import { getFlag } from "@/lib/country-flags"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useToast } from "@/hooks/use-toast"; @@ -39,6 +39,14 @@ export default function Detections() { refetchInterval: 5000, }); + // Fetch whitelist to check if IP is already whitelisted + const { data: whitelistData } = useQuery({ + queryKey: ["/api/whitelist"], + }); + + // Create a Set of whitelisted IPs for fast lookup + const whitelistedIps = new Set(whitelistData?.map(w => w.ipAddress) || []); + const filteredDetections = detections?.filter((d) => d.sourceIp.toLowerCase().includes(searchQuery.toLowerCase()) || d.anomalyType.toLowerCase().includes(searchQuery.toLowerCase()) @@ -278,17 +286,30 @@ export default function Detections() { )} - + {whitelistedIps.has(detection.sourceIp) ? ( + + ) : ( + + )} diff --git a/client/src/pages/Whitelist.tsx b/client/src/pages/Whitelist.tsx index b28f1a9..e889a57 100644 --- a/client/src/pages/Whitelist.tsx +++ b/client/src/pages/Whitelist.tsx @@ -2,7 +2,7 @@ import { useQuery, useMutation } from "@tanstack/react-query"; import { queryClient, apiRequest } from "@/lib/queryClient"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { Shield, Plus, Trash2, CheckCircle2, XCircle } from "lucide-react"; +import { Shield, Plus, Trash2, CheckCircle2, XCircle, Search } from "lucide-react"; import { format } from "date-fns"; import { useState } from "react"; import { useForm } from "react-hook-form"; @@ -44,6 +44,7 @@ const whitelistFormSchema = insertWhitelistSchema.extend({ export default function WhitelistPage() { const { toast } = useToast(); const [isAddDialogOpen, setIsAddDialogOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); const form = useForm>({ resolver: zodResolver(whitelistFormSchema), @@ -59,6 +60,13 @@ export default function WhitelistPage() { queryKey: ["/api/whitelist"], }); + // Filter whitelist based on search query + const filteredWhitelist = whitelist?.filter((item) => + item.ipAddress.toLowerCase().includes(searchQuery.toLowerCase()) || + item.reason?.toLowerCase().includes(searchQuery.toLowerCase()) || + item.comment?.toLowerCase().includes(searchQuery.toLowerCase()) + ); + const addMutation = useMutation({ mutationFn: async (data: z.infer) => { return await apiRequest("POST", "/api/whitelist", data); @@ -189,11 +197,27 @@ export default function WhitelistPage() { + {/* Search Bar */} + + +
+ + setSearchQuery(e.target.value)} + className="pl-9" + data-testid="input-search-whitelist" + /> +
+
+
+ - IP Protetti ({whitelist?.length || 0}) + IP Protetti ({filteredWhitelist?.length || 0}{searchQuery && whitelist ? ` di ${whitelist.length}` : ''}) @@ -201,9 +225,9 @@ export default function WhitelistPage() {
Caricamento...
- ) : whitelist && whitelist.length > 0 ? ( + ) : filteredWhitelist && filteredWhitelist.length > 0 ? (
- {whitelist.map((item) => ( + {filteredWhitelist.map((item) => (