Commit Graph
100 Commits
Author SHA1 Message Date
Pontoporeia 1ed69a2c1a refactor(justfile): de-dup deploy-code, move nginx/setup to deploy-nginx 2026-09-18 16:26:48 +02:00
Pontoporeia bdde7173ea fix(ui): reserve scrollbar gutter in public TOC so it doesn't overlay text 2026-09-18 16:26:36 +02:00
Pontoporeia fc66b37801 feat(home): htmx lazy-load cover images
Replace the eager <img> on the home page with an htmx placeholder <figure>
that fetches a /cover-fragment endpoint when it scrolls into view
(hx-trigger="revealed"), so heavy cover bytes load only on demand.
Add spinner + settle-fade transition CSS, and load htmx.min.js on home.
2026-09-18 16:26:36 +02:00
Pontoporeia 541470b9bb feat(provision): idempotent setup for local dev and remote server 2026-09-18 16:26:36 +02:00
Pontoporeia d5c1dfb23d docs: keep only reference documentation, archive one-offs 2026-09-18 16:26:36 +02:00
Pontoporeia 8accb88452 update: CSS per-page split and lightningcss unusedSymbols report
docs: record CSS template inventory + decide unusedSymbols-before-split ordering

feat(css): add content-source collector + dynamic-class safelist for unusedSymbols report

- scripts/css-content-sources.mjs: buildCorpus() gathers templates/public/src
  PHP + first-party js/app JS (vendor excluded), returns {corpus, sources,
  totalBytes, safelist, prefixes}
- Mined 22 exact runtime classes + 5 DB/state-derived suffix prefixes from
  status-badge.php, SystemController statusClass/logLineClass, and class=<?=?>
  ternaries
- docs/css-split-analysis.md notes content-corpus section
- td: #11 collect-content-sources done; feeds #12 report script

feat(css): unusedSymbols report script + just css-report recipe

- scripts/css-unused-report.mjs: per-bundle class/id extraction vs buildCorpus()
  corpus + safelists; measures reclaimable bytes via lightningcss transform
  unusedSymbols (report-only, no stripping to disk)
- just css-report: rebuild CSS then run the report
- css-content-sources.mjs: add VENDOR_CLASS_PREFIXES (filepond--*, htmx-*)
- RESULT: 216,383B total, ~6.2KB (2.9%) reclaimable; FilePond/HTMX exclusion
  corrected inflated 26% (56KB) false-positive down to honest 2.9%
- docs/css-split-analysis.md findings table + TODO 12/13 done

docs(css): record go/no-go decision — split NO-GO, pruning conditional-go

- Decision analysis in docs/css-split-analysis.md
- ~6.2KB (2.9%) reclaimable of 216KB; base.min.css only 484B (2.3%)
- SPLIT NO-GO: base.css already well-used; parked u/w/x/y(/z) as deferred
- PRUNING conditional-go on hand-verifiable dead selers from source, never dist;
  re-run just css-report after each edit; keep needs-review + vendor-prefix cls
- td: task 14 done; split stream 41 tasks -> 2 pending / 32 done / 7 deferred

todo: defer CSS pruning stream (10/u/w/x/y/z), context updated
2026-09-18 16:26:36 +02:00
Pontoporeia a31e4ab307 Recherche insensible aux accents sur toutes les barres de recherche (publique + backoffice).
Ajoute une fonction SQLite UDF accfold() (app/src/AccentFolding.php) qui plie les caractères accentués latin vers leur base ASCII (é→e, ç→c, …), et l'applique à chaque condition de recherche côté colonne ET côté terme (accfold(column) LIKE accfold(:term)). Comme le runtime n'a ni intl (Normalizer) ni iconv, le repli passe par une map de translitération manuelle (Western Latin-1 + Latin Extended-A, NULL-safe).

Couvert :
- recherche publique (searchTheses / countSearchResults) : titre, sous-titre, synopsis, auteurs, promoteurs, tags ;
- popover étudiant (getThesesByAuthorName / getThesesForAuthors) : a.name ;
- recherche backoffice (getThesesList / getThesesListCount) : titre, sous-titre, identifiant, auteur.

L'UDF est enregistré dans Database::registerSqliteFunctions() (appelé par le constructeur et par le harnais de test TestDatabaseInstance). Évite aussi la dépréciation PHP 8.5 de PDO::sqliteCreateFunction() : la connexion est créée via \Pdo\Sqlite quand disponible (createFunction()) avec repli sur PDO (sqliteCreateFunction()) sur les anciens runtimes ; les tests passent de @dataProvider docblock à l'attribut #[DataProvider] (fin de la dépréciation PHPUnit). Détache .php-cs-fixer.cache (gitignoré) pour ne plus polluer le working copy.

