Merge branch 'develop' of ssh://ognproject.evlt.uma.es:21987/opengnsys/oggui into develop
commit
4001d2adca
|
@ -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,
|
||||
|
|
|
@ -23,12 +23,6 @@
|
|||
</mat-icon>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'downloadUrl'">
|
||||
<span matTooltip="{{ image.downloadUrl }}">
|
||||
{{ image.downloadUrl ? image.downloadUrl.substring(0, 20) + '...' : '' }}
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl'">
|
||||
{{ column.cell(image) }}
|
||||
</ng-container>
|
||||
|
@ -40,7 +34,8 @@
|
|||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||
<td mat-cell *matCellDef="let calendar" style="text-align: center;">
|
||||
<button mat-icon-button color="primary" (click)="editCalendar(calendar)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button color="primary" (click)="sync(calendar)"><mat-icon>sync</mat-icon></button>
|
||||
<button *ngIf="!syncUds" mat-icon-button color="primary" (click)="sync(calendar)"><mat-icon>sync</mat-icon></button>
|
||||
<button *ngIf="syncUds" mat-icon-button color="primary"><mat-spinner diameter="24"></mat-spinner></button>
|
||||
<button mat-icon-button color="warn" (click)="deleteCalendar(calendar)" i18n="@@buttonDelete"><mat-icon>delete</mat-icon></button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -17,16 +17,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="time-fields">
|
||||
<mat-form-field appearance="fill" class="time-field">
|
||||
<mat-label>Hora de inicio</mat-label>
|
||||
<input matInput [(ngModel)]="busyFromHour" type="time" placeholder="Selecciona la hora de inicio">
|
||||
<input matInput [(ngModel)]="busyFromHour" type="time" placeholder="Selecciona la hora de inicio" [required]="!isRemoteAvailable">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="time-field">
|
||||
<mat-label>Hora de fin</mat-label>
|
||||
<input matInput [(ngModel)]="busyToHour" type="time" placeholder="Selecciona la hora de fin">
|
||||
<input matInput [(ngModel)]="busyToHour" type="time" placeholder="Selecciona la hora de fin" [required]="!isRemoteAvailable">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,19 +33,19 @@
|
|||
<div *ngIf="isRemoteAvailable" class="form-group">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Razón</mat-label>
|
||||
<input matInput [(ngModel)]="availableReason" placeholder="Razon para la excepción">
|
||||
<input matInput [(ngModel)]="availableReason" placeholder="Razon para la excepción" [required]="isRemoteAvailable">
|
||||
</mat-form-field>
|
||||
<div class="time-fields">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Fecha de inicio</mat-label>
|
||||
<input matInput [matDatepicker]="picker1" [(ngModel)]="availableFromDate">
|
||||
<input matInput [matDatepicker]="picker1" [(ngModel)]="availableFromDate" [required]="isRemoteAvailable">
|
||||
<mat-hint>MM/DD/YYYY</mat-hint>
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker1></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Fecha de fin</mat-label>
|
||||
<input matInput [matDatepicker]="picker2" [(ngModel)]="availableToDate">
|
||||
<input matInput [matDatepicker]="picker2" [(ngModel)]="availableToDate" [required]="isRemoteAvailable">
|
||||
<mat-hint>MM/DD/YYYY</mat-hint>
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker2></mat-datepicker>
|
||||
|
@ -57,5 +56,11 @@
|
|||
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||
<button mat-button (click)="submitRule()" cdkFocusInitial>{{ isEditMode ? 'Guardar' : 'Añadir' }}</button>
|
||||
<button
|
||||
mat-button
|
||||
(click)="submitRule()"
|
||||
cdkFocusInitial
|
||||
[disabled]="(!isRemoteAvailable && (!busyFromHour || !busyToHour)) || (isRemoteAvailable && (!availableReason || !availableFromDate || !availableToDate))">
|
||||
{{ isEditMode ? 'Guardar' : 'Añadir' }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
<div class="text-content">
|
||||
<div matListItemTitle>{{ rule.isRemoteAvailable ? 'Disponible' : 'No disponible ( periodo presencial )' }}</div>
|
||||
<div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ rule.busyFromHour }} - {{ rule.busyToHour }}</div>
|
||||
<div matListItemLine *ngIf="rule.isRemoteAvailable">{{ rule.availableReason }} | {{ rule.busyFromHour }} - {{ rule.busyToHour }}</div>
|
||||
<div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ rule.busyWeekDaysMap }}</div>
|
||||
<div matListItemLine *ngIf="rule.isRemoteAvailable">{{ rule.availableReason }} | {{ rule.availableFromDate | date }} - {{ rule.availableToDate | date }}</div>
|
||||
</div>
|
||||
<div class="icon-container">
|
||||
<button mat-icon-button color="primary" class="right-icon" (click)="createRule(rule)" i18n="@@editImage">
|
||||
|
|
|
@ -17,6 +17,7 @@ export class CreateCalendarComponent implements OnInit {
|
|||
remoteCalendarRules: any[] = [];
|
||||
isEditMode: boolean = false;
|
||||
calendarId: string | null = null;
|
||||
busyWeekDaysMap: string[] = [];
|
||||
|
||||
constructor(
|
||||
private toastService: ToastrService,
|
||||
|
@ -40,6 +41,9 @@ export class CreateCalendarComponent implements OnInit {
|
|||
this.name = response.name;
|
||||
this.remoteCalendarRules = response.remoteCalendarRules;
|
||||
this.calendarId = this.data;
|
||||
this.remoteCalendarRules.forEach(rule => {
|
||||
rule.busyWeekDaysMap = this.getBusyWeekDaysMap(rule.busyWeekDays);
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error fetching remote calendar:', err);
|
||||
|
@ -47,6 +51,14 @@ export class CreateCalendarComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
getBusyWeekDaysMap(indices: number[]): string[] {
|
||||
console.log(indices)
|
||||
const weekDays = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'];
|
||||
return indices.map(index => weekDays[index]);
|
||||
}
|
||||
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
|
|
@ -45,10 +45,11 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
|
||||
<td mat-cell *matCellDef="let client">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||
<td mat-cell *matCellDef="let client" style="text-align: center;">
|
||||
<button mat-icon-button color="info" (click)="handleClientClick($event, client)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
|
||||
<button mat-icon-button color="primary" (click)="onEditClick($event, client.uuid)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button (click)="onDeleteClick($event, client)">
|
||||
<button mat-icon-button color="warn" (click)="onDeleteClick($event, client)">
|
||||
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
|
|
|
@ -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<any>(`${this.apiUrl}?&page=${this.page}&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe(
|
||||
this.http.get<any>(`${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 = {};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<div class="header-container">
|
||||
<h2 class="title" i18n="@@adminImagesTitle">Administrar unidades organizativas</h2>
|
||||
<div class="images-button-row">
|
||||
<button mat-flat-button color="primary" (click)="resetFilters()">Reiniciar filtros</button>
|
||||
<button mat-flat-button color="primary" (click)="addOrganizationalUnit($event)">Añadir OU</button>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label i18n="@@searchLabel">Buscar nombre de cliente</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="search-boolean">
|
||||
<mat-label i18n="@@searchLabel">Tipo</mat-label>
|
||||
<mat-select [(ngModel)]="filters['type']" (selectionChange)="search()" placeholder="Seleccionar opción" >
|
||||
<mat-option [value]="''">Todos</mat-option>
|
||||
<mat-option [value]="'organizational-unit'">Unidad organizativa</mat-option>
|
||||
<mat-option [value]="'classroom-group'">Grupos de aulas</mat-option>
|
||||
<mat-option [value]="'classroom'">Aula</mat-option>
|
||||
<mat-option [value]="'clients-group'">Grupos de PCs</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<table mat-table [dataSource]="dataSource">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let image" >
|
||||
<ng-container >
|
||||
{{ column.cell(image) }}
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||
<td mat-cell *matCellDef="let client" style="text-align: center;">
|
||||
<button mat-icon-button color="info" (click)="onShowClick($event, client)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
|
||||
<button mat-icon-button color="primary" (click)="onEditClick($event, client.uuid)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button color="warn" (click)="onDeleteClick($event, client)">
|
||||
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
<div class="paginator-container">
|
||||
<mat-paginator [length]="length"
|
||||
[pageSize]="itemsPerPage"
|
||||
[pageIndex]="page"
|
||||
[pageSizeOptions]="pageSizeOptions"
|
||||
(page)="onPageChange($event)">
|
||||
</mat-paginator>
|
||||
</div>
|
|
@ -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<OrganizationalUnitTabViewComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [OrganizationalUnitTabViewComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(OrganizationalUnitTabViewComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -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<any>();
|
||||
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<any>(`${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<void>(`${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();
|
||||
}
|
||||
}
|
|
@ -29,15 +29,7 @@
|
|||
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
|
||||
<div class="item-content">
|
||||
<mat-icon>apartment</mat-icon>
|
||||
{{ breadcrumb.length === 0 ? unidad.name : null }}
|
||||
<ng-container *ngIf="unidad === selectedUnidad">
|
||||
<span class="breadcrumb">
|
||||
<ng-container *ngFor="let crumb of breadcrumb; let i = index">
|
||||
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
|
||||
<span *ngIf="i < breadcrumb.length - 1"> > </span>
|
||||
</ng-container>
|
||||
</span>
|
||||
</ng-container>
|
||||
{{ unidad.name }}
|
||||
<span class="actions">
|
||||
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">more_vert</mat-icon>
|
||||
<mat-menu #menu="matMenu">
|
||||
|
@ -161,4 +153,7 @@
|
|||
<mat-tab i18n-label label="Clientes">
|
||||
<app-client-tab-view></app-client-tab-view>
|
||||
</mat-tab>
|
||||
<mat-tab i18n-label label="Unidades organizativas">
|
||||
<app-organizational-unit-tab-view></app-organizational-unit-tab-view>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -21,60 +21,48 @@
|
|||
<button mat-flat-button color="primary" (click)="addSubnet()">Añadir Subnet</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label i18n="@@searchLabel">Buscar nombre de imagen</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label i18n="@@searchLabel">Buscar netmask</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['netmask']" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label i18n="@@searchLabel">Buscar IP</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['ip']" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let subnet">
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'name'">
|
||||
{{ subnet.name }}
|
||||
<ng-container >
|
||||
{{ column.cell(subnet) }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'netmask'">
|
||||
{{ subnet.netmask }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'ipAddress'">
|
||||
{{ subnet.ipAddress }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'nextServer'">
|
||||
{{ subnet.nextServer }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'bootFileName'">
|
||||
{{ subnet.bootFileName }}
|
||||
</ng-container>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
|
||||
<td mat-cell *matCellDef="let subnet">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||
<td mat-cell *matCellDef="let subnet" style="text-align: center;">
|
||||
<button mat-icon-button color="primary" (click)="editSubnet(subnet)" i18n="@@editSubnet">
|
||||
<mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button color="warn" (click)="deleteSubnet(subnet)"><mat-icon>delete</mat-icon></button>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
<button mat-icon-button (click)="addClientsToSubnet(subnet)">
|
||||
<mat-icon>computer</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="addSubnet()">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>Añadir Subnet</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="updateSubnet()">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>Actualizar</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="addClientsToSubnet(subnet)">
|
||||
<mat-icon>computer</mat-icon>
|
||||
<span>Add Clients to Subnet</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
@ -85,4 +73,4 @@
|
|||
<mat-paginator [length]="length" [pageSize]="itemsPerPage" [pageIndex]="page" [pageSizeOptions]="pageSizeOptions"
|
||||
(page)="onPageChange($event)">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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<Subnet>([]);
|
||||
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();
|
||||
|
|
Loading…
Reference in New Issue