diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index f35957b..a462ce1 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -100,6 +100,7 @@ import { DetailTaskComponent } from './components/commands/commands-task/detail- import { ClientTabViewComponent } from './components/groups/components/client-tab-view/client-tab-view.component'; import { AdvancedSearchComponent } from './components/groups/components/advanced-search/advanced-search.component'; import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; +import { OrganizationalUnitTabViewComponent } from './components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component'; @NgModule({ declarations: [ AppComponent, @@ -156,7 +157,8 @@ import { TaskLogsComponent } from './components/commands/commands-task/task-logs DetailTaskComponent, ClientTabViewComponent, AdvancedSearchComponent, - TaskLogsComponent + TaskLogsComponent, + OrganizationalUnitTabViewComponent ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/calendar/calendar.component.html b/ogWebconsole/src/app/components/calendar/calendar.component.html index 990232f..9e6a6b6 100644 --- a/ogWebconsole/src/app/components/calendar/calendar.component.html +++ b/ogWebconsole/src/app/components/calendar/calendar.component.html @@ -23,12 +23,6 @@ - - - {{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }} - - - {{ column.cell(image) }} @@ -40,7 +34,8 @@ Acciones - + + diff --git a/ogWebconsole/src/app/components/calendar/calendar.component.ts b/ogWebconsole/src/app/components/calendar/calendar.component.ts index 0a1671d..d21d2d4 100644 --- a/ogWebconsole/src/app/components/calendar/calendar.component.ts +++ b/ogWebconsole/src/app/components/calendar/calendar.component.ts @@ -29,21 +29,27 @@ export class CalendarComponent implements OnInit { alertMessage: string | null = null; readonly panelOpenState = signal(false); datePipe: DatePipe = new DatePipe('es-ES'); + syncUds: boolean = false; columns = [ { columnDef: 'id', header: 'ID', - cell: (user: any) => `${user.id}`, + cell: (remoteCalendar: any) => `${remoteCalendar.id}`, }, { columnDef: 'name', header: 'Nombre', - cell: (user: any) => `${user.name}` + cell: (remoteCalendar: any) => `${remoteCalendar.name}` + }, + { + columnDef: 'rulesLength', + header: 'Nº de reglas', + cell: (remoteCalendar: any) => `${remoteCalendar.remoteCalendarRules.length}` }, { columnDef: 'createdAt', header: 'Fecha de creación', - cell: (user: any) => `${this.datePipe.transform(user.createdAt, 'dd/MM/yyyy hh:mm:ss')}`, + cell: (remoteCalendar: any) => `${this.datePipe.transform(remoteCalendar.createdAt, 'dd/MM/yyyy hh:mm:ss')}`, } ]; displayedColumns = [...this.columns.map(column => column.columnDef), 'actions']; @@ -88,6 +94,20 @@ export class CalendarComponent implements OnInit { sync(calendar: any): void { console.log('Syncing calendars'); + this.syncUds = true; + this.http.post(`${this.apiUrl}/${calendar.uuid}/sync-uds`, {}).subscribe({ + next: () => { + console.log('Calendars synced successfully'); + this.toastService.success('Calendarios sincronizados correctamente'); + this.search(); + this.syncUds = false; + }, + error: (error) => { + console.error('Error al sincronizar los calendarios:', error); + this.toastService.error(error.error['hydra:description']); + this.syncUds = false; + } + }); } editCalendar(calendar: any): void { diff --git a/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html b/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html index 8249a20..9fe6871 100644 --- a/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html +++ b/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html @@ -17,16 +17,15 @@ -
Hora de inicio - + Hora de fin - +
@@ -34,19 +33,19 @@
Razón - +
Fecha de inicio - + MM/DD/YYYY Fecha de fin - + MM/DD/YYYY @@ -57,5 +56,11 @@ - + diff --git a/ogWebconsole/src/app/components/calendar/create-calendar/create-calendar.component.html b/ogWebconsole/src/app/components/calendar/create-calendar/create-calendar.component.html index c90baeb..803f79b 100644 --- a/ogWebconsole/src/app/components/calendar/create-calendar/create-calendar.component.html +++ b/ogWebconsole/src/app/components/calendar/create-calendar/create-calendar.component.html @@ -23,7 +23,8 @@
{{ rule.isRemoteAvailable ? 'Disponible' : 'No disponible ( periodo presencial )' }}
{{ rule.busyFromHour }} - {{ rule.busyToHour }}
-
{{ rule.availableReason }} | {{ rule.busyFromHour }} - {{ rule.busyToHour }}
+
{{ rule.busyWeekDaysMap }}
+
{{ rule.availableReason }} | {{ rule.availableFromDate | date }} - {{ rule.availableToDate | date }}
- diff --git a/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts b/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts index 278c00f..cc4b819 100644 --- a/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-tab-view/client-tab-view.component.ts @@ -11,6 +11,7 @@ import {CreateClientComponent} from "../../shared/clients/create-client/create-c import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; import { throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; +import {ClientViewComponent} from "../../shared/client-view/client-view.component"; @Component({ selector: 'app-client-tab-view', templateUrl: './client-tab-view.component.html', @@ -23,7 +24,7 @@ export class ClientTabViewComponent { loading:boolean = false; itemsPerPage: number = 10; pageSizeOptions: number[] = [5, 10, 25, 100]; - page: number = 1; + page: number = 0; filters: { [key: string]: string } = {}; organizationalUnits: any[] = []; datePipe: DatePipe = new DatePipe('es-ES'); @@ -77,7 +78,7 @@ export class ClientTabViewComponent { } getClients() { - this.http.get(`${this.apiUrl}?&page=${this.page}&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe( + this.http.get(`${this.apiUrl}?&page=${this.page + 1 }&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe( (data) => { this.dataSource.data = data['hydra:member']; this.length = data['hydra:totalItems']; @@ -123,6 +124,11 @@ export class ClientTabViewComponent { }); } + handleClientClick(event: MouseEvent, client: any): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(ClientViewComponent, { data: { client }, width: '800px', height:'700px' }); + } + resetFilters() { this.loading = true; this.filters = {}; diff --git a/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.css b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.css new file mode 100644 index 0000000..27cd5b5 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.css @@ -0,0 +1,36 @@ + +.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; +} + +button{ + margin-left: 10px; +} diff --git a/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.html b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.html new file mode 100644 index 0000000..b781fd6 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.html @@ -0,0 +1,58 @@ +
+

Administrar unidades organizativas

+
+ + +
+
+ +
+ + Buscar nombre de cliente + + search + Pulsar 'enter' para buscar + + + Tipo + + Todos + Unidad organizativa + Grupos de aulas + Aula + Grupos de PCs + + +
+ + + + + + + + + + + + + +
{{ column.header }} + + {{ column.cell(image) }} + + Acciones + + + +
+
+ + +
diff --git a/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.spec.ts b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.spec.ts new file mode 100644 index 0000000..0c495fd --- /dev/null +++ b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OrganizationalUnitTabViewComponent } from './organizational-unit-tab-view.component'; + +describe('OrganizationalUnitTabViewComponent', () => { + let component: OrganizationalUnitTabViewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [OrganizationalUnitTabViewComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OrganizationalUnitTabViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.ts b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.ts new file mode 100644 index 0000000..788d0d2 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/components/organizational-unit-tab-view/organizational-unit-tab-view.component.ts @@ -0,0 +1,149 @@ +import { Component } from '@angular/core'; +import {MatTableDataSource} from "@angular/material/table"; +import {DatePipe} from "@angular/common"; +import {DataService} from "../client-tab-view/data.service"; +import {MatDialog} from "@angular/material/dialog"; +import {ToastrService} from "ngx-toastr"; +import {HttpClient} from "@angular/common/http"; +import {EditClientComponent} from "../../shared/clients/edit-client/edit-client.component"; +import {CreateClientComponent} from "../../shared/clients/create-client/create-client.component"; +import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; +import {catchError} from "rxjs/operators"; +import {throwError} from "rxjs"; +import { + CreateOrganizationalUnitComponent +} from "../../shared/organizational-units/create-organizational-unit/create-organizational-unit.component"; +import { + ShowOrganizationalUnitComponent +} from "../../shared/organizational-units/show-organizational-unit/show-organizational-unit.component"; +import { + EditOrganizationalUnitComponent +} from "../../shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component"; + +@Component({ + selector: 'app-organizational-unit-tab-view', + templateUrl: './organizational-unit-tab-view.component.html', + styleUrl: './organizational-unit-tab-view.component.css' +}) +export class OrganizationalUnitTabViewComponent { + 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 = 0; + filters: { [key: string]: string } = {}; + organizationalUnits: any[] = []; + datePipe: DatePipe = new DatePipe('es-ES'); + + private apiUrl = `${this.baseUrl}/organizational-units`; + + columns = [ + { + columnDef: 'id', + header: 'ID', + cell: (ou: any) => `${ou.id}` + }, + { + columnDef: 'name', + header: 'Nombre', + cell: (ou: any) => `${ou.name}` + }, + { + columnDef: 'type', + header: 'Tipo', + cell: (ou: any) => `${ou.type}` + }, + { + columnDef: 'createdAt', + header: 'Fecha de creación', + cell: (ou: any) => `${this.datePipe.transform(ou.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.getOrganizationalUnits(); + } + + getOrganizationalUnits() { + this.http.get(`${this.apiUrl}?&page=${this.page + 1}&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); + } + ); + } + + onShowClick(event: MouseEvent, data: any): void { + event.stopPropagation(); + if (data.type != "client") { + const dialogRef = this.dialog.open(ShowOrganizationalUnitComponent, { data: { data }, width: '700px'}); + } + } + + onEditClick(event: MouseEvent, uuid: string): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid }, width: '700px'}); + dialogRef.afterClosed().subscribe(() => this.getOrganizationalUnits()); + } + + addOrganizationalUnit(event: MouseEvent, organizationalUnit:any = null): void { + event.stopPropagation(); + const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, { data: { organizationalUnit }, width: '900px'}); + dialogRef.afterClosed().subscribe(() => { + this.getOrganizationalUnits(); + }); + } + + 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.getOrganizationalUnits(); + }); + } + }); + } + + resetFilters() { + this.loading = true; + this.filters = {}; + this.getOrganizationalUnits(); + } + + + search(): void { + this.loading = true; + this.getOrganizationalUnits() + } + + onPageChange(event: any): void { + this.page = event.pageIndex; + this.itemsPerPage = event.pageSize; + this.length = event.length; + this.getOrganizationalUnits(); + } +} diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 2db1732..e0ce288 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -29,15 +29,7 @@ [ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
apartment - {{ breadcrumb.length === 0 ? unidad.name : null }} - - - - {{ crumb }} - > - - - + {{ unidad.name }} more_vert @@ -161,4 +153,7 @@ + + + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.css index 9b093f0..e71097c 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.css @@ -45,6 +45,20 @@ button { border-bottom: 1px solid rgba(122, 122, 122, 0.555); } +.search-container { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 0 5px; + box-sizing: border-box; +} + +.search-string { + flex: 2; + padding: 5px; +} + .image-container h4 { margin: 0; flex: 1; diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html index f081224..23ffbad 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html @@ -21,60 +21,48 @@
+ + +
+ + Buscar nombre de imagen + + search + Pulsar 'enter' para buscar + + + Buscar netmask + + search + Pulsar 'enter' para buscar + + + Buscar IP + + search + Pulsar 'enter' para buscar + +
- - + @@ -85,4 +73,4 @@ - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts index 71bd6ae..81c986b 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts @@ -29,17 +29,19 @@ export interface Subnet { }) export class OgDhcpSubnetsComponent { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - displayedColumns: string[] = ['name', 'netmask', 'ipAddress', 'nextServer', 'bootFileName', 'actions']; + displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'nextServer', 'bootFileName', 'actions']; dataSource = new MatTableDataSource([]); length = 0; itemsPerPage: number = 10; page = 0; + filters: { [key: string]: string } = {}; pageSizeOptions: number[] = [5, 10, 20]; alertMessage: string | null = null; @ViewChild(MatPaginator) paginator: MatPaginator | undefined; - + columns = [ + { columnDef: 'id', header: 'ID', cell: (subnet: Subnet) => subnet.id }, { columnDef: 'name', header: 'Name', cell: (subnet: Subnet) => subnet.name }, { columnDef: 'netmask', header: 'Netmask', cell: (subnet: Subnet) => subnet.netmask }, { columnDef: 'ipAddress', header: 'IP Address', cell: (subnet: Subnet) => subnet.ipAddress }, @@ -89,9 +91,9 @@ export class OgDhcpSubnetsComponent { console.log('Editando subnet:', subnet); const dialogRef = this.dialog.open(CreateSubnetComponent, { width: '400px', - data: { subnet } + data: { subnet } }); - + dialogRef.afterClosed().subscribe(result => { console.log('The dialog was closed'); this.loadSubnets() @@ -104,11 +106,11 @@ export class OgDhcpSubnetsComponent { width: '300px', data: { name: subnet.name } }); - + dialogRef.afterClosed().subscribe(result => { if (result) { const apiUrl = `${this.baseUrl}${subnet['@id']}`; - + this.http.delete(apiUrl).subscribe({ next: () => { console.log('Subnet deleted successfully'); @@ -131,12 +133,12 @@ export class OgDhcpSubnetsComponent { } addClientsToSubnet(subnet: Subnet) { - + const dialogRef = this.dialog.open(AddClientsToSubnetComponent, { width: '600px', - data: { subnetUuid: subnet.uuid, subnetName: subnet.name } + data: { subnetUuid: subnet.uuid, subnetName: subnet.name } }); - + dialogRef.afterClosed().subscribe(result => { console.log('The dialog was closed'); this.loadSubnets();
{{ column.header }} - - - {{ subnet.name }} + + {{ column.cell(subnet) }} - - - {{ subnet.netmask }} - - - - {{ subnet.ipAddress }} - - - - {{ subnet.nextServer }} - - - - {{ subnet.bootFileName }} - - Acciones + Acciones - - - - - - - -