294 tests PHPUnit verts sans dépréciation, phpstan niveau 5 OK.
2026-09-18 16:26:36 +02:00
Pontoporeia 0896c4b8c8 Synopsis : normalisation SÛRE des text ajouté par formulaire
- fins de ligne \r\n/\r → \n,
- blocs de lignes vides → \n\n, è
- espaces/tabulations/NBSP → espace unique,
- trim.
Les retours à la ligne simples intra-paragraphe sont LAISSÉS INTACTS :
une coupure de ligne peut être une vraie frontière de mot (→ espace)
ou une coupure du mot ("dyna\nmiques" → "dynamiques"),
indistinguables sans dictionnaire — automatiser corromprait l'entrée
("poursuivantsur").

Migration batch 045 (backfill des données existantes) RETIRÉE : le
nettoyage automatique fiable des synopsis existants est impossible.
Chaque modification est testée (277 tests PHPUnit).
2026-09-18 16:26:36 +02:00
Pontoporeia 6e1fc6a781 Add admin-only route to open Interdit thesis files from backoffice:
- reliable tab title /favicon wrapper,
- Content-Disposition filename,
- admin media route hardened to thesis-file prefixes only (defense-in-depth)
2026-09-18 16:26:36 +02:00
Pontoporeia e518163c5b Style links on licences, charte, a propos pages as real links (underline + accent hover) 2026-09-18 16:26:36 +02:00
Pontoporeia 116dca5d75 Admin: search by thesis identifiant (id) in backoffice list 2026-09-18 16:26:36 +02:00
Pontoporeia 61b105da27 feature: Lien BAIU + thesis ID in tfe.php 2026-09-18 16:26:36 +02:00
Pontoporeia 3316a352e3 docs: add environment/runtime requirements spec 2026-09-18 16:26:36 +02:00
Pontoporeia 307988eb3c feat: enforce idle + absolute timeouts on admin session 2026-09-18 16:26:36 +02:00
Pontoporeia 30a16f9e9e fix: display db timestamps in Brussels time
(heure de dépôt was showing UTC)

- feat: add date_depot column (real TFE deposit date)
with CSV round-trip + Brussels→UTC sanitization
- fix: keep PHP default tz at UTC to preserve token/share-link
 expiry consistency; convert to Brussels only in db_datetime()
