feat: add Top Attacking IPs chart component and integrate into CrowdSec configuration page

- Implemented TopAttackingIPsChart component for visualizing top attacking IPs.
- Created hooks for fetching CrowdSec dashboard data including summary, timeline, top IPs, scenarios, and alerts.
- Added tests for the new hooks to ensure data fetching works as expected.
- Updated translation files for new dashboard terms in multiple languages.
- Refactored CrowdSecConfig page to include a tabbed interface for configuration and dashboard views.
- Added end-to-end tests for CrowdSec dashboard functionality including tab navigation, data display, and interaction with time range and refresh features.
This commit is contained in:
GitHub Actions
2026-03-25 17:16:54 +00:00
parent 846eedeab0
commit 1fe69c2a15
41 changed files with 5910 additions and 540 deletions
+22 -1
View File
@@ -1,7 +1,7 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { isAxiosError } from 'axios'
import { Shield, ShieldOff, Trash2, Search, AlertTriangle, ExternalLink } from 'lucide-react'
import { useEffect, useMemo, useState } from 'react'
import { lazy, Suspense, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate, Link } from 'react-router-dom'
@@ -15,11 +15,15 @@ import { ConfigReloadOverlay } from '../components/LoadingStates'
import { Button } from '../components/ui/Button'
import { Card } from '../components/ui/Card'
import { Input } from '../components/ui/Input'
import { Skeleton } from '../components/ui/Skeleton'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/Tabs'
import { CROWDSEC_PRESETS, type CrowdsecPreset } from '../data/crowdsecPresets'
import { useConsoleStatus, useEnrollConsole, useClearConsoleEnrollment } from '../hooks/useConsoleEnrollment'
import { buildCrowdsecExportFilename, downloadCrowdsecExport, promptCrowdsecFilename } from '../utils/crowdsecExport'
import { toast } from '../utils/toast'
const CrowdSecDashboard = lazy(() => import('../components/crowdsec/CrowdSecDashboard'))
export default function CrowdSecConfig() {
const { t } = useTranslation()
const { data: status, isLoading, error } = useQuery({ queryKey: ['security-status'], queryFn: getSecurityStatus })
@@ -557,6 +561,20 @@ export default function CrowdSecConfig() {
<div className="space-y-6">
<h1 className="text-2xl font-bold">{t('crowdsecConfig.title')}</h1>
<Tabs defaultValue="config">
<TabsList>
<TabsTrigger value="config">{t('security.crowdsec.tabs.config', 'Configuration')}</TabsTrigger>
<TabsTrigger value="dashboard">{t('security.crowdsec.tabs.dashboard', 'Dashboard')}</TabsTrigger>
</TabsList>
<TabsContent value="dashboard" className="mt-4">
<Suspense fallback={<div className="space-y-4"><Skeleton className="h-24 w-full" /><Skeleton className="h-64 w-full" /></div>}>
<CrowdSecDashboard />
</Suspense>
</TabsContent>
<TabsContent value="config" className="mt-4">
{/* CrowdSec Bouncer API Key - moved from Security Dashboard */}
{status.cerberus?.enabled && status.crowdsec.enabled && (
<CrowdSecBouncerKeyDisplay />
@@ -1221,6 +1239,9 @@ export default function CrowdSecConfig() {
)}
</div>
</Card>
</TabsContent>
</Tabs>
</div>
{/* Ban IP Modal */}