@@ -188,6 +188,23 @@ function setPercentage(percent) {
188188 $("#progress .progress-bar span").text(percent + "%");
189189}
190190
191+ /**
192+ * Formatta i bytes in formato leggibile
193+ * @param bytes
194+ * @param decimals
195+ */
196+ function formatBytes(bytes, decimals = 2) {
197+ if (bytes === 0) return "0 Bytes";
198+
199+ const k = 1024;
200+ const dm = decimals < 0 ? 0 : decimals;
201+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
202+
203+ const i = Math.floor(Math.log(bytes) / Math.log(k));
204+
205+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
206+ }
207+
191208/**
192209*
193210* @param controllo
@@ -205,15 +222,53 @@ function initcard(controllo, success, records) {
205222
206223 let card = `<div class="card ` + cssClass + `" id="controllo-` + controllo["id"] + `">
207224 <div class="card-header with-border">
208- <h3 class="card-title">` + controllo["name"] + `</h3>
225+ <h3 class="card-title">` + controllo["name"];
226+
227+ // Aggiungi badge inline per il controllo IntegritaFile
228+ if (controllo["class"] === "Modules \\\\Aggiornamenti \\\\Controlli \\\\IntegritaFile" && !success && records.length > 0) {
229+ let orphanFiles = records.filter(r => r.tipo === "file_orfano");
230+ let orphanRecords = records.filter(r => r.tipo === "file_mancante");
231+
232+ if (orphanFiles.length > 0 || orphanRecords.length > 0) {
233+ if (orphanFiles.length > 0) {
234+ let totalSize = 0;
235+ orphanFiles.forEach(function(file) {
236+ if (file.dimensione_bytes) {
237+ totalSize += parseInt(file.dimensione_bytes);
238+ }
239+ });
240+ let sizeFormatted = totalSize > 0 ? formatBytes(totalSize) : "";
241+ card += ` <span class="badge badge-danger ml-2">
242+ <i class="fa fa-trash mr-1"></i>${orphanFiles.length} file${sizeFormatted ? " - " + sizeFormatted : ""}
243+ </span>`;
244+ }
245+
246+ if (orphanRecords.length > 0) {
247+ card += ` <span class="badge badge-warning ml-2">
248+ <i class="fa fa-database mr-1"></i>${orphanRecords.length} record
249+ </span>`;
250+ }
251+ }
252+ }
253+
254+ card += `</h3>
209255 <div class="card-tools pull-right">`;
210256
211- // Aggiungi pulsante azione globale se il controllo lo supporta e ci sono record
257+ // Aggiungi pulsanti azione globale se il controllo lo supporta e ci sono record
212258 if (!success && records.length > 0 && hasGlobalActions(controllo)) {
213- card += `
214- <button type="button" class="btn btn-success btn-sm" data-controllo-id="` + controllo["id"] + `" data-controllo-class="` + controllo["class"] + `" onclick="eseguiAzioneGlobale(this)">
215- <i class="fa fa-check-circle"></i> ' .tr ('Risolvi tutti i conflitti ' ).'
216- </button>`;
259+ // Pulsante specifico per IntegritaFile che esegue entrambe le operazioni
260+ if (controllo["class"] === "Modules \\\\Aggiornamenti \\\\Controlli \\\\IntegritaFile") {
261+ card += `
262+ <button type="button" class="btn btn-success btn-sm" data-controllo-id="` + controllo["id"] + `" data-controllo-class="` + controllo["class"] + `" data-action="remove_all_both" onclick="eseguiAzioneGlobaleConParametri(this)">
263+ <i class="fa fa-check-circle"></i> ' .tr ('Risolvi tutti i conflitti ' ).'
264+ </button>`;
265+ } else {
266+ // Pulsante generico per altri controlli
267+ card += `
268+ <button type="button" class="btn btn-success btn-sm" data-controllo-id="` + controllo["id"] + `" data-controllo-class="` + controllo["class"] + `" onclick="eseguiAzioneGlobale(this)">
269+ <i class="fa fa-check-circle"></i> ' .tr ('Risolvi tutti i conflitti ' ).'
270+ </button>`;
271+ }
217272 }
218273
219274 card += `
@@ -233,11 +288,11 @@ function initcard(controllo, success, records) {
233288 <table class="table table-striped table-hover table-sm table-bordered">
234289 <thead>
235290 <tr>
236- <th width="15 %"> ' .tr ('Record ' ).'</th>
291+ <th width="30 %"> ' .tr ('Record ' ).'</th>
237292 <th> ' .tr ('Descrizione ' ).'</th>`;
238293
239294 if (hasRowOptions) {
240- card += `<th class="text-center" width="15 %"> ' .tr ('Opzioni ' ).'</th>`;
295+ card += `<th class="text-center" width="12 %"> ' .tr ('Opzioni ' ).'</th>`;
241296 }
242297
243298 card += `
@@ -271,7 +326,7 @@ function addRiga(controllo, card, record) {
271326 <td>` + record.descrizione + `</td>`;
272327
273328 if (hasOptions) {
274- riga += `<td></td>`;
329+ riga += `<td class="text-center" ></td>`;
275330 }
276331
277332 riga += `</tr>`;
@@ -281,7 +336,7 @@ function addRiga(controllo, card, record) {
281336 if (hasOptions) {
282337 const options_columns = riga.find("td").last();
283338 record.options.forEach(function (option, id){
284- let button = `<button type="button" class="btn btn-` + option.color + `">
339+ let button = `<button type="button" class="btn btn-` + option.color + ` btn-sm ">
285340 <i class="` + option.icon + `"></i> ` + option.name + `
286341 </buttton>`;
287342 button = $(button);
@@ -310,7 +365,8 @@ function hasGlobalActions(controllo) {
310365 "Modules \\\\Aggiornamenti \\\\Controlli \\\\ReaValidi",
311366 "Modules \\\\Aggiornamenti \\\\Controlli \\\\ColonneDuplicateViste",
312367 "Modules \\\\Aggiornamenti \\\\Controlli \\\\PluginDuplicati",
313- "Modules \\\\Aggiornamenti \\\\Controlli \\\\TabelleLanguage"
368+ "Modules \\\\Aggiornamenti \\\\Controlli \\\\TabelleLanguage",
369+ "Modules \\\\Aggiornamenti \\\\Controlli \\\\IntegritaFile"
314370 ];
315371
316372 return controlliConAzioniGlobali.includes(controllo["class"]);
@@ -375,6 +431,17 @@ function getMessaggioConferma(controlloClass) {
375431 " ' .tr ('Migliorerà la coerenza del database multilingua ' ).'",
376432 " ' .tr ('Operazione sicura e reversibile ' ).'"
377433 ]
434+ },
435+ "Modules \\\\Aggiornamenti \\\\Controlli \\\\IntegritaFile": {
436+ titolo: " ' .tr ('Conferma operazioni di pulizia ' ).'",
437+ descrizione: " ' .tr ('Sei sicuro di voler procedere con le operazioni di pulizia selezionate? ' ).'",
438+ operazioni: [
439+ " ' .tr ('RIMOZIONE FILE ORFANI: Rimuoverà definitivamente tutti i file presenti nel filesystem ma non registrati nel database ' ).'",
440+ " ' .tr ('RIMOZIONE RECORD ORFANI: Rimuoverà dal database tutti i record che puntano a file fisici inesistenti ' ).'",
441+ " ' .tr ('I file e record eliminati non potranno essere recuperati ' ).'",
442+ " ' .tr ('Libererà spazio su disco e pulirà il database da riferimenti non validi ' ).'",
443+ " ' .tr ('Non può essere annullata ' ).'"
444+ ]
378445 }
379446 };
380447
@@ -474,10 +541,103 @@ function eseguiAzioneGlobale(buttonElement) {
474541 });
475542}
476543
544+ /**
545+ * Esegue un azione globale con parametri specifici
546+ */
547+ function eseguiAzioneGlobaleConParametri(button) {
548+ let controlloId = $(button).data("controllo-id");
549+ let controlloClass = $(button).data("controllo-class");
550+ let action = $(button).data("action");
551+
552+ // Usa la stessa logica della funzione esistente ma con parametri
553+ let messaggio = getMessaggioConferma(controlloClass);
554+
555+ // Genera la lista delle operazioni
556+ let operazioniHtml = "";
557+ messaggio.operazioni.forEach(function(operazione) {
558+ operazioniHtml += `<li>${operazione}</li>`;
559+ });
560+
561+ // Crea modal di conferma con lo stile del gestionale
562+ let modalHtml = `
563+ <div class="modal fade" id="modal-conferma-risoluzione" tabindex="-1" role="dialog">
564+ <div class="modal-dialog modal-lg" role="document">
565+ <div class="modal-content">
566+ <div class="modal-header">
567+ <h4 class="modal-title">
568+ <i class="fa fa-exclamation-triangle text-warning"></i>
569+ ${messaggio.titolo}
570+ </h4>
571+ <button type="button" class="close" data-dismiss="modal">
572+ <span>×</span>
573+ </button>
574+ </div>
575+ <div class="modal-body">
576+ <p>${messaggio.descrizione}</p>
577+ <div class="alert alert-warning">
578+ <i class="fa fa-info-circle"></i>
579+ ' .tr ('Questa operazione: ' ).'
580+ <ul class="mb-0 mt-2">
581+ ${operazioniHtml}
582+ </ul>
583+ </div>
584+ </div>
585+ <div class="modal-footer">
586+ <button type="button" class="btn btn-default" data-dismiss="modal" style="float: left;">
587+ <i class="fa fa-times"></i> ' .tr ('Annulla ' ).'
588+ </button>
589+ <button type="button" class="btn btn-warning" id="conferma-risoluzione" style="float: right;">
590+ <i class="fa fa-check"></i> ' .tr ('Procedi ' ).'
591+ </button>
592+ <div style="clear: both;"></div>
593+ </div>
594+ </div>
595+ </div>
596+ </div>
597+ `;
598+
599+ // Rimuovi modal esistente se presente
600+ $("#modal-conferma-risoluzione").remove();
601+
602+ // Aggiungi modal al DOM
603+ $("body").append(modalHtml);
604+
605+ // Mostra modal con configurazione per evitare chiusura accidentale
606+ $("#modal-conferma-risoluzione").modal({
607+ backdrop: "static",
608+ keyboard: false,
609+ show: true
610+ });
611+
612+ // Gestisci click su conferma
613+ $("#conferma-risoluzione").on("click", function(e) {
614+ e.preventDefault();
615+ e.stopPropagation();
616+
617+ let confirmButton = $(this);
618+ let restoreConfirm = buttonLoading(confirmButton);
619+
620+ // Disabilita il pulsante di annulla durante l operazione
621+ $("#modal-conferma-risoluzione .btn-default").prop("disabled", true);
622+
623+ eseguiRisoluzioneGlobale(button, controlloId, controlloClass, function() {
624+ // Callback di successo: chiudi modal
625+ $("#modal-conferma-risoluzione").modal("hide");
626+ loadControllo(controlloId);
627+ }, function() {
628+ // Callback di errore: ripristina pulsanti
629+ buttonRestore(confirmButton, restoreConfirm);
630+ $("#modal-conferma-risoluzione .btn-default").prop("disabled", false);
631+ }, {action: action});
632+
633+ return false;
634+ });
635+ }
636+
477637/**
478638* Esegue effettivamente la risoluzione globale
479639*/
480- function eseguiRisoluzioneGlobale(button, controlloId, controlloClass, successCallback, errorCallback) {
640+ function eseguiRisoluzioneGlobale(button, controlloId, controlloClass, successCallback, errorCallback, params = {} ) {
481641 let restore = buttonLoading(button);
482642
483643 $.ajax({
@@ -488,7 +648,7 @@ function eseguiRisoluzioneGlobale(button, controlloId, controlloClass, successCa
488648 id_module: globals.id_module,
489649 op: "controlli-action-global",
490650 controllo: controlloClass,
491- params: {} ,
651+ params: params ,
492652 },
493653 success: function(results) {
494654 // Rimuovi tutte le righe del controllo
0 commit comments