feat: Add Wild Central web app (Central-only UI)
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>
This commit is contained in:
128
web/src/hooks/useCrowdSec.ts
Normal file
128
web/src/hooks/useCrowdSec.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user