From a1f32acaa1d71e1cded516c0cca5c05c3d8b773c Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Fri, 3 Jul 2026 17:03:14 +0200 Subject: [PATCH] =?UTF-8?q?cleanup:=20s=C3=A9lection=20multiple=20+=20page?= =?UTF-8?q?=20d=C3=A9di=C3=A9e=20(/admin/cleanup.php)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cleanup-tmp.php: accepte les arrays filepond_dirs[] et trash_files[] pour suppression en lot - cleanup-stats-fragment.php: ajout checkboxes + barre d'actions groupées + formulaire bulk HTMX - admin-cleanup-bulk.js: module JS pour toggleAll, updateBulk, bulkDelete - Nouvelle page /admin/cleanup.php remplace la modale (tmp-cleanup.php supprimé) - Bouton Nettoyer dans index.php devient un lien vers la page dédiée --- TODO.md | 2 + .../admin/actions/cleanup-stats-fragment.php | 29 +++++++- app/public/admin/actions/cleanup-tmp.php | 36 ++++++---- app/public/admin/cleanup.php | 20 ++++++ .../assets/js/app/admin-cleanup-bulk.js | 71 +++++++++++++++++++ app/public/assets/js/app/admin-entry.js | 1 + app/templates/admin/cleanup.php | 38 ++++++++++ app/templates/admin/index.php | 7 +- .../admin/partials/dialogs/tmp-cleanup.php | 34 --------- 9 files changed, 183 insertions(+), 55 deletions(-) create mode 100644 app/public/admin/cleanup.php create mode 100644 app/public/assets/js/app/admin-cleanup-bulk.js create mode 100644 app/templates/admin/cleanup.php delete mode 100644 app/templates/admin/partials/dialogs/tmp-cleanup.php diff --git a/TODO.md b/TODO.md index 8d39800..34371d1 100644 --- a/TODO.md +++ b/TODO.md @@ -15,3 +15,5 @@ - [x] Responsive paginator: hide first/last buttons on mobile, smaller touch targets - [x] Compact range counter on mobile: "1–15 / 112" instead of full "1–15 sur 112 résultats" - [x] Remove orientation display from search result card meta +- [x] Add bulk select/delete to tmp cleanup dialog (like admin/index.php pattern) +- [x] Move cleanup UI from modal to dedicated page (like add.php/edit.php) diff --git a/app/public/admin/actions/cleanup-stats-fragment.php b/app/public/admin/actions/cleanup-stats-fragment.php index 0484506..eeedad7 100644 --- a/app/public/admin/actions/cleanup-stats-fragment.php +++ b/app/public/admin/actions/cleanup-stats-fragment.php @@ -41,7 +41,7 @@ elseif ($staleSize > 0) { $staleHuman = $staleSize . ' B'; } $summaryMeta = $staleMeta; if ($staleHuman) $summaryMeta .= ' · ' . $staleHuman; -if ($totalStale === 0 && $totalFiles === 0): ?> +
@@ -54,6 +54,27 @@ if ($totalStale === 0 && $totalFiles === 0): ?>
+ + + + + +
@@ -62,10 +83,11 @@ if ($totalStale === 0 && $totalFiles === 0): ?> 0): ?> - + + @@ -93,10 +115,11 @@ if ($totalStale === 0 && $totalFiles === 0): ?> Corbeille

NomTailleÂge
NomTailleÂge
~ min
- + + diff --git a/app/public/admin/actions/cleanup-tmp.php b/app/public/admin/actions/cleanup-tmp.php index eaae11d..a07611d 100644 --- a/app/public/admin/actions/cleanup-tmp.php +++ b/app/public/admin/actions/cleanup-tmp.php @@ -43,32 +43,42 @@ $details = []; $db = new Database(); $pdo = $db->getPDO(); -// ── Individual deletion mode ──────────────────────────────────────────── +// ── Individual / bulk deletion mode ──────────────────────────────────── $individualFilepond = trim($_POST['filepond_dir'] ?? ''); $individualTrash = trim($_POST['trash_file'] ?? ''); +$bulkFilepond = $_POST['filepond_dirs'] ?? []; +$bulkTrash = $_POST['trash_files'] ?? []; -if ($individualFilepond !== '' || $individualTrash !== '') { - if ($individualFilepond !== '') { - $dirPath = $filepondDir . '/' . basename($individualFilepond); +// Normalize: single values also become arrays for unified handling +$filepondItems = $individualFilepond !== '' ? [$individualFilepond] : (is_array($bulkFilepond) ? $bulkFilepond : []); +$trashItems = $individualTrash !== '' ? [$individualTrash] : (is_array($bulkTrash) ? $bulkTrash : []); + +if (!empty($filepondItems) || !empty($trashItems)) { + foreach ($filepondItems as $item) { + $item = trim($item); + if ($item === '') continue; + $dirPath = $filepondDir . '/' . basename($item); if (is_dir($dirPath) && str_starts_with(realpath($dirPath), realpath($filepondDir))) { rmdirRecursive($dirPath); - $filepondRemoved = 1; - $details[] = "filepond/$individualFilepond: suppression manuelle"; + $filepondRemoved++; + $details[] = "filepond/$item: suppression manuelle"; } else { - $errors[] = 'Dossier introuvable : ' . htmlspecialchars($individualFilepond); + $errors[] = 'Dossier introuvable : ' . htmlspecialchars($item); } } - if ($individualTrash !== '') { - $filePath = $trashDir . '/' . basename($individualTrash); + foreach ($trashItems as $item) { + $item = trim($item); + if ($item === '') continue; + $filePath = $trashDir . '/' . basename($item); if (is_file($filePath) && str_starts_with(realpath($filePath), realpath($trashDir))) { if (@unlink($filePath)) { - $trashRemoved = 1; - $details[] = "_trash/$individualTrash: suppression manuelle"; + $trashRemoved++; + $details[] = "_trash/$item: suppression manuelle"; } else { - $errors[] = 'Impossible de supprimer : ' . htmlspecialchars($individualTrash); + $errors[] = 'Impossible de supprimer : ' . htmlspecialchars($item); } } else { - $errors[] = 'Fichier introuvable : ' . htmlspecialchars($individualTrash); + $errors[] = 'Fichier introuvable : ' . htmlspecialchars($item); } } diff --git a/app/public/admin/cleanup.php b/app/public/admin/cleanup.php new file mode 100644 index 0000000..01a2e05 --- /dev/null +++ b/app/public/admin/cleanup.php @@ -0,0 +1,20 @@ + { + function cleanupToggleAll(src, group) { + const selector = group === 'filepond' + ? 'input[name="filepond_dirs[]"]' + : 'input[name="trash_files[]"]'; + document.querySelectorAll(selector).forEach((cb) => { + cb.checked = src.checked; + }); + cleanupUpdateBulk(); + } + + function cleanupUpdateBulk() { + const bar = document.getElementById('cleanup-bulk-actions'); + const countEl = document.getElementById('cleanup-selected-count'); + if (!bar || !countEl) return; + + const n = document.querySelectorAll( + 'input[name="filepond_dirs[]"]:checked, input[name="trash_files[]"]:checked' + ).length; + countEl.textContent = n; + bar.style.display = n > 0 ? 'flex' : 'none'; + } + + function cleanupBulkDelete() { + const form = document.getElementById('cleanup-bulk-form'); + const container = document.getElementById('cleanup-bulk-checkboxes'); + if (!form || !container) return; + + // Populate hidden inputs from checked checkboxes + container.innerHTML = ''; + document.querySelectorAll( + 'input[name="filepond_dirs[]"]:checked, input[name="trash_files[]"]:checked' + ).forEach((cb) => { + const inp = document.createElement('input'); + inp.type = 'hidden'; + inp.name = cb.name; // "filepond_dirs[]" or "trash_files[]" + inp.value = cb.value; + container.appendChild(inp); + }); + + // Submit via HTMX + htmx.trigger(form, 'submit'); + } + + function reattachListeners() { + document.querySelectorAll( + 'input[name="filepond_dirs[]"], input[name="trash_files[]"]' + ).forEach((cb) => { + cb.addEventListener('change', cleanupUpdateBulk); + }); + cleanupUpdateBulk(); + } + + document.addEventListener('htmx:afterSwap', (evt) => { + // Only reattach if the swap target is our cleanup wrapper + if (evt.detail.target.id === 'tmp-cleanup-stats-wrapper') { + reattachListeners(); + } + }); + + // Export to global scope for onclick handlers in HTML + window.cleanupToggleAll = cleanupToggleAll; + window.cleanupUpdateBulk = cleanupUpdateBulk; + window.cleanupBulkDelete = cleanupBulkDelete; +})(); diff --git a/app/public/assets/js/app/admin-entry.js b/app/public/assets/js/app/admin-entry.js index ccadb85..6519409 100644 --- a/app/public/assets/js/app/admin-entry.js +++ b/app/public/assets/js/app/admin-entry.js @@ -16,6 +16,7 @@ import "./htmx-global-setup.js"; // Admin features import "./admin-index-bulk.js"; +import "./admin-cleanup-bulk.js"; import "./admin-tags.js"; import "./admin-contenus-langues.js"; import "./admin-contenus-motscles.js"; diff --git a/app/templates/admin/cleanup.php b/app/templates/admin/cleanup.php new file mode 100644 index 0000000..0fd8742 --- /dev/null +++ b/app/templates/admin/cleanup.php @@ -0,0 +1,38 @@ +
+
+
+
+

+ + Nettoyer les fichiers temporaires +

+
+
+
+ +
+ +
+
+ + + Fichiers temporaires + +

Chargement…

+
+
+ + +
+

Chargement…

+
+
+
diff --git a/app/templates/admin/index.php b/app/templates/admin/index.php index 4aa962e..6b476e3 100644 --- a/app/templates/admin/index.php +++ b/app/templates/admin/index.php @@ -29,10 +29,9 @@ 0): ?> - + - -
- -
- -
-
- - - Fichiers temporaires - -

Chargement…

-
-
- -
-

Chargement…

-
-
-
-
NomTailleÂge
NomTailleÂge
~ j