refs #1282. Adapted ogCore filter. Refactor unused and wrong code

pull/10/head
Manuel Aranda Rosales 2024-12-20 12:03:30 +01:00
parent 369e09ee86
commit 013536bc9e
9 changed files with 150 additions and 183 deletions

View File

@ -31,9 +31,11 @@
<ng-container *ngIf="column.columnDef !== 'readOnly'">
{{ column.cell(command) }}
</ng-container>
<ng-container *ngIf="column.columnDef === 'readOnly'">
<mat-chip *ngIf="command.readOnly" class="mat-chip-readonly-true"><mat-icon style="color:white;">check</mat-icon></mat-chip>
<mat-chip *ngIf="!command.readOnly" class="mat-chip-readonly-false"><mat-icon style="color:white;">close</mat-icon></mat-chip>
<mat-icon [color]="command[column.columnDef] ? 'primary' : 'warn'">
{{ command[column.columnDef] ? 'check_circle' : 'cancel' }}
</mat-icon>
</ng-container>
</td>
</ng-container>
@ -41,7 +43,6 @@
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
<td mat-cell *matCellDef="let command" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
<button mat-icon-button color="info" (click)="executeCommand($event, command)"><mat-icon>play_arrow</mat-icon></button>
<button mat-icon-button color="info" (click)="viewDetails($event, command)"><mat-icon>visibility</mat-icon></button>
<button mat-icon-button color="primary" [disabled]="command.readOnly" (click)="editCommand($event, command)"><mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" [disabled]="command.readOnly" (click)="deleteCommand($event, command)"><mat-icon>delete</mat-icon></button>

View File

@ -50,7 +50,7 @@ export class CommandsComponent implements OnInit {
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
private apiUrl = `${this.baseUrl}/commands`;
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
private joyrideService: JoyrideService) {}
ngOnInit(): void {
@ -114,19 +114,6 @@ export class CommandsComponent implements OnInit {
});
}
executeCommand(event: MouseEvent, command: any): void {
this.dialog.open(ExecuteCommandComponent, {
width: '50%',
data: { commandData: command }
}).afterClosed().subscribe((result) => {
if (result) {
console.log('Comando ejecutado con éxito');
} else {
console.log('Ejecución de comando cancelada');
}
});
}
onPageChange(event: any): void {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
@ -147,5 +134,5 @@ export class CommandsComponent implements OnInit {
themeColor: '#3f51b5'
});
}
}

View File

@ -1,40 +1,10 @@
<h2 mat-dialog-title>{{ 'executeCommandTitle' | translate }}</h2>
<button mat-icon-button color="primary" [matMenuTriggerFor]="commandMenu">
<mat-icon>terminal</mat-icon>
</button>
<mat-dialog-content class="form-container">
<form [formGroup]="form" class="command-form">
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="unit">
<mat-option *ngFor="let unit of units" [value]="unit.uuid">{{ unit.name }}</mat-option>
</mat-select>
</mat-form-field>
<mat-menu #commandMenu="matMenu">
<button mat-menu-item [disabled]="command.disabled" *ngFor="let command of arrayCommands" (click)="onCommandSelect(command.slug)">
{{ command.name }}
</button>
</mat-menu>
<mat-form-field appearance="fill" class="full-width">
<mat-label>{{ 'subOrganizationalUnitLabel' | translate }}</mat-label>
<mat-select formControlName="childUnit">
<mat-option *ngFor="let child of childUnits" [value]="child.uuid">{{ child.name }}</mat-option>
</mat-select>
</mat-form-field>
<div class="checkbox-group">
<label>{{ 'clientsLabel' | translate }}</label>
<div *ngIf="clients.length > 0">
<mat-checkbox *ngFor="let client of clients"
(change)="toggleClientSelection(client.uuid)"
[checked]="form.get('clientSelection')?.value.includes(client.uuid)">
{{ client.name }}
</mat-checkbox>
</div>
<div *ngIf="clients.length === 0">
<p>{{ 'noClientsAvailable' | translate }}</p>
</div>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="closeModal()">{{ 'buttonCancel' | translate }}</button>
<button mat-button (click)="executeCommand()" [disabled]="!form.get('clientSelection')?.value.length">{{ 'buttonExecute' | translate }}</button>
</mat-dialog-actions>

