diff --git a/ogWebconsole/src/app/components/task-logs/task-logs.component.html b/ogWebconsole/src/app/components/task-logs/task-logs.component.html index 132bccf..b3c8311 100644 --- a/ogWebconsole/src/app/components/task-logs/task-logs.component.html +++ b/ogWebconsole/src/app/components/task-logs/task-logs.component.html @@ -224,6 +224,11 @@ {{ 'showingResults' | translate: { from: getPaginationFrom(), to: getPaginationTo(), total: getPaginationTotal() } }}
+ @@ -231,6 +236,22 @@
+ + + + +
+ + + + + +
diff --git a/ogWebconsole/src/app/components/task-logs/task-logs.component.ts b/ogWebconsole/src/app/components/task-logs/task-logs.component.ts index f20c525..36da5b0 100644 --- a/ogWebconsole/src/app/components/task-logs/task-logs.component.ts +++ b/ogWebconsole/src/app/components/task-logs/task-logs.component.ts @@ -8,6 +8,7 @@ import { map, startWith } from 'rxjs/operators'; import { DatePipe } from '@angular/common'; import { JoyrideService } from 'ngx-joyride'; import { MatDialog } from "@angular/material/dialog"; +import { SelectionModel } from "@angular/cdk/collections"; import { InputDialogComponent } from "./input-dialog/input-dialog.component"; import { ProgressBarMode } from '@angular/material/progress-bar'; import { DeleteModalComponent } from "../../shared/delete_modal/delete-modal/delete-modal.component"; @@ -111,7 +112,8 @@ export class TaskLogsComponent implements OnInit, OnDestroy { sortable: true }, ]; - displayedColumns = [...this.columns.map(column => column.columnDef), 'information']; + displayedColumns = ['select', ...this.columns.map(column => column.columnDef), 'information']; + selection = new SelectionModel(true, []); filters: { [key: string]: string } = {}; filteredClients!: Observable; @@ -179,6 +181,31 @@ export class TaskLogsComponent implements OnInit, OnDestroy { this.selectedTrace = trace; } + isCancellable(trace: any): boolean { + return trace.status === 'pending' || trace.status === 'in-progress'; + } + + get cancellableTraces(): any[] { + return this.traces.filter(trace => this.isCancellable(trace)); + } + + isAllSelected(): boolean { + return this.selection.selected.length === this.cancellableTraces.length && this.cancellableTraces.length > 0; + } + + toggleAllRows(): void { + if (this.isAllSelected()) { + this.selection.clear(); + } else { + this.selection.clear(); + this.selection.select(...this.cancellableTraces); + } + } + + toggleRow(row: any): void { + this.selection.toggle(row); + } + sortColumn(columnDef: string): void { if (this.currentSortColumn === columnDef) { this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'; @@ -328,6 +355,55 @@ export class TaskLogsComponent implements OnInit, OnDestroy { }); } + cancelSelectedTraces(): void { + const selectedTraces = this.selection.selected.filter(trace => this.isCancellable(trace)); + + if (selectedTraces.length === 0) { + this.toastService.warning(this.translate.instant('noTracesSelectedToCancel'), 'Advertencia'); + return; + } + + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '400px', + data: { + title: this.translate.instant('cancelSelectedTraces'), + message: this.translate.instant('confirmCancelSelectedTraces', { count: selectedTraces.length }), + confirmText: 'Cancelar', + cancelText: 'No cancelar' + } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.post(`${this.baseUrl}/traces/cancel-multiple`, { + traces: selectedTraces.map(trace => trace['@id']) + }).subscribe( + (response) => { + const cancelledCount = response?.cancelled?.length ?? selectedTraces.length; + const failedCount = response?.failed?.length ?? 0; + + if (failedCount > 0) { + this.toastService.warning( + this.translate.instant('selectedTracesCancelledSummary', { cancelled: cancelledCount, failed: failedCount }), + 'Advertencia' + ); + } else { + this.toastService.success(this.translate.instant('traceCanceledSuccessfully'), 'Éxito'); + } + + this.selection.clear(); + this.loadTraces(); + this.loadTotalStats(); + }, + (error) => { + console.error(this.translate.instant('errorCancelingSelectedTraces'), error); + this.toastService.error(this.translate.instant('errorCancelingSelectedTraces'), 'Error'); + } + ); + } + }); + } + markTraceAsSuccess(trace: any): void { if (trace.status !== 'in-progress') { this.toastService.warning(this.translate.instant('canOnlyBeMarkedAs'), 'Advertencia'); @@ -471,6 +547,7 @@ export class TaskLogsComponent implements OnInit, OnDestroy { this.traces = data['hydra:member']; this.length = data['hydra:totalItems']; this.groupedTraces = this.groupByCommandId(this.traces); + this.selection.clear(); this.loading = false; if (Object.keys(this.filters).length === 0) { this.loadTotalStats(); diff --git a/ogWebconsole/src/locale/cat.json b/ogWebconsole/src/locale/cat.json index 945a6e4..d35ee3e 100644 --- a/ogWebconsole/src/locale/cat.json +++ b/ogWebconsole/src/locale/cat.json @@ -177,6 +177,7 @@ "cancelAllDisplayedActions": "Cancel·lar totes les accions mostrades", "cancelImageTransmission": "Cancel·lar transmissió d'imatge", "cancelled": "Cancel·lat", + "cancelSelectedTraces": "Cancel·lar seleccionades", "cancelTrace": "Cancel·lant traça", "cannotAccess": "No es pot accedir als registres: IP del client no disponible", "cannotConnectBootServer": "No s'ha pogut connectar amb el servidor OgBoot seleccionat", @@ -288,6 +289,7 @@ "configuredParameters": "(paràmetres configurats)", "configureRequiredParameters": "Configuri els valors per als paràmetres requerits", "confirmationTitle": "Confirmació", + "confirmCancelSelectedTraces": "Segur que vols cancel·lar {{count}} traça/traces seleccionada(es)?", "confirmServerMigration": "Confirmar migració de servidors", "connectionError": "Error de connexió", "convertImageButton": "Convertir imatge virtual", @@ -427,6 +429,7 @@ "errorCancelingActions1": "Error en cancel·lar les accions:", "errorCancelingInprogressTrace": "Error en cancel·lar la traça en progrés:", "errorCancelingPendingTrace": "Error en cancel·lar la traça pendent:", + "errorCancelingSelectedTraces": "Error en cancel·lar les traces seleccionades", "errorCancelingTrace": "Error en cancel·lar la traça", "errorChangingPassword": "Error en canviar la contrasenya:", "errorCheckingStatus": "Error en comprovar l'estat de l'aula", @@ -1046,6 +1049,7 @@ "noTemplateOption": "Cap", "noTemplatesInServer": "No hi ha plantilles en aquest servidor", "notEnoughFreeSpace": "No hi ha suficient espai lliure al disc per crear una nova partició.", + "noTracesSelectedToCancel": "No hi ha traces seleccionades per cancel·lar", "notesPlaceholder": "Ingressa les teves notes aquí", "notValidDataFound": "No s'han trobat dades vàlides", "ntfsOption": "NTFS", @@ -1276,6 +1280,7 @@ "selectedClientsTitle": "Clients seleccionats:", "selectedCommandsTitle": "Comandaments Seleccionats", "selectedSoftwareCount": "{{count}} programari afegit", + "selectedTracesCancelledSummary": "{{cancelled}} cancel·lada(es), {{failed}} no s'han pogut cancel·lar", "selectGitRepoHint": "Selecciona el repositori git per obtenir les imatges disponibles.", "selectGitRepoOs": "Seleccionar repositori git / SO", "selectGitRepository": "Seleccionar repositori Git", diff --git a/ogWebconsole/src/locale/en.json b/ogWebconsole/src/locale/en.json index d1f11b2..d67fc9f 100644 --- a/ogWebconsole/src/locale/en.json +++ b/ogWebconsole/src/locale/en.json @@ -177,6 +177,7 @@ "cancelAllDisplayedActions": "Cancel all displayed actions", "cancelImageTransmission": "Cancel image transmission", "cancelled": "Cancelled", + "cancelSelectedTraces": "Cancel selected", "cancelTrace": "Cancelling Trace", "cannotAccess": "Cannot access logs: Client IP not available", "cannotConnectBootServer": "Could not connect to the selected OgBoot server", @@ -288,6 +289,7 @@ "configuredParameters": "(configured parameters)", "configureRequiredParameters": "Configure values for required parameters", "confirmationTitle": "Confirmation", + "confirmCancelSelectedTraces": "Are you sure you want to cancel {{count}} selected trace(s)?", "confirmServerMigration": "Confirm server migration", "connectionError": "Connection error", "convertImageButton": "Convert virtual image", @@ -427,6 +429,7 @@ "errorCancelingActions1": "Error canceling actions:", "errorCancelingInprogressTrace": "Error cancelling in-progress trace:", "errorCancelingPendingTrace": "Error cancelling pending trace:", + "errorCancelingSelectedTraces": "Error cancelling selected traces", "errorCancelingTrace": "Error canceling trace", "errorChangingPassword": "Error changing password:", "errorCheckingStatus": "Error checking classroom status", @@ -1046,6 +1049,7 @@ "noTemplateOption": "None", "noTemplatesInServer": "There are no templates on this server", "notEnoughFreeSpace": "Not enough free space on the disk to create a new partition.", + "noTracesSelectedToCancel": "No traces selected to cancel", "notesPlaceholder": "Enter your notes here", "notValidDataFound": "No valid data found", "ntfsOption": "NTFS", @@ -1276,6 +1280,7 @@ "selectedClientsTitle": "Selected clients:", "selectedCommandsTitle": "Selected Commands", "selectedSoftwareCount": "{{count}} software added", + "selectedTracesCancelledSummary": "{{cancelled}} cancelled, {{failed}} could not be cancelled", "selectGitRepoHint": "Select the git repository to get available images.", "selectGitRepoOs": "Select git repository / OS", "selectGitRepository": "Select Git repository", diff --git a/ogWebconsole/src/locale/es.json b/ogWebconsole/src/locale/es.json index 5c8f219..c85be5d 100644 --- a/ogWebconsole/src/locale/es.json +++ b/ogWebconsole/src/locale/es.json @@ -177,6 +177,7 @@ "cancelAllDisplayedActions": "Cancelar todas las acciones mostradas", "cancelImageTransmission": "Cancelar transmisión de imagen", "cancelled": "Cancelado", + "cancelSelectedTraces": "Cancelar seleccionadas", "cancelTrace": "Cancelando traza", "cannotAccess": "No se puede acceder a los logs: IP del cliente no disponible", "cannotConnectBootServer": "No se pudo conectar con el servidor OgBoot seleccionado", @@ -288,6 +289,7 @@ "configuredParameters": "(parámetros configurados)", "configureRequiredParameters": "Configure los valores para los parámetros requeridos", "confirmationTitle": "Confirmación", + "confirmCancelSelectedTraces": "¿Estás seguro de que quieres cancelar {{count}} traza(s) seleccionada(s)?", "confirmServerMigration": "Confirmar migración de servidores", "connectionError": "Error de conexión", "convertImageButton": "Convertir imagen virtual", @@ -427,6 +429,7 @@ "errorCancelingActions1": "Error al cancelar las acciones:", "errorCancelingInprogressTrace": "Error al cancelar la traza en progreso:", "errorCancelingPendingTrace": "Error al cancelar la traza pendiente:", + "errorCancelingSelectedTraces": "Error al cancelar las trazas seleccionadas", "errorCancelingTrace": "Error al cancelar la traza", "errorChangingPassword": "Error al cambiar la contraseña:", "errorCheckingStatus": "Error al comprobar el estado del aula", @@ -1046,6 +1049,7 @@ "noTemplateOption": "Ninguna", "noTemplatesInServer": "No hay plantillas en este servidor", "notEnoughFreeSpace": "No hay suficiente espacio libre en el disco para crear una nueva partición.", + "noTracesSelectedToCancel": "No hay trazas seleccionadas para cancelar", "notesPlaceholder": "Ingresa tus notas aquí", "notValidDataFound": "No se encontraron datos válidos", "ntfsOption": "NTFS", @@ -1276,6 +1280,7 @@ "selectedClientsTitle": "Clientes seleccionados:", "selectedCommandsTitle": "Comandos Seleccionados", "selectedSoftwareCount": "{{count}} programas añadidos", + "selectedTracesCancelledSummary": "{{cancelled}} cancelada(s), {{failed}} no se pudieron cancelar", "selectGitRepoHint": "Selecciona el repositorio git para obtener las imágenes disponibles.", "selectGitRepoOs": "Seleccionar repositorio git / SO", "selectGitRepository": "Seleccionar repositorio Git",