From 71a92d682b86a4d00c85de1245424c42cfb66de5 Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Sun, 21 Jun 2026 16:50:44 +0200 Subject: [PATCH] Fix nettoyage modal: SVG icon files, padding/margin consistency, BBBDMSans font, fix HTMX trigger, nested details cleanup --- TODO.md | 33 ++-- .../admin/actions/cleanup-stats-fragment.php | 173 +++++++++++------- .../actions/peertube-orphans-fragment.php | 22 ++- app/public/admin/contenus.php | 1 - app/public/admin/structure-formulaire.php | 25 +++ app/public/assets/css/admin.css | 48 ++++- app/public/assets/css/components/details.css | 4 +- app/public/assets/icons/caret-down.svg | 1 + app/public/assets/icons/caret-right.svg | 1 + .../assets/icons/paint-brush-household.svg | 1 + app/public/assets/icons/trash.svg | 1 + app/public/assets/icons/video.svg | 1 + app/public/assets/icons/warning-diamond.svg | 1 + app/templates/admin/contenus.php | 55 +----- app/templates/admin/index.php | 2 +- .../admin/partials/dialogs/tmp-cleanup.php | 19 +- app/templates/admin/structure-formulaire.php | 67 +++++++ 17 files changed, 289 insertions(+), 166 deletions(-) create mode 100644 app/public/admin/structure-formulaire.php create mode 100644 app/public/assets/icons/caret-down.svg create mode 100644 app/public/assets/icons/caret-right.svg create mode 100644 app/public/assets/icons/paint-brush-household.svg create mode 100644 app/public/assets/icons/trash.svg create mode 100644 app/public/assets/icons/video.svg create mode 100644 app/public/assets/icons/warning-diamond.svg create mode 100644 app/templates/admin/structure-formulaire.php diff --git a/TODO.md b/TODO.md index 44eb14e..c7a5eb1 100644 --- a/TODO.md +++ b/TODO.md @@ -1,39 +1,23 @@ # TODO > Last updated: 2026-06-21 -> Context: Add SQLite indexes for contenus page language/tag query performance + fix soft-deleted thesis count filtering +> Context: nettoyage modal caret icons, padding consistency, font fix -## In Progress -- [x] #contenus-indexes Add index on thesis_languages(language_id) + tags(deleted_at, name); fix count queries to exclude soft-deleted theses `(Database.php, DatabaseMigrations.php, schema.sql, migrations/applied/041_thesis_languages_index.sql)` ✓ ## Completed - +- [x] #cleanup-modal-fixes Fix nettoyage modal: SVG caret icons, margin→padding, BBBDMSans summary `(admin.css, details.css)` ✓ +- [x] #structure-formulaire-page Move "Structure du Formulaire" from contenus.php to its own dedicated page with back button `(structure-formulaire.php [new], contenus.php)` ✓ - [x] #contenus-indexes Add index on thesis_languages(language_id) + tags(deleted_at, name); fix count queries to exclude soft-deleted theses `(Database.php, DatabaseMigrations.php, schema.sql, migrations/applied/041_thesis_languages_index.sql)` ✓ -- [x] #peertube-orphans-check Add Peertube orphan video check + relink in admin — listChannelVideos (PeerTubeService), peertube-orphans.php endpoint, UI in nettoyage dialog, relink support on edit page (peertube-relink.php, peertube-browser.php, fichiers-fragment.php, file-upload-filepond.js) ✓ - -## Pending -- [ ] #overtype-analysis Analyse and fix OverType editor reliability on contenus-edit.php - +- [x] #peertube-orphans-check Add Peertube orphan video check + relink in admin — listChannelVideos (PeerTubeService), peertube-orphans.php endpoint, UI in nettoyage dialog, relink support on edit page `(peertube-relink.php, peertube-browser.php, fichiers-fragment.php, file-upload-filepond.js)` ✓ - [x] #tfe-optional-formats Make TFE file optional when format is Site web (1), Performance (4) or Installation (6) — fixed incorrect format IDs [3→1,4,6] + added client-side JS toggle for TFE required/asterisk. Note d'intention remains required. 🎯 `(fichiers-fragment.php, file-upload-filepond.js)` ✓ - [x] #typography-weight-300 Set search placeholder + apropos/charte/licence