View File

@ -1,7 +1,9 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {Component, Inject, Input, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
import { HttpClient } from '@angular/common/http';
import { FormBuilder, FormGroup } from '@angular/forms';
import {Router} from "@angular/router";
import {ToastrService} from "ngx-toastr";
@Component({
selector: 'app-execute-command',
@ -9,92 +11,129 @@ import { FormBuilder, FormGroup } from '@angular/forms';
styleUrls: ['./execute-command.component.css']
})
export class ExecuteCommandComponent implements OnInit {
form: FormGroup;
units: any[] = [];
childUnits: any[] = [];
clients: any[] = [];
selectedClients: any[] = [];
@Input() clientData: any = {};
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
loading: boolean = true;
arrayCommands: any[] = [
{name: 'Enceder', slug: 'power-on', disabled: false},
{name: 'Apagar', slug: 'power-off', disabled: false},
{name: 'Reiniciar', slug: 'reboot', disabled: false},
{name: 'Iniciar Sesión', slug: 'login', disabled: true},
{name: 'Crear Image', slug: 'create-image', disabled: false},
{name: 'Deploy Image', slug: 'deploy-image', disabled: false},
{name: 'Eliminar Imagen Cache', slug: 'delete-image-cache', disabled: true},
{name: 'Particionar y Formatear', slug: 'partition', disabled: false},
{name: 'Inventario Software', slug: 'software-inventory', disabled: true},
{name: 'Inventario Hardware', slug: 'hardware-inventory', disabled: true},
{name: 'Ejecutar script', slug: 'run-script', disabled: true},
];
constructor(
private dialogRef: MatDialogRef<ExecuteCommandComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private dialog: MatDialog,
private http: HttpClient,
private fb: FormBuilder
private fb: FormBuilder,
private router: Router,
private toastService: ToastrService
) {
this.form = this.fb.group({
unit: [null],
childUnit: [null],
clientSelection: [[]]
});
}
ngOnInit(): void {
this.loadUnits();
this.form.get('unit')?.valueChanges.subscribe(value => this.onUnitChange(value));
this.form.get('childUnit')?.valueChanges.subscribe(value => this.onChildUnitChange(value));
this.clientData = this.clientData || {};
this.loadClient(this.clientData)
}
loadUnits(): void {
this.http.get<any>(`${this.baseUrl}/organizational-units?page=1&itemsPerPage=30`).subscribe(
response => {
this.units = response['hydra:member'].filter((unit: { type: string; }) => unit.type === 'organizational-unit');
loadClient = (uuid: string) => {
this.http.get<any>(`${this.baseUrl}${uuid}`).subscribe({
next: data => {
this.clientData = data;
this.loading = false;
},
error => console.error('Error fetching organizational units:', error)
error: error => {
console.error('Error al obtener el cliente:', error);
}
});
}
onCommandSelect(action: any): void {
if (action === 'partition') {
this.openPartitionAssistant();
}
if (action === 'create-image') {
this.openCreateImageAssistant();
}
if (action === 'deploy-image') {
this.openDeployImageAssistant();
}
if (action === 'reboot') {
this.rebootClient();
}
if (action === 'power-off') {
this.powerOffClient();
}
if (action === 'power-on') {
this.powerOnClient();
}
}
rebootClient(): void {
this.http.post(`${this.baseUrl}/clients/server/${this.clientData.uuid}/reboot`, {}).subscribe(
response => {
this.toastService.success('Cliente actualizado correctamente');
},
error => {
this.toastService.error('Error de conexión con el cliente');
}
);
}
onUnitChange(unitId: string): void {
const unit = this.units.find(unit => unit.uuid === unitId);
this.childUnits = unit ? this.getAllChildren(unit) : [];
this.clients = [];
this.form.patchValue({ childUnit: null, clientSelection: [] });
}
getAllChildren(unit: any): any[] {
let allChildren = [];
if (unit.children && unit.children.length > 0) {
for (const child of unit.children) {
allChildren.push(child);
allChildren = allChildren.concat(this.getAllChildren(child));
}
}
return allChildren;
}
onChildUnitChange(childUnitId: string): void {
const childUnit = this.childUnits.find(unit => unit.uuid === childUnitId);
this.clients = childUnit && childUnit.clients ? childUnit.clients : [];
this.form.patchValue({ clientSelection: [] });
}
executeCommand(): void {
powerOnClient(): void {
const payload = {
clients: ['/clients/'+this.form.get('clientSelection')?.value]
};
this.http.post(`${this.baseUrl}/commands/${this.data.commandData.uuid}/execute`, payload)
.subscribe({
next: () => {
console.log('Comando ejecutado con éxito');
this.dialogRef.close(true);
},
error: (error) => {
console.error('Error al ejecutar el comando:', error);
}
});
}
closeModal(): void {
this.dialogRef.close(false);
}
toggleClientSelection(clientId: string): void {
const selectedClients = this.form.get('clientSelection')?.value;
if (selectedClients.includes(clientId)) {
this.form.get('clientSelection')?.setValue(selectedClients.filter((id: string) => id !== clientId));
} else {
this.form.get('clientSelection')?.setValue([...selectedClients, clientId]);
client: this.clientData['@id']
}
this.http.post(`${this.baseUrl}${this.clientData.repository['@id']}/wol`, payload).subscribe(
response => {
this.toastService.success('Cliente actualizado correctamente');
},
error => {
this.toastService.error('Error de conexión con el cliente');
}
);
}
powerOffClient(): void {
this.http.post(`${this.baseUrl}/clients/server/${this.clientData.uuid}/power-off`, {}).subscribe(
response => {
this.toastService.success('Cliente actualizado correctamente');
},
error => {
this.toastService.error('Error de conexión con el cliente');
}
);
}
openPartitionAssistant(): void {
this.router.navigate([`/clients/${this.clientData.uuid}/partition-assistant`]).then(r => {
console.log('navigated', r);
});
}
openCreateImageAssistant(): void {
this.router.navigate([`/clients/${this.clientData.uuid}/create-image`]).then(r => {
console.log('navigated', r);
});
}
openDeployImageAssistant(): void {
this.router.navigate([`/clients/${this.clientData.uuid}/deploy-image`]).then(r => {
console.log('navigated', r);
});
}
}

View File

@ -122,6 +122,7 @@ export class ClientMainViewComponent implements OnInit {
}
});
}
updateGeneralData() {
this.generalData = [
{ property: 'Nombre', value: this.clientData?.name || '' },

View File

@ -187,7 +187,6 @@ export class DeployImageComponent {
.subscribe({
next: (response) => {
this.toastService.success('Petición de despliegue enviada correctamente');
this.router.navigate(['/commands-logs'])
},
error: (error) => {
console.error('Error:', error);

View File

@ -166,10 +166,6 @@
</button>
</mat-menu>
<mat-menu #menu="matMenu">
<button *ngIf="selectedNode?.type === 'classroom'" mat-menu-item [matMenuTriggerFor]="commandMenu" (click)="fetchCommands()">
<mat-icon>play_arrow</mat-icon>
<span>{{ 'executeCommand' | translate }}</span>
</button>
<button mat-menu-item (click)="onShowDetailsClick($event, selectedNode)">
<mat-icon matTooltip="{{ 'viewUnitTooltip' | translate }}" matTooltipHideDelay="0">visibility</mat-icon>
<span>{{ 'viewUnitMenu' | translate }}</span>
@ -227,9 +223,7 @@
<button mat-icon-button color="primary" (click)="onShowClientDetail($event, client)">
<mat-icon>visibility</mat-icon>
</button>
<button mat-icon-button color="primary">
<mat-icon>more_vert</mat-icon>
</button>
<app-execute-command [clientData]="client['@id']"></app-execute-command>
</div>
</div>
</div>
@ -245,7 +239,6 @@
[src]="'assets/images/ordenador_' + client.status + '.png'"
alt="Client Icon"
class="client-image" />
</td>
</ng-container>
@ -299,25 +292,14 @@
<td mat-cell *matCellDef="let client"> {{ client.parentName }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<ng-container matColumnDef="actions" >
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'actions' | translate }} </th>
<td mat-cell *matCellDef="let client">
<button mat-icon-button [matMenuTriggerFor]="clientMenu">
<mat-icon>more_vert</mat-icon>
</button>
<app-execute-command [clientData]="client['@id']"></app-execute-command>
<mat-menu #clientMenu="matMenu">
<mat-menu restoreFocus=false #commandMenu="matMenu" xPosition="before">
<button mat-menu-item *ngFor="let command of commands" (click)="executeClientCommand(command, client)">
<span>{{ command.name }}</span>
</button>
</mat-menu>
<button mat-menu-item [matMenuTriggerFor]="commandMenu" (click)="fetchCommands()">
<mat-icon>play_arrow</mat-icon>
<span>{{ 'executeCommand' | translate }}</span>
</button>
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
<mat-icon>edit</mat-icon>
<span>{{ 'edit' | translate }}</span>

View File

@ -135,6 +135,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
}
private transformer = (node: TreeNode, level: number): FlatNode => ({
id: node.id,
name: node.name,
type: node.type,
level,
@ -268,6 +269,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
private convertToTreeData(data: UnidadOrganizativa): TreeNode[] {
const processNode = (node: UnidadOrganizativa): TreeNode => ({
id: node.id,
name: node.name,
type: node.type,
'@id': node['@id'],
@ -279,34 +281,22 @@ export class GroupsComponent implements OnInit, OnDestroy {
onNodeClick(node: TreeNode): void {
console.log('Node clicked:', node);
this.selectedNode = node;
this.fetchClientsForNode(node);
}
private fetchClientsForNode(node: TreeNode): void {
if (node.hasClients && node['@id']) {
this.subscriptions.add(
this.http.get<{ clients: Client[] }>(`${this.baseUrl}${node['@id']}`).subscribe(
(data) => {
const clientsWithParentName = (data.clients || []).map(client => ({
...client,
parentName: node.name
}));
this.selectedClients.data = clientsWithParentName;
this.selectedClients._updateChangeSubscription();
if (this._paginator) {
this._paginator.firstPage();
}
},
(error) => {
console.error('Error fetching clients:', error);
}
)
);
} else {
this.selectedClients.data = [];
this.selectedClients._updateChangeSubscription();
}
console.log('Node:', node);
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${node.id}`).subscribe({
next: (response) => {
this.selectedClients.data = response['hydra:member'];
this.loading = false;
},
error: () => {
this.loading = false;
}
});
}
getNodeIcon(node: TreeNode): string {
@ -357,7 +347,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
.filter(node => this.treeControl.isExpanded(node))
.map(node => this.extractUuid(node['@id']))
: [];
this.subscriptions.add(
this.dataService.getOrganizationalUnits().subscribe(
(data) => {
@ -368,7 +358,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
const treeData = this.convertToTreeData(updatedData);
this.originalTreeData = treeData[0]?.children || [];
this.treeDataSource.data = [...this.originalTreeData];
setTimeout(() => {
this.treeControl.dataNodes.forEach(node => {
const nodeId = this.extractUuid(node['@id']);
@ -384,7 +374,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
)
);
}
onEditNode(event: MouseEvent, node: TreeNode | null): void {
event.stopPropagation();
@ -494,10 +484,6 @@ export class GroupsComponent implements OnInit, OnDestroy {
}
}
executeClientCommand(command: Command, client: Client): void {
this.toastr.success(`Ejecutando comando: ${command.name} en ${client.name}`);
}
onShowClientDetail(event: MouseEvent, client: Client): void {
event.stopPropagation();
this.router.navigate(['clients', client.uuid], { state: { clientData: client } });
@ -591,13 +577,13 @@ export class GroupsComponent implements OnInit, OnDestroy {
this.toastr.success('Cliente actualizado correctamente');
this.syncStatus = false;
this.syncingClientId = null;
this.onNodeClick(node);
this.search()
},
() => {
this.toastr.error('Error de conexión con el cliente');
this.syncStatus = false;
this.syncingClientId = null;
this.onNodeClick(node);
this.search()
}
)
);

View File

@ -60,6 +60,7 @@ export interface ClientCollection {
}
export interface TreeNode {
id?: string
name: string;
type: string;
'@id'?: string;
@ -70,6 +71,7 @@ export interface TreeNode {
}
export interface FlatNode {
id?: string;
name: string;
type: string;
level: number;