diff --git a/backend/server.js b/backend/server.js index a7c96ad..4be8e39 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1404,6 +1404,86 @@ app.get('/api/health', (req, res) => { }) }) +// Vider le cache d'un dossier +app.delete('/api/folders/:folderHash/cache', (req, res) => { + const { folderHash } = req.params + + console.log(`[CACHE] Demande de suppression du cache pour le dossier: ${folderHash}`) + + try { + const { cachePath, uploadsPath } = createFolderStructure(folderHash) + + let deletedFiles = 0 + let deletedDirs = 0 + + // Supprimer le dossier cache s'il existe + if (fs.existsSync(cachePath)) { + const files = fs.readdirSync(cachePath) + for (const file of files) { + const filePath = path.join(cachePath, file) + try { + fs.unlinkSync(filePath) + deletedFiles++ + console.log(`[CACHE] Fichier supprimé: ${file}`) + } catch (error) { + console.error(`[CACHE] Erreur lors de la suppression de ${file}:`, error.message) + } + } + + // Supprimer le dossier cache vide + try { + fs.rmdirSync(cachePath) + deletedDirs++ + console.log(`[CACHE] Dossier cache supprimé: ${cachePath}`) + } catch (error) { + console.error(`[CACHE] Erreur lors de la suppression du dossier cache:`, error.message) + } + } + + // Supprimer le dossier uploads s'il existe + if (fs.existsSync(uploadsPath)) { + const files = fs.readdirSync(uploadsPath) + for (const file of files) { + const filePath = path.join(uploadsPath, file) + try { + fs.unlinkSync(filePath) + deletedFiles++ + console.log(`[CACHE] Fichier upload supprimé: ${file}`) + } catch (error) { + console.error(`[CACHE] Erreur lors de la suppression de ${file}:`, error.message) + } + } + + // Supprimer le dossier uploads vide + try { + fs.rmdirSync(uploadsPath) + deletedDirs++ + console.log(`[CACHE] Dossier uploads supprimé: ${uploadsPath}`) + } catch (error) { + console.error(`[CACHE] Erreur lors de la suppression du dossier uploads:`, error.message) + } + } + + console.log(`[CACHE] Cache vidé pour le dossier ${folderHash}: ${deletedFiles} fichiers, ${deletedDirs} dossiers supprimés`) + + res.json({ + success: true, + message: `Cache vidé pour le dossier ${folderHash}`, + deletedFiles, + deletedDirs, + folderHash + }) + + } catch (error) { + console.error(`[CACHE] Erreur lors du vidage du cache:`, error) + res.status(500).json({ + success: false, + error: 'Erreur lors du vidage du cache', + details: error.message + }) + } +}) + // Démarrage du serveur app.listen(PORT, () => { console.log(`🚀 Serveur backend démarré sur le port ${PORT}`) diff --git a/src/services/folderApi.ts b/src/services/folderApi.ts index 32ac601..8ca7aa4 100644 --- a/src/services/folderApi.ts +++ b/src/services/folderApi.ts @@ -166,15 +166,31 @@ export async function uploadFileToFolder(file: File, folderHash: string): Promis const formData = new FormData() formData.append('document', file) formData.append('folderHash', folderHash) - + const response = await fetch(`${API_BASE_URL}/extract`, { method: 'POST', body: formData, }) - + if (!response.ok) { throw new Error(`Erreur lors de l'upload: ${response.statusText}`) } - + + return response.json() +} + +// Vider le cache d'un dossier +export async function clearFolderCache(folderHash: string): Promise<{ success: boolean; message: string; deletedFiles: number; deletedDirs: number }> { + const response = await fetch(`${API_BASE_URL}/folders/${folderHash}/cache`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }) + + if (!response.ok) { + throw new Error(`Erreur lors du vidage du cache: ${response.statusText}`) + } + return response.json() } diff --git a/src/store/documentSlice.ts b/src/store/documentSlice.ts index dacee06..7d864b2 100644 --- a/src/store/documentSlice.ts +++ b/src/store/documentSlice.ts @@ -4,7 +4,7 @@ import type { Document, ExtractionResult, AnalysisResult, ContextResult, Conseil import { documentApi } from '../services/api' import { openaiDocumentApi } from '../services/openai' import { backendDocumentApi, checkBackendHealth } from '../services/backendApi' -import { createDefaultFolder, getDefaultFolder, getFolderResults, uploadFileToFolder, type FolderResult } from '../services/folderApi' +import { createDefaultFolder, getDefaultFolder, getFolderResults, uploadFileToFolder, clearFolderCache, type FolderResult } from '../services/folderApi' interface DocumentState { documents: Document[] @@ -214,6 +214,13 @@ export const uploadFileToFolderThunk = createAsyncThunk( } ) +export const clearFolderCacheThunk = createAsyncThunk( + 'document/clearFolderCache', + async (folderHash: string) => { + return await clearFolderCache(folderHash) + } +) + const documentSlice = createSlice({ name: 'document', initialState, @@ -436,6 +443,21 @@ const documentSlice = createSlice({ state.loading = false state.error = action.error.message || 'Erreur lors de l\'upload du fichier' }) + .addCase(clearFolderCacheThunk.fulfilled, (state, action) => { + console.log(`[STORE] Cache vidé: ${action.payload.deletedFiles} fichiers, ${action.payload.deletedDirs} dossiers supprimés`) + // Vider les résultats du dossier actuel + state.folderResults = [] + state.documents = [] + state.currentResultIndex = 0 + state.loading = false + }) + .addCase(clearFolderCacheThunk.pending, (state) => { + state.loading = true + }) + .addCase(clearFolderCacheThunk.rejected, (state, action) => { + state.loading = false + state.error = action.error.message || 'Erreur lors du vidage du cache' + }) }, }) diff --git a/src/views/UploadView.tsx b/src/views/UploadView.tsx index 9603267..42df05c 100644 --- a/src/views/UploadView.tsx +++ b/src/views/UploadView.tsx @@ -33,10 +33,11 @@ import { PictureAsPdf, FolderOpen, Add, - ContentCopy + ContentCopy, + Delete } from '@mui/icons-material' import { useAppDispatch, useAppSelector } from '../store' -import { uploadFileToFolderThunk, loadFolderResults, removeDocument, createDefaultFolderThunk, setCurrentFolderHash } from '../store/documentSlice' +import { uploadFileToFolderThunk, loadFolderResults, removeDocument, createDefaultFolderThunk, setCurrentFolderHash, clearFolderCacheThunk } from '../store/documentSlice' import { Layout } from '../components/Layout' import { FilePreview } from '../components/FilePreview' import type { Document } from '../types' @@ -84,6 +85,22 @@ export default function UploadView() { } }, [currentFolderHash]) + // Fonction pour vider le cache du dossier + const handleClearCache = useCallback(async () => { + if (!currentFolderHash) return + + if (window.confirm('Êtes-vous sûr de vouloir vider le cache de ce dossier ? Cette action supprimera tous les fichiers et résultats d\'extraction.')) { + try { + const result = await dispatch(clearFolderCacheThunk(currentFolderHash)).unwrap() + console.log('✅ [UPLOAD] Cache vidé:', result) + // Recharger les résultats du dossier (qui seront vides) + await dispatch(loadFolderResults(currentFolderHash)).unwrap() + } catch (error) { + console.error('❌ [UPLOAD] Erreur lors du vidage du cache:', error) + } + } + }, [dispatch, currentFolderHash]) + const onDrop = useCallback( async (acceptedFiles: File[]) => { if (!currentFolderHash) { @@ -212,6 +229,17 @@ export default function UploadView() { > Charger dossier + {currentFolderHash && ( + + )}