2026-09-18 16:26:36 +02:00
Pontoporeia 2232981753 fix tfe.php scroll: make .tfe-main a flex container so the height chain resolves
.tfe-main (main) is a block container by default, so .tfe-layout's
height:100% and .tfe-content-row's flex:1 never resolved to a
definite height. The columns' overflow-y:auto thus had nothing to
constrain, and main's overflow:hidden clipped the content — scroll
was visually broken. Adding display:flex lets the column/height
chain resolve so both columns scroll independently as intended.
2026-08-24 11:36:15 +02:00
Pontoporeia 55c714a35d Reorganise docs: move historical files to archive/, merge overlapping docs
- Move 12 historical/superseded docs + 1 session log + 1 PDF + 1 HTML plan to archive/
- Merge 4 VM-crash docs into archive/vm-crash-incident.md
- Merge LDAP plan + spec into ldap.md
- Merge FilePond race investigation into filepond-crash-analysis.md
- Merge SPECS.md client notes into spec-sheet.md appendix
- Update README index and security.md cross-reference
2026-08-24 11:36:02 +02:00
Pontoporeia e4b48867aa Add sso-diagnose.sh: verify all peertube-sso-incident claims into a log
- docs: record the open identity-forwarding question, auth contracts, and responsibility boundary
2026-08-24 11:36:02 +02:00
Pontoporeia f31addb6bc add password-reset smoke test + AdminAuth DI + OneTimeToken empty-context redeem fix 2026-08-24 11:36:02 +02:00
Pontoporeia ddae5d8fef add password-reset flow: request endpoint + reset page + login link (shared OneTimeToken) 2026-08-24 11:36:02 +02:00
Pontoporeia d7184e4447 migrate file-access tokens onto shared OneTimeToken model (hash-at-rest) 2026-08-24 11:36:02 +02:00
Pontoporeia 3f1dcf5d43 test: add characterization tests for file-access token lifecycle 2026-08-24 11:36:02 +02:00
Pontoporeia abb735253e extract shared OneTimeToken model for single-use tokens + AdminAuth reset API 2026-08-24 11:35:22 +02:00
Pontoporeia 802b601b59 admin parametres: remove the remove-credentials danger zone 2026-08-24 11:35:22 +02:00
Pontoporeia c205a00c3f admin parametres: hr separator between current/new password, drop new-password top border 2026-08-24 11:35:22 +02:00
Pontoporeia 138b59f66c admin parametres: add shared Identifiants section, trim Emails, restructure PeerTube fieldsets
- admin parametres: move Compte administrateur into Identifiants as a fieldset
- admin parametres: space the account fieldset and drop confirm-password top border
- admin parametres: tighten param-form row spacing, relabel password button
- admin parametres: move password submit button outside the account fieldset
2026-08-24 11:35:22 +02:00
Pontoporeia fb5e856288 admin: backup logs via parameters.php, nextcloud secondary backup
- surface backup/cleanup cron logs + backup freshness status
- email xamxam@erg.be when SQLite backups go stale (backup watchdog)
- sync SQLite snapshots to Nextcloud WebDAV + remote-freshness watchdog
- precise retention pruning, manual sync in check recipe, and Nextcloud-sync docs
2026-08-24 11:34:57 +02:00
Pontoporeia 3e721b19f0 ui: system logs style update
- Increase padding in admin log dropdown selects
- Move admin log filters above the Journaux tabs
2026-08-24 11:34:34 +02:00
Pontoporeia d2cef85966 logs: standardise log filenames to xamxam-{service}-{date}.log 2026-08-24 11:34:34 +02:00
Pontoporeia 7b6d79c133 diag: invalid_grant is SSO auth-method mismatch, not bad creds
- feat: creds-test.sh gum probe for SMTP vs PeerTube auth + PeerTubeService::probeAuth()
- feat: app-token.sh gum probe for long-lived PeerTube app token (client_credentials)
- docs: add copy-paste proof commands to demonstrate the SSO break to admins
2026-08-24 11:33:34 +02:00
Pontoporeia 5460041989 feat: allow exporting an empty CSV template for imports 2026-08-24 11:33:34 +02:00
Pontoporeia 7938ab39c0 feat: add custom 404 page rendered via the site layout 2026-08-24 11:32:02 +02:00
Pontoporeia e9747edce0 docs: verify and refactor documentation to match current codebase 2026-08-24 11:31:38 +02:00
Pontoporeia b2cdbd0174 fix: CSV import VALUES placeholder count mismatch (27 values for 26 columns) 2026-07-10 19:07:19 +02:00
Pontoporeia 64323fd17e sort TFE files by display category on public page: note d'intention → TFE → image → video → audio → website → annexes 2026-07-10 19:07:14 +02:00
Pontoporeia 9965529fd4 nginx: open CSP frame-src from hardcoded domain whitelist to https: scheme-wide 2026-07-10 17:26:02 +02:00
Pontoporeia 6e1d54511d fix: remove redundant query= param from filter-specific metadata links on TFE page
Clicking orientation, AP program, finality, year, format, or keyword links
on the TFE page was passing both a dedicated filter param AND a query=
param. The query= text search doesn't look at the filter columns
(orientation, ap_program, etc.), so the AND combination yielded zero
results when the filter value didn't appear in title/authors/etc fields.

Also fix the language link: it was passing language as query= which
searches only title/authors/etc, not the languages column. Now uses
the dedicated language= param (DB layer already supported it, and
collectSearchParams now collects it).
2026-07-10 17:20:21 +02:00
Pontoporeia 14c21586c5 fix: clamp student popover position to stay within viewport vertically 2026-07-10 17:11:10 +02:00
Pontoporeia d8f85b03ad fix: use getElementById for relink FilePond pool lookup
FilePond 4.x wraps the original input element in its own DOM structure
which can break CSS attribute selectors. querySelector with
.tfe-file-picker[data-queue-type='...'] returned null even though the
element existed and was initialized.

Switched to getElementById with a queueType→inputId map:
  cover → couverture
  note_intention → note_intention
  tfe → tfe-files-input
  annexe → annexe-files-input

getElementById is both faster and immune to FilePond's DOM wrapping.
2026-07-10 16:42:56 +02:00
Pontoporeia 6da45435f5 fix: relinked files now appear in FilePond UI immediately
Switched from pond.addFile(type:'limbo') to pond.addFiles([{source, options:{type:'local'}}])
in both XamxamRelinkFile and XamxamRelinkPeerTube.

addFile with type 'limbo' doesn't trigger server.load to fetch the file
for the preview/thumbnail. The data-existing-files format (type:'local')
correctly tells FilePond to call server.load for the file identified by
the source (DB ID), rendering it properly in the pool.
2026-07-10 16:36:30 +02:00
Pontoporeia 7013f79fc0 fix: merge corbeille lists + bulk restore button in cleanup
- Single unified 'Corbeille' table replaces the two separate lists
  (stale/orphelin + restorable). Each row has a Statut column showing
  '↺ Restaurable' or 'Orphelin', plus a checkbox for bulk ops.

