@wakastellar/ui 2.4.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocks/antivirus-dashboard/index.d.ts +44 -0
- package/dist/blocks/clamav-service-status/index.d.ts +35 -0
- package/dist/blocks/file-scan-uploader/index.d.ts +29 -0
- package/dist/blocks/index.d.ts +18 -9
- package/dist/blocks/quarantine-manager/index.d.ts +27 -0
- package/dist/blocks/scan-history-log/index.d.ts +28 -0
- package/dist/blocks/scan-policy-editor/index.d.ts +27 -0
- package/dist/blocks/scan-report-generator/index.d.ts +47 -0
- package/dist/blocks/signature-database-manager/index.d.ts +39 -0
- package/dist/blocks/threat-alert-banner/index.d.ts +26 -0
- package/dist/components/index.d.ts +4 -4
- package/dist/components/waka-signature-pad/index.d.ts +1 -1
- package/dist/exceljs.min-BcLLX0PC.js +29 -0
- package/dist/exceljs.min-KOayaaQ4.mjs +23013 -0
- package/dist/export.cjs.js +1 -1
- package/dist/export.d.ts +2 -2
- package/dist/export.es.js +1 -1
- package/dist/index.cjs.js +136 -136
- package/dist/index.es.js +29978 -27215
- package/dist/stories/Button.stories.d.ts +1 -1
- package/dist/stories/Header.stories.d.ts +1 -1
- package/dist/stories/Page.stories.d.ts +1 -1
- package/dist/useDataTableImport-COVnvslz.js +9 -0
- package/dist/useDataTableImport-DAlxBY8w.mjs +237 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/package.json +6 -5
- package/src/blocks/antivirus-dashboard/AntivirusDashboard.stories.tsx +291 -0
- package/src/blocks/antivirus-dashboard/index.tsx +525 -0
- package/src/blocks/clamav-service-status/ClamAVServiceStatus.stories.tsx +195 -0
- package/src/blocks/clamav-service-status/index.tsx +370 -0
- package/src/blocks/file-scan-uploader/FileScanUploader.stories.tsx +257 -0
- package/src/blocks/file-scan-uploader/index.tsx +311 -0
- package/src/blocks/index.ts +163 -11
- package/src/blocks/quarantine-manager/QuarantineManager.stories.tsx +209 -0
- package/src/blocks/quarantine-manager/index.tsx +435 -0
- package/src/blocks/scan-history-log/ScanHistoryLog.stories.tsx +231 -0
- package/src/blocks/scan-history-log/index.tsx +406 -0
- package/src/blocks/scan-policy-editor/ScanPolicyEditor.stories.tsx +106 -0
- package/src/blocks/scan-policy-editor/index.tsx +418 -0
- package/src/blocks/scan-report-generator/ScanReportGenerator.stories.tsx +232 -0
- package/src/blocks/scan-report-generator/index.tsx +612 -0
- package/src/blocks/sidebar/index.tsx +2 -1
- package/src/blocks/signature-database-manager/SignatureDatabaseManager.stories.tsx +279 -0
- package/src/blocks/signature-database-manager/index.tsx +470 -0
- package/src/blocks/theme-creator-block/index.tsx +16 -2
- package/src/blocks/threat-alert-banner/ThreatAlertBanner.stories.tsx +152 -0
- package/src/blocks/threat-alert-banner/index.tsx +320 -0
- package/src/components/DataTable/DataTable.stories.tsx +203 -0
- package/src/components/DataTable/hooks/useDataTableExport.ts +38 -31
- package/src/components/DataTable/hooks/useDataTableImport.ts +31 -20
- package/src/components/error-boundary/ErrorBoundary.stories.tsx +125 -0
- package/src/components/index.ts +45 -4
- package/src/components/language-selector/LanguageSelector.stories.tsx +112 -0
- package/src/components/theme-selector/ThemeSelector.stories.tsx +77 -0
- package/src/components/toaster/Toaster.stories.tsx +67 -0
- package/src/components/waka-activity-feed/WakaActivityFeed.stories.tsx +116 -0
- package/src/components/waka-ad-banner/WakaAdBanner.stories.tsx +102 -0
- package/src/components/waka-ad-fallback/WakaAdFallback.stories.tsx +117 -0
- package/src/components/waka-ad-inline/WakaAdInline.stories.tsx +105 -0
- package/src/components/waka-ad-interstitial/WakaAdInterstitial.stories.tsx +92 -0
- package/src/components/waka-ad-placeholder/WakaAdPlaceholder.stories.tsx +89 -0
- package/src/components/waka-ad-provider/WakaAdProvider.stories.tsx +110 -0
- package/src/components/waka-ad-sidebar/WakaAdSidebar.stories.tsx +89 -0
- package/src/components/waka-ad-sidebar/index.tsx +3 -2
- package/src/components/waka-ad-sticky-footer/WakaAdStickyFooter.stories.tsx +88 -0
- package/src/components/waka-address-autocomplete/WakaAddressAutocomplete.stories.tsx +46 -0
- package/src/components/waka-admincrumb/WakaAdmincrumb.stories.tsx +166 -0
- package/src/components/waka-alert-panel/WakaAlertPanel.stories.tsx +45 -0
- package/src/components/waka-alert-stack/WakaAlertStack.stories.tsx +62 -0
- package/src/components/waka-allocation-matrix/WakaAllocationMatrix.stories.tsx +68 -0
- package/src/components/waka-approval-chain/WakaApprovalChain.stories.tsx +63 -0
- package/src/components/waka-audit-log/WakaAuditLog.stories.tsx +73 -0
- package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +132 -172
- package/src/components/waka-biometric-prompt/WakaBiometricPrompt.stories.tsx +48 -0
- package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +74 -191
- package/src/components/waka-breadcrumb-path/WakaBreadcrumbPath.stories.tsx +40 -0
- package/src/components/waka-budget-burn/WakaBudgetBurn.stories.tsx +86 -0
- package/src/components/waka-capacity-planner/WakaCapacityPlanner.stories.tsx +273 -0
- package/src/components/waka-cart-summary/WakaCartSummary.stories.tsx +176 -0
- package/src/components/waka-cart-summary/index.tsx +19 -10
- package/src/components/waka-challenge-timer/WakaChallengeTimer.stories.tsx +98 -0
- package/src/components/waka-chat-bubble/WakaChatBubble.stories.tsx +118 -0
- package/src/components/waka-checklist/WakaChecklist.stories.tsx +71 -0
- package/src/components/waka-checkout-stepper/WakaCheckoutStepper.stories.tsx +102 -0
- package/src/components/waka-cohort-table/WakaCohortTable.stories.tsx +56 -0
- package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +99 -155
- package/src/components/waka-combo-counter/WakaComboCounter.stories.tsx +128 -0
- package/src/components/waka-command-bar/WakaCommandBar.stories.tsx +45 -0
- package/src/components/waka-compare-period/WakaComparePeriod.stories.tsx +76 -0
- package/src/components/waka-config-comparator/WakaConfigComparator.stories.tsx +143 -0
- package/src/components/waka-connection-matrix/WakaConnectionMatrix.stories.tsx +52 -0
- package/src/components/waka-content-recommendation/WakaContentRecommendation.stories.tsx +41 -0
- package/src/components/waka-coupon-input/WakaCouponInput.stories.tsx +126 -0
- package/src/components/waka-credit-card-input/WakaCreditCardInput.stories.tsx +120 -0
- package/src/components/waka-datetime-picker.form-integration/WakaDateTimePickerForm.stories.tsx +79 -0
- package/src/components/waka-dependency-tree/WakaDependencyTree.stories.tsx +72 -0
- package/src/components/waka-device-trust/WakaDeviceTrust.stories.tsx +109 -0
- package/src/components/waka-empty-state/WakaEmptyState.stories.tsx +87 -0
- package/src/components/waka-feature-announcement/WakaFeatureAnnouncement.stories.tsx +47 -0
- package/src/components/waka-feature-flag-row/WakaFeatureFlagRow.stories.tsx +188 -0
- package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +118 -174
- package/src/components/waka-floating-nav/WakaFloatingNav.stories.tsx +53 -0
- package/src/components/waka-goal-progress/WakaGoalProgress.stories.tsx +137 -0
- package/src/components/waka-hotspot/WakaHotspot.stories.tsx +56 -0
- package/src/components/waka-invoice-preview/WakaInvoicePreview.stories.tsx +169 -0
- package/src/components/waka-kpi-dashboard/WakaKpiDashboard.stories.tsx +46 -0
- package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +94 -75
- package/src/components/waka-liquid-button/WakaLiquidButton.stories.tsx +45 -0
- package/src/components/waka-magic-link/WakaMagicLink.stories.tsx +61 -0
- package/src/components/waka-magnetic-button/WakaMagneticButton.stories.tsx +40 -0
- package/src/components/waka-mention-input/WakaMentionInput.stories.tsx +140 -0
- package/src/components/waka-milestone-road/WakaMilestoneRoad.stories.tsx +143 -0
- package/src/components/waka-orbital-menu/WakaOrbitalMenu.stories.tsx +54 -0
- package/src/components/waka-order-tracker/WakaOrderTracker.stories.tsx +163 -0
- package/src/components/waka-outstream-video/WakaOutstreamVideo.stories.tsx +94 -0
- package/src/components/waka-pagination/WakaPagination.stories.tsx +110 -280
- package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +132 -268
- package/src/components/waka-payment-method-picker/WakaPaymentMethodPicker.stories.tsx +141 -0
- package/src/components/waka-permission-matrix/WakaPermissionMatrix.stories.tsx +124 -0
- package/src/components/waka-phone-input/WakaPhoneInput.stories.tsx +56 -0
- package/src/components/waka-points-popup/WakaPointsPopup.stories.tsx +96 -0
- package/src/components/waka-power-up/WakaPowerUp.stories.tsx +121 -0
- package/src/components/waka-presence-indicator/WakaPresenceIndicator.stories.tsx +49 -0
- package/src/components/waka-pricing-table/WakaPricingTable.stories.tsx +159 -0
- package/src/components/waka-product-card/WakaProductCard.stories.tsx +202 -0
- package/src/components/waka-progress-onboarding/WakaProgressOnboarding.stories.tsx +57 -0
- package/src/components/waka-pull-to-refresh/WakaPullToRefresh.stories.tsx +51 -0
- package/src/components/waka-rank-badge/WakaRankBadge.stories.tsx +108 -0
- package/src/components/waka-rating-input/WakaRatingInput.stories.tsx +51 -0
- package/src/components/waka-reaction-picker/WakaReactionPicker.stories.tsx +52 -0
- package/src/components/waka-region-map/WakaRegionMap.stories.tsx +181 -0
- package/src/components/waka-resource-pool/WakaResourcePool.stories.tsx +70 -0
- package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +108 -197
- package/src/components/waka-rollback-slider/WakaRollbackSlider.stories.tsx +41 -0
- package/src/components/waka-schedule-picker/WakaSchedulePicker.stories.tsx +64 -0
- package/src/components/waka-season-pass/WakaSeasonPass.stories.tsx +107 -0
- package/src/components/waka-security-scan-result/WakaSecurityScanResult.stories.tsx +146 -0
- package/src/components/waka-security-score/WakaSecurityScore.stories.tsx +63 -0
- package/src/components/waka-session-manager/WakaSessionManager.stories.tsx +68 -0
- package/src/components/waka-signature-pad/WakaSignaturePad.stories.tsx +159 -0
- package/src/components/waka-signature-pad/index.tsx +5 -3
- package/src/components/waka-sla-tracker/WakaSlaTracker.stories.tsx +65 -0
- package/src/components/waka-slider-range/WakaSliderRange.stories.tsx +66 -0
- package/src/components/waka-sponsored-badge/WakaSponsoredBadge.stories.tsx +60 -0
- package/src/components/waka-sponsored-card/WakaSponsoredCard.stories.tsx +64 -0
- package/src/components/waka-sponsored-feed/WakaSponsoredFeed.stories.tsx +58 -0
- package/src/components/waka-spotlight/WakaSpotlight.stories.tsx +53 -0
- package/src/components/waka-stats-hexagon/WakaStatsHexagon.stories.tsx +161 -0
- package/src/components/waka-stepper/WakaStepper.stories.tsx +137 -410
- package/src/components/waka-swipe-card/WakaSwipeCard.stories.tsx +51 -0
- package/src/components/waka-tag-input/WakaTagInput.stories.tsx +224 -0
- package/src/components/waka-team-banner/WakaTeamBanner.stories.tsx +50 -0
- package/src/components/waka-theme-creator/WakaThemeCreator.stories.tsx +58 -0
- package/src/components/waka-theme-manager/WakaThemeManager.stories.tsx +298 -0
- package/src/components/waka-theme-manager/index.tsx +6 -11
- package/src/components/waka-thread-view/WakaThreadView.stories.tsx +143 -0
- package/src/components/waka-timeline/WakaTimeline.stories.tsx +171 -324
- package/src/components/waka-tooltip-tour/WakaTooltipTour.stories.tsx +92 -0
- package/src/components/waka-tour-guide/WakaTourGuide.stories.tsx +89 -0
- package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +234 -129
- package/src/components/waka-treemap-chart/index.tsx +2 -2
- package/src/components/waka-two-factor-setup/WakaTwoFactorSetup.stories.tsx +142 -0
- package/src/components/waka-typing-indicator/WakaTypingIndicator.stories.tsx +134 -0
- package/src/components/waka-video-ad/WakaVideoAd.stories.tsx +138 -0
- package/src/components/waka-video-call/WakaVideoCall.stories.tsx +186 -0
- package/src/components/waka-video-overlay/WakaVideoOverlay.stories.tsx +100 -0
- package/src/components/waka-voice-message/WakaVoiceMessage.stories.tsx +190 -0
- package/src/components/waka-welcome-modal/WakaWelcomeModal.stories.tsx +87 -0
- package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +29 -29
- package/dist/useDataTableImport-D8R2HQl6.mjs +0 -229
- package/dist/useDataTableImport-S_hhA5Wo.js +0 -9
- package/src/components/DataTable/README.md +0 -446
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useState } from "react"
|
|
4
|
+
import { Badge } from "../../components/badge"
|
|
5
|
+
import { Button } from "../../components/button"
|
|
6
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../../components/card"
|
|
7
|
+
import { Input } from "../../components/input"
|
|
8
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../components/select"
|
|
9
|
+
import { Progress } from "../../components/progress"
|
|
10
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/tabs"
|
|
11
|
+
import { Checkbox } from "../../components/checkbox"
|
|
12
|
+
import { Label } from "../../components/label"
|
|
13
|
+
import {
|
|
14
|
+
FileText,
|
|
15
|
+
Download,
|
|
16
|
+
Mail,
|
|
17
|
+
Calendar,
|
|
18
|
+
CheckCircle2,
|
|
19
|
+
AlertTriangle,
|
|
20
|
+
XCircle,
|
|
21
|
+
Shield,
|
|
22
|
+
TrendingUp,
|
|
23
|
+
BarChart3,
|
|
24
|
+
FileSpreadsheet,
|
|
25
|
+
FileJson,
|
|
26
|
+
} from "lucide-react"
|
|
27
|
+
import { cn } from "../../utils/cn"
|
|
28
|
+
|
|
29
|
+
export type ReportFormat = "pdf" | "csv" | "json"
|
|
30
|
+
export type ReportType = "executive_summary" | "detailed" | "iso27001_compliance" | "hds_audit"
|
|
31
|
+
|
|
32
|
+
export interface ReportConfig {
|
|
33
|
+
startDate: Date
|
|
34
|
+
endDate: Date
|
|
35
|
+
format: ReportFormat
|
|
36
|
+
type: ReportType
|
|
37
|
+
includeSections: {
|
|
38
|
+
generalStats: boolean
|
|
39
|
+
threatDetails: boolean
|
|
40
|
+
scannedFiles: boolean
|
|
41
|
+
actionsTaken: boolean
|
|
42
|
+
recommendations: boolean
|
|
43
|
+
}
|
|
44
|
+
recipientEmail?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ReportPreview {
|
|
48
|
+
totalScans: number
|
|
49
|
+
totalThreats: number
|
|
50
|
+
detectionRate: number
|
|
51
|
+
quarantinedFiles: number
|
|
52
|
+
threatsBySeverity: { severity: string; count: number }[]
|
|
53
|
+
complianceChecks: { name: string; passed: boolean; details: string }[]
|
|
54
|
+
weeklyTrend: { week: string; scans: number; threats: number }[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ScanReportGeneratorProps {
|
|
58
|
+
config?: Partial<ReportConfig>
|
|
59
|
+
preview?: ReportPreview
|
|
60
|
+
isGenerating?: boolean
|
|
61
|
+
generationProgress?: number
|
|
62
|
+
onGenerate?: (config: ReportConfig) => void
|
|
63
|
+
onSchedule?: (config: ReportConfig, frequency: "daily" | "weekly" | "monthly") => void
|
|
64
|
+
onSendEmail?: (config: ReportConfig, email: string) => void
|
|
65
|
+
className?: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const defaultConfig: ReportConfig = {
|
|
69
|
+
startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
|
|
70
|
+
endDate: new Date(),
|
|
71
|
+
format: "pdf",
|
|
72
|
+
type: "executive_summary",
|
|
73
|
+
includeSections: {
|
|
74
|
+
generalStats: true,
|
|
75
|
+
threatDetails: true,
|
|
76
|
+
scannedFiles: true,
|
|
77
|
+
actionsTaken: true,
|
|
78
|
+
recommendations: true,
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const defaultPreview: ReportPreview = {
|
|
83
|
+
totalScans: 1247,
|
|
84
|
+
totalThreats: 34,
|
|
85
|
+
detectionRate: 98.5,
|
|
86
|
+
quarantinedFiles: 28,
|
|
87
|
+
threatsBySeverity: [
|
|
88
|
+
{ severity: "critical", count: 3 },
|
|
89
|
+
{ severity: "high", count: 8 },
|
|
90
|
+
{ severity: "medium", count: 15 },
|
|
91
|
+
{ severity: "low", count: 8 },
|
|
92
|
+
],
|
|
93
|
+
complianceChecks: [
|
|
94
|
+
{ name: "Antivirus actif", passed: true, details: "ClamAV opérationnel" },
|
|
95
|
+
{ name: "Scans automatisés", passed: true, details: "Planification quotidienne" },
|
|
96
|
+
{ name: "Quarantaine sécurisée", passed: true, details: "Isolation cryptographique" },
|
|
97
|
+
{ name: "Audit trail", passed: true, details: "Logs immutables activés" },
|
|
98
|
+
],
|
|
99
|
+
weeklyTrend: [
|
|
100
|
+
{ week: "S1", scans: 280, threats: 7 },
|
|
101
|
+
{ week: "S2", scans: 295, threats: 9 },
|
|
102
|
+
{ week: "S3", scans: 340, threats: 11 },
|
|
103
|
+
{ week: "S4", scans: 332, threats: 7 },
|
|
104
|
+
],
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function ScanReportGenerator({
|
|
108
|
+
config: initialConfig,
|
|
109
|
+
preview: initialPreview,
|
|
110
|
+
isGenerating = false,
|
|
111
|
+
generationProgress = 0,
|
|
112
|
+
onGenerate,
|
|
113
|
+
onSchedule,
|
|
114
|
+
onSendEmail,
|
|
115
|
+
className,
|
|
116
|
+
}: ScanReportGeneratorProps) {
|
|
117
|
+
const [config, setConfig] = useState<ReportConfig>({ ...defaultConfig, ...initialConfig })
|
|
118
|
+
const [preview] = useState<ReportPreview>(initialPreview || defaultPreview)
|
|
119
|
+
const [recipientEmail, setRecipientEmail] = useState("")
|
|
120
|
+
const [activeTab, setActiveTab] = useState("config")
|
|
121
|
+
|
|
122
|
+
const formatIcons: Record<ReportFormat, React.ReactNode> = {
|
|
123
|
+
pdf: <FileText className="h-4 w-4" />,
|
|
124
|
+
csv: <FileSpreadsheet className="h-4 w-4" />,
|
|
125
|
+
json: <FileJson className="h-4 w-4" />,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const reportTypeLabels: Record<ReportType, string> = {
|
|
129
|
+
executive_summary: "Résumé exécutif",
|
|
130
|
+
detailed: "Détail complet",
|
|
131
|
+
iso27001_compliance: "Conformité ISO27001",
|
|
132
|
+
hds_audit: "Audit HDS",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const severityColors: Record<string, string> = {
|
|
136
|
+
critical: "bg-red-500",
|
|
137
|
+
high: "bg-orange-500",
|
|
138
|
+
medium: "bg-yellow-500",
|
|
139
|
+
low: "bg-blue-500",
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const updateSection = (section: keyof ReportConfig["includeSections"], value: boolean) => {
|
|
143
|
+
setConfig({
|
|
144
|
+
...config,
|
|
145
|
+
includeSections: {
|
|
146
|
+
...config.includeSections,
|
|
147
|
+
[section]: value,
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const maxThreatCount = Math.max(...preview.threatsBySeverity.map((t) => t.count))
|
|
153
|
+
const maxTrendValue = Math.max(...preview.weeklyTrend.map((t) => Math.max(t.scans, t.threats)))
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<div className={cn("space-y-6", className)}>
|
|
157
|
+
{/* Header */}
|
|
158
|
+
<div className="flex items-start justify-between">
|
|
159
|
+
<div>
|
|
160
|
+
<h2 className="text-2xl font-bold">Générateur de rapports</h2>
|
|
161
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
162
|
+
Créez des rapports de scan personnalisés pour vos audits de sécurité
|
|
163
|
+
</p>
|
|
164
|
+
</div>
|
|
165
|
+
<Badge variant="outline" className="gap-1.5">
|
|
166
|
+
<Shield className="h-3.5 w-3.5" />
|
|
167
|
+
ISO27001 / HDS
|
|
168
|
+
</Badge>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{/* Main Content */}
|
|
172
|
+
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
|
173
|
+
<TabsList>
|
|
174
|
+
<TabsTrigger value="config">Configuration</TabsTrigger>
|
|
175
|
+
<TabsTrigger value="preview">Aperçu</TabsTrigger>
|
|
176
|
+
</TabsList>
|
|
177
|
+
|
|
178
|
+
{/* Configuration Tab */}
|
|
179
|
+
<TabsContent value="config" className="space-y-6">
|
|
180
|
+
<Card>
|
|
181
|
+
<CardHeader>
|
|
182
|
+
<CardTitle>Période du rapport</CardTitle>
|
|
183
|
+
<CardDescription>Sélectionnez la plage de dates à analyser</CardDescription>
|
|
184
|
+
</CardHeader>
|
|
185
|
+
<CardContent className="grid gap-4 sm:grid-cols-2">
|
|
186
|
+
<div className="space-y-2">
|
|
187
|
+
<Label htmlFor="startDate">Date de début</Label>
|
|
188
|
+
<Input
|
|
189
|
+
id="startDate"
|
|
190
|
+
type="date"
|
|
191
|
+
value={config.startDate.toISOString().split("T")[0]}
|
|
192
|
+
onChange={(e) =>
|
|
193
|
+
setConfig({ ...config, startDate: new Date(e.target.value) })
|
|
194
|
+
}
|
|
195
|
+
/>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="space-y-2">
|
|
198
|
+
<Label htmlFor="endDate">Date de fin</Label>
|
|
199
|
+
<Input
|
|
200
|
+
id="endDate"
|
|
201
|
+
type="date"
|
|
202
|
+
value={config.endDate.toISOString().split("T")[0]}
|
|
203
|
+
onChange={(e) => setConfig({ ...config, endDate: new Date(e.target.value) })}
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
</CardContent>
|
|
207
|
+
</Card>
|
|
208
|
+
|
|
209
|
+
<Card>
|
|
210
|
+
<CardHeader>
|
|
211
|
+
<CardTitle>Type et format</CardTitle>
|
|
212
|
+
<CardDescription>Choisissez le type de rapport et le format de sortie</CardDescription>
|
|
213
|
+
</CardHeader>
|
|
214
|
+
<CardContent className="grid gap-4 sm:grid-cols-2">
|
|
215
|
+
<div className="space-y-2">
|
|
216
|
+
<Label htmlFor="reportType">Type de rapport</Label>
|
|
217
|
+
<Select
|
|
218
|
+
value={config.type}
|
|
219
|
+
onValueChange={(value) => setConfig({ ...config, type: value as ReportType })}
|
|
220
|
+
>
|
|
221
|
+
<SelectTrigger id="reportType">
|
|
222
|
+
<SelectValue />
|
|
223
|
+
</SelectTrigger>
|
|
224
|
+
<SelectContent>
|
|
225
|
+
{Object.entries(reportTypeLabels).map(([value, label]) => (
|
|
226
|
+
<SelectItem key={value} value={value}>
|
|
227
|
+
{label}
|
|
228
|
+
</SelectItem>
|
|
229
|
+
))}
|
|
230
|
+
</SelectContent>
|
|
231
|
+
</Select>
|
|
232
|
+
</div>
|
|
233
|
+
<div className="space-y-2">
|
|
234
|
+
<Label htmlFor="format">Format de sortie</Label>
|
|
235
|
+
<Select
|
|
236
|
+
value={config.format}
|
|
237
|
+
onValueChange={(value) => setConfig({ ...config, format: value as ReportFormat })}
|
|
238
|
+
>
|
|
239
|
+
<SelectTrigger id="format">
|
|
240
|
+
<SelectValue />
|
|
241
|
+
</SelectTrigger>
|
|
242
|
+
<SelectContent>
|
|
243
|
+
<SelectItem value="pdf">
|
|
244
|
+
<span className="flex items-center gap-2">
|
|
245
|
+
{formatIcons.pdf}
|
|
246
|
+
PDF
|
|
247
|
+
</span>
|
|
248
|
+
</SelectItem>
|
|
249
|
+
<SelectItem value="csv">
|
|
250
|
+
<span className="flex items-center gap-2">
|
|
251
|
+
{formatIcons.csv}
|
|
252
|
+
CSV
|
|
253
|
+
</span>
|
|
254
|
+
</SelectItem>
|
|
255
|
+
<SelectItem value="json">
|
|
256
|
+
<span className="flex items-center gap-2">
|
|
257
|
+
{formatIcons.json}
|
|
258
|
+
JSON
|
|
259
|
+
</span>
|
|
260
|
+
</SelectItem>
|
|
261
|
+
</SelectContent>
|
|
262
|
+
</Select>
|
|
263
|
+
</div>
|
|
264
|
+
</CardContent>
|
|
265
|
+
</Card>
|
|
266
|
+
|
|
267
|
+
<Card>
|
|
268
|
+
<CardHeader>
|
|
269
|
+
<CardTitle>Sections à inclure</CardTitle>
|
|
270
|
+
<CardDescription>Personnalisez le contenu du rapport</CardDescription>
|
|
271
|
+
</CardHeader>
|
|
272
|
+
<CardContent className="space-y-3">
|
|
273
|
+
<div className="flex items-center gap-2">
|
|
274
|
+
<Checkbox
|
|
275
|
+
id="generalStats"
|
|
276
|
+
checked={config.includeSections.generalStats}
|
|
277
|
+
onCheckedChange={(checked) =>
|
|
278
|
+
updateSection("generalStats", checked as boolean)
|
|
279
|
+
}
|
|
280
|
+
/>
|
|
281
|
+
<Label htmlFor="generalStats" className="cursor-pointer">
|
|
282
|
+
Statistiques générales
|
|
283
|
+
</Label>
|
|
284
|
+
</div>
|
|
285
|
+
<div className="flex items-center gap-2">
|
|
286
|
+
<Checkbox
|
|
287
|
+
id="threatDetails"
|
|
288
|
+
checked={config.includeSections.threatDetails}
|
|
289
|
+
onCheckedChange={(checked) =>
|
|
290
|
+
updateSection("threatDetails", checked as boolean)
|
|
291
|
+
}
|
|
292
|
+
/>
|
|
293
|
+
<Label htmlFor="threatDetails" className="cursor-pointer">
|
|
294
|
+
Détails des menaces détectées
|
|
295
|
+
</Label>
|
|
296
|
+
</div>
|
|
297
|
+
<div className="flex items-center gap-2">
|
|
298
|
+
<Checkbox
|
|
299
|
+
id="scannedFiles"
|
|
300
|
+
checked={config.includeSections.scannedFiles}
|
|
301
|
+
onCheckedChange={(checked) =>
|
|
302
|
+
updateSection("scannedFiles", checked as boolean)
|
|
303
|
+
}
|
|
304
|
+
/>
|
|
305
|
+
<Label htmlFor="scannedFiles" className="cursor-pointer">
|
|
306
|
+
Liste des fichiers scannés
|
|
307
|
+
</Label>
|
|
308
|
+
</div>
|
|
309
|
+
<div className="flex items-center gap-2">
|
|
310
|
+
<Checkbox
|
|
311
|
+
id="actionsTaken"
|
|
312
|
+
checked={config.includeSections.actionsTaken}
|
|
313
|
+
onCheckedChange={(checked) =>
|
|
314
|
+
updateSection("actionsTaken", checked as boolean)
|
|
315
|
+
}
|
|
316
|
+
/>
|
|
317
|
+
<Label htmlFor="actionsTaken" className="cursor-pointer">
|
|
318
|
+
Actions prises
|
|
319
|
+
</Label>
|
|
320
|
+
</div>
|
|
321
|
+
<div className="flex items-center gap-2">
|
|
322
|
+
<Checkbox
|
|
323
|
+
id="recommendations"
|
|
324
|
+
checked={config.includeSections.recommendations}
|
|
325
|
+
onCheckedChange={(checked) =>
|
|
326
|
+
updateSection("recommendations", checked as boolean)
|
|
327
|
+
}
|
|
328
|
+
/>
|
|
329
|
+
<Label htmlFor="recommendations" className="cursor-pointer">
|
|
330
|
+
Recommandations
|
|
331
|
+
</Label>
|
|
332
|
+
</div>
|
|
333
|
+
</CardContent>
|
|
334
|
+
</Card>
|
|
335
|
+
|
|
336
|
+
{/* Actions */}
|
|
337
|
+
<div className="flex flex-col sm:flex-row gap-3">
|
|
338
|
+
<Button
|
|
339
|
+
className="flex-1"
|
|
340
|
+
onClick={() => onGenerate?.(config)}
|
|
341
|
+
disabled={isGenerating}
|
|
342
|
+
>
|
|
343
|
+
<Download className="h-4 w-4 mr-2" />
|
|
344
|
+
Générer le rapport
|
|
345
|
+
</Button>
|
|
346
|
+
<Button
|
|
347
|
+
variant="outline"
|
|
348
|
+
className="flex-1"
|
|
349
|
+
onClick={() => onSchedule?.(config, "weekly")}
|
|
350
|
+
disabled={isGenerating}
|
|
351
|
+
>
|
|
352
|
+
<Calendar className="h-4 w-4 mr-2" />
|
|
353
|
+
Planifier génération
|
|
354
|
+
</Button>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
<Card>
|
|
358
|
+
<CardHeader>
|
|
359
|
+
<CardTitle>Envoi par email</CardTitle>
|
|
360
|
+
<CardDescription>Envoyez le rapport directement par email</CardDescription>
|
|
361
|
+
</CardHeader>
|
|
362
|
+
<CardContent className="flex gap-2">
|
|
363
|
+
<Input
|
|
364
|
+
placeholder="email@example.com"
|
|
365
|
+
type="email"
|
|
366
|
+
value={recipientEmail}
|
|
367
|
+
onChange={(e) => setRecipientEmail(e.target.value)}
|
|
368
|
+
className="flex-1"
|
|
369
|
+
/>
|
|
370
|
+
<Button
|
|
371
|
+
variant="outline"
|
|
372
|
+
onClick={() => onSendEmail?.(config, recipientEmail)}
|
|
373
|
+
disabled={!recipientEmail || isGenerating}
|
|
374
|
+
>
|
|
375
|
+
<Mail className="h-4 w-4 mr-2" />
|
|
376
|
+
Envoyer
|
|
377
|
+
</Button>
|
|
378
|
+
</CardContent>
|
|
379
|
+
</Card>
|
|
380
|
+
|
|
381
|
+
{/* Generation Progress */}
|
|
382
|
+
{isGenerating && (
|
|
383
|
+
<Card>
|
|
384
|
+
<CardContent className="pt-6">
|
|
385
|
+
<div className="space-y-2">
|
|
386
|
+
<div className="flex items-center justify-between text-sm">
|
|
387
|
+
<span className="text-muted-foreground">Génération en cours...</span>
|
|
388
|
+
<span className="font-medium">{generationProgress}%</span>
|
|
389
|
+
</div>
|
|
390
|
+
<Progress value={generationProgress} />
|
|
391
|
+
</div>
|
|
392
|
+
</CardContent>
|
|
393
|
+
</Card>
|
|
394
|
+
)}
|
|
395
|
+
</TabsContent>
|
|
396
|
+
|
|
397
|
+
{/* Preview Tab */}
|
|
398
|
+
<TabsContent value="preview" className="space-y-6">
|
|
399
|
+
{/* Header Preview */}
|
|
400
|
+
<Card>
|
|
401
|
+
<CardContent className="pt-6">
|
|
402
|
+
<div className="space-y-4">
|
|
403
|
+
<div className="flex items-start justify-between">
|
|
404
|
+
<div>
|
|
405
|
+
<div className="h-12 w-12 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center mb-3">
|
|
406
|
+
<Shield className="h-6 w-6 text-white" />
|
|
407
|
+
</div>
|
|
408
|
+
<h3 className="text-xl font-bold">Rapport de scan de sécurité</h3>
|
|
409
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
410
|
+
{reportTypeLabels[config.type]}
|
|
411
|
+
</p>
|
|
412
|
+
</div>
|
|
413
|
+
<Badge variant="secondary">
|
|
414
|
+
{config.startDate.toLocaleDateString()} -{" "}
|
|
415
|
+
{config.endDate.toLocaleDateString()}
|
|
416
|
+
</Badge>
|
|
417
|
+
</div>
|
|
418
|
+
<div className="text-xs text-muted-foreground">
|
|
419
|
+
Généré le {new Date().toLocaleString()}
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
</CardContent>
|
|
423
|
+
</Card>
|
|
424
|
+
|
|
425
|
+
{/* Summary Stats */}
|
|
426
|
+
{config.includeSections.generalStats && (
|
|
427
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
428
|
+
<Card>
|
|
429
|
+
<CardContent className="pt-6">
|
|
430
|
+
<div className="space-y-2">
|
|
431
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
432
|
+
<BarChart3 className="h-4 w-4" />
|
|
433
|
+
Total scans
|
|
434
|
+
</div>
|
|
435
|
+
<div className="text-2xl font-bold">{preview.totalScans.toLocaleString()}</div>
|
|
436
|
+
</div>
|
|
437
|
+
</CardContent>
|
|
438
|
+
</Card>
|
|
439
|
+
<Card>
|
|
440
|
+
<CardContent className="pt-6">
|
|
441
|
+
<div className="space-y-2">
|
|
442
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
443
|
+
<AlertTriangle className="h-4 w-4" />
|
|
444
|
+
Menaces détectées
|
|
445
|
+
</div>
|
|
446
|
+
<div className="text-2xl font-bold">{preview.totalThreats}</div>
|
|
447
|
+
</div>
|
|
448
|
+
</CardContent>
|
|
449
|
+
</Card>
|
|
450
|
+
<Card>
|
|
451
|
+
<CardContent className="pt-6">
|
|
452
|
+
<div className="space-y-2">
|
|
453
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
454
|
+
<TrendingUp className="h-4 w-4" />
|
|
455
|
+
Taux de détection
|
|
456
|
+
</div>
|
|
457
|
+
<div className="text-2xl font-bold">{preview.detectionRate}%</div>
|
|
458
|
+
</div>
|
|
459
|
+
</CardContent>
|
|
460
|
+
</Card>
|
|
461
|
+
<Card>
|
|
462
|
+
<CardContent className="pt-6">
|
|
463
|
+
<div className="space-y-2">
|
|
464
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
465
|
+
<Shield className="h-4 w-4" />
|
|
466
|
+
Fichiers en quarantaine
|
|
467
|
+
</div>
|
|
468
|
+
<div className="text-2xl font-bold">{preview.quarantinedFiles}</div>
|
|
469
|
+
</div>
|
|
470
|
+
</CardContent>
|
|
471
|
+
</Card>
|
|
472
|
+
</div>
|
|
473
|
+
)}
|
|
474
|
+
|
|
475
|
+
{/* Threats by Severity */}
|
|
476
|
+
{config.includeSections.threatDetails && (
|
|
477
|
+
<Card>
|
|
478
|
+
<CardHeader>
|
|
479
|
+
<CardTitle>Menaces par sévérité</CardTitle>
|
|
480
|
+
<CardDescription>Distribution des menaces détectées</CardDescription>
|
|
481
|
+
</CardHeader>
|
|
482
|
+
<CardContent className="space-y-4">
|
|
483
|
+
{preview.threatsBySeverity.map((item) => (
|
|
484
|
+
<div key={item.severity} className="space-y-2">
|
|
485
|
+
<div className="flex items-center justify-between text-sm">
|
|
486
|
+
<span className="capitalize font-medium">{item.severity}</span>
|
|
487
|
+
<span className="text-muted-foreground">{item.count}</span>
|
|
488
|
+
</div>
|
|
489
|
+
<div className="h-2 bg-muted rounded-full overflow-hidden">
|
|
490
|
+
<div
|
|
491
|
+
className={cn("h-full rounded-full", severityColors[item.severity])}
|
|
492
|
+
style={{ width: `${(item.count / maxThreatCount) * 100}%` }}
|
|
493
|
+
/>
|
|
494
|
+
</div>
|
|
495
|
+
</div>
|
|
496
|
+
))}
|
|
497
|
+
</CardContent>
|
|
498
|
+
</Card>
|
|
499
|
+
)}
|
|
500
|
+
|
|
501
|
+
{/* Weekly Trend */}
|
|
502
|
+
{config.includeSections.generalStats && (
|
|
503
|
+
<Card>
|
|
504
|
+
<CardHeader>
|
|
505
|
+
<CardTitle>Tendance hebdomadaire</CardTitle>
|
|
506
|
+
<CardDescription>Évolution des scans et menaces</CardDescription>
|
|
507
|
+
</CardHeader>
|
|
508
|
+
<CardContent>
|
|
509
|
+
<div className="space-y-4">
|
|
510
|
+
<div className="flex items-end gap-4 h-48">
|
|
511
|
+
{preview.weeklyTrend.map((item) => (
|
|
512
|
+
<div key={item.week} className="flex-1 flex flex-col items-center gap-2">
|
|
513
|
+
<div className="flex-1 w-full flex items-end gap-1">
|
|
514
|
+
<div
|
|
515
|
+
className="flex-1 bg-blue-500 rounded-t"
|
|
516
|
+
style={{ height: `${(item.scans / maxTrendValue) * 100}%` }}
|
|
517
|
+
title={`Scans: ${item.scans}`}
|
|
518
|
+
/>
|
|
519
|
+
<div
|
|
520
|
+
className="flex-1 bg-orange-500 rounded-t"
|
|
521
|
+
style={{ height: `${(item.threats / maxTrendValue) * 100}%` }}
|
|
522
|
+
title={`Menaces: ${item.threats}`}
|
|
523
|
+
/>
|
|
524
|
+
</div>
|
|
525
|
+
<span className="text-xs text-muted-foreground">{item.week}</span>
|
|
526
|
+
</div>
|
|
527
|
+
))}
|
|
528
|
+
</div>
|
|
529
|
+
<div className="flex items-center justify-center gap-6 text-xs">
|
|
530
|
+
<div className="flex items-center gap-2">
|
|
531
|
+
<div className="h-3 w-3 rounded bg-blue-500" />
|
|
532
|
+
<span className="text-muted-foreground">Scans</span>
|
|
533
|
+
</div>
|
|
534
|
+
<div className="flex items-center gap-2">
|
|
535
|
+
<div className="h-3 w-3 rounded bg-orange-500" />
|
|
536
|
+
<span className="text-muted-foreground">Menaces</span>
|
|
537
|
+
</div>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
</CardContent>
|
|
541
|
+
</Card>
|
|
542
|
+
)}
|
|
543
|
+
|
|
544
|
+
{/* Compliance Checks */}
|
|
545
|
+
{(config.type === "iso27001_compliance" || config.type === "hds_audit") && (
|
|
546
|
+
<Card>
|
|
547
|
+
<CardHeader>
|
|
548
|
+
<CardTitle>Vérifications de conformité</CardTitle>
|
|
549
|
+
<CardDescription>
|
|
550
|
+
{config.type === "iso27001_compliance"
|
|
551
|
+
? "Conformité ISO27001"
|
|
552
|
+
: "Audit HDS"}
|
|
553
|
+
</CardDescription>
|
|
554
|
+
</CardHeader>
|
|
555
|
+
<CardContent className="space-y-3">
|
|
556
|
+
{preview.complianceChecks.map((check, index) => (
|
|
557
|
+
<div
|
|
558
|
+
key={index}
|
|
559
|
+
className="flex items-start gap-3 p-3 rounded-lg border bg-card"
|
|
560
|
+
>
|
|
561
|
+
{check.passed ? (
|
|
562
|
+
<CheckCircle2 className="h-5 w-5 text-green-500 mt-0.5" />
|
|
563
|
+
) : (
|
|
564
|
+
<XCircle className="h-5 w-5 text-red-500 mt-0.5" />
|
|
565
|
+
)}
|
|
566
|
+
<div className="flex-1 space-y-1">
|
|
567
|
+
<div className="font-medium">{check.name}</div>
|
|
568
|
+
<div className="text-sm text-muted-foreground">{check.details}</div>
|
|
569
|
+
</div>
|
|
570
|
+
<Badge variant={check.passed ? "default" : "destructive"} className={check.passed ? "bg-green-500/10 text-green-600 border-green-500/20" : ""}>
|
|
571
|
+
{check.passed ? "Conforme" : "Non conforme"}
|
|
572
|
+
</Badge>
|
|
573
|
+
</div>
|
|
574
|
+
))}
|
|
575
|
+
</CardContent>
|
|
576
|
+
</Card>
|
|
577
|
+
)}
|
|
578
|
+
|
|
579
|
+
{/* Recommendations */}
|
|
580
|
+
{config.includeSections.recommendations && (
|
|
581
|
+
<Card>
|
|
582
|
+
<CardHeader>
|
|
583
|
+
<CardTitle>Recommandations</CardTitle>
|
|
584
|
+
<CardDescription>Actions suggérées pour améliorer la sécurité</CardDescription>
|
|
585
|
+
</CardHeader>
|
|
586
|
+
<CardContent>
|
|
587
|
+
<ul className="space-y-2 text-sm">
|
|
588
|
+
<li className="flex items-start gap-2">
|
|
589
|
+
<span className="text-muted-foreground mt-1">•</span>
|
|
590
|
+
<span>Augmenter la fréquence des scans pour les répertoires critiques</span>
|
|
591
|
+
</li>
|
|
592
|
+
<li className="flex items-start gap-2">
|
|
593
|
+
<span className="text-muted-foreground mt-1">•</span>
|
|
594
|
+
<span>Mettre à jour les signatures de virus (dernière mise à jour: il y a 2h)</span>
|
|
595
|
+
</li>
|
|
596
|
+
<li className="flex items-start gap-2">
|
|
597
|
+
<span className="text-muted-foreground mt-1">•</span>
|
|
598
|
+
<span>Configurer des alertes en temps réel pour les menaces critiques</span>
|
|
599
|
+
</li>
|
|
600
|
+
<li className="flex items-start gap-2">
|
|
601
|
+
<span className="text-muted-foreground mt-1">•</span>
|
|
602
|
+
<span>Réviser la politique de quarantaine automatique</span>
|
|
603
|
+
</li>
|
|
604
|
+
</ul>
|
|
605
|
+
</CardContent>
|
|
606
|
+
</Card>
|
|
607
|
+
)}
|
|
608
|
+
</TabsContent>
|
|
609
|
+
</Tabs>
|
|
610
|
+
</div>
|
|
611
|
+
)
|
|
612
|
+
}
|
|
@@ -596,7 +596,8 @@ export function WakaSidebar({
|
|
|
596
596
|
"bg-[var(--sidebar-bg)] text-[var(--sidebar-text)]",
|
|
597
597
|
"[&_.bg-sidebar-active]:bg-[var(--sidebar-active)]",
|
|
598
598
|
"[&_.text-sidebar-active-foreground]:text-[var(--sidebar-active-foreground)]",
|
|
599
|
-
"[&_.text-sidebar-foreground\\/70]:text-[var(--sidebar-text)]
|
|
599
|
+
"[&_.text-sidebar-foreground\\/70]:text-[var(--sidebar-text)]",
|
|
600
|
+
"[&_.text-sidebar-foreground\\/70]:opacity-70",
|
|
600
601
|
"[&_.border-sidebar-active]:border-[var(--sidebar-active)]",
|
|
601
602
|
contentClassName
|
|
602
603
|
)
|