import { useEffect, useRef, useState } from 'react'; import SwaggerUI from 'swagger-ui-react'; import 'swagger-ui-react/swagger-ui.css'; import { env } from '@/config/env'; import { logger } from '@/utils/logger'; import { AlertCircle, RefreshCw } from 'lucide-react'; import { Button } from '@/components/ui/button'; interface SwaggerUIProps { specUrl?: string; spec?: object; } /** * Composant Swagger UI pour afficher la documentation API * Charge le fichier OpenAPI depuis le backend ou utilise un spec fourni */ export function SwaggerUIDoc({ specUrl, spec }: SwaggerUIProps) { const containerRef = useRef(null); const [error, setError] = useState(null); // Construire l'URL du fichier OpenAPI/Swagger avec fallback const getOpenApiUrl = () => { if (specUrl) return specUrl; // Si API_URL est relatif, construire l'URL complète const apiBase = env.API_URL.startsWith('http') ? env.API_URL : `${window.location.origin}${env.API_URL}`; const baseUrl = apiBase.replace(/\/api\/v1$/, ''); // gin-swagger peut servir le JSON à différents endroits // Essayer /swagger/doc.json (endpoint standard gin-swagger) // Si ça ne fonctionne pas, l'utilisateur peut utiliser le bouton "Open in New Tab" pour accéder à /swagger/index.html return `${baseUrl}/swagger/doc.json`; }; // Fallback: charger le fichier openapi.yaml depuis le repo si l'endpoint ne fonctionne pas const loadOpenApiFromFile = async () => { try { // Essayer de charger depuis le backend const response = await fetch('/api/v1/../openapi.yaml'); if (response.ok) { const yamlText = await response.text(); // Parser YAML basique (ou utiliser une librairie) // Pour l'instant, retourner null et laisser SwaggerUI gérer l'erreur return null; } } catch (e) { // Ignorer les erreurs } return null; }; useEffect(() => { if (containerRef.current) { logger.debug('Swagger UI initialized', { specUrl: specUrl || getOpenApiUrl(), hasSpec: !!spec, }); } }, [specUrl, spec]); const swaggerConfig = { url: spec ? undefined : getOpenApiUrl(), spec: spec, deepLinking: true, displayOperationId: false, defaultModelsExpandDepth: 1, defaultModelExpandDepth: 1, docExpansion: 'list' as const, filter: true, showExtensions: true, showCommonExtensions: true, tryItOutEnabled: true, supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'] as ('get' | 'post' | 'put' | 'delete' | 'patch')[], requestInterceptor: (request: any) => { // Ajouter le token d'authentification si disponible const token = localStorage.getItem('access_token'); if (token && request.headers) { request.headers['Authorization'] = `Bearer ${token}`; } // Ajouter le CSRF token si disponible const csrfToken = localStorage.getItem('csrf_token'); if (csrfToken && request.headers) { request.headers['X-CSRF-Token'] = csrfToken; } return request; }, onComplete: () => { setError(null); logger.debug('Swagger UI loaded successfully', { url: getOpenApiUrl(), }); }, onFailure: (err: Error) => { setError(err.message || 'Failed to load Swagger documentation'); logger.error('Failed to load Swagger UI', { error: err.message, stack: err.stack, url: getOpenApiUrl(), }); }, }; const handleRetry = () => { setError(null); // Force reload by updating the key window.location.reload(); }; if (error) { const swaggerUiUrl = getOpenApiUrl().replace('/swagger/doc.json', '/swagger/index.html'); return (

Failed to Load API Documentation

{error}

Trying to load from: {getOpenApiUrl()}
The Swagger JSON endpoint may not be available. Try opening Swagger UI directly.

); } return (
); }