- Checkboxes on restorable rows carry data-restorable='1' attribute
  so the bulk JS can distinguish them.

- Bulk actions bar now has both 'Supprimer la sélection' and
  '↺ Restaurer la sélection' buttons. The restore button only appears
  when at least one restorable item is checked.

- New cleanupBulkRestore() JS function populates a dedicated hidden
  form and confirms before submitting. Only restorable items are sent.

- restore-trash.php refactored to handle both single (trash_file) and
  bulk (trash_files[]) inputs via a loop, accumulating restored/skipped
  counts and re-rendering the fragment on HTMX requests.
2026-07-10 16:33:06 +02:00
Pontoporeia 3cecee10c9 fix: prevent file deletion on relink + restore button now visible + OOB-style in-place update
Two critical fixes:

1. Relink flow no longer destroys/recreates FilePond instances:
   The relink (XamxamRelinkFile) and PeerTube relink (XamxamRelinkPeerTube)
   previously refreshed the entire fichiers fragment via HTMX after
   pond.addFile(). This triggered destroyFilePondsIn on ALL pools, which
   could fire server.remove callbacks and move existing files to corbeille.
   Now just closes the modal — the file is already added to the pool in-place,
   and syncOrderInput creates the hidden form input.

2. Cleanup page « Corbeille (restaurable) » now actually shows files:
   _cleanup-stats-data.php previously classified trash files by checking if
   the thesis_files DB row still existed. But both deleteThesisFileToTrash
   and FilepondHandler::handleRemove DELETE the DB row. So ALL trash files
   appeared as `stale` (not restorable). Now uses the JSON sidecar file
   presence as the classification criterion — if the sidecar exists and is
   recent, the file is restorable regardless of DB row state.

Also removed unused DB query from _cleanup-stats-data.php.
2026-07-10 16:29:04 +02:00
Pontoporeia ed19e30cf0 repertoire keyword column: smaller font (step--1), tighter line-height (1.15), no hyphenation 2026-07-10 15:59:48 +02:00
Pontoporeia 0045c06fef fix: prevent keyword word-breaking in repertoire columns 2026-07-10 15:51:03 +02:00
Pontoporeia c1a05efcda fix: bypass /tmp tmpfs for file uploads by redirecting PHP upload_tmp_dir to storage partition 2026-07-10 15:42:07 +02:00
Pontoporeia 1293b1be6c remove TOC temporary debug error_log calls 2026-07-10 15:23:52 +02:00
Pontoporeia c67262673f paramètres: fix logs Copier button scrolling out of view on horizontal scroll
Wrap .log-output and the copy button in a .log-output-wrapper div
with position:relative, so the button sits outside the overflow-x:auto
scroll container and stays fixed at the top-right corner.
2026-07-10 15:21:29 +02:00
Pontoporeia 3e3d829d11 fix: website iframe overlay — icon button bottom-right, no blur, tooltip 2026-07-10 15:18:42 +02:00
Pontoporeia 3d5d972ad0 fix TOC invisible: add open attr to details.toc — extractToc works but closed details + desktop pointer-events:none hid content; also make apropos TOC dynamic
fix: website iframe overlay — icon button bottom-right, no blur
2026-07-10 15:18:42 +02:00
Pontoporeia 250e33b571 fix: add frame-src CSP for videos.erg.be and depnum.happyngreen.fr 2026-07-10 15:18:42 +02:00
Pontoporeia 018d699ebd apropos: dynamic TOC via extractToc, HeadingPermalinkExtension, debug logging for TOC diagnosis 2026-07-10 15:07:14 +02:00
Pontoporeia 2461f526bf fix: prevent line breaks before punctuation in TFE titles and meta labels
- Override aggressive word-break: break-word from base.css
  with word-break: normal + overflow-wrap: break-word + hyphens: auto
  on .tfe-title, .tfe-author, .tfe-meta-item
- Replace regular spaces before colons with &nbsp; in all meta labels
  (French typographic rule: non-breaking space before double punctuation)
- Rebuild tfe.min.css
2026-07-10 14:47:52 +02:00
Pontoporeia bbf063f3eb fix: header font-size + css syntax error 2026-07-10 14:38:58 +02:00
Pontoporeia eb0f48d320 fix: gradient across public 2026-07-10 14:32:46 +02:00
Pontoporeia 269b751fea fix: Logger default WARNING→INFO + structured PeerTube logging
Log level: production default was Level::Warning, but all facades
(AppLogger, AdminLogger, Audit) write at Monolog INFO level. This
silently discarded submission, admin action, and audit logs when
LOG_LEVEL env var was unset. Changed to Level::Info.

