From 7c30d1c55d4dbed7664293c91e41adfd24a2e446 Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Tue, 19 May 2026 01:13:39 +0200 Subject: [PATCH] Fix relink: close modal + HTMX refresh for immediate pool update - After relink, always close the modal (even if FilePond input not found, e.g. page refreshed by live-reload during the fetch). - After closing, re-fetch #format-fichiers-block via HTMX from /admin/fragments/fichiers.php?_thesis_id=N which loads thesis files from DB and re-renders the fragment with pre-populated FilePond pools. The afterSwap handler auto-reinitializes FilePond instances. - Updated admin/fragments/fichiers.php to accept _thesis_id, load existing files from DB, build per-queue-type JSON, and render in edit mode. --- TODO.md | 2 + app/public/admin/fragments/fichiers.php | 46 +++++++++++++++++++ .../assets/js/app/file-upload-filepond.js | 34 ++++++++++---- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index 6bf8a92..05f0d20 100644 --- a/TODO.md +++ b/TODO.md @@ -31,6 +31,8 @@ - [x] CSS: .relink-modal + .file-browser styles in form.css - [x] Fix: relinked file not appearing in FilePond pool — add file metadata to addFile() options and extensive diag logging - [x] Fix: addFile called with single object instead of (source, options) — FilePond API mismatch prevented files from loading +- [x] Fix: use type 'limbo' for relinked files so they go through DID_COMPLETE_ITEM_PROCESSING → onprocessfile → syncOrderInput + green checkmark visual +- [x] Fix: change .filepond--file default border from yellow to green (existing files never reach processing-complete state) - [ ] Migration: rename existing theses/ directories to documents/ on disk and update DB paths ## Trash policy diff --git a/app/public/admin/fragments/fichiers.php b/app/public/admin/fragments/fichiers.php index 365ef74..1115fd6 100644 --- a/app/public/admin/fragments/fichiers.php +++ b/app/public/admin/fragments/fichiers.php @@ -1,13 +1,59 @@ getThesisFiles($thesisId); + + // Build per-queue-type existing-files JSON for FilePond edit mode + $buildQueueFilesJson = function (array $files, string $queueType): array { + $result = []; + foreach ($files as $f) { + $ft = $f['file_type'] ?? ''; + $fp = $f['file_path'] ?? ''; + if (str_starts_with($fp, 'http://') || str_starts_with($fp, 'https://')) continue; + if ($queueType === 'cover' && $ft !== 'cover') continue; + if ($queueType === 'note_intention' && $ft !== 'note_intention') continue; + if ($queueType === 'tfe' && ($ft === 'cover' || $ft === 'note_intention' || $ft === 'annex')) continue; + if ($queueType === 'annexe' && $ft !== 'annex') continue; + $result[] = [ + 'source' => (string)((int)$f['id']), + 'options' => [ + 'type' => 'local', + 'file' => [ + 'name' => $f['file_name'] ?? basename($f['file_path'] ?? ''), + 'size' => (int)($f['file_size'] ?? 0), + 'type' => $f['mime_type'] ?? 'application/octet-stream', + ], + ], + ]; + } + return $result; + }; + + $existingFilesJsonForCover = $buildQueueFilesJson($currentFiles, 'cover'); + $existingFilesJsonForNoteIntention = $buildQueueFilesJson($currentFiles, 'note_intention'); + $existingFilesJsonForTfe = $buildQueueFilesJson($currentFiles, 'tfe'); + $existingFilesJsonForAnnexe = $buildQueueFilesJson($currentFiles, 'annexe'); + + $_POST['edit_mode'] = '1'; +} + require_once APP_ROOT . '/templates/partials/form/fichiers-fragment.php'; diff --git a/app/public/assets/js/app/file-upload-filepond.js b/app/public/assets/js/app/file-upload-filepond.js index 694f096..42f2de2 100644 --- a/app/public/assets/js/app/file-upload-filepond.js +++ b/app/public/assets/js/app/file-upload-filepond.js @@ -629,15 +629,33 @@ } console.log('[relink] success | new_id=' + data.id); - // Add the new file to the FilePond pool + // Add the new file to the FilePond pool, then close the modal. + // If the DOM was replaced (e.g. live-reload), refresh the + // form fragment via HTMX so the server re-renders the pools + // with the newly-linked file included. var input = document.querySelector(`.tfe-file-picker[data-queue-type="${queueType}"]`); console.log('[relink] looking for input | selector=' + `.tfe-file-picker[data-queue-type="${queueType}"]` + ' | found=' + !!input); + var closeAndRefresh = function() { + var modal = document.getElementById('relink-modal'); + if (modal) modal.close(); + // Re-fetch the fichiers fragment from the server so the + // newly-linked file appears in the FilePond pools. + var block = document.getElementById('format-fichiers-block'); + if (block && window.htmx) { + var url = '/admin/fragments/fichiers.php'; + if (window.__xamxamRelinkCtx && window.__xamxamRelinkCtx.thesisId) { + url += '?_thesis_id=' + encodeURIComponent(window.__xamxamRelinkCtx.thesisId); + } + htmx.ajax('GET', url, { + target: '#format-fichiers-block', + swap: 'outerHTML' + }); + } + }; if (input) { var pond = FilePond.find(input); console.log('[relink] looking for pond | found=' + !!pond); if (pond) { - // Add as LIMBO to trigger server.load, which returns the actual file blob + headers. - // type: 'local' with file metadata skips load and may not render correctly. pond.addFile(String(data.id), { type: 'limbo', file: { @@ -647,18 +665,18 @@ } }).then(function() { console.log('[relink] addFile resolved | source=' + String(data.id) + ' | queueType=' + queueType); - // Close modal after file is added to the pond. - // syncOrderInput fires via onprocessfile / onupdatefiles. - var modal = document.getElementById('relink-modal'); - if (modal) modal.close(); + closeAndRefresh(); }).catch(function(err) { console.error('[relink] addFile rejected', err); + closeAndRefresh(); }); } else { console.error('[relink] FilePond.find returned null for input', input); + closeAndRefresh(); } } else { - console.error('[relink] input not found | queueType=' + queueType); + console.warn('[relink] input not found, page may have reloaded | queueType=' + queueType); + closeAndRefresh(); } // Mark form dirty