feat: purge import history by retention

This commit is contained in:
Manus
2026-10-09 10:22:46 +00:00
parent 6d72547509
commit 16759b4ad5
6 changed files with 176 additions and 20 deletions

View File

@@ -167,6 +167,12 @@ export default function History() {
const [selectedLog, setSelectedLog] = useState<DetailedImportLog | null>(null);
const [selectedAccountId, setSelectedAccountId] = useState("none");
const [confirmManualCheckOpen, setConfirmManualCheckOpen] = useState(false);
const [retentionMonths, setRetentionMonths] = useState<3 | 6 | 12>(6);
const { data: retentionPreview, isLoading: retentionPreviewLoading } = trpc.importLogs.retentionPreview.useQuery(
{ months: retentionMonths },
{ enabled: isAdmin },
);
const retentionPurgeMutation = trpc.importLogs.purgeBeforeRetention.useMutation();
const selectedAccount = useMemo(
() => configuredAccounts.find((account) => String(account.userId) === selectedAccountId),
@@ -183,6 +189,22 @@ export default function History() {
}
};
const handleRetentionPurge = async () => {
try {
const result = await retentionPurgeMutation.mutateAsync({ months: retentionMonths });
setPage(0);
await Promise.all([
utils.importLogs.getByUser.invalidate(),
utils.importLogs.retentionPreview.invalidate(),
]);
toast.success("Purge de l’historique terminée", {
description: `${result.deletedCount.toLocaleString("fr-FR")} journal${result.deletedCount > 1 ? "x" : ""} antérieur${result.deletedCount > 1 ? "s" : ""} à ${result.months} mois supprimé${result.deletedCount > 1 ? "s" : ""}.`,
});
} catch (error: any) {
toast.error(error?.message || "Impossible de purger l’historique des imports.");
}
};
const handleManualEmailCheck = async () => {
if (!selectedAccount) return;
try {
@@ -244,25 +266,59 @@ export default function History() {
<h1 className="text-3xl font-bold">Historique des imports</h1>
<p className="mt-1 text-gray-500">Suivez la date, la source, le compte et le mode de déclenchement de chaque ajout.</p>
</div>
{detailedLogs.length > 0 && (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive" size="sm"><Trash2 className="mr-2 h-4 w-4" />Effacer l’historique</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Supprimer l’historique ?</AlertDialogTitle>
<AlertDialogDescription>Cette action est irréversible et supprime les enregistrements accessibles avec votre rôle.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Annuler</AlertDialogCancel>
<AlertDialogAction onClick={handleDeleteAll} disabled={deleteAllMutation.isPending} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
{deleteAllMutation.isPending ? "Suppression…" : "Supprimer"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)}
<div className="flex flex-wrap items-center gap-2">
{isAdmin && (
<>
<Select value={String(retentionMonths)} onValueChange={(value) => setRetentionMonths(Number(value) as 3 | 6 | 12)}>
<SelectTrigger className="h-9 w-40 text-sm"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="3">Conserver 3 mois</SelectItem>
<SelectItem value="6">Conserver 6 mois</SelectItem>
<SelectItem value="12">Conserver 1 an</SelectItem>
</SelectContent>
</Select>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="outline" size="sm" className="border-orange-300 bg-orange-50 text-orange-800 hover:bg-orange-100"><Trash2 className="mr-2 h-4 w-4" />Purger l’historique</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Purger les journaux anciens ?</AlertDialogTitle>
<AlertDialogDescription>
{retentionPreviewLoading ? "Calcul du volume à purger…" : `${(retentionPreview?.count ?? 0).toLocaleString("fr-FR")} journal${(retentionPreview?.count ?? 0) > 1 ? "x" : ""} antérieur${(retentionPreview?.count ?? 0) > 1 ? "s" : ""} à ${retentionMonths} mois seront supprimés.`}
{" Les factures, fichiers source et PDF ne seront pas supprimés."}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Annuler</AlertDialogCancel>
<AlertDialogAction onClick={handleRetentionPurge} disabled={retentionPreviewLoading || retentionPurgeMutation.isPending} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
{retentionPurgeMutation.isPending ? "Purge…" : "Confirmer la purge"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
)}
{detailedLogs.length > 0 && (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive" size="sm"><Trash2 className="mr-2 h-4 w-4" />Effacer l’historique</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Supprimer l’historique ?</AlertDialogTitle>
<AlertDialogDescription>Cette action est irréversible et supprime les enregistrements accessibles avec votre rôle.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Annuler</AlertDialogCancel>
<AlertDialogAction onClick={handleDeleteAll} disabled={deleteAllMutation.isPending} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
{deleteAllMutation.isPending ? "Suppression…" : "Supprimer"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)}
</div>
</div>
{isAdmin && (