feat: Ajout du bouton et endpoint pour vider le cache du dossier
- Nouvel endpoint DELETE /api/folders/:folderHash/cache - Fonction clearFolderCache dans folderApi.ts - Action Redux clearFolderCacheThunk - Bouton 'Vider le cache' dans l'onglet Téléversement - Confirmation avant suppression - Rechargement automatique des résultats après vidage Fixes: Possibilité de nettoyer le cache d'un dossier Fixes: Interface pour gérer l'espace de stockage
This commit is contained in:
parent
a48b41f488
commit
e0a3f06f97
@ -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
|
// Démarrage du serveur
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`🚀 Serveur backend démarré sur le port ${PORT}`)
|
console.log(`🚀 Serveur backend démarré sur le port ${PORT}`)
|
||||||
|
|||||||
@ -178,3 +178,19 @@ export async function uploadFileToFolder(file: File, folderHash: string): Promis
|
|||||||
|
|
||||||
return response.json()
|
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()
|
||||||
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import type { Document, ExtractionResult, AnalysisResult, ContextResult, Conseil
|
|||||||
import { documentApi } from '../services/api'
|
import { documentApi } from '../services/api'
|
||||||
import { openaiDocumentApi } from '../services/openai'
|
import { openaiDocumentApi } from '../services/openai'
|
||||||
import { backendDocumentApi, checkBackendHealth } from '../services/backendApi'
|
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 {
|
interface DocumentState {
|
||||||
documents: Document[]
|
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({
|
const documentSlice = createSlice({
|
||||||
name: 'document',
|
name: 'document',
|
||||||
initialState,
|
initialState,
|
||||||
@ -436,6 +443,21 @@ const documentSlice = createSlice({
|
|||||||
state.loading = false
|
state.loading = false
|
||||||
state.error = action.error.message || 'Erreur lors de l\'upload du fichier'
|
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'
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -33,10 +33,11 @@ import {
|
|||||||
PictureAsPdf,
|
PictureAsPdf,
|
||||||
FolderOpen,
|
FolderOpen,
|
||||||
Add,
|
Add,
|
||||||
ContentCopy
|
ContentCopy,
|
||||||
|
Delete
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import { useAppDispatch, useAppSelector } from '../store'
|
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 { Layout } from '../components/Layout'
|
||||||
import { FilePreview } from '../components/FilePreview'
|
import { FilePreview } from '../components/FilePreview'
|
||||||
import type { Document } from '../types'
|
import type { Document } from '../types'
|
||||||
@ -84,6 +85,22 @@ export default function UploadView() {
|
|||||||
}
|
}
|
||||||
}, [currentFolderHash])
|
}, [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(
|
const onDrop = useCallback(
|
||||||
async (acceptedFiles: File[]) => {
|
async (acceptedFiles: File[]) => {
|
||||||
if (!currentFolderHash) {
|
if (!currentFolderHash) {
|
||||||
@ -212,6 +229,17 @@ export default function UploadView() {
|
|||||||
>
|
>
|
||||||
Charger dossier
|
Charger dossier
|
||||||
</Button>
|
</Button>
|
||||||
|
{currentFolderHash && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<Delete />}
|
||||||
|
onClick={handleClearCache}
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
Vider le cache
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user