parent
f0e3a34f00
commit
1962beaf8a
|
@ -1,20 +1,18 @@
|
|||
<ng-container [ngSwitch]="buttonType">
|
||||
<button *ngSwitchCase="'icon'" mat-icon-button color="primary" [matMenuTriggerFor]="commandMenu">
|
||||
<button *ngSwitchCase="'icon'" mat-icon-button color="primary" [matMenuTriggerFor]="commandMenu"
|
||||
[disabled]="disabled">
|
||||
<mat-icon>{{ icon }}</mat-icon>
|
||||
</button>
|
||||
|
||||
<button class="action-button" [disabled]="clientData.length === 0" *ngSwitchCase="'text'" [matMenuTriggerFor]="commandMenu">
|
||||
<button class="action-button" [disabled]="clientData.length === 0 || disabled" *ngSwitchCase="'text'"
|
||||
[matMenuTriggerFor]="commandMenu">
|
||||
{{ buttonText }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<mat-menu #commandMenu="matMenu" >
|
||||
<button
|
||||
mat-menu-item
|
||||
[disabled]="command.disabled || (command.slug === 'create-image' && clientData.length > 1)"
|
||||
*ngFor="let command of arrayCommands"
|
||||
(click)="onCommandSelect(command.slug)"
|
||||
>
|
||||
<mat-menu #commandMenu="matMenu">
|
||||
<button mat-menu-item [disabled]="command.disabled || (command.slug === 'create-image' && clientData.length > 1)"
|
||||
*ngFor="let command of arrayCommands" (click)="onCommandSelect(command.slug)">
|
||||
{{ command.name }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
</mat-menu>
|
|
@ -15,6 +15,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
@Input() buttonType: 'icon' | 'text' = 'icon';
|
||||
@Input() buttonText: string = 'Ejecutar Comandos';
|
||||
@Input() icon: string = 'terminal';
|
||||
@Input() disabled: boolean = false;
|
||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
loading: boolean = true;
|
||||
|
||||
|
|
|
@ -328,12 +328,6 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.clients-container {
|
||||
width: 75%;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.client-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
@ -378,13 +372,6 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
color: #666;
|
||||
}
|
||||
|
||||
.clients-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
gap: 4px;
|
||||
/* Espaciado reducido entre cards */
|
||||
}
|
||||
|
||||
.clients-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -405,15 +392,6 @@ mat-tree mat-tree-node.disabled:hover {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.clients-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
/* 6 columnas por fila */
|
||||
gap: 16px;
|
||||
/* Espaciado entre tarjetas */
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.clients-list .list-item-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
@ -568,4 +546,24 @@ mat-button-toggle-group {
|
|||
|
||||
.mat-button-toggle-group .mat-button-toggle.mat-button-toggle-disabled {
|
||||
background-color: #c7c7c7;
|
||||
}
|
||||
|
||||
.clients-container {
|
||||
width: 75%;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.cards-view {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.clients-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 8px 20px 20px 20px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -171,8 +171,8 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="view-type-container">
|
||||
<app-execute-command [clientData]="arrayClients" [buttonType]="'text'"
|
||||
[buttonText]="'Ejecutar comandos'"></app-execute-command>
|
||||
<app-execute-command [clientData]="selection.selected" [buttonType]="'text'"
|
||||
[buttonText]="'Ejecutar comandos'" [disabled]="selection.selected.length === 0"></app-execute-command>
|
||||
<mat-button-toggle-group name="viewType" aria-label="View Type" [hideSingleSelectionIndicator]="true"
|
||||
(change)="toggleView($event.value)">
|
||||
<mat-button-toggle value="list" [disabled]="currentView === 'list'">
|
||||
|
@ -190,55 +190,63 @@
|
|||
<div *ngIf="!isLoadingClients">
|
||||
<div *ngIf="hasClients; else noClientsTemplate">
|
||||
<!-- Cards view -->
|
||||
<div class="clients-grid" *ngIf="currentView === 'card'">
|
||||
<div *ngFor="let client of arrayClients" class="client-item">
|
||||
<div class="client-card">
|
||||
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(client)"
|
||||
[checked]="selection.isSelected(client)" [disabled]="client.status === 'busy'">
|
||||
</mat-checkbox>
|
||||
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
|
||||
class="client-image" />
|
||||
<div *ngIf="currentView === 'card'" class="cards-view">
|
||||
<mat-checkbox (change)="toggleAllCards()" [checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()" style="margin-left: 1em; margin-top: 0.5rem;">
|
||||
</mat-checkbox>
|
||||
<div class="clients-grid">
|
||||
<div *ngFor="let client of arrayClients" class="client-item">
|
||||
<div class="client-card">
|
||||
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(client)"
|
||||
[checked]="selection.isSelected(client)" [disabled]="client.status === 'busy'">
|
||||
</mat-checkbox>
|
||||
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
|
||||
class="client-image" />
|
||||
|
||||
<div class="client-details">
|
||||
<span class="client-name">{{ client.name }}</span>
|
||||
<span class="client-ip">{{ client.ip }}</span>
|
||||
<span class="client-ip">{{ client.mac }}</span>
|
||||
<div class="action-icons">
|
||||
<button *ngIf="(!syncStatus || syncingClientId !== client.uuid)" mat-icon-button color="primary"
|
||||
(click)="getStatus(client, selectedNode)">
|
||||
<mat-icon>sync</mat-icon>
|
||||
</button>
|
||||
|
||||
<button *ngIf="syncStatus && syncingClientId === client.uuid" mat-icon-button color="primary">
|
||||
<mat-spinner diameter="24"></mat-spinner>
|
||||
</button>
|
||||
|
||||
<app-execute-command [clientData]="[client]" [buttonType]="'icon'"
|
||||
[icon]="'terminal'"></app-execute-command>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>{{ 'edit' | translate }}</span>
|
||||
<div class="client-details">
|
||||
<span class="client-name">{{ client.name }}</span>
|
||||
<span class="client-ip">{{ client.ip }}</span>
|
||||
<span class="client-ip">{{ client.mac }}</span>
|
||||
<div class="action-icons">
|
||||
<button *ngIf="(!syncStatus || syncingClientId !== client.uuid)" mat-icon-button color="primary"
|
||||
(click)="getStatus(client, selectedNode)">
|
||||
<mat-icon>sync</mat-icon>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>{{ 'viewDetails' | translate }}</span>
|
||||
|
||||
<button *ngIf="syncStatus && syncingClientId === client.uuid" mat-icon-button color="primary">
|
||||
<mat-spinner diameter="24"></mat-spinner>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'delete' | translate }}</span>
|
||||
|
||||
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
|
||||
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
|
||||
|
||||
<button
|
||||
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
|
||||
mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>{{ 'edit' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>{{ 'viewDetails' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'delete' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List view -->
|
||||
<div class="clients-table" *ngIf="currentView === 'list'">
|
||||
<table mat-table matSort [dataSource]="selectedClients" class="mat-elevation-z8">
|
||||
|
@ -314,11 +322,13 @@
|
|||
<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" color="primary">
|
||||
<button
|
||||
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
|
||||
mat-icon-button [matMenuTriggerFor]="clientMenu" color="primary">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<app-execute-command [clientData]="[client]" [buttonType]="'icon'"
|
||||
[icon]="'terminal'"></app-execute-command>
|
||||
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
|
||||
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
|
@ -244,7 +244,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
|
||||
private refreshData(selectedNodeIdOrUuid?: string): void {
|
||||
private refreshData(selectedNodeIdOrUuid?: string, selectedClientsBeforeEdit: string[] = []): void {
|
||||
this.dataService.getOrganizationalUnits().subscribe({
|
||||
next: (data) => {
|
||||
this.originalTreeData = data.map((unidad) => this.convertToTreeData(unidad));
|
||||
|
@ -255,13 +255,13 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
if (this.selectedNode) {
|
||||
this.treeControl.collapseAll();
|
||||
this.expandPathToNode(this.selectedNode);
|
||||
this.fetchClientsForNode(this.selectedNode);
|
||||
this.fetchClientsForNode(this.selectedNode, selectedClientsBeforeEdit);
|
||||
}
|
||||
} else {
|
||||
this.treeControl.collapseAll();
|
||||
if (this.treeDataSource.data.length > 0) {
|
||||
this.selectedNode = this.treeDataSource.data[0];
|
||||
this.fetchClientsForNode(this.selectedNode);
|
||||
this.fetchClientsForNode(this.selectedNode, selectedClientsBeforeEdit);
|
||||
} else {
|
||||
this.selectedNode = null;
|
||||
this.selectedClients.data = [];
|
||||
|
@ -333,7 +333,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
|
||||
public fetchClientsForNode(node: TreeNode): void {
|
||||
public fetchClientsForNode(node: TreeNode, selectedClientsBeforeEdit: string[] = []): void {
|
||||
this.isLoadingClients = true;
|
||||
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${node.id}`).subscribe({
|
||||
next: (response) => {
|
||||
|
@ -342,6 +342,13 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
this.hasClients = node.hasClients ?? false;
|
||||
this.isLoadingClients = false;
|
||||
this.initialLoading = false;
|
||||
this.selection.clear();
|
||||
selectedClientsBeforeEdit.forEach(uuid => {
|
||||
const client = this.selectedClients.data.find(client => client.uuid === uuid);
|
||||
if (client) {
|
||||
this.selection.select(client);
|
||||
}
|
||||
});
|
||||
},
|
||||
error: () => {
|
||||
this.isLoadingClients = false;
|
||||
|
@ -483,12 +490,13 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
|
||||
onEditClick(event: MouseEvent, type: string, uuid: string): void {
|
||||
event.stopPropagation();
|
||||
const selectedClientsBeforeEdit = this.selection.selected.map(client => client.uuid);
|
||||
const dialogRef = type !== NodeType.Client
|
||||
? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' })
|
||||
: this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' });
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
this.refreshData(this.selectedNode?.id);
|
||||
this.refreshData(this.selectedNode?.id, selectedClientsBeforeEdit);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -668,12 +676,19 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
toggleAllRows() {
|
||||
if (this.isAllSelected()) {
|
||||
this.selection.clear();
|
||||
this.arrayClients = []
|
||||
return;
|
||||
} else {
|
||||
this.selection.select(...this.selectedClients.data);
|
||||
}
|
||||
this.updateSelectedClients();
|
||||
}
|
||||
|
||||
this.selection.select(...this.selectedClients.data);
|
||||
this.arrayClients = [...this.selection.selected];
|
||||
toggleAllCards() {
|
||||
if (this.isAllSelected()) {
|
||||
this.selection.clear();
|
||||
} else {
|
||||
this.selection.select(...this.selectedClients.data);
|
||||
}
|
||||
this.updateSelectedClients();
|
||||
}
|
||||
|
||||
|
||||
|
@ -684,7 +699,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
|
||||
|
||||
updateSelectedClients() {
|
||||
this.arrayClients = [...this.selection.selected];
|
||||
this.arrayClients = this.selectedClients.data;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue