Extract Central pages from the wild-cloud web app into a standalone React app for Wild Central. Includes: - Central overview, DNS, DHCP, Firewall, VPN, Ingress, CrowdSec pages - Simplified sidebar with Central-only navigation - Branding updated to "Wild Central" - All Cloud-specific pages, components, hooks, and API services removed - TypeScript type-check and production build pass Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { crowdSecApi, type AddDecisionRequest } from '../services/api/networking';
|
|
|
|
export const useCrowdSec = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
const statusQuery = useQuery({
|
|
queryKey: ['crowdsec', 'status'],
|
|
queryFn: () => crowdSecApi.getStatus(),
|
|
refetchInterval: false,
|
|
staleTime: 30000,
|
|
});
|
|
|
|
const summaryQuery = useQuery({
|
|
queryKey: ['crowdsec', 'summary'],
|
|
queryFn: () => crowdSecApi.getSummary(),
|
|
refetchInterval: false,
|
|
staleTime: 300000, // 5 minutes — CAPI bans change slowly
|
|
enabled: statusQuery.data?.active ?? false,
|
|
});
|
|
|
|
const alertsQuery = useQuery({
|
|
queryKey: ['crowdsec', 'alerts'],
|
|
queryFn: () => crowdSecApi.getAlerts(50),
|
|
refetchInterval: false,
|
|
staleTime: 60000,
|
|
enabled: statusQuery.data?.active ?? false,
|
|
});
|
|
|
|
const alertsGraphQuery = useQuery({
|
|
queryKey: ['crowdsec', 'alerts-graph'],
|
|
queryFn: () => crowdSecApi.getAlerts(500),
|
|
refetchInterval: false,
|
|
staleTime: 120000,
|
|
enabled: statusQuery.data?.active ?? false,
|
|
});
|
|
|
|
const decisionsQuery = useQuery({
|
|
queryKey: ['crowdsec', 'decisions'],
|
|
queryFn: () => crowdSecApi.getDecisions(),
|
|
refetchInterval: false,
|
|
staleTime: 30000,
|
|
enabled: statusQuery.data?.active ?? false,
|
|
});
|
|
|
|
const addDecisionMutation = useMutation({
|
|
mutationFn: (req: AddDecisionRequest) => crowdSecApi.addDecision(req),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'decisions'] });
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'summary'] });
|
|
},
|
|
});
|
|
|
|
const deleteDecisionMutation = useMutation({
|
|
mutationFn: (id: number) => crowdSecApi.deleteDecision(id),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'decisions'] });
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'summary'] });
|
|
},
|
|
});
|
|
|
|
const deleteDecisionByIPMutation = useMutation({
|
|
mutationFn: (ip: string) => crowdSecApi.deleteDecisionByIP(ip),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'decisions'] });
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'summary'] });
|
|
},
|
|
});
|
|
|
|
const deleteBouncerMutation = useMutation({
|
|
mutationFn: (name: string) => crowdSecApi.deleteBouncer(name),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'status'] });
|
|
},
|
|
});
|
|
|
|
const deleteMachineMutation = useMutation({
|
|
mutationFn: (name: string) => crowdSecApi.deleteMachine(name),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'status'] });
|
|
},
|
|
});
|
|
|
|
const provisionMutation = useMutation({
|
|
mutationFn: (instanceName: string) => crowdSecApi.provision(instanceName),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['crowdsec', 'status'] });
|
|
},
|
|
});
|
|
|
|
return {
|
|
status: statusQuery.data,
|
|
isLoadingStatus: statusQuery.isLoading,
|
|
statusError: statusQuery.error,
|
|
|
|
summary: summaryQuery.data,
|
|
isLoadingSummary: summaryQuery.isLoading,
|
|
|
|
alerts: alertsQuery.data?.alerts ?? [],
|
|
isLoadingAlerts: alertsQuery.isLoading,
|
|
refetchAlerts: alertsQuery.refetch,
|
|
|
|
graphAlerts: alertsGraphQuery.data?.alerts ?? [],
|
|
isLoadingGraphAlerts: alertsGraphQuery.isLoading,
|
|
|
|
decisions: decisionsQuery.data?.decisions ?? [],
|
|
isLoadingDecisions: decisionsQuery.isLoading,
|
|
|
|
addDecision: addDecisionMutation.mutate,
|
|
isAddingDecision: addDecisionMutation.isPending,
|
|
addDecisionError: addDecisionMutation.error,
|
|
|
|
deleteDecision: deleteDecisionMutation.mutate,
|
|
isDeletingDecision: deleteDecisionMutation.isPending,
|
|
|
|
deleteDecisionByIP: deleteDecisionByIPMutation.mutate,
|
|
isDeletingByIP: deleteDecisionByIPMutation.isPending,
|
|
|
|
deleteBouncer: deleteBouncerMutation.mutate,
|
|
isDeletingBouncer: deleteBouncerMutation.isPending,
|
|
|
|
deleteMachine: deleteMachineMutation.mutate,
|
|
isDeletingMachine: deleteMachineMutation.isPending,
|
|
|
|
provision: provisionMutation.mutate,
|
|
isProvisioning: provisionMutation.isPending,
|
|
};
|
|
};
|