diff --git a/.replit b/.replit index baa3edd..2e1a3ae 100644 --- a/.replit +++ b/.replit @@ -37,4 +37,4 @@ args = "npm run dev" waitForPort = 5000 [agent] -integrations = ["javascript_object_storage==1.0.0", "javascript_log_in_with_replit==1.0.0", "javascript_database==1.0.0"] +integrations = ["javascript_object_storage==1.0.0", "javascript_database==1.0.0", "javascript_log_in_with_replit==1.0.0"] diff --git a/attached_assets/{E841CD9A-C6E4-4C7A-A17D-CA1CF9DBA375}_1756904852244.png b/attached_assets/{E841CD9A-C6E4-4C7A-A17D-CA1CF9DBA375}_1756904852244.png new file mode 100644 index 0000000..501edd4 Binary files /dev/null and b/attached_assets/{E841CD9A-C6E4-4C7A-A17D-CA1CF9DBA375}_1756904852244.png differ diff --git a/client/src/pages/Utilities.tsx b/client/src/pages/Utilities.tsx index f46a5c6..d2c0a62 100644 --- a/client/src/pages/Utilities.tsx +++ b/client/src/pages/Utilities.tsx @@ -6,7 +6,8 @@ import { Database, Server, Bug, - Cloud + Cloud, + Send } from "lucide-react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; @@ -17,6 +18,7 @@ import BackupManager from "./BackupManager"; import NocoDBConfig from "./NocoDBConfig"; import DatabaseDebug from "./DatabaseDebug"; import WeatherSettings from "./WeatherSettings"; +import WebhookBAPConfig from "./WebhookBAPConfig"; export default function Utilities() { const { user } = useAuthUnified(); @@ -35,9 +37,10 @@ export default function Utilities() { const canManageNocoDB = user?.role === 'admin'; const canDebugDatabase = user?.role === 'admin'; const canManageWeather = user?.role === 'admin'; + const canManageWebhookBAP = user?.role === 'admin'; // Si l'utilisateur n'a aucune permission, afficher le message d'accès refusé - if (!canManageBackups && !canManageNocoDB && !canDebugDatabase && !canManageWeather) { + if (!canManageBackups && !canManageNocoDB && !canDebugDatabase && !canManageWeather && !canManageWebhookBAP) { return (
@@ -73,7 +76,7 @@ export default function Utilities() { {/* Content avec onglets */}
- + {canManageBackups && ( @@ -98,6 +101,12 @@ export default function Utilities() { Météo )} + {canManageWebhookBAP && ( + + + Configuration BAP + + )} {/* Contenu des onglets */} @@ -132,6 +141,14 @@ export default function Utilities() {
)} + + {canManageWebhookBAP && ( + +
+ +
+
+ )}
diff --git a/client/src/pages/WebhookBAPConfig.tsx b/client/src/pages/WebhookBAPConfig.tsx new file mode 100644 index 0000000..e58ca96 --- /dev/null +++ b/client/src/pages/WebhookBAPConfig.tsx @@ -0,0 +1,289 @@ +import { useState, useEffect } from "react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Switch } from "@/components/ui/switch"; +import { Textarea } from "@/components/ui/textarea"; +import { useToast } from "@/hooks/use-toast"; +import { Send, Globe, AlertCircle, CheckCircle2, Copy } from "lucide-react"; +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { apiRequest } from "@/lib/queryClient"; + +interface WebhookBapConfig { + id: number; + name: string; + webhookUrl: string; + description: string | null; + isActive: boolean; + createdAt: string; + updatedAt: string; +} + +export default function WebhookBAPConfig() { + const { toast } = useToast(); + const queryClient = useQueryClient(); + const [formData, setFormData] = useState({ + name: "Configuration BAP", + webhookUrl: "", + description: "", + isActive: true + }); + + const { data: config, isLoading } = useQuery({ + queryKey: ['/api/webhook-bap-config'], + }); + + const testMutation = useMutation({ + mutationFn: async () => { + if (!formData.webhookUrl) { + throw new Error("URL webhook requise pour le test"); + } + + const response = await fetch('/api/webhook-bap-config/test', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ webhookUrl: formData.webhookUrl }), + credentials: 'include' + }); + + if (!response.ok) { + const error = await response.json(); + throw new Error(error.error || 'Erreur lors du test'); + } + + return response.json(); + }, + onSuccess: () => { + toast({ + title: "Test réussi", + description: "Le webhook BAP répond correctement", + }); + }, + onError: (error: any) => { + toast({ + title: "Échec du test", + description: error.message, + variant: "destructive", + }); + }, + }); + + const saveMutation = useMutation({ + mutationFn: async (data: typeof formData) => { + return apiRequest('/api/webhook-bap-config', 'POST', data); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['/api/webhook-bap-config'] }); + toast({ + title: "Configuration sauvegardée", + description: "La configuration du webhook BAP a été mise à jour", + }); + }, + onError: (error: any) => { + toast({ + title: "Erreur de sauvegarde", + description: error.message, + variant: "destructive", + }); + }, + }); + + useEffect(() => { + if (config) { + // Gérer à la fois les cas où l'API retourne un objet ou un array + const configData = Array.isArray(config) && config.length > 0 ? config[0] : config; + if (configData && typeof configData === 'object') { + setFormData({ + name: configData.name || "Configuration BAP", + webhookUrl: configData.webhookUrl || "", + description: configData.description || "", + isActive: configData.isActive ?? true + }); + } + } + }, [config]); + + const handleSave = () => { + if (!formData.webhookUrl.trim()) { + toast({ + title: "Erreur", + description: "L'URL du webhook est requise", + variant: "destructive", + }); + return; + } + + if (!formData.webhookUrl.startsWith('http')) { + toast({ + title: "Erreur", + description: "L'URL doit commencer par http:// ou https://", + variant: "destructive", + }); + return; + } + + saveMutation.mutate(formData); + }; + + const handleTest = () => { + if (!formData.webhookUrl.trim()) { + toast({ + title: "Erreur", + description: "L'URL du webhook est requise pour effectuer le test", + variant: "destructive", + }); + return; + } + testMutation.mutate(); + }; + + const copyUrl = () => { + navigator.clipboard.writeText(formData.webhookUrl); + toast({ + title: "URL copiée", + description: "L'URL a été copiée dans le presse-papiers", + }); + }; + + if (isLoading) { + return ( +
+
Chargement de la configuration...
+
+ ); + } + + return ( +
+ + + + + Configuration Webhook BAP + + + Configurez l'URL du webhook n8n pour l'envoi des fichiers BAP vers Prissela et Célia + + + +
+ + setFormData({ ...formData, name: e.target.value })} + placeholder="Configuration BAP" + /> +
+ +
+ +
+ setFormData({ ...formData, webhookUrl: e.target.value })} + placeholder="https://workflow.ffnancy.fr/webhook/..." + className="flex-1" + /> + +
+

+ URL complète du webhook n8n qui recevra les fichiers PDF BAP +

+
+ +
+ +