Merge branch 'develop' of ssh://ognproject.evlt.uma.es:21987/opengnsys/oggui into develop
testing/ogGui-multibranch/pipeline/head There was a failure building this commit
Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit
Details
commit
9b67d6ef43
|
@ -35,9 +35,7 @@ import { GroupsComponent } from './components/groups/groups.component';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
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 { DeleteModalComponent } from './shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from './shared/delete_modal/delete-modal/delete-modal.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";
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
|
@ -130,6 +128,7 @@ import { CreateSubnetComponent } from "./components/ogdhcp/create-subnet/create-
|
||||||
import { AddClientsToSubnetComponent } from "./components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component";
|
import { AddClientsToSubnetComponent } from "./components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component";
|
||||||
import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component';
|
import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component';
|
||||||
import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component';
|
import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component';
|
||||||
|
import { ManageClientComponent } from './components/groups/shared/clients/manage-client/manage-client.component';
|
||||||
export function HttpLoaderFactory(http: HttpClient) {
|
export function HttpLoaderFactory(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||||
}
|
}
|
||||||
|
@ -150,9 +149,8 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
AddRoleModalComponent,
|
AddRoleModalComponent,
|
||||||
ChangePasswordModalComponent,
|
ChangePasswordModalComponent,
|
||||||
GroupsComponent,
|
GroupsComponent,
|
||||||
CreateClientComponent,
|
ManageClientComponent,
|
||||||
DeleteModalComponent,
|
DeleteModalComponent,
|
||||||
EditClientComponent,
|
|
||||||
ClassroomViewComponent,
|
ClassroomViewComponent,
|
||||||
ClientViewComponent,
|
ClientViewComponent,
|
||||||
ShowOrganizationalUnitComponent,
|
ShowOrganizationalUnitComponent,
|
||||||
|
@ -215,7 +213,7 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
ManageOrganizationalUnitComponent,
|
ManageOrganizationalUnitComponent,
|
||||||
BackupImageComponent,
|
BackupImageComponent,
|
||||||
ShowClientsComponent,
|
ShowClientsComponent,
|
||||||
OperationResultDialogComponent,
|
OperationResultDialogComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
imports: [BrowserModule,
|
imports: [BrowserModule,
|
||||||
|
|
|
@ -5,8 +5,8 @@ import {MatTableDataSource} from "@angular/material/table";
|
||||||
import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component";
|
import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component";
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
import {Router} from "@angular/router";
|
import {Router} from "@angular/router";
|
||||||
import {EditClientComponent} from "../../shared/clients/edit-client/edit-client.component";
|
|
||||||
import {ToastrService} from "ngx-toastr";
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
import { ManageClientComponent } from "../../shared/clients/manage-client/manage-client.component";
|
||||||
|
|
||||||
interface ClientInfo {
|
interface ClientInfo {
|
||||||
property: string;
|
property: string;
|
||||||
|
@ -198,7 +198,7 @@ export class ClientMainViewComponent implements OnInit {
|
||||||
|
|
||||||
onEditClick(event: MouseEvent, uuid: string): void {
|
onEditClick(event: MouseEvent, uuid: string): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dialogRef = this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' } );
|
const dialogRef = this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' } );
|
||||||
dialogRef.afterClosed().subscribe();
|
dialogRef.afterClosed().subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,7 @@ 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 { CreateClientComponent } from './shared/clients/create-client/create-client.component';
|
|
||||||
import { ManageOrganizationalUnitComponent } from './shared/organizational-units/manage-organizational-unit/manage-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 { 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';
|
||||||
import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
|
@ -22,6 +20,7 @@ import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
||||||
import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component";
|
import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component";
|
||||||
import { SelectionModel } from "@angular/cdk/collections";
|
import { SelectionModel } from "@angular/cdk/collections";
|
||||||
|
import { ManageClientComponent } from "./shared/clients/manage-client/manage-client.component";
|
||||||
|
|
||||||
enum NodeType {
|
enum NodeType {
|
||||||
OrganizationalUnit = 'organizational-unit',
|
OrganizationalUnit = 'organizational-unit',
|
||||||
|
@ -392,7 +391,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
addClient(event: MouseEvent, organizationalUnit: TreeNode | null = null): void {
|
addClient(event: MouseEvent, organizationalUnit: TreeNode | null = null): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const targetNode = organizationalUnit || this.selectedNode;
|
const targetNode = organizationalUnit || this.selectedNode;
|
||||||
const dialogRef = this.dialog.open(CreateClientComponent, {
|
const dialogRef = this.dialog.open(ManageClientComponent, {
|
||||||
data: { organizationalUnit: targetNode },
|
data: { organizationalUnit: targetNode },
|
||||||
width: '900px',
|
width: '900px',
|
||||||
});
|
});
|
||||||
|
@ -443,7 +442,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
const dialogRef = node?.type !== NodeType.Client
|
const dialogRef = node?.type !== NodeType.Client
|
||||||
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||||
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
: this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' });
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
if (node) {
|
if (node) {
|
||||||
|
@ -510,7 +509,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
const selectedClientsBeforeEdit = this.selection.selected.map(client => client.uuid);
|
const selectedClientsBeforeEdit = this.selection.selected.map(client => client.uuid);
|
||||||
const dialogRef = type !== NodeType.Client
|
const dialogRef = type !== NodeType.Client
|
||||||
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||||
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
: this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' });
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
this.refreshData(this.selectedNode?.id, selectedClientsBeforeEdit);
|
this.refreshData(this.selectedNode?.id, selectedClientsBeforeEdit);
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #3f51b5;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-dialog-content {
|
|
||||||
padding: 15px 50px 15px 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-option .unit-name {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-option .unit-path {
|
|
||||||
display: block;
|
|
||||||
font-size: 0.8em;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.create-client-container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-form {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
column-gap: 20px;
|
|
||||||
row-gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 1em;
|
|
||||||
padding: 1.5em;
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
<div class="create-client-container">
|
|
||||||
<h1 mat-dialog-title i18n="@@add-client-dialog-title">Añadir Cliente</h1>
|
|
||||||
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
|
|
||||||
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
|
||||||
<form [formGroup]="clientForm" class="client-form grid-form" *ngIf="!loading">
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@organizational-unit-label">Padre</mat-label>
|
|
||||||
<mat-select formControlName="organizationalUnit" (selectionChange)="onParentChange($event)">
|
|
||||||
<mat-select-trigger>
|
|
||||||
{{ getSelectedParentName() }}
|
|
||||||
</mat-select-trigger>
|
|
||||||
<mat-option *ngFor="let unit of parentUnitsWithPaths" [value]="unit.id">
|
|
||||||
<div class="unit-name">{{ 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 i18n="@@name-label">Nombre</mat-label>
|
|
||||||
<input matInput formControlName="name">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@oglive-label">OgLive</mat-label>
|
|
||||||
<mat-select formControlName="ogLive">
|
|
||||||
<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 i18n="@@serial-number-label">Número de Serie</mat-label>
|
|
||||||
<input matInput formControlName="serialNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@netiface-label">Interfaz de red</mat-label>
|
|
||||||
<mat-select formControlName="netiface">
|
|
||||||
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
|
|
||||||
{{ type.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@net-driver-label">Controlador de red</mat-label>
|
|
||||||
<mat-select formControlName="netDriver">
|
|
||||||
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
|
|
||||||
{{ type.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@mac-label">MAC</mat-label>
|
|
||||||
<mat-hint i18n="@@mac-hint">Ejemplo: 00:11:22:33:44:55</mat-hint>
|
|
||||||
<input matInput formControlName="mac">
|
|
||||||
<mat-error i18n="@@mac-error">Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@ip-label">Dirección IP</mat-label>
|
|
||||||
<mat-hint i18n="@@ip-hint">Ejemplo: 127.0.0.1</mat-hint>
|
|
||||||
<input matInput formControlName="ip">
|
|
||||||
<mat-error i18n="@@ip-error">Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@oglive-label">Plantilla PXE</mat-label>
|
|
||||||
<mat-select formControlName="template">
|
|
||||||
<mat-option *ngFor="let template of templates" [value]="template['@id']">
|
|
||||||
{{ template.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@hardware-profile-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 i18n="@@hardware-profile-error">Formato de URL inválido.</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@hardware-profile-label">Repositorio</mat-label>
|
|
||||||
<mat-select formControlName="repository">
|
|
||||||
<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>{{ 'menuLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="menu">
|
|
||||||
<mat-option *ngFor="let menu of menus" [value]="menu['@id']">
|
|
||||||
{{ menu.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
<mat-error>{{ 'menuError' | translate }}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div mat-dialog-actions class="action-container">
|
|
||||||
<button class="ordinary-button" (click)="onNoClick()" i18n="@@cancel-button">Cancelar</button>
|
|
||||||
<button class="submit-button" [disabled]="!clientForm.valid" (click)="onSubmit()"
|
|
||||||
i18n="@@add-button">Añadir</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,217 +0,0 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
|
||||||
import { DataService } from '../../../services/data.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-create-client',
|
|
||||||
templateUrl: './create-client.component.html',
|
|
||||||
styleUrls: ['./create-client.component.css']
|
|
||||||
})
|
|
||||||
export class CreateClientComponent implements OnInit {
|
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
|
||||||
clientForm!: FormGroup;
|
|
||||||
parentUnits: any[] = [];
|
|
||||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
|
||||||
hardwareProfiles: any[] = [];
|
|
||||||
ogLives: any[] = [];
|
|
||||||
menus: any[] = [];
|
|
||||||
templates: any[] = [];
|
|
||||||
repositories: any[] = [];
|
|
||||||
loading: boolean = false;
|
|
||||||
displayedColumns: string[] = ['name', 'ip'];
|
|
||||||
protected netifaceTypes = [
|
|
||||||
{ name: 'Eth0', value: 'eth0' },
|
|
||||||
{ name: 'Eth1', value: 'eth1' },
|
|
||||||
{ name: 'Eth2', value: 'eth2' }
|
|
||||||
];
|
|
||||||
protected netDriverTypes = [
|
|
||||||
{ name: 'Generic', value: 'generic' }
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private fb: FormBuilder,
|
|
||||||
private dialogRef: MatDialogRef<CreateClientComponent>,
|
|
||||||
private http: HttpClient,
|
|
||||||
private snackBar: MatSnackBar,
|
|
||||||
private toastService: ToastrService,
|
|
||||||
private dataService: DataService,
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.loadParentUnits();
|
|
||||||
this.loadHardwareProfiles();
|
|
||||||
this.loadOgLives();
|
|
||||||
this.loadPxeTemplates();
|
|
||||||
this.loadRepositories();
|
|
||||||
this.loadMenus()
|
|
||||||
this.initForm();
|
|
||||||
}
|
|
||||||
|
|
||||||
initForm(): void {
|
|
||||||
this.clientForm = this.fb.group({
|
|
||||||
organizationalUnit: [
|
|
||||||
this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null,
|
|
||||||
Validators.required
|
|
||||||
],
|
|
||||||
name: ['', Validators.required],
|
|
||||||
serialNumber: [''],
|
|
||||||
netiface: null,
|
|
||||||
netDriver: null,
|
|
||||||
mac: ['', Validators.required],
|
|
||||||
ip: ['', Validators.required],
|
|
||||||
template: [null],
|
|
||||||
hardwareProfile: [null],
|
|
||||||
ogLive: [null],
|
|
||||||
repository: [null],
|
|
||||||
menu: [null]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadParentUnits(): void {
|
|
||||||
this.loading = true;
|
|
||||||
const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
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),
|
|
||||||
repository: unit.networkSettings?.repository?.['@id'],
|
|
||||||
hardwareProfile: unit.networkSettings?.hardwareProfile?.['@id'],
|
|
||||||
ogLive: unit.networkSettings?.ogLive?.['@id'],
|
|
||||||
menu: unit.networkSettings?.menu?.['@id']
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 🚀 Ahora que los datos están listos, aplicamos la configuración inicial
|
|
||||||
const initialUnitId = this.clientForm.get('organizationalUnit')?.value;
|
|
||||||
if (initialUnitId) {
|
|
||||||
this.setOrganizationalUnitDefaults(initialUnitId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching parent units:', error);
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedParentName(): string | undefined {
|
|
||||||
const parentId = this.clientForm.get('organizationalUnit')?.value;
|
|
||||||
return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadHardwareProfiles(): void {
|
|
||||||
this.dataService.getHardwareProfiles().subscribe(
|
|
||||||
(data: any[]) => {
|
|
||||||
this.hardwareProfiles = data;
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching hardware profiles:', error);
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadOgLives(): void {
|
|
||||||
const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=30`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.ogLives = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching ogLives:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadPxeTemplates(): void {
|
|
||||||
const url = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.templates = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching PXE templates:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMenus(): void {
|
|
||||||
const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.menus = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching menus:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadRepositories(): void {
|
|
||||||
const url = `${this.baseUrl}/image-repositories?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.repositories = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching ogLives:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onParentChange(event: any): void {
|
|
||||||
this.setOrganizationalUnitDefaults(event.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setOrganizationalUnitDefaults(unitId: string): void {
|
|
||||||
const selectedUnit: any = this.parentUnitsWithPaths.find(unit => unit.id === unitId);
|
|
||||||
if (selectedUnit) {
|
|
||||||
this.clientForm.patchValue({
|
|
||||||
repository: selectedUnit.repository || null,
|
|
||||||
hardwareProfile: selectedUnit.hardwareProfile || null,
|
|
||||||
ogLive: selectedUnit.ogLive || null,
|
|
||||||
menu: selectedUnit.menu || null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(): void {
|
|
||||||
if (this.clientForm.valid) {
|
|
||||||
const formData = this.clientForm.value;
|
|
||||||
|
|
||||||
this.http.post(`${this.baseUrl}/clients`, formData).subscribe(
|
|
||||||
(response) => {
|
|
||||||
this.toastService.success('Cliente creado exitosamente', 'Éxito');
|
|
||||||
this.dialogRef.close({
|
|
||||||
client: response,
|
|
||||||
organizationalUnit: formData.organizationalUnit,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
this.toastService.error(error.error['hydra:description'], 'Error al crear el cliente');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.toastService.error('Formulario inválido. Por favor, revise los campos obligatorios.', 'Error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onNoClick(): void {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #3f51b5;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-dialog-content {
|
|
||||||
padding: 15px 50px 15px 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-option .unit-name {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-option .unit-path {
|
|
||||||
display: block;
|
|
||||||
font-size: 0.8em;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.create-client-container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-form {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
column-gap: 20px;
|
|
||||||
row-gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 1em;
|
|
||||||
padding: 1.5em;
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
<h1 mat-dialog-title>{{ 'editClientDialogTitle' | translate }}</h1>
|
|
||||||
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
|
|
||||||
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
|
||||||
<form [formGroup]="clientForm" class="client-form grid-form" *ngIf="!loading">
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="organizationalUnit">
|
|
||||||
<mat-select-trigger>
|
|
||||||
{{ getSelectedParentName() }}
|
|
||||||
</mat-select-trigger>
|
|
||||||
<mat-option *ngFor="let unit of parentUnitsWithPaths" [value]="unit.id">
|
|
||||||
<div class="unit-name">{{ 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>{{ 'nameLabel' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="name">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="ogLive">
|
|
||||||
<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>{{ 'serialNumberLabel' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="serialNumber">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'netifaceLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="netiface">
|
|
||||||
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
|
|
||||||
{{ type.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'netDriverLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="netDriver">
|
|
||||||
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
|
|
||||||
{{ type.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'macLabel' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="mac">
|
|
||||||
<mat-error>{{ 'macError' | translate }}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'ipLabel' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="ip">
|
|
||||||
<mat-error>{{ 'ipError' | translate }}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label>{{ 'templateLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="template">
|
|
||||||
<mat-option *ngFor="let template of templates" [value]="template['@id']">
|
|
||||||
{{ template.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</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-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<mat-label i18n="@@hardware-profile-label">Repositorio</mat-label>
|
|
||||||
<mat-select formControlName="repository">
|
|
||||||
<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>{{ 'menuLabel' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="menu">
|
|
||||||
<mat-option *ngFor="let menu of menus" [value]="menu['@id']">
|
|
||||||
{{ menu.name }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
<mat-error>{{ 'menuError' | translate }}</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div mat-dialog-actions class="action-container">
|
|
||||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
|
||||||
<button class="submit-button" [disabled]="!clientForm.valid" (click)="onSubmit()">
|
|
||||||
{{ !isEditMode ? ('addButton' | translate) : ('saveButton' | translate) }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
|
@ -1,239 +0,0 @@
|
||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
||||||
import { Component, Inject } from '@angular/core';
|
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
||||||
import { CreateClientComponent } from '../create-client/create-client.component';
|
|
||||||
import { DataService } from '../../../services/data.service';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-edit-client',
|
|
||||||
templateUrl: './edit-client.component.html',
|
|
||||||
styleUrls: ['./edit-client.component.css']
|
|
||||||
})
|
|
||||||
export class EditClientComponent {
|
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
|
||||||
clientForm!: FormGroup;
|
|
||||||
parentUnits: any[] = [];
|
|
||||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
|
||||||
hardwareProfiles: any[] = [];
|
|
||||||
repositories: any[] = [];
|
|
||||||
ogLives: any[] = [];
|
|
||||||
templates: any[] = [];
|
|
||||||
menus: any[] = [];
|
|
||||||
isEditMode: boolean;
|
|
||||||
protected netifaceTypes = [
|
|
||||||
{ "name": 'Eth0', "value": "eth0" },
|
|
||||||
{ "name": 'Eth1', "value": "eth1" },
|
|
||||||
{ "name": 'Eth2', "value": "eth2" },
|
|
||||||
];
|
|
||||||
protected netDriverTypes = [
|
|
||||||
{ "name": 'Generic', "value": "generic" },
|
|
||||||
];
|
|
||||||
loading: boolean = false;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private fb: FormBuilder,
|
|
||||||
private dialogRef: MatDialogRef<CreateClientComponent>,
|
|
||||||
private http: HttpClient,
|
|
||||||
private dataService: DataService,
|
|
||||||
private toastService: ToastrService,
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
|
||||||
) {
|
|
||||||
this.isEditMode = !!data?.uuid;
|
|
||||||
if (this.isEditMode) {
|
|
||||||
this.loadData(data.uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.loadParentUnits();
|
|
||||||
this.loadHardwareProfiles();
|
|
||||||
this.loadOgLives();
|
|
||||||
this.loadPxeTemplates()
|
|
||||||
this.loadRepositories();
|
|
||||||
this.loadMenus()
|
|
||||||
this.clientForm = this.fb.group({
|
|
||||||
organizationalUnit: [null, Validators.required],
|
|
||||||
name: ['', Validators.required],
|
|
||||||
serialNumber: null,
|
|
||||||
netiface: null,
|
|
||||||
netDriver: null,
|
|
||||||
mac: null,
|
|
||||||
ip: null,
|
|
||||||
template: null,
|
|
||||||
hardwareProfile: null,
|
|
||||||
ogLive: null,
|
|
||||||
repository: null,
|
|
||||||
menu: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadParentUnits(): void {
|
|
||||||
this.loading = true;
|
|
||||||
const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
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)
|
|
||||||
}));
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching parent units:', error);
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedParentName(): string | undefined {
|
|
||||||
const parentId = this.clientForm.get('organizationalUnit')?.value;
|
|
||||||
return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadHardwareProfiles(): void {
|
|
||||||
this.dataService.getHardwareProfiles().subscribe(
|
|
||||||
(data: any[]) => {
|
|
||||||
this.hardwareProfiles = data;
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
console.error('Error fetching hardware profiles', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadOgLives(): void {
|
|
||||||
const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.ogLives = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching ogLives:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMenus(): void {
|
|
||||||
const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.menus = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching menus:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadRepositories(): void {
|
|
||||||
const url = `${this.baseUrl}/image-repositories?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.repositories = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching ogLives:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadPxeTemplates(): void {
|
|
||||||
const url = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=10000`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
response => {
|
|
||||||
this.templates = response['hydra:member'];
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error fetching ogLives:', error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadData(uuid: string) {
|
|
||||||
this.loading = true;
|
|
||||||
const url = `${this.baseUrl}/clients/${uuid}`;
|
|
||||||
|
|
||||||
this.http.get<any>(url).subscribe(
|
|
||||||
data => {
|
|
||||||
this.clientForm.patchValue({
|
|
||||||
name: data.name,
|
|
||||||
ip: data.ip,
|
|
||||||
mac: data.mac,
|
|
||||||
netiface: data.netiface,
|
|
||||||
netDriver: data.netDriver,
|
|
||||||
serialNumber: data.serialNumber,
|
|
||||||
hardwareProfile: data.hardwareProfile ? data.hardwareProfile['@id'] : null,
|
|
||||||
organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : null,
|
|
||||||
repository: data.repository ? data.repository['@id'] : null,
|
|
||||||
ogLive: data.ogLive ? data.ogLive['@id'] : null,
|
|
||||||
template: data.template ? data.template['@id'] : null,
|
|
||||||
menu: data.menu ? data.menu['@id'] : null,
|
|
||||||
});
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error al cargar datos del cliente:', error);
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
if (this.clientForm.valid) {
|
|
||||||
const formData = this.clientForm.value;
|
|
||||||
|
|
||||||
if (this.isEditMode) {
|
|
||||||
// Edit mode: Send PUT request to update the unit
|
|
||||||
const putUrl = `${this.baseUrl}/clients/${this.data.uuid}`;
|
|
||||||
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
|
||||||
|
|
||||||
this.http.patch<any>(putUrl, formData, { headers }).subscribe(
|
|
||||||
response => {
|
|
||||||
this.dialogRef.close();
|
|
||||||
this.openSnackBar(false, 'Cliente actualizado exitosamente');
|
|
||||||
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error al realizar PUT:', error);
|
|
||||||
this.openSnackBar(true, 'Error al actualizar el cliente: ' + error.error['hydra:description']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Create mode: Send POST request to create a new unit
|
|
||||||
const postUrl = `${this.baseUrl}/clients`;
|
|
||||||
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
|
||||||
|
|
||||||
this.http.post<any>(postUrl, formData, { headers }).subscribe(
|
|
||||||
response => {
|
|
||||||
this.dialogRef.close();
|
|
||||||
this.openSnackBar(false, 'Cliente creado exitosamente');
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
console.error('Error al realizar POST:', error);
|
|
||||||
this.openSnackBar(true, 'Error al crear el cliente: ' + error.error['hydra:description']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onNoClick(): void {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
openSnackBar(isError: boolean, message: string) {
|
|
||||||
if (isError) {
|
|
||||||
this.toastService.error(' Error al crear el cliente: ' + message, 'Error');
|
|
||||||
} else
|
|
||||||
this.toastService.success(message, 'Éxito');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3f51b5;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-dialog-content {
|
||||||
|
padding: 15px 50px 15px 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-option .unit-name {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-option .unit-path {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-client-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
column-gap: 20px;
|
||||||
|
row-gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 1em;
|
||||||
|
padding: 1.5em;
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
<div class="create-client-container">
|
||||||
|
<h1 mat-dialog-title>{{ dialogTitle | translate }}</h1>
|
||||||
|
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
|
||||||
|
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
||||||
|
<form *ngIf="clientForm && !loading" [formGroup]="clientForm" class="client-form grid-form">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="organizationalUnit" (selectionChange)="onParentChange($event)">
|
||||||
|
<mat-select-trigger>
|
||||||
|
{{ getSelectedParentName() }}
|
||||||
|
</mat-select-trigger>
|
||||||
|
<mat-option *ngFor="let unit of parentUnitsWithPaths" [value]="unit.id">
|
||||||
|
<div class="unit-name">{{ 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>{{ 'nameLabel' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="name" required>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="ogLive">
|
||||||
|
<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>{{ 'serialNumberLabel' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="serialNumber">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'netifaceLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="netiface">
|
||||||
|
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
|
||||||
|
{{ type.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'netDriverLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="netDriver">
|
||||||
|
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
|
||||||
|
{{ type.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'macLabel' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="mac" required>
|
||||||
|
<mat-error>{{ 'macError' | translate }}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'ipLabel' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="ip" required>
|
||||||
|
<mat-error>{{ 'ipError' | translate }}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'templateLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="template">
|
||||||
|
<mat-option *ngFor="let template of templates" [value]="template['@id']">
|
||||||
|
{{ template.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'hardwareProfileLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="hardwareProfile">
|
||||||
|
<mat-option *ngFor="let profile of hardwareProfiles" [value]="profile['@id']">
|
||||||
|
{{ profile.description }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="repository">
|
||||||
|
<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>{{ 'menuLabel' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="menu">
|
||||||
|
<mat-option *ngFor="let menu of menus" [value]="menu['@id']">
|
||||||
|
{{ menu.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error>{{ 'menuError' | translate }}</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions class="action-container">
|
||||||
|
<button class="ordinary-button" (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||||
|
<button class="submit-button" [disabled]="!clientForm.valid" (click)="onSubmit()">
|
||||||
|
{{ isEditMode ? 'Guardar' : 'Crear' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
|
import { ManageClientComponent } from './manage-client.component';
|
||||||
|
import { DataService } from '../../../services/data.service';
|
||||||
|
|
||||||
|
describe('ManageClientComponent', () => {
|
||||||
|
let component: ManageClientComponent;
|
||||||
|
let fixture: ComponentFixture<ManageClientComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ManageClientComponent],
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
ToastrModule.forRoot(),
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
MatProgressSpinnerModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
|
{ provide: MAT_DIALOG_DATA, useValue: { uuid: '123', organizationalUnit: { '@id': '/units/1' } } },
|
||||||
|
DataService
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ManageClientComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize form', () => {
|
||||||
|
expect(component.clientForm).toBeDefined();
|
||||||
|
expect(component.clientForm.controls['name']).toBeDefined();
|
||||||
|
expect(component.clientForm.controls['mac']).toBeDefined();
|
||||||
|
expect(component.clientForm.controls['ip']).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set dialog title for edit mode', () => {
|
||||||
|
component.isEditMode = true;
|
||||||
|
component.data = { uuid: '123', organizationalUnit: { '@id': '/units/1' } };
|
||||||
|
component.ngOnInit();
|
||||||
|
expect(component.dialogTitle).toBe('editClientDialogTitle');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call onSubmit when form is valid', () => {
|
||||||
|
spyOn(component, 'onSubmit');
|
||||||
|
component.clientForm.controls['name'].setValue('Test Client');
|
||||||
|
component.clientForm.controls['mac'].setValue('00:11:22:33:44:55');
|
||||||
|
component.clientForm.controls['ip'].setValue('192.168.1.1');
|
||||||
|
fixture.detectChanges();
|
||||||
|
const button = fixture.debugElement.nativeElement.querySelector('.submit-button');
|
||||||
|
button.click();
|
||||||
|
expect(component.onSubmit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,302 @@
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { DataService } from '../../../services/data.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-manage-client',
|
||||||
|
templateUrl: './manage-client.component.html',
|
||||||
|
styleUrls: ['./manage-client.component.css']
|
||||||
|
})
|
||||||
|
export class ManageClientComponent implements OnInit {
|
||||||
|
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||||
|
clientForm!: FormGroup;
|
||||||
|
parentUnits: any[] = [];
|
||||||
|
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||||
|
hardwareProfiles: any[] = [];
|
||||||
|
ogLives: any[] = [];
|
||||||
|
menus: any[] = [];
|
||||||
|
templates: any[] = [];
|
||||||
|
repositories: any[] = [];
|
||||||
|
loading: boolean = false;
|
||||||
|
displayedColumns: string[] = ['name', 'ip'];
|
||||||
|
dialogTitle: string;
|
||||||
|
protected netifaceTypes = [
|
||||||
|
{ name: 'Eth0', value: 'eth0' },
|
||||||
|
{ name: 'Eth1', value: 'eth1' },
|
||||||
|
{ name: 'Eth2', value: 'eth2' }
|
||||||
|
];
|
||||||
|
protected netDriverTypes = [
|
||||||
|
{ name: 'Generic', value: 'generic' }
|
||||||
|
];
|
||||||
|
isEditMode: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private dialogRef: MatDialogRef<ManageClientComponent>,
|
||||||
|
private http: HttpClient,
|
||||||
|
private snackBar: MatSnackBar,
|
||||||
|
private toastService: ToastrService,
|
||||||
|
private dataService: DataService,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
|
) {
|
||||||
|
this.isEditMode = !!data?.uuid;
|
||||||
|
this.dialogTitle = this.isEditMode ? 'editClientDialogTitle' : 'addClientDialogTitle';
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.initForm();
|
||||||
|
const observables = [
|
||||||
|
this.loadParentUnits(),
|
||||||
|
this.loadHardwareProfiles(),
|
||||||
|
this.loadOgLives(),
|
||||||
|
this.loadPxeTemplates(),
|
||||||
|
this.loadRepositories(),
|
||||||
|
this.loadMenus()
|
||||||
|
];
|
||||||
|
|
||||||
|
Promise.all(observables).then(() => {
|
||||||
|
if (this.isEditMode) {
|
||||||
|
this.loadData(this.data.uuid).then(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Error loading data:', error);
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initForm(): void {
|
||||||
|
this.clientForm = this.fb.group({
|
||||||
|
organizationalUnit: [
|
||||||
|
this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null,
|
||||||
|
Validators.required
|
||||||
|
],
|
||||||
|
name: ['', Validators.required],
|
||||||
|
serialNumber: [''],
|
||||||
|
netiface: null,
|
||||||
|
netDriver: null,
|
||||||
|
mac: ['', Validators.required],
|
||||||
|
ip: ['', Validators.required],
|
||||||
|
template: [null],
|
||||||
|
hardwareProfile: [null],
|
||||||
|
ogLive: [null],
|
||||||
|
repository: [null],
|
||||||
|
menu: [null]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadParentUnits(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`;
|
||||||
|
|
||||||
|
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),
|
||||||
|
repository: unit.networkSettings?.repository?.['@id'],
|
||||||
|
hardwareProfile: unit.networkSettings?.hardwareProfile?.['@id'],
|
||||||
|
ogLive: unit.networkSettings?.ogLive?.['@id'],
|
||||||
|
menu: unit.networkSettings?.menu?.['@id']
|
||||||
|
}));
|
||||||
|
|
||||||
|
const initialUnitId = this.clientForm.get('organizationalUnit')?.value;
|
||||||
|
if (initialUnitId) {
|
||||||
|
this.setOrganizationalUnitDefaults(initialUnitId);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching parent units:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedParentName(): string | undefined {
|
||||||
|
const parentId = this.clientForm.get('organizationalUnit')?.value;
|
||||||
|
return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadHardwareProfiles(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.dataService.getHardwareProfiles().subscribe(
|
||||||
|
(data: any[]) => {
|
||||||
|
this.hardwareProfiles = data;
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching hardware profiles:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadOgLives(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=30`;
|
||||||
|
|
||||||
|
this.http.get<any>(url).subscribe(
|
||||||
|
response => {
|
||||||
|
this.ogLives = response['hydra:member'];
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching ogLives:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadPxeTemplates(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=10000`;
|
||||||
|
|
||||||
|
this.http.get<any>(url).subscribe(
|
||||||
|
response => {
|
||||||
|
this.templates = response['hydra:member'];
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching PXE templates:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadMenus(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`;
|
||||||
|
|
||||||
|
this.http.get<any>(url).subscribe(
|
||||||
|
response => {
|
||||||
|
this.menus = response['hydra:member'];
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching menus:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRepositories(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = `${this.baseUrl}/image-repositories?page=1&itemsPerPage=10000`;
|
||||||
|
|
||||||
|
this.http.get<any>(url).subscribe(
|
||||||
|
response => {
|
||||||
|
this.repositories = response['hydra:member'];
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching ogLives:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onParentChange(event: any): void {
|
||||||
|
this.setOrganizationalUnitDefaults(event.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
setOrganizationalUnitDefaults(unitId: string): void {
|
||||||
|
const selectedUnit: any = this.parentUnitsWithPaths.find(unit => unit.id === unitId);
|
||||||
|
if (selectedUnit) {
|
||||||
|
this.clientForm.patchValue({
|
||||||
|
repository: selectedUnit.repository || null,
|
||||||
|
hardwareProfile: selectedUnit.hardwareProfile || null,
|
||||||
|
ogLive: selectedUnit.ogLive || null,
|
||||||
|
menu: selectedUnit.menu || null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData(uuid: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const url = `${this.baseUrl}/clients/${uuid}`;
|
||||||
|
|
||||||
|
this.http.get<any>(url).subscribe(
|
||||||
|
data => {
|
||||||
|
this.clientForm.patchValue({
|
||||||
|
name: data.name,
|
||||||
|
ip: data.ip,
|
||||||
|
mac: data.mac,
|
||||||
|
netiface: data.netiface,
|
||||||
|
netDriver: data.netDriver,
|
||||||
|
serialNumber: data.serialNumber,
|
||||||
|
hardwareProfile: data.hardwareProfile ? data.hardwareProfile['@id'] : null,
|
||||||
|
organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : null,
|
||||||
|
repository: data.repository ? data.repository['@id'] : null,
|
||||||
|
ogLive: data.ogLive ? data.ogLive['@id'] : null,
|
||||||
|
template: data.template ? data.template['@id'] : null,
|
||||||
|
menu: data.menu ? data.menu['@id'] : null,
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error al cargar datos del cliente:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.clientForm.valid) {
|
||||||
|
const formData = this.clientForm.value;
|
||||||
|
|
||||||
|
if (this.isEditMode) {
|
||||||
|
const putUrl = `${this.baseUrl}/clients/${this.data.uuid}`;
|
||||||
|
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
||||||
|
|
||||||
|
this.http.patch<any>(putUrl, formData, { headers }).subscribe(
|
||||||
|
response => {
|
||||||
|
this.dialogRef.close();
|
||||||
|
this.toastService.success('Cliente actualizado exitosamente', 'Éxito');
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error al realizar PUT:', error);
|
||||||
|
this.toastService.error('Error al actualizar el cliente: ' + error.error['hydra:description'], 'Error');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.http.post(`${this.baseUrl}/clients`, formData).subscribe(
|
||||||
|
(response) => {
|
||||||
|
this.toastService.success('Cliente creado exitosamente', 'Éxito');
|
||||||
|
this.dialogRef.close({
|
||||||
|
client: response,
|
||||||
|
organizationalUnit: formData.organizationalUnit,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.toastService.error(error.error['hydra:description'], 'Error al crear el cliente');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.toastService.error('Formulario inválido. Por favor, revise los campos obligatorios.', 'Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue