Added router in subnet. Advanced bootfile changes, and partition assistant updates
testing/ogGui-multibranch/pipeline/head This commit is unstable Details

pull/10/head
Manuel Aranda Rosales 2024-12-05 12:50:15 +01:00
parent aecc16c332
commit e3cf6a85d0
22 changed files with 296 additions and 159 deletions

View File

@ -71,12 +71,12 @@ table {
} }
.chip-failed { .chip-failed {
background-color: #f15d5d !important; background-color: #e87979 !important;
color: white; color: white;
} }
.chip-success { .chip-success {
background-color: #32c532 !important; background-color: #46c446 !important;
color: white; color: white;
} }

View File

@ -247,9 +247,8 @@
} }
.charts-container { .charts-container {
flex: 2; flex: 1;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
} }

View File

@ -34,7 +34,7 @@ export class ClientMainViewComponent implements OnInit {
partitions: any[] = []; partitions: any[] = [];
commands: any[] = []; commands: any[] = [];
chartDisk: any[] = []; chartDisk: any[] = [];
view: [number, number] = [600, 300]; view: [number, number] = [300, 200];
showLegend: boolean = true; showLegend: boolean = true;
arrayCommands: any[] = [ arrayCommands: any[] = [
@ -100,15 +100,28 @@ export class ClientMainViewComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.clientData = history.state.clientData; this.clientData = history.state.clientData['@id'];
this.loadPartitions() this.loadClient(this.clientData)
this.updateGeneralData();
this.updateNetworkData();
this.loadCommands() this.loadCommands()
this.calculateDiskUsage(); this.calculateDiskUsage();
this.loading = false; this.loading = false;
} }
loadClient = (uuid: string) => {
this.http.get<any>(`${this.baseUrl}${uuid}`).subscribe({
next: data => {
this.clientData = data;
this.updateGeneralData();
this.updateNetworkData();
this.loadPartitions()
this.loading = false;
},
error: error => {
console.error('Error al obtener el cliente:', error);
}
});
}
updateGeneralData() { updateGeneralData() {
this.generalData = [ this.generalData = [
{ property: 'Nombre', value: this.clientData?.name || '' }, { property: 'Nombre', value: this.clientData?.name || '' },
@ -184,15 +197,6 @@ export class ClientMainViewComponent implements OnInit {
dialogRef.afterClosed().subscribe(); dialogRef.afterClosed().subscribe();
} }
getStrokeOffset(partitions: any[], index: number): number {
const totalSize = partitions.reduce((acc, part) => acc + (part.size / 1024), 0);
const offset = partitions.slice(0, index).reduce((acc, part) => acc + (part.size / 1024), 0);
console.log(offset, totalSize)
return totalSize > 0 ? (offset / totalSize) : 0;
}
loadPartitions(): void { loadPartitions(): void {
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[partitionNumber]=ASC`).subscribe({ this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[partitionNumber]=ASC`).subscribe({
next: data => { next: data => {
@ -218,7 +222,6 @@ export class ClientMainViewComponent implements OnInit {
} }
onCommandSelect(action: any): void { onCommandSelect(action: any): void {
console.log(action);
if (action === 'partition') { if (action === 'partition') {
this.openPartitionAssistant(); this.openPartitionAssistant();
} }

View File

@ -25,7 +25,7 @@
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Seleccione método de deploy</mat-label> <mat-label>Seleccione método de deploy</mat-label>
<mat-select [(ngModel)]="selectedMethod" name="selectedMethod"> <mat-select [(ngModel)]="selectedMethod" name="selectedMethod">
<mat-option *ngFor="let method of deployMethods" [disabled]="method !== 'unicast'" [value]="method">{{ method }}</mat-option> <mat-option *ngFor="let method of deployMethods" [value]="method">{{ method }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>

View File

@ -20,7 +20,7 @@ export class DeployImageComponent {
images: any[] = []; images: any[] = [];
clientName: string = ''; clientName: string = '';
selectedImage: string | null = null; selectedImage: string | null = null;
selectedOption: string | null = null; selectedOption: string | null = 'deploy-image';
selectedMethod: string | null = null; selectedMethod: string | null = null;
selectedPartition: any = null; selectedPartition: any = null;
mcastIp: string = ''; mcastIp: string = '';
@ -98,7 +98,7 @@ export class DeployImageComponent {
ngOnInit() { ngOnInit() {
this.clientId = this.route.snapshot.paramMap.get('id'); this.clientId = this.route.snapshot.paramMap.get('id');
this.selectedOption = 'deploy-image';
this.loadPartitions(); this.loadPartitions();
this.loadImages(); this.loadImages();
} }
@ -147,6 +147,21 @@ export class DeployImageComponent {
} }
save(): void { save(): void {
if (!this.selectedImage) {
this.toastService.error('Debe seleccionar una imagen');
return;
}
if (!this.selectedMethod) {
this.toastService.error('Debe seleccionar un método');
return;
}
if (!this.selectedPartition) {
this.toastService.error('Debe seleccionar una partición');
return;
}
const payload = { const payload = {
client: `/clients/${this.clientId}`, client: `/clients/${this.clientId}`,
method: this.selectedMethod, method: this.selectedMethod,
@ -163,7 +178,7 @@ export class DeployImageComponent {
.subscribe({ .subscribe({
next: (response) => { next: (response) => {
this.toastService.success('Imagen creada exitosamente'); this.toastService.success('Imagen creada exitosamente');
this.router.navigate(['/images']); this.router.navigate(['/commmands-logs'])
}, },
error: (error) => { error: (error) => {
console.error('Error:', error); console.error('Error:', error);

View File

@ -289,7 +289,7 @@ export class PartitionAssistantComponent implements OnInit {
this.http.post(this.apiUrl, bulkPayload).subscribe( this.http.post(this.apiUrl, bulkPayload).subscribe(
(response) => { (response) => {
this.toastService.success('Particiones creadas exitosamente'); this.toastService.success('Particiones creadas exitosamente');
this.router.navigate(['/traces']); this.router.navigate(['/commands-logs']);
}, },
(error) => { (error) => {
console.error('Error al crear las particiones:', error); console.error('Error al crear las particiones:', error);

View File

@ -218,7 +218,7 @@
<mat-icon>sync</mat-icon> <mat-icon>sync</mat-icon>
<span>Sincronizar</span> <span>Sincronizar</span>
</button> </button>
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)"> <button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
<span>Edit</span> <span>Edit</span>
@ -289,7 +289,7 @@
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
</button> </button>
<mat-menu #clientMenu="matMenu"> <mat-menu #clientMenu="matMenu">
<button mat-menu-item *ngIf="(!syncStatus || syncingClientId !== client.uuid)" (click)="getStatus(client)"> <button mat-menu-item *ngIf="(!syncStatus || syncingClientId !== client.uuid)" (click)="getStatus(client)">
<mat-icon>sync</mat-icon> <mat-icon>sync</mat-icon>
<span>Sincronizar</span> <span>Sincronizar</span>
@ -317,4 +317,4 @@
</div> </div>
</div> </div>
</div> </div>
</ng-template> </ng-template>

View File

@ -86,11 +86,45 @@ export class DataService {
); );
} }
getOgLives(): Observable<any[]> {
const url = `${this.baseUrl}/og-lives`;
return this.http.get<any>(url).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);
})
);
}
getRepositories(): Observable<any[]> {
const url = `${this.baseUrl}/image-repositories`;
return this.http.get<any>(url).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);
})
);
}
deleteElement(uuid: string, type: string): Observable<void> { deleteElement(uuid: string, type: string): Observable<void> {
const url = type === 'client' const url = type === 'client'
? `${this.baseUrl}/clients/${uuid}` ? `${this.baseUrl}/clients/${uuid}`
: `${this.baseUrl}/organizational-units/${uuid}`; : `${this.baseUrl}/organizational-units/${uuid}`;
console.log('DELETE URL:', url); // Depuración console.log('DELETE URL:', url); // Depuración
return this.http.delete<void>(url).pipe( return this.http.delete<void>(url).pipe(
catchError(error => { catchError(error => {
@ -99,7 +133,7 @@ export class DataService {
}) })
); );
} }
changeParent(uuid: string): Observable<void> { changeParent(uuid: string): Observable<void> {
const url = `${this.baseUrl}/organizational-units/${uuid}/change-parent`; const url = `${this.baseUrl}/organizational-units/${uuid}/change-parent`;
@ -186,7 +220,7 @@ export class DataService {
}) })
); );
} }
getOrganizationalUnitById(id: string): Observable<any> { getOrganizationalUnitById(id: string): Observable<any> {
const url = `${this.baseUrl}/organizational-units/${id}`; const url = `${this.baseUrl}/organizational-units/${id}`;
return this.http.get<any>(url).pipe( return this.http.get<any>(url).pipe(
@ -196,6 +230,6 @@ export class DataService {
}) })
); );
} }
} }

View File

@ -84,6 +84,22 @@
<mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="networkSettingsFormGroup"> <mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="networkSettingsFormGroup">
<form [formGroup]="networkSettingsFormGroup"> <form [formGroup]="networkSettingsFormGroup">
<ng-template matStepLabel>{{ 'networkSettingsStepLabel' | translate }}</ng-template> <ng-template matStepLabel>{{ 'networkSettingsStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field">
<mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
<mat-select formControlName="oglive" (selectionChange)="onOgLiveChange($event)">
<mat-option *ngFor="let oglive of ogLives" [value]="oglive['@id']">
{{ oglive.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
<mat-select formControlName="repository" (selectionChange)="onRepositoryChange($event)">
<mat-option *ngFor="let repository of repositories" [value]="repository['@id']">
{{ repository.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>{{ 'nextServerLabel' | translate }}</mat-label> <mat-label>{{ 'nextServerLabel' | translate }}</mat-label>
<input matInput formControlName="nextServer"> <input matInput formControlName="nextServer">

View File

@ -37,6 +37,8 @@ export class CreateOrganizationalUnitComponent implements OnInit {
parentUnits: any[] = []; parentUnits: any[] = [];
hardwareProfiles: any[] = []; hardwareProfiles: any[] = [];
calendars: any[] = []; calendars: any[] = [];
ogLives: any[] = [];
repositories: any[] = [];
selectedCalendarUuid: string | null = null; selectedCalendarUuid: string | null = null;
@Output() unitAdded = new EventEmitter(); @Output() unitAdded = new EventEmitter();
@ -59,6 +61,8 @@ export class CreateOrganizationalUnitComponent implements OnInit {
comments: [''], comments: [''],
}); });
this.networkSettingsFormGroup = this._formBuilder.group({ this.networkSettingsFormGroup = this._formBuilder.group({
ogLive: [null],
ogRepository: [null],
nextServer: [''], nextServer: [''],
bootFileName: [''], bootFileName: [''],
proxy: [''], proxy: [''],
@ -89,6 +93,8 @@ export class CreateOrganizationalUnitComponent implements OnInit {
this.loadParentUnits(); this.loadParentUnits();
this.loadHardwareProfiles(); this.loadHardwareProfiles();
this.loadCalendars(); this.loadCalendars();
this.loadOgLives();
this.loadRepositories();
} }
loadParentUnits() { loadParentUnits() {
@ -106,6 +112,20 @@ export class CreateOrganizationalUnitComponent implements OnInit {
); );
} }
loadOgLives() {
this.dataService.getOgLives().subscribe(
(data: any[]) => this.ogLives = data,
error => console.error('Error fetching ogLives', error)
);
}
loadRepositories() {
this.dataService.getRepositories().subscribe(
(data: any[]) => this.repositories = data,
error => console.error('Error fetching repositories', error)
);
}
loadCalendars() { loadCalendars() {
const apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=30`; const apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=30`;
this.http.get<any>(apiUrl).subscribe( this.http.get<any>(apiUrl).subscribe(
@ -169,14 +189,25 @@ export class CreateOrganizationalUnitComponent implements OnInit {
comments: additionalInfoFormValues.comments, comments: additionalInfoFormValues.comments,
networkSettings: { ...networkSettingsFormValues }, networkSettings: { ...networkSettingsFormValues },
menu: networkSettingsFormValues.menu || null, menu: networkSettingsFormValues.menu || null,
ogLive: networkSettingsFormValues.ogLive || null,
ogRepository: networkSettingsFormValues.ogRepository || null,
hardwareProfile: networkSettingsFormValues.hardwareProfile || null, hardwareProfile: networkSettingsFormValues.hardwareProfile || null,
}; };
} }
onCalendarChange(event: any) { onCalendarChange(event: any) {
this.generalFormGroup.value.remoteCalendar = event.value;
this.selectedCalendarUuid = event.value; this.selectedCalendarUuid = event.value;
} }
onOgLiveChange(event: any) {
this.networkSettingsFormGroup.value.ogLive = event.value;
}
onRepositoryChange(event: any) {
this.networkSettingsFormGroup.value.ogRepository = event
}
onNoClick(): void { onNoClick(): void {
this.dialogRef.close(); this.dialogRef.close();
} }

View File

@ -81,6 +81,22 @@
<mat-step [stepControl]="networkSettingsFormGroup"> <mat-step [stepControl]="networkSettingsFormGroup">
<form [formGroup]="networkSettingsFormGroup"> <form [formGroup]="networkSettingsFormGroup">
<ng-template matStepLabel>{{ 'networkSettingsStepLabel' | translate }}</ng-template> <ng-template matStepLabel>{{ 'networkSettingsStepLabel' | translate }}</ng-template>
<mat-form-field class="form-field">
<mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
<mat-select formControlName="ogLive" (selectionChange)="onOgLiveChange($event)">
<mat-option *ngFor="let oglive of ogLives" [value]="oglive['@id']">
{{ oglive.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
<mat-select formControlName="repository" (selectionChange)="onRepositoryChange($event)">
<mat-option *ngFor="let repository of repositories" [value]="repository['@id']">
{{ repository.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>{{ 'proxyUrlLabel' | translate }}</mat-label> <mat-label>{{ 'proxyUrlLabel' | translate }}</mat-label>
<input matInput formControlName="proxy"> <input matInput formControlName="proxy">
@ -143,12 +159,12 @@
<mat-slide-toggle formControlName="validation">{{ 'validationToggle' | translate }}</mat-slide-toggle> <mat-slide-toggle formControlName="validation">{{ 'validationToggle' | translate }}</mat-slide-toggle>
<div> <div>
<button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button> <button mat-button matStepperPrevious>{{ 'backButton' | translate }}</button>
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">{{ 'submitButton' | translate }}</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
</mat-stepper> </mat-stepper>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button> <button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">{{ 'submitButton' | translate }}</button>
</div> </div>

View File

@ -1,8 +1,8 @@
import { HttpClient, HttpHeaders } from '@angular/common/http'; import {HttpClient, HttpHeaders} from '@angular/common/http';
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; import {Component, EventEmitter, Inject, OnInit, Output} from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import {FormBuilder, FormGroup} from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import { CreateOrganizationalUnitComponent } from '../create-organizational-unit/create-organizational-unit.component'; import {CreateOrganizationalUnitComponent} from '../create-organizational-unit/create-organizational-unit.component';
import {DataService} from "../../../services/data.service"; import {DataService} from "../../../services/data.service";
import {ToastrService} from "ngx-toastr"; import {ToastrService} from "ngx-toastr";
@ -23,6 +23,8 @@ export class EditOrganizationalUnitComponent implements OnInit {
hardwareProfiles: any[] = []; hardwareProfiles: any[] = [];
isEditMode: boolean; isEditMode: boolean;
currentCalendar: any = []; currentCalendar: any = [];
ogLives: any[] = [];
repositories: any[] = [];
protected p2pModeOptions = [ protected p2pModeOptions = [
{"name": 'Leecher', "value": "p2p-mode-leecher"}, {"name": 'Leecher', "value": "p2p-mode-leecher"},
{"name": 'Peer', "value": "p2p-mode-peer"}, {"name": 'Peer', "value": "p2p-mode-peer"},
@ -57,6 +59,8 @@ export class EditOrganizationalUnitComponent implements OnInit {
}); });
this.networkSettingsFormGroup = this._formBuilder.group({ this.networkSettingsFormGroup = this._formBuilder.group({
ogLive: [null],
repository: [null],
proxy: [null], proxy: [null],
dns: [null], dns: [null],
netmask: [null], netmask: [null],
@ -90,6 +94,8 @@ export class EditOrganizationalUnitComponent implements OnInit {
this.loadParentUnits(); this.loadParentUnits();
this.loadHardwareProfiles(); this.loadHardwareProfiles();
this.loadCalendars(); this.loadCalendars();
this.loadOgLives();
this.loadRepositories();
} }
loadParentUnits() { loadParentUnits() {
@ -116,6 +122,20 @@ export class EditOrganizationalUnitComponent implements OnInit {
); );
} }
loadOgLives() {
this.dataService.getOgLives().subscribe(
(data: any[]) => this.ogLives = data,
error => console.error('Error fetching ogLives', error)
);
}
loadRepositories() {
this.dataService.getRepositories().subscribe(
(data: any[]) => this.repositories = data,
error => console.error('Error fetching repositories', error)
);
}
loadCalendars() { loadCalendars() {
const apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=30`; const apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=30`;
this.http.get<any>(apiUrl).subscribe( this.http.get<any>(apiUrl).subscribe(
@ -138,9 +158,15 @@ export class EditOrganizationalUnitComponent implements OnInit {
);} );}
onCalendarChange(event: any) { onCalendarChange(event: any) {
const selectedCalendarId = event.value; this.generalFormGroup.value.remoteCalendar = event.value;
console.log('Selected calendar ID:', selectedCalendarId); }
this.generalFormGroup.value.remoteCalendar = selectedCalendarId;
onOgLiveChange(event: any) {
this.networkSettingsFormGroup.value.ogLive = event.value;
}
onRepositoryChange(event: any) {
this.networkSettingsFormGroup.value.repository = event.value
} }
loadData(uuid: string) { loadData(uuid: string) {
@ -171,6 +197,8 @@ export class EditOrganizationalUnitComponent implements OnInit {
mcastMode: data.networkSettings.mcastMode, mcastMode: data.networkSettings.mcastMode,
menu: data.networkSettings.menu ? data.networkSettings.menu['@id'] : null, menu: data.networkSettings.menu ? data.networkSettings.menu['@id'] : null,
hardwareProfile: data.networkSettings.hardwareProfile ? data.networkSettings.hardwareProfile['@id'] : null, hardwareProfile: data.networkSettings.hardwareProfile ? data.networkSettings.hardwareProfile['@id'] : null,
ogLive: data.networkSettings.ogLive ? data.networkSettings.ogLive['@id'] : null,
repository: data.networkSettings.repository ? data.networkSettings.repository['@id'] : null,
validation: data.networkSettings.validation validation: data.networkSettings.validation
}); });
this.classroomInfoFormGroup.patchValue({ this.classroomInfoFormGroup.patchValue({
@ -245,5 +273,5 @@ export class EditOrganizationalUnitComponent implements OnInit {
this.dialogRef.close(); this.dialogRef.close();
} }
} }

View File

@ -11,9 +11,9 @@ export class ShowOrganizationalUnitComponent {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
displayedColumns: string[] = ['property', 'value']; displayedColumns: string[] = ['property', 'value'];
currentCalendar: any; currentCalendar: any;
ou: any;
generalData: any[] = []; generalData: any[] = [];
networkData = [ networkData: any[] = [];
];
constructor( constructor(
@Inject(MAT_DIALOG_DATA) public data: any, @Inject(MAT_DIALOG_DATA) public data: any,
@ -22,11 +22,22 @@ export class ShowOrganizationalUnitComponent {
} }
ngOnInit(): void { ngOnInit(): void {
if (this.data.data.remoteCalendar) { this.loadOrganizationalUnit(this.data.data['@id']);
this.loadCurrentCalendar(this.data.data.remoteCalendar.uuid); }
} else {
this.initializeGeneralData(); loadOrganizationalUnit(uuid: string): void {
} console.log(this.data['@id'])
const apiUrl = `${this.baseUrl}${uuid}`;
this.http.get<any>(apiUrl).subscribe(
response => {
this.ou = response;
console.log('Organizational unit', this.ou);
this.initializeData();
},
error => {
console.error('Error loading organizational unit', error);
this.initializeData();
});
} }
loadCurrentCalendar(uuid: string): void { loadCurrentCalendar(uuid: string): void {
@ -34,26 +45,39 @@ export class ShowOrganizationalUnitComponent {
this.http.get<any>(apiUrl).subscribe( this.http.get<any>(apiUrl).subscribe(
response => { response => {
this.currentCalendar = response.name; this.currentCalendar = response.name;
this.initializeGeneralData(); this.initializeData();
}, },
error => { error => {
console.error('Error loading current calendar', error); console.error('Error loading current calendar', error);
this.initializeGeneralData(); this.initializeData();
} }
); );
} }
initializeGeneralData(): void { initializeData(): void {
this.generalData = [ this.generalData = [
{ property: 'Nombre', value: this.data.data.name }, { property: 'Nombre', value: this.ou.name },
{ property: 'Uuid', value: this.data.data.uuid }, { property: 'Uuid', value: this.ou.uuid },
{ property: 'Descripción', value: this.data.data.description }, { property: 'Descripción', value: this.ou.description },
{ property: 'Comentarios', value: this.data.data.comments }, { property: 'Comentarios', value: this.ou.comments },
{ property: 'Tipo', value: this.data.data.type }, { property: 'Tipo', value: this.ou.type },
{ property: 'Unidad organizativa superior', value: this.data.data.parent ? this.data.data.parent.name : '-' }, { property: 'Unidad organizativa superior', value: this.ou.parent ? this.ou.parent.name : '-' },
{ property: 'Creado por', value: this.data.data.createdBy }, { property: 'Creado el', value: this.ou.createdAt },
{ property: 'Creado el', value: this.data.data.createdAt },
{ property: 'Calendario asociado', value: this.data.data.remoteCalendar ? this.currentCalendar : '-' }
]; ];
this.networkData = [
{ property: 'Calendario asociado', value: this.ou.remoteCalendar ? this.currentCalendar : '-' },
{ property: 'Aforo', value: this.ou.capacity },
{ property: 'Localización', value: this.ou.location },
{ property: 'Calendario', value: this.ou.calendar ? this.ou.calendar.name : '-' },
{ property: 'Proyector', value: this.ou.projector },
{ property: 'Pizarra', value: this.ou.board },
{ property: 'OgLive', value: this.ou.networkSettings.ogLive ? this.ou.networkSettings.ogLive.name : '-' },
{ property: 'Repositorio', value: this.ou.networkSettings.repository ? this.ou.networkSettings.repository.name : '-' },
{ property: 'OgLog', value: this.ou.networkSettings.oglog },
{ property: 'OgShare', value: this.ou.networkSettings.ogshare },
{ property: 'Perfil de hardware', value: this.ou.networkSettings.hardwareProfile ? this.ou.networkSettings.hardwareProfile.name : '-' },
{ property: 'Máscara de red', value: this.ou.networkSettings.netmask },
]
} }
} }

View File

@ -71,19 +71,23 @@ table {
margin: 8px 8px 8px 0; margin: 8px 8px 8px 0;
} }
.status-success { .chip-failed {
background-color: #4caf50; /* Verde */ background-color: #e87979 !important;
color: white; color: white;
} }
.status-failed { .chip-success {
background-color: #f44336; /* Rojo */ background-color: #46c446 !important;
color: white; color: white;
} }
.status-pending { .chip-pending {
background-color: #ff9800; /* Naranja */ background-color: lightgrey !important;
color: black;
}
.chip-in-progress {
background-color: #f5a623 !important;
color: white; color: white;
} }

View File

@ -32,7 +32,12 @@
</mat-icon> </mat-icon>
</ng-container> </ng-container>
<ng-container *ngIf="column.columnDef === 'status'"> <ng-container *ngIf="column.columnDef === 'status'">
<mat-chip > <mat-chip [ngClass]="{
'chip-failed': image.status === 'failed',
'chip-success': image.status === 'success',
'chip-pending': image.status === 'pending',
'chip-in-progress': image.status === 'in-progress'
}">
{{ getStatusLabel(image[column.columnDef]) }} {{ getStatusLabel(image[column.columnDef]) }}
</mat-chip> </mat-chip>
</ng-container> </ng-container>
@ -54,7 +59,7 @@
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item [disabled]="!image.imageFullSum" (click)="toggleAction(image, 'get-aux')">Obtener ficheros auxiliares</button> <button mat-menu-item (click)="toggleAction(image, 'get-aux')">Obtener ficheros auxiliares</button>
<button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'success'" (click)="toggleAction(image, 'delete-trash')">Eliminar imagen temporalmente</button> <button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'success'" (click)="toggleAction(image, 'delete-trash')">Eliminar imagen temporalmente</button>
<button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'trash'" (click)="toggleAction(image, 'recover')">Recuperar imagen de la papelera</button> <button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'trash'" (click)="toggleAction(image, 'recover')">Recuperar imagen de la papelera</button>

View File

@ -8,30 +8,14 @@
</div> </div>
<div [formGroup]="taskForm" class="search-container"> <div [formGroup]="taskForm" class="search-container">
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="selectUnitStep" text="{{ 'selectUnitDescription' | translate }}"> <div [formGroup]="taskForm" class="search-container">
<mat-label>{{ 'selectUnitLabel' | translate }}</mat-label> <mat-form-field appearance="fill" class="search-boolean" joyrideStep="selectClassStep" text="{{ 'selectClassDescription' | translate }}">
<mat-select formControlName="organizationalUnit" (selectionChange)="onOrganizationalUnitChange()"> <mat-label>{{ 'selectClassLabel' | translate }}</mat-label>
<mat-option *ngIf="loadingUnits" disabled>{{ 'loadingUnitsOption' | translate }}</mat-option> <mat-select (selectionChange)="loadChildUnits($event.value)">
<mat-option *ngFor="let unit of availableOrganizationalUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of units" [value]="unit.uuid">{{ unit.name }}</mat-option>
{{ unit.name }} </mat-select>
</mat-option> </mat-form-field>
</mat-select> </div>
<mat-error *ngIf="taskForm.get('organizationalUnit')?.invalid">
{{ 'requiredFieldError' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="selectClassStep" text="{{ 'selectClassDescription' | translate }}">
<mat-label>{{ 'selectClassLabel' | translate }}</mat-label>
<mat-select formControlName="selectedChild" (selectionChange)="onChildChange()">
<mat-option *ngIf="selectedUnitChildren.length === 0" disabled>
{{ 'noClassesOption' | translate }}
</mat-option>
<mat-option *ngFor="let child of selectedUnitChildren" [value]="child['@id']">
{{ child.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div> </div>
<mat-divider class="divider"></mat-divider> <mat-divider class="divider"></mat-divider>
@ -49,7 +33,7 @@
<button <button
mat-flat-button mat-flat-button
color="primary" color="primary"
[disabled]="selectedUnitChildren.length === 0" [disabled]="units.length === 0"
(click)="saveOgLiveTemplates()" (click)="saveOgLiveTemplates()"
joyrideStep="saveButtonStep" joyrideStep="saveButtonStep"
text="{{ 'saveButtonDescription' | translate }}"> text="{{ 'saveButtonDescription' | translate }}">
@ -68,6 +52,16 @@
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell> <mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="ip">
<mat-header-cell *matHeaderCellDef>{{ 'nameColumnHeader' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.ip }} </mat-cell>
</ng-container>
<ng-container matColumnDef="mac">
<mat-header-cell *matHeaderCellDef>{{ 'nameColumnHeader' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.mac }} </mat-cell>
</ng-container>
<ng-container matColumnDef="ogLive"> <ng-container matColumnDef="ogLive">
<mat-header-cell *matHeaderCellDef>{{ 'templateColumnHeader' | translate }}</mat-header-cell> <mat-header-cell *matHeaderCellDef>{{ 'templateColumnHeader' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let client"> <mat-cell *matCellDef="let client">

View File

@ -19,7 +19,7 @@ export class PxeBootFilesComponent implements OnInit {
selectedUnitChildren: any[] = []; selectedUnitChildren: any[] = [];
dataSource: any[] = []; dataSource: any[] = [];
taskForm: FormGroup; taskForm: FormGroup;
loadingUnits: boolean = false; units: any[] = [];
ogLiveOptions: any[] = []; ogLiveOptions: any[] = [];
globalOgLive: string | null = null; globalOgLive: string | null = null;
length: number = 0; length: number = 0;
@ -27,7 +27,7 @@ export class PxeBootFilesComponent implements OnInit {
page: number = 0; page: number = 0;
pageSizeOptions: number[] = [5, 10, 20, 40, 100]; pageSizeOptions: number[] = [5, 10, 20, 40, 100];
filters: any = {}; filters: any = {};
displayedColumns: string[] = ['id', 'name', 'ogLive']; displayedColumns: string[] = ['id', 'ip', 'mac', 'name', 'ogLive'];
constructor( constructor(
@ -43,23 +43,17 @@ export class PxeBootFilesComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.fetchOrganizationalUnits();
this.fetchPxeTemplates(); this.fetchPxeTemplates();
this.loadUnits()
} }
fetchOrganizationalUnits(): void { loadUnits() {
this.loadingUnits = true; this.http.get<any>(`${this.baseUrl}/organizational-units?type=classroom&page=1&itemsPerPage=50`).subscribe(
this.http.get<any>(`${this.baseUrl}/organizational-units?page=1&itemsPerPage=30`) response => {
.subscribe( this.units = response['hydra:member'];
response => { },
this.availableOrganizationalUnits = response['hydra:member'].filter((item: any) => item.type === 'organizational-unit'); error => console.error('Error fetching organizational units:', error)
this.loadingUnits = false; );
},
error => {
this.toastService.error('Error al cargar las unidades organizativas');
this.loadingUnits = false;
}
);
} }
fetchPxeTemplates(): void { fetchPxeTemplates(): void {
@ -75,45 +69,15 @@ export class PxeBootFilesComponent implements OnInit {
); );
} }
onOrganizationalUnitChange(): void { loadChildUnits(unitId: string) {
const selectedUnitId = this.taskForm.get('organizationalUnit')?.value; this.http.get<any>(`${this.baseUrl}/clients?parent.id${unitId}`).subscribe(
const selectedUnit = this.availableOrganizationalUnits.find(unit => unit['@id'] === selectedUnitId); response => {
this.dataSource = response['hydra:member'];
if (selectedUnit) { },
this.selectedUnitChildren = this.getAllClassrooms(selectedUnit); error => console.error('Error fetching child units:', error)
} else { );
this.selectedUnitChildren = [];
}
} }
getAllClassrooms(unit: any): any[] {
let classrooms: any[] = [];
if (unit.type === 'classroom') {
classrooms.push(unit);
}
if (unit.children) {
for (const child of unit.children) {
classrooms = classrooms.concat(this.getAllClassrooms(child));
}
}
return classrooms;
}
onChildChange(): void {
const selectedChildId = this.taskForm.get('selectedChild')?.value;
const selectedChild = this.selectedUnitChildren.find(child => child['@id'] === selectedChildId);
if (selectedChild && selectedChild.clients) {
this.dataSource = selectedChild.clients.map((client: { template: { [x: string]: any; }; }) => ({
...client,
ogLive: client.template ? client.template['@id'] : null
}));
} else {
this.dataSource = [];
}
}
applyToAll(): void { applyToAll(): void {
this.dataSource = this.dataSource.map(client => ({ this.dataSource = this.dataSource.map(client => ({
...client, ...client,
@ -152,12 +116,6 @@ export class PxeBootFilesComponent implements OnInit {
}); });
} }
onPageChange(event: PageEvent): void {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
this.fetchPxeTemplates();
}
iniciarTour(): void { iniciarTour(): void {
this.joyrideService.startTour({ this.joyrideService.startTour({
steps: [ steps: [
@ -173,5 +131,5 @@ export class PxeBootFilesComponent implements OnInit {
themeColor: '#3f51b5' themeColor: '#3f51b5'
}); });
} }
} }

View File

@ -31,6 +31,10 @@
<mat-label>Boot File Name</mat-label> <mat-label>Boot File Name</mat-label>
<input matInput [(ngModel)]="bootFileName" placeholder="Boot File Name"> <input matInput [(ngModel)]="bootFileName" placeholder="Boot File Name">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width">
<mat-label>Router</mat-label>
<input matInput [(ngModel)]="router" placeholder="Router">
</mat-form-field>
</mat-expansion-panel> </mat-expansion-panel>
</div> </div>
</mat-tab> </mat-tab>
@ -60,5 +64,5 @@
<mat-dialog-actions align="end"> <mat-dialog-actions align="end">
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()">Cancelar</button>
<button mat-button (click)="addNetworkConfig()" cdkFocusInitial>Guardar</button> <button mat-button (click)="save()" cdkFocusInitial>Guardar</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -17,6 +17,7 @@ export class CreateSubnetComponent implements OnInit {
ipAddress: string = ''; ipAddress: string = '';
nextServer: string = ''; nextServer: string = '';
bootFileName: string = ''; bootFileName: string = '';
router: string = '';
syncronized: boolean = false; syncronized: boolean = false;
serverId: number = 0; serverId: number = 0;
clients: any[] = []; clients: any[] = [];
@ -44,6 +45,7 @@ export class CreateSubnetComponent implements OnInit {
this.ipAddress = this.data.ipAddress; this.ipAddress = this.data.ipAddress;
this.nextServer = this.data.nextServer; this.nextServer = this.data.nextServer;
this.bootFileName = this.data.bootFileName; this.bootFileName = this.data.bootFileName;
this.router = this.data.router;
this.syncronized = this.data.syncronized; this.syncronized = this.data.syncronized;
this.serverId = this.data.serverId; this.serverId = this.data.serverId;
this.clients = this.data.clients this.clients = this.data.clients
@ -53,13 +55,14 @@ export class CreateSubnetComponent implements OnInit {
this.dialogRef.close(); this.dialogRef.close();
} }
addNetworkConfig(): void { save(): void {
const payload = { const payload = {
name: this.name, name: this.name,
netmask: this.netmask, netmask: this.netmask,
ipAddress: this.ipAddress, ipAddress: this.ipAddress,
nextServer: this.nextServer || null, router: this.router || null,
bootFileName: this.bootFileName || null nextServer: this.nextServer || null,
bootFileName: this.bootFileName || null
}; };
if (!this.data){ if (!this.data){

View File

@ -18,6 +18,7 @@ export interface Subnet {
netmask: string; netmask: string;
ipAddress: string; ipAddress: string;
nextServer: string; nextServer: string;
router: string;
bootFileName: string; bootFileName: string;
synchronized: boolean; synchronized: boolean;
serverId: number; serverId: number;

View File

@ -232,6 +232,7 @@
"editClientDialogTitle": "Edit Client", "editClientDialogTitle": "Edit Client",
"organizationalUnitLabel": "Parent", "organizationalUnitLabel": "Parent",
"ogLiveLabel": "OgLive", "ogLiveLabel": "OgLive",
"repositoryLabel": "Repository",
"serialNumberLabel": "Serial Number", "serialNumberLabel": "Serial Number",
"netifaceLabel": "Network interface", "netifaceLabel": "Network interface",
"netDriverLabel": "Network driver", "netDriverLabel": "Network driver",

View File

@ -233,6 +233,7 @@
"editClientDialogTitle": "Editar Cliente", "editClientDialogTitle": "Editar Cliente",
"organizationalUnitLabel": "Padre", "organizationalUnitLabel": "Padre",
"ogLiveLabel": "OgLive", "ogLiveLabel": "OgLive",
"repositoryLabel": "Repositorio",
"serialNumberLabel": "Número de Serie", "serialNumberLabel": "Número de Serie",
"netifaceLabel": "Interfaz de red", "netifaceLabel": "Interfaz de red",
"netDriverLabel": "Controlador de red", "netDriverLabel": "Controlador de red",