Compare commits
2 Commits
0298b4a790
...
58fb6476c5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58fb6476c5 | ||
|
|
1b47e08129 |
@ -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<Whitelist[]>({
|
||||
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,6 +286,18 @@ export default function Detections() {
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{whitelistedIps.has(detection.sourceIp) ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled
|
||||
className="w-full bg-green-500/10 border-green-500 text-green-600 dark:text-green-400"
|
||||
data-testid={`button-whitelist-${detection.id}`}
|
||||
>
|
||||
<ShieldCheck className="h-3 w-3 mr-1" />
|
||||
In Whitelist
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@ -289,6 +309,7 @@ export default function Detections() {
|
||||
<ShieldPlus className="h-3 w-3 mr-1" />
|
||||
Whitelist
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -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<z.infer<typeof whitelistFormSchema>>({
|
||||
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<typeof whitelistFormSchema>) => {
|
||||
return await apiRequest("POST", "/api/whitelist", data);
|
||||
@ -189,11 +197,27 @@ export default function WhitelistPage() {
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
{/* Search Bar */}
|
||||
<Card data-testid="card-search">
|
||||
<CardContent className="pt-6">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="Cerca per IP, motivo o note..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-9"
|
||||
data-testid="input-search-whitelist"
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card data-testid="card-whitelist">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Shield className="h-5 w-5" />
|
||||
IP Protetti ({whitelist?.length || 0})
|
||||
IP Protetti ({filteredWhitelist?.length || 0}{searchQuery && whitelist ? ` di ${whitelist.length}` : ''})
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
@ -201,9 +225,9 @@ export default function WhitelistPage() {
|
||||
<div className="text-center py-8 text-muted-foreground" data-testid="text-loading">
|
||||
Caricamento...
|
||||
</div>
|
||||
) : whitelist && whitelist.length > 0 ? (
|
||||
) : filteredWhitelist && filteredWhitelist.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{whitelist.map((item) => (
|
||||
{filteredWhitelist.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="p-4 rounded-lg border hover-elevate"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
\restrict Z0SMaiaV5vhgZwK1NSwbNjjsNLFygVnbAXhqZs1XJQSNOdt4n4ybTuKWgXktCsc
|
||||
\restrict PRKBLjzmAC8I39HJVa9aOlkzFFiqgPPqt4hjKaZLwxRVM51Z47YCL9xNIeoXWQj
|
||||
|
||||
-- Dumped from database version 16.11 (74c6bb6)
|
||||
-- Dumped by pg_dump version 16.10
|
||||
@ -387,5 +387,5 @@ ALTER TABLE ONLY public.public_blacklist_ips
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
\unrestrict Z0SMaiaV5vhgZwK1NSwbNjjsNLFygVnbAXhqZs1XJQSNOdt4n4ybTuKWgXktCsc
|
||||
\unrestrict PRKBLjzmAC8I39HJVa9aOlkzFFiqgPPqt4hjKaZLwxRVM51Z47YCL9xNIeoXWQj
|
||||
|
||||
|
||||
16
version.json
16
version.json
@ -1,7 +1,13 @@
|
||||
{
|
||||
"version": "1.0.98",
|
||||
"lastUpdate": "2026-01-02T15:20:02.824Z",
|
||||
"version": "1.0.99",
|
||||
"lastUpdate": "2026-01-02T15:39:39.640Z",
|
||||
"changelog": [
|
||||
{
|
||||
"version": "1.0.99",
|
||||
"date": "2026-01-02",
|
||||
"type": "patch",
|
||||
"description": "Deployment automatico v1.0.99"
|
||||
},
|
||||
{
|
||||
"version": "1.0.98",
|
||||
"date": "2026-01-02",
|
||||
@ -295,12 +301,6 @@
|
||||
"date": "2025-11-24",
|
||||
"type": "patch",
|
||||
"description": "Deployment automatico v1.0.50"
|
||||
},
|
||||
{
|
||||
"version": "1.0.49",
|
||||
"date": "2025-11-24",
|
||||
"type": "patch",
|
||||
"description": "Deployment automatico v1.0.49"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user