refs #1520 and #1524. Unify edit and create organizational unit into one single component. Refactor form structure.
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
parent
952938a253
commit
024914d993
|
@ -32,12 +32,10 @@ import { AddRoleModalComponent } from './components/admin/roles/roles/add-role-m
|
|||
import { ChangePasswordModalComponent } from './components/admin/users/users/change-password-modal/change-password-modal.component';
|
||||
import { GroupsComponent } from './components/groups/groups.component';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { CreateOrganizationalUnitComponent } from './components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component';
|
||||
import { MatStepperModule } from '@angular/material/stepper';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { CreateClientComponent } from './components/groups/shared/clients/create-client/create-client.component';
|
||||
import { DeleteModalComponent } from './shared/delete_modal/delete-modal/delete-modal.component';
|
||||
import { EditOrganizationalUnitComponent } from './components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component';
|
||||
import { EditClientComponent } from './components/groups/shared/clients/edit-client/edit-client.component';
|
||||
import { ClassroomViewComponent } from './components/groups/shared/classroom-view/classroom-view.component';
|
||||
import { MatProgressSpinner } from "@angular/material/progress-spinner";
|
||||
|
@ -130,6 +128,7 @@ import {ImportImageComponent} from "./components/repositories/import-image/impor
|
|||
import { LoadingComponent } from './shared/loading/loading.component';
|
||||
import { RepositoryImagesComponent } from './components/repositories/repository-images/repository-images.component';
|
||||
import { InputDialogComponent } from './components/commands/commands-task/task-logs/input-dialog/input-dialog.component';
|
||||
import { ManageOrganizationalUnitComponent } from './components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component';
|
||||
export function HttpLoaderFactory(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||
}
|
||||
|
@ -150,10 +149,8 @@ export function HttpLoaderFactory(http: HttpClient) {
|
|||
AddRoleModalComponent,
|
||||
ChangePasswordModalComponent,
|
||||
GroupsComponent,
|
||||
CreateOrganizationalUnitComponent,
|
||||
CreateClientComponent,
|
||||
DeleteModalComponent,
|
||||
EditOrganizationalUnitComponent,
|
||||
EditClientComponent,
|
||||
ClassroomViewComponent,
|
||||
ClientViewComponent,
|
||||
|
@ -217,6 +214,7 @@ export function HttpLoaderFactory(http: HttpClient) {
|
|||
LoadingComponent,
|
||||
RepositoryImagesComponent,
|
||||
InputDialogComponent,
|
||||
ManageOrganizationalUnitComponent,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [BrowserModule,
|
||||
|
|
|
@ -10,9 +10,8 @@ import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'
|
|||
import { Subscription } from 'rxjs';
|
||||
import { DataService } from './services/data.service';
|
||||
import { UnidadOrganizativa, Client, TreeNode, FlatNode, Command } from './model/model';
|
||||
import { CreateOrganizationalUnitComponent } from './shared/organizational-units/create-organizational-unit/create-organizational-unit.component';
|
||||
import { CreateClientComponent } from './shared/clients/create-client/create-client.component';
|
||||
import { EditOrganizationalUnitComponent } from './shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component';
|
||||
import { ManageOrganizationalUnitComponent } from './shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component';
|
||||
import { EditClientComponent } from './shared/clients/edit-client/edit-client.component';
|
||||
import { ShowOrganizationalUnitComponent } from './shared/organizational-units/show-organizational-unit/show-organizational-unit.component';
|
||||
import { LegendComponent } from './shared/legend/legend.component';
|
||||
|
@ -325,13 +324,12 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
|
||||
addOU(event: MouseEvent, parent: TreeNode | null = null): void {
|
||||
event.stopPropagation();
|
||||
const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, {
|
||||
const dialogRef = this.dialog.open(ManageOrganizationalUnitComponent, {
|
||||
data: { parent },
|
||||
width: '900px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((newUnit) => {
|
||||
if (newUnit?.uuid) {
|
||||
console.log('Unidad organizativa creada:', newUnit);
|
||||
this.refreshData(newUnit.uuid);
|
||||
}
|
||||
});
|
||||
|
@ -391,7 +389,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
if (!uuid) return;
|
||||
|
||||
const dialogRef = node?.type !== NodeType.Client
|
||||
? this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
|
@ -457,7 +455,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
onEditClick(event: MouseEvent, type: string, uuid: string): void {
|
||||
event.stopPropagation();
|
||||
const dialogRef = type !== NodeType.Client
|
||||
? this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
|
|
|
@ -4,21 +4,15 @@ h1 {
|
|||
font-weight: 400;
|
||||
color: #3f51b5;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.network-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mat-dialog-content {
|
||||
padding: 50px;
|
||||
padding: 15px 50px 15px 50px;
|
||||
}
|
||||
|
||||
button {
|
||||
|
@ -27,10 +21,6 @@ button {
|
|||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mat-slide-toggle {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
mat-option .unit-name {
|
||||
display: block;
|
||||
}
|
||||
|
@ -55,9 +45,6 @@ mat-option .unit-path {
|
|||
.grid-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
}
|
||||
column-gap: 20px;
|
||||
row-gap: 20px;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
h1 {
|
||||
text-align: center;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 400;
|
||||
color: #3f51b5;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.network-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mat-dialog-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.mat-dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
text-transform: none;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mat-slide-toggle {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
mat-slide-toggle{
|
||||
margin-left: 10px;
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
<h1 mat-dialog-title>{{ 'addOrgUnitTitle' | translate }}</h1>
|
||||
<div mat-dialog-content>
|
||||
<!-- Paso 1: General -->
|
||||
<form [formGroup]="generalFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'typeLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="type" required>
|
||||
<mat-option *ngFor="let type of filteredTypes" [value]="type">
|
||||
{{ typeTranslations[type] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'nameLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'createOrgUnitparentLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="parent">
|
||||
<mat-select-trigger>
|
||||
{{ getSelectedParentName() }}
|
||||
</mat-select-trigger>
|
||||
<mat-option *ngFor="let unit of parentUnitsWithPaths" [value]="unit.id">
|
||||
<div>{{ unit.name }}</div>
|
||||
<div style="font-size: smaller; color: gray;">{{ unit.path }}</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'descriptionLabel' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="description"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 2: Información del Aula -->
|
||||
<form *ngIf="generalFormGroup.value.type === 'classroom'" [formGroup]="classroomInfoFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'locationLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="location">
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle formControlName="projector">{{ 'projectorToggle' | translate }}</mat-slide-toggle>
|
||||
<mat-slide-toggle formControlName="board">{{ 'boardToggle' | translate }}</mat-slide-toggle>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'capacityLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="capacity" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field" appearance="fill">
|
||||
<mat-label>{{ 'associatedCalendarLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)">
|
||||
<mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']">
|
||||
{{ calendar.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 3: Información Adicional -->
|
||||
<form [formGroup]="additionalInfoFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'commentsLabel' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="comments"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 4: Configuración de Red -->
|
||||
<form *ngIf="generalFormGroup.value.type === 'classroom' || generalFormGroup.value.type === 'clients-group'" [formGroup]="networkSettingsFormGroup">
|
||||
<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-label>{{ 'nextServerLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="nextServer">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'bootFileNameLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="bootFileName">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'proxyUrlLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="proxy">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'dnsIpLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="dns">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'netmaskLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="netmask">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'routerLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="router">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'ntpIpLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="ntp">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'p2pModeLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="p2pMode">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'p2pTimeLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="p2pTime" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastIpLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mcastIp">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastSpeedLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mcastSpeed" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastPortLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mcastPort" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastModeLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="mcastMode">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'menuUrlLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="menu" type="url">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="hardwareProfile">
|
||||
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }}</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>{{ 'urlFormatError' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</div>
|
||||
<div mat-dialog-actions align="end">
|
||||
<button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">{{ 'addOUSubmitButton' | translate }}</button>
|
||||
</div>
|
|
@ -1,240 +0,0 @@
|
|||
import { Component, OnInit, Output, EventEmitter, Inject } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { DataService } from '../../../services/data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-organizational-unit',
|
||||
templateUrl: './create-organizational-unit.component.html',
|
||||
styleUrls: ['./create-organizational-unit.component.css']
|
||||
})
|
||||
export class CreateOrganizationalUnitComponent implements OnInit {
|
||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
isLinear = true;
|
||||
generalFormGroup: FormGroup;
|
||||
additionalInfoFormGroup: FormGroup;
|
||||
networkSettingsFormGroup: FormGroup;
|
||||
classroomInfoFormGroup: FormGroup;
|
||||
types: string[] = ['organizational-unit', 'classrooms-group', 'classroom', 'clients-group'];
|
||||
typeTranslations: { [key: string]: string } = {
|
||||
'organizational-unit': 'Centro',
|
||||
'classrooms-group': 'Grupo de aulas',
|
||||
'classroom': 'Aula',
|
||||
'clients-group': 'Grupo de clientes'
|
||||
};
|
||||
protected p2pModeOptions = [
|
||||
{ name: 'Leecher', value: 'leecher' },
|
||||
{ name: 'Peer', value: 'peer' },
|
||||
{ name: 'Seeder', value: 'seeder' },
|
||||
];
|
||||
protected multicastModeOptions = [
|
||||
{"name": 'Half duplex', "value": "half"},
|
||||
{"name": 'Full duplex', "value": "full"},
|
||||
];
|
||||
parentUnits: any[] = [];
|
||||
hardwareProfiles: any[] = [];
|
||||
calendars: any[] = [];
|
||||
ogLives: any[] = [];
|
||||
repositories: any[] = [];
|
||||
selectedCalendarUuid: string | null = null;
|
||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||
|
||||
@Output() unitAdded = new EventEmitter<{ uuid: string; name: string }>();
|
||||
|
||||
constructor(
|
||||
private _formBuilder: FormBuilder,
|
||||
private dialogRef: MatDialogRef<CreateOrganizationalUnitComponent>,
|
||||
private http: HttpClient,
|
||||
private toastService: ToastrService,
|
||||
private dataService: DataService,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {
|
||||
this.generalFormGroup = this._formBuilder.group({
|
||||
name: ['', Validators.required],
|
||||
parent: [this.data.parent ? this.data.parent['@id'] : null],
|
||||
description: [''],
|
||||
type: ['', Validators.required]
|
||||
});
|
||||
this.additionalInfoFormGroup = this._formBuilder.group({
|
||||
comments: [''],
|
||||
});
|
||||
this.networkSettingsFormGroup = this._formBuilder.group({
|
||||
ogLive: [null],
|
||||
ogRepository: [null],
|
||||
nextServer: [''],
|
||||
bootFileName: [''],
|
||||
proxy: [''],
|
||||
dns: [''],
|
||||
netmask: [''],
|
||||
router: [''],
|
||||
ntp: [''],
|
||||
p2pMode: [''],
|
||||
p2pTime: [0, Validators.min(0)],
|
||||
mcastIp: [''],
|
||||
mcastSpeed: [0, Validators.min(0)],
|
||||
mcastPort: [0, Validators.min(0)],
|
||||
mcastMode: [''],
|
||||
menu: [''],
|
||||
hardwareProfile: [''],
|
||||
validation: [false]
|
||||
});
|
||||
this.classroomInfoFormGroup = this._formBuilder.group({
|
||||
location: [''],
|
||||
projector: [false],
|
||||
board: [false],
|
||||
capacity: [0, Validators.min(0)],
|
||||
remoteCalendar: ['']
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.loadParentUnits();
|
||||
this.loadHardwareProfiles();
|
||||
this.loadCalendars();
|
||||
this.loadOgLives();
|
||||
this.loadRepositories();
|
||||
}
|
||||
|
||||
get filteredTypes(): string[] {
|
||||
return this.generalFormGroup.get('parent')?.value ? this.types.filter(type => type !== 'organizational-unit') : this.types;
|
||||
}
|
||||
|
||||
loadParentUnits() {
|
||||
const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=1000`;
|
||||
this.http.get<any>(url).subscribe(
|
||||
response => {
|
||||
this.parentUnits = response['hydra:member'];
|
||||
this.parentUnitsWithPaths = this.parentUnits.map(unit => ({
|
||||
id: unit['@id'],
|
||||
name: unit.name,
|
||||
path: this.dataService.getOrganizationalUnitPath(unit, this.parentUnits)
|
||||
}));
|
||||
},
|
||||
error => console.error('Error fetching parent units:', error)
|
||||
);
|
||||
}
|
||||
|
||||
getSelectedParentName(): string | undefined {
|
||||
const parentId = this.generalFormGroup.get('parent')?.value;
|
||||
return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name;
|
||||
}
|
||||
|
||||
loadHardwareProfiles(): void {
|
||||
this.dataService.getHardwareProfiles().subscribe(
|
||||
(data: any[]) => this.hardwareProfiles = data,
|
||||
error => console.error('Error fetching hardware profiles', error)
|
||||
);
|
||||
}
|
||||
|
||||
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() {
|
||||
const apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=30`;
|
||||
this.http.get<any>(apiUrl).subscribe(
|
||||
response => this.calendars = response['hydra:member'],
|
||||
error => {
|
||||
console.error('Error loading calendars', error);
|
||||
this.openSnackBar(true, 'Error loading calendars');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private cleanFormValues(formGroup: FormGroup): any {
|
||||
const cleanedValues: any = {};
|
||||
Object.keys(formGroup.controls).forEach(key => {
|
||||
const value = formGroup.get(key)?.value;
|
||||
if (value !== '' && value !== 0) {
|
||||
cleanedValues[key] = value;
|
||||
}
|
||||
});
|
||||
return cleanedValues;
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.isFormValid()) {
|
||||
const formData: any = this.buildPayload();
|
||||
const postUrl = `${this.baseUrl}/organizational-units`;
|
||||
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
||||
|
||||
this.http.post<any>(postUrl, formData, { headers }).subscribe(
|
||||
response => {
|
||||
this.unitAdded.emit(response);
|
||||
this.dialogRef.close(response);
|
||||
this.toastService.success('Unidad creada exitosamente', 'Éxito');
|
||||
this.openSnackBar(false, 'Unidad creada exitosamente');
|
||||
},
|
||||
error => {
|
||||
console.error('Error al realizar POST:', error);
|
||||
this.toastService.error('Ha ocurrido un error');
|
||||
this.openSnackBar(true, 'Error al crear la unidad organizativa: ' + error.error['hydra:description']);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private isFormValid(): boolean {
|
||||
return this.generalFormGroup.valid &&
|
||||
this.additionalInfoFormGroup.valid &&
|
||||
this.networkSettingsFormGroup.valid &&
|
||||
(this.generalFormGroup.value.type !== 'classroom' || this.classroomInfoFormGroup.valid);
|
||||
}
|
||||
|
||||
private buildPayload(): any {
|
||||
const generalFormValues = this.cleanFormValues(this.generalFormGroup);
|
||||
const additionalInfoFormValues = this.cleanFormValues(this.additionalInfoFormGroup);
|
||||
const networkSettingsFormValues = this.cleanFormValues(this.networkSettingsFormGroup);
|
||||
const classroomInfoFormValues = this.cleanFormValues(this.classroomInfoFormGroup);
|
||||
|
||||
return {
|
||||
...generalFormValues,
|
||||
...classroomInfoFormValues,
|
||||
comments: additionalInfoFormValues.comments,
|
||||
networkSettings: { ...networkSettingsFormValues },
|
||||
menu: networkSettingsFormValues.menu || null,
|
||||
ogLive: networkSettingsFormValues.ogLive || null,
|
||||
ogRepository: networkSettingsFormValues.ogRepository || null,
|
||||
hardwareProfile: networkSettingsFormValues.hardwareProfile || null,
|
||||
};
|
||||
}
|
||||
|
||||
onCalendarChange(event: any) {
|
||||
this.generalFormGroup.value.remoteCalendar = 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 {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
openSnackBar(isError: boolean, message: string) {
|
||||
if (isError) {
|
||||
this.toastService.error('Error al crear la unidad: ' + message, 'Error');
|
||||
} else {
|
||||
this.toastService.success('Unidad creada exitosamente', 'Éxito');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
h1 {
|
||||
text-align: center;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 400;
|
||||
color: #3f51b5;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.network-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mat-dialog-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.mat-dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
text-transform: none;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mat-slide-toggle {
|
||||
margin-top: 20px;
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
<h1 mat-dialog-title>{{ 'editOrgUnitTitle' | translate }}</h1>
|
||||
<div mat-dialog-content>
|
||||
<!-- Paso 1: General -->
|
||||
<form [formGroup]="generalFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'typeLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="type" required>
|
||||
<mat-option *ngFor="let type of filteredTypes" [value]="type">
|
||||
{{ typeTranslations[type] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'nameLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'editOrgUnitParentLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="parent">
|
||||
<mat-select-trigger>
|
||||
{{ getSelectedParentName() }}
|
||||
</mat-select-trigger>
|
||||
<mat-option *ngFor="let unit of parentUnitsWithPaths" [value]="unit.id">
|
||||
<div>{{ unit.name }}</div>
|
||||
<div style="font-size: smaller; color: gray;">{{ unit.path }}</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'descriptionLabel' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="description"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 2: Información del Aula -->
|
||||
<form [formGroup]="classroomInfoFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'locationLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="location">
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle formControlName="projector">{{ 'projectorToggle' | translate }}</mat-slide-toggle>
|
||||
<mat-slide-toggle formControlName="board">{{ 'boardToggle' | translate }}</mat-slide-toggle>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'capacityLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="capacity" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field" appearance="fill">
|
||||
<mat-label>{{ 'associatedCalendarLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)">
|
||||
<mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']">
|
||||
{{ calendar.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 3: Información Adicional -->
|
||||
<form [formGroup]="additionalInfoFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'commentsLabel' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="comments"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 4: Configuración de Red -->
|
||||
<form [formGroup]="networkSettingsFormGroup">
|
||||
<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-label>{{ 'proxyUrlLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="proxy">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'dnsIpLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="dns">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'netmaskLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="netmask">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'routerLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="router">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'ntpIpLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="ntp">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'p2pModeLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="p2pMode">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">{{ option.name }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'p2pTimeLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="p2pTime" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastIpLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mcastIp">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastSpeedLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mcastSpeed" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastPortLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="mcastPort" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'mcastModeLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="mcastMode">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">{{ option.name }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'menuUrlLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="menu" type="url">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="hardwareProfile">
|
||||
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }}</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>{{ 'urlFormatError' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle formControlName="validation">{{ 'validationToggle' | translate }}</mat-slide-toggle>
|
||||
</form>
|
||||
</div>
|
||||
<div mat-dialog-actions align="end">
|
||||
<button mat-button (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">{{ 'editOUSubmitButton' | translate }}</button>
|
||||
</div>
|
|
@ -0,0 +1,64 @@
|
|||
h1 {
|
||||
text-align: center;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 400;
|
||||
color: #3f51b5;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.description-form-field {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.mat-dialog-content {
|
||||
padding: 0px 40px 15px 50px;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mat-dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 1em;
|
||||
padding: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
button {
|
||||
text-transform: none;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.grid-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
column-gap: 20px;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
color: #3f51b5;
|
||||
margin: 40px 0 15px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.projector-board-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
grid-column: span 2;
|
||||
gap: 2em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.validation-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
grid-column: span 2;
|
||||
margin-bottom: 10px;
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
<h1 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Crear' }} Unidad Organizativa</h1>
|
||||
<div class="mat-dialog-content">
|
||||
<!-- Paso 1: General -->
|
||||
<span class="step-title">General</span>
|
||||
<form [formGroup]="generalFormGroup" class="grid-form">
|
||||
<mat-form-field class="form-field" appearance="fill">
|
||||
<mat-label>Tipo</mat-label>
|
||||
<mat-select formControlName="type" required>
|
||||
<mat-option *ngFor="let type of filteredTypes" [value]="type">
|
||||
{{ typeTranslations[type] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field" appearance="fill">
|
||||
<mat-label>Nombre</mat-label>
|
||||
<input matInput formControlName="name" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field" appearance="fill">
|
||||
<mat-label>Padre</mat-label>
|
||||
<mat-select formControlName="parent">
|
||||
<mat-select-trigger>
|
||||
{{ getSelectedParentName() }}
|
||||
</mat-select-trigger>
|
||||
<mat-option *ngFor="let unit of parentUnitsWithPaths" [value]="unit.id">
|
||||
<div>{{ unit.name }}</div>
|
||||
<div style="font-size: smaller; color: gray;">{{ unit.path }}</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field description-form-field" appearance="fill">
|
||||
<mat-label>Descripción</mat-label>
|
||||
<textarea matInput formControlName="description"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Paso 2: Información del Aula -->
|
||||
<span *ngIf="generalFormGroup.value.type === 'classroom'" class="step-title">Información del aula</span>
|
||||
<form *ngIf="generalFormGroup.value.type === 'classroom'" class="grid-form" [formGroup]="classroomInfoFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Localización</mat-label>
|
||||
<input matInput formControlName="location">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Aforo</mat-label>
|
||||
<input matInput formControlName="capacity" type="number" min="0">
|
||||
<mat-error *ngIf="classroomInfoFormGroup.get('capacity')?.hasError('min')">
|
||||
El aforo no puede ser negativo
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field" appearance="fill" style="grid-column: span 1;">
|
||||
<mat-label>Calendario Asociado</mat-label>
|
||||
<mat-select formControlName="remoteCalendar" (selectionChange)="onCalendarChange($event)">
|
||||
<mat-option *ngFor="let calendar of calendars" [value]="calendar['@id']">
|
||||
{{ calendar.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<div class="projector-board-field">
|
||||
<mat-slide-toggle formControlName="projector">Proyector</mat-slide-toggle>
|
||||
<mat-slide-toggle formControlName="board">Pizarra</mat-slide-toggle>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Paso 3: Configuración de Red -->
|
||||
<span class="step-title">Configuración de Red</span>
|
||||
<form [formGroup]="networkSettingsFormGroup" class="grid-form">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>OgLive</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>Repositorio</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-label>Proxy</mat-label>
|
||||
<input matInput formControlName="proxy">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>DNS</mat-label>
|
||||
<input matInput formControlName="dns">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Máscara de Red</mat-label>
|
||||
<input matInput formControlName="netmask">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Router</mat-label>
|
||||
<input matInput formControlName="router">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>NTP</mat-label>
|
||||
<input matInput formControlName="ntp">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Modo P2P</mat-label>
|
||||
<mat-select formControlName="p2pMode">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Tiempo P2P</mat-label>
|
||||
<input matInput formControlName="p2pTime" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Mcast IP</mat-label>
|
||||
<input matInput formControlName="mcastIp">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Mcast Speed</mat-label>
|
||||
<input matInput formControlName="mcastSpeed" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Mcast Port</mat-label>
|
||||
<input matInput formControlName="mcastPort" type="number">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Mcast Mode</mat-label>
|
||||
<mat-select formControlName="mcastMode">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Menú</mat-label>
|
||||
<input matInput formControlName="menu" type="url">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Perfil de Hardware</mat-label>
|
||||
<mat-select formControlName="hardwareProfile">
|
||||
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description
|
||||
}}</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>Formato de URL incorrecto</mat-error>
|
||||
</mat-form-field>
|
||||
<div class="validation-field">
|
||||
<mat-slide-toggle formControlName="validation">Validación</mat-slide-toggle>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Paso 4: Información Adicional -->
|
||||
<span class="step-title">Información Adicional</span>
|
||||
<form [formGroup]="additionalInfoFormGroup">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Comentarios</mat-label>
|
||||
<textarea matInput formControlName="comments"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</div>
|
||||
<div class="mat-dialog-actions">
|
||||
<button mat-button (click)="onNoClick()">Cancelar</button>
|
||||
<button mat-button (click)="onSubmit()"
|
||||
[disabled]="!generalFormGroup.valid || !additionalInfoFormGroup.valid || !networkSettingsFormGroup.valid">{{
|
||||
isEditMode ? 'Editar' : 'Crear' }}</button>
|
||||
</div>
|
|
@ -0,0 +1,45 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ManageOrganizationalUnitComponent } from './manage-organizational-unit.component';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('ManageOrganizationalUnitComponent', () => {
|
||||
let component: ManageOrganizationalUnitComponent;
|
||||
let fixture: ComponentFixture<ManageOrganizationalUnitComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ManageOrganizationalUnitComponent],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
ReactiveFormsModule,
|
||||
ToastrModule.forRoot(),
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatSlideToggleModule,
|
||||
BrowserAnimationsModule
|
||||
],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: {} },
|
||||
{ provide: MAT_DIALOG_DATA, useValue: {} }
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ManageOrganizationalUnitComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -1,17 +1,16 @@
|
|||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
import {Component, EventEmitter, Inject, OnInit, Output} from '@angular/core';
|
||||
import {FormBuilder, FormGroup} from '@angular/forms';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
|
||||
import {CreateOrganizationalUnitComponent} from '../create-organizational-unit/create-organizational-unit.component';
|
||||
import {DataService} from "../../../services/data.service";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { DataService } from "../../../services/data.service";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-organizational-unit',
|
||||
templateUrl: './edit-organizational-unit.component.html',
|
||||
styleUrl: './edit-organizational-unit.component.css'
|
||||
selector: 'app-manage-organizational-unit',
|
||||
templateUrl: './manage-organizational-unit.component.html',
|
||||
styleUrls: ['./manage-organizational-unit.component.css']
|
||||
})
|
||||
export class EditOrganizationalUnitComponent implements OnInit {
|
||||
export class ManageOrganizationalUnitComponent implements OnInit {
|
||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
isLinear = true;
|
||||
generalFormGroup: FormGroup;
|
||||
|
@ -33,20 +32,20 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
repositories: any[] = [];
|
||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||
protected p2pModeOptions = [
|
||||
{"name": 'Leecher', "value": "leecher"},
|
||||
{"name": 'Peer', "value": "peer"},
|
||||
{"name": 'Seeder', "value": "seeder"},
|
||||
{ "name": 'Leecher', "value": "leecher" },
|
||||
{ "name": 'Peer', "value": "peer" },
|
||||
{ "name": 'Seeder', "value": "seeder" },
|
||||
];
|
||||
protected multicastModeOptions = [
|
||||
{"name": 'Half duplex', "value": "half"},
|
||||
{"name": 'Full duplex', "value": "full"},
|
||||
{ "name": 'Half duplex', "value": "half" },
|
||||
{ "name": 'Full duplex', "value": "full" },
|
||||
];
|
||||
@Output() unitAdded = new EventEmitter();
|
||||
calendars: any;
|
||||
|
||||
constructor(
|
||||
private _formBuilder: FormBuilder,
|
||||
private dialogRef: MatDialogRef<CreateOrganizationalUnitComponent>,
|
||||
private dialogRef: MatDialogRef<ManageOrganizationalUnitComponent>,
|
||||
private http: HttpClient,
|
||||
private dataService: DataService,
|
||||
private toastService: ToastrService,
|
||||
|
@ -55,10 +54,10 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
this.isEditMode = !!data?.uuid;
|
||||
|
||||
this.generalFormGroup = this._formBuilder.group({
|
||||
name: [null],
|
||||
parent: [null],
|
||||
name: [null, Validators.required],
|
||||
parent: [data?.parent ? data.parent['@id'] : null],
|
||||
description: [null],
|
||||
type: [null]
|
||||
type: [null, Validators.required]
|
||||
});
|
||||
|
||||
this.additionalInfoFormGroup = this._formBuilder.group({
|
||||
|
@ -88,7 +87,7 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
location: [null],
|
||||
projector: [false],
|
||||
board: [false],
|
||||
capacity: [null],
|
||||
capacity: [null, [Validators.required, Validators.min(0)]],
|
||||
remoteCalendar: [null]
|
||||
});
|
||||
|
||||
|
@ -142,7 +141,9 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
|
||||
loadOgLives() {
|
||||
this.dataService.getOgLives().subscribe(
|
||||
(data: any[]) => this.ogLives = data,
|
||||
(data: any[]) => {
|
||||
this.ogLives = data
|
||||
},
|
||||
error => console.error('Error fetching ogLives', error)
|
||||
);
|
||||
}
|
||||
|
@ -173,7 +174,8 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
console.error('Error loading current calendar', error);
|
||||
this.toastService.error('Error loading current calendar');
|
||||
}
|
||||
);}
|
||||
);
|
||||
}
|
||||
|
||||
onCalendarChange(event: any) {
|
||||
this.generalFormGroup.value.remoteCalendar = event.value;
|
||||
|
@ -184,12 +186,12 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
}
|
||||
|
||||
onRepositoryChange(event: any) {
|
||||
this.networkSettingsFormGroup.value.repository = event.value
|
||||
this.networkSettingsFormGroup.value.repository = event.value;
|
||||
}
|
||||
|
||||
loadData(uuid: string) {
|
||||
const url = `${this.baseUrl}/organizational-units/${uuid}`;
|
||||
|
||||
|
||||
this.http.get<any>(url).subscribe(
|
||||
data => {
|
||||
this.generalFormGroup.patchValue({
|
||||
|
@ -227,14 +229,13 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
remoteCalendar: data.remoteCalendar ? data.remoteCalendar['@id'] : null
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
error => {
|
||||
console.error('Error fetching data for edit:', error);
|
||||
this.toastService.error('Error fetching data');
|
||||
this.onNoClick()
|
||||
this.onNoClick();
|
||||
}
|
||||
);
|
||||
console.log(this.classroomInfoFormGroup.value);
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
|
@ -247,18 +248,19 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
comments: this.additionalInfoFormGroup.value.comments,
|
||||
remoteCalendar: this.generalFormGroup.value.remoteCalendar,
|
||||
type: this.generalFormGroup.value.type,
|
||||
networkSettings: this.networkSettingsFormGroup.value
|
||||
networkSettings: this.networkSettingsFormGroup.value,
|
||||
location: this.classroomInfoFormGroup.value.location,
|
||||
projector: this.classroomInfoFormGroup.value.projector,
|
||||
board: this.classroomInfoFormGroup.value.board,
|
||||
capacity: this.classroomInfoFormGroup.value.capacity,
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (this.isEditMode) {
|
||||
const putUrl = `${this.baseUrl}/organizational-units/${this.data.uuid}`;
|
||||
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
||||
|
||||
console.log('PUT URLLLLL:', formData);
|
||||
|
||||
this.http.put<any>(putUrl, formData, { headers }).subscribe(
|
||||
response => {
|
||||
console.log('PUT successful:', response);
|
||||
this.unitAdded.emit();
|
||||
this.dialogRef.close();
|
||||
this.toastService.success('Editado exitosamente', 'Éxito');
|
||||
|
@ -271,16 +273,16 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
} else {
|
||||
const postUrl = `${this.baseUrl}/organizational-units`;
|
||||
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
||||
|
||||
|
||||
this.http.post<any>(postUrl, formData, { headers }).subscribe(
|
||||
response => {
|
||||
this.unitAdded.emit();
|
||||
this.dialogRef.close();
|
||||
this.toastService.success('Editado exitosamente', 'Éxito');
|
||||
this.unitAdded.emit(response);
|
||||
this.dialogRef.close(response);
|
||||
this.toastService.success('Creado exitosamente', 'Éxito');
|
||||
},
|
||||
error => {
|
||||
console.error('Error al realizar POST:', error);
|
||||
this.toastService.error('Error al editar:', error.error['hydra:description']);
|
||||
this.toastService.error('Error al crear:', error.error['hydra:description']);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -290,4 +292,4 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
|||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {CreateOrganizationalUnitComponent} from "../create-organizational-unit/create-organizational-unit.component";
|
||||
import {DatePipe} from "@angular/common";
|
||||
|
||||
@Component({
|
||||
|
|
Loading…
Reference in New Issue