From 024914d993a27eef7037178c7607d9a1fa4c1aa5 Mon Sep 17 00:00:00 2001 From: llara Date: Mon, 17 Feb 2025 14:05:58 +0100 Subject: [PATCH] refs #1520 and #1524. Unify edit and create organizational unit into one single component. Refactor form structure. --- ogWebconsole/src/app/app.module.ts | 6 +- .../app/components/groups/groups.component.ts | 10 +- .../create-client/create-client.component.css | 23 +- .../create-organizational-unit.component.css | 42 --- .../create-organizational-unit.component.html | 160 ------------ .../create-organizational-unit.component.ts | 240 ------------------ .../edit-organizational-unit.component.css | 38 --- .../edit-organizational-unit.component.html | 148 ----------- .../manage-organizational-unit.component.css | 64 +++++ .../manage-organizational-unit.component.html | 166 ++++++++++++ ...nage-organizational-unit.component.spec.ts | 45 ++++ .../manage-organizational-unit.component.ts} | 82 +++--- .../show-organizational-unit.component.ts | 1 - 13 files changed, 328 insertions(+), 697 deletions(-) delete mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.css delete mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.html delete mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.ts delete mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.css delete mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.html create mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css create mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html create mode 100644 ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts rename ogWebconsole/src/app/components/groups/shared/organizational-units/{edit-organizational-unit/edit-organizational-unit.component.ts => manage-organizational-unit/manage-organizational-unit.component.ts} (82%) diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 4a39cb8..d7d5f8d 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -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, diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index 36db6f9..eaebf71 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -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(() => { diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css index fcf40bd..254ced8 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css +++ b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css @@ -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; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.css b/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.css deleted file mode 100644 index ffd86db..0000000 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.css +++ /dev/null @@ -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; -} diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.html deleted file mode 100644 index 6aab1c6..0000000 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.html +++ /dev/null @@ -1,160 +0,0 @@ -

{{ 'addOrgUnitTitle' | translate }}

-
- -
- - {{ 'typeLabel' | translate }} - - - {{ typeTranslations[type] }} - - - - - {{ 'nameLabel' | translate }} - - - - {{ 'createOrgUnitparentLabel' | translate }} - - - {{ getSelectedParentName() }} - - -
{{ unit.name }}
-
{{ unit.path }}
-
-
-
- - {{ 'descriptionLabel' | translate }} - - -
- - -
- - {{ 'locationLabel' | translate }} - - - {{ 'projectorToggle' | translate }} - {{ 'boardToggle' | translate }} - - {{ 'capacityLabel' | translate }} - - - - {{ 'associatedCalendarLabel' | translate }} - - - {{ calendar.name }} - - - -
- - -
- - {{ 'commentsLabel' | translate }} - - -
- - -
- - {{ 'ogLiveLabel' | translate }} - - - {{ oglive.name }} - - - - - {{ 'repositoryLabel' | translate }} - - - {{ repository.name }} - - - - - {{ 'nextServerLabel' | translate }} - - - - {{ 'bootFileNameLabel' | translate }} - - - - - {{ 'proxyUrlLabel' | translate }} - - - - {{ 'dnsIpLabel' | translate }} - - - - {{ 'netmaskLabel' | translate }} - - - - {{ 'routerLabel' | translate }} - - - - {{ 'ntpIpLabel' | translate }} - - - - {{ 'p2pModeLabel' | translate }} - - - {{ option.name }} - - - - - {{ 'p2pTimeLabel' | translate }} - - - - {{ 'mcastIpLabel' | translate }} - - - - {{ 'mcastSpeedLabel' | translate }} - - - - {{ 'mcastPortLabel' | translate }} - - - - {{ 'mcastModeLabel' | translate }} - - - {{ option.name }} - - - - - {{ 'menuUrlLabel' | translate }} - - - - {{ 'hardwareProfileLabel' | translate }} - - {{ unit.description }} - - {{ 'urlFormatError' | translate }} - -
-
-
- - -
diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.ts deleted file mode 100644 index f3aae66..0000000 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/create-organizational-unit/create-organizational-unit.component.ts +++ /dev/null @@ -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, - 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(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(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(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'); - } - } -} diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.css b/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.css deleted file mode 100644 index 76f9983..0000000 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.css +++ /dev/null @@ -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; - } diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.html deleted file mode 100644 index fb3fb5f..0000000 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.html +++ /dev/null @@ -1,148 +0,0 @@ -

{{ 'editOrgUnitTitle' | translate }}

-
- -
- - {{ 'typeLabel' | translate }} - - - {{ typeTranslations[type] }} - - - - - {{ 'nameLabel' | translate }} - - - - {{ 'editOrgUnitParentLabel' | translate }} - - - {{ getSelectedParentName() }} - - -
{{ unit.name }}
-
{{ unit.path }}
-
-
-
- - {{ 'descriptionLabel' | translate }} - - -
- - -
- - {{ 'locationLabel' | translate }} - - - {{ 'projectorToggle' | translate }} - {{ 'boardToggle' | translate }} - - {{ 'capacityLabel' | translate }} - - - - {{ 'associatedCalendarLabel' | translate }} - - - {{ calendar.name }} - - - -
- - -
- - {{ 'commentsLabel' | translate }} - - -
- - -
- - {{ 'ogLiveLabel' | translate }} - - - {{ oglive.name }} - - - - - {{ 'repositoryLabel' | translate }} - - - {{ repository.name }} - - - - - {{ 'proxyUrlLabel' | translate }} - - - - {{ 'dnsIpLabel' | translate }} - - - - {{ 'netmaskLabel' | translate }} - - - - {{ 'routerLabel' | translate }} - - - - {{ 'ntpIpLabel' | translate }} - - - - {{ 'p2pModeLabel' | translate }} - - {{ option.name }} - - - - {{ 'p2pTimeLabel' | translate }} - - - - {{ 'mcastIpLabel' | translate }} - - - - {{ 'mcastSpeedLabel' | translate }} - - - - {{ 'mcastPortLabel' | translate }} - - - - {{ 'mcastModeLabel' | translate }} - - {{ option.name }} - - - - {{ 'menuUrlLabel' | translate }} - - - - {{ 'hardwareProfileLabel' | translate }} - - {{ unit.description }} - - {{ 'urlFormatError' | translate }} - - {{ 'validationToggle' | translate }} -
-
-
- - -
diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css new file mode 100644 index 0000000..01f846d --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css @@ -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; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html new file mode 100644 index 0000000..d9dfd38 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html @@ -0,0 +1,166 @@ +

{{ isEditMode ? 'Editar' : 'Crear' }} Unidad Organizativa

+
+ + General +
+ + Tipo + + + {{ typeTranslations[type] }} + + + + + Nombre + + + + Padre + + + {{ getSelectedParentName() }} + + +
{{ unit.name }}
+
{{ unit.path }}
+
+
+
+ + Descripción + + +
+ + + Información del aula +
+ + Localización + + + + Aforo + + + El aforo no puede ser negativo + + + + Calendario Asociado + + + {{ calendar.name }} + + + +
+ Proyector + Pizarra +
+
+ + + Configuración de Red +
+ + OgLive + + + {{ oglive.name }} + + + + + Repositorio + + + {{ repository.name }} + + + + + Proxy + + + + DNS + + + + Máscara de Red + + + + Router + + + + NTP + + + + Modo P2P + + + {{ option.name }} + + + + + Tiempo P2P + + + + Mcast IP + + + + Mcast Speed + + + + Mcast Port + + + + Mcast Mode + + + {{ option.name }} + + + + + Menú + + + + Perfil de Hardware + + {{ unit.description + }} + + Formato de URL incorrecto + +
+ Validación +
+
+ + + Información Adicional +
+ + Comentarios + + +
+
+
+ + +
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts new file mode 100644 index 0000000..882d8ac --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts @@ -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; + + 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(); + }); +}); \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts similarity index 82% rename from ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.ts rename to ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts index 6c53596..2a2915b 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/edit-organizational-unit/edit-organizational-unit.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts @@ -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, + private dialogRef: MatDialogRef, 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(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(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(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(); } -} +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts index da0bd19..2287ff2 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts @@ -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({