From ebc09f8ca55fbf505f7a8134128b6353e5037281 Mon Sep 17 00:00:00 2001 From: jmbardallo Date: Mon, 27 Jul 2026 13:55:00 +0200 Subject: [PATCH] Refactor client action menu to use shared matMenuContent --- CHANGELOG.md | 10 +- .../components/groups/groups.component.html | 1127 ++++++++--------- .../client-pending-tasks.component.ts | 2 +- .../client-task-logs.component.ts | 2 +- .../task-logs/task-logs.component.ts | 2 +- 5 files changed, 570 insertions(+), 573 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebdee3..046d622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [1.8.2] - 2026-07-27 + +### Fixed +- Menú de opciones de cliente (`groups.component.html`): Unificado el menú de acciones (tres puntos verticales) usando `matMenuContent`. Se elimina la duplicidad de código que causaba divergencias de comportamiento entre la vista tarjeta y la vista lista. Ahora la opción de "Logs en tiempo real" está siempre disponible en ambas vistas, al igual que los bloqueos al sincronizar. +- Detalles de tareas (`OutputDialogComponent`): Ampliado el ancho de la ventana modal de detalles a `70vw` para facilitar la lectura de trazas largas y comandos de OGAgent/OGLive. + ## [1.8.1] - 2026-07-17 ### Added @@ -9,8 +15,8 @@ - Modal de partición de arranque (`boot-so-partition`): Refactorizado para usar el componente compartido `app-disk-partition-selector`, eliminando código duplicado y unificando el diseño y comportamiento de la selección de discos y particiones con el resto de modales. ### Fixed -- Detalles de tareas (`OutputDialogComponent`): Corregido el formateo de los detalles mostrados desde los agentes (OGAgent) para renderizar el texto en crudo sin el parseo estricto JSON, lo cual causaba que los saltos de línea (`\n`) se vieran de forma literal (`\r\n\r\n`). -- Formulario de despliegue (`Deploy Image`): Solucionado el problema que ocultaba las instrucciones (comandos) cuando el despliegue era en modo caché. Refactorizado todo el HTML del componente para utilizar la nueva sintaxis de control de flujo de Angular (`@if`, `@for`). +- Detalles de tareas (`OutputDialogComponent`): Corregido el formateo de los detalles mostrados desde los agentes (OGAgent) para renderizar el texto en crudo manteniendo los saltos de línea (usando pre-wrap por CSS y
 tag), y dándole formato monoespaciado en lugar de intentar forzar un parseo estricto JSON que rompía la salida de comandos.
+- Formulario de despliegue (`Deploy Image`): Solucionado el problema que ocultaba las comandos (instructions) cuando el despliegue era en modo caché. El código ha sido refactorizado y limpiado usando directivas estructurales estándar de Angular (`*ngIf`, `*ngFor`).
 - Roles: Permisos actualizados en vistas para reflejar recientes cambios de backend en la gestión de perfiles de software.
 
 ## [1.8.0] - 2026-06-16
diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html
index b4e1424..7252db4 100644
--- a/ogWebconsole/src/app/components/groups/groups.component.html
+++ b/ogWebconsole/src/app/components/groups/groups.component.html
@@ -1,5 +1,5 @@
-
 
 
@@ -16,19 +16,23 @@
     
     
- - + } + @if (auth.userCategory !== 'ou-minimal') { + + } + }}
- - - - - - + + + + + + +
+ } + + + @if (initialLoading) { +
+
- - -
- -
- - - + } @else {
-
-
@@ -77,33 +80,40 @@ {{ 'searchTree' | translate }} - + @if (treeSearchInput.value) { + + } {{ 'searchClient' | translate }} - + @if (clientSearchInput.value) { + + } - - {{ option.name }} - + @for (option of status; track option) { + + {{ option.name }} + + } - + @if (clientSearchStatusInput.value) { + + } -
- +
+
+ +
+
+

+ account_tree + {{ 'organizationalStructure' | translate }} +

+
+ +
- - -
-
-

- account_tree - {{ 'organizationalStructure' | translate }} -

-
- - +
+
+ + {{ + node.type === 'organizational-unit' ? 'business' + : node.type === 'classrooms-group' ? 'meeting_room' + : node.type === 'classroom' ? 'school' + : node.type === 'clients-group' ? 'dns' + : node.type === 'client' ? 'computer' + : 'folder' + }} + + {{ node.name }} +
+
+ @if (node.type === 'client') { + {{ node.ip }} + } + @if (node.children && node.children.length > 0) { + {{ node.children.length }} {{ getNodeCountLabel(node.children.length) }} + } +
+
+
+ +
-
- - - - -
- - -
-
- - {{ - node.type === 'organizational-unit' ? 'business' - : node.type === 'classrooms-group' ? 'meeting_room' - : node.type === 'classroom' ? 'school' - : node.type === 'clients-group' ? 'dns' - : node.type === 'client' ? 'computer' - : 'folder' - }} - - {{ node.name }} -
- -
- - {{ node.ip }} - - - {{ node.children.length }} {{ getNodeCountLabel(node.children.length) }} - -
+ + +
+ +
+
+ + {{ + node.type === 'organizational-unit' ? 'business' + : node.type === 'classrooms-group' ? 'meeting_room' + : node.type === 'classroom' ? 'school' + : node.type === 'clients-group' ? 'dns' + : node.type === 'client' ? 'computer' + : 'folder' + }} + + {{ node.name }}
- -
- +
+ @if (node.type === 'client') { + {{ node.ip }} + {{ node.mac }} + + {{ getStatusLabel(node.status) }} + + }
- - - - -
- - -
-
- - {{ - node.type === 'organizational-unit' ? 'business' - : node.type === 'classrooms-group' ? 'meeting_room' - : node.type === 'classroom' ? 'school' - : node.type === 'clients-group' ? 'dns' - : node.type === 'client' ? 'computer' - : 'folder' - }} - - {{ node.name }} -
- -
- - {{ node.ip }} - {{ node.mac }} - - {{ getStatusLabel(node.status) }} - - -
-
- -
- -
-
- -
- - - -
+
+ +
+ + + @for (command of commands; track command) { + - - - - + @if (selectedNode?.type === 'classroom') { + - - - - - - - - - - -
- - - - -
- - -
- - {{ 'labelClients' | translate }} - {{ selectedNode?.name }} - -
- + storage + {{ 'partitions' | translate }} + + + + + +
+ + +
+ + +
+ + {{ 'labelClients' | translate }} + {{ selectedNode?.name }} + +
+ @if (currentView === 'card') { + - - -
- -
- - +
+ +
+ @if (classroomCalendarUuid && !syncingUds) { + - - - - - - - list {{ 'vistalista' | translate }} - - - grid_view {{ 'vistatarjeta' | translate }} - - -
+ delete + + + + list {{ 'vistalista' | translate }} + + + grid_view {{ 'vistatarjeta' | translate }} + +
- - - - -
+ + + @if (!isLoadingClients) { +
-
- -
-
-
- computer -
-
-
{{ totalStats.total }}
-
{{ 'totalClients' | translate }}
-
-
-
-
- wifi_off -
-
-
{{ getStatusCount('off') }}
-
{{ 'offline' | translate }}
-
-
-
-
- wifi -
-
-
{{ getStatusCount('og-live') + getStatusCount('linux') + getStatusCount('windows') }}
-
{{ 'online' | translate }}
-
-
-
-
- hourglass_empty -
-
-
{{ getStatusCount('busy') }}
-
{{ 'busy' | translate }}
-
-
-
- - -
-
-
-
-
- - - Client Icon - -
- {{ client.name }} - {{ client.ip }} - {{ client.mac }} - - computer - RemotePC - -
- - - - - - - - - - - - - - - - - - - - -
-
+ @if (hasClients) { +
+ @if (currentView === 'list') { +
+
+
+ computer +
+
+
{{ totalStats.total }}
+
{{ 'totalClients' | translate }}
+
+
+
+
+ wifi_off +
+
+
{{ getStatusCount('off') }}
+
{{ 'offline' | translate }}
+
+
+
+
+ wifi +
+
+
{{ getStatusCount('og-live') + getStatusCount('linux') + getStatusCount('windows') }}
+
{{ 'online' | translate }}
+
+
+
+
+ hourglass_empty +
+
+
{{ getStatusCount('busy') }}
+
{{ 'busy' | translate }}
-
-
- - -
-
- - -
-
-
- {{ 'showingResults' | translate: { from: getPaginationFrom(), to: getPaginationTo(), total: getPaginationTotal() } }} + } + + @if (currentView === 'card') { +
+
+
+ @for (client of arrayClients; track client) { +
+
+ + + Client Icon +
+ {{ client.name }} + {{ client.ip }} + {{ client.mac }} + @if (client.isRemotePcActive) { + + computer + RemotePC + + } +
+ + + + + + @if (syncingClientIds.has(client.uuid)) { + + + + } +
+
+
+
+ } +
+
+
+ + +
-
- - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @if (currentView === 'list') { +
+
+
+ {{ 'showingResults' | translate: { from: getPaginationFrom(), to: getPaginationTo(), total: getPaginationTotal() } }} +
+
+ + +
+
+
+
- - - - - - -
- {{ 'labelState' | translate }} - -
-
-
- Client Icon - - - -
-
-
- {{ 'name' | translate }} - -
-
-
- {{ client.name }} -
-
-
- {{ 'labelIpCaps' | translate }} - -
-
-
- {{ client.ip }} - {{ client.mac }} -
-
-
- {{ 'firmwareType' | translate }} - -
-
- - {{ client.firmwareType }} - - {{ 'ogLiveTitle' | translate }} -
- {{ client.ogLive?.kernel }} - {{ client.ogLive?.date | date }} -
-
{{ 'maintenance' | translate }} {{ client.maintenance }} {{ 'subnet' | translate }} {{ client.subnet }} {{ 'pxeTemplate' | translate }} {{ client.pxeTemplate?.name }} {{ 'labelEditOrgUnitParent' | translate }} {{ client.parentName }} {{ 'actions' | translate }} -
- - - - -
- - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
+ + + + + + +
+ {{ 'labelState' | translate }} + +
+
+
+ Client Icon + @if (syncingClientIds.has(client.uuid)) { + + + + } +
+
+
+ {{ 'name' | translate }} + +
+
+
+ {{ client.name }} +
+
+
+ {{ 'labelIpCaps' | translate }} + +
+
+
+ {{ client.ip }} + {{ client.mac }} +
+
+
+ {{ 'firmwareType' | translate }} + +
+
+ @if (client.firmwareType) { + + {{ client.firmwareType }} + + } + {{ 'ogLiveTitle' | translate }} +
+ {{ client.ogLive?.kernel }} + {{ client.ogLive?.date | date }} +
+
{{ 'maintenance' | translate }} {{ client.maintenance }} {{ 'subnet' | translate }} {{ client.subnet }} {{ 'pxeTemplate' | translate }} {{ client.pxeTemplate?.name }} {{ 'labelEditOrgUnitParent' | translate }} {{ client.parentName }} {{ 'actions' | translate }} +
+ + + + + + + +
+
-
- - + + + + +
+ }
- -
- + } @else { + @if (!initialLoading) { +
+ {{ 'noClients' | translate }} + error_outline +
+ } + } - -
- {{ 'noClients' | translate }} - error_outline -
-
-
- + }
- +
+} + +
+ + + + @if (auth.userCategory !== 'ou-minimal') { + + } + + @if (!syncingClientIds.has(client.uuid)) { + + } + + + + + + @if (auth.userCategory !== 'ou-minimal') { + + } + + + diff --git a/ogWebconsole/src/app/components/task-logs/client-pending-tasks/client-pending-tasks.component.ts b/ogWebconsole/src/app/components/task-logs/client-pending-tasks/client-pending-tasks.component.ts index 0eba079..b6d5d32 100644 --- a/ogWebconsole/src/app/components/task-logs/client-pending-tasks/client-pending-tasks.component.ts +++ b/ogWebconsole/src/app/components/task-logs/client-pending-tasks/client-pending-tasks.component.ts @@ -240,7 +240,7 @@ export class ClientPendingTasksComponent implements OnInit { openOutputModal(outputData: any): void { this.dialog.open(OutputDialogComponent, { - width: '500px', + width: '70vw', data: { input: outputData } }); } diff --git a/ogWebconsole/src/app/components/task-logs/client-task-logs/client-task-logs.component.ts b/ogWebconsole/src/app/components/task-logs/client-task-logs/client-task-logs.component.ts index ef40cda..ec9390a 100644 --- a/ogWebconsole/src/app/components/task-logs/client-task-logs/client-task-logs.component.ts +++ b/ogWebconsole/src/app/components/task-logs/client-task-logs/client-task-logs.component.ts @@ -172,7 +172,7 @@ export class ClientTaskLogsComponent implements OnInit { openOutputModal(outputData: any): void { this.dialog.open(OutputDialogComponent, { - width: '500px', + width: '70vw', data: { input: outputData } }); } diff --git a/ogWebconsole/src/app/components/task-logs/task-logs.component.ts b/ogWebconsole/src/app/components/task-logs/task-logs.component.ts index 36da5b0..1ad1bcb 100644 --- a/ogWebconsole/src/app/components/task-logs/task-logs.component.ts +++ b/ogWebconsole/src/app/components/task-logs/task-logs.component.ts @@ -499,7 +499,7 @@ export class TaskLogsComponent implements OnInit, OnDestroy { openOutputModal(outputData: any): void { this.dialog.open(OutputDialogComponent, { - width: '500px', + width: '70vw', data: { input: outputData } }); }