PeerTube: replaced raw error_log() calls in PeerTubeService::upload(),
deleteVideo(), FilepondHandler::process(), ThesisCreateController,
and ThesisFileHandler with structured logging:
- Successes → Logger::get('app')->info() (visible in App — soumissions tab)
- Failures  → ErrorHandler::log('peertube_*', ...) (visible in Erreurs tab)
Added require_once for Logger and ErrorHandler in PeerTubeService.
2026-07-10 14:16:53 +02:00
Pontoporeia f427352a71 tfe: redirect internal metadata links from /repertoire to /search
redirect internal metadata links from /repertoire to /search, add query param for search bar prefill, fix filter visibility on desktop

 redirect metadata links from /repertoire to /search, prefill search bar, fix filter visibility

 link metadata to /search, preserve keyword filter in form, show active keyword chip
2026-07-10 14:16:36 +02:00
Pontoporeia f5a7d70fbc tfe: wrap website iframe in overlay-style div with Site web badge, clearer link text 2026-07-10 14:16:05 +02:00
Pontoporeia c513ad2545 TOC: extract h1/h2/h3, indent sub-levels in charte/licence sidebar 2026-07-10 14:16:05 +02:00
Pontoporeia 485324368f content-page.css: smaller heading scale with explicit clamp values
Replace var(--step-5)/--step-3/--step-1 for h1/h2/h3 with explicit
clamp() values. New hierarchy: h1 ~2rem, h2 ~1.5rem, h3 ~1.2rem.
Also update .content-section-title to use direct clamp (was --step-3,
now matches h2). Mobile override swapped from --step-2 to explicit
clamp. Kept --step-0 for body text (consistent with site baseline).
2026-07-10 14:16:05 +02:00
Pontoporeia 83e95bc4f5 repertoire: HTMX OOB swaps for filter columns + fix fading edge cases
Switch from swapping the entire #repertoire-index block to targeted
hx-swap-oob swaps: only the <ul> list elements are replaced, while
section headers and accordion chrome stay in the DOM untouched.

- Filter column <ul>s get IDs (rep-list-years, rep-list-ap, etc.)
  and render with hx-swap-oob=true on HTMX requests
- Students <ul> gets id=rep-students as main swap target
- Filter buttons now target #rep-students instead of #repertoire-index
- Server sets $isOob=true when rendering HTMX partial responses
- Accordion re-init on swap no longer needed (headers never replaced)
- Scroll-restore updated to capture/restore per <ul> ID

Fading fixes:
- Restore rep-entry--faded class with simplified logic: any active
  filter fades entries whose matched flag is false (removed the
  $colHasMatch gate that prevented fading when a column had no matches)
- Add $noResults guard: when matched_ids is empty, force-fade all
  non-selected entries across ALL columns
- Fix keyword matched computation: use full intersection
  ($buildWhere('__none__')) instead of excluding the keyword filter.
  Previously keywords were matched against only non-keyword filters,
  so selecting a keyword would not narrow the available keyword set,
  causing entries to appear valid that would yield zero results.
2026-07-10 13:02:32 +02:00
Pontoporeia ec9c140ba2 repertoire: HTMX OOB swaps for filter columns + fix fading edge cases
Switch from swapping the entire #repertoire-index block to targeted
hx-swap-oob swaps: only the <ul> list elements are replaced, while
section headers and accordion chrome stay in the DOM untouched.

- Filter column <ul>s get IDs (rep-list-years, rep-list-ap, etc.)
  and render with hx-swap-oob=true on HTMX requests
- Students <ul> gets id=rep-students as main swap target
- Filter buttons now target #rep-students instead of #repertoire-index
- Server sets $isOob=true when rendering HTMX partial responses
- Accordion re-init on swap no longer needed (headers never replaced)
- Scroll-restore updated to capture/restore per <ul> ID

Fading fixes:
- Restore rep-entry--faded class with simplified logic: any active
  filter fades entries whose matched flag is false (removed the
  $colHasMatch gate that prevented fading when a column had no matches)
- Add $noResults guard: when matched_ids is empty (zero theses match
  all active filters), force-fade all non-selected entries across ALL
  columns. This covers the keyword edge case where per-column matched
  is computed excluding the keyword filter (many-to-many), causing
  keywords to appear valid even though the full intersection is empty.
2026-07-10 12:59:12 +02:00
Pontoporeia f86deaf02f repertoire: remove matched-first sorting and faded/disabled system for filter entries
Remove the system that sorted valid (matched) filter entries to the top and
faded/disabled unmatched ones when any filter was active. Entries now stay in
their natural alphabetical/numeric order regardless of selection state.

