mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Fix nettoyage modal: SVG icon files, padding/margin consistency, BBBDMSans font, fix HTMX trigger, nested details cleanup
This commit is contained in:
33
TODO.md
33
TODO.md
@@ -1,39 +1,23 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
> Last updated: 2026-06-21
|
> 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
|
## 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] #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) ✓
|
- [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] #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] #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 <p> content to BBBDMSans weight 300 `(search.css, apropos.css)` ✓
|
- [x] #typography-weight-300 Set search placeholder + apropos/charte/licence <p> 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] #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] #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 <a> 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] #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 <a> 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-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)` ✓
|
- [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] #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)` ✓
|
- [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] #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 <form> — both broke FilePond uploads and form submission `(admin/actions/draft.php, partage/fragments/draft.php, FormBootstrap.php, pill-search.js)` ✓
|
- [x] #csrf-rotation-race Stop CSRF token rotation in draft.php + remove hx-post from <form> — 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] ~~#filepond-csrf-stale~~ (superseded by #csrf-rotation-race)
|
||||||
- [x] #adminold-return-type Fix adminOld closure return type from `:string` to `:string|array` `(FormBootstrap.php)` ✓
|
- [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] #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] #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] #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] #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-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-database Update `createThesis`, `updateThesis`, `getThesisRawFields` in Database `(Database.php)` ✓
|
||||||
- [x] #duration-controllers Handle duration in `ThesisCreateController` and `ThesisEditController` `(ThesisCreateController.php, ThesisEditController.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] #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)` ✓
|
- [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
|
## Deferred / Blocked
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* GET /admin/actions/cleanup-stats-fragment.php
|
* 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__ . '/../../../bootstrap.php';
|
||||||
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
||||||
@@ -16,76 +16,115 @@ require __DIR__ . '/cleanup-stats.php';
|
|||||||
$json = ob_get_clean();
|
$json = ob_get_clean();
|
||||||
$d = json_decode($json, true);
|
$d = json_decode($json, true);
|
||||||
|
|
||||||
$hasFilePond = ($d['filepond_stale_count'] ?? 0) > 0 || ($d['filepond_active_count'] ?? 0) > 0;
|
$fpStale = $d['filepond_stale_count'] ?? 0;
|
||||||
$hasTrash = ($d['trash_stale_count'] ?? 0) > 0 || ($d['trash_active_count'] ?? 0) > 0;
|
$fpActive = $d['filepond_active_count'] ?? 0;
|
||||||
|
$trStale = $d['trash_stale_count'] ?? 0;
|
||||||
|
$trActive = $d['trash_active_count'] ?? 0;
|
||||||
|
|
||||||
if (!$hasFilePond && !$hasTrash): ?>
|
$totalStale = $fpStale + $trStale;
|
||||||
<p style="margin:0;color:var(--accent-green)">✓ Aucun fichier temporaire.</p>
|
$totalFiles = $fpStale + $fpActive + $trStale + $trActive;
|
||||||
<?php return; endif; ?>
|
|
||||||
|
|
||||||
<?php if ($d['filepond_stale_count'] > 0): ?>
|
// Build summary meta: total stale count + total size
|
||||||
<p class="n-heading">
|
$staleParts = [];
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 256 256" aria-hidden="true"><path d="M230.64,25.36a32,32,0,0,0-45.26,0q-.21.21-.42.45L131.55,88.22,121,77.64a24,24,0,0,0-33.95,0l-76.69,76.7a8,8,0,0,0,0,11.31l80,80a8,8,0,0,0,11.31,0L178.36,169a24,24,0,0,0,0-33.95l-10.58-10.57L230.19,71c.15-.14.31-.28.45-.43A32,32,0,0,0,230.64,25.36ZM96,228.69,79.32,212l22.34-22.35a8,8,0,0,0-11.31-11.31L68,200.68,55.32,188l22.34-22.35a8,8,0,0,0-11.31-11.31L44,176.68,27.31,160,72,115.31,140.69,184ZM219.52,59.1l-68.71,58.81a8,8,0,0,0-.46,11.74L167,146.34a8,8,0,0,1,0,11.31l-15,15L83.32,104l15-15a8,8,0,0,1,11.31,0l16.69,16.69a8,8,0,0,0,11.74-.46L196.9,36.48A16,16,0,0,1,219.52,59.1Z"></path></svg>
|
if ($fpStale > 0) $staleParts[] = $fpStale . ' téléversement';
|
||||||
Téléversements abandonnés <span class="n-meta"><?= $d['filepond_stale_count'] ?> dossier(s) · <?= htmlspecialchars($d['filepond_stale_human']) ?></span>
|
if ($trStale > 0) $staleParts[] = $trStale . ' corbeille';
|
||||||
</p>
|
$staleMeta = implode(' + ', $staleParts);
|
||||||
<table class="n-table">
|
|
||||||
<thead><tr><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
// Approximate total stale size
|
||||||
<tbody>
|
$staleSize = ($d['filepond_stale_size'] ?? 0) + ($d['trash_stale_size'] ?? 0);
|
||||||
<?php foreach ($d['filepond_stale_files'] as $f): ?>
|
$staleHuman = '';
|
||||||
<tr>
|
if ($staleSize >= 1073741824) { $staleHuman = number_format($staleSize / 1073741824, 1) . ' GB'; }
|
||||||
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
elseif ($staleSize >= 1048576) { $staleHuman = number_format($staleSize / 1048576, 1) . ' MB'; }
|
||||||
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
elseif ($staleSize >= 1024) { $staleHuman = number_format($staleSize / 1024, 0) . ' KB'; }
|
||||||
<td style="white-space:nowrap">~<?= (int)$f['age_minutes'] ?> min</td>
|
elseif ($staleSize > 0) { $staleHuman = $staleSize . ' B'; }
|
||||||
<td style="white-space:nowrap">
|
|
||||||
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
$summaryMeta = $staleMeta;
|
||||||
hx-post="/admin/actions/cleanup-tmp.php"
|
if ($staleHuman) $summaryMeta .= ' · ' . $staleHuman;
|
||||||
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","filepond_dir":"<?= htmlspecialchars($f['name']) ?>"}'
|
|
||||||
hx-target="#tmp-cleanup-stats"
|
if ($totalStale === 0 && $totalFiles === 0): ?>
|
||||||
hx-swap="innerHTML"
|
<div id="tmp-cleanup-stats-wrapper">
|
||||||
hx-indicator="#tmp-cleanup-stats">
|
<details class="n-section" open>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 256 256" aria-hidden="true"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
<summary>
|
||||||
Supprimer
|
<img src="/assets/icons/paint-brush-household.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
</button>
|
Fichiers temporaires
|
||||||
</td>
|
</summary>
|
||||||
</tr>
|
<p style="margin:0;color:var(--accent-green)">✓ Aucun fichier temporaire.</p>
|
||||||
<?php endforeach; ?>
|
</details>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
<?php return; endif; ?>
|
||||||
|
|
||||||
|
<div id="tmp-cleanup-stats-wrapper">
|
||||||
|
<details class="n-section" open>
|
||||||
|
<summary>
|
||||||
|
<img src="/assets/icons/paint-brush-household.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Fichiers temporaires <span class="n-meta"><?= htmlspecialchars($summaryMeta) ?></span>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
<?php if ($fpStale > 0): ?>
|
||||||
|
<p class="n-heading">
|
||||||
|
<img src="/assets/icons/paint-brush-household.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Téléversements abandonnés
|
||||||
|
</p>
|
||||||
|
<table class="n-table">
|
||||||
|
<thead><tr><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($d['filepond_stale_files'] as $f): ?>
|
||||||
|
<tr>
|
||||||
|
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
||||||
|
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
||||||
|
<td style="white-space:nowrap">~<?= (int)$f['age_minutes'] ?> min</td>
|
||||||
|
<td style="white-space:nowrap">
|
||||||
|
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
||||||
|
hx-post="/admin/actions/cleanup-tmp.php"
|
||||||
|
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","filepond_dir":"<?= htmlspecialchars($f['name']) ?>"}'
|
||||||
|
hx-target="#tmp-cleanup-stats-wrapper"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-indicator="#tmp-cleanup-stats-wrapper">
|
||||||
|
<img src="/assets/icons/trash.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Supprimer
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($d['trash_stale_count'] > 0): ?>
|
<?php if ($trStale > 0): ?>
|
||||||
<p class="n-heading">
|
<p class="n-heading">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 256 256" aria-hidden="true"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
<img src="/assets/icons/trash.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
Corbeille <span class="n-meta"><?= $d['trash_stale_count'] ?> fichier(s) · <?= htmlspecialchars($d['trash_stale_human']) ?></span>
|
Corbeille
|
||||||
</p>
|
</p>
|
||||||
<table class="n-table">
|
<table class="n-table">
|
||||||
<thead><tr><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
<thead><tr><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($d['trash_stale_files'] as $f): ?>
|
<?php foreach ($d['trash_stale_files'] as $f): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
||||||
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
||||||
<td style="white-space:nowrap">~<?= (int)$f['age_days'] ?> j</td>
|
<td style="white-space:nowrap">~<?= (int)$f['age_days'] ?> j</td>
|
||||||
<td style="white-space:nowrap">
|
<td style="white-space:nowrap">
|
||||||
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
||||||
hx-post="/admin/actions/cleanup-tmp.php"
|
hx-post="/admin/actions/cleanup-tmp.php"
|
||||||
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","trash_file":"<?= htmlspecialchars($f['name']) ?>"}'
|
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","trash_file":"<?= htmlspecialchars($f['name']) ?>"}'
|
||||||
hx-target="#tmp-cleanup-stats"
|
hx-target="#tmp-cleanup-stats-wrapper"
|
||||||
hx-swap="innerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-indicator="#tmp-cleanup-stats">
|
hx-indicator="#tmp-cleanup-stats-wrapper">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 256 256" aria-hidden="true"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
<img src="/assets/icons/trash.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
Supprimer
|
Supprimer
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (($d['filepond_active_count'] ?? 0) > 0 || ($d['trash_active_count'] ?? 0) > 0): ?>
|
<?php if ($fpActive > 0 || $trActive > 0): ?>
|
||||||
<p style="margin:var(--space-sm) 0 0 0;font-size:0.85em;color:var(--text-secondary)">Conservés :
|
<p style="margin:var(--space-sm) 0 0 0;font-size:0.85em;color:var(--text-secondary)">Conservés :
|
||||||
<?php if ($d['filepond_active_count']) echo $d['filepond_active_count'] . ' téléversement(s) actif(s) (' . htmlspecialchars($d['filepond_active_human']) . '), '; ?>
|
<?php if ($fpActive) echo $fpActive . ' téléversement(s) actif(s) (' . htmlspecialchars($d['filepond_active_human']) . '), '; ?>
|
||||||
<?php if ($d['trash_active_count']) echo $d['trash_active_count'] . ' fichier(s) récent(s) (' . htmlspecialchars($d['trash_active_human']) . ')'; ?>
|
<?php if ($trActive) echo $trActive . ' fichier(s) récent(s) (' . htmlspecialchars($d['trash_active_human']) . ')'; ?>
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ $d = json_decode($json, true);
|
|||||||
if (!($d['configured'] ?? false)): ?>
|
if (!($d['configured'] ?? false)): ?>
|
||||||
<div id="peertube-orphans-wrapper">
|
<div id="peertube-orphans-wrapper">
|
||||||
<details id="peertube-orphans-col" class="n-section" open>
|
<details id="peertube-orphans-col" class="n-section" open>
|
||||||
<summary>Vidéos PeerTube orphelines</summary>
|
<summary>
|
||||||
|
<img src="/assets/icons/video.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Vidéos PeerTube orphelines
|
||||||
|
</summary>
|
||||||
<div id="peertube-orphans-stats">
|
<div id="peertube-orphans-stats">
|
||||||
<p style="margin:0;color:var(--color-warning)">⚠️ PeerTube non configuré.</p>
|
<p style="margin:0;color:var(--color-warning)">⚠️ PeerTube non configuré.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -30,7 +33,10 @@ if (!($d['configured'] ?? false)): ?>
|
|||||||
<?php if (!empty($d['error'])): ?>
|
<?php if (!empty($d['error'])): ?>
|
||||||
<div id="peertube-orphans-wrapper">
|
<div id="peertube-orphans-wrapper">
|
||||||
<details id="peertube-orphans-col" class="n-section" open>
|
<details id="peertube-orphans-col" class="n-section" open>
|
||||||
<summary>Vidéos PeerTube orphelines</summary>
|
<summary>
|
||||||
|
<img src="/assets/icons/video.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Vidéos PeerTube orphelines
|
||||||
|
</summary>
|
||||||
<div id="peertube-orphans-stats">
|
<div id="peertube-orphans-stats">
|
||||||
<p style="margin:0;color:var(--color-error)">✗ <?= htmlspecialchars($d['error']) ?></p>
|
<p style="margin:0;color:var(--color-error)">✗ <?= htmlspecialchars($d['error']) ?></p>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,7 +46,10 @@ if (!($d['configured'] ?? false)): ?>
|
|||||||
|
|
||||||
<div id="peertube-orphans-wrapper">
|
<div id="peertube-orphans-wrapper">
|
||||||
<details id="peertube-orphans-col" class="n-section" open>
|
<details id="peertube-orphans-col" class="n-section" open>
|
||||||
<summary>Vidéos PeerTube orphelines <span class="n-meta"><?= (int)($d['total_on_channel'] ?? 0) ?> vidéos · <?= (int)($d['total_linked'] ?? 0) ?> liées</span></summary>
|
<summary>
|
||||||
|
<img src="/assets/icons/video.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Vidéos PeerTube orphelines <span class="n-meta"><?= (int)($d['orphan_count'] ?? 0) ?> vidéos orphelines</span>
|
||||||
|
</summary>
|
||||||
<div id="peertube-orphans-stats">
|
<div id="peertube-orphans-stats">
|
||||||
<?php if (($d['orphan_count'] ?? 0) > 0): ?>
|
<?php if (($d['orphan_count'] ?? 0) > 0): ?>
|
||||||
<table class="n-table">
|
<table class="n-table">
|
||||||
@@ -61,7 +70,7 @@ if (!($d['configured'] ?? false)): ?>
|
|||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-indicator="#peertube-orphans-wrapper">
|
hx-indicator="#peertube-orphans-wrapper">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 256 256" aria-hidden="true"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
<img src="/assets/icons/trash.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
Supprimer
|
Supprimer
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@@ -77,7 +86,10 @@ if (!($d['configured'] ?? false)): ?>
|
|||||||
|
|
||||||
<?php if (($d['stale_count'] ?? 0) > 0): ?>
|
<?php if (($d['stale_count'] ?? 0) > 0): ?>
|
||||||
<details id="peertube-stale-section" class="n-section" open>
|
<details id="peertube-stale-section" class="n-section" open>
|
||||||
<summary>Références DB obsolètes <span class="n-meta"><?= $d['stale_count'] ?></span></summary>
|
<summary>
|
||||||
|
<img src="/assets/icons/warning-diamond.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Références DB obsolètes <span class="n-meta"><?= $d['stale_count'] ?></span>
|
||||||
|
</summary>
|
||||||
<p style="margin:0 0 var(--space-sm) 0;font-size:0.85em;color:var(--text-secondary)">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.</p>
|
<p style="margin:0 0 var(--space-sm) 0;font-size:0.85em;color:var(--text-secondary)">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.</p>
|
||||||
<table class="n-table">
|
<table class="n-table">
|
||||||
<thead><tr><th>UUID</th><th>TFE(s)</th></tr></thead>
|
<thead><tr><th>UUID</th><th>TFE(s)</th></tr></thead>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ try {
|
|||||||
$allPages = $db->getAllPages();
|
$allPages = $db->getAllPages();
|
||||||
$pages = array_values(array_filter($allPages, fn($p) => in_array($p['slug'], $allowedPageSlugs, true)));
|
$pages = array_values(array_filter($allPages, fn($p) => in_array($p['slug'], $allowedPageSlugs, true)));
|
||||||
$aproposKeys = $db->getAllAproposContents();
|
$aproposKeys = $db->getAllAproposContents();
|
||||||
$formHelpBlocks = $db->getAllFormHelpBlocks();
|
|
||||||
$siteSettings = $db->getAllSettings();
|
$siteSettings = $db->getAllSettings();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Error loading contenus: " . $e->getMessage());
|
error_log("Error loading contenus: " . $e->getMessage());
|
||||||
|
|||||||
25
app/public/admin/structure-formulaire.php
Normal file
25
app/public/admin/structure-formulaire.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . "/../../bootstrap.php";
|
||||||
|
require_once __DIR__ . '/../../src/AdminAuth.php';
|
||||||
|
AdminAuth::requireLogin();
|
||||||
|
require_once __DIR__ . '/../../src/Database.php';
|
||||||
|
|
||||||
|
$pageTitle = "Structure du Formulaire";
|
||||||
|
|
||||||
|
if (empty($_SESSION['csrf_token'])) {
|
||||||
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = new Database();
|
||||||
|
$formHelpBlocks = $db->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';
|
||||||
@@ -1075,7 +1075,6 @@ th.admin-ap-col {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
margin: var(--space-xs) 0 var(--space-md) 0;
|
|
||||||
}
|
}
|
||||||
.n-table thead th {
|
.n-table thead th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -1119,6 +1118,10 @@ th.admin-ap-col {
|
|||||||
.n-grid > section,
|
.n-grid > section,
|
||||||
.n-grid > details {
|
.n-grid > details {
|
||||||
margin: 2ch 0;
|
margin: 2ch 0;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
.n-section:first-child,
|
.n-section:first-child,
|
||||||
.n-grid > section:first-child,
|
.n-grid > section:first-child,
|
||||||
@@ -1135,27 +1138,54 @@ th.admin-ap-col {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* <details>/<summary> inside cleanup sections */
|
/* <details>/<summary> inside cleanup sections */
|
||||||
.n-grid > details > summary {
|
.n-grid > details > summary,
|
||||||
|
.n-section > summary {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: var(--step--1);
|
font-size: var(--step--1);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
padding: var(--space-xs) 0;
|
padding: var(--space-xs);
|
||||||
list-style: none;
|
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;
|
display: none;
|
||||||
}
|
}
|
||||||
.n-grid > details > summary::before {
|
.n-section[open],
|
||||||
content: '▸ ';
|
.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;
|
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;
|
transition: transform 0.15s;
|
||||||
}
|
}
|
||||||
.n-grid > details[open] > summary::before {
|
.n-grid > details[open] > summary::before,
|
||||||
|
.n-section[open] > summary::before {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
.n-grid > details > :not(summary) {
|
.n-grid > details > :not(summary),
|
||||||
padding-left: calc(1ch + var(--space-xs));
|
.n-section > :not(summary) {
|
||||||
|
padding: 0 var(--space-s) var(--space-xs) var(--space-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Import results log ─────────────────────────────────────────────── */
|
/* ── Import results log ─────────────────────────────────────────────── */
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ details[open] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
details > :not(summary) {
|
details > :not(summary) {
|
||||||
margin-left: var(--space-s);
|
padding-left: var(--space-s);
|
||||||
margin-right: var(--space-s);
|
padding-right: var(--space-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
summary {
|
summary {
|
||||||
|
|||||||
1
app/public/assets/icons/caret-down.svg
Normal file
1
app/public/assets/icons/caret-down.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 238 B |
1
app/public/assets/icons/caret-right.svg
Normal file
1
app/public/assets/icons/caret-right.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 243 B |
1
app/public/assets/icons/paint-brush-household.svg
Normal file
1
app/public/assets/icons/paint-brush-household.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M230.64,25.36a32,32,0,0,0-45.26,0q-.21.21-.42.45L131.55,88.22,121,77.64a24,24,0,0,0-33.95,0l-76.69,76.7a8,8,0,0,0,0,11.31l80,80a8,8,0,0,0,11.31,0L178.36,169a24,24,0,0,0,0-33.95l-10.58-10.57L230.19,71c.15-.14.31-.28.45-.43A32,32,0,0,0,230.64,25.36ZM96,228.69,79.32,212l22.34-22.35a8,8,0,0,0-11.31-11.31L68,200.68,55.32,188l22.34-22.35a8,8,0,0,0-11.31-11.31L44,176.68,27.31,160,72,115.31,140.69,184ZM219.52,59.1l-68.71,58.81a8,8,0,0,0-.46,11.74L167,146.34a8,8,0,0,1,0,11.31l-15,15L83.32,104l15-15a8,8,0,0,1,11.31,0l16.69,16.69a8,8,0,0,0,11.74-.46L196.9,36.48A16,16,0,0,1,219.52,59.1Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 705 B |
1
app/public/assets/icons/trash.svg
Normal file
1
app/public/assets/icons/trash.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 416 B |
1
app/public/assets/icons/video.svg
Normal file
1
app/public/assets/icons/video.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M164.44,105.34l-48-32A8,8,0,0,0,104,80v64a8,8,0,0,0,12.44,6.66l48-32a8,8,0,0,0,0-13.32ZM120,129.05V95l25.58,17ZM216,40H40A16,16,0,0,0,24,56V168a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,128H40V56H216V168Zm16,40a8,8,0,0,1-8,8H32a8,8,0,0,1,0-16H224A8,8,0,0,1,232,208Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 412 B |
1
app/public/assets/icons/warning-diamond.svg
Normal file
1
app/public/assets/icons/warning-diamond.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,72a8,8,0,0,1,8,8v56a8,8,0,0,1-16,0V80A8,8,0,0,1,128,72ZM116,172a12,12,0,1,0,12-12A12,12,0,0,0,116,172Zm124-44a15.85,15.85,0,0,1-4.67,11.28l-96.05,96.06a16,16,0,0,1-22.56,0h0l-96-96.06a16,16,0,0,1,0-22.56l96.05-96.06a16,16,0,0,1,22.56,0l96.05,96.06A15.85,15.85,0,0,1,240,128Zm-16,0L128,32,32,128,128,224h0Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 434 B |
@@ -229,58 +229,9 @@
|
|||||||
Chaque <strong>bloc d'aide</strong> s'affiche au-dessus de sa section dans le formulaire de soumission.
|
Chaque <strong>bloc d'aide</strong> s'affiche au-dessus de sa section dans le formulaire de soumission.
|
||||||
Le <strong>bouton rond</strong> active/désactive l'affichage.
|
Le <strong>bouton rond</strong> active/désactive l'affichage.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
<?php
|
<a href="/admin/structure-formulaire.php" class="btn btn--primary btn--sm">Gérer la structure du formulaire (page dédiée)</a>
|
||||||
$blocks = $formHelpBlocks;
|
</p>
|
||||||
$pairs = [
|
|
||||||
['partage_intro', null, null],
|
|
||||||
['fieldset_tfe_info', 'Informations du TFE',
|
|
||||||
['Titre', 'Sous-titre', 'Auteur·ice(s)', 'Contact visible', 'Synopsis']],
|
|
||||||
['fieldset_languages', 'Langue(s)',
|
|
||||||
['Langues du TFE (cases à cocher)', 'Autre(s) langue(s)']],
|
|
||||||
['fieldset_keywords', 'Mots-clés',
|
|
||||||
['Mots-clés (max 10), séparés par des virgules']],
|
|
||||||
['fieldset_academic', 'Cadre académique',
|
|
||||||
['Année', 'Orientation', 'AP', 'Finalité']],
|
|
||||||
['fieldset_jury', 'Composition du jury',
|
|
||||||
['Président·e', 'Promoteur·ice(s)', 'Lecteur·ices']],
|
|
||||||
['fieldset_files', 'Format(s) + Fichiers',
|
|
||||||
['Formats (PDF, vidéo, audio, site web…)', 'Couverture', 'Note d\'intention', 'Fichier principal', 'Annexes']],
|
|
||||||
['fieldset_access', 'Degrés d\'ouverture et licences',
|
|
||||||
['Généralités', 'Degré (libre/interne/interdit)', 'Licence', 'CC2r']],
|
|
||||||
['fieldset_email', 'E-mail de confirmation',
|
|
||||||
['Adresse e-mail']],
|
|
||||||
];
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="fhb-structure">
|
|
||||||
<?php foreach ($pairs as [$helpKey, $fieldsetName, $inputs]):
|
|
||||||
$b = $blocks[$helpKey] ?? ['content' => '', 'name' => '', 'enabled' => 0];
|
|
||||||
$title = $b['name'] ?: ($fieldsetName ?? $helpKey);
|
|
||||||
?>
|
|
||||||
<div class="fhb-block-wrapper" data-key="<?= htmlspecialchars($helpKey) ?>">
|
|
||||||
<div class="fhb-inline"
|
|
||||||
hx-get="/admin/form-help-inline-fragment.php?key=<?= urlencode($helpKey) ?>"
|
|
||||||
hx-trigger="load"
|
|
||||||
hx-swap="outerHTML">
|
|
||||||
<div class="fhb-inline-name"><?= htmlspecialchars($title) ?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if ($fieldsetName !== null): ?>
|
|
||||||
<div class="fhb-fieldset-card">
|
|
||||||
<div class="fhb-fieldset-card-legend"><?= htmlspecialchars($fieldsetName) ?></div>
|
|
||||||
<?php if ($inputs): ?>
|
|
||||||
<ul class="fhb-fieldset-card-inputs">
|
|
||||||
<?php foreach ($inputs as $inp): ?>
|
|
||||||
<li><?= htmlspecialchars($inp) ?></li>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</ul>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ document.addEventListener('htmx:afterSwap',()=>{document.querySelectorAll('input
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($tmpTotalCount > 0): ?>
|
<?php if ($tmpTotalCount > 0): ?>
|
||||||
<button type="button" class="btn btn--sm btn--secondary" id="tmp-cleanup-btn"
|
<button type="button" class="btn btn--sm btn--secondary" id="tmp-cleanup-btn"
|
||||||
onclick="document.getElementById('tmp-cleanup-dialog').showModal(); htmx.trigger('#tmp-cleanup-stats','loadStats'); htmx.trigger('#peertube-orphans-wrapper','loadPeertube')">
|
onclick="document.getElementById('tmp-cleanup-dialog').showModal(); htmx.trigger('#tmp-cleanup-stats-wrapper','loadStats'); htmx.trigger('#peertube-orphans-wrapper','loadPeertube')">
|
||||||
Nettoyer (<?= $tmpTotalCount ?>)
|
Nettoyer (<?= $tmpTotalCount ?>)
|
||||||
</button>
|
</button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -8,14 +8,19 @@
|
|||||||
<div id="tmp-cleanup-result" style="display:none;margin-bottom:var(--space-sm)"></div>
|
<div id="tmp-cleanup-result" style="display:none;margin-bottom:var(--space-sm)"></div>
|
||||||
<div class="n-grid" id="cleanup-grid-parent">
|
<div class="n-grid" id="cleanup-grid-parent">
|
||||||
<!-- ═══════ FilePond / Trash ═══════ -->
|
<!-- ═══════ FilePond / Trash ═══════ -->
|
||||||
<details id="tmp-cleanup-stats" class="n-section" open>
|
<div id="tmp-cleanup-stats-wrapper"
|
||||||
<summary>Fichiers temporaires</summary>
|
hx-get="/admin/actions/cleanup-stats-fragment.php"
|
||||||
<div hx-get="/admin/actions/cleanup-stats-fragment.php"
|
hx-trigger="loadStats"
|
||||||
hx-trigger="loadStats"
|
hx-swap="outerHTML"
|
||||||
hx-swap="innerHTML">
|
hx-indicator="#tmp-cleanup-stats-wrapper">
|
||||||
|
<details class="n-section" open>
|
||||||
|
<summary>
|
||||||
|
<img src="/assets/icons/paint-brush-household.svg" width="14" height="14" alt="" aria-hidden="true">
|
||||||
|
Fichiers temporaires
|
||||||
|
</summary>
|
||||||
<p style="margin:0;color:var(--text-secondary)">Chargement…</p>
|
<p style="margin:0;color:var(--text-secondary)">Chargement…</p>
|
||||||
</div>
|
</details>
|
||||||
</details>
|
</div>
|
||||||
<!-- ═══════ PeerTube ═══════ -->
|
<!-- ═══════ PeerTube ═══════ -->
|
||||||
<div id="peertube-orphans-wrapper"
|
<div id="peertube-orphans-wrapper"
|
||||||
hx-get="/admin/actions/peertube-orphans-fragment.php"
|
hx-get="/admin/actions/peertube-orphans-fragment.php"
|
||||||
|
|||||||
67
app/templates/admin/structure-formulaire.php
Normal file
67
app/templates/admin/structure-formulaire.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<main id="main-content" class="admin-main">
|
||||||
|
<article>
|
||||||
|
<h1>Structure du Formulaire</h1>
|
||||||
|
|
||||||
|
<p style="margin-bottom:var(--space-s)">
|
||||||
|
<a href="/admin/contenus.php" class="btn btn--sm btn--secondary">← Retour aux Contenus</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="fhb-hint">
|
||||||
|
Chaque <strong>bloc d'aide</strong> s'affiche au-dessus de sa section dans le formulaire de soumission.
|
||||||
|
Le <strong>bouton rond</strong> active/désactive l'affichage.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$blocks = $formHelpBlocks;
|
||||||
|
$pairs = [
|
||||||
|
['partage_intro', null, null],
|
||||||
|
['fieldset_tfe_info', 'Informations du TFE',
|
||||||
|
['Titre', 'Sous-titre', 'Auteur·ice(s)', 'Contact visible', 'Synopsis']],
|
||||||
|
['fieldset_languages', 'Langue(s)',
|
||||||
|
['Langues du TFE (cases à cocher)', 'Autre(s) langue(s)']],
|
||||||
|
['fieldset_keywords', 'Mots-clés',
|
||||||
|
['Mots-clés (max 10), séparés par des virgules']],
|
||||||
|
['fieldset_academic', 'Cadre académique',
|
||||||
|
['Année', 'Orientation', 'AP', 'Finalité']],
|
||||||
|
['fieldset_jury', 'Composition du jury',
|
||||||
|
['Président·e', 'Promoteur·ice(s)', 'Lecteur·ices']],
|
||||||
|
['fieldset_files', 'Format(s) + Fichiers',
|
||||||
|
['Formats (PDF, vidéo, audio, site web…)', 'Couverture', 'Note d\'intention', 'Fichier principal', 'Annexes']],
|
||||||
|
['fieldset_access', 'Degrés d\'ouverture et licences',
|
||||||
|
['Généralités', 'Degré (libre/interne/interdit)', 'Licence', 'CC2r']],
|
||||||
|
['fieldset_email', 'E-mail de confirmation',
|
||||||
|
['Adresse e-mail']],
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="fhb-structure">
|
||||||
|
<?php foreach ($pairs as [$helpKey, $fieldsetName, $inputs]):
|
||||||
|
$b = $blocks[$helpKey] ?? ['content' => '', 'name' => '', 'enabled' => 0];
|
||||||
|
$title = $b['name'] ?: ($fieldsetName ?? $helpKey);
|
||||||
|
?>
|
||||||
|
<div class="fhb-block-wrapper" data-key="<?= htmlspecialchars($helpKey) ?>">
|
||||||
|
<div class="fhb-inline"
|
||||||
|
hx-get="/admin/form-help-inline-fragment.php?key=<?= urlencode($helpKey) ?>"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-swap="outerHTML">
|
||||||
|
<div class="fhb-inline-name"><?= htmlspecialchars($title) ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($fieldsetName !== null): ?>
|
||||||
|
<div class="fhb-fieldset-card">
|
||||||
|
<div class="fhb-fieldset-card-legend"><?= htmlspecialchars($fieldsetName) ?></div>
|
||||||
|
<?php if ($inputs): ?>
|
||||||
|
<ul class="fhb-fieldset-card-inputs">
|
||||||
|
<?php foreach ($inputs as $inp): ?>
|
||||||
|
<li><?= htmlspecialchars($inp) ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
Reference in New Issue
Block a user