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 { ChangePasswordModalComponent } from './components/admin/users/users/change-password-modal/change-password-modal.component';
|
||||||
import { GroupsComponent } from './components/groups/groups.component';
|
import { GroupsComponent } from './components/groups/groups.component';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
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 { MatStepperModule } from '@angular/material/stepper';
|
||||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
import { CreateClientComponent } from './components/groups/shared/clients/create-client/create-client.component';
|
import { CreateClientComponent } from './components/groups/shared/clients/create-client/create-client.component';
|
||||||
import { DeleteModalComponent } from './shared/delete_modal/delete-modal/delete-modal.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 { EditClientComponent } from './components/groups/shared/clients/edit-client/edit-client.component';
|
||||||
import { ClassroomViewComponent } from './components/groups/shared/classroom-view/classroom-view.component';
|
import { ClassroomViewComponent } from './components/groups/shared/classroom-view/classroom-view.component';
|
||||||
import { MatProgressSpinner } from "@angular/material/progress-spinner";
|
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 { LoadingComponent } from './shared/loading/loading.component';
|
||||||
import { RepositoryImagesComponent } from './components/repositories/repository-images/repository-images.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 { 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) {
|
export function HttpLoaderFactory(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||||
}
|
}
|
||||||
|
@ -150,10 +149,8 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
AddRoleModalComponent,
|
AddRoleModalComponent,
|
||||||
ChangePasswordModalComponent,
|
ChangePasswordModalComponent,
|
||||||
GroupsComponent,
|
GroupsComponent,
|
||||||
CreateOrganizationalUnitComponent,
|
|
||||||
CreateClientComponent,
|
CreateClientComponent,
|
||||||
DeleteModalComponent,
|
DeleteModalComponent,
|
||||||
EditOrganizationalUnitComponent,
|
|
||||||
EditClientComponent,
|
EditClientComponent,
|
||||||
ClassroomViewComponent,
|
ClassroomViewComponent,
|
||||||
ClientViewComponent,
|
ClientViewComponent,
|
||||||
|
@ -217,6 +214,7 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
LoadingComponent,
|
LoadingComponent,
|
||||||
RepositoryImagesComponent,
|
RepositoryImagesComponent,
|
||||||
InputDialogComponent,
|
InputDialogComponent,
|
||||||
|
ManageOrganizationalUnitComponent,
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
imports: [BrowserModule,
|
imports: [BrowserModule,
|
||||||
|
|
|
@ -10,9 +10,8 @@ import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { DataService } from './services/data.service';
|
import { DataService } from './services/data.service';
|
||||||
import { UnidadOrganizativa, Client, TreeNode, FlatNode, Command } from './model/model';
|
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 { 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 { EditClientComponent } from './shared/clients/edit-client/edit-client.component';
|
||||||
import { ShowOrganizationalUnitComponent } from './shared/organizational-units/show-organizational-unit/show-organizational-unit.component';
|
import { ShowOrganizationalUnitComponent } from './shared/organizational-units/show-organizational-unit/show-organizational-unit.component';
|
||||||
import { LegendComponent } from './shared/legend/legend.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 {
|
addOU(event: MouseEvent, parent: TreeNode | null = null): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, {
|
const dialogRef = this.dialog.open(ManageOrganizationalUnitComponent, {
|
||||||
data: { parent },
|
data: { parent },
|
||||||
width: '900px',
|
width: '900px',
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().subscribe((newUnit) => {
|
dialogRef.afterClosed().subscribe((newUnit) => {
|
||||||
if (newUnit?.uuid) {
|
if (newUnit?.uuid) {
|
||||||
console.log('Unidad organizativa creada:', newUnit);
|
|
||||||
this.refreshData(newUnit.uuid);
|
this.refreshData(newUnit.uuid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -391,7 +389,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
if (!uuid) return;
|
if (!uuid) return;
|
||||||
|
|
||||||
const dialogRef = node?.type !== NodeType.Client
|
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' });
|
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
@ -457,7 +455,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
onEditClick(event: MouseEvent, type: string, uuid: string): void {
|
onEditClick(event: MouseEvent, type: string, uuid: string): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dialogRef = type !== NodeType.Client
|
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' });
|
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
|
|
@ -4,21 +4,15 @@ h1 {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #3f51b5;
|
color: #3f51b5;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
margin-top: 20px;
|
||||||
|
|
||||||
.network-form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field {
|
.form-field {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-dialog-content {
|
.mat-dialog-content {
|
||||||
padding: 50px;
|
padding: 15px 50px 15px 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
@ -27,10 +21,6 @@ button {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-slide-toggle {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-option .unit-name {
|
mat-option .unit-name {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -55,9 +45,6 @@ mat-option .unit-path {
|
||||||
.grid-form {
|
.grid-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
gap: 20px;
|
column-gap: 20px;
|
||||||
}
|
row-gap: 20px;
|
||||||
|
|
||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
|
@ -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 { 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 {FormBuilder, FormGroup} from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
|
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 {DataService} from "../../../services/data.service";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {ToastrService} from "ngx-toastr";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-edit-organizational-unit',
|
selector: 'app-manage-organizational-unit',
|
||||||
templateUrl: './edit-organizational-unit.component.html',
|
templateUrl: './manage-organizational-unit.component.html',
|
||||||
styleUrl: './edit-organizational-unit.component.css'
|
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;
|
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||||
isLinear = true;
|
isLinear = true;
|
||||||
generalFormGroup: FormGroup;
|
generalFormGroup: FormGroup;
|
||||||
|
@ -33,20 +32,20 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
repositories: any[] = [];
|
repositories: any[] = [];
|
||||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||||
protected p2pModeOptions = [
|
protected p2pModeOptions = [
|
||||||
{"name": 'Leecher', "value": "leecher"},
|
{ "name": 'Leecher', "value": "leecher" },
|
||||||
{"name": 'Peer', "value": "peer"},
|
{ "name": 'Peer', "value": "peer" },
|
||||||
{"name": 'Seeder', "value": "seeder"},
|
{ "name": 'Seeder', "value": "seeder" },
|
||||||
];
|
];
|
||||||
protected multicastModeOptions = [
|
protected multicastModeOptions = [
|
||||||
{"name": 'Half duplex', "value": "half"},
|
{ "name": 'Half duplex', "value": "half" },
|
||||||
{"name": 'Full duplex', "value": "full"},
|
{ "name": 'Full duplex', "value": "full" },
|
||||||
];
|
];
|
||||||
@Output() unitAdded = new EventEmitter();
|
@Output() unitAdded = new EventEmitter();
|
||||||
calendars: any;
|
calendars: any;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _formBuilder: FormBuilder,
|
private _formBuilder: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<CreateOrganizationalUnitComponent>,
|
private dialogRef: MatDialogRef<ManageOrganizationalUnitComponent>,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
@ -55,10 +54,10 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
this.isEditMode = !!data?.uuid;
|
this.isEditMode = !!data?.uuid;
|
||||||
|
|
||||||
this.generalFormGroup = this._formBuilder.group({
|
this.generalFormGroup = this._formBuilder.group({
|
||||||
name: [null],
|
name: [null, Validators.required],
|
||||||
parent: [null],
|
parent: [data?.parent ? data.parent['@id'] : null],
|
||||||
description: [null],
|
description: [null],
|
||||||
type: [null]
|
type: [null, Validators.required]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.additionalInfoFormGroup = this._formBuilder.group({
|
this.additionalInfoFormGroup = this._formBuilder.group({
|
||||||
|
@ -88,7 +87,7 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
location: [null],
|
location: [null],
|
||||||
projector: [false],
|
projector: [false],
|
||||||
board: [false],
|
board: [false],
|
||||||
capacity: [null],
|
capacity: [null, [Validators.required, Validators.min(0)]],
|
||||||
remoteCalendar: [null]
|
remoteCalendar: [null]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -142,7 +141,9 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
|
|
||||||
loadOgLives() {
|
loadOgLives() {
|
||||||
this.dataService.getOgLives().subscribe(
|
this.dataService.getOgLives().subscribe(
|
||||||
(data: any[]) => this.ogLives = data,
|
(data: any[]) => {
|
||||||
|
this.ogLives = data
|
||||||
|
},
|
||||||
error => console.error('Error fetching ogLives', error)
|
error => console.error('Error fetching ogLives', error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +174,8 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
console.error('Error loading current calendar', error);
|
console.error('Error loading current calendar', error);
|
||||||
this.toastService.error('Error loading current calendar');
|
this.toastService.error('Error loading current calendar');
|
||||||
}
|
}
|
||||||
);}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
onCalendarChange(event: any) {
|
onCalendarChange(event: any) {
|
||||||
this.generalFormGroup.value.remoteCalendar = event.value;
|
this.generalFormGroup.value.remoteCalendar = event.value;
|
||||||
|
@ -184,7 +186,7 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
onRepositoryChange(event: any) {
|
onRepositoryChange(event: any) {
|
||||||
this.networkSettingsFormGroup.value.repository = event.value
|
this.networkSettingsFormGroup.value.repository = event.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData(uuid: string) {
|
loadData(uuid: string) {
|
||||||
|
@ -231,10 +233,9 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
error => {
|
error => {
|
||||||
console.error('Error fetching data for edit:', error);
|
console.error('Error fetching data for edit:', error);
|
||||||
this.toastService.error('Error fetching data');
|
this.toastService.error('Error fetching data');
|
||||||
this.onNoClick()
|
this.onNoClick();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log(this.classroomInfoFormGroup.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
|
@ -247,18 +248,19 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
comments: this.additionalInfoFormGroup.value.comments,
|
comments: this.additionalInfoFormGroup.value.comments,
|
||||||
remoteCalendar: this.generalFormGroup.value.remoteCalendar,
|
remoteCalendar: this.generalFormGroup.value.remoteCalendar,
|
||||||
type: this.generalFormGroup.value.type,
|
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) {
|
if (this.isEditMode) {
|
||||||
const putUrl = `${this.baseUrl}/organizational-units/${this.data.uuid}`;
|
const putUrl = `${this.baseUrl}/organizational-units/${this.data.uuid}`;
|
||||||
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
||||||
|
|
||||||
console.log('PUT URLLLLL:', formData);
|
|
||||||
this.http.put<any>(putUrl, formData, { headers }).subscribe(
|
this.http.put<any>(putUrl, formData, { headers }).subscribe(
|
||||||
response => {
|
response => {
|
||||||
console.log('PUT successful:', response);
|
|
||||||
this.unitAdded.emit();
|
this.unitAdded.emit();
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
this.toastService.success('Editado exitosamente', 'Éxito');
|
this.toastService.success('Editado exitosamente', 'Éxito');
|
||||||
|
@ -274,13 +276,13 @@ export class EditOrganizationalUnitComponent implements OnInit {
|
||||||
|
|
||||||
this.http.post<any>(postUrl, formData, { headers }).subscribe(
|
this.http.post<any>(postUrl, formData, { headers }).subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.unitAdded.emit();
|
this.unitAdded.emit(response);
|
||||||
this.dialogRef.close();
|
this.dialogRef.close(response);
|
||||||
this.toastService.success('Editado exitosamente', 'Éxito');
|
this.toastService.success('Creado exitosamente', 'Éxito');
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.error('Error al realizar POST:', 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']);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
import {CreateOrganizationalUnitComponent} from "../create-organizational-unit/create-organizational-unit.component";
|
|
||||||
import {DatePipe} from "@angular/common";
|
import {DatePipe} from "@angular/common";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
Loading…
Reference in New Issue