- Drop usort calls that reordered entries by matched status
- Simplify repFilterEntry: remove anyActive and colHasMatch params
- Remove colHasMatches computation
- Remove rep-entry--faded CSS rule
- All filter buttons remain clickable at all times
2026-07-10 12:35:45 +02:00
Pontoporeia b9c7d6c663 fix: sort repertoire Années column reverse chronological (newest first) 2026-07-10 12:29:08 +02:00
Pontoporeia dae97ab812 fix: repertoire heading font sizes 2026-07-10 12:27:24 +02:00
Pontoporeia a8dcc4bba5 Consistent scrollbar styling across browsers
- colors.css: added --scrollbar-thumb, --scrollbar-thumb-hover, --scrollbar-track, --scrollbar-corner custom properties
- base.css: consolidated all scrollbar rules (WebKit ::-webkit-scrollbar* + Firefox scrollbar-width/color), added ::-webkit-scrollbar-corner, changed selector from * to html (scrollbar-width inherits), added scrollbar-gutter: stable
- admin.css: removed redundant scrollbar-width: thin on header nav
- toc.css: removed redundant scrollbar-width: thin on desktop .toc
2026-07-10 12:00:36 +02:00
Pontoporeia 08a9b7309f fix: locked_year cleared on edit — populate edit dialog field
The openEditDialog JS function didn't populate the locked_year input
in the edit dialog, and the PHP template didn't pass locked_year as an
argument. Any edit to a link (even just changing the name) would clear
the locked academic year to NULL.

- Pass $linkLockedYear as 5th argument to openEditDialog in the template
- Accept and populate edit-locked-year input in the JS handler
2026-07-10 11:56:27 +02:00
Pontoporeia 1025d99601 fix: use getThesis() instead of getThesisById() in share recap page
getThesisById() filters by is_published=1, but theses submitted
via share links are unpublished. The recap page after submission
was showing 'TFE introuvable' because it couldn't find the
just-created unpublished thesis.
2026-07-10 11:56:27 +02:00
Pontoporeia 28c0efe755 fix: masquer le bloc "Durée" sur la page TFE quand aucune durée n'est encodée 2026-07-10 11:56:27 +02:00
Pontoporeia b0925d9cfa Close TOC and Filtres details elements by default on mobile 2026-07-10 11:56:27 +02:00
Pontoporeia 56b3feb73f extend admin auth cookie lifetime from session-only to 1 week (604800s) 2026-07-10 11:56:27 +02:00
Pontoporeia 22a49f7cb6 fix: unify CSV import/export columns, fix import JS error, fix createThesis VALUES
- Fix createThesis SQL: extra ? placeholder in VALUES (27 values for 26 columns)
- Add createThesis integration tests to catch column/value mismatches
- Add CSV_COLUMNS as single source of truth in ExportController, deriving
  csvHeaders() and positional fallback from it
- Add missing columns to export query + CSV: duration_pages, duration_minutes,
  has_annexes, license_custom, contact_visible, objet
- Add missing columns to import INSERT: license_id, license_custom, cc2r,
  exemplaire_baiu, exemplaire_erg, objet, contact_visible, duration_pages,
  duration_minutes, has_annexes
- Resolve license name → license_id during import
- Fix XamxamInitFilePonds: add file-upload-filepond.js to admin-entry.js
  so FilePond initialization code is available on the admin list page
- Add FilePond vendor CSS to admin.min.css bundle (import dialog styling)
- Generate .admin-file-hint from csvHeaders() instead of hardcoded stale list
- Use positional fallback from CSV_COLUMNS for import cell parsing
2026-07-10 11:56:27 +02:00
Pontoporeia ce936e3b71 fix: various styling fixes; simplify tfe.php structure and CSS with grid 2026-07-10 11:56:27 +02:00
Pontoporeia 61029ea437 css: apropos special block styling 2026-07-09 14:45:03 +02:00
Pontoporeia 20873f94af pdf-viewer: various visual and usability changes
- fix page nav buttons, smaller default pages, violet bg

  - Build toolbar after renderAllPages so it queries existing canvases;
    query canvases fresh in the scroll handler so page tracking works
    after re-render (zoom in/out).
  - Default data-pdf-scale 0.85 (JS fallback 0.8) so pages are a bit
    smaller by default.
  - Add dark transparent violet background (accent-secondary 22%) to
    .pdf-expanded, behind the pages.

  - expand to fill column top-to-bottom via CSS flex

    Use a flex chain (.tfe-files flex:1, .tfe-file-item:has(.pdf-expanded)
    flex:1) so the expanded PDF wrapper fills the right column from under
    the header to the bottom of the viewport, instead of viewport-based
    clamp math that didn't account for the header height.

  - fill right column, center pages, freeze column on expand

  The expanded viewer now stays inside the right column instead of
  growing the page: the column switches to overflow:hidden while the
  PDF panel scrolls internally. Pages are centered horizontally via
  flexbox align-items: center.

  - fix toolbar not full-width, hide sibling file items

  The toolbar was constrained by the parent's align-items:center; fixed
  with align-self:stretch. Hiding sibling .tfe-file-item elements when
  a PDF is expanded prevents them from rendering above the overlay.

  - disable overscroll on expanded view

  - use overscroll-behavior-y on container, none on toolbar

  - disable body overscroll via .pdf-viewer-open class

  - mobile full-viewport, iframe matches pdf height

  - mobile overlay above everything via position:fixed

  - opaque dark-violet bg on mobile overlay

  - tfe: add 'Open in new tab' link above website iframes

  - trim column padding when expanded for more vertical space

  - 5% zoom increments, subtle padding on expanded column

  - prevent horizontal overflow/overscroll
2026-07-08 22:41:52 +02:00
Pontoporeia 82d8eff512 Fix lint: use IterableCallbackReturn — wrap forEach body in braces 2026-07-08 15:14:20 +02:00
Pontoporeia f6468c6d44 Always show durée and annexes fields in recapitulatif and public TFE pages
Previously these fields were conditionally hidden when empty, making
  it unclear whether the data was simply not entered. Now they always
  display: durée shows '–' when no data, annexes shows 'Non'.
2026-07-08 15:05:35 +02:00
Pontoporeia 6ecab96137 fieldset-academic: dim locked year field, remove required asterisk
When locked_year is set, render the Année label+input inline with
opacity:0.55 instead of via text-field.php. No asterisk since editing
is disabled. The hidden input still ensures the value is submitted.
2026-07-08 13:50:03 +02:00
Pontoporeia f9d8fab120 partage: lock Année field to link's locked_year when present
When a student-access share link specifies a locked_year, the Année field
in the student-facing form is now pre-filled with that year and rendered
as disabled+readonly, with a hidden input ensuring the value is submitted.

- renderShareLinkForm() exposes  from ['locked_year']
- fieldset-academic.php checks for : if set, outputs a hidden
  input plus the visible field locked to that value; otherwise falls back
  to the normal editable field
2026-07-08 13:50:03 +02:00
Pontoporeia a3953800a4 Move annexes checkbox from Fichiers fieldset to Durée fieldset 2026-07-08 13:50:03 +02:00
Pontoporeia 912b38583b Add --quiet flag to build.mjs for cleaner 'just dev' output 2026-07-08 13:50:03 +02:00
Pontoporeia 033ea90684 Fix lint warnings: arrow functions in admin-acces.js, duplicate gap in admin.css, biome formatting 2026-07-08 13:50:03 +02:00
Pontoporeia 402799a412 Fix remaining JS functions missing from window global scope 2026-07-08 13:50:03 +02:00
Pontoporeia 83287cdcd8 Expose tag/langue/motscles JS functions on window to survive ESM tree-shaking 2026-07-08 13:50:03 +02:00
Pontoporeia 8e67b9c155 admin toc: label rename + padding
- rename 'Sur cette page' to 'Parties'
- add padding-top between PARTIES label and toc links
2026-07-08 13:49:36 +02:00
Pontoporeia 30f901f1ed fix: various padding, layouts and visual issues
- fixed padding in the tfe.php page
- fixed the layout in admin/index.php toolbar top
- the gap issued with the table theader
- rearranged button order in the toolbar top
2026-07-08 13:09:35 +02:00
Pontoporeia a4cfe4356f chore: add explicit spacing to cleanup page article and h1 2026-07-07 19:53:35 +02:00
Pontoporeia 3eb8ec9075 feat: add padding-bottom to tfe left column for synopsis breathing room 2026-07-07 19:04:40 +02:00
Pontoporeia 58fb4142b7 relabel: Promoteur·ice ULB → Promoteur·ice université in all UI labels
Pure label change across 6 template/controller files — no DB schema change.
Migration 043 added to track the change.
2026-07-06 19:51:42 +02:00
Pontoporeia 6573dd5452 tfe: add scrollbar=0 to PDF iframe embed params 2026-07-06 19:51:42 +02:00
Pontoporeia fa6d19f767 tfe: rework desktop layout to 35/65 flex columns, independent scrolling, no horizontal overflow
Switched from grid to flex for two-column layout
Left column (flex: 0 0 35%): author, title, meta, synopsis — scrolls independently  
Right column (flex: 1): files/media — scrolls independently
Added .tfe-file-iframe class to PDF/website iframes, scoped width/height constraints
All media gets width:100% + max-width:100% to prevent overflow
Mobile (<900px): reverts to single-column page-level scrolling
2026-07-06 19:51:42 +02:00
Pontoporeia 0979267c68 stretch heading scale (h1→step-5, h3→step-1) + reduce heading bottom margin (space-l → space-m) 2026-07-06 19:51:20 +02:00
Pontoporeia 148ffe79f0 fix: search bar icon/placeholder overlap caused by specificity conflict
The base input rule uses a high-specificity :not() chain (0,8,1) that
overpowered .header-search-input-wrap input (0,1,1). The base padding
won, so the search input's padding-left (which makes room for the icon)
was overridden. Switched to #site-search-input (1,0,0) to win the
specificity battle.
2026-07-05 15:00:47 +02:00
Pontoporeia 10df92b643 fix: load autosave-handler.js on about_page edit view, persist contact group deletion
Two fixes:

1. about_page edit was missing autosave-handler.js: the first if block
   (editType === 'page' || 'about_page') overrode $extraJs with only
   overtype.min.js, making the elseif that added autosave-handler.js
   unreachable for about_page. Added autosave-handler.js to the first
   block, removed dead 'about_page' from the elseif.

2. Deleting a contact group (Contacts 3/4/5) only removed the DOM
   element but never triggered htmx autosave. Dispatched a 'change'
   event on the form after removal+reindex so the hx-trigger fires.

Also expanded autosave-handler.js URL filter to accept apropos.php
so the status indicator (Enregistrement/Enregistré) works for contacts saves.
2026-07-05 14:14:13 +02:00
Pontoporeia 1e714982d3 fix: restore contact_interne/contact_public column names in v_theses_full
Migration 041 accidentally renamed contact_interne → author_email and
contact_public → author_show_contact, but all application code still
references the old names. Migration 042 rebuilds the views with the
correct column aliases. Also updated schema.sql to match.
2026-07-05 14:04:29 +02:00
Pontoporeia 8e309bbcb7 Remove public contact visibility checkbox from admin add/edit forms 2026-07-05 14:04:29 +02:00
Pontoporeia ec6c939f4e Fix CC2r: uncheck not persisting + want_license hiding cc2r when active
Issue 1 — hidden seeds overriding user input:
Removed all hidden seed inputs (cc2r, want_license, license_id,
license_custom). The .licence-license-choice div is now rendered
directly from $formData on page load instead of via HTMX load
trigger. This eliminates stale-seed interference on both HTMX
radio changes and full form submits.

Issue 2 — Interne want_license uncheck clearing CC2r:
When want_license is unchecked, CC2r and licence selections are
cleared (section hidden). Added hidden want_license=0 so the
fragment handler can distinguish "arriving from another access
type" (no want_license in POST → preserve values) from "explicit
Interne toggle" (want_license present → clear CC2r if off).

CC2r is independently toggleable within the visible section.
Licence dropdown placeholder changed to 'Aucune licence' for
an explicit no-licence choice.
2026-07-05 14:04:05 +02:00
Pontoporeia 83e9dd0bc2 structure-formulaire.php: replace ← text back link with arrow-left-circle icon + admin-back-btn class 2026-07-05 12:51:44 +02:00
Pontoporeia 3c845f9d40 acces.php: remove Mot de passe column, add key icon copy button, reorder actions, switch URL icon to link-simple; fix dialog functions not on window; fix archive: move form into dialog (native submit); add caret icon to archived links details 2026-07-05 12:05:53 +02:00
Pontoporeia 3e93150c76 justfile: standardise test recipes to lint-php/lint-css/lint-js/test + add fix recipe
- Removed ambiguous aliases: phpstan, cs-check, syntax
- Split lint-biome into lint-css and lint-js with correct paths
- Added lint meta-recipe and fix recipe (biome --unsafe + php-cs-fixer)
- Fixed FormBootstrap dead null check, CSS shorthand override bug
- Updated phpstan baseline, suppressed noDescendingSpecificity/noInnerDeclarations
- Applied ~74 biome auto-fixes across CSS/JS
2026-07-05 11:07:41 +02:00
Pontoporeia 34b5d3e585 justfile: standardise test recipes to lint-php/lint-css/lint-js/test + add fix recipe
- Removed ambiguous aliases: phpstan, cs-check (both pointed to lint-php which
  also ran php-cs-fixer, making the names misleading)
- Removed syntax (php -l) — redundant, phpstan already catches parse errors
- Split lint-biome into lint-css and lint-js with correct paths
- Added lint meta-recipe that runs all three linters
- Added fix recipe: biome check --write (CSS/JS format+lint) + php-cs-fixer fix (PHP)
- Updated build-lint to delegate to lint-css + lint-js
2026-07-05 10:50:42 +02:00