Index page: remove Mots-clés button, move export to bulk selection, fix ZipArchive error, move DB export to paramètres, sticky thead

- Remove 'Mots-clés' button from toolbar (redundant with admin sidebar tags)
- Replace export dialog with 'Exporter CSV' + 'Exporter fichiers' buttons in bulk selection bar
- Export dispatcher now accepts ?ids=1,2,3 for per-selection export
- All ExportController/Database methods accept optional thesisIds array
- Graceful error message when ZipArchive extension is missing on server
- Move DB export (SQLite download) to paramètres → Maintenance section
- Sticky table column headers (position: sticky, top: 0, z-index: 5) for index page table
This commit is contained in:
Pontoporeia
2026-05-19 19:05:28 +02:00
parent b484943128
commit 678f9fc804
8 changed files with 148 additions and 86 deletions

View File

@@ -40,16 +40,17 @@ class ExportController
// ── Files export ────────────────────────────────────────────────────
/**
* Fetch all thesis file records with their thesis identifier.
* Fetch thesis file records with their thesis identifier.
*
* @param int[] $thesisIds Optional filter by thesis IDs.
* @return list<array{id:int, thesis_id:int, identifier:?string, file_type:string,
* file_path:string, file_name:string, file_size:?int,
* mime_type:?string, description:?string, sort_order:int,
* display_label:?string, file_hash:?string}>
*/
public function getAllThesisFiles(): array
public function getAllThesisFiles(array $thesisIds = []): array
{
return $this->db->getAllThesisFilesForExport();
return $this->db->getAllThesisFilesForExport($thesisIds);
}
/**
@@ -58,12 +59,13 @@ class ExportController
* The manifest maps identifier → { title, files: [{type, path, name, size, mime, hash, label}] }
* and is used on restore to re-link files to DB records.
*
* @param int[] $thesisIds Optional filter by thesis IDs.
* @return array
*/
public function buildExportManifest(): array
public function buildExportManifest(array $thesisIds = []): array
{
$files = $this->getAllThesisFiles();
$theses = $this->db->getAllThesesForExport();
$files = $this->getAllThesisFiles($thesisIds);
$theses = $this->db->getAllThesesForExport($thesisIds);
// Index theses by id for O(1) lookup
$byId = [];
@@ -115,17 +117,18 @@ class ExportController
* Returns the path to the temporary zip file. Caller is responsible
* for unlink() after streaming.
*
* @param int[] $thesisIds Optional filter by thesis IDs.
* @param string|null $baseDir Base directory path for files inside the zip.
* Defaults to "files" (so files are at "files/theses/...").
* @return string Absolute path to the generated zip file.
* @throws Exception if zip creation fails.
*/
public function createExportZip(?string $baseDir = null): string
public function createExportZip(array $thesisIds = [], ?string $baseDir = null): string
{
$baseDir ??= 'files';
$storageRoot = defined('STORAGE_ROOT') ? STORAGE_ROOT : APP_ROOT . '/storage';
$files = $this->getAllThesisFiles();
$manifest = $this->buildExportManifest();
$files = $this->getAllThesisFiles($thesisIds);
$manifest = $this->buildExportManifest($thesisIds);
$tmpPath = tempnam(sys_get_temp_dir(), 'xamxam-export-');
if ($tmpPath === false) {
@@ -214,12 +217,13 @@ class ExportController
*
* Uses batch queries (one per related table) to avoid N+1.
*
* @param int[] $thesisIds Optional filter by thesis IDs.
* @return list<list<string>> Each inner list has CSV_HEADERS_COUNT elements.
*/
public function exportAllTheses(): array
public function exportAllTheses(array $thesisIds = []): array
{
// 1) Base thesis data (includes license_name via migration; fallback to license_type from the view)
$theses = $this->db->getAllThesesForExport();
$theses = $this->db->getAllThesesForExport($thesisIds);
if ($theses === []) {
return [];
}