fix : bouton desactivé pendant le téléchargement + plus de abort

This commit is contained in:
Alexis Burnaz 2025-12-22 12:24:30 +01:00
parent 5de492b308
commit 0a536140ab
2 changed files with 84 additions and 8 deletions

View File

@ -229,4 +229,12 @@ td.nc-value {
} }
#historiqueParcours tr.shown > td { background: #fffdf5; } #historiqueParcours tr.shown > td { background: #fffdf5; }
.parcours-details { font-size: 0.95rem; } .parcours-details { font-size: 0.95rem; }
/* Style pour les boutons d'export désactivés */
#divBtnFilter button:disabled {
opacity: 0.5 !important;
cursor: not-allowed !important;
pointer-events: none !important;
}

View File

@ -18,8 +18,30 @@ document.addEventListener("DOMContentLoaded", async function () {
// Initialiser DataTables en mode server-side (obligé pour pagination) // Initialiser DataTables en mode server-side (obligé pour pagination)
const table = initServerSideDataTable(); const table = initServerSideDataTable();
// Variable pour suivre l'état des exports
let isExporting = false;
// Fonction pour désactiver/activer les boutons d'export
function setExportButtonsState(disabled) {
isExporting = disabled;
const buttons = ["#exportCSV", "#exportCSVFilter", "#exportXlxs", "#exportXlxsFilter"];
buttons.forEach(selector => {
const $btn = $(selector);
$btn.prop("disabled", disabled);
if (disabled) {
$btn.css("opacity", "0.5");
$btn.css("cursor", "not-allowed");
} else {
$btn.css("opacity", "1");
$btn.css("cursor", "pointer");
}
});
}
// Exports CSV/XLSX // Exports CSV/XLSX
$("#exportCSV").on("click", function () { $("#exportCSV").on("click", function () {
if (isExporting) return;
const dt = $("#historiqueParcours").DataTable(); const dt = $("#historiqueParcours").DataTable();
if (!dt) { if (!dt) {
displayError("Impossible d'accéder à la table de données."); displayError("Impossible d'accéder à la table de données.");
@ -32,6 +54,8 @@ document.addEventListener("DOMContentLoaded", async function () {
return; return;
} }
setExportButtonsState(true);
const payload = { const payload = {
mode: "full", // export total mode: "full", // export total
search: { value: "" }, search: { value: "" },
@ -62,12 +86,18 @@ document.addEventListener("DOMContentLoaded", async function () {
a.click(); a.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
a.remove(); a.remove();
setExportButtonsState(false);
}) })
.catch(() => displayError("Export CSV (complet) impossible")); .catch((err) => {
displayError("Export CSV (complet) impossible");
setExportButtonsState(false);
});
}); });
$("#exportCSVFilter").on("click", function () { $("#exportCSVFilter").on("click", function () {
if (isExporting) return;
const dt = $("#historiqueParcours").DataTable(); const dt = $("#historiqueParcours").DataTable();
if (!dt) { if (!dt) {
displayError("Impossible d'accéder à la table de données."); displayError("Impossible d'accéder à la table de données.");
@ -80,6 +110,8 @@ document.addEventListener("DOMContentLoaded", async function () {
return; return;
} }
setExportButtonsState(true);
const payload = { const payload = {
mode: "filtered", // export avec les filtres/colonnes/tri actuels mode: "filtered", // export avec les filtres/colonnes/tri actuels
search: { value: dt.search() || "" }, // recherche globale search: { value: dt.search() || "" }, // recherche globale
@ -108,12 +140,18 @@ document.addEventListener("DOMContentLoaded", async function () {
a.click(); a.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
a.remove(); a.remove();
setExportButtonsState(false);
}) })
.catch(() => displayError("Export CSV (filtré) impossible")); .catch((err) => {
displayError("Export CSV (filtré) impossible");
setExportButtonsState(false);
});
}); });
$("#exportXlxs").on("click", function () { $("#exportXlxs").on("click", function () {
if (isExporting) return;
const dt = $("#historiqueParcours").DataTable(); const dt = $("#historiqueParcours").DataTable();
if (!dt) { if (!dt) {
displayError("Impossible d'accéder à la table de données."); displayError("Impossible d'accéder à la table de données.");
@ -126,6 +164,8 @@ document.addEventListener("DOMContentLoaded", async function () {
return; return;
} }
setExportButtonsState(true);
const payload = { const payload = {
mode: "full", mode: "full",
search: { value: "" }, search: { value: "" },
@ -145,12 +185,18 @@ document.addEventListener("DOMContentLoaded", async function () {
a.href = url; a.download = "historique_parcours_complet.xls"; a.href = url; a.download = "historique_parcours_complet.xls";
document.body.appendChild(a); a.click(); document.body.appendChild(a); a.click();
URL.revokeObjectURL(url); a.remove(); URL.revokeObjectURL(url); a.remove();
setExportButtonsState(false);
}) })
.catch(() => displayError("Export XLS (complet) impossible")); .catch((err) => {
displayError("Export XLS (complet) impossible");
setExportButtonsState(false);
});
}); });
$("#exportXlxsFilter").on("click", function () { $("#exportXlxsFilter").on("click", function () {
if (isExporting) return;
const dt = $("#historiqueParcours").DataTable(); const dt = $("#historiqueParcours").DataTable();
if (!dt) { if (!dt) {
displayError("Impossible d'accéder à la table de données."); displayError("Impossible d'accéder à la table de données.");
@ -163,6 +209,8 @@ document.addEventListener("DOMContentLoaded", async function () {
return; return;
} }
setExportButtonsState(true);
const payload = { const payload = {
mode: "filtered", // export avec les filtres/colonnes/tri actuels mode: "filtered", // export avec les filtres/colonnes/tri actuels
search: { value: dt.search() || "" }, // recherche globale search: { value: dt.search() || "" }, // recherche globale
@ -191,8 +239,12 @@ document.addEventListener("DOMContentLoaded", async function () {
a.click(); a.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
a.remove(); a.remove();
setExportButtonsState(false);
}) })
.catch(() => displayError("Export XLS (filtré) impossible")); .catch((err) => {
displayError("Export XLS (filtré) impossible");
setExportButtonsState(false);
});
}); });
@ -243,21 +295,29 @@ function initServerSideDataTable() {
search: data.search || { value: "" }, search: data.search || { value: "" },
}; };
if (inflightController) inflightController.abort(); // action en cours if (inflightController) inflightController.abort(); // action en cours
inflightController = new AbortController(); inflightController = new AbortController();
const currentController = inflightController;
fetch("/historiqueParcours/datatable", { fetch("/historiqueParcours/datatable", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(body), body: JSON.stringify(body),
signal: inflightController.signal, signal: currentController.signal,
}) })
.then(res => { .then(res => {
// Vérifier si la requête a été annulée
if (currentController.signal.aborted || inflightController !== currentController) {
return null;
}
if (!res.ok) throw new Error(`HTTP ${res.status}`); if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json(); return res.json();
}) })
.then(payload => { .then(payload => {
// Vérifier si la requête a été annulée
if (currentController.signal.aborted || inflightController !== currentController) {
return;
}
if (!payload || typeof payload !== 'object') { if (!payload || typeof payload !== 'object') {
throw new Error("Réponse invalide du serveur"); throw new Error("Réponse invalide du serveur");
} }
@ -269,7 +329,15 @@ function initServerSideDataTable() {
}); });
}) })
.catch(err => { .catch(err => {
if (err && err.name === "AbortError") return; // Ignorer silencieusement toutes les erreurs d'abort
if (err && (err.name === "AbortError" || err.name === "DOMException")) {
return;
}
// Vérifier aussi si le signal a été aborted
if (currentController.signal.aborted || inflightController !== currentController) {
return;
}
// Seulement afficher une erreur si ce n'est PAS un abort
displayError("Failed to fetch data. Please try again later."); displayError("Failed to fetch data. Please try again later.");
callback({ draw: 0, recordsTotal: 0, recordsFiltered: 0, data: [] }); callback({ draw: 0, recordsTotal: 0, recordsFiltered: 0, data: [] });
}); });