From b8cfa9a4e1e8424145ad6f6c6f8d8211c2ec5461 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 27 Sep 2024 11:58:18 +0200 Subject: [PATCH] Added new tab in groups. Search client --- ogWebconsole/src/app/app.module.ts | 4 +- .../create-command-group.component.ts | 10 +- .../create-task/create-task.component.html | 11 +- .../create-task/create-task.component.ts | 9 +- .../create-command.component.ts | 3 +- .../client-tab-view.component.css | 32 ++++ .../client-tab-view.component.html | 67 ++++++++ .../client-tab-view.component.spec.ts | 23 +++ .../client-tab-view.component.ts | 157 ++++++++++++++++++ .../groups/client-tab-view/data.service.ts | 35 ++++ .../create-client/create-client.component.css | 17 +- .../create-client.component.html | 14 +- .../edit-client/edit-client.component.css | 16 +- .../edit-client/edit-client.component.html | 16 +- .../components/groups/groups.component.css | 1 - .../components/groups/groups.component.html | 3 + .../app/components/groups/groups.component.ts | 15 +- 17 files changed, 394 insertions(+), 39 deletions(-) create mode 100644 ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.css create mode 100644 ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.html create mode 100644 ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.spec.ts create mode 100644 ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.ts create mode 100644 ogWebconsole/src/app/components/groups/client-tab-view/data.service.ts diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index db3797b..a266182 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -94,6 +94,7 @@ import { CreateCommandGroupComponent } from './components/commands/commands-grou import { DetailCommandGroupComponent } from './components/commands/commands-groups/detail-command-group/detail-command-group.component'; import { CreateTaskComponent } from './components/commands/commands-task/create-task/create-task.component'; import { DetailTaskComponent } from './components/commands/commands-task/detail-task/detail-task.component'; +import { ClientTabViewComponent } from './components/groups/client-tab-view/client-tab-view.component'; @NgModule({ declarations: [ AppComponent, @@ -144,7 +145,8 @@ import { DetailTaskComponent } from './components/commands/commands-task/detail- CreateCommandGroupComponent, DetailCommandGroupComponent, CreateTaskComponent, - DetailTaskComponent + DetailTaskComponent, + ClientTabViewComponent ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/commands/commands-groups/create-command-group/create-command-group.component.ts b/ogWebconsole/src/app/components/commands/commands-groups/create-command-group/create-command-group.component.ts index 2d4bd88..fe9c58d 100644 --- a/ogWebconsole/src/app/components/commands/commands-groups/create-command-group/create-command-group.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-groups/create-command-group/create-command-group.component.ts @@ -15,8 +15,6 @@ export class CreateCommandGroupComponent implements OnInit { groupName: string = ''; position: number = 1; enabled: boolean = true; - - private apiUrl = 'http://127.0.0.1:8001/commands'; constructor( private http: HttpClient, @@ -29,9 +27,9 @@ export class CreateCommandGroupComponent implements OnInit { } loadAvailableCommands(): void { - this.http.get(this.apiUrl).subscribe( + this.http.get(`${this.baseUrl}/commands`).subscribe( (data) => { - this.availableCommands = data['hydra:member']; + this.availableCommands = data['hydra:member']; }, (error) => { console.error('Error fetching available commands', error); @@ -53,13 +51,13 @@ export class CreateCommandGroupComponent implements OnInit { onSubmit(): void { const payload = { name: this.groupName, - commands: this.selectedCommands.map(cmd => cmd['@id']), + commands: this.selectedCommands.map(cmd => cmd['@id']), position: this.position, enabled: this.enabled }; console.log('Payload', payload); - this.http.post('http://127.0.0.1:8001/command-groups', payload).subscribe({ + this.http.post(`${this.baseUrl}/command-groups`, payload).subscribe({ next: () => { this.toastService.success('Grupo de comandos creado con éxito'); this.dialogRef.close(); diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html index 467f882..7849cee 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html @@ -2,7 +2,16 @@ - Selecciona un Grupo de Comandos + Selecciona Comandos + + + {{ group.name }} + + + Este campo es obligatorio + + + Selecciona Grupo de Comandoss {{ group.name }} diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.ts b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.ts index 3bc5220..4dffbe4 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.ts @@ -25,8 +25,8 @@ export class CreateTaskComponent implements OnInit { ) { this.taskForm = this.fb.group({ commandGroup: ['', Validators.required], - date: ['', Validators.required], - time: ['', Validators.required], + date: ['', Validators.required], + time: ['', Validators.required], notes: [''] }); } @@ -65,11 +65,10 @@ export class CreateTaskComponent implements OnInit { } const formData = this.taskForm.value; - const dateTime = this.combineDateAndTime(formData.date, formData.time); + const dateTime = this.combineDateAndTime(formData.date, formData.time); const payload = { commandGroups: '/command-groups/'+formData.commandGroup, - commands: this.selectedGroupCommands.map(cmd => cmd['@id']), dateTime: dateTime, notes: formData.notes || '' }; @@ -90,7 +89,7 @@ export class CreateTaskComponent implements OnInit { const dateObj = new Date(date); const [hours, minutes] = time.split(':').map(Number); - dateObj.setHours(hours, minutes, 0); + dateObj.setHours(hours, minutes, 0); return dateObj.toISOString(); // Return in ISO format (e.g., 2021-10-01T00:00:00+00:00) } diff --git a/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.ts b/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.ts index 7a07a8f..f4cf673 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.ts +++ b/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.ts @@ -9,9 +9,10 @@ import { HttpClient } from '@angular/common/http'; styleUrls: ['./create-command.component.css'] }) export class CreateCommandComponent { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; createCommandForm!: FormGroup; isEditMode: boolean; - private apiUrl = 'http://127.0.0.1:8080/commands'; // URL para añadir o editar el comando + private apiUrl = `${this.baseUrl}/commands`; constructor( private fb: FormBuilder, diff --git a/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.css b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.css new file mode 100644 index 0000000..594f4e0 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.css @@ -0,0 +1,32 @@ + +.header-container { + display: flex; + justify-content: space-between; + align-items: center; + height: 100px; + padding: 10px; + margin-top: 16px; +} + +.search-container { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + box-sizing: border-box; +} + +.search-string { + flex: 1; + padding: 5px; +} + +.search-boolean { + flex: 1; + padding: 5px; +} + +.search-select { + flex: 2; + padding: 5px; +} diff --git a/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.html b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.html new file mode 100644 index 0000000..45c040a --- /dev/null +++ b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.html @@ -0,0 +1,67 @@ +
+

Administrar clientes

+
+ + +
+
+ +
+ + Buscar nombre de cliente + + search + Pulsar 'enter' para buscar + + + Buscar IP + + search + Pulsar 'enter' para buscar + + + Buscar MAC + + search + Pulsar 'enter' para buscar + + + U. Organizativa + + + {{ unit.name }} + + + +
+ + + + + + + + + + + + + +
{{ column.header }} + + {{ column.cell(image) }} + + Acciones + + +
+
+ + +
diff --git a/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.spec.ts b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.spec.ts new file mode 100644 index 0000000..53377bb --- /dev/null +++ b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ClientTabViewComponent } from './client-tab-view.component'; + +describe('ClientTabViewComponent', () => { + let component: ClientTabViewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ClientTabViewComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ClientTabViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.ts b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.ts new file mode 100644 index 0000000..9ca1503 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/client-tab-view/client-tab-view.component.ts @@ -0,0 +1,157 @@ +import { Component } from '@angular/core'; +import {PageEvent} from "@angular/material/paginator"; +import {DatePipe} from "@angular/common"; +import {MatTableDataSource} from "@angular/material/table"; +import {MatDialog} from "@angular/material/dialog"; +import {ToastrService} from "ngx-toastr"; +import {HttpClient} from "@angular/common/http"; +import {DataService} from "./data.service"; +import {EditClientComponent} from "../clients/edit-client/edit-client.component"; +import {CreateClientComponent} from "../clients/create-client/create-client.component"; +import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; +import { throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +@Component({ + selector: 'app-client-tab-view', + templateUrl: './client-tab-view.component.html', + styleUrl: './client-tab-view.component.css' +}) +export class ClientTabViewComponent { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + dataSource = new MatTableDataSource(); + length: number = 0; + loading:boolean = false; + itemsPerPage: number = 10; + pageSizeOptions: number[] = [5, 10, 25, 100]; + page: number = 1; + filters: { [key: string]: string } = {}; + organizationalUnits: any[] = []; + datePipe: DatePipe = new DatePipe('es-ES'); + + private apiUrl = `${this.baseUrl}/clients`; + + columns = [ + { + columnDef: 'id', + header: 'ID', + cell: (client: any) => `${client.id}` + }, + { + columnDef: 'name', + header: 'Nombre del cliente', + cell: (client: any) => `${client.name}` + }, + { + columnDef: 'ip', + header: 'IP', + cell: (client: any) => `${client.ip}` + }, + { + columnDef: 'mac', + header: 'Mac', + cell: (client: any) => `${client.mac}` + }, + { + columnDef: 'organizationalUnit', + header: 'Pertenece a', + cell: (client: any) => `${client.organizationalUnit.name}` + }, + { + columnDef: 'createdAt', + header: 'Fecha de creación', + cell: (client: any) => `${this.datePipe.transform(client.createdAt, 'dd/MM/yyyy hh:mm:ss')}` + } + ]; + displayedColumns = [...this.columns.map(column => column.columnDef), 'actions']; + + constructor( + private dataService: DataService, + public dialog: MatDialog, + private toastService: ToastrService, + private http: HttpClient + ) {} + + ngOnInit(): void { + this.getClients(); + this.loadOrganizationalUnits(); + } + + getClients() { + this.http.get(`${this.apiUrl}?&page=${this.page}&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe( + (data) => { + this.dataSource.data = data['hydra:member']; + this.length = data['hydra:totalItems']; + }, + (error) => { + console.error('Error fetching commands', error); + } + ); + } + + onEditClick(event: MouseEvent, uuid: string): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' } ); + dialogRef.afterClosed().subscribe(() => this.getClients()); + } + + addClient(event: MouseEvent, organizationalUnit:any = null): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(CreateClientComponent, { data: { organizationalUnit }, width: '900px'}); + dialogRef.afterClosed().subscribe(() => { + this.getClients(); + }); + } + + onDeleteClick(event: MouseEvent, client: any): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '400px' + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.delete(`${this.apiUrl}/${client.uuid}`).pipe( + catchError(error => { + this.toastService.error(error.error['hydra:description']); + return throwError(error); + }) + ).subscribe(() => { + this.toastService.success('Elemento eliminado correctamente'); + this.getClients(); + }); + } + }); + } + + resetFilters() { + this.loading = true; + this.filters = {}; + this.getClients(); + } + + loadOrganizationalUnits() { + this.loading = true; + this.http.get( `${this.baseUrl}/organizational-units?&page=1&itemsPerPage=10000`).subscribe( + response => { + this.organizationalUnits = response['hydra:member']; + this.loading = false; + }, + error => { + console.error('Error fetching parent units:', error); + this.loading = false; + } + ); + } + + search(): void { + this.loading = true; + this.getClients() + } + + onPageChange(event: any): void { + this.page = event.pageIndex; + this.itemsPerPage = event.pageSize; + this.length = event.length; + this.getClients(); + } +} diff --git a/ogWebconsole/src/app/components/groups/client-tab-view/data.service.ts b/ogWebconsole/src/app/components/groups/client-tab-view/data.service.ts new file mode 100644 index 0000000..cade56a --- /dev/null +++ b/ogWebconsole/src/app/components/groups/client-tab-view/data.service.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core'; +import {HttpClient, HttpParams} from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class DataService { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + + private apiUrl = `${this.baseUrl}/organizational-units`; + private clientsUrl = `${this.baseUrl}/clients`; + + constructor(private http: HttpClient) {} + + getClients(itemsPerPage: number = 10, page: number = 1): Observable { + return this.http.get(this.clientsUrl, { + params: new HttpParams().set('itemsPerPage', itemsPerPage.toString()).set('page', page.toString()) + }) + .pipe( + map(response => { + if (response['hydra:member'] && Array.isArray(response['hydra:member'])) { + return response['hydra:member'] + } else { + throw new Error('Unexpected response format'); + } + }), + catchError(error => { + console.error('Error fetching clients', error); + return throwError(error); + }) + ); + } +} diff --git a/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.css b/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.css index 687587d..fcf40bd 100644 --- a/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.css +++ b/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.css @@ -21,12 +21,6 @@ h1 { padding: 50px; } -.mat-dialog-actions { - display: flex; - justify-content: flex-end; - padding: 10px 20px; -} - button { text-transform: none; font-size: 16px; @@ -56,5 +50,14 @@ mat-option .unit-path { .create-client-container { position: relative; - height: 90vh; +} + +.grid-form { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20px; +} + +.form-field { + width: 100%; } diff --git a/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.html b/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.html index 5a939cc..f6c7379 100644 --- a/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.html +++ b/ogWebconsole/src/app/components/groups/clients/create-client/create-client.component.html @@ -2,7 +2,7 @@

Añadir Cliente

-
+ Padre @@ -12,10 +12,12 @@ + Nombre + OgLive @@ -24,10 +26,12 @@ + Número de Serie + Interfaz de red @@ -36,6 +40,7 @@ + Controlador de red @@ -44,23 +49,27 @@ + MAC Ejemplo: 00:11:22:33:44:55 Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55 + Dirección IP Ejemplo: 127.0.0.1 Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1 + Menú URL Formato de URL inválido. + Perfil de Hardware @@ -72,7 +81,8 @@
-
+ +
diff --git a/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.css b/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.css index 79104af..69cf4a7 100644 --- a/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.css +++ b/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.css @@ -21,12 +21,6 @@ h1 { padding: 50px; } -.mat-dialog-actions { - display: flex; - justify-content: flex-end; - padding: 10px 20px; -} - button { text-transform: none; font-size: 16px; @@ -58,3 +52,13 @@ button { .form-field { width: 100%; } + +.grid-form { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20px; +} + +.form-field { + width: 100%; +} diff --git a/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.html b/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.html index 78e41e8..1b3d5a1 100644 --- a/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.html +++ b/ogWebconsole/src/app/components/groups/clients/edit-client/edit-client.component.html @@ -1,7 +1,8 @@

Editar Cliente

-
+ + Padre @@ -10,10 +11,12 @@ + Nombre + OgLive @@ -22,10 +25,12 @@ + Número de Serie + Interfaz de red @@ -34,6 +39,7 @@ + Controlador de red @@ -42,21 +48,25 @@ + MAC Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55 + Dirección IP Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1 + Menú URL Formato de URL inválido. + Perfil de Hardware @@ -66,9 +76,11 @@ Formato de URL inválido. +
-
+ +
+ + + diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index b8be0e8..184aa3e 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -17,6 +17,8 @@ import {HttpClient} from "@angular/common/http"; import {PageEvent} from "@angular/material/paginator"; import { SaveFiltersDialogComponent } from './save-filters-dialog/save-filters-dialog.component'; import { AcctionsModalComponent } from './acctions-modal/acctions-modal.component'; +import {MatTableDataSource} from "@angular/material/table"; +import {DatePipe} from "@angular/common"; @Component({ selector: 'app-groups', @@ -25,6 +27,7 @@ import { AcctionsModalComponent } from './acctions-modal/acctions-modal.componen }) export class GroupsComponent implements OnInit { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + dataSource = new MatTableDataSource(); organizationalUnits: UnidadOrganizativa[] = []; selectedUnidad: UnidadOrganizativa | null = null; selectedDetail: any | null = null; @@ -37,12 +40,10 @@ export class GroupsComponent implements OnInit { searchTerm: string = ''; selectedFilter1: string = 'none'; selectedFilter2: string = 'none'; - selectedFilterOS: string[] = []; selectedFilterStatus: string[] = []; filterIP: string = ''; filterMAC: string = ''; - filterName: string = ''; filteredResults: any[] = []; savedFilterNames: any[] = []; @@ -52,7 +53,8 @@ export class GroupsComponent implements OnInit { pageSizeOptions: number[] = [5, 10, 25, 100]; selectedElements: any[] = []; isAllSelected: boolean = false; - + filters: { [key: string]: string } = {}; + datePipe: DatePipe = new DatePipe('es-ES'); constructor( private dataService: DataService, @@ -155,7 +157,7 @@ export class GroupsComponent implements OnInit { addOU(event: MouseEvent, parent:any = null): void { event.stopPropagation(); - const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, { data: { parent }, width: '700px'}); + const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, { data: { parent }, width: '900px'}); dialogRef.afterClosed().subscribe(() => { this.dataService.getOrganizationalUnits().subscribe( data => { @@ -170,7 +172,7 @@ export class GroupsComponent implements OnInit { addClient(event: MouseEvent, organizationalUnit:any = null): void { event.stopPropagation(); - const dialogRef = this.dialog.open(CreateClientComponent, { data: { organizationalUnit }, width: '700px'}); + const dialogRef = this.dialog.open(CreateClientComponent, { data: { organizationalUnit }, width: '900px'}); dialogRef.afterClosed().subscribe(() => { this.dataService.getOrganizationalUnits().subscribe( @@ -318,7 +320,6 @@ export class GroupsComponent implements OnInit { this.applyFilter(); } - saveFilters() { const dialogRef = this.dialog.open(SaveFiltersDialogComponent); @@ -401,7 +402,7 @@ export class GroupsComponent implements OnInit { isSelected(name: string): boolean { return this.selectedElements.includes(name); - + }