content to BBBDMSans weight 300 `(search.css, apropos.css)` ✓ - [x] #toc-parts-uppercase Hardcode "PARTIES" uppercase + black bottom border on TOC label `(about.php, charte.php, licence.php, apropos.css)` ✓ - [x] #apropos-overflow Prevent #apropos-intro and content-section children from overflowing `(apropos.css)` ✓ - [x] #toc-navigation Fix TOC links not navigating to headings — added `apply_id_to_heading: true` to CommonMark config so IDs land on headings not hidden elements; added scroll-margin-top to headings; unstuck main from flex container so sticky TOC works for full page height `(CharteController.php, LicenceController.php, apropos.css)` ✓ - - [x] #apropos-toc-style Fix TOC "Parties" label: Ductus font + lowercase, remove border-left from links, match global link style; rename .apropos-content → section.content, .apropos-section → .content-section, remove .prose wrapper `(apropos.css, about.php, charte.php, licence.php)` ✓ - - [x] #apropos-toc-confirm Fixed sticky TOC: removed `flex: 1; min-height: 0` on main for apropos-body so the sticky container is full content height; added `max-height` + `overflow-y: auto` to TOC for long lists `(apropos.css)` ✓ -- [ ] #contact-test-manual Test contact decoupling end-to-end: student submission → admin edit → public TFE display -- [ ] #aria-test-manual Test WCAG changes with VoiceOver and NVDA on full add/edit/partage form flows -- [ ] #nojs-upload-test Test end-to-end: submit partage form with JS disabled, verify files arrive via `$_FILES` -- [ ] #csp-media-iframe-deploy Deploy nginx config fix to server, test PDF iframe on /tfe?id=221 - - [x] #fix-finality-types Create standalone script + just command to rename finality types (Approfondi→Approfondie, Enseignement→Didactique, Spécialisé→Spécialisée) `(scripts/fix-finality-types.php, justfile)` ✓ - [x] #context-note-synopsis Display contextual note above synopsis (italic) instead of in meta column on TFE page `(tfe.php, tfe.css)` ✓ - -## Completed - - [x] #decouple-contacts Decouple contact_visible (public) & contact_interne (private email): backend already decoupled; made contact_public checkbox functional in admin add/edit forms; contact_public now controls TFE page visibility `(FormBootstrap.php, ThesisCreateController.php, ThesisEditController.php, tfe.php, form.php)` ✓ - - [x] #csrf-rotation-race Stop CSRF token rotation in draft.php + remove hx-post from

— both broke FilePond uploads and form submission `(admin/actions/draft.php, partage/fragments/draft.php, FormBootstrap.php, pill-search.js)` ✓ - [x] ~~#filepond-csrf-stale~~ (superseded by #csrf-rotation-race) - [x] #adminold-return-type Fix adminOld closure return type from `:string` to `:string|array` `(FormBootstrap.php)` ✓ @@ -42,9 +26,7 @@ - [x] #restore-languages Un-soft-delete anglais (id=2) and néerlandais (id=71) in dev DB ✓ - [x] #php-upload-limits Increase PHP upload_max_filesize to 8G, post_max_size to 8.5G `(.user.ini)` ✓ - [x] #formdata-fieldset-crash Remove leftover debug console.log that called new FormData(fieldset) `(admin/footer.php)` ✓ - - [x] #csp-media-iframe-fix Fix CSP `frame-ancestors 'none'` blocking PDF iframes — replaced `try_files` redirect with direct `fastcgi_pass` in `location = /media` so `add_header` CSP override survives internal nginx redirect `(nginx/xamxam.conf)` ✓ - - [x] #duration-migration Add migration to reintroduce `duration_value` and `duration_unit` columns + update views `(migrations/applied/040_duration_fields.sql)` ✓ - [x] #duration-database Update `createThesis`, `updateThesis`, `getThesisRawFields` in Database `(Database.php)` ✓ - [x] #duration-controllers Handle duration in `ThesisCreateController` and `ThesisEditController` `(ThesisCreateController.php, ThesisEditController.php)` ✓ @@ -68,4 +50,11 @@ - [x] #split-form-css Split `form.css` into `form-base.css` and `form-admin.css` ✓ - [x] #extra-css-admin Update `head.php` to support `$extraCssAdmin` for admin-only stylesheets `(head.php)` ✓ +## Pending +- [ ] #overtype-analysis Analyse and fix OverType editor reliability on contenus-edit.php +- [ ] #contact-test-manual Test contact decoupling end-to-end: student submission → admin edit → public TFE display +- [ ] #aria-test-manual Test WCAG changes with VoiceOver and NVDA on full add/edit/partage form flows +- [ ] #nojs-upload-test Test end-to-end: submit partage form with JS disabled, verify files arrive via `$_FILES` +- [ ] #csp-media-iframe-deploy Deploy nginx config fix to server, test PDF iframe on /tfe?id=221 + ## Deferred / Blocked diff --git a/app/public/admin/actions/cleanup-stats-fragment.php b/app/public/admin/actions/cleanup-stats-fragment.php index bdc3c28..ab64930 100644 --- a/app/public/admin/actions/cleanup-stats-fragment.php +++ b/app/public/admin/actions/cleanup-stats-fragment.php @@ -4,7 +4,7 @@ * * GET /admin/actions/cleanup-stats-fragment.php * - * Returns an HTML fragment ready for HTMX swap into #tmp-cleanup-stats. + * Returns an HTML fragment ready for HTMX swap into #tmp-cleanup-stats-wrapper. */ require_once __DIR__ . '/../../../bootstrap.php'; require_once __DIR__ . '/../../../src/AdminAuth.php'; @@ -16,76 +16,115 @@ require __DIR__ . '/cleanup-stats.php'; $json = ob_get_clean(); $d = json_decode($json, true); -$hasFilePond = ($d['filepond_stale_count'] ?? 0) > 0 || ($d['filepond_active_count'] ?? 0) > 0; -$hasTrash = ($d['trash_stale_count'] ?? 0) > 0 || ($d['trash_active_count'] ?? 0) > 0; +$fpStale = $d['filepond_stale_count'] ?? 0; +$fpActive = $d['filepond_active_count'] ?? 0; +$trStale = $d['trash_stale_count'] ?? 0; +$trActive = $d['trash_active_count'] ?? 0; -if (!$hasFilePond && !$hasTrash): ?> -

✓ Aucun fichier temporaire.

- +$totalStale = $fpStale + $trStale; +$totalFiles = $fpStale + $fpActive + $trStale + $trActive; - 0): ?> -

- - Téléversements abandonnés dossier(s) · -

- - - - - - - - - - - - -
NomTailleÂge
~ min - -
+// Build summary meta: total stale count + total size +$staleParts = []; +if ($fpStale > 0) $staleParts[] = $fpStale . ' téléversement'; +if ($trStale > 0) $staleParts[] = $trStale . ' corbeille'; +$staleMeta = implode(' + ', $staleParts); + +// Approximate total stale size +$staleSize = ($d['filepond_stale_size'] ?? 0) + ($d['trash_stale_size'] ?? 0); +$staleHuman = ''; +if ($staleSize >= 1073741824) { $staleHuman = number_format($staleSize / 1073741824, 1) . ' GB'; } +elseif ($staleSize >= 1048576) { $staleHuman = number_format($staleSize / 1048576, 1) . ' MB'; } +elseif ($staleSize >= 1024) { $staleHuman = number_format($staleSize / 1024, 0) . ' KB'; } +elseif ($staleSize > 0) { $staleHuman = $staleSize . ' B'; } + +$summaryMeta = $staleMeta; +if ($staleHuman) $summaryMeta .= ' · ' . $staleHuman; + +if ($totalStale === 0 && $totalFiles === 0): ?> +
+
+ + + Fichiers temporaires + +

✓ Aucun fichier temporaire.

+
+
+ + +
+
+ + + Fichiers temporaires + + + 0): ?> +

+ + Téléversements abandonnés +

+ + + + + + + + + + + + +
NomTailleÂge
~ min + +
- 0): ?> -

- - Corbeille fichier(s) · -

- - - - - - - - - - - - -
NomTailleÂge
~ j - -
+ 0): ?> +

+ + Corbeille +

+ + + + + + + + + + + + +
NomTailleÂge
~ j + +
- 0 || ($d['trash_active_count'] ?? 0) > 0): ?> -

Conservés : - - -

+ 0 || $trActive > 0): ?> +

Conservés : + + +

+
+
diff --git a/app/public/admin/actions/peertube-orphans-fragment.php b/app/public/admin/actions/peertube-orphans-fragment.php index 82d375d..dd8e0b5 100644 --- a/app/public/admin/actions/peertube-orphans-fragment.php +++ b/app/public/admin/actions/peertube-orphans-fragment.php @@ -19,7 +19,10 @@ $d = json_decode($json, true); if (!($d['configured'] ?? false)): ?>
- Vidéos PeerTube orphelines + + + Vidéos PeerTube orphelines +

⚠️ PeerTube non configuré.

@@ -30,7 +33,10 @@ if (!($d['configured'] ?? false)): ?>
- Vidéos PeerTube orphelines + + + Vidéos PeerTube orphelines +

@@ -40,7 +46,10 @@ if (!($d['configured'] ?? false)): ?>
- Vidéos PeerTube orphelines vidéos · liées + + + Vidéos PeerTube orphelines vidéos orphelines +
0): ?> @@ -61,7 +70,7 @@ if (!($d['configured'] ?? false)): ?> hx-swap="outerHTML" hx-trigger="click" hx-indicator="#peertube-orphans-wrapper"> - + Supprimer @@ -77,7 +86,10 @@ if (!($d['configured'] ?? false)): ?> 0): ?>
- Références DB obsolètes + + + Références DB obsolètes +

Ces UUID sont référencés en base de données mais n'existent plus sur la chaîne PeerTube. Les TFE liés affichent des liens morts.

diff --git a/app/public/admin/contenus.php b/app/public/admin/contenus.php index 6e5e4f0..3bc6c7b 100644 --- a/app/public/admin/contenus.php +++ b/app/public/admin/contenus.php @@ -18,7 +18,6 @@ try { $allPages = $db->getAllPages(); $pages = array_values(array_filter($allPages, fn($p) => in_array($p['slug'], $allowedPageSlugs, true))); $aproposKeys = $db->getAllAproposContents(); - $formHelpBlocks = $db->getAllFormHelpBlocks(); $siteSettings = $db->getAllSettings(); } catch (Exception $e) { error_log("Error loading contenus: " . $e->getMessage()); diff --git a/app/public/admin/structure-formulaire.php b/app/public/admin/structure-formulaire.php new file mode 100644 index 0000000..5f9d87d --- /dev/null +++ b/app/public/admin/structure-formulaire.php @@ -0,0 +1,25 @@ +getAllFormHelpBlocks(); +} catch (Exception $e) { + error_log("Error loading structure-formulaire: " . $e->getMessage()); + die("Erreur lors du chargement de la structure du formulaire."); +} + +$isAdmin = true; $bodyClass = 'admin-body'; +require_once APP_ROOT . '/templates/head.php'; +include APP_ROOT . '/templates/header.php'; +include APP_ROOT . '/templates/admin/structure-formulaire.php'; +require_once APP_ROOT . '/templates/admin/footer.php'; diff --git a/app/public/assets/css/admin.css b/app/public/assets/css/admin.css index d26d435..939462d 100644 --- a/app/public/assets/css/admin.css +++ b/app/public/assets/css/admin.css @@ -1075,7 +1075,6 @@ th.admin-ap-col { width: 100%; border-collapse: collapse; font-size: 0.85em; - margin: var(--space-xs) 0 var(--space-md) 0; } .n-table thead th { text-align: left; @@ -1119,6 +1118,10 @@ th.admin-ap-col { .n-grid > section, .n-grid > details { margin: 2ch 0; + border: none; + border-radius: 0; + background: transparent; + overflow: visible; } .n-section:first-child, .n-grid > section:first-child, @@ -1135,27 +1138,54 @@ th.admin-ap-col { } /*
/ inside cleanup sections */ -.n-grid > details > summary { +.n-grid > details > summary, +.n-section > summary { cursor: pointer; font-weight: 600; font-size: var(--step--1); color: var(--text-primary); - padding: var(--space-xs) 0; + padding: var(--space-xs); list-style: none; + font-family: var(--font-body); + display: flex; + align-items: center; + gap: var(--space-2xs); } -.n-grid > details > summary::-webkit-details-marker { +.n-grid > details > summary::-webkit-details-marker, +.n-section > summary::-webkit-details-marker { display: none; } -.n-grid > details > summary::before { - content: '▸ '; +.n-section[open], +.n-grid > details[open] { + padding-bottom: 0; +} + +.n-grid > details > summary:hover, +.n-section > summary:hover { + background: transparent; +} + +.n-grid > details > summary::before, +.n-section > summary::before { + content: ''; display: inline-block; + width: 16px; + height: 16px; + flex-shrink: 0; + background: currentColor; + mask-image: url("/assets/icons/caret-right.svg"); + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; transition: transform 0.15s; } -.n-grid > details[open] > summary::before { +.n-grid > details[open] > summary::before, +.n-section[open] > summary::before { transform: rotate(90deg); } -.n-grid > details > :not(summary) { - padding-left: calc(1ch + var(--space-xs)); +.n-grid > details > :not(summary), +.n-section > :not(summary) { + padding: 0 var(--space-s) var(--space-xs) var(--space-s); } /* ── Import results log ─────────────────────────────────────────────── */ diff --git a/app/public/assets/css/components/details.css b/app/public/assets/css/components/details.css index 0b27741..d77de55 100644 --- a/app/public/assets/css/components/details.css +++ b/app/public/assets/css/components/details.css @@ -24,8 +24,8 @@ details[open] { } details > :not(summary) { - margin-left: var(--space-s); - margin-right: var(--space-s); + padding-left: var(--space-s); + padding-right: var(--space-s); } summary { diff --git a/app/public/assets/icons/caret-down.svg b/app/public/assets/icons/caret-down.svg new file mode 100644 index 0000000..42f37b7 --- /dev/null +++ b/app/public/assets/icons/caret-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/public/assets/icons/caret-right.svg b/app/public/assets/icons/caret-right.svg new file mode 100644 index 0000000..81658b0 --- /dev/null +++ b/app/public/assets/icons/caret-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/public/assets/icons/paint-brush-household.svg b/app/public/assets/icons/paint-brush-household.svg new file mode 100644 index 0000000..d67ecb3 --- /dev/null +++ b/app/public/assets/icons/paint-brush-household.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/public/assets/icons/trash.svg b/app/public/assets/icons/trash.svg new file mode 100644 index 0000000..0504592 --- /dev/null +++ b/app/public/assets/icons/trash.svg @@ -0,0 +1 @@ + diff --git a/app/public/assets/icons/video.svg b/app/public/assets/icons/video.svg new file mode 100644 index 0000000..d711517 --- /dev/null +++ b/app/public/assets/icons/video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/public/assets/icons/warning-diamond.svg b/app/public/assets/icons/warning-diamond.svg new file mode 100644 index 0000000..fb1346d --- /dev/null +++ b/app/public/assets/icons/warning-diamond.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/templates/admin/contenus.php b/app/templates/admin/contenus.php index c535f3f..a7f8031 100644 --- a/app/templates/admin/contenus.php +++ b/app/templates/admin/contenus.php @@ -229,58 +229,9 @@ Chaque bloc d'aide s'affiche au-dessus de sa section dans le formulaire de soumission. Le bouton rond active/désactive l'affichage.

- - - -
- '', 'name' => '', 'enabled' => 0]; - $title = $b['name'] ?: ($fieldsetName ?? $helpKey); - ?> -
-
-
-
-
- - -
-
- -
    - -
  • - -
- -
- - -
+

+ Gérer la structure du formulaire (page dédiée) +

diff --git a/app/templates/admin/index.php b/app/templates/admin/index.php index 2f73478..7ef86d4 100644 --- a/app/templates/admin/index.php +++ b/app/templates/admin/index.php @@ -41,7 +41,7 @@ document.addEventListener('htmx:afterSwap',()=>{document.querySelectorAll('input 0): ?> diff --git a/app/templates/admin/partials/dialogs/tmp-cleanup.php b/app/templates/admin/partials/dialogs/tmp-cleanup.php index 6191bf8..f6d661d 100644 --- a/app/templates/admin/partials/dialogs/tmp-cleanup.php +++ b/app/templates/admin/partials/dialogs/tmp-cleanup.php @@ -8,14 +8,19 @@
-
- Fichiers temporaires -
+
+
+ + + Fichiers temporaires +

Chargement…

-
-
+
+
+
+

Structure du Formulaire

+ +

+ ← Retour aux Contenus +

+ +

+ Chaque bloc d'aide s'affiche au-dessus de sa section dans le formulaire de soumission. + Le bouton rond active/désactive l'affichage. +

+ + + +
+ '', 'name' => '', 'enabled' => 0]; + $title = $b['name'] ?: ($fieldsetName ?? $helpKey); + ?> +
+
+
+
+
+ + +
+
+ +
    + +
  • + +
+ +
+ + +
+ +
+
UUIDTFE(s)