Added breadcrumb interative. Added edit organizational-unit and client load data

pull/4/head
Manuel Aranda Rosales 2024-07-02 13:13:07 +02:00
parent 6dec7c7f2c
commit 9e74ee0c63
18 changed files with 287 additions and 72 deletions

8
.idea/.gitignore vendored 100644
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="215863cb:18f708d4624:-7ffe" />
</MTProjectMetadataState>
</option>
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/oggui.iml" filepath="$PROJECT_DIR$/.idea/oggui.iml" />
</modules>
</component>
</project>

8
.idea/oggui.iml 100644
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

19
.idea/php.xml 100644
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

6
.idea/vcs.xml 100644
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -102,5 +102,8 @@
}
}
}
},
"cli": {
"analytics": "95fac95c-8936-41a8-8c9c-1fae82fe6912"
}
}

View File

@ -42,6 +42,7 @@ import { CreateClientComponent } from './components/groups/clients/create-client
import { DeleteModalComponent } from './components/groups/delete-modal/delete-modal.component';
import { EditOrganizationalUnitComponent } from './components/groups/organizational-units/edit-organizational-unit/edit-organizational-unit.component';
import { EditClientComponent } from './components/groups/clients/edit-client/edit-client.component';
import {MatProgressSpinner} from "@angular/material/progress-spinner";
@NgModule({ declarations: [
@ -88,7 +89,7 @@ import { EditClientComponent } from './components/groups/clients/edit-client/edi
MatSelectModule,
MatDividerModule,
MatStepperModule,
MatSlideToggleModule],
MatSlideToggleModule, MatProgressSpinner],
providers: [
{
provide: HTTP_INTERCEPTORS,

View File

@ -15,5 +15,5 @@
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">Añadir</button>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">{{ !isEditMode ? 'Añadir' : 'Guardar' }}</button>
</div>

View File

@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Component, Inject} from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import { CreateClientComponent } from '../create-client/create-client.component';
@Component({
@ -12,12 +12,20 @@ import { CreateClientComponent } from '../create-client/create-client.component'
export class EditClientComponent {
clientForm!: FormGroup;
parentUnits: any[] = []; // Array to store parent units fetched from API
isEditMode: boolean; // Flag to check if it's edit mode
constructor(
private fb: FormBuilder,
private dialogRef: MatDialogRef<CreateClientComponent>,
private http: HttpClient
) { }
private http: HttpClient,
@Inject(MAT_DIALOG_DATA) public data: any // Inject data for edit mode
) {
this.isEditMode = !!data?.uuid; // Check if uuid is passed to determine edit mode
if (this.isEditMode) {
this.loadData(data.uuid);
}
}
ngOnInit(): void {
this.loadParentUnits(); // Load parent units when component initializes
@ -48,19 +56,52 @@ export class EditClientComponent {
);
}
loadData(uuid: string) {
const url = `http://127.0.0.1:8080/clients/${uuid}`;
this.http.get<any>(url).subscribe(
data => {
this.clientForm.patchValue({
name: data.name,
organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : ''
});
});
}
onSubmit() {
console.log('Form data:', this.clientForm.value);
if (this.clientForm.valid) {
const formData = this.clientForm.value;
this.http.post('http://127.0.0.1:8080/clients', formData).subscribe(
if (this.isEditMode) {
// Edit mode: Send PUT request to update the unit
const putUrl = `http://127.0.0.1:8080/clients/${this.data.uuid}`;
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
this.http.patch<any>(putUrl, formData, { headers }).subscribe(
response => {
console.log('Response from POST:', response);
this.dialogRef.close(response);
console.log('PUT successful:', response);
this.dialogRef.close();
},
error => {
console.error('Error during POST:', error);
console.error('Error al realizar PUT:', error);
}
);
} else {
// Create mode: Send POST request to create a new unit
const postUrl = 'http://127.0.0.1:8080/clients';
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
this.http.post<any>(postUrl, formData, { headers }).subscribe(
response => {
console.log('POST successful:', response);
this.dialogRef.close();
},
error => {
console.error('Error al realizar POST:', error);
}
);
}
}
}

View File

@ -7,11 +7,36 @@ mat-card {
margin: 10px;
}
mat-card-title {
display: flex;
justify-content: space-between;
margin: 10px;
}
.elements-card{
margin: 10px;
width: 800px;
background-color: #fafafa;
}
.title-with-breadcrumb {
display: flex;
flex-direction: column;
}
mat-card-subtitle {
font-size: 0.875rem;
color: rgba(0, 0, 0, 0.54);
}
mat-card-subtitle a {
cursor: pointer;
text-decoration: underline;
color: #1976d2; /* Color azul típico de enlaces */
}
mat-card-subtitle a:hover {
text-decoration: none;
}
.groups-button-row {

View File

@ -25,8 +25,17 @@
</mat-card>
<mat-card class="elements-card">
<mat-card-title>Elementos</mat-card-title>
<mat-card-subtitle>{{ breadcrumb.join(' > ') }}</mat-card-subtitle>
<mat-card-title>
<div class="title-with-breadcrumb">
<span>Elementos</span>
<mat-card-subtitle>
<ng-container *ngFor="let crumb of breadcrumb; let i = index">
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
<span *ngIf="i < breadcrumb.length - 1"> > </span>
</ng-container>
</mat-card-subtitle>
</div>
</mat-card-title>
<mat-card-content>
<mat-list role="list">
<mat-list-item *ngFor="let child of children" [ngClass]="{'clickable-item': true}">

View File

@ -19,6 +19,7 @@ export class GroupsComponent implements OnInit {
selectedDetail: any | null = null; // Nueva variable para el detalle del elemento seleccionado
children: any[] = [];
breadcrumb: string[] = [];
breadcrumbData: any[] = []; // Almacenar datos de breadcrumb para navegar
constructor(private dataService: DataService, public dialog: MatDialog) {}
@ -33,6 +34,7 @@ export class GroupsComponent implements OnInit {
this.selectedUnidad = unidad;
this.selectedDetail = unidad; // Mostrar detalles de la unidad seleccionada
this.breadcrumb = [unidad.nombre];
this.breadcrumbData = [unidad];
this.loadChildrenAndClients(unidad.uuid);
}
@ -40,10 +42,22 @@ export class GroupsComponent implements OnInit {
this.selectedDetail = child; // Mostrar detalles del niño seleccionado
if (child.type !== 'client' && child.uuid && child.id) {
this.breadcrumb.push(child.name || child.nombre);
this.breadcrumbData.push(child);
this.loadChildrenAndClients(child.uuid);
}
}
navigateToBreadcrumb(index: number): void {
this.breadcrumb = this.breadcrumb.slice(0, index + 1);
const target = this.breadcrumbData[index];
this.breadcrumbData = this.breadcrumbData.slice(0, index + 1);
if (target.type === 'client') {
this.selectedDetail = target;
} else {
this.loadChildrenAndClients(target.uuid);
}
}
loadChildrenAndClients(uuid: string): void {
this.dataService.getChildren(uuid).subscribe(
childrenData => {
@ -57,7 +71,6 @@ export class GroupsComponent implements OnInit {
this.children = newChildren;
} else {
this.children = []; // Limpiar card2 cuando no hay elementos
this.breadcrumb.pop(); // Revertir breadcrumb solo si no hay elementos
// Si deseas que la unidad organizativa se limpie completamente, descomenta la línea siguiente:
// this.selectedUnidad = null;
@ -147,10 +160,10 @@ export class GroupsComponent implements OnInit {
console.log('Tipo del elemento a editar:', type);
console.log('UUID del elemento a editar:', uuid);
if (type != "client") {
const dialogRef = this.dialog.open(EditOrganizationalUnitComponent);
const dialogRef = this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid } });
} else {
console.log('Editar cliente');
const dialogRef = this.dialog.open(EditClientComponent);
const dialogRef = this.dialog.open(EditClientComponent, { data: { uuid } } );
}
}
}

View File

@ -1,4 +1,5 @@
<h1 mat-dialog-title>Añadir Unidad Organizativa</h1>
<div mat-dialog-content>
<mat-stepper orientation="vertical" [linear]="isLinear">
<!-- Step 1: General -->

View File

@ -1,7 +1,7 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component, EventEmitter, Output } from '@angular/core';
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { CreateOrganizationalUnitComponent } from '../create-organizational-unit/create-organizational-unit.component';
@Component({
@ -9,30 +9,36 @@ import { CreateOrganizationalUnitComponent } from '../create-organizational-unit
templateUrl: './edit-organizational-unit.component.html',
styleUrl: './edit-organizational-unit.component.css'
})
export class EditOrganizationalUnitComponent {
export class EditOrganizationalUnitComponent implements OnInit {
isLinear = true;
generalFormGroup: FormGroup;
additionalInfoFormGroup: FormGroup;
networkSettingsFormGroup: FormGroup;
types: string[] = ['organizational-unit', 'classrooms-group', 'classroom', 'clients-group'];
parentUnits: any[] = []; // Array to store parent units fetched from API
isEditMode: boolean; // Flag to check if it's edit mode
@Output() unitAdded = new EventEmitter(); // Event emitter to notify parent component about unit addition
constructor(
private _formBuilder: FormBuilder,
private dialogRef: MatDialogRef<CreateOrganizationalUnitComponent>,
private http: HttpClient // Inject HttpClient for HTTP requests
private http: HttpClient, // Inject HttpClient for HTTP requests
@Inject(MAT_DIALOG_DATA) public data: any // Inject data for edit mode
) {
this.isEditMode = !!data?.uuid; // Check if uuid is passed to determine edit mode
this.generalFormGroup = this._formBuilder.group({
name: ['', Validators.required],
parent: [''],
description: [''],
type: ['', Validators.required]
});
this.additionalInfoFormGroup = this._formBuilder.group({
comments: [''],
});
this.networkSettingsFormGroup = this._formBuilder.group({
proxy: [''],
dns: [''],
@ -49,6 +55,10 @@ export class EditOrganizationalUnitComponent {
hardwareProfile: ['', Validators.pattern('https?://.+')],
validation: [false]
});
if (this.isEditMode) {
this.loadData(data.uuid);
}
}
ngOnInit() {
@ -68,6 +78,43 @@ export class EditOrganizationalUnitComponent {
);
}
loadData(uuid: string) {
const url = `http://127.0.0.1:8080/organizational-units/${uuid}`;
this.http.get<any>(url).subscribe(
data => {
this.generalFormGroup.patchValue({
name: data.name,
parent: data.parent ? data.parent['@id'] : '',
description: data.description,
type: data.type
});
this.additionalInfoFormGroup.patchValue({
comments: data.comments
});
this.networkSettingsFormGroup.patchValue({
proxy: data.proxy,
dns: data.dns,
netmask: data.netmask,
router: data.router,
ntp: data.ntp,
p2pMode: data.p2pMode,
p2pTime: data.p2pTime,
mcastIp: data.mcastIp,
mcastSpeed: data.mcastSpeed,
mcastPort: data.mcastPort,
mcastMode: data.mcastMode,
menu: data.menu,
hardwareProfile: data.hardwareProfile,
validation: data.validation
});
},
error => {
console.error('Error fetching data for edit:', error);
}
);
}
onSubmit() {
if (this.generalFormGroup.valid && this.additionalInfoFormGroup.valid && this.networkSettingsFormGroup.valid) {
const parentValue = this.generalFormGroup.value.parent;
@ -77,29 +124,43 @@ export class EditOrganizationalUnitComponent {
parent: parentValue || null,
description: this.generalFormGroup.value.description,
comments: this.additionalInfoFormGroup.value.comments,
type: this.generalFormGroup.value.type
type: this.generalFormGroup.value.type,
...this.networkSettingsFormGroup.value
};
// Realizar la solicitud POST
console.log('POST data:', formData);
if (this.isEditMode) {
// Edit mode: Send PUT request to update the unit
const putUrl = `http://127.0.0.1:8080/organizational-units/${this.data.uuid}`;
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
this.http.put<any>(putUrl, formData, { headers }).subscribe(
response => {
console.log('PUT successful:', response);
this.unitAdded.emit();
this.dialogRef.close();
},
error => {
console.error('Error al realizar PUT:', error);
}
);
} else {
// Create mode: Send POST request to create a new unit
const postUrl = 'http://127.0.0.1:8080/organizational-units';
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
this.http.post<any>(postUrl, formData, { headers }).subscribe(
response => {
console.log('POST successful:', response);
// Emitir evento para notificar que se ha añadido una nueva unidad
this.unitAdded.emit();
this.dialogRef.close(); // Cerrar el diálogo después de añadir
this.dialogRef.close();
},
error => {
console.error('Error al realizar POST:', error);
// Manejar el error según sea necesario
}
);
}
}
}
onNoClick(): void {
this.dialogRef.close();