diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts
index 9ec2f42..1245eeb 100644
--- a/ogWebconsole/src/app/app.module.ts
+++ b/ogWebconsole/src/app/app.module.ts
@@ -123,7 +123,7 @@ import { JoyrideModule } from 'ngx-joyride';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { EnvVarsComponent } from './components/admin/env-vars/env-vars.component';
-
+import { MatSortModule } from '@angular/material/sort';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './locale/', '.json');
}
@@ -234,6 +234,7 @@ export function HttpLoaderFactory(http: HttpClient) {
MatDatepickerModule,
MatNativeDateModule,
MatSliderModule,
+ MatSortModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html
index 0c1b9fc..85c1ad6 100644
--- a/ogWebconsole/src/app/components/groups/groups.component.html
+++ b/ogWebconsole/src/app/components/groups/groups.component.html
@@ -40,7 +40,7 @@
Filtrar por tipo
Todos
- Grupos de aulas
+ Grupos de aulas
Aulas
Grupos de ordenadores
diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts
index 0d64752..96cf096 100644
--- a/ogWebconsole/src/app/components/groups/groups.component.ts
+++ b/ogWebconsole/src/app/components/groups/groups.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
+import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
@@ -8,8 +8,10 @@ import { ToastrService } from 'ngx-toastr';
import { JoyrideService } from 'ngx-joyride';
import { FlatTreeControl } from '@angular/cdk/tree';
import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
+import { Subscription } from 'rxjs';
+
import { DataService } from './services/data.service';
-import { UnidadOrganizativa } from './model/model';
+import { UnidadOrganizativa, Client, TreeNode, FlatNode, Command, Filter } 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';
@@ -22,86 +24,67 @@ import { OrganizationalUnitTabViewComponent } from './components/organizational-
import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/delete-modal.component';
import { ClassroomViewDialogComponent } from './shared/classroom-view/classroom-view-modal';
-interface TreeNode {
- clients?: any[];
- name: string;
- type: string;
- children?: TreeNode[];
- ip?: string;
- '@id'?: string;
- hasClients?: boolean;
- status?: string;
-}
-
-interface FlatNode {
- name: string;
- type: string;
- level: number;
- expandable: boolean;
- ip?: string;
- hasClients?: boolean;
+enum NodeType {
+ OrganizationalUnit = 'organizational-unit',
+ ClassroomsGroup = 'classrooms-group',
+ Classroom = 'classroom',
+ ClientsGroup = 'clients-group',
+ Client = 'client',
}
@Component({
selector: 'app-groups',
templateUrl: './groups.component.html',
- styleUrls: ['./groups.component.css']
+ styleUrls: ['./groups.component.css'],
})
-export class GroupsComponent implements OnInit {
+export class GroupsComponent implements OnInit, OnDestroy {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
organizationalUnits: UnidadOrganizativa[] = [];
selectedUnidad: UnidadOrganizativa | null = null;
- selectedDetail: any | null = null;
- loading: boolean = false;
- loadingChildren: boolean = false;
- searchTerm: string = '';
+ selectedDetail: UnidadOrganizativa | null = null;
+ loading = false;
+ searchTerm = '';
treeControl: FlatTreeControl;
treeFlattener: MatTreeFlattener;
treeDataSource: MatTreeFlatDataSource;
selectedNode: TreeNode | null = null;
- commands: any[] = [];
- commandsLoading: boolean = false;
- selectedClients: any[] = [];
- cols: number = 4;
- selectedClientsOriginal: any[] = [];
+ commands: Command[] = [];
+ commandsLoading = false;
+ selectedClients: Client[] = [];
+ cols = 4;
+ selectedClientsOriginal: Client[] = [];
currentView: 'card' | 'list' = 'list';
- isTreeViewActive: boolean = false;
- savedFilterNames: any[] = [];
- selectedTreeFilter: string = '';
-
- syncStatus: boolean = false;
- syncingClientId: number | null = null;
+ isTreeViewActive = false;
+ savedFilterNames: [string, string][] = [];
+ selectedTreeFilter = '';
+ syncStatus = false;
+ syncingClientId: string | null = null;
+ private originalTreeData: TreeNode[] = [];
@ViewChild('clientTab') clientTabComponent!: ClientTabViewComponent;
@ViewChild('organizationalUnitTab') organizationalUnitTabComponent!: OrganizationalUnitTabViewComponent;
+ private subscriptions: Subscription = new Subscription();
+
constructor(
private http: HttpClient,
private router: Router,
private dataService: DataService,
public dialog: MatDialog,
- private _bottomSheet: MatBottomSheet,
+ private bottomSheet: MatBottomSheet,
private joyrideService: JoyrideService,
private toastr: ToastrService
) {
this.treeFlattener = new MatTreeFlattener(
- (node: TreeNode, level: number) => ({
- name: node.name,
- type: node.type,
- level,
- expandable: !!node.children?.length,
- hasClients: node.hasClients,
- ip: node.ip,
- ['@id']: node['@id']
- }),
- node => node.level,
- node => node.expandable,
- node => node.children
+ this.transformer,
+ (node) => node.level,
+ (node) => node.expandable,
+ (node) => node.children
);
this.treeControl = new FlatTreeControl(
- node => node.level,
- node => node.expandable
+ (node) => node.level,
+ (node) => node.expandable
);
this.treeDataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
@@ -111,17 +94,32 @@ export class GroupsComponent implements OnInit {
this.search();
this.getFilters();
this.updateGridCols();
- window.addEventListener('resize', () => this.updateGridCols());
+ window.addEventListener('resize', this.updateGridCols);
}
- toggleView(view: 'card' | 'list') {
+ ngOnDestroy(): void {
+ window.removeEventListener('resize', this.updateGridCols);
+ this.subscriptions.unsubscribe();
+ }
+
+ private transformer = (node: TreeNode, level: number): FlatNode => ({
+ name: node.name,
+ type: node.type,
+ level,
+ expandable: !!node.children?.length,
+ hasClients: node.hasClients,
+ ip: node.ip,
+ '@id': node['@id'],
+ });
+
+ toggleView(view: 'card' | 'list'): void {
this.currentView = view;
}
- updateGridCols(): void {
+ updateGridCols = (): void => {
const width = window.innerWidth;
this.cols = width <= 600 ? 1 : width <= 960 ? 2 : width <= 1280 ? 3 : 4;
- }
+ };
clearSelection(): void {
this.selectedUnidad = null;
@@ -139,112 +137,122 @@ export class GroupsComponent implements OnInit {
}
getFilters(): void {
- this.dataService.getFilters().subscribe(
- data => {
- this.savedFilterNames = data.map((filter: any) => [filter.name, filter.uuid]);
- },
- error => {
- console.error('Error fetching filters:', error);
- }
+ this.subscriptions.add(
+ this.dataService.getFilters().subscribe(
+ (data) => {
+ this.savedFilterNames = data.map((filter: { name: string; uuid: string; }) => [filter.name, filter.uuid]);
+ },
+ (error) => {
+ console.error('Error fetching filters:', error);
+ }
+ )
);
}
- loadSelectedFilter(savedFilter: any) {
- const url = `${this.baseUrl}/views/` + savedFilter[1];
- this.dataService.getFilter(savedFilter[1]).subscribe(response => {
- if (response) {
- console.log('Filter1:', response.filters);
- }
- }, error => {
- console.error('Error:', error);
- });
+ loadSelectedFilter(savedFilter: [string, string]): void {
+ this.subscriptions.add(
+ this.dataService.getFilter(savedFilter[1]).subscribe(
+ (response) => {
+ if (response) {
+ console.log('Filter:', response.filters);
+ }
+ },
+ (error) => {
+ console.error('Error:', error);
+ }
+ )
+ );
}
search(): void {
this.loading = true;
- this.dataService.getOrganizationalUnits(this.searchTerm).subscribe(
- data => {
- this.organizationalUnits = data;
- this.loading = false;
- },
- error => {
- console.error('Error fetching unidades organizativas', error);
- this.loading = false;
- }
+ this.subscriptions.add(
+ this.dataService.getOrganizationalUnits(this.searchTerm).subscribe(
+ (data) => {
+ this.organizationalUnits = data;
+ this.loading = false;
+ },
+ (error) => {
+ console.error('Error fetching organizational units', error);
+ this.loading = false;
+ }
+ )
);
}
- onSelectUnidad(unidad: any): void {
+ onSelectUnidad(unidad: UnidadOrganizativa): void {
this.selectedUnidad = unidad;
this.selectedDetail = unidad;
this.selectedClients = this.collectAllClients(unidad);
this.selectedClientsOriginal = [...this.selectedClients];
- this.loadChildrenAndClients(unidad.id).then(fullData => {
+ this.loadChildrenAndClients(unidad.id).then((fullData) => {
const treeData = this.convertToTreeData(fullData);
this.treeDataSource.data = treeData[0]?.children || [];
});
this.isTreeViewActive = true;
}
- private collectAllClients(node: any): any[] {
+ private collectAllClients(node: UnidadOrganizativa): Client[] {
let clients = node.clients || [];
- if (node.children && node.children.length > 0) {
- node.children.forEach((child: any) => {
+ if (node.children) {
+ node.children.forEach((child) => {
clients = clients.concat(this.collectAllClients(child));
});
}
return clients;
}
- async loadChildrenAndClients(id: string): Promise {
+ private async loadChildrenAndClients(id: string): Promise {
try {
const childrenData = await this.dataService.getChildren(id).toPromise();
- const processHierarchy = (nodes: UnidadOrganizativa[]): TreeNode[] => {
- return nodes.map(node => ({
- name: node.name,
- type: node.type,
- '@id': node['@id'],
+
+ const processHierarchy = (nodes: UnidadOrganizativa[]): UnidadOrganizativa[] => {
+ return nodes.map((node) => ({
+ ...node,
children: node.children ? processHierarchy(node.children) : [],
- clients: node.clients || []
}));
};
-
+
return {
- ...this.selectedUnidad,
- children: childrenData ? processHierarchy(childrenData) : []
+ ...this.selectedUnidad!,
+ children: childrenData ? processHierarchy(childrenData) : [],
};
} catch (error) {
console.error('Error loading children:', error);
- return this.selectedUnidad;
+ return this.selectedUnidad!;
}
}
+
- convertToTreeData(data: any): TreeNode[] {
- const processNode = (node: UnidadOrganizativa): TreeNode => ({
- name: node.name,
- type: node.type,
- '@id': node['@id'],
- children: node.children?.map(processNode) || [],
- hasClients: node.clients && node.clients.length > 0,
- });
-
- return [processNode(data)];
- }
+ private convertToTreeData(data: UnidadOrganizativa): TreeNode[] {
+ const processNode = (node: UnidadOrganizativa): TreeNode => ({
+ name: node.name,
+ type: node.type,
+ '@id': node['@id'],
+ children: node.children?.map(processNode) || [],
+ hasClients: (node.clients?.length ?? 0) > 0,
+ });
+ return [processNode(data)];
+}
+
onNodeClick(node: TreeNode): void {
this.selectedNode = node;
- this.selectedClients = node.clients || [];
- this.selectedClientsOriginal = [...this.selectedClients];
- if (node.hasClients) {
- const url = `${this.baseUrl}${node['@id']}`;
- this.http.get(url).subscribe(
- (data: any) => {
- this.selectedClientsOriginal = [...data.clients];
- this.selectedClients = data.clients || [];
- },
- (error) => {
- console.error('Error fetching clients:', error);
- }
+ 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) => {
+ this.selectedClientsOriginal = [...data.clients];
+ this.selectedClients = data.clients || [];
+ },
+ (error) => {
+ console.error('Error fetching clients:', error);
+ }
+ )
);
} else {
this.selectedClients = [];
@@ -252,222 +260,207 @@ export class GroupsComponent implements OnInit {
}
}
- getNodeIcon(node: any): string {
+ getNodeIcon(node: TreeNode): string {
switch (node.type) {
- case 'organizational-unit': return 'apartment';
- case 'classrooms-group': return 'doors';
- case 'classroom': return 'school';
- case 'clients-group': return 'lan';
- case 'client': return 'computer';
- default: return 'group';
+ case NodeType.OrganizationalUnit:
+ return 'apartment';
+ case NodeType.ClassroomsGroup:
+ return 'doors';
+ case NodeType.Classroom:
+ return 'school';
+ case NodeType.ClientsGroup:
+ return 'lan';
+ case NodeType.Client:
+ return 'computer';
+ default:
+ return 'group';
}
}
- addOU(event: MouseEvent, parent: any = null): void {
+ addOU(event: MouseEvent, parent: TreeNode | null = null): void {
event.stopPropagation();
- const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, { data: { parent }, width: '900px' });
+ const dialogRef = this.dialog.open(CreateOrganizationalUnitComponent, {
+ data: { parent },
+ width: '900px',
+ });
dialogRef.afterClosed().subscribe(() => {
- this.dataService.getOrganizationalUnits().subscribe(
- data => {
- this.organizationalUnits = data;
- this.loadChildrenAndClients(this.selectedUnidad?.id || '').then(updatedData => {
- const treeData = this.convertToTreeData(updatedData);
- this.treeDataSource.data = treeData[0]?.children || [];
- });
- },
- error => console.error('Error fetching unidades organizativas', error)
- );
+ this.refreshOrganizationalUnits();
});
}
- addClient(event: MouseEvent, organizationalUnit: any = null): void {
+ addClient(event: MouseEvent, organizationalUnit: TreeNode | null = null): void {
event.stopPropagation();
- const dialogRef = this.dialog.open(CreateClientComponent, { data: { organizationalUnit }, width: '900px' });
+ const dialogRef = this.dialog.open(CreateClientComponent, {
+ data: { organizationalUnit },
+ width: '900px',
+ });
dialogRef.afterClosed().subscribe(() => {
+ this.refreshOrganizationalUnits();
+ if (organizationalUnit && organizationalUnit['@id']) {
+ this.refreshClientsForNode(organizationalUnit);
+ }
+ });
+ }
+
+ private refreshOrganizationalUnits(): void {
+ this.subscriptions.add(
this.dataService.getOrganizationalUnits().subscribe(
- data => {
+ (data) => {
this.organizationalUnits = data;
- this.loadChildrenAndClients(this.selectedUnidad?.id || '').then(updatedData => {
- const treeData = this.convertToTreeData(updatedData);
- this.treeDataSource.data = treeData[0]?.children || [];
- });
- if (organizationalUnit && organizationalUnit.id) {
- this.loadChildrenAndClients(organizationalUnit.id);
- this.refreshClients(organizationalUnit);
- }
- },
- error => console.error('Error fetching unidades organizativas', error)
- );
- });
- }
-
- setSelectedNode(node: TreeNode): void {
- this.selectedNode = node;
- }
-
- onEditNode(event: MouseEvent, node: TreeNode | null): void {
- if (!node) return;
-
- const uuid = node['@id'] ? node['@id'].split('/').pop() : '';
- const type = node.type;
-
- event.stopPropagation();
-
- if (type !== 'client') {
- this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid }, width: '900px' });
- } else {
- this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
- }
- }
-
- onDelete(node: TreeNode | null): void {
- console.log('Deleting node:', node);
- }
-
- onDeleteClick(event: MouseEvent, node: TreeNode | null, clientNode?: TreeNode | null): void {
- const uuid = node && node['@id'] ? node['@id'].split('/').pop() || '' : '';
- const name = node?.name || 'Elemento desconocido';
- const type = node?.type || '';
-
- event.stopPropagation();
-
- const dialogRef = this.dialog.open(DeleteModalComponent, {
- width: '400px',
- data: { name }
- });
-
- dialogRef.afterClosed().subscribe(result => {
- if (result === true) {
- this.dataService.deleteElement(uuid, type).subscribe(
- () => {
- this.loadChildrenAndClients(this.selectedUnidad?.id || '').then(updatedData => {
+ if (this.selectedUnidad) {
+ this.loadChildrenAndClients(this.selectedUnidad?.id || '').then((updatedData) => {
+ this.selectedUnidad = updatedData;
const treeData = this.convertToTreeData(updatedData);
- this.treeDataSource.data = treeData[0]?.children || [];
- });
-
- if (type === 'client' && clientNode) {
- this.refreshClients(clientNode);
- }
-
- this.dataService.getOrganizationalUnits().subscribe(
- data => {
- this.organizationalUnits = data;
- },
- error => console.error('Error fetching unidades organizativas', error)
- );
-
- this.toastr.success('Entidad eliminada exitosamente');
- },
- error => {
- console.error('Error deleting entity:', error);
- this.toastr.error('Error al eliminar la entidad', error.message);
+ this.originalTreeData = treeData[0]?.children || [];
+ this.treeDataSource.data = [...this.originalTreeData];
+ });
}
- );
- }
- });
- }
-
- private refreshClients(node: TreeNode): void {
- if (!node || !node['@id']) {
- this.selectedClients = [];
- return;
- }
-
- const url = `${this.baseUrl}${node['@id']}`;
- this.http.get(url).subscribe(
- (data: any) => {
- if (data && Array.isArray(data.clients)) {
- this.selectedClients = data.clients;
- } else {
- this.selectedClients = [];
- }
- },
- error => {
- console.error('Error refreshing clients:', error);
- const errorMessage = error.status === 404
- ? 'No se encontraron clientes para este nodo.'
- : 'Error al comunicarse con el servidor.';
- this.toastr.error(errorMessage);
- }
+ },
+ (error) => console.error('Error fetching organizational units', error)
+ )
);
}
- onEditClick(event: MouseEvent, type: any, uuid: string): void {
+ onEditNode(event: MouseEvent, node: TreeNode | null): void {
event.stopPropagation();
- if (type != 'client') {
+ const uuid = node ? this.extractUuid(node['@id']) : null;
+ if (!uuid) return;
+
+ if (node && node.type !== NodeType.Client) {
this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid }, width: '900px' });
} else {
this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
}
}
- onRoomMap(room: any): void {
- this.http.get(`${this.baseUrl}`+ room['@id']).subscribe(
- (response: any) => {
- this.dialog.open(ClassroomViewDialogComponent, {
- width: '90vw',
- data: { clients: response.clients }
- });
- },
- (error: any) => {
- console.error('Error en la solicitud HTTP:', error);
+ onDeleteClick(event: MouseEvent, node: TreeNode | null, clientNode?: TreeNode | null): void{
+ event.stopPropagation();
+ const uuid = node ? this.extractUuid(node['@id']) : null;
+ if (!uuid) return;
+
+ if (!node) return;
+ const dialogRef = this.dialog.open(DeleteModalComponent, {
+ width: '400px',
+ data: { name: node.name },
+ });
+
+ dialogRef.afterClosed().subscribe((result) => {
+ if (result === true) {
+ this.deleteEntity(uuid, node.type, node);
}
+ });
+ }
+
+ private deleteEntity(uuid: string, type: string, node: TreeNode): void {
+ this.subscriptions.add(
+ this.dataService.deleteElement(uuid, type).subscribe(
+ () => {
+ this.refreshOrganizationalUnits();
+ if (type === NodeType.Client) {
+ this.refreshClientsForNode(node);
+ }
+ this.toastr.success('Entidad eliminada exitosamente');
+ },
+ (error) => {
+ console.error('Error deleting entity:', error);
+ this.toastr.error('Error al eliminar la entidad', error.message);
+ }
+ )
+ );
+ }
+
+ private refreshClientsForNode(node: TreeNode): void {
+ if (!node['@id']) {
+ this.selectedClients = [];
+ return;
+ }
+ this.fetchClientsForNode(node);
+ }
+
+ onEditClick(event: MouseEvent, type: string, uuid: string): void {
+ event.stopPropagation();
+ if (type !== NodeType.Client) {
+ this.dialog.open(EditOrganizationalUnitComponent, { data: { uuid }, width: '900px' });
+ } else {
+ this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
+ }
+ }
+
+ onRoomMap(room: TreeNode | null): void {
+ if (!room || !room['@id']) return;
+ this.subscriptions.add(
+ this.http.get<{ clients: Client[] }>(`${this.baseUrl}${room['@id']}`).subscribe(
+ (response) => {
+ this.dialog.open(ClassroomViewDialogComponent, {
+ width: '90vw',
+ data: { clients: response.clients },
+ });
+ },
+ (error) => {
+ console.error('Error fetching room data:', error);
+ }
+ )
);
}
fetchCommands(): void {
this.commandsLoading = true;
- this.http.get(`${this.baseUrl}`+'/commands?page=1&itemsPerPage=30').subscribe(
- (response: any) => {
- this.commands = response['hydra:member'];
- this.commandsLoading = false;
- },
- (error) => {
- console.error('Error fetching commands:', error);
- this.commandsLoading = false;
- }
+ this.subscriptions.add(
+ this.http.get<{ 'hydra:member': Command[] }>(`${this.baseUrl}/commands?page=1&itemsPerPage=30`).subscribe(
+ (response) => {
+ this.commands = response['hydra:member'];
+ this.commandsLoading = false;
+ },
+ (error) => {
+ console.error('Error fetching commands:', error);
+ this.commandsLoading = false;
+ }
+ )
);
}
- executeCommand(command: any, selectedNode: any): void {
- this.toastr.success('Ejecutando comando: ' + command.name + " en " + selectedNode.name);
+ executeCommand(command: Command, selectedNode: TreeNode | null): void {
+
+ if (!selectedNode) {
+ this.toastr.error('No hay un nodo seleccionado.');
+ return;
+ } else {
+ this.toastr.success(`Ejecutando comando: ${command.name} en ${selectedNode.name}`);
+ }
}
- onClientActions(client: any): void {
- console.log('Client actions:', client);
- }
-
- onShowClientDetail(event: MouseEvent, client: any): void {
+ onShowClientDetail(event: MouseEvent, client: Client): void {
event.stopPropagation();
this.router.navigate(['clients', client.uuid], { state: { clientData: client } });
}
- onShowDetailsClick(event: MouseEvent, data: any): void {
+ onShowDetailsClick(event: MouseEvent, data: TreeNode | null): void {
event.stopPropagation();
- if (data.type != 'client') {
+ if (data && data.type !== NodeType.Client) {
this.dialog.open(ShowOrganizationalUnitComponent, { data: { data }, width: '700px' });
- }
- if (data.type == 'client') {
- this.router.navigate(['clients', data['@id'].split('/').pop()], { state: { clientData: data } });
+ } else {
+ if (data) {
+ this.router.navigate(['clients', this.extractUuid(data['@id'])], { state: { clientData: data } });
+ }
}
}
- onTreeClick(event: MouseEvent, data: any): void {
+ onTreeClick(event: MouseEvent, data: TreeNode): void {
event.stopPropagation();
- if (data.type != 'client') {
+ if (data.type !== NodeType.Client) {
this.dialog.open(TreeViewComponent, { data: { data }, width: '800px' });
}
}
openBottomSheet(): void {
- this._bottomSheet.open(LegendComponent);
+ this.bottomSheet.open(LegendComponent);
}
iniciarTour(): void {
this.joyrideService.startTour({
steps: ['groupsTitleStepText', 'addStep', 'keyStep', 'unitStep', 'elementsStep', 'tabsStep'],
showPrevButton: true,
- themeColor: '#3f51b5'
+ themeColor: '#3f51b5',
});
}
@@ -475,23 +468,25 @@ export class GroupsComponent implements OnInit {
isLeafNode = (_: number, node: FlatNode): boolean => !node.expandable;
filterTree(searchTerm: string, filterType: string): void {
- const filterNodes = (nodes: any[]): any[] => {
- return nodes
- .map(node => {
- const matchesName = node.name.toLowerCase().includes(searchTerm.toLowerCase());
- const matchesType = filterType ? node.type.toLowerCase() === filterType.toLowerCase() : true;
- const filteredChildren = node.children ? filterNodes(node.children) : [];
- if (matchesName && matchesType || filteredChildren.length > 0) {
- return { ...node, children: filteredChildren };
- }
- return null;
- })
- .filter(node => node !== null);
+ const filterNodes = (nodes: TreeNode[]): TreeNode[] => {
+ const filteredNodes: TreeNode[] = [];
+ for (const node of nodes) {
+ const matchesName = node.name.toLowerCase().includes(searchTerm.toLowerCase());
+ const matchesType = filterType ? node.type.toLowerCase() === filterType.toLowerCase() : true;
+ const filteredChildren = node.children ? filterNodes(node.children) : [];
+
+ if ((matchesName && matchesType) || filteredChildren.length > 0) {
+ filteredNodes.push({ ...node, children: filteredChildren });
+ }
+ }
+ return filteredNodes;
};
-
- const filteredData = filterNodes(this.treeDataSource.data);
+
+ const filteredData = filterNodes(this.originalTreeData);
this.treeDataSource.data = filteredData;
}
+
+
onTreeFilterInput(event: Event): void {
const input = event.target as HTMLInputElement;
@@ -513,32 +508,44 @@ export class GroupsComponent implements OnInit {
const lowerTerm = searchTerm.toLowerCase();
- this.selectedClients = this.selectedClientsOriginal.filter(client => {
- const matchesName = client.name.toLowerCase().includes(lowerTerm);
- const matchesIP = client.ip?.toLowerCase().includes(lowerTerm) || false;
- const matchesStatus = client.status?.toLowerCase().includes(lowerTerm) || false;
- const matchesMac = client.mac?.toLowerCase().includes(lowerTerm) || false;
-
- return matchesName || matchesIP || matchesStatus || matchesMac;
+ this.selectedClients = this.selectedClientsOriginal.filter((client) => {
+ return (
+ client.name.toLowerCase().includes(lowerTerm) ||
+ client.ip?.toLowerCase().includes(lowerTerm) ||
+ client.status?.toLowerCase().includes(lowerTerm) ||
+ client.mac?.toLowerCase().includes(lowerTerm)
+ );
});
}
- getStatus(client: any): void {
+ public setSelectedNode(node: TreeNode): void {
+ this.selectedNode = node;
+ }
+
+ getStatus(client: Client): void {
+ if (!client.uuid || !client['@id']) return;
+
this.syncingClientId = client.uuid;
this.syncStatus = true;
- this.http.post(`${this.baseUrl}${client['@id']}/agent/status`, {}).subscribe(
- response => {
- this.toastr.success('Cliente actualizado correctamente');
- this.search();
- this.syncStatus = false;
- this.syncingClientId = null;
- },
- error => {
- this.toastr.error('Error de conexión con el cliente');
- this.syncStatus = false;
- this.syncingClientId = null;
- }
+ this.subscriptions.add(
+ this.http.post(`${this.baseUrl}${client['@id']}/agent/status`, {}).subscribe(
+ () => {
+ this.toastr.success('Cliente actualizado correctamente');
+ this.search();
+ this.syncStatus = false;
+ this.syncingClientId = null;
+ },
+ () => {
+ this.toastr.error('Error de conexión con el cliente');
+ this.syncStatus = false;
+ this.syncingClientId = null;
+ }
+ )
);
}
+
+ private extractUuid(idPath: string | undefined): string | null {
+ return idPath ? idPath.split('/').pop() || null : null;
+ }
}
diff --git a/ogWebconsole/src/app/components/groups/model/model.ts b/ogWebconsole/src/app/components/groups/model/model.ts
index 289a796..7789157 100644
--- a/ogWebconsole/src/app/components/groups/model/model.ts
+++ b/ogWebconsole/src/app/components/groups/model/model.ts
@@ -9,14 +9,14 @@ export interface Aula {
}
export interface UnidadOrganizativa {
- clients: any[];
- children: UnidadOrganizativa[];
- '@id'?: string;
id: string;
- name: string;
uuid: string;
+ name: string;
type: string;
- parent: UnidadOrganizativa[];
+ '@id': string;
+ clients?: Client[];
+ children?: UnidadOrganizativa[];
+ parent?: UnidadOrganizativa;
}
export interface OrganizationalUnit {
@@ -29,6 +29,9 @@ export interface OrganizationalUnit {
}
export interface Client {
+ mac: any;
+ status: any;
+ ip: any;
"@id": string;
"@type": string;
id: number;
@@ -54,3 +57,35 @@ export interface ClientCollection {
"@type": string;
};
}
+
+export interface TreeNode {
+ name: string;
+ type: string;
+ '@id'?: string;
+ children?: TreeNode[];
+ hasClients?: boolean;
+ clients?: Client[];
+ ip?: string;
+}
+
+export interface FlatNode {
+ name: string;
+ type: string;
+ level: number;
+ expandable: boolean;
+ hasClients?: boolean;
+ ip?: string;
+ '@id'?: string;
+}
+
+
+export interface Command {
+ name: string;
+ description?: string;
+}
+
+export interface Filter {
+ name: string;
+ uuid: string;
+}
+