fixed api
This commit is contained in:
@@ -43,6 +43,7 @@ class VisualLimsApiClient
|
|||||||
{
|
{
|
||||||
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'VisualLims-Client/1.0');
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||||
'Username' => $this->username,
|
'Username' => $this->username,
|
||||||
@@ -105,6 +106,7 @@ class VisualLimsApiClient
|
|||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'VisualLims-Client/1.0');
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
"Authorization: Bearer {$token}",
|
"Authorization: Bearer {$token}",
|
||||||
"Accept: application/json"
|
"Accept: application/json"
|
||||||
@@ -144,6 +146,7 @@ class VisualLimsApiClient
|
|||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'VisualLims-Client/1.0');
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
@@ -177,6 +180,7 @@ class VisualLimsApiClient
|
|||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'VisualLims-Client/1.0');
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
@@ -225,6 +229,7 @@ class VisualLimsApiClient
|
|||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'VisualLims-Client/1.0');
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
@@ -268,6 +273,7 @@ class VisualLimsApiClient
|
|||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'VisualLims-Client/1.0');
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
"Authorization: Bearer {$token}",
|
"Authorization: Bearer {$token}",
|
||||||
"Accept: */*"
|
"Accept: */*"
|
||||||
|
|||||||
@@ -43,17 +43,23 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
* Clear all validation-error highlights from the grid.
|
* Clear all validation-error highlights from the grid.
|
||||||
*/
|
*/
|
||||||
function clearValidationErrors() {
|
function clearValidationErrors() {
|
||||||
document.querySelectorAll(".grid-cell.validation-error").forEach((cell) => {
|
document
|
||||||
cell.classList.remove("validation-error");
|
.querySelectorAll(".grid-cell.validation-error")
|
||||||
cell.querySelectorAll(".input-validation-error").forEach((el) => {
|
.forEach((cell) => {
|
||||||
el.classList.remove("input-validation-error");
|
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");
|
||||||
});
|
});
|
||||||
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");
|
|
||||||
});
|
|
||||||
// Also clear batch-row-error that came from validation
|
// Also clear batch-row-error that came from validation
|
||||||
clearAllRowErrors();
|
clearAllRowErrors();
|
||||||
}
|
}
|
||||||
@@ -90,16 +96,24 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (targetIndex) {
|
if (targetIndex) {
|
||||||
const rowIndex = row.querySelector(".grid-cell[data-row]")?.getAttribute("data-row");
|
const rowIndex = row
|
||||||
|
.querySelector(".grid-cell[data-row]")
|
||||||
|
?.getAttribute("data-row");
|
||||||
if (rowIndex !== null) {
|
if (rowIndex !== null) {
|
||||||
cell = row.querySelector(`.grid-cell[data-row="${rowIndex}"][data-index="${targetIndex}"]`);
|
cell = row.querySelector(
|
||||||
|
`.grid-cell[data-row="${rowIndex}"][data-index="${targetIndex}"]`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Direct data-col match
|
// Direct data-col match
|
||||||
const rowIndex = row.querySelector(".grid-cell[data-row]")?.getAttribute("data-row");
|
const rowIndex = row
|
||||||
|
.querySelector(".grid-cell[data-row]")
|
||||||
|
?.getAttribute("data-row");
|
||||||
if (rowIndex !== null) {
|
if (rowIndex !== null) {
|
||||||
cell = row.querySelector(`.grid-cell[data-col="${err.field}"][data-row="${rowIndex}"]`);
|
cell = row.querySelector(
|
||||||
|
`.grid-cell[data-col="${err.field}"][data-row="${rowIndex}"]`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,8 +208,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
* Show the result of a single export in the response modal.
|
* Show the result of a single export in the response modal.
|
||||||
*/
|
*/
|
||||||
function showExportResult(data) {
|
function showExportResult(data) {
|
||||||
const responseModalElement =
|
const responseModalElement = document.getElementById(
|
||||||
document.getElementById("exportResponseModal");
|
"exportResponseModal",
|
||||||
|
);
|
||||||
if (!responseModalElement) {
|
if (!responseModalElement) {
|
||||||
alert("Errore: Modale di risposta non trovato");
|
alert("Errore: Modale di risposta non trovato");
|
||||||
return;
|
return;
|
||||||
@@ -276,20 +291,28 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
errorEl.className = "batch-error-msg";
|
errorEl.className = "batch-error-msg";
|
||||||
errorEl.textContent = "⚠ Errore — clicca per dettagli";
|
errorEl.textContent = "⚠ Errore — clicca per dettagli";
|
||||||
errorEl.addEventListener("click", () => {
|
errorEl.addEventListener("click", () => {
|
||||||
document.getElementById("exportResponseMessage").innerHTML = message.replace(/\n/g, "<br>");
|
document.getElementById("exportResponseMessage").innerHTML =
|
||||||
document.getElementById("exportResponseModalLabel").textContent = "Errore Validazione (id: " + iddatadb + ")";
|
message.replace(/\n/g, "<br>");
|
||||||
new bootstrap.Modal(document.getElementById("exportResponseModal"), { keyboard: false }).show();
|
document.getElementById(
|
||||||
|
"exportResponseModalLabel",
|
||||||
|
).textContent = "Errore Validazione (id: " + iddatadb + ")";
|
||||||
|
new bootstrap.Modal(
|
||||||
|
document.getElementById("exportResponseModal"),
|
||||||
|
{ keyboard: false },
|
||||||
|
).show();
|
||||||
});
|
});
|
||||||
btnCell.appendChild(errorEl);
|
btnCell.appendChild(errorEl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearAllRowErrors() {
|
function clearAllRowErrors() {
|
||||||
document.querySelectorAll(".grid-row.batch-row-error").forEach((row) => {
|
document
|
||||||
row.classList.remove("batch-row-error");
|
.querySelectorAll(".grid-row.batch-row-error")
|
||||||
const msg = row.querySelector(".batch-error-msg");
|
.forEach((row) => {
|
||||||
if (msg) msg.remove();
|
row.classList.remove("batch-row-error");
|
||||||
});
|
const msg = row.querySelector(".batch-error-msg");
|
||||||
|
if (msg) msg.remove();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableAllRowButtons() {
|
function disableAllRowButtons() {
|
||||||
@@ -333,15 +356,23 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
// Show validating state on the row
|
// Show validating state on the row
|
||||||
setRowExporting(gridRow, true);
|
setRowExporting(gridRow, true);
|
||||||
const spinner = gridRow.querySelector(".batch-row-spinner");
|
const spinner = gridRow.querySelector(".batch-row-spinner");
|
||||||
if (spinner) spinner.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Validating...';
|
if (spinner)
|
||||||
|
spinner.innerHTML =
|
||||||
|
'<i class="fas fa-spinner fa-spin"></i> Validating...';
|
||||||
|
|
||||||
validateRows([{ iddatadb: parseInt(iddatadb), index: parseInt(rowIndex) }])
|
validateRows([
|
||||||
|
{ iddatadb: parseInt(iddatadb), index: parseInt(rowIndex) },
|
||||||
|
])
|
||||||
.then((validationData) => {
|
.then((validationData) => {
|
||||||
setRowExporting(gridRow, false);
|
setRowExporting(gridRow, false);
|
||||||
gridRow.classList.remove("batch-disabled");
|
gridRow.classList.remove("batch-disabled");
|
||||||
|
|
||||||
if (!validationData.success) {
|
if (!validationData.success) {
|
||||||
showExportResult({ success: false, message: validationData.message || "Errore di validazione" });
|
showExportResult({
|
||||||
|
success: false,
|
||||||
|
message:
|
||||||
|
validationData.message || "Errore di validazione",
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +391,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
gridRow.classList.remove("batch-disabled");
|
gridRow.classList.remove("batch-disabled");
|
||||||
|
|
||||||
console.error("Validation error:", error);
|
console.error("Validation error:", error);
|
||||||
showExportResult({ success: false, message: "Errore di validazione: " + error.message });
|
showExportResult({
|
||||||
|
success: false,
|
||||||
|
message: "Errore di validazione: " + error.message,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +436,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
gridRow.classList.remove("batch-disabled");
|
gridRow.classList.remove("batch-disabled");
|
||||||
|
|
||||||
if (!data.success) {
|
if (!data.success) {
|
||||||
showRowError(gridRow, iddatadb, data.message || "Errore sconosciuto");
|
showRowError(
|
||||||
|
gridRow,
|
||||||
|
iddatadb,
|
||||||
|
data.message || "Errore sconosciuto",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
showExportResult(data);
|
showExportResult(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -577,8 +615,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
document.getElementById("exportResponseMessage").innerHTML =
|
document.getElementById("exportResponseMessage").innerHTML =
|
||||||
`Nessuna riga valida per l'esportazione.<br>` +
|
`Nessuna riga valida per l'esportazione.<br>` +
|
||||||
`<strong>${invalidCount}</strong> righe con errori di validazione.`;
|
`<strong>${invalidCount}</strong> righe con errori di validazione.`;
|
||||||
document.getElementById("exportResponseModalLabel").textContent =
|
document.getElementById(
|
||||||
"Validazione Fallita";
|
"exportResponseModalLabel",
|
||||||
|
).textContent = "Validazione Fallita";
|
||||||
new bootstrap.Modal(
|
new bootstrap.Modal(
|
||||||
document.getElementById("exportResponseModal"),
|
document.getElementById("exportResponseModal"),
|
||||||
{ keyboard: false },
|
{ keyboard: false },
|
||||||
@@ -595,27 +634,38 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
if (invalidCount > 0) {
|
if (invalidCount > 0) {
|
||||||
countText += ` (${invalidCount} escluse per errori di validazione)`;
|
countText += ` (${invalidCount} escluse per errori di validazione)`;
|
||||||
}
|
}
|
||||||
document.getElementById("exportBatchCount").textContent = countText;
|
document.getElementById("exportBatchCount").textContent =
|
||||||
|
countText;
|
||||||
confirmModal.show();
|
confirmModal.show();
|
||||||
|
|
||||||
const confirmBtn = document.getElementById("exportBatchConfirmBtn");
|
const confirmBtn = document.getElementById(
|
||||||
|
"exportBatchConfirmBtn",
|
||||||
|
);
|
||||||
if (pendingBatchConfirmHandler) {
|
if (pendingBatchConfirmHandler) {
|
||||||
confirmBtn.removeEventListener("click", pendingBatchConfirmHandler);
|
confirmBtn.removeEventListener(
|
||||||
|
"click",
|
||||||
|
pendingBatchConfirmHandler,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
pendingBatchConfirmHandler = () => {
|
pendingBatchConfirmHandler = () => {
|
||||||
pendingBatchConfirmHandler = null;
|
pendingBatchConfirmHandler = null;
|
||||||
confirmModal.hide();
|
confirmModal.hide();
|
||||||
startBatchExport(validRows);
|
startBatchExport(validRows);
|
||||||
};
|
};
|
||||||
confirmBtn.addEventListener("click", pendingBatchConfirmHandler, { once: true });
|
confirmBtn.addEventListener(
|
||||||
|
"click",
|
||||||
|
pendingBatchConfirmHandler,
|
||||||
|
{ once: true },
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
showValidationSpinner(false);
|
showValidationSpinner(false);
|
||||||
console.error("Batch validation error:", error);
|
console.error("Batch validation error:", error);
|
||||||
document.getElementById("exportResponseMessage").textContent =
|
document.getElementById("exportResponseMessage").textContent =
|
||||||
"Errore di validazione: " + error.message;
|
"Errore di validazione: " + error.message;
|
||||||
document.getElementById("exportResponseModalLabel").textContent =
|
document.getElementById(
|
||||||
"Errore Validazione";
|
"exportResponseModalLabel",
|
||||||
|
).textContent = "Errore Validazione";
|
||||||
new bootstrap.Modal(
|
new bootstrap.Modal(
|
||||||
document.getElementById("exportResponseModal"),
|
document.getElementById("exportResponseModal"),
|
||||||
{ keyboard: false },
|
{ keyboard: false },
|
||||||
@@ -635,54 +685,51 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
);
|
);
|
||||||
unsavedModal.show();
|
unsavedModal.show();
|
||||||
|
|
||||||
document
|
document.getElementById("batchSaveAndExportBtn").addEventListener(
|
||||||
.getElementById("batchSaveAndExportBtn")
|
"click",
|
||||||
.addEventListener(
|
() => {
|
||||||
"click",
|
unsavedModal.hide();
|
||||||
() => {
|
// Trigger Save All, then proceed
|
||||||
unsavedModal.hide();
|
const saveAllEl = document.querySelector(".save-all-btn");
|
||||||
// Trigger Save All, then proceed
|
if (!saveAllEl) return;
|
||||||
const saveAllEl =
|
|
||||||
document.querySelector(".save-all-btn");
|
|
||||||
if (!saveAllEl) return;
|
|
||||||
|
|
||||||
// Watch for all .cell-changed to disappear
|
// Watch for all .cell-changed to disappear
|
||||||
const observer = new MutationObserver(() => {
|
const observer = new MutationObserver(() => {
|
||||||
if (!hasUnsavedChanges()) {
|
if (!hasUnsavedChanges()) {
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
const eligibleRows = collectEligibleRows();
|
const eligibleRows = collectEligibleRows();
|
||||||
if (eligibleRows.length === 0) {
|
if (eligibleRows.length === 0) {
|
||||||
|
document.getElementById(
|
||||||
|
"exportResponseMessage",
|
||||||
|
).textContent =
|
||||||
|
"Tutte le righe sono già state esportate al LIMS.";
|
||||||
|
document.getElementById(
|
||||||
|
"exportResponseModalLabel",
|
||||||
|
).textContent = "Export All";
|
||||||
|
new bootstrap.Modal(
|
||||||
document.getElementById(
|
document.getElementById(
|
||||||
"exportResponseMessage",
|
"exportResponseModal",
|
||||||
).textContent =
|
),
|
||||||
"Tutte le righe sono già state esportate al LIMS.";
|
{ keyboard: false },
|
||||||
document.getElementById(
|
).show();
|
||||||
"exportResponseModalLabel",
|
return;
|
||||||
).textContent = "Export All";
|
|
||||||
new bootstrap.Modal(
|
|
||||||
document.getElementById(
|
|
||||||
"exportResponseModal",
|
|
||||||
),
|
|
||||||
{ keyboard: false },
|
|
||||||
).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
showBatchConfirm(eligibleRows);
|
|
||||||
}
|
}
|
||||||
});
|
showBatchConfirm(eligibleRows);
|
||||||
observer.observe(
|
}
|
||||||
document.querySelector(".grid-container"),
|
});
|
||||||
{
|
observer.observe(
|
||||||
subtree: true,
|
document.querySelector(".grid-container"),
|
||||||
attributes: true,
|
{
|
||||||
attributeFilter: ["class"],
|
subtree: true,
|
||||||
},
|
attributes: true,
|
||||||
);
|
attributeFilter: ["class"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
saveAllEl.click();
|
saveAllEl.click();
|
||||||
},
|
},
|
||||||
{ once: true },
|
{ once: true },
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,7 +801,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
succeeded++;
|
succeeded++;
|
||||||
} else {
|
} else {
|
||||||
failed++;
|
failed++;
|
||||||
showRowError(row, iddatadb, data.message || "Errore sconosciuto");
|
showRowError(
|
||||||
|
row,
|
||||||
|
iddatadb,
|
||||||
|
data.message || "Errore sconosciuto",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
processed++;
|
processed++;
|
||||||
@@ -794,7 +845,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const modalEl = document.getElementById("exportResponseModal");
|
const modalEl = document.getElementById("exportResponseModal");
|
||||||
const modal = new bootstrap.Modal(modalEl, { keyboard: false });
|
const modal = new bootstrap.Modal(modalEl, { keyboard: false });
|
||||||
modal.show();
|
modal.show();
|
||||||
modalEl.addEventListener("hidden.bs.modal", cleanupBackdrop, { once: true });
|
modalEl.addEventListener("hidden.bs.modal", cleanupBackdrop, {
|
||||||
|
once: true,
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user