From c2fd2dc470bcfa89b02acb327a4a070c6f4e4eb3 Mon Sep 17 00:00:00 2001 From: solocla Date: Fri, 17 Jul 2026 10:46:33 +0200 Subject: [PATCH] fixed export and save to selection --- public/userarea/clone_parts_to_visible.php | 23 ++ public/userarea/exportLims_gridData.js | 417 +++++++++++++++------ public/userarea/modal_partsTable.php | 6 + public/userarea/partsTable.js | 18 +- public/userarea/saveAll.js | 118 ++++-- 5 files changed, 423 insertions(+), 159 deletions(-) diff --git a/public/userarea/clone_parts_to_visible.php b/public/userarea/clone_parts_to_visible.php index 23a4f3a..a2a9222 100644 --- a/public/userarea/clone_parts_to_visible.php +++ b/public/userarea/clone_parts_to_visible.php @@ -14,6 +14,7 @@ $targetList = $data['target_iddatadb_list'] ?? []; // (comportamento di default richiesto, coerente con la checkbox pre-spuntata) $cloneNotes = array_key_exists('clone_notes', $data) ? !empty($data['clone_notes']) : true; $cloneAnalyses = !empty($data['clone_analyses']); +$overwrite = !empty($data['overwrite']); $targetIds = array_values(array_unique(array_filter(array_map('intval', (array)$targetList), function ($v) use ($sourceIddatadb) { return $v > 0 && $v !== $sourceIddatadb; @@ -93,6 +94,28 @@ try { $details = []; $totalClonedParts = 0; $totalClonedAnalyses = 0; + $totalDeletedParts = 0; + + // 2b. Se overwrite: elimina le parti esistenti dei target (e i loro figli) + if ($overwrite) { + $stmtSelectExisting = $pdo->prepare("SELECT id FROM identification_parts WHERE iddatadb = ?"); + $stmtDeleteCFByPart = $pdo->prepare("DELETE FROM identification_parts_customfields WHERE part_id = ?"); + $stmtDeleteAnByPart = $pdo->prepare("DELETE FROM identification_parts_analyses WHERE part_id = ?"); + $stmtDeletePart = $pdo->prepare("DELETE FROM identification_parts WHERE id = ?"); + + foreach ($targetIds as $targetIddatadb) { + $stmtSelectExisting->execute([$targetIddatadb]); + $existingIds = $stmtSelectExisting->fetchAll(PDO::FETCH_COLUMN); + + foreach ($existingIds as $existingPartId) { + $existingPartId = (int)$existingPartId; + $stmtDeleteCFByPart->execute([$existingPartId]); + $stmtDeleteAnByPart->execute([$existingPartId]); + $stmtDeletePart->execute([$existingPartId]); + $totalDeletedParts++; + } + } + } // 3. Clone source parts to each target record foreach ($targetIds as $targetIddatadb) { diff --git a/public/userarea/exportLims_gridData.js b/public/userarea/exportLims_gridData.js index 3c1730a..44bb57a 100644 --- a/public/userarea/exportLims_gridData.js +++ b/public/userarea/exportLims_gridData.js @@ -5,7 +5,7 @@ * Single export + batch export (Export All) with validation. */ (function () { - 'use strict'; + "use strict"; let pendingConfirmHandler = null; let batchRunning = false; @@ -17,7 +17,7 @@ // ── Helpers ────────────────────────────────────────────────────────── function cleanupBackdrop() { - document.querySelectorAll(".modal-backdrop").forEach(b => b.remove()); + document.querySelectorAll(".modal-backdrop").forEach((b) => b.remove()); document.body.classList.remove("modal-open"); document.body.style.paddingRight = ""; const overlay = document.querySelector(".overlay.toggle-icon"); @@ -29,7 +29,9 @@ } function getRowIndexByIddatadb(iddatadb) { - return (window.gridData || []).findIndex(r => String(r.iddatadb) === String(iddatadb)); + return (window.gridData || []).findIndex( + (r) => String(r.iddatadb) === String(iddatadb), + ); } // ── Validation ────────────────────────────────────────────────────── @@ -40,21 +42,31 @@ headers: { "Content-Type": "application/json" }, body: JSON.stringify({ rows: rowsToValidate }), }); - if (!response.ok) throw new Error(`Validation HTTP error: ${response.status}`); + if (!response.ok) + throw new Error(`Validation HTTP error: ${response.status}`); return response.json(); } function clearValidationErrors() { // Clear from gridData - (window.gridData || []).forEach(row => { delete row._validationErrors; delete row._exportError; }); - - document.querySelectorAll(".grid-cell.validation-error").forEach(cell => { - cell.classList.remove("validation-error"); - cell.querySelectorAll(".input-validation-error").forEach(el => el.classList.remove("input-validation-error")); - const tooltip = cell.querySelector(".validation-tooltip"); - if (tooltip) tooltip.remove(); + (window.gridData || []).forEach((row) => { + delete row._validationErrors; + delete row._exportError; }); - document.querySelectorAll(".grid-row.validation-row-error").forEach(row => row.classList.remove("validation-row-error")); + + document + .querySelectorAll(".grid-cell.validation-error") + .forEach((cell) => { + cell.classList.remove("validation-error"); + cell.querySelectorAll(".input-validation-error").forEach((el) => + el.classList.remove("input-validation-error"), + ); + const tooltip = cell.querySelector(".validation-tooltip"); + if (tooltip) tooltip.remove(); + }); + document + .querySelectorAll(".grid-row.validation-row-error") + .forEach((row) => row.classList.remove("validation-row-error")); clearAllRowErrors(); } @@ -67,7 +79,7 @@ gridRow.classList.add("validation-row-error"); const messages = []; - errors.forEach(err => { + errors.forEach((err) => { messages.push(err.message); if (!err.field) return; @@ -76,19 +88,26 @@ const label = err.field.substring("field_label:".length); const headers = document.querySelectorAll(".grid-header"); let targetIndex = null; - headers.forEach(h => { - if (h.textContent.trim() === label) targetIndex = h.getAttribute("data-index"); + headers.forEach((h) => { + if (h.textContent.trim() === label) + targetIndex = h.getAttribute("data-index"); }); if (targetIndex) { - cell = gridRow.querySelector(`.grid-cell[data-index="${targetIndex}"]`); + cell = gridRow.querySelector( + `.grid-cell[data-index="${targetIndex}"]`, + ); } } else { - cell = gridRow.querySelector(`.grid-cell[data-col="${err.field}"]`); + cell = gridRow.querySelector( + `.grid-cell[data-col="${err.field}"]`, + ); } if (cell) { cell.classList.add("validation-error"); - cell.querySelectorAll("input, select").forEach(el => el.classList.add("input-validation-error")); + cell.querySelectorAll("input, select").forEach((el) => + el.classList.add("input-validation-error"), + ); let tooltip = cell.querySelector(".validation-tooltip"); if (!tooltip) { tooltip = document.createElement("div"); @@ -109,34 +128,43 @@ formData.append("iddatadb", iddatadb); if (batchUuid) formData.append("batch_uuid", batchUuid); - const response = await fetch("export_to_lims.php", { method: "POST", body: formData }); - if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); + const response = await fetch("export_to_lims.php", { + method: "POST", + body: formData, + }); + if (!response.ok) + throw new Error(`HTTP error! status: ${response.status}`); const data = await response.json(); if (data.success) { // Update gridData const idx = getRowIndexByIddatadb(iddatadb); if (idx >= 0) { - window.gridData[idx].status = 'l'; + window.gridData[idx].status = "l"; window.gridData[idx].commessaweb = data.commessaweb; } // Update visible DOM row const gridRow = getGridRow(iddatadb); if (gridRow) { - const statusBadge = gridRow.querySelector('.grid-cell[data-col="status"] .status-badge'); + const statusBadge = gridRow.querySelector( + '.grid-cell[data-col="status"] .status-badge', + ); if (statusBadge) { statusBadge.classList.remove("status-i", "status-P"); statusBadge.classList.add("status-l"); statusBadge.textContent = "To LIMS"; } - const statusCell = gridRow.querySelector('.grid-cell[data-col="status"]'); + const statusCell = gridRow.querySelector( + '.grid-cell[data-col="status"]', + ); if (statusCell && data.commessaweb) { let cwSpan = statusCell.querySelector(".commessaweb-code"); if (!cwSpan) { cwSpan = document.createElement("span"); cwSpan.className = "commessaweb-code"; - cwSpan.style.cssText = "display:block; font-size:0.75em; color:#555; margin-top:2px;"; + cwSpan.style.cssText = + "display:block; font-size:0.75em; color:#555; margin-top:2px;"; statusCell.appendChild(cwSpan); } cwSpan.textContent = data.commessaweb; @@ -164,7 +192,8 @@ const label = document.getElementById("exportResponseModalLabel"); if (data.success) { - msg.innerHTML = `${data.message.replace(/\n/g, "
")}` + + msg.innerHTML = + `${data.message.replace(/\n/g, "
")}` + `
ID CommessaWeb: ${data.idcommessaweb}` + `
Codice CommessaWeb: ${data.commessaweb}` + (data.totalPhotos > 0 ? `
Foto: ${data.totalPhotos}` : ""); @@ -186,10 +215,14 @@ row.classList.remove("batch-disabled"); row.classList.add("batch-exporting"); if (btnCell) { - btnCell.querySelectorAll(".action-btn").forEach(b => { b.dataset.prevDisplay = b.style.display; b.style.display = "none"; }); + btnCell.querySelectorAll(".action-btn").forEach((b) => { + b.dataset.prevDisplay = b.style.display; + b.style.display = "none"; + }); const spinner = document.createElement("span"); spinner.className = "batch-row-spinner"; - spinner.innerHTML = ' Exporting...'; + spinner.innerHTML = + ' Exporting...'; btnCell.appendChild(spinner); } } else { @@ -197,7 +230,10 @@ if (btnCell) { const spinner = btnCell.querySelector(".batch-row-spinner"); if (spinner) spinner.remove(); - btnCell.querySelectorAll(".action-btn").forEach(b => { b.style.display = b.dataset.prevDisplay || ""; delete b.dataset.prevDisplay; }); + btnCell.querySelectorAll(".action-btn").forEach((b) => { + b.style.display = b.dataset.prevDisplay || ""; + delete b.dataset.prevDisplay; + }); } } } @@ -213,32 +249,56 @@ errorEl.className = "batch-error-msg"; errorEl.textContent = "Warning — click for details"; errorEl.addEventListener("click", () => { - document.getElementById("exportResponseMessage").innerHTML = message.replace(/\n/g, "
"); - document.getElementById("exportResponseModalLabel").textContent = "Error (id: " + iddatadb + ")"; - new bootstrap.Modal(document.getElementById("exportResponseModal"), { keyboard: false }).show(); + document.getElementById("exportResponseMessage").innerHTML = + message.replace(/\n/g, "
"); + document.getElementById( + "exportResponseModalLabel", + ).textContent = "Error (id: " + iddatadb + ")"; + new bootstrap.Modal( + document.getElementById("exportResponseModal"), + { keyboard: false }, + ).show(); }); btnCell.appendChild(errorEl); } } function clearAllRowErrors() { - document.querySelectorAll(".grid-row.batch-row-error").forEach(row => { - row.classList.remove("batch-row-error"); - const msg = row.querySelector(".batch-error-msg"); - if (msg) msg.remove(); - }); + document + .querySelectorAll(".grid-row.batch-row-error") + .forEach((row) => { + row.classList.remove("batch-row-error"); + const msg = row.querySelector(".batch-error-msg"); + if (msg) msg.remove(); + }); } function disableAllRowButtons() { - document.querySelectorAll(".grid-row[data-id]").forEach(row => row.classList.add("batch-disabled")); - const toggle = document.querySelector(".actions-dropdown .dropdown-toggle"); - if (toggle) { toggle.disabled = true; toggle.style.opacity = "0.5"; toggle.style.pointerEvents = "none"; } + document + .querySelectorAll(".grid-row[data-id]") + .forEach((row) => row.classList.add("batch-disabled")); + const toggle = document.querySelector( + ".actions-dropdown .dropdown-toggle", + ); + if (toggle) { + toggle.disabled = true; + toggle.style.opacity = "0.5"; + toggle.style.pointerEvents = "none"; + } } function enableAllRowButtons() { - document.querySelectorAll(".grid-row[data-id]").forEach(row => row.classList.remove("batch-disabled")); - const toggle = document.querySelector(".actions-dropdown .dropdown-toggle"); - if (toggle) { toggle.disabled = false; toggle.style.opacity = ""; toggle.style.pointerEvents = ""; } + document + .querySelectorAll(".grid-row[data-id]") + .forEach((row) => row.classList.remove("batch-disabled")); + const toggle = document.querySelector( + ".actions-dropdown .dropdown-toggle", + ); + if (toggle) { + toggle.disabled = false; + toggle.style.opacity = ""; + toggle.style.pointerEvents = ""; + } } // ── Single row export: validate → confirm → send ──────────────────── @@ -250,40 +310,61 @@ if (gridRow) { setRowExporting(gridRow, true); const spinner = gridRow.querySelector(".batch-row-spinner"); - if (spinner) spinner.innerHTML = ' Validating...'; + if (spinner) + spinner.innerHTML = + ' Validating...'; } validateRows([{ iddatadb: parseInt(iddatadb), index: rowIndex }]) - .then(validationData => { - if (gridRow) { setRowExporting(gridRow, false); gridRow.classList.remove("batch-disabled"); } + .then((validationData) => { + if (gridRow) { + setRowExporting(gridRow, false); + gridRow.classList.remove("batch-disabled"); + } if (!validationData.success) { - showExportResult({ success: false, message: validationData.message || "Validation error" }); + showExportResult({ + success: false, + message: validationData.message || "Validation error", + }); return; } const result = validationData.results[rowIndex]; if (result && !result.valid) { - if (gridRow) showValidationErrors(gridRow, iddatadb, result.errors); + if (gridRow) + showValidationErrors(gridRow, iddatadb, result.errors); return; } showConfirmAndExport(iddatadb, rowIndex); }) - .catch(error => { - if (gridRow) { setRowExporting(gridRow, false); gridRow.classList.remove("batch-disabled"); } - showExportResult({ success: false, message: "Validation error: " + error.message }); + .catch((error) => { + if (gridRow) { + setRowExporting(gridRow, false); + gridRow.classList.remove("batch-disabled"); + } + showExportResult({ + success: false, + message: "Validation error: " + error.message, + }); }); } function showConfirmAndExport(iddatadb, rowIndex) { - const confirmModalElement = document.getElementById("exportConfirmModal"); + const confirmModalElement = + document.getElementById("exportConfirmModal"); if (!confirmModalElement) return; - const confirmModal = new bootstrap.Modal(confirmModalElement, { keyboard: false }); + const confirmModal = new bootstrap.Modal(confirmModalElement, { + keyboard: false, + }); document.getElementById("exportIddatadb").textContent = iddatadb; confirmModal.show(); const confirmBtn = document.getElementById("exportConfirmBtn"); - if (!confirmBtn) { confirmModal.hide(); return; } + if (!confirmBtn) { + confirmModal.hide(); + return; + } const confirmHandler = async () => { pendingConfirmHandler = null; @@ -294,24 +375,36 @@ try { const data = await sendExport(iddatadb); - if (gridRow) { setRowExporting(gridRow, false); gridRow.classList.remove("batch-disabled"); } - if (!data.success) showRowError(gridRow, iddatadb, data.message || "Unknown error"); + if (gridRow) { + setRowExporting(gridRow, false); + gridRow.classList.remove("batch-disabled"); + } + if (!data.success) + showRowError( + gridRow, + iddatadb, + data.message || "Unknown error", + ); showExportResult(data); } catch (error) { - if (gridRow) { setRowExporting(gridRow, false); gridRow.classList.remove("batch-disabled"); } + if (gridRow) { + setRowExporting(gridRow, false); + gridRow.classList.remove("batch-disabled"); + } showRowError(gridRow, iddatadb, error.message); showExportResult({ success: false, message: error.message }); } }; - if (pendingConfirmHandler) confirmBtn.removeEventListener("click", pendingConfirmHandler); + if (pendingConfirmHandler) + confirmBtn.removeEventListener("click", pendingConfirmHandler); pendingConfirmHandler = confirmHandler; confirmBtn.addEventListener("click", confirmHandler, { once: true }); } // ── Single row click (event delegation) ───────────────────────────── - $(document).on('click', '.export-lims-btn', function (e) { + $(document).on("click", ".export-lims-btn", function (e) { e.preventDefault(); if (batchRunning) return; @@ -322,24 +415,34 @@ // Check unsaved changes for this row const dataRow = window.gridData?.[rowIndex]; if (dataRow && dataRow._dirty) { - const unsavedModal = new bootstrap.Modal(document.getElementById("exportUnsavedModal"), { keyboard: false }); + const unsavedModal = new bootstrap.Modal( + document.getElementById("exportUnsavedModal"), + { keyboard: false }, + ); unsavedModal.show(); - document.getElementById("saveAndExportBtn")?.addEventListener("click", () => { - unsavedModal.hide(); - // Save first, then export - const formData = window.buildSavePayload(rowIndex); - fetch('save_edited_row.php', { method: 'POST', body: formData }) - .then(r => r.json()) - .then(result => { - if (result.success) { - dataRow._dirty = false; - startExportConfirmFlow(iddatadb, rowIndex); - } else { - alert('Save failed: ' + result.message); - } - }); - }, { once: true }); + document.getElementById("saveAndExportBtn")?.addEventListener( + "click", + () => { + unsavedModal.hide(); + // Save first, then export + const formData = window.buildSavePayload(rowIndex); + fetch("save_edited_row.php", { + method: "POST", + body: formData, + }) + .then((r) => r.json()) + .then((result) => { + if (result.success) { + dataRow._dirty = false; + startExportConfirmFlow(iddatadb, rowIndex); + } else { + alert("Save failed: " + result.message); + } + }); + }, + { once: true }, + ); return; } @@ -349,18 +452,33 @@ // ── Batch export (Export All) ─────────────────────────────────────── function collectEligibleRows() { - // Read from gridData, not DOM + // Read from gridData, not DOM. Se i filtri sono attivi, limita al target set. + const target = + typeof window.getTargetGridIds === "function" + ? window.getTargetGridIds() + : null; const eligible = []; (window.gridData || []).forEach((row, index) => { - if (row.status !== 'l') { - eligible.push({ iddatadb: row.iddatadb, index, row: getGridRow(row.iddatadb) }); - } + if (row.status === "l") return; + if (target && !target.has(parseInt(row.iddatadb, 10))) return; + eligible.push({ + iddatadb: row.iddatadb, + index, + row: getGridRow(row.iddatadb), + }); }); return eligible; } function hasUnsavedChanges() { - return (window.gridData || []).some(r => r._dirty); + const target = + typeof window.getTargetGridIds === "function" + ? window.getTargetGridIds() + : null; + return (window.gridData || []).some( + (r) => + r._dirty && (!target || target.has(parseInt(r.iddatadb, 10))), + ); } async function validateAndFilter(eligibleRows) { @@ -369,7 +487,8 @@ index, })); const validationData = await validateRows(rowsToValidate); - if (!validationData.success) throw new Error(validationData.message || "Validation error"); + if (!validationData.success) + throw new Error(validationData.message || "Validation error"); const validRows = []; let invalidCount = 0; @@ -377,7 +496,12 @@ for (const item of eligibleRows) { const result = validationData.results[item.index]; if (result && !result.valid) { - if (item.row) showValidationErrors(item.row, item.iddatadb, result.errors); + if (item.row) + showValidationErrors( + item.row, + item.iddatadb, + result.errors, + ); invalidCount++; } else { validRows.push(item); @@ -410,54 +534,92 @@ if (validRows.length === 0) { document.getElementById("exportResponseMessage").innerHTML = `No valid rows for export.
${invalidCount} rows with validation errors.`; - document.getElementById("exportResponseModalLabel").textContent = "Validation Failed"; - new bootstrap.Modal(document.getElementById("exportResponseModal"), { keyboard: false }).show(); + document.getElementById( + "exportResponseModalLabel", + ).textContent = "Validation Failed"; + new bootstrap.Modal( + document.getElementById("exportResponseModal"), + { keyboard: false }, + ).show(); return; } - const confirmModal = new bootstrap.Modal(document.getElementById("exportBatchConfirmModal"), { keyboard: false }); + const confirmModal = new bootstrap.Modal( + document.getElementById("exportBatchConfirmModal"), + { keyboard: false }, + ); let countText = String(validRows.length); - if (invalidCount > 0) countText += ` (${invalidCount} excluded due to errors)`; - document.getElementById("exportBatchCount").textContent = countText; + if (invalidCount > 0) + countText += ` (${invalidCount} excluded due to errors)`; + document.getElementById("exportBatchCount").textContent = + countText; confirmModal.show(); - const confirmBtn = document.getElementById("exportBatchConfirmBtn"); - if (pendingBatchConfirmHandler) confirmBtn.removeEventListener("click", pendingBatchConfirmHandler); + const confirmBtn = document.getElementById( + "exportBatchConfirmBtn", + ); + if (pendingBatchConfirmHandler) + confirmBtn.removeEventListener( + "click", + pendingBatchConfirmHandler, + ); pendingBatchConfirmHandler = () => { pendingBatchConfirmHandler = null; confirmModal.hide(); startBatchExport(validRows); }; - confirmBtn.addEventListener("click", pendingBatchConfirmHandler, { once: true }); + confirmBtn.addEventListener( + "click", + pendingBatchConfirmHandler, + { once: true }, + ); }) - .catch(error => { + .catch((error) => { showValidationSpinner(false); - document.getElementById("exportResponseMessage").textContent = "Validation error: " + error.message; - document.getElementById("exportResponseModalLabel").textContent = "Validation Error"; - new bootstrap.Modal(document.getElementById("exportResponseModal"), { keyboard: false }).show(); + document.getElementById("exportResponseMessage").textContent = + "Validation error: " + error.message; + document.getElementById( + "exportResponseModalLabel", + ).textContent = "Validation Error"; + new bootstrap.Modal( + document.getElementById("exportResponseModal"), + { keyboard: false }, + ).show(); }); } - $(document).on('click', '.export-all-lims-btn', function (e) { + $(document).on("click", ".export-all-lims-btn", function (e) { e.preventDefault(); if (batchRunning) return; if (hasUnsavedChanges()) { - const unsavedModal = new bootstrap.Modal(document.getElementById("exportBatchUnsavedModal"), { keyboard: false }); + const unsavedModal = new bootstrap.Modal( + document.getElementById("exportBatchUnsavedModal"), + { keyboard: false }, + ); unsavedModal.show(); - document.getElementById("batchSaveAndExportBtn")?.addEventListener("click", () => { - unsavedModal.hide(); - // Trigger save all first — listen for completion - alert("Please Save All first, then Export All."); - }, { once: true }); + document.getElementById("batchSaveAndExportBtn")?.addEventListener( + "click", + () => { + unsavedModal.hide(); + // Trigger save all first — listen for completion + alert("Please Save All first, then Export All."); + }, + { once: true }, + ); return; } const eligibleRows = collectEligibleRows(); if (eligibleRows.length === 0) { - document.getElementById("exportResponseMessage").textContent = "All rows already exported to LIMS."; - document.getElementById("exportResponseModalLabel").textContent = "Export All"; - new bootstrap.Modal(document.getElementById("exportResponseModal"), { keyboard: false }).show(); + document.getElementById("exportResponseMessage").textContent = + "All rows already exported to LIMS."; + document.getElementById("exportResponseModalLabel").textContent = + "Export All"; + new bootstrap.Modal( + document.getElementById("exportResponseModal"), + { keyboard: false }, + ).show(); return; } showBatchConfirm(eligibleRows); @@ -468,7 +630,9 @@ batchRunning = true; const batchUuid = crypto.randomUUID(); const total = eligibleRows.length; - let processed = 0, succeeded = 0, failed = 0; + let processed = 0, + succeeded = 0, + failed = 0; disableAllRowButtons(); @@ -479,18 +643,25 @@ if (cancelBtn) cancelBtn.disabled = false; if (statusEl) statusEl.textContent = `Exporting 0 / ${total}...`; - cancelBtn?.addEventListener("click", () => { - batchCancelled = true; - if (statusEl) statusEl.textContent = "Cancelling... (waiting for current row)"; - if (cancelBtn) cancelBtn.disabled = true; - }, { once: true }); + cancelBtn?.addEventListener( + "click", + () => { + batchCancelled = true; + if (statusEl) + statusEl.textContent = + "Cancelling... (waiting for current row)"; + if (cancelBtn) cancelBtn.disabled = true; + }, + { once: true }, + ); (async () => { for (let i = 0; i < eligibleRows.length; i++) { if (batchCancelled) break; const { iddatadb, row } = eligibleRows[i]; - if (statusEl) statusEl.textContent = `Exporting ${processed + 1} / ${total} (id: ${iddatadb})...`; + if (statusEl) + statusEl.textContent = `Exporting ${processed + 1} / ${total} (id: ${iddatadb})...`; const gridRow = row || getGridRow(iddatadb); if (gridRow) setRowExporting(gridRow, true); @@ -503,18 +674,29 @@ } else { failed++; const errIdx = getRowIndexByIddatadb(iddatadb); - if (errIdx >= 0) window.gridData[errIdx]._exportError = data.message || "Unknown error"; - if (gridRow) showRowError(gridRow, iddatadb, data.message || "Unknown error"); + if (errIdx >= 0) + window.gridData[errIdx]._exportError = + data.message || "Unknown error"; + if (gridRow) + showRowError( + gridRow, + iddatadb, + data.message || "Unknown error", + ); } } catch (error) { processed++; failed++; const errIdx = getRowIndexByIddatadb(iddatadb); - if (errIdx >= 0) window.gridData[errIdx]._exportError = error.message; + if (errIdx >= 0) + window.gridData[errIdx]._exportError = error.message; if (gridRow) showRowError(gridRow, iddatadb, error.message); } - if (gridRow) { setRowExporting(gridRow, false); gridRow.classList.remove("batch-disabled"); } + if (gridRow) { + setRowExporting(gridRow, false); + gridRow.classList.remove("batch-disabled"); + } } batchRunning = false; @@ -529,7 +711,8 @@ (window.gridData || []).forEach((row, idx) => { if (row._exportError) { const gridRow = getGridRow(row.iddatadb); - if (gridRow) showRowError(gridRow, row.iddatadb, row._exportError); + if (gridRow) + showRowError(gridRow, row.iddatadb, row._exportError); } }); @@ -549,7 +732,9 @@ const modalEl = document.getElementById("exportResponseModal"); new bootstrap.Modal(modalEl, { keyboard: false }).show(); - modalEl.addEventListener("hidden.bs.modal", cleanupBackdrop, { once: true }); + modalEl.addEventListener("hidden.bs.modal", cleanupBackdrop, { + once: true, + }); })(); } })(); diff --git a/public/userarea/modal_partsTable.php b/public/userarea/modal_partsTable.php index 75d945c..0157a2c 100644 --- a/public/userarea/modal_partsTable.php +++ b/public/userarea/modal_partsTable.php @@ -214,6 +214,12 @@ Duplica anche le analisi collegate +
+ + +