diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts
index 4303a9c..7f54af6 100644
--- a/ogWebconsole/src/app/components/groups/groups.component.ts
+++ b/ogWebconsole/src/app/components/groups/groups.component.ts
@@ -147,15 +147,22 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.arrayClients = this.selectedClients.data;
- const eventSource = new EventSource(`${this.mercureUrl}?topic=`
- + encodeURIComponent(`clients`));
+ const eventSource = new EventSource(`${this.mercureUrl}?topic=` + encodeURIComponent(`clients`));
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
- if (data && data['@id']) {
+
+ if (Array.isArray(data)) {
+ data.forEach((client) => {
+ if (client && client['@id']) {
+ this.updateClientStatus(client['@id'], client.status);
+ }
+ });
+ }
+ else if (data && data['@id']) {
this.updateClientStatus(data['@id'], data.status);
}
- }
+ };
this.clientFilterSubject.pipe(debounceTime(500)).subscribe(searchTerm => {
this.filters['query'] = searchTerm;
@@ -378,7 +385,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.selectedClients.data = response['hydra:member'];
this.length = response['hydra:totalItems'];
this.arrayClients = this.selectedClients.data;
- this.hasClients = node.hasClients ?? false;
+ this.hasClients = this.selectedClients.data.length > 0;
this.isLoadingClients = false;
this.initialLoading = false;
this.selection.clear();
diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.css b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.css
deleted file mode 100644
index ecb91dd..0000000
--- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.css
+++ /dev/null
@@ -1,97 +0,0 @@
-
-table {
- width: 100%;
-}
-
-.search-container {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- margin: 1.5rem 0rem 1.5rem 0rem;
- box-sizing: border-box;
-}
-
-.search-string {
- flex: 2;
- padding: 5px;
-}
-
-.search-boolean {
- flex: 1;
- padding: 5px;
-}
-
-.header-container {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 10px 10px;
- border-bottom: 1px solid #ddd;
-}
-
-.mat-elevation-z8 {
- box-shadow: 0px 0px 0px rgba(0,0,0,0.2);
-}
-
-.paginator-container {
- display: flex;
- justify-content: end;
- margin-bottom: 30px;
-}
-
-.example-headers-align .mat-expansion-panel-header-description {
- justify-content: space-between;
- align-items: center;
-}
-
-.example-headers-align .mat-mdc-form-field + .mat-mdc-form-field {
- margin-left: 8px;
-}
-
-.button-row {
- display: table-cell;
- max-width: 600px;
-}
-
-.button-row .mat-mdc-button-base {
- margin: 8px 8px 8px 0;
-}
-
-.chip-failed {
- background-color: #e87979 !important;
- color: white;
-}
-
-.chip-success {
- background-color: #46c446 !important;
- color: white;
-}
-
-.chip-pending {
- background-color: lightgrey !important;
- color: black;
-}
-
-.chip-in-progress {
- background-color: #f5a623 !important;
- color: white;
-}
-
-.chip-transferring {
- background-color: #f5a623 !important;
- color: white;
-}
-
-.header-container-title {
- flex-grow: 1;
- text-align: left;
- margin-left: 1em;
-}
-
-.images-button-row {
- display: flex;
- gap: 15px;
- padding: 5px;
-}
-
diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html
deleted file mode 100644
index e1f3c60..0000000
--- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
-
- {{ 'searchLabel' | translate }}
-
- search
- {{ 'searchHint' | translate }}
-
-
- Estado
-
- Fallido
- Pendiente
- Transfiriendo
- Creado con éxito
- En progreso
- Papelera
- Creando archivos auxiliares
-
-
-
-
-
-
- {{ column.header }} |
-
-
-
- {{ image.image[column.columnDef] ? 'check_circle' : 'cancel' }}
-
-
-
-
- {{ getStatusLabel(image[column.columnDef]) }}
-
-
-
- {{ column.cell(image) }}
-
- |
-
-
-
- Acciones |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.spec.ts b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.spec.ts
deleted file mode 100644
index 064bad7..0000000
--- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.spec.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { provideHttpClient } from '@angular/common/http';
-import { provideHttpClientTesting } from '@angular/common/http/testing';
-import { ReactiveFormsModule, FormsModule, FormBuilder } from '@angular/forms';
-import { MatButtonModule } from '@angular/material/button';
-import { MatCheckboxModule } from '@angular/material/checkbox';
-import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { MatTableModule } from '@angular/material/table';
-import { MatPaginatorModule } from '@angular/material/paginator';
-import { MatDividerModule } from '@angular/material/divider';
-import { MatIconModule } from '@angular/material/icon';
-import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import { TranslateModule } from '@ngx-translate/core';
-import { ToastrModule, ToastrService } from 'ngx-toastr';
-import { JoyrideModule } from 'ngx-joyride';
-import { CommonModule } from '@angular/common';
-import {MatProgressSpinner} from "@angular/material/progress-spinner";
-import {RepositoryImagesComponent} from "./repository-images.component";
-import {LoadingComponent} from "../../../shared/loading/loading.component";
-import {MatOptionModule} from "@angular/material/core";
-import {MatSelectModule} from "@angular/material/select";
-import { ConfigService } from '@services/config.service';
-
-describe('RepositoriesComponent', () => {
- let component: RepositoryImagesComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- const mockConfigService = {
- apiUrl: 'http://mock-api-url',
- mercureUrl: 'http://mock-mercure-url'
- };
-
- await TestBed.configureTestingModule({
- declarations: [RepositoryImagesComponent, LoadingComponent],
- imports: [
- ReactiveFormsModule,
- FormsModule,
- MatDialogModule,
- MatFormFieldModule,
- MatInputModule,
- MatCheckboxModule,
- MatButtonModule,
- MatTableModule,
- MatPaginatorModule,
- MatDividerModule,
- MatIconModule,
- MatOptionModule,
- BrowserAnimationsModule,
- MatProgressSpinner,
- MatSelectModule ,
- ToastrModule.forRoot(),
- TranslateModule.forRoot(),
- JoyrideModule.forRoot(),
- CommonModule
- ],
- providers: [
- FormBuilder,
- ToastrService,
- provideHttpClient(),
- provideHttpClientTesting(),
- {
- provide: MatDialogRef,
- useValue: {}
- },
- {
- provide: MAT_DIALOG_DATA,
- useValue: {}
- },
- { provide: ConfigService, useValue: mockConfigService }
- ]
- }).compileComponents();
-
- fixture = TestBed.createComponent(RepositoryImagesComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts
deleted file mode 100644
index 5fde29f..0000000
--- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts
+++ /dev/null
@@ -1,362 +0,0 @@
-import {Component, Input, isDevMode, OnInit} from '@angular/core';
-import {MatTableDataSource} from "@angular/material/table";
-import {DatePipe} from "@angular/common";
-import {MatDialog} from "@angular/material/dialog";
-import {HttpClient} from "@angular/common/http";
-import {ToastrService} from "ngx-toastr";
-import {JoyrideService} from "ngx-joyride";
-import {Observable} from "rxjs";
-import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
-import {ExportImageComponent} from "../../images/export-image/export-image.component";
-import {BackupImageComponent} from "../backup-image/backup-image.component";
-import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
-import {ImportImageComponent} from "../import-image/import-image.component";
-import {ConvertImageComponent} from "../convert-image/convert-image.component";
-import { ConfigService } from '@services/config.service';
-import {Router} from "@angular/router";
-
-@Component({
- selector: 'app-repository-images',
- templateUrl: './repository-images.component.html',
- styleUrl: './repository-images.component.css'
-})
-export class RepositoryImagesComponent implements OnInit {
- baseUrl: string;
- private apiUrl: string;
- dataSource = new MatTableDataSource();
- length: number = 0;
- itemsPerPage: number = 10;
- page: number = 0;
- loading: boolean = false;
- filters: { [key: string]: string } = {};
- alertMessage: string | null = null;
- repository: any = {};
- datePipe: DatePipe = new DatePipe('es-ES');
- columns = [
- {
- columnDef: 'id',
- header: 'Id',
- cell: (image: any) => `${image.id}`
- },
- {
- columnDef: 'name',
- header: 'Nombre de imagen',
- cell: (image: any) => `${image.image.name}`
- },
- {
- columnDef: 'remotePc',
- header: 'Remote Pc',
- cell: (image: any) => `${image.image?.remotePc}`
- },
- {
- columnDef: 'isGlobal',
- header: 'Imagen global',
- cell: (image: any) => `${image.image?.isGlobal}`
- },
- {
- columnDef: 'status',
- header: 'Estado',
- cell: (image: any) => `${image.status}`
- },
- {
- columnDef: 'imageFullsum',
- header: 'Fullsum',
- cell: (image: any) => `${image.imageFullsum}`
- },
- {
- columnDef: 'createdAt',
- header: 'Fecha de creación',
- cell: (image: any) => `${this.datePipe.transform(image.createdAt, 'dd/MM/yyyy hh:mm:ss')}`
- }
- ];
- displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
-
- @Input() repositoryUuid: any
- private repositoryId: any;
-
- constructor(
- public dialog: MatDialog,
- private http: HttpClient,
- private toastService: ToastrService,
- private joyrideService: JoyrideService,
- private configService: ConfigService,
- private router: Router,
- ) {
- this.baseUrl = this.configService.apiUrl;
- this.apiUrl = `${this.baseUrl}/image-image-repositories`;
- }
-
- ngOnInit(): void {
- if (this.repositoryUuid) {
- this.loadRepository()
- } else {
- this.search();
- }
- }
-
- loadRepository(): void {
- this.http.get(`${this.baseUrl}/image-repositories/${this.repositoryUuid}`, {}).subscribe(
- data => {
- this.repositoryId = data.id;
- this.repository = data
- this.search();
- },
- error => {
- console.error('Error fetching image repositories', error);
- }
- )
- }
-
- getStatusLabel(status: string): string {
- switch (status) {
- case 'pending':
- return 'Pendiente';
- case 'in-progress':
- return 'En progreso';
- case 'aux-files-pending':
- return 'Archivos auxiliares pendientes';
- case 'success':
- return 'Creado con éxito';
- case 'trash':
- return 'Papelera temporal';
- case 'failed':
- return 'Fallido';
- case 'transferring':
- return 'Transfiriendo';
- default:
- return 'Estado desconocido';
- }
- }
-
- search(): void {
- this.loading = true;
- this.http.get(`${this.apiUrl}?page=${this.page +1 }&itemsPerPage=${this.itemsPerPage}&repository.id=${this.repositoryId}`, { params: this.filters }).subscribe(
- data => {
- this.dataSource.data = data['hydra:member'];
- this.length = data['hydra:totalItems'];
- this.loading = false;
- },
- error => {
- console.error('Error fetching images', error);
- this.loading = false;
- }
- );
- }
-
- onPageChange(event: any): void {
- this.page = event.pageIndex;
- this.itemsPerPage = event.pageSize;
- this.length = event.length;
- this.search();
- }
-
- loadImageAlert(image: any): Observable {
- return this.http.get(`${this.apiUrl}/server/${image.uuid}/get`, {});
- }
-
- showImageInfo(event: MouseEvent, image:any) {
- event.stopPropagation();
- this.loading = true;
- this.loadImageAlert(image).subscribe(
- response => {
- this.alertMessage = response;
-
- this.dialog.open(ServerInfoDialogComponent, {
- width: '800px',
- data: {
- message: this.alertMessage
- }
- });
- this.loading = false;
- },
- error => {
- this.toastService.error(error.error['hydra:description']);
- this.loading = false;
- }
- );
- }
-
- importImage(): void {
- this.dialog.open(ImportImageComponent, {
- width: '600px',
- data: {
- repositoryUuid: this.repositoryUuid,
- name: this.repository.name
- }
- }).afterClosed().subscribe((result) => {
- if (result) {
- this.search();
- }
- });
- }
-
- convertImage(): void {
- this.dialog.open(ConvertImageComponent, {
- width: '600px',
- data: {
- repositoryUuid: this.repositoryUuid,
- name: this.repository.name
- }
- }).afterClosed().subscribe((result) => {
- if (result) {
- this.search();
- }
- });
- }
-
- toggleAction(image: any, action:string): void {
- switch (action) {
- case 'get-aux':
- this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/create-aux-files`, {}).subscribe({
- next: (message) => {
- this.toastService.success('Petición de creación de archivos auxiliares enviada');
- this.search()
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- break;
- case 'delete-trash':
- if (!image.imageFullsum) {
- const dialogRef = this.dialog.open(DeleteModalComponent, {
- width: '400px',
- data: { name: image.name },
- });
-
- dialogRef.afterClosed().subscribe((result) => {
- this.http.delete(`${this.baseUrl}${image['@id']}`).subscribe({
- next: () => {
- this.toastService.success('Image deleted successfully');
- this.search()
- },
- error: (error) => {
- this.toastService.error('Error deleting image');
- }
- });
- });
- } else {
- this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/delete-trash`,
- { repository: `/image-repositories/${this.repositoryUuid}` })
- .subscribe({
- next: () => {
- this.toastService.success('Petición de eliminación de la papelera temporal enviada');
- this.search()
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- }
-
- break;
- case 'delete-permanent':
- this.dialog.open(DeleteModalComponent, {
- width: '300px',
- data: { name: image.name },
- }).afterClosed().subscribe((result) => {
- if (result) {
- this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/delete-permanent`, {}).subscribe({
- next: () => {
- this.toastService.success('Petición de eliminación de la papelera temporal enviada');
- this.search()
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- }
- });
- break;
- case 'recover':
- this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/recover`, {}).subscribe({
- next: () => {
- this.toastService.success('Petición de recuperación de la imagen enviada');
- this.search()
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- break;
- case 'status':
- this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/status`, {}).subscribe({
- next: (response: any) => {
- this.toastService.info(response?.output);
- this.search()
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- break;
- case 'transfer':
- this.http.get(`${this.baseUrl}${image.image['@id']}`).subscribe({
- next: (response) => {
- this.dialog.open(ExportImageComponent, {
- width: '600px',
- data: {
- image: response,
- imageImageRepository: image
- }
- });
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- break;
- case 'transfer-global':
- this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/transfer-global`, {
- }).subscribe({
- next: (response) => {
- this.toastService.success('Petición de exportación de imagen realizada correctamente');
- this.loading = false;
- this.router.navigate(['/commands-logs']);
- },
- error: error => {
- this.loading = false;
- this.toastService.error('Error en la petición de exportación de imagen');
- }
- });
- break;
- case 'backup':
- this.http.get(`${this.baseUrl}${image.image['@id']}`).subscribe({
- next: (response) => {
- this.dialog.open(BackupImageComponent, {
- width: '600px',
- data: {
- image: response,
- imageImageRepository: image
- }
- });
- },
- error: (error) => {
- this.toastService.error(error.error['hydra:description']);
- }
- });
- break;
- default:
- console.error('Acción no soportada:', action);
- break;
- }
- }
- iniciarTour(): void {
- this.joyrideService.startTour({
- steps: [
- 'imagesTitleStep',
- 'addImageButton',
- 'searchImagesField',
- 'imagesTable',
- 'actionsHeader',
- 'editImageButton',
- 'deleteImageButton',
- 'imagesPagination'
- ],
- showPrevButton: true,
- themeColor: '#3f51b5'
- });
- }
-
- protected readonly isDevMode = isDevMode;
-}
diff --git a/ogWebconsole/src/assets/images/close-delete-remove-trash-cancel-cross-svgrepo-com.svg b/ogWebconsole/src/assets/images/close-delete-remove-trash-cancel-cross-svgrepo-com.svg
new file mode 100644
index 0000000..1d3d548
--- /dev/null
+++ b/ogWebconsole/src/assets/images/close-delete-remove-trash-cancel-cross-svgrepo-com.svg
@@ -0,0 +1,12 @@
+
+
+
\ No newline at end of file
diff --git a/ogWebconsole/src/assets/images/computer_disconnected.svg b/ogWebconsole/src/assets/images/computer_disconnected.svg
new file mode 100644
index 0000000..e455b73
--- /dev/null
+++ b/ogWebconsole/src/assets/images/computer_disconnected.svg
@@ -0,0 +1,4 @@
+
diff --git a/ogWebconsole/src/assets/images/computer_initializing.svg b/ogWebconsole/src/assets/images/computer_initializing.svg
index f0e2e65..152a739 100644
--- a/ogWebconsole/src/assets/images/computer_initializing.svg
+++ b/ogWebconsole/src/assets/images/computer_initializing.svg
@@ -1,3 +1,4 @@
-