From b4a389e5bdbff8b831dd7ba4cec16e01d48bbbf6 Mon Sep 17 00:00:00 2001 From: llara Date: Tue, 18 Feb 2025 14:16:52 +0100 Subject: [PATCH 01/38] refs #1529. Refactor task logs component: enhance client fetching logic with forkJoin for better performance --- .../task-logs/task-logs.component.html | 7 +++--- .../task-logs/task-logs.component.ts | 25 +++++++++++++++---- ogWebconsole/src/locale/en.json | 4 +-- ogWebconsole/src/locale/es.json | 4 +-- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html index d49b789..9d1a425 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html @@ -20,7 +20,7 @@ + placeholder="{{ 'filterClientPlaceholder' | translate }}"> @@ -32,7 +32,7 @@ + placeholder="{{ 'filterCommandPlaceholder' | translate }}"> @@ -44,6 +44,7 @@ Estado + Todos Fallido Pendiente de ejecutar Ejecutando @@ -115,4 +116,4 @@ - + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts index f991704..07be884 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; +import { Observable, forkJoin } from 'rxjs'; import { FormControl } from '@angular/forms'; import { map, startWith } from 'rxjs/operators'; import { DatePipe } from '@angular/common'; @@ -144,7 +144,11 @@ export class TaskLogsComponent implements OnInit { loadTraces(): void { this.loading = true; const url = `${this.baseUrl}/traces?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}`; - this.http.get(url, { params: this.filters }).subscribe( + const params = { ...this.filters }; + if (params['status'] === undefined) { + delete params['status']; + } + this.http.get(url, { params }).subscribe( (data) => { this.traces = data['hydra:member']; this.length = data['hydra:totalItems']; @@ -163,6 +167,7 @@ export class TaskLogsComponent implements OnInit { this.http.get(`${this.baseUrl}/commands?&page=1&itemsPerPage=10000`).subscribe( response => { this.commands = response['hydra:member']; + console.log(this.commands); this.loading = false; }, error => { @@ -176,10 +181,20 @@ export class TaskLogsComponent implements OnInit { this.loading = true; this.http.get(`${this.baseUrl}/clients?&page=1&itemsPerPage=10000`).subscribe( response => { - this.clients = response['hydra:member']; - this.loading = false; + const clientIds = response['hydra:member'].map((client: any) => client['@id']); + const clientDetailsRequests: Observable[] = clientIds.map((id: string) => this.http.get(`${this.baseUrl}${id}`)); + forkJoin(clientDetailsRequests).subscribe( + (clients: any[]) => { + this.clients = clients; + this.loading = false; + }, + (error: any) => { + console.error('Error fetching client details:', error); + this.loading = false; + } + ); }, - error => { + (error: any) => { console.error('Error fetching clients:', error); this.loading = false; } diff --git a/ogWebconsole/src/locale/en.json b/ogWebconsole/src/locale/en.json index 1b4d204..1ccfd67 100644 --- a/ogWebconsole/src/locale/en.json +++ b/ogWebconsole/src/locale/en.json @@ -99,9 +99,9 @@ "resetFiltersStepText": "Click to reset the applied filters and see all traces.", "resetFilters": "Reset filters", "clientSelectStepText": "Select a client to see the associated traces.", - "selectClientPlaceholder": "Select a client", + "filterClientPlaceholder": "Filter by client", "commandSelectStepText": "Select a command to see the specific traces of that command.", - "selectCommandPlaceholder": "Select a command", + "filterCommandPlaceholder": "Filter by command", "taskDetailsTitle": "Task Details", "taskId": "Task ID", "status": "Status", diff --git a/ogWebconsole/src/locale/es.json b/ogWebconsole/src/locale/es.json index 1a1e13f..4028d0f 100644 --- a/ogWebconsole/src/locale/es.json +++ b/ogWebconsole/src/locale/es.json @@ -100,9 +100,9 @@ "resetFiltersStepText": "Haz clic para reiniciar los filtros aplicados y ver todas las trazas.", "resetFilters": "Reiniciar filtros", "clientSelectStepText": "Selecciona un cliente para ver las trazas asociadas.", - "selectClientPlaceholder": "Seleccione un cliente", + "filterClientPlaceholder": "Filtrar por cliente", "commandSelectStepText": "Selecciona un comando para ver las trazas específicas de ese comando.", - "selectCommandPlaceholder": "Seleccione un comando", + "filterCommandPlaceholder": "Filtrar por comando", "taskDetailsTitle": "Detalles de la Tarea", "taskId": "ID de la Tarea", "status": "Estado", From 37aff33b11e9337dbf4bd5e7492af30db95c4810 Mon Sep 17 00:00:00 2001 From: llara Date: Wed, 19 Feb 2025 16:26:12 +0100 Subject: [PATCH 02/38] refs #1551 Apply global button styles to all components --- .../app/components/admin/admin.component.css | 10 -- .../app/components/admin/admin.component.html | 4 +- .../components/admin/admin.component.spec.ts | 9 -- .../admin/env-vars/env-vars.component.css | 4 - .../admin/env-vars/env-vars.component.html | 4 +- .../add-role-modal.component.css | 14 +- .../add-role-modal.component.html | 6 +- .../admin/roles/roles/roles.component.html | 2 +- .../add-user-modal.component.css | 36 ++---- .../add-user-modal.component.html | 6 +- .../change-password-modal.component.css | 11 +- .../change-password-modal.component.html | 8 +- .../admin/users/users/users.component.html | 2 +- .../calendar/calendar.component.html | 4 +- .../components/calendar/calendar.component.ts | 2 +- .../create-calendar-rule.component.css | 7 + .../create-calendar-rule.component.html | 6 +- .../create-calendar.component.css | 11 +- .../create-calendar.component.html | 8 +- .../commands-groups.component.html | 4 +- .../create-command-group.component.css | 7 + .../create-command-group.component.html | 6 +- .../detail-command-group.component.css | 29 +---- .../detail-command-group.component.html | 8 +- .../commands-task.component.html | 2 +- .../create-task/create-task.component.css | 1 + .../create-task/create-task.component.html | 13 +- .../detail-task/detail-task.component.css | 22 ---- .../detail-task/detail-task.component.html | 2 +- .../input-dialog/input-dialog.component.html | 2 +- .../task-logs/task-logs.component.html | 2 +- .../main-commands/commands.component.html | 2 +- .../create-command.component.css | 12 +- .../create-command.component.html | 6 +- .../execute-command.component.html | 2 +- .../execute-command.component.ts | 6 - .../components/groups/groups.component.css | 37 ++---- .../components/groups/groups.component.html | 11 +- .../create-client.component.html | 4 +- .../manage-organizational-unit.component.css | 6 - .../manage-organizational-unit.component.html | 4 +- .../app/layout/header/header.component.css | 53 +++++--- .../app/layout/header/header.component.html | 49 ++++--- ogWebconsole/src/styles.css | 120 +++++++++++++----- 44 files changed, 283 insertions(+), 281 deletions(-) diff --git a/ogWebconsole/src/app/components/admin/admin.component.css b/ogWebconsole/src/app/components/admin/admin.component.css index 30a016d..8c90c1c 100644 --- a/ogWebconsole/src/app/components/admin/admin.component.css +++ b/ogWebconsole/src/app/components/admin/admin.component.css @@ -14,16 +14,6 @@ margin: 0 10px; } -/* Estilos de los botones */ -button { - height: 150px; - width: 150px; - margin: 5px; - padding: 5px; - cursor: pointer; - transition: all 0.3s; -} - /* Estilos del texto debajo de los botones */ span{ margin: 0; diff --git a/ogWebconsole/src/app/components/admin/admin.component.html b/ogWebconsole/src/app/components/admin/admin.component.html index cf2f0aa..bf2ca78 100644 --- a/ogWebconsole/src/app/components/admin/admin.component.html +++ b/ogWebconsole/src/app/components/admin/admin.component.html @@ -1,9 +1,9 @@
- - diff --git a/ogWebconsole/src/app/components/admin/admin.component.spec.ts b/ogWebconsole/src/app/components/admin/admin.component.spec.ts index 5bd5fe2..2ed2fec 100644 --- a/ogWebconsole/src/app/components/admin/admin.component.spec.ts +++ b/ogWebconsole/src/app/components/admin/admin.component.spec.ts @@ -45,13 +45,4 @@ describe('AdminComponent', () => { expect(button).toBeTruthy(); expect(button.querySelector('mat-icon').textContent.trim()).toBe('group'); }); - - - it('debería aplicar la clase "fab-button" a ambos botones', () => { - const buttons = fixture.nativeElement.querySelectorAll('button'); - buttons.forEach((button: HTMLElement) => { - expect(button.classList).toContain('fab-button'); - }); - }); - }); diff --git a/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.css b/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.css index 5dd7cdc..01287db 100644 --- a/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.css +++ b/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.css @@ -15,10 +15,6 @@ gap: 16px; justify-content: flex-end; margin-top: 16px; - - button { - min-width: 120px; - } } } diff --git a/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.html b/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.html index 47e71b8..f4fbbc0 100644 --- a/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.html +++ b/ogWebconsole/src/app/components/admin/env-vars/env-vars.component.html @@ -27,7 +27,7 @@
- - + +
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.css b/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.css index 13e2689..a4b2450 100644 --- a/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.css +++ b/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.css @@ -1,7 +1,9 @@ .full-width { width: 100%; } + .form-container { + margin-top: 2em; padding: 40px; } @@ -15,16 +17,24 @@ margin-bottom: 16px; } -.checkbox-group { +.checkbox-group { margin: 15px 0; align-items: flex-start; } .time-fields { display: flex; - gap: 15px; /* Espacio entre los campos */ + gap: 15px; + /* Espacio entre los campos */ } .time-field { flex: 1; } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.html b/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.html index 7fbef12..7a03e84 100644 --- a/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.html +++ b/ogWebconsole/src/app/components/admin/roles/roles/add-role-modal/add-role-modal.component.html @@ -16,7 +16,7 @@ - - - + + + diff --git a/ogWebconsole/src/app/components/admin/roles/roles/roles.component.html b/ogWebconsole/src/app/components/admin/roles/roles/roles.component.html index d5070fb..183d4ff 100644 --- a/ogWebconsole/src/app/components/admin/roles/roles/roles.component.html +++ b/ogWebconsole/src/app/components/admin/roles/roles/roles.component.html @@ -3,7 +3,7 @@

{{ 'adminRolesTitle' | translate }}

-
diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.css b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.css index 13e2689..2d45e90 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.css +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.css @@ -1,30 +1,12 @@ -.full-width { - width: 100%; -} -.form-container { - padding: 40px; -} - -.form-group { - margin-top: 20px; - margin-bottom: 26px; -} - -.full-width { - width: 100%; - margin-bottom: 16px; -} - -.checkbox-group { - margin: 15px 0; - align-items: flex-start; -} - -.time-fields { +.user-form { display: flex; - gap: 15px; /* Espacio entre los campos */ + flex-direction: column; + margin-top: 2rem; } -.time-field { - flex: 1; -} +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html index ad9efdb..b8cee9e 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html @@ -29,7 +29,7 @@
- - - + + + diff --git a/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.css b/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.css index 8aefe41..d37ba39 100644 --- a/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.css +++ b/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.css @@ -1,6 +1,6 @@ .user-form .form-field { - display: block; - margin-bottom: 10px; + display: block; + margin-bottom: 10px; } .checkbox-group label { @@ -17,3 +17,10 @@ mat-spinner { margin: 0 auto; align-self: center; } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.html b/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.html index 17a0805..0a3aac7 100644 --- a/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.html +++ b/ogWebconsole/src/app/components/admin/users/users/change-password-modal/change-password-modal.component.html @@ -23,7 +23,7 @@ - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/admin/users/users/users.component.html b/ogWebconsole/src/app/components/admin/users/users/users.component.html index 7c2ccee..a1cd0ac 100644 --- a/ogWebconsole/src/app/components/admin/users/users/users.component.html +++ b/ogWebconsole/src/app/components/admin/users/users/users.component.html @@ -3,7 +3,7 @@

{{ 'adminUsersTitle' | translate }}

-
diff --git a/ogWebconsole/src/app/components/calendar/calendar.component.html b/ogWebconsole/src/app/components/calendar/calendar.component.html index d057115..706f2f4 100644 --- a/ogWebconsole/src/app/components/calendar/calendar.component.html +++ b/ogWebconsole/src/app/components/calendar/calendar.component.html @@ -6,8 +6,8 @@

{{ 'adminCalendarsTitle' | translate }}

-
diff --git a/ogWebconsole/src/app/components/calendar/calendar.component.ts b/ogWebconsole/src/app/components/calendar/calendar.component.ts index cbfb249..c24d9ea 100644 --- a/ogWebconsole/src/app/components/calendar/calendar.component.ts +++ b/ogWebconsole/src/app/components/calendar/calendar.component.ts @@ -66,7 +66,7 @@ export class CalendarComponent implements OnInit { this.search(); } - addImage(): void { + addCalendar(): void { const dialogRef = this.dialog.open(CreateCalendarComponent, { width: '400px' }); diff --git a/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.css b/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.css index 13e2689..2f3d78a 100644 --- a/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.css +++ b/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.css @@ -28,3 +28,10 @@ .time-field { flex: 1; } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html b/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html index 9fb31c2..b1de852 100644 --- a/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html +++ b/ogWebconsole/src/app/components/calendar/create-calendar-rule/create-calendar-rule.component.html @@ -56,10 +56,10 @@ - - + + @@ -41,9 +41,9 @@ - - - + diff --git a/ogWebconsole/src/app/components/commands/commands-groups/commands-groups.component.html b/ogWebconsole/src/app/components/commands/commands-groups/commands-groups.component.html index 80d6d4b..3092715 100644 --- a/ogWebconsole/src/app/components/commands/commands-groups/commands-groups.component.html +++ b/ogWebconsole/src/app/components/commands/commands-groups/commands-groups.component.html @@ -6,7 +6,7 @@

{{ 'adminCommandGroupsTitle' | translate }}

-
@@ -35,7 +35,7 @@ - + - + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.css b/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.css index dd408ba..6d252df 100644 --- a/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.css +++ b/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.css @@ -58,19 +58,6 @@ padding: 10px 20px; } - button { - background-color: #3f51b5; /* Color primario */ - color: white; - padding: 10px 15px; - border: none; - border-radius: 4px; - cursor: pointer; - } - - button:hover { - background-color: #2c387e; /* Color primario oscuro */ - } - @media (max-width: 600px) { .mat-card { margin: 10px 0; @@ -86,15 +73,6 @@ } } - .cancel-button { - background-color: #dc3545; - color: white; - border-radius: 5px; - } - .cancel-button:hover { - opacity: 0.9; - } - .create-command-group-container { padding: 20px; } @@ -146,8 +124,9 @@ color: #666; } - .command-group-actions { - margin-top: 20px; + .action-container { display: flex; - justify-content: space-between; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; } diff --git a/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.html b/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.html index c8edddb..c3c7c7a 100644 --- a/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.html +++ b/ogWebconsole/src/app/components/commands/commands-groups/detail-command-group/detail-command-group.component.html @@ -49,10 +49,10 @@ -
- + -
- + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/commands/commands-task/commands-task.component.html b/ogWebconsole/src/app/components/commands/commands-task/commands-task.component.html index a3a6ccc..86f3f8e 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/commands-task.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/commands-task.component.html @@ -6,7 +6,7 @@

{{ 'manageTasksTitle' | translate }}

-
diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.css b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.css index 3c41e87..b69339e 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.css +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.css @@ -14,6 +14,7 @@ display: flex; justify-content: flex-end; margin-top: 20px; + padding: 1.5rem; } mat-form-field { diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html index 8e5fdca..9d5b756 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task/create-task.component.html @@ -87,10 +87,6 @@
-
- -
- Selecciona Clientes @@ -102,10 +98,9 @@
- -
- -
- + +
+ +
diff --git a/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.css b/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.css index dce95aa..cabeb18 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.css +++ b/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.css @@ -57,26 +57,4 @@ justify-content: flex-end; padding: 10px 20px; } - - button { - background-color: #3f51b5; - color: white; - padding: 10px 15px; - border: none; - border-radius: 4px; - cursor: pointer; - } - - button:hover { - background-color: #2c387e; - } - - .cancel-button { - background-color: #dc3545; - color: white; - } - - .cancel-button:hover { - opacity: 0.9; - } \ No newline at end of file diff --git a/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.html b/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.html index 940cf2c..4217141 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/detail-task/detail-task.component.html @@ -50,6 +50,6 @@
- +
diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/input-dialog/input-dialog.component.html b/ogWebconsole/src/app/components/commands/commands-task/task-logs/input-dialog/input-dialog.component.html index e12c176..eed69e9 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/input-dialog/input-dialog.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/input-dialog/input-dialog.component.html @@ -3,5 +3,5 @@
{{ data.input | json }}
- +
diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html index 9d1a425..8990735 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html @@ -9,7 +9,7 @@
- diff --git a/ogWebconsole/src/app/components/commands/main-commands/commands.component.html b/ogWebconsole/src/app/components/commands/main-commands/commands.component.html index e92aee1..6aa5914 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/commands.component.html +++ b/ogWebconsole/src/app/components/commands/main-commands/commands.component.html @@ -6,7 +6,7 @@

{{ 'CommandsTitle' | translate }}

- +
diff --git a/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.css b/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.css index aefc820..c45022f 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.css +++ b/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.css @@ -7,12 +7,6 @@ .form-group { margin-top: 20px; - margin-bottom: 26px; -} - -.full-width { - width: 100%; - margin-bottom: 16px; } .additional-form { @@ -58,3 +52,9 @@ cursor: pointer; } +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.html b/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.html index 60b8adf..6fe8575 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.html +++ b/ogWebconsole/src/app/components/commands/main-commands/create-command/create-command.component.html @@ -23,7 +23,7 @@ - - - + + + diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html index 2e45e56..11353a8 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html +++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html @@ -3,7 +3,7 @@ {{ icon }} - diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts index 9f6bdc9..bc7dd55 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts +++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts @@ -47,12 +47,6 @@ export class ExecuteCommandComponent implements OnInit { this.clientData = this.clientData || []; } - ngOnChanges(changes: SimpleChanges): void { - if (changes['clientData']) { - console.log(this.clientData.length) - } - } - onCommandSelect(action: any): void { if (action === 'partition') { this.openPartitionAssistant(); diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index d2a5b90..ab06306 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -1,4 +1,3 @@ - .header-container { display: flex; justify-content: space-between; @@ -24,14 +23,6 @@ margin: 20px 0; } -button[mat-raised-button] { - display: flex; - align-items: center; - gap: 8px; - padding: 8px 16px; - font-size: 16px; -} - .actions mat-icon { color: #757575; cursor: pointer; @@ -87,10 +78,6 @@ button[mat-raised-button] { width: 100%; } -button[mat-raised-button] { - align-self: flex-start; -} - @media (max-width: 1024px) { .card-container { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); @@ -391,14 +378,11 @@ mat-tree mat-tree-node.disabled:hover { color: #666; } -button[mat-raised-button] { - margin-top: 15px; -} - .clients-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); - gap: 4px; /* Espaciado reducido entre cards */ + gap: 4px; + /* Espaciado reducido entre cards */ } .clients-list { @@ -423,8 +407,10 @@ button[mat-raised-button] { .clients-grid { display: grid; - grid-template-columns: repeat(6, 1fr); /* 6 columnas por fila */ - gap: 16px; /* Espaciado entre tarjetas */ + grid-template-columns: repeat(6, 1fr); + /* 6 columnas por fila */ + gap: 16px; + /* Espaciado entre tarjetas */ padding: 20px; } @@ -442,7 +428,8 @@ button[mat-raised-button] { margin-top: 10px; } -.client-card, .list-item-content { +.client-card, +.list-item-content { border: 1px solid #ccc; border-radius: 5px; } @@ -453,12 +440,8 @@ button[mat-raised-button] { margin-bottom: 0.5rem; } -.back-button { - flex-shrink: 0; -} - .mat-elevation-z8 { - box-shadow: 0px 0px 0px rgba(0,0,0,0.2); + box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.2); } .client-info { @@ -523,4 +506,4 @@ button[mat-raised-button] { gap: 10px; margin-top: 1.5rem; margin-left: 1.6rem; -} +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index aff6c54..1273645 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -9,19 +9,18 @@
- - + -
@@ -347,4 +346,4 @@ - + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html index 5bebae5..5994b10 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html +++ b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html @@ -108,7 +108,7 @@
- - + +
diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css index 01f846d..b786c8b 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.css @@ -28,12 +28,6 @@ h1 { margin-right: 1em; } -button { - text-transform: none; - font-size: 16px; - font-weight: 500; -} - .grid-form { display: grid; grid-template-columns: repeat(2, 1fr); diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html index 5ced9bc..a3e1fac 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html @@ -165,8 +165,8 @@
- - +
diff --git a/ogWebconsole/src/app/layout/header/header.component.css b/ogWebconsole/src/app/layout/header/header.component.css index dab15f9..b69be3a 100644 --- a/ogWebconsole/src/app/layout/header/header.component.css +++ b/ogWebconsole/src/app/layout/header/header.component.css @@ -1,29 +1,46 @@ - mat-toolbar { - height: 60px; - background-color: #3f51b5; - color: white; -} - -.admin-button, -.user-button{ - background-color: #e0e0e0; + height: 60px; + background-color: #3f51b5; + color: white; } .trace-button .mat-icon { - color: #f0f0f0; + color: #ffffff; } -.navbar-button-row { - display: flex; - justify-content: end; - flex-grow: 1; +.navbar-actions-row { + display: flex; + justify-content: end; + align-items: center; + flex-grow: 1; } -button[mat-flat-button] { - margin: 0 5px; +.navbar-buttons-row { + display: flex; + gap: 1rem; } -.navbar-title{ - cursor: pointer; +.navbar-title { + cursor: pointer; } + +.logout-button { + background-color: #f00e0e; + color: white; + padding: 8px 18px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 16px; + transition: transform 0.3s ease; + font-family: Roboto, "Helvetica Neue", sans-serif; +} + +.logout-button:hover:not(:disabled) { + background-color: #f00e0edc; +} + +.logout-button:disabled { + background-color: #ced0df; + cursor: not-allowed; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/layout/header/header.component.html b/ogWebconsole/src/app/layout/header/header.component.html index fb44be4..852fa13 100644 --- a/ogWebconsole/src/app/layout/header/header.component.html +++ b/ogWebconsole/src/app/layout/header/header.component.html @@ -1,39 +1,48 @@ - + Opengnsys webconsole - - - diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html index 634a3bd..189f45d 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html @@ -7,7 +7,7 @@
- +
diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html index 0fd1c85..4de8d9d 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html @@ -7,7 +7,7 @@
- +
diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css index 782c974..020cb8b 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css @@ -9,8 +9,8 @@ display: flex; justify-content: space-between; align-items: center; - height: 100px; - padding: 10px; + padding: 10px 10px; + border-bottom: 1px solid #ddd; } .disk-size { diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html index 7c09394..a5ee1b8 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html @@ -7,10 +7,9 @@
- +
-
@@ -19,13 +18,10 @@ Listado de clientes donde se realizará el particionado -
+
- Client Icon + Client Icon
{{ client.name }} @@ -54,86 +50,74 @@
-
+ class="partition-segment"> {{ partition.partitionCode }} ({{ (partition.size / 1024).toFixed(2) }} GB)
- +
- - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + +
ParticiónTipo particiónS. ficherosTamaño (MB)Tamaño (%)FormatearEliminar
ParticiónTipo particiónS. ficherosTamaño (MB)Tamaño (%)FormatearEliminar
{{ partition.partitionNumber }} - - - - - - - - - - - -
{{ partition.partitionNumber }} + + + + + + + + + + + +
- +
-
{{ errorMessage }}
+
{{ errorMessage }}
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index ab06306..97a7e90 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -488,9 +488,19 @@ mat-tree mat-tree-node.disabled:hover { .clients-view-header { display: flex; + flex-direction: row; justify-content: space-between; margin-bottom: 1rem; align-items: center; + padding-right: 1rem; +} + +@media (max-width: 1560px) { + .clients-view-header { + display: flex; + flex-direction: column; + } + } .clients-title-name { @@ -506,4 +516,56 @@ mat-tree mat-tree-node.disabled:hover { gap: 10px; margin-top: 1.5rem; margin-left: 1.6rem; +} + +.view-type-container { + display: flex; + justify-content: flex-end; + gap: 2rem; + align-items: center; +} + +mat-button-toggle-group { + border: none; +} + +.mat-button-toggle-group .mat-button-toggle { + height: 36px; + background-color: #3f51b5; + color: white; + border: none; + cursor: pointer; + font-size: 16px; + transition: transform 0.3s ease; + font-family: Roboto, "Helvetica Neue", sans-serif; + display: flex; + align-items: center; + justify-content: center; + padding: 0 6px; +} + +.mat-button-toggle-group .mat-button-toggle:first-child { + border-top-left-radius: 15px; + border-bottom-left-radius: 15px; +} + +.mat-button-toggle-group .mat-button-toggle:last-child { + border-top-right-radius: 15px; + border-bottom-right-radius: 15px; +} + +.mat-button-toggle-group .mat-button-toggle:not(:first-child):not(:last-child) { + border-radius: 0; +} + +.mat-button-toggle-group .mat-button-toggle:hover { + background-color: #303f9f; +} + +.mat-button-toggle-group .mat-button-toggle.mat-button-toggle-checked { + background-color: #303f9f; +} + +.mat-button-toggle-group .mat-button-toggle.mat-button-toggle-disabled { + background-color: #c7c7c7; } \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 1273645..6a7420d 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -9,8 +9,8 @@
- @@ -164,19 +164,24 @@
- - {{ 'clients' | translate }} - {{ selectedNode?.name }} - +
+ + {{ 'clients' | translate }} + {{ selectedNode?.name }} + +
- - + + + list {{ 'Vista Lista' | translate }} + + + grid_view {{ 'Vista Tarjeta' | translate }} + +
diff --git a/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.css b/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.css index bcf134e..4413607 100644 --- a/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.css +++ b/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.css @@ -129,6 +129,6 @@ mat-dialog-content { margin-bottom: 25px; } -.saveDisposition-btn{ - margin-top: 10px; -} +.submit-button { + margin: 1rem; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.html b/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.html index 5485a3d..c5b1bbd 100644 --- a/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.html +++ b/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.html @@ -21,5 +21,5 @@
- + diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css index 254ced8..b3c6559 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css +++ b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css @@ -15,12 +15,6 @@ h1 { padding: 15px 50px 15px 50px; } -button { - text-transform: none; - font-size: 16px; - font-weight: 500; -} - mat-option .unit-name { display: block; } @@ -47,4 +41,11 @@ mat-option .unit-path { grid-template-columns: repeat(2, 1fr); column-gap: 20px; row-gap: 20px; +} + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; } \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html index 5994b10..3cbfd51 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html +++ b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html @@ -9,7 +9,7 @@ {{ getSelectedParentName() }} - +
{{ unit.name }}
{{ unit.path }}
@@ -107,8 +107,9 @@
-
+
- +
-
+
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.css index 64a2fb8..b90667f 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.css +++ b/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.css @@ -1,10 +1,12 @@ .create-client-container { display: flex; flex-direction: column; - padding: 16px; + padding: 16px 16px 0px 16px; } -h1, h3, h4 { +h1, +h3, +h4 { margin: 0 0 16px; color: #333; font-weight: 600; @@ -75,7 +77,8 @@ table { border-collapse: collapse; } -th, td { +th, +td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; @@ -90,14 +93,6 @@ tr:hover { background-color: #f9f9f9; } -button { - margin-right: 8px; -} - -button:last-child { - margin-right: 0; -} - .mat-dialog-actions { margin-top: 16px; display: flex; @@ -148,7 +143,8 @@ input[type="file"] { gap: 16px; } - .mat-dialog-content, .create-multiple-client-container { + .mat-dialog-content, + .create-multiple-client-container { padding: 12px; } @@ -156,3 +152,10 @@ input[type="file"] { max-height: 150px; } } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.html index 1b34d9c..297869d 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.html +++ b/ogWebconsole/src/app/components/groups/shared/clients/create-multiple-client/create-multiple-client.component.html @@ -20,12 +20,15 @@
- +

o añadelos manualmente:

- - + +
@@ -55,8 +58,9 @@
-
- - +
+ +
-
+
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css index 69cf4a7..b3c6559 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css +++ b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css @@ -4,31 +4,25 @@ h1 { font-weight: 400; color: #3f51b5; margin-bottom: 20px; -} - -.network-form { - display: flex; - flex-direction: column; - gap: 15px; + margin-top: 20px; } .form-field { width: 100%; - margin-top: 10px; } .mat-dialog-content { - padding: 50px; + padding: 15px 50px 15px 50px; } -button { - text-transform: none; - font-size: 16px; - font-weight: 500; +mat-option .unit-name { + display: block; } -.mat-slide-toggle { - margin-top: 20px; +mat-option .unit-path { + display: block; + font-size: 0.8em; + color: gray; } .loading-spinner { @@ -38,27 +32,20 @@ button { justify-content: center; } -.mat-dialog-content.loading { - display: flex; - align-items: center; - justify-content: center; - height: 100%; -} - -.client-form { - width: 100%; -} - -.form-field { - width: 100%; +.create-client-container { + position: relative; } .grid-form { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 20px; + column-gap: 20px; + row-gap: 20px; } -.form-field { - width: 100%; -} +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html index fee5dfc..ba47bb9 100644 --- a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html +++ b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html @@ -104,9 +104,9 @@
-
- - +
diff --git a/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.css b/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.css index b908066..f7b5bbe 100644 --- a/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.css +++ b/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.css @@ -1,57 +1,55 @@ .form-container { - display: flex; - flex-direction: column; - gap: 16px; - padding: 16px; - } - - .command-form { - width: 100%; - } - - .full-width { - width: 100%; - } - - .checkbox-group { - display: flex; - flex-direction: column; - gap: 8px; - padding-top: 8px; - } - - .checkbox-group label { - font-weight: bold; - margin-bottom: 8px; - } - - .mat-checkbox { - margin-left: 8px; - } - - .mat-dialog-title { - font-size: 20px; - font-weight: 600; - margin-bottom: 12px; - } - - .mat-dialog-content { - max-height: 60vh; - overflow-y: auto; - } - - .mat-dialog-actions { - display: flex; - justify-content: flex-end; - gap: 8px; - padding: 16px; - } - - button[mat-button] { - font-weight: 500; - } - - button[mat-button]:disabled { - color: rgba(0, 0, 0, 0.38); - } - \ No newline at end of file + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px; +} + +.command-form { + width: 100%; +} + +.full-width { + width: 100%; +} + +.checkbox-group { + display: flex; + flex-direction: column; + gap: 8px; + padding-top: 8px; +} + +.checkbox-group label { + font-weight: bold; + margin-bottom: 8px; +} + +.mat-checkbox { + margin-left: 8px; +} + +.mat-dialog-title { + font-size: 20px; + font-weight: 600; + margin-bottom: 12px; +} + +.mat-dialog-content { + max-height: 60vh; + overflow-y: auto; +} + +.mat-dialog-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 16px; +} + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.html b/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.html index 154290d..3b5902f 100644 --- a/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.html +++ b/ogWebconsole/src/app/components/groups/shared/execute-command-ou/execute-command-ou.component.html @@ -20,9 +20,8 @@
- + {{ client.name }}
@@ -34,12 +33,10 @@ - - - + - + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html index a3e1fac..52d1291 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html @@ -34,7 +34,7 @@ - {{ 'excludeParentChanges' | translate }} + {{ 'excludeParentChanges' | translate }} @@ -137,14 +137,14 @@ - - Menu - - - {{ menu.name }} - - - + + Menu + + + {{ menu.name }} + + + Perfil de Hardware @@ -169,4 +169,4 @@ -
+
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.html index d642dbb..47bc3ee 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.html +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.html @@ -46,5 +46,5 @@
- +
diff --git a/ogWebconsole/src/app/components/images/create-image/create-image.component.css b/ogWebconsole/src/app/components/images/create-image/create-image.component.css index ffb19eb..8a9bda9 100644 --- a/ogWebconsole/src/app/components/images/create-image/create-image.component.css +++ b/ogWebconsole/src/app/components/images/create-image/create-image.component.css @@ -1,13 +1,15 @@ .dialog-content { display: flex; flex-direction: column; - gap: 16px; /* Espacio entre los elementos del formulario */ + gap: 16px; + /* Espacio entre los elementos del formulario */ } .image-form { width: 100%; display: flex; flex-direction: column; + margin-top: 1rem; } .form-field { @@ -16,27 +18,19 @@ } .partition-info-container { - background-color: #f0f8ff; /* Un color de fondo suave */ + background-color: #f0f8ff; + /* Un color de fondo suave */ padding: 10px; border: 1px solid #ccc; margin-top: 10px; border-radius: 5px; } -/* Botones alineados al final, con margen superior */ -.dialog-actions { - display: flex; - justify-content: flex-end; - margin-top: 24px; -} - -button { - margin-left: 8px; /* Espacio entre los botones */ -} - .warning-card { - background-color: #ffebee; /* Rojo claro */ - color: #d32f2f; /* Rojo oscuro */ + background-color: #ffebee; + /* Rojo claro */ + color: #d32f2f; + /* Rojo oscuro */ padding: 16px; border-left: 5px solid #d32f2f; display: flex; @@ -68,3 +62,10 @@ button { margin-bottom: 8px; } } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/images/create-image/create-image.component.html b/ogWebconsole/src/app/components/images/create-image/create-image.component.html index fc5e87d..f3b8278 100644 --- a/ogWebconsole/src/app/components/images/create-image/create-image.component.html +++ b/ogWebconsole/src/app/components/images/create-image/create-image.component.html @@ -5,7 +5,8 @@ warning - Ha marcado la casilla "Imagen Global". Se transferirá la imagen al resto de repositorios en el caso de que no exista previamente. + Ha marcado la casilla "Imagen Global". Se transferirá la imagen al resto de repositorios en el + caso de que no exista previamente. @@ -16,7 +17,8 @@ {{ 'repositoryLabel' | translate }} - + {{ imageRepository.name }} @@ -41,16 +43,11 @@ - + {{ 'remotePcLabel' | translate }} - + {{ 'globalImageLabel' | translate }} @@ -68,7 +65,7 @@ - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/images/export-image/export-image.component.html b/ogWebconsole/src/app/components/images/export-image/export-image.component.html index 0837588..ad113c3 100644 --- a/ogWebconsole/src/app/components/images/export-image/export-image.component.html +++ b/ogWebconsole/src/app/components/images/export-image/export-image.component.html @@ -12,6 +12,6 @@ - - + + diff --git a/ogWebconsole/src/app/components/images/images.component.html b/ogWebconsole/src/app/components/images/images.component.html index b921d68..5f169b0 100644 --- a/ogWebconsole/src/app/components/images/images.component.html +++ b/ogWebconsole/src/app/components/images/images.component.html @@ -10,7 +10,7 @@
-
@@ -38,7 +38,7 @@ - +
-
diff --git a/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.css b/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.css index a2b595f..5efc52e 100644 --- a/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.css +++ b/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.css @@ -1,20 +1,19 @@ .dialog-content { display: flex; flex-direction: column; - gap: 16px; - padding: 16px; + margin-top: 2rem; } .form-container { display: flex; - flex-direction: row; /* Alinear elementos horizontalmente */ + flex-direction: row; justify-content: space-between; gap: 24px; - align-items: flex-start; /* Para alinear superiormente */ + align-items: flex-start; } .menu-form { - flex: 1; /* El formulario ocupa el espacio restante */ + flex: 1; display: flex; flex-direction: column; gap: 16px; @@ -25,11 +24,11 @@ } .iframe-container { - flex: 1; /* El iframe ocupa la otra mitad del espacio */ + flex: 1; display: flex; justify-content: center; align-items: flex-start; - max-width: 50%; /* Limitar ancho máximo */ + max-width: 50%; } .iframe { @@ -39,3 +38,10 @@ border-radius: 8px; box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.html b/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.html index c15e7a8..3095add 100644 --- a/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.html +++ b/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.html @@ -25,10 +25,7 @@ - + {{ 'defaultMenuLabel' | translate }} @@ -40,7 +37,7 @@ - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/menus/menus.component.html b/ogWebconsole/src/app/components/menus/menus.component.html index a60ac00..12ecb01 100644 --- a/ogWebconsole/src/app/components/menus/menus.component.html +++ b/ogWebconsole/src/app/components/menus/menus.component.html @@ -7,7 +7,7 @@ Administrar menús
-
diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html index 0e20a3b..ba5a912 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html @@ -11,8 +11,8 @@
- - +
diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.html b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.html index 34d1f13..f8caba7 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.html @@ -31,7 +31,7 @@ - diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.css b/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.css index 5a93649..53eeb5c 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.css +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.css @@ -7,3 +7,10 @@ display: block; justify-content: center; } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.html b/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.html index 44c8fd3..09f4410 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/create-image/create-image/create-image.component.html @@ -11,7 +11,7 @@ - - - + + + diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html b/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html index 87d5a9e..236f131 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/info-image/info-image/info-image.component.html @@ -3,5 +3,5 @@
{{ data | json }}
- + diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html index d093040..bf06c2f 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.html @@ -8,8 +8,8 @@
- - + diff --git a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css index 4abaa49..65a0a2c 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css +++ b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.css @@ -1,6 +1,5 @@ mat-form-field { width: 100%; - margin-bottom: 20px; } pre { @@ -77,7 +76,9 @@ h3 { display: flex; justify-content: space-between; width: 100%; - align-items: center; + align-items: center; + margin-bottom: 1rem; + padding-right: 1rem; } .action-buttons { diff --git a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html index f79fd47..75a76cc 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe/create-pxeTemplate/create-pxe-template.component.html @@ -13,7 +13,8 @@ {{ 'templateContentLabel' | translate }} - + {{ 'templateContentError' | translate }} @@ -24,7 +25,7 @@
- @@ -33,10 +34,10 @@
- - +
-
+ \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html index a1d3940..ca58141 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html +++ b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.html @@ -7,8 +7,8 @@ translate }}
- - +
diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.css index 2239479..3c43c3c 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.css @@ -20,3 +20,10 @@ mat-dialog-actions { flex-direction: column; gap: 10px; } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html index 6ea0177..4c0b532 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html @@ -23,7 +23,7 @@ - - - + + + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css index 36b762b..106da2f 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css @@ -2,7 +2,7 @@ width: 100%; } -form{ +form { padding: 20px; } @@ -33,3 +33,10 @@ form{ margin-left: 8px; cursor: pointer; } + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html index 68f9b0b..ed1940e 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html @@ -62,7 +62,7 @@ - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html index 0caafe9..1f3aac2 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html @@ -7,9 +7,9 @@ text="Desde aquí puedes gestionar las subredes configuradas en el servidor OgDHCP.">Administrar Subredes
- -
@@ -58,7 +58,7 @@ - + +
diff --git a/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.css b/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.css index 722ef4f..f9086a7 100644 --- a/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.css +++ b/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.css @@ -1,60 +1,15 @@ -.full-width { - width: 100%; -} .form-container { - padding: 40px; -} - -.form-group { - margin-top: 20px; - margin-bottom: 26px; + padding: 20px; } .full-width { width: 100%; - margin-bottom: 16px; + margin-top: 16px; } -.additional-form { - margin-top: 20px; -} - -.checkbox-group { +.action-container { display: flex; - flex-direction: column; - margin: 15px 0; - align-items: flex-start; -} - -.time-fields { - display: flex; - gap: 15px; /* Espacio entre los campos */ -} - -.time-field { - flex: 1; -} - -.list-item-content { - display: flex; - align-items: flex-start; /* Alinea el contenido al inicio */ - justify-content: space-between; /* Espacio entre los textos y los íconos */ - width: 100%; /* Asegúrate de que el contenido ocupe todo el ancho */ -} - -.text-content { - flex-grow: 1; /* Permite que este contenedor ocupe el espacio disponible */ - margin-right: 16px; /* Espaciado a la derecha para separar de los íconos */ - margin-left: 10px; -} - -.icon-container { - display: flex; - align-items: center; /* Alinea los íconos verticalmente */ -} - -.right-icon { - margin-left: 8px; /* Espaciado entre los íconos */ - cursor: pointer; -} - + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.html b/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.html index 5263ebd..ca4f066 100644 --- a/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.html +++ b/ogWebconsole/src/app/components/operative-system/create-operative-system/create-operative-system.component.html @@ -8,8 +8,7 @@ - - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/operative-system/operative-system.component.html b/ogWebconsole/src/app/components/operative-system/operative-system.component.html index 49ccd5c..8a1a845 100644 --- a/ogWebconsole/src/app/components/operative-system/operative-system.component.html +++ b/ogWebconsole/src/app/components/operative-system/operative-system.component.html @@ -9,7 +9,7 @@
-
diff --git a/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.css b/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.css index 57c71a9..afab99f 100644 --- a/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.css +++ b/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.css @@ -1,7 +1,6 @@ .dialog-content { display: flex; flex-direction: column; - gap: 16px; } .repository-form { @@ -12,17 +11,14 @@ .form-field { width: 100%; - margin-bottom: 16px; + margin-top: 16px; } -.dialog-actions { +.action-container { display: flex; justify-content: flex-end; - margin-top: 24px; -} - -button { - margin-left: 8px; + gap: 1em; + padding: 1.5em; } @media (max-width: 600px) { @@ -40,4 +36,4 @@ button { margin-left: 0; margin-bottom: 8px; } -} +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.html b/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.html index 501d1fa..84ce0db 100644 --- a/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.html +++ b/ogWebconsole/src/app/components/repositories/create-repository/create-repository.component.html @@ -19,7 +19,7 @@ - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/repositories/import-image/import-image.component.html b/ogWebconsole/src/app/components/repositories/import-image/import-image.component.html index 943cc38..82bc9fd 100644 --- a/ogWebconsole/src/app/components/repositories/import-image/import-image.component.html +++ b/ogWebconsole/src/app/components/repositories/import-image/import-image.component.html @@ -23,6 +23,6 @@ - - + + diff --git a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html index d7b0563..70229ae 100644 --- a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html +++ b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html @@ -83,8 +83,8 @@

Editar datos repositorio

- - + +
@@ -108,7 +108,7 @@ - + diff --git a/ogWebconsole/src/app/components/repositories/repositories.component.html b/ogWebconsole/src/app/components/repositories/repositories.component.html index 1a51e54..6ad69e6 100644 --- a/ogWebconsole/src/app/components/repositories/repositories.component.html +++ b/ogWebconsole/src/app/components/repositories/repositories.component.html @@ -10,7 +10,7 @@
-
diff --git a/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.css b/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.css index 722ef4f..0ec67f1 100644 --- a/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.css +++ b/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.css @@ -1,18 +1,18 @@ .full-width { width: 100%; } + .form-container { padding: 40px; } .form-group { margin-top: 20px; - margin-bottom: 26px; } .full-width { width: 100%; - margin-bottom: 16px; + margin-top: 16px; } .additional-form { @@ -58,3 +58,9 @@ cursor: pointer; } +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 0em 1.5em 1.5em 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.html b/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.html index a448bcc..17ad578 100644 --- a/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.html +++ b/ogWebconsole/src/app/components/software-profile/create-software-profile/create-software-profile.component.html @@ -4,7 +4,7 @@
- + Descripción @@ -22,7 +22,7 @@ Seleccionar sistema operativo - + {{ op.name }} @@ -34,16 +34,10 @@
- - @@ -67,7 +61,7 @@ - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/software-profile/software-profile.component.html b/ogWebconsole/src/app/components/software-profile/software-profile.component.html index f13f48f..9b9b767 100644 --- a/ogWebconsole/src/app/components/software-profile/software-profile.component.html +++ b/ogWebconsole/src/app/components/software-profile/software-profile.component.html @@ -7,7 +7,7 @@ text="En esta pantalla podrás administrar los diferentes perfiles de software">Administrar perfiles software
-
diff --git a/ogWebconsole/src/app/components/software/create-software/create-software.component.css b/ogWebconsole/src/app/components/software/create-software/create-software.component.css index 722ef4f..ca3e639 100644 --- a/ogWebconsole/src/app/components/software/create-software/create-software.component.css +++ b/ogWebconsole/src/app/components/software/create-software/create-software.component.css @@ -1,6 +1,7 @@ .full-width { width: 100%; } + .form-container { padding: 40px; } @@ -12,49 +13,12 @@ .full-width { width: 100%; - margin-bottom: 16px; + margin-top: 16px; } -.additional-form { - margin-top: 20px; -} - -.checkbox-group { +.action-container { display: flex; - flex-direction: column; - margin: 15px 0; - align-items: flex-start; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; } - -.time-fields { - display: flex; - gap: 15px; /* Espacio entre los campos */ -} - -.time-field { - flex: 1; -} - -.list-item-content { - display: flex; - align-items: flex-start; /* Alinea el contenido al inicio */ - justify-content: space-between; /* Espacio entre los textos y los íconos */ - width: 100%; /* Asegúrate de que el contenido ocupe todo el ancho */ -} - -.text-content { - flex-grow: 1; /* Permite que este contenedor ocupe el espacio disponible */ - margin-right: 16px; /* Espaciado a la derecha para separar de los íconos */ - margin-left: 10px; -} - -.icon-container { - display: flex; - align-items: center; /* Alinea los íconos verticalmente */ -} - -.right-icon { - margin-left: 8px; /* Espaciado entre los íconos */ - cursor: pointer; -} - diff --git a/ogWebconsole/src/app/components/software/create-software/create-software.component.html b/ogWebconsole/src/app/components/software/create-software/create-software.component.html index 495f491..b8093d2 100644 --- a/ogWebconsole/src/app/components/software/create-software/create-software.component.html +++ b/ogWebconsole/src/app/components/software/create-software/create-software.component.html @@ -22,8 +22,7 @@ - - - - - + + + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/software/software.component.html b/ogWebconsole/src/app/components/software/software.component.html index 77916bd..8ee4f5e 100644 --- a/ogWebconsole/src/app/components/software/software.component.html +++ b/ogWebconsole/src/app/components/software/software.component.html @@ -7,7 +7,7 @@ text="Administra el software deisponible desde este componente.">Administrar Software
-
diff --git a/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.css b/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.css index 470356d..d1640b2 100644 --- a/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.css +++ b/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.css @@ -1,29 +1,40 @@ mat-dialog-content { - font-size: 16px; - margin-bottom: 20px; - color: #555; /* Color de texto más suave */ - } - - mat-dialog-actions { - margin-top: 20px; - display: flex; - justify-content: flex-end; /* Alineación a la derecha */ - } - - button[mat-button] { - margin-left: 8px; /* Espacio entre los botones */ - } - - button[mat-button]:first-child { - color: #757575; /* Color para el botón de cancelar */ - } - - button[mat-raised-button] { - box-shadow: none; - } - - strong { - font-weight: bold; - color: #000; /* Color de texto más fuerte para el nombre del elemento */ - } - \ No newline at end of file + font-size: 16px; + margin-bottom: 20px; + color: #555; + /* Color de texto más suave */ +} + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 0.5em 1.5em 1.5em 1.5em; +} + +strong { + font-weight: bold; + color: #000; + /* Color de texto más fuerte para el nombre del elemento */ +} + +.delete-button { + background-color: #f00e0e; + color: white; + padding: 8px 18px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 16px; + transition: transform 0.3s ease; + font-family: Roboto, "Helvetica Neue", sans-serif; +} + +.delete-button:hover:not(:disabled) { + background-color: #f00e0edc; +} + +.delete-button:disabled { + background-color: #ced0df; + cursor: not-allowed; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.html b/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.html index bd1b25f..f3592de 100644 --- a/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.html +++ b/ogWebconsole/src/app/shared/delete_modal/delete-modal/delete-modal.component.html @@ -4,7 +4,7 @@ ¿Estás seguro que deseas eliminar {{ data.name }}?

-
- - +
+ +
From 09f83f6af759febe0cb56b8270c70fa735b00773 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Feb 2025 10:57:24 +0100 Subject: [PATCH 04/38] refs #1604. Backup image UX --- .../create-image/create-image.component.html | 9 +-- .../create-image/create-image.component.ts | 10 ++-- .../backup-image/backup-image.component.css | 46 +++++++++++++++ .../backup-image/backup-image.component.html | 21 +++++++ .../backup-image.component.spec.ts | 23 ++++++++ .../backup-image/backup-image.component.ts | 58 +++++++++++++++++++ .../main-repository-view.component.html | 5 +- .../main-repository-view.component.ts | 17 +++--- 8 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.css create mode 100644 ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.html create mode 100644 ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts create mode 100644 ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.ts diff --git a/ogWebconsole/src/app/components/images/create-image/create-image.component.html b/ogWebconsole/src/app/components/images/create-image/create-image.component.html index f3b8278..fcc73de 100644 --- a/ogWebconsole/src/app/components/images/create-image/create-image.component.html +++ b/ogWebconsole/src/app/components/images/create-image/create-image.component.html @@ -1,3 +1,5 @@ + +

{{ imageId ? 'Editar' : 'Crear' }} imagen

@@ -14,11 +16,10 @@ - + {{ 'repositoryLabel' | translate }} - + {{ imageRepository.name }} @@ -68,4 +69,4 @@ - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/images/create-image/create-image.component.ts b/ogWebconsole/src/app/components/images/create-image/create-image.component.ts index 262ae1f..df6a1e8 100644 --- a/ogWebconsole/src/app/components/images/create-image/create-image.component.ts +++ b/ogWebconsole/src/app/components/images/create-image/create-image.component.ts @@ -16,8 +16,9 @@ export class CreateImageComponent implements OnInit { imageId: string | null = null; softwareProfiles: any[] = []; repositories: any[] = []; + loading: boolean = false; partitionInfo: { [key: string]: string } = {}; - showWarning: boolean = false; // Nueva variable para mostrar la advertencia + showWarning: boolean = false; constructor( private fb: FormBuilder, @@ -39,12 +40,13 @@ export class CreateImageComponent implements OnInit { } ngOnInit() { + this.loading = true; if (this.data) { this.load() } this.fetchSoftwareProfiles(); this.fetchRepositories(); - + this.loading = false; } load(): void { @@ -79,7 +81,6 @@ export class CreateImageComponent implements OnInit { this.softwareProfiles = response['hydra:member']; }, error: (error) => { - console.error('Error al obtener los perfiles de software:', error); this.toastService.error('Error al obtener los perfiles de software'); } }); @@ -92,7 +93,6 @@ export class CreateImageComponent implements OnInit { this.repositories = response['hydra:member']; }, error: (error) => { - console.error('Error al obtener los repositorios de imágenes:', error); this.toastService.error('Error al obtener los repositorios de imágenes'); } }); @@ -117,7 +117,6 @@ export class CreateImageComponent implements OnInit { }, (error) => { this.toastService.error(error['error']['hydra:description']); - console.error('Error al editar la imagen', error); } ); } else { @@ -128,7 +127,6 @@ export class CreateImageComponent implements OnInit { }, (error) => { this.toastService.error(error['error']['hydra:description']); - console.error('Error al añadir la imagen', error); } ); } diff --git a/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.css b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.css new file mode 100644 index 0000000..336b7b9 --- /dev/null +++ b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.css @@ -0,0 +1,46 @@ +.loading-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100px; +} + +mat-form-field { + width: 100%; +} + +mat-dialog-actions { + display: flex; + justify-content: flex-end; +} + +.checkbox-group { + display: flex; + flex-direction: column; + gap: 10px; +} + +.selected-list ul { + list-style: none; + padding: 0; +} + +.selected-item { + display: flex; + justify-content: space-between; /* Alinea texto a la izquierda y botón a la derecha */ + align-items: center; /* Centra verticalmente */ + padding: 8px; + border-bottom: 1px solid #ccc; +} + +.selected-item button { + margin-left: 10px; +} + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} diff --git a/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.html b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.html new file mode 100644 index 0000000..cc15162 --- /dev/null +++ b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.html @@ -0,0 +1,21 @@ + + +

Realizar backup a repositorio remoto

+ + +
+ + Ip servidor + + + + Remote path remoto + + +
+
+ +
+ + +
diff --git a/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts new file mode 100644 index 0000000..11a1500 --- /dev/null +++ b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BackupImageComponent } from './backup-image.component'; + +describe('BackupImageComponent', () => { + let component: BackupImageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BackupImageComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(BackupImageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.ts b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.ts new file mode 100644 index 0000000..12a9ed0 --- /dev/null +++ b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.ts @@ -0,0 +1,58 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {HttpClient} from "@angular/common/http"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {ToastrService} from "ngx-toastr"; +import {Router} from "@angular/router"; +import {FormBuilder, FormGroup, Validators} from "@angular/forms"; + +@Component({ + selector: 'app-backup-image', + templateUrl: './backup-image.component.html', + styleUrl: './backup-image.component.css' +}) +export class BackupImageComponent implements OnInit { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + loading: boolean = false; + form!: FormGroup; + + constructor( + private fb: FormBuilder, + private http: HttpClient, + public dialogRef: MatDialogRef, + private toastService: ToastrService, + private router: Router, + @Inject(MAT_DIALOG_DATA) public data: { imageImageRepository: any } + ) { + + } + + ngOnInit(): void { + this.form = this.fb.group({ + remotePath: ['', Validators.required], + repoIp: ['', Validators.required] + }); + } + + save() { + this.loading = true + this.http.post(`${this.baseUrl}${this.data.imageImageRepository['@id']}/backup-image`, { + remotePath: this.form.value.remotePath, + repoIp: this.form.value.repoIp + }).subscribe({ + next: (response) => { + this.toastService.success('Peticion de backup de imagen enviada correctamente'); + this.dialogRef.close(); + this.loading = false; + this.router.navigate(['/commands-logs']); + }, + error: error => { + this.loading = false; + this.toastService.error('Error al realizar la petición de backup de imagen'); + } + }); + } + + close() { + this.dialogRef.close(); + } +} diff --git a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html index 70229ae..c2b6da9 100644 --- a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html +++ b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.html @@ -1,5 +1,6 @@ +

OgRepository Server Status

@@ -108,7 +109,7 @@ - +
@@ -117,4 +118,4 @@ -
\ No newline at end of file + diff --git a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts index 941bf06..e398311 100644 --- a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts +++ b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts @@ -22,7 +22,7 @@ export class MainRepositoryViewComponent implements OnInit { repositoryForm: FormGroup; repositoryId: string | null = null; dataSource = new MatTableDataSource(); - loading: boolean = true; + loading: boolean = false; diskUsage: any = {}; servicesStatus: any = {}; processesStatus: any = {}; @@ -103,9 +103,8 @@ export class MainRepositoryViewComponent implements OnInit { ngOnInit() { this.repositoryId = this.route.snapshot.paramMap.get('id'); - this.loading = true - this.load() this.loadStatus() + this.load() } load(): void { @@ -118,11 +117,9 @@ export class MainRepositoryViewComponent implements OnInit { ip: [response.ip], comments: [response.comments], }); - this.loading = false; }, (error) => { console.error('Error al cargar los datos del cliente:', error); - this.loading = false; } ); } @@ -158,9 +155,11 @@ export class MainRepositoryViewComponent implements OnInit { } loadStatus(): void { + this.loading = true; this.http.get(`${this.baseUrl}/image-repositories/server/${this.repositoryId}/status`).subscribe(data => { if (!data.success) { - console.error('Error: No se pudo obtener los datos del servidor'); + this.toastService.error('Error al obtener el estado del servidor'); + this.loading = false; this.status = false; return; } @@ -182,13 +181,11 @@ export class MainRepositoryViewComponent implements OnInit { ]; this.cpuUsage = { percentage: cpu.used_percentage }; - this.servicesStatus = Object.entries(services).map(([name, status]) => ({ name, status })); - this.processesStatus = Object.entries(processes).map(([name, status]) => ({ name, status })); - + this.loading = false; }, error => { - console.error('Error fetching status', error); + this.loading = false; }); } From 2d9ccd01b4233c2fc50de36ad1c7658004fe88eb Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Feb 2025 11:22:01 +0100 Subject: [PATCH 05/38] refs #1575. Mercure and notifications --- ogWebconsole/src/app/app.module.ts | 2 + .../task-logs/task-logs.component.html | 6 +-- .../task-logs/task-logs.component.ts | 42 ++++++++++++++++--- .../app/components/groups/groups.component.ts | 29 +++++++++++++ .../components/images/images.component.html | 10 ++--- .../backup-image.component.spec.ts | 41 +++++++++++++++++- .../repository-images.component.html | 3 +- .../repository-images.component.ts | 38 +++++++++++++---- 8 files changed, 147 insertions(+), 24 deletions(-) diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 8bdcfd5..7af2819 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -130,6 +130,7 @@ import { LoadingComponent } from './shared/loading/loading.component'; import { RepositoryImagesComponent } from './components/repositories/repository-images/repository-images.component'; import { InputDialogComponent } from './components/commands/commands-task/task-logs/input-dialog/input-dialog.component'; import { ManageOrganizationalUnitComponent } from './components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component'; +import { BackupImageComponent } from './components/repositories/backup-image/backup-image.component'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http, './locale/', '.json'); } @@ -216,6 +217,7 @@ export function HttpLoaderFactory(http: HttpClient) { RepositoryImagesComponent, InputDialogComponent, ManageOrganizationalUnitComponent, + BackupImageComponent, ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html index 8990735..b52093c 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.html @@ -67,9 +67,9 @@
- + - {{progress}}% + {{trace.progress}}%
@@ -116,4 +116,4 @@ - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts index 07be884..2c9e24a 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import {ChangeDetectorRef, Component, OnInit} from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, forkJoin } from 'rxjs'; import { FormControl } from '@angular/forms'; @@ -27,7 +27,7 @@ export class TaskLogsComponent implements OnInit { pageSizeOptions: number[] = [10, 20, 30, 50]; datePipe: DatePipe = new DatePipe('es-ES'); mode: ProgressBarMode = 'buffer'; - progress = 65; + progress = 0; bufferValue = 0; columns = [ @@ -86,14 +86,15 @@ export class TaskLogsComponent implements OnInit { commandControl = new FormControl(); constructor(private http: HttpClient, - private joyrideService: JoyrideService, - private dialog: MatDialog + private joyrideService: JoyrideService, + private dialog: MatDialog, + private cdr: ChangeDetectorRef ) { } ngOnInit(): void { this.loadTraces(); this.loadCommands(); - this.loadClients(); + //this.loadClients(); this.filteredCommands = this.commandControl.valueChanges.pipe( startWith(''), map(value => (typeof value === 'string' ? value : value?.name)), @@ -104,8 +105,39 @@ export class TaskLogsComponent implements OnInit { map(value => (typeof value === 'string' ? value : value?.name)), map(name => (name ? this._filterClients(name) : this.clients.slice())) ); + + const eventSource = new EventSource('http://localhost:3000/.well-known/mercure?topic=' + + encodeURIComponent(`traces`)); + + eventSource.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data && data['@id']) { + this.updateTracesStatus(data['@id'], data.status, data.progress); + } + } } + private updateTracesStatus(clientUuid: string, newStatus: string, progress: Number): void { + const traceIndex = this.traces.findIndex(trace => trace['@id'] === clientUuid); + if (traceIndex !== -1) { + const updatedTraces = [...this.traces]; + + updatedTraces[traceIndex] = { + ...updatedTraces[traceIndex], + status: newStatus, + progress: progress + }; + + this.traces = updatedTraces; + this.cdr.detectChanges(); + + console.log(`Estado actualizado para la traza ${clientUuid}: ${newStatus}`); + } else { + console.warn(`Traza con UUID ${clientUuid} no encontrado en la lista.`); + } + } + + private _filterClients(name: string): any[] { const filterValue = name.toLowerCase(); return this.clients.filter(client => client.name.toLowerCase().includes(filterValue)); diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index eaebf71..dcdc0fd 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -126,6 +126,35 @@ export class GroupsComponent implements OnInit, OnDestroy { }; this.arrayClients = this.selectedClients.data; + + const eventSource = new EventSource('http://localhost:3000/.well-known/mercure?topic=' + + encodeURIComponent(`clients`)); + + eventSource.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data && data['@id']) { + this.updateClientStatus(data['@id'], data.status); + } + } + } + + private updateClientStatus(clientUuid: string, newStatus: string): void { + const clientIndex = this.selectedClients.data.findIndex(client => client['@id'] === clientUuid); + + if (clientIndex !== -1) { + const updatedClients = [...this.selectedClients.data]; + + updatedClients[clientIndex] = { + ...updatedClients[clientIndex], + status: newStatus + }; + + this.selectedClients.data = updatedClients; + + console.log(`Estado actualizado para el cliente ${clientUuid}: ${newStatus}`); + } else { + console.warn(`Cliente con UUID ${clientUuid} no encontrado en la lista.`); + } } diff --git a/ogWebconsole/src/app/components/images/images.component.html b/ogWebconsole/src/app/components/images/images.component.html index 5f169b0..44a0a0c 100644 --- a/ogWebconsole/src/app/components/images/images.component.html +++ b/ogWebconsole/src/app/components/images/images.component.html @@ -38,12 +38,10 @@
- - - - + + {{ repository.imageRepository.name }} + + diff --git a/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts index 11a1500..648e229 100644 --- a/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts +++ b/ogWebconsole/src/app/components/repositories/backup-image/backup-image.component.spec.ts @@ -1,6 +1,19 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { BackupImageComponent } from './backup-image.component'; +import {ImportImageComponent} from "../import-image/import-image.component"; +import {FormBuilder, ReactiveFormsModule} from "@angular/forms"; +import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from "@angular/material/dialog"; +import {MatFormFieldModule} from "@angular/material/form-field"; +import {MatInputModule} from "@angular/material/input"; +import {MatButtonModule} from "@angular/material/button"; +import {MatSelectModule} from "@angular/material/select"; +import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; +import {ToastrModule, ToastrService} from "ngx-toastr"; +import {TranslateModule} from "@ngx-translate/core"; +import {provideHttpClient} from "@angular/common/http"; +import {provideHttpClientTesting} from "@angular/common/http/testing"; +import {LoadingComponent} from "../../../shared/loading/loading.component"; describe('BackupImageComponent', () => { let component: BackupImageComponent; @@ -8,9 +21,33 @@ describe('BackupImageComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [BackupImageComponent] + declarations: [BackupImageComponent, LoadingComponent], + imports: [ + ReactiveFormsModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatSelectModule, + BrowserAnimationsModule, + ToastrModule.forRoot(), + TranslateModule.forRoot() + ], + providers: [ + FormBuilder, + ToastrService, + provideHttpClient(), + provideHttpClientTesting(), + { + provide: MatDialogRef, + useValue: {} + }, + { + provide: MAT_DIALOG_DATA, + useValue: {} + }] }) - .compileComponents(); + .compileComponents(); fixture = TestBed.createComponent(BackupImageComponent); component = fixture.componentInstance; diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html index 3bb5b7b..eca724f 100644 --- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html +++ b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html @@ -70,9 +70,10 @@ - + + diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts index 69fd13f..652ebcc 100644 --- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts +++ b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts @@ -10,6 +10,7 @@ import {Observable} from "rxjs"; import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; import {ExportImageComponent} from "../../images/export-image/export-image.component"; +import {BackupImageComponent} from "../backup-image/backup-image.component"; @Component({ selector: 'app-repository-images', @@ -209,13 +210,20 @@ export class RepositoryImagesComponent implements OnInit { break; case 'delete-permanent': - this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/delete-permanent`, {}).subscribe({ - next: () => { - this.toastService.success('Petición de eliminación de la papelera temporal enviada'); - this.search() - }, - error: (error) => { - this.toastService.error(error.error['hydra:description']); + this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: image.name }, + }).afterClosed().subscribe((result) => { + if (result) { + this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/delete-permanent`, {}).subscribe({ + next: () => { + this.toastService.success('Petición de eliminación de la papelera temporal enviada'); + this.search() + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); } }); break; @@ -246,6 +254,22 @@ export class RepositoryImagesComponent implements OnInit { } }); break; + case 'backup': + this.http.get(`${this.baseUrl}${image.image['@id']}`).subscribe({ + next: (response) => { + this.dialog.open(BackupImageComponent, { + width: '600px', + data: { + image: response, + imageImageRepository: image + } + }); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + break; default: console.error('Acción no soportada:', action); break; From 56966fd76770544a964e7a351cabe8f69c3c858d Mon Sep 17 00:00:00 2001 From: Nicolas Arenas Date: Fri, 21 Feb 2025 11:46:13 +0100 Subject: [PATCH 06/38] Increase maximun size error --- ogWebconsole/angular.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ogWebconsole/angular.json b/ogWebconsole/angular.json index 3684cc7..f5adc43 100644 --- a/ogWebconsole/angular.json +++ b/ogWebconsole/angular.json @@ -66,8 +66,8 @@ }, { "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" + "maximumWarning": "4kb", + "maximumError": "10kb" } ], "outputHashing": "all" From f1ddf20d0c307b7adfe63b5505af427a49afc7ad Mon Sep 17 00:00:00 2001 From: llara Date: Mon, 24 Feb 2025 12:50:27 +0100 Subject: [PATCH 07/38] refs #1550. Improve error handling in ManageOrganizationalUnitComponent by parsing and cleaning error messages for better user feedback --- .../manage-organizational-unit.component.ts | 12 ++++++++++-- ogWebconsole/src/styles.css | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts index f094da8..b64a9a9 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts @@ -284,7 +284,11 @@ export class ManageOrganizationalUnitComponent implements OnInit { }, error => { console.error('Error al realizar PUT:', error); - this.toastService.error('Error al editar:', error); + const errorMessages = error.error['hydra:description'].split('\n'); + errorMessages.forEach((message: string) => { + const cleanedMessage = message.replace(/networkSettings\.(\w+):/, 'Error $1:'); + this.toastService.error(cleanedMessage); + }); } ); } else { @@ -299,7 +303,11 @@ export class ManageOrganizationalUnitComponent implements OnInit { }, error => { console.error('Error al realizar POST:', error); - this.toastService.error('Error al crear:', error.error['hydra:description']); + const errorMessages = error.error['hydra:description'].split('\n'); + errorMessages.forEach((message: string) => { + const cleanedMessage = message.replace(/networkSettings\.(\w+):/, 'Error $1:'); + this.toastService.error(cleanedMessage); + }); } ); } diff --git a/ogWebconsole/src/styles.css b/ogWebconsole/src/styles.css index 28f1c65..9f78cfb 100644 --- a/ogWebconsole/src/styles.css +++ b/ogWebconsole/src/styles.css @@ -56,7 +56,7 @@ body { .ordinary-button { background-color: #fafafa; - color: #5f5f5f; + color: #3d3d3d; padding: 8px 18px; border: 1px solid #5f5f5f; border-radius: 4px; From 1c4343bb48fa130917c1f56b46dccd84bc44b156 Mon Sep 17 00:00:00 2001 From: llara Date: Mon, 24 Feb 2025 16:13:29 +0100 Subject: [PATCH 08/38] refs #1549. Add loading state management to ManageOrganizationalUnitComponent for improved user experience during data fetching --- .../manage-organizational-unit.component.html | 337 +++++++++--------- ...nage-organizational-unit.component.spec.ts | 9 +- .../manage-organizational-unit.component.ts | 52 ++- 3 files changed, 221 insertions(+), 177 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html index 52d1291..c5a785f 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html @@ -1,172 +1,177 @@ -

{{ isEditMode ? 'Editar' : 'Crear' }} Unidad Organizativa

-
- - General -
- - Tipo - - - {{ typeTranslations[type] }} - - - - - Nombre - - - - Padre - - - {{ getSelectedParentName() }} - - -
{{ unit.name }}
-
{{ unit.path }}
-
-
-
+ - - Descripción - - +
+

{{ isEditMode ? 'Editar' : 'Crear' }} Unidad Organizativa

+
+ + General + + + Tipo + + + {{ typeTranslations[type] }} + + + + + Nombre + + + + Padre + + + {{ getSelectedParentName() }} + + +
{{ unit.name }}
+
{{ unit.path }}
+
+
+
- - {{ 'excludeParentChanges' | translate }} - - + + Descripción + + - - Información del aula -
- - Localización - - - - Aforo - - - El aforo no puede ser negativo - - - - Calendario Asociado - - - {{ calendar.name }} - - - -
- Proyector - Pizarra -
-
+ + {{ 'excludeParentChanges' | translate }} + + - - Configuración de Red -
- - OgLive - - - {{ oglive.name }} - - - - - Repositorio - - - {{ repository.name }} - - - - - Proxy - - - - DNS - - - - Máscara de Red - - - - Router - - - - NTP - - - - Modo P2P - - - {{ option.name }} - - - - - Tiempo P2P - - - - Mcast IP - - - - Mcast Speed - - - - Mcast Port - - - - Mcast Mode - - - {{ option.name }} - - - - - Menu - - - {{ menu.name }} - - - - - Perfil de Hardware - - {{ unit.description - }} - - Formato de URL incorrecto - -
+ + Información del aula +
+ + Localización + + + + Aforo + + + El aforo no puede ser negativo + + + + Calendario Asociado + + + {{ calendar.name }} + + + +
+ Proyector + Pizarra +
+
- - Información Adicional -
- - Comentarios - - -
-
-
- - + + Configuración de Red +
+ + OgLive + + + {{ oglive.name }} + + + + + Repositorio + + + {{ repository.name }} + + + + + Proxy + + + + DNS + + + + Máscara de Red + + + + Router + + + + NTP + + + + Modo P2P + + + {{ option.name }} + + + + + Tiempo P2P + + + + Mcast IP + + + + Mcast Speed + + + + Mcast Port + + + + Mcast Mode + + + {{ option.name }} + + + + + Menu + + + {{ menu.name }} + + + + + Perfil de Hardware + + {{ unit.description + }} + + Formato de URL incorrecto + +
+ + + Información Adicional +
+ + Comentarios + + +
+
+
+ + +
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts index 53a8360..1e1ea2a 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.spec.ts @@ -11,6 +11,8 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { TranslateModule } from '@ngx-translate/core'; +import { LoadingComponent } from '../../../../../shared/loading/loading.component'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; describe('ManageOrganizationalUnitComponent', () => { let component: ManageOrganizationalUnitComponent; @@ -18,7 +20,7 @@ describe('ManageOrganizationalUnitComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ManageOrganizationalUnitComponent], + declarations: [ManageOrganizationalUnitComponent, LoadingComponent], imports: [ HttpClientTestingModule, ReactiveFormsModule, @@ -29,14 +31,15 @@ describe('ManageOrganizationalUnitComponent', () => { MatSlideToggleModule, MatCheckboxModule, TranslateModule.forRoot(), - BrowserAnimationsModule + BrowserAnimationsModule, + MatProgressSpinnerModule ], providers: [ { provide: MatDialogRef, useValue: {} }, { provide: MAT_DIALOG_DATA, useValue: {} } ] }) - .compileComponents(); + .compileComponents(); fixture = TestBed.createComponent(ManageOrganizationalUnitComponent); component = fixture.componentInstance; diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts index b64a9a9..e99f7d3 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts @@ -43,6 +43,7 @@ export class ManageOrganizationalUnitComponent implements OnInit { ]; @Output() unitAdded = new EventEmitter(); calendars: any; + loading: boolean = false; constructor( private _formBuilder: FormBuilder, @@ -111,6 +112,7 @@ export class ManageOrganizationalUnitComponent implements OnInit { } loadParentUnits() { + this.loading = true; const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=1000`; this.http.get(url).subscribe( response => { @@ -120,8 +122,12 @@ export class ManageOrganizationalUnitComponent implements OnInit { name: unit.name, path: this.dataService.getOrganizationalUnitPath(unit, this.parentUnits) })); + this.loading = false; }, - error => console.error('Error fetching parent units:', error) + error => { + console.error('Error fetching parent units:', error); + this.loading = false; + } ); } @@ -131,64 +137,91 @@ export class ManageOrganizationalUnitComponent implements OnInit { } loadHardwareProfiles(): void { + this.loading = true; this.dataService.getHardwareProfiles().subscribe( (data: any[]) => { this.hardwareProfiles = data; + this.loading = false; }, (error: any) => { console.error('Error fetching hardware profiles', error); + this.loading = false; } ); } loadMenus(): void { + this.loading = true; const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`; this.http.get(url).subscribe( response => { this.menus = response['hydra:member']; + this.loading = false; }, error => { console.error('Error fetching menus:', error); + this.loading = false; } ); } - loadOgLives() { + this.loading = true; this.dataService.getOgLives().subscribe( (data: any[]) => { - this.ogLives = data + this.ogLives = data; + this.loading = false; }, - error => console.error('Error fetching ogLives', error) + error => { + console.error('Error fetching ogLives', error); + this.loading = false; + } ); } loadRepositories() { + this.loading = true; this.dataService.getRepositories().subscribe( - (data: any[]) => this.repositories = data, - error => console.error('Error fetching repositories', error) + (data: any[]) => { + this.repositories = data; + this.loading = false; + }, + error => { + console.error('Error fetching repositories', error); + this.loading = false; + } ); } loadCalendars() { + this.loading = true; const apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=30`; this.http.get(apiUrl).subscribe( - response => this.calendars = response['hydra:member'], + response => { + this.calendars = response['hydra:member']; + this.loading = false; + }, error => { console.error('Error loading calendars', error); this.toastService.error('Error loading current calendar'); + this.loading = false; } ); } loadCurrentCalendar(uuid: string): void { + this.loading = true; const apiUrl = `${this.baseUrl}/remote-calendars/${uuid}`; this.http.get(apiUrl).subscribe( - response => this.currentCalendar = response, + response => { + this.currentCalendar = response; + this.loading = false; + }, error => { console.error('Error loading current calendar', error); this.toastService.error('Error loading current calendar'); + this.loading = false; } ); } @@ -206,6 +239,7 @@ export class ManageOrganizationalUnitComponent implements OnInit { } loadData(uuid: string) { + this.loading = true; const url = `${this.baseUrl}/organizational-units/${uuid}`; this.http.get(url).subscribe( @@ -244,11 +278,13 @@ export class ManageOrganizationalUnitComponent implements OnInit { capacity: data.capacity, remoteCalendar: data.remoteCalendar ? data.remoteCalendar['@id'] : null }); + this.loading = false; }, error => { console.error('Error fetching data for edit:', error); this.toastService.error('Error fetching data'); + this.loading = false; this.onNoClick(); } ); From 27bdcbf98bc3727c5dd64187b61a15db7efe9aa7 Mon Sep 17 00:00:00 2001 From: Nicolas Arenas Date: Mon, 24 Feb 2025 12:26:12 +0100 Subject: [PATCH 09/38] Update angular.json to fix locale issue --- ogWebconsole/angular.json | 2 +- ogWebconsole/src/locale/en-US.json | 465 +++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 ogWebconsole/src/locale/en-US.json diff --git a/ogWebconsole/angular.json b/ogWebconsole/angular.json index f5adc43..aba92ea 100644 --- a/ogWebconsole/angular.json +++ b/ogWebconsole/angular.json @@ -7,7 +7,7 @@ "i18n": { "sourceLocale": "es", "locales": { - "en-US": "src/locale/en.json" + "en-US": "src/locale/en-US.json" } }, "projectType": "application", diff --git a/ogWebconsole/src/locale/en-US.json b/ogWebconsole/src/locale/en-US.json new file mode 100644 index 0000000..1ccfd67 --- /dev/null +++ b/ogWebconsole/src/locale/en-US.json @@ -0,0 +1,465 @@ +{ + "loginlabelUsername": "Enter your username", + "loginlabelPassword": "Enter your password", + "buttonLogin": "Login", + "welcomeMessage": "Welcome {{username}}", + "loginError": "Login error: {{error}}", + "labelUsers": "Users", + "labelRoles": "Roles", + "adminImagesTitle": "Manage images", + "addUser": "Add users", + "searchLabel": "Search image name", + "searchPlaceholder": "Search", + "searchHint": "Press 'enter' to search", + "columnActions": "Actions", + "dialogTitleAddUser": "Add User", + "addUserlabelUsername": "Username", + "addUserlabelPassword": "Password", + "labelRole": "Role", + "labelOrganizationalUnit": "Organizational Unit", + "buttonCancel": "Cancel", + "buttonAdd": "Add", + "addButton": "Add", + "addClientDialogTitle": "Add Client", + "dialogTitleEditUser": "Edit User", + "labelCurrentPassword": "Current password", + "labelNewPassword": "New password", + "labelRepeatPassword": "Repeat password", + "errorPasswordMismatch": "Passwords do not match", + "buttonEdit": "Edit", + "adminRolesTitle": "Manage Roles", + "addRole": "Add role", + "searchRoleLabel": "Search role name", + "dialogTitleAddRole": "Add Role", + "labelRoleName": "Name", + "sectionTitlePermissions": "Permissions:", + "checkboxSuperAdmin": "Super Admin", + "checkboxOrgAdmin": "Organizational Unit Admin", + "checkboxOrgOperator": "Organizational Unit Operator", + "checkboxOrgMinimal": "Minimal Organizational Unit", + "checkboxUserRole": "User", + "groupsTitleStepText": "On this screen, you can manage the main organizational units (Faculties, Classrooms, Classroom Groups, and clients).", + "titleStepText": "On this screen, you can manage the calendars of remote teams connected to the UDS service", + "groupsAddStepText": "Click to add a new organizational unit or client.", + "adminCalendarsTitle": "Manage calendars", + "addButtonStepText": "Click here to add a new calendar.", + "addCalendar": "Add calendar", + "searchStepText": "Use this search bar to filter existing calendars.", + "searchCalendarLabel": "Search calendar name", + "tableStepText": "Here are the existing calendars with their characteristics and settings.", + "actionsStepText": "Access the available actions for each calendar here.", + "editCalendar": "Edit calendar", + "remoteAvailability": "Remote availability?", + "selectWeekDays": "Select the days of the week", + "startTime": "Start time", + "startTimePlaceholder": "Select start time", + "endTime": "End time", + "endTimePlaceholder": "Select end time", + "reasonLabel": "Reason", + "reasonPlaceholder": "Reason for the exception", + "startDate": "Start date", + "endDate": "End date", + "buttonSave": "Save", + "adminCommandGroupsTitle": "Manage Command Groups", + "addCommandGroupStepText": "Click to add a new command group.", + "addCommandGroup": "Add Command Group", + "searchGroupNameLabel": "Search group name", + "loadingStepText": "Wait while the command groups are loading.", + "viewCommands": "View commands", + "paginationStepText": "Navigate between command group pages using the paginator.", + "commandGroupDetailsTitle": "Command Group Details", + "createdBy": "Created by", + "groupId": "Group ID", + "creationDate": "Creation Date", + "includedCommands": "Included Commands", + "nameColumn": "Name", + "selectClients": "Select clients:", + "clientsLabel": "Clients", + "selectAtLeastOneClient": "You must select at least one client.", + "execute": "Execute", + "scheduleExecution": "Schedule Execution", + "editCommandGroup": "Edit command group", + "createCommandGroup": "Create command group", + "groupNameLabel": "Group Name", + "enabledToggle": "Enabled", + "availableCommandsTitle": "Available Commands", + "selectedCommandsTitle": "Selected Commands", + "manageTasksTitle": "Manage Tasks", + "addTaskStepText": "Click to add a new task.", + "addTask": "Add Task", + "searchTaskLabel": "Search task", + "idColumn": "Id", + "infoColumn": "Info", + "createdByColumn": "Created by", + "executionDateColumn": "Execution Date", + "statusColumn": "Status", + "enabled": "Enabled", + "disabled": "Disabled", + "adminCommandsTitle": "Command and procedure traces", + "resetFiltersStepText": "Click to reset the applied filters and see all traces.", + "resetFilters": "Reset filters", + "clientSelectStepText": "Select a client to see the associated traces.", + "filterClientPlaceholder": "Filter by client", + "commandSelectStepText": "Select a command to see the specific traces of that command.", + "filterCommandPlaceholder": "Filter by command", + "taskDetailsTitle": "Task Details", + "taskId": "Task ID", + "status": "Status", + "notes": "Notes", + "includedCommandGroups": "Included Command Groups", + "commandGroupColumn": "Command Group", + "commandsToExecute": "Commands to execute", + "group": "Group", + "commandColumn": "Command", + "editTask": "Edit Task", + "createTask": "Create Task", + "informationSectionTitle": "Information", + "informationLabel": "Information", + "notesPlaceholder": "Enter your notes here", + "commandSelectionSectionTitle": "Command selection", + "selectCommandsLabel": "Select Commands", + "requiredFieldError": "This field is required", + "executionDateTimeSectionTitle": "Execution date and time", + "executionDateLabel": "Execution Date", + "selectDatePlaceholder": "Select a date", + "executionTimeLabel": "Execution Time", + "selectTimePlaceholder": "Select a time", + "destinationSelectionSectionTitle": "Select destination", + "selectOrganizationalUnitLabel": "Select Organizational Unit", + "selectClassroomLabel": "Select Classroom", + "selectAllClients": "Select all", + "addCommand": "Add Command", + "searchCommandLabel": "Search command name", + "executeCommandTitle": "Execute Command", + "subOrganizationalUnitLabel": "Sub-organizational Unit", + "noClientsAvailable": "No clients available", + "buttonExecute": "Execute", + "commandDetailsTitle": "Command Details", + "nameLabel": "Name", + "commentsLabel": "Comments", + "createdByLabel": "Created by", + "creationDateLabel": "Creation Date", + "scriptLabel": "Script", + "selectClientsTitle": "Select clients:", + "selectAtLeastOneClientError": "You must select at least one client.", + "editCommandTitle": "Edit Command", + "createCommandTitle": "Create Command", + "commandNamePlaceholder": "Command name", + "commandScriptPlaceholder": "Command script", + "readOnlyLabel": "Read only", + "enabledLabel": "Enabled", + "cancelButton": "Cancel", + "saveButton": "Save", + "generalTabLabel": "General", + "tabsStepText": "Use the tabs to access different viewing and search options for organizational units and clients.", + "adminGroupsTitle": "Manage groups", + "newOrganizationalUnitTooltip": "Open modal to create organizational units of any type (Center, Classroom, Classroom Group, or Client Group)", + "newOrganizationalUnitButton": "New Organizational Unit", + "newClientButton": "New Client", + "newSingleClientButton": "Add single client", + "newMultipleClientButton": "Add numerous clients", + "keyStepText": "The legend will show you the types of organizational units and their corresponding icons", + "legendButton": "Legend", + "unitStepText": "This is the section where 'Center' type organizational units will be displayed", + "organizationalUnitTitle": "Centers", + "elementsStepText": "This is the section to view internal units of the selected center and navigate through them.", + "internalElementsTitle": "Internal elements", + "noInternalElementsMessage": "No internal elements", + "viewTreeTooltip": "View unit as a tree", + "viewTreeMenu": "View organizational chart", + "editUnitTooltip": "Edit this organizational unit", + "viewUnitTooltip": "View organizational unit details", + "viewUnitMenu": "View data", + "addInternalUnitTooltip": "Create a new internal organizational unit", + "addClientTooltip": "Register a client in this organizational unit", + "deleteElementTooltip": "Delete this element", + "deleteElementMenu": "Delete element", + "executeCommandTooltip": "Execute command on this element", + "advancedSearchTabLabel": "Advanced search", + "clientsTabLabel": "Clients", + "organizationalUnitsTabLabel": "Organizational units", + "viewTreeTitle": "View organizational unit tree", + "toggleNodeAriaLabel": "Toggle node", + "closeButton": "Close", + "inputDetails": "Input details", + "excludeParentChanges": "Exclude parent changes", + "orgUnitPropertiesTitle": "Organizational unit properties", + "generalDataTab": "General data", + "propertyHeader": "Property", + "valueHeader": "Value", + "classroomNetworkPropertiesTab": "Classroom and network properties", + "editOrgUnitTitle": "Edit Organizational Unit", + "generalStepLabel": "General", + "typeLabel": "Type", + "editOrgUnitParentLabel": "Parent", + "descriptionLabel": "Description", + "nextButton": "Next", + "classroomInfoStepLabel": "Classroom Information", + "locationLabel": "Location", + "projectorToggle": "Projector", + "boardToggle": "Board", + "capacityLabel": "Capacity", + "associatedCalendarLabel": "Associated Calendar", + "backButton": "Back", + "additionalInfoStepLabel": "Additional Information", + "networkSettingsStepLabel": "Network Settings", + "proxyUrlLabel": "Proxy server URL", + "dnsIpLabel": "DNS server IP", + "netmaskLabel": "Netmask", + "routerLabel": "Router", + "ntpIpLabel": "NTP server IP", + "p2pModeLabel": "P2P Mode", + "p2pTimeLabel": "P2P Time", + "mcastIpLabel": "Multicast IP", + "mcastSpeedLabel": "Multicast Speed", + "mcastPortLabel": "Multicast Port", + "mcastModeLabel": "Multicast Mode", + "menuUrlLabel": "Menu URL", + "menuLabel": "Menu", + "hardwareProfileLabel": "Hardware Profile", + "urlFormatError": "Invalid URL format.", + "validationToggle": "Validation", + "addOUSubmitButton": "Add", + "editOUSubmitButton": "Edit", + "addOrgUnitTitle": "Add Organizational Unit", + "createOrgUnitparentLabel": "Parent organizational unit", + "noParentOption": "--", + "nextServerLabel": "NextServer", + "bootFileNameLabel": "bootFileName", + "orgUnitTitle": "Organizational unit", + "classroomGroupsTitle": "Classroom groups", + "classroomTitle": "Classroom", + "clientGroupsTitle": "Client groups", + "clientTitle": "Client", + "executeCommandOrGroupTitle": "Execute Command or Command Group", + "selectCommandLabel": "Select Command", + "selectCommandGroupLabel": "Select Command Group", + "noClientsMessage": "No clients available", + "editClientDialogTitle": "Edit Client", + "organizationalUnitLabel": "Parent", + "ogLiveLabel": "OgLive", + "serialNumberLabel": "Serial Number", + "netifaceLabel": "Network interface", + "netDriverLabel": "Network driver", + "macLabel": "MAC", + "macError": "Invalid MAC format. Valid example: 00:11:22:33:44:55", + "ipLabel": "IP Address", + "ipError": "Invalid IP address format. Valid example: 127.0.0.1", + "templateLabel": "PXE Template", + "digitalBoard": "Digital board", + "projectorAlt": "Projector", + "clientAlt": "Client", + "saveDispositionButton": "Save disposition", + "actionsModalTitle": "Actions", + "adminOuTitle": "Manage organizational units", + "resetFiltersButton": "Reset filters", + "addOUButton": "Add OU", + "searchLabelOu": "Search OU name", + "macHint": "Example: 00:11:22:33:44:55", + "ipHint": "Example: 123.1.1.1", + "allOption": "All", + "centerOption": "Center", + "classroomsGroupOption": "Classroom Groups", + "classroomOption": "Classroom", + "clientsGroupOption": "PC Groups", + "roomMapOption": "Classroom map", + "clientDetailsTitle": "Client details", + "commandsButton": "Commands", + "networkPropertiesTab": "Network properties", + "disksPartitionsTitle": "Disks/Partitions", + "diskTitle": "Disk", + "diskUsedLabel": "Used", + "diskTotalLabel": "Total", + "diskImageAssistantTitle": "Disk image assistant", + "deployImage": "Deploy image", + "partitionColumn": "Partition", + "isoImageColumn": "ISO Image", + "ogliveColumn": "OgLive", + "selectImageOption": "Select image", + "selectOgLiveOption": "Select OgLive", + "repositoryTitle": "Admin Repository", + "saveAssociationsButton": "Save Associations", + "partitionAssistantTitle": "Partition assistant", + "diskSizeLabel": "Size", + "partitionTypeColumn": "Partition type", + "partitionSizeColumn": "Size (MB)", + "usageColumn": "Usage (%)", + "formatColumn": "Format", + "remotePcLabel": "Remote PC", + "globalImageLabel": "Global image", + "ntfsOption": "NTFS", + "linuxOption": "LINUX", + "cacheOption": "CACHE", + "deleteButton": "Delete", + "searchTitle": "Advanced search", + "selectFilterLabel": "Select filter", + "gridViewButton": "Grid", + "listViewButton": "List", + "selectOptionLabel": "Select an option", + "namePlaceholder": "Organizational unit", + "selectAllButton": "Select/Deselect All", + "saveFiltersButton": "Save Filters", + "sendFiltersButton": "Send Action", + "addPxeButton": "Add PXE file", + "repositoryLabel": "Repositories", + "internalUnits": "Internal units", + "imageNameLabel": "Image name", + "noResultsMessage": "No results to display.", + "imagesTitle": "Manage images", + "addImageButton": "Add image", + "searchNameDescription": "Search images by name to quickly find a specific image.", + "searchDefaultDescription": "Filter images to show only default or non-default images.", + "searchDefaultLabel": "Default image", + "searchInstalledDescription": "Filter images to show only those installed on the OgBoot server.", + "searchInstalledLabel": "Installed on OgBoot server", + "tableDescription": "Here is the list of available images to manage.", + "actionsColumnHeader": "Actions", + "viewIcon": "visibility", + "editIcon": "edit", + "installOption": "Install", + "uninstallOption": "Uninstall", + "setDefaultOption": "Set as default image", + "paginationDescription": "Navigate between image pages using the paginator.", + "detailsTitle": "Details of {{ name }}", + "editTemplateTitle": "Edit template", + "addTemplateTitle": "Add template", + "templateNameLabel": "Template Name", + "templateNamePlaceholder": "Enter the template name", + "templateContentPlaceholder": "Enter the template content", + "loadTemplateModelButton": "Load model template", + "diskModel": "Disk boot", + "createButton": "Create", + "manageClientsTitle": "Manage clients", + "syncIcon": "sync", + "addClientsTitle": "Add clients to {{ subnetName }}", + "selectedClientsTitle": "Selected clients:", + "editClientTitle": "Edit Client", + "addClientTitle": "Add Client", + "advancedNetbootTitle": "Advanced netboot", + "selectUnitLabel": "Select Organizational Unit", + "loadingUnitsOption": "Loading units...", + "selectClassLabel": "Select classroom", + "applyToAllLabel": "Select template to apply to all clients", + "saveButtonLabel": "Save", + "idColumnHeader": "Id", + "nameColumnHeader": "Name", + "templateColumnHeader": "Template", + "pxeImageTitle": "Information on ogBoot server", + "serverInfoDescription": "Access information and synchronization options on the OgBoot server.", + "syncDatabaseButton": "Sync database", + "viewInfoButton": "View Information", + "adminImagesDescription": "From here you can manage the images configured on the OgBoot server.", + "actionsDescription": "Manage each image with options to view, edit, delete, and more.", + "addClientButton": "Add client", + "searchClientNameLabel": "Search client name", + "searchIPLabel": "Search IP", + "searchMACLabel": "Search MAC", + "diskUsageTitle": "Disk Usage", + "ogBootServerStatus": "OgBoot Server Status", + "servicesTitle": "Services", + "Legend": "Legend", + "totalLabel": "Total", + "usedLabel": "Used", + "freeLabel": "Free", + "availableLabel": "Available", + "InstalledOglivesTitle": "Installed OgLives", + "idLabel": "ID", + "KernelLabel": "Kernel", + "architectureLabel": "Architecture", + "revisionLabel": "Revision", + "serverInfoTitle": "Server Information", + "adminPxeTitle": "Manage PXE Files", + "createdOgBootLabel": "Created in OgBoot", + "selectOptionPlaceholder": "Select an option", + "yesOption": "Yes", + "noOption": "No", + "actionsColumn": "Actions", + "createServerButton": "Create Server", + "labelName": "Name", + "diskUsageDescription": "Here is the disk usage of the server.", + "servicesStatusDescription": "Here is the status of the server services.", + "oglivesDescription": "Here are the OgLives installed on the server.", + "addImageButtonDescription": "Click to add a new image.", + "adminPxeDescription": "From here you can manage the PXE templates of the server.", + "addTemplateButtonDescription": "Add PXE Template", + "addTemplateButton": "Add Template", + "searchSyncDescription": "Filter PXE templates to show only synchronized or unsynchronized ones.", + "advancedNetbootDescription": "From here you can configure the advanced netboot of the clients.", + "selectUnitDescription": "Select the organizational unit to which the clients belong.", + "selectClassDescription": "Select the classroom to which the clients belong.", + "applyToAllDescription": "Select a template to apply to all clients.", + "saveButtonDescription": "Save the changes made.", + "welcomeUser": "Welcome {{username}}", + "TOOLTIP_WELCOME_USER": "Welcome, {{username}}", + "groups": "Groups", + "TOOLTIP_GROUPS": "Manage user groups", + "actions": "Actions", + "TOOLTIP_ACTIONS": "View and execute predefined actions", + "commands": "Commands", + "TOOLTIP_COMMANDS": "List of available commands", + "commandGroups": "Groups", + "TOOLTIP_COMMAND_GROUPS": "Manage command groups", + "tasks": "Tasks", + "TOOLTIP_TASKS": "View and manage scheduled tasks", + "dhcp": "DHCP", + "TOOLTIP_DHCP": "Configure and manage DHCP", + "TOOLTIP_DHCP_STATUS": "Current status of the DHCP service", + "subnets": "Subnets", + "TOOLTIP_SUBNETS": "Manage and create subnets", + "boot": "Boot", + "TOOLTIP_BOOT": "Configure and manage boot options", + "ogLive": "ogLive", + "TOOLTIP_PXE_IMAGES": "View available PXE boot images", + "pxeTemplates": "PXE Templates", + "pxeTemplate" : "Plantilla", + "TOOLTIP_PXE_TEMPLATES": "Manage PXE boot templates", + "pxeBootFiles": "PXE Boot Files", + "TOOLTIP_PXE_BOOT_FILES": "Configure PXE boot files", + "calendars": "Calendars", + "TOOLTIP_CALENDARS": "Manage remotePC calendars", + "software": "Software", + "TOOLTIP_SOFTWARE": "Manage software configurations", + "softwareList": "List", + "TOOLTIP_SOFTWARE_LIST": "View list of available software", + "softwareProfiles": "Profiles", + "TOOLTIP_SOFTWARE_PROFILES": "Manage software profiles", + "operativeSystems": "Operating Systems", + "TOOLTIP_OPERATIVE_SYSTEMS": "Configure operating systems", + "images": "Images", + "TOOLTIP_IMAGES": "Manage system images", + "repositories": "Repositories", + "TOOLTIP_REPOSITORIES": "View and manage software repositories", + "menus": "Menus", + "TOOLTIP_MENUS": "Menu management (option disabled)", + "search": "Search", + "TOOLTIP_SEARCH": "Search function (option disabled)", + "detailsOf": "Details of", + "editUnitMenu": "Edit", + "addInternalUnitMenu": "Add", + "addClientMenu": "Add client", + "filters": "Filters", + "searchClient": "Search client", + "searchTree": "Search organizational unit", + "filterByType": "Filter by type", + "all": "All", + "classroomsGroup": "Classroom groups", + "classrooms": "Classrooms", + "computerGroups": "PC groups", + "executeCommand": "Execute command", + "roomMap": "Classroom map", + "addOrganizationalUnit": "Add organizational unit", + "edit": "Edit", + "delete": "Delete", + "clients": "Clients", + "sync": "Sync", + "viewDetails": "View details", + "name": "Name", + "maintenance": "Maintenance", + "subnet": "Subnet", + "parent": "Parent", + "adminUsersTitle": "Manage users", + "filtersPanelStepText": "Use these filters to search or load configurations.", + "organizationalUnitsStepText": "List of Organizational Units. Click on one to view details.", + "defaultMenuLabel": "Main menu", + "noClients": "No clients" +} From e7d99be6c232e692448e9a2edde013c13104f019 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 25 Feb 2025 12:15:26 +0000 Subject: [PATCH 10/38] First version of debian packge for oggui --- DEBIAN/changelog | 5 ++++ DEBIAN/control | 9 +++++++ DEBIAN/copyright | 21 +++++++++++++++++ DEBIAN/postinst | 40 ++++++++++++++++++++++++++++++++ DEBIAN/postrm | 32 +++++++++++++++++++++++++ DEBIAN/preinst | 15 ++++++++++++ bin/start-oggui.sh | 34 +++++++++++++++++++++++++++ etc/nginx/oggui.conf | 19 +++++++++++++++ etc/systemd/system/oggui.service | 14 +++++++++++ var/lib/oggui/oggui.config.hash | 1 + 10 files changed, 190 insertions(+) create mode 100644 DEBIAN/changelog create mode 100644 DEBIAN/control create mode 100644 DEBIAN/copyright create mode 100644 DEBIAN/postinst create mode 100755 DEBIAN/postrm create mode 100644 DEBIAN/preinst create mode 100644 bin/start-oggui.sh create mode 100644 etc/nginx/oggui.conf create mode 100644 etc/systemd/system/oggui.service create mode 100644 var/lib/oggui/oggui.config.hash diff --git a/DEBIAN/changelog b/DEBIAN/changelog new file mode 100644 index 0000000..65d538d --- /dev/null +++ b/DEBIAN/changelog @@ -0,0 +1,5 @@ +oggui (1.0) unstable; urgency=low + + * Initial release. + + -- Your Name Thu, 01 Jan 1970 00:00:00 +0000 diff --git a/DEBIAN/control b/DEBIAN/control new file mode 100644 index 0000000..3bd121f --- /dev/null +++ b/DEBIAN/control @@ -0,0 +1,9 @@ +Package: oggui +Version: %%VERSION%% +Section: base +Priority: optional +Architecture: all +Depends: nginx , npm , nodejs +Maintainer: Nicolas Arenas +Description: Description of the ogcore package + This is a longer description of the ogcore package. diff --git a/DEBIAN/copyright b/DEBIAN/copyright new file mode 100644 index 0000000..97ef204 --- /dev/null +++ b/DEBIAN/copyright @@ -0,0 +1,21 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ogcore +Source: + +Files: * +Copyright: 2023 Your Name +License: GPL-3+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. diff --git a/DEBIAN/postinst b/DEBIAN/postinst new file mode 100644 index 0000000..393ab12 --- /dev/null +++ b/DEBIAN/postinst @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +# Asegurarse de que el usuario exista +USER="opengnsys" +HASH_FILE="/opt/opengnsys/oggui/var/lib/oggui/oggui.config.hash" +CONFIG_FILE="/opt/opengnsys/oggui/src/.env" + +# Provisionar base de datos si es necesario en caso de instalación. + + +# Detectar si es una instalación nueva o una actualización +if [ "$1" = "configure" ] && [ -z "$2" ]; then + cd /opt/opengnsys/oggui/src/ + npm install -g @angular/cli + npm install + /usr/local/bin/ng build --base-href=/ --output-path=dist/oggui --optimization=true --configuration=production --localize=false + cp -pr /opt/opengnsys/oggui/src/dist/oggui/browser/* /opt/opengnsys/oggui/browser/ + md5sum "$CONFIG_FILE" > "$HASH_FILE" + ln -s /opt/opengnsys/oggui/etc/systemd/system/oggui.service /etc/systemd/system/oggui.service + systemctl daemon-reload + systemctl enable oggui +elif [ "$1" = "configure" ] && [ -n "$2" ]; then + cd /opt/opengnsys/oggui + echo "Actualización desde la versión $2" +fi + +# Cambiar la propiedad de los archivos al usuario especificado +chown opengnsys:www-data /opt/opengnsys/ +chown -R opengnsys:www-data /opt/opengnsys/oggui +# Install http server stuff +ln -s /opt/opengnsys/oggui/etc/nginx/oggui.conf /etc/nginx/sites-enabled/oggui.conf +# Reiniciar servicios si es necesario +# systemctl restart nombre_del_servicio + +systemctl daemon-reload +systemctl restart nginx + +exit 0 diff --git a/DEBIAN/postrm b/DEBIAN/postrm new file mode 100755 index 0000000..6581225 --- /dev/null +++ b/DEBIAN/postrm @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + + +NGINX_FILE="/etc/nginx/sites-enabled/oggui.conf" +UNIT_FILE="/etc/systemd/system/oggui.service" + + +case "$1" in + remove) + echo "El paquete se está desinstalando..." + # Aquí puedes hacer limpieza de archivos o servicios + if [ -L "$NGINX_FILE" ]; then + rm -f "$NGINX_FILE" + systemctl restart nginx + fi + if [ -L "$UNIT_FILE" ]; then + rm -f "$UNIT_FILE" + systemctl daemon-reload + fi + ;; + purge) + echo "Eliminando configuración residual..." + ;; + + upgrade) + echo "Actualizando paquete..." + ;; +esac + +exit 0 diff --git a/DEBIAN/preinst b/DEBIAN/preinst new file mode 100644 index 0000000..dc60472 --- /dev/null +++ b/DEBIAN/preinst @@ -0,0 +1,15 @@ +#!/bin/bash + +set -e + +# Asegurarse de que el usuario exista +USER="opengnsys" +HOME_DIR="/opt/opengnsys" +if id "$USER" &>/dev/null; then + echo "El usuario $USER ya existe." +else + echo "Creando el usuario $USER con home en $HOME_DIR." + useradd -m -d "$HOME_DIR" -s /bin/bash "$USER" +fi + +exit 0 \ No newline at end of file diff --git a/bin/start-oggui.sh b/bin/start-oggui.sh new file mode 100644 index 0000000..525c90b --- /dev/null +++ b/bin/start-oggui.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -e + +CONFIG_FILE="/opt/opengnsys/oggui/src/.env" +HASH_FILE="/opt/opengnsys/oggui/var/lib/oggui/oggui.config.hash" +APP_DIR="/opt/opengnsys/oggui/browser" +SRC_DIR="/opt/opengnsys/oggui/src" +COMPILED_DIR=$SRC_DIR/dist +NGINX_SERVICE="nginx" + +# Verificar si el archivo de configuración cambió +if [ -f "$CONFIG_FILE" ] && [ -f "$HASH_FILE" ]; then + OLD_HASH=$(cat "$HASH_FILE") + NEW_HASH=$(md5sum "$CONFIG_FILE") + + if [ "$OLD_HASH" != "$NEW_HASH" ]; then + echo "🔄 Cambios detectados en $CONFIG_FILE, recompilando Angular..." + cd "$SRC_DIR" + npm install -g @angular/cli + npm install + /usr/local/bin/ng build --base-href=/ --output-path=dist/oggui --optimization=true --configuration=production --localize=false + md5sum "$CONFIG_FILE" > "$HASH_FILE" + exit 0 + else + echo "No hay cambios en $CONFIG_FILE, no es necesario recompilar." + exit 0 + fi +else + echo "Archivo de configuración no encontrado o sin hash previo. No se recompilará." + exit 1 +fi + +# Iniciar Nginx +systemctl restart "$NGINX_SERVICE" \ No newline at end of file diff --git a/etc/nginx/oggui.conf b/etc/nginx/oggui.conf new file mode 100644 index 0000000..e036513 --- /dev/null +++ b/etc/nginx/oggui.conf @@ -0,0 +1,19 @@ +server { + listen 4200; + server_name localhost; + + root /opt/opengnsys/oggui/browser; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + # Manejo de archivos estáticos + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + try_files $uri =404; + } + + # Configuración para evitar problemas con rutas de Angular + error_page 404 /index.html; +} \ No newline at end of file diff --git a/etc/systemd/system/oggui.service b/etc/systemd/system/oggui.service new file mode 100644 index 0000000..8a75041 --- /dev/null +++ b/etc/systemd/system/oggui.service @@ -0,0 +1,14 @@ +[Unit] +Description=Aplicación Angular con Nginx +After=network.target + +[Service] +Type=simple +ExecStart=/opt/opengnsys/oggui/bin/start-oggui.sh +Restart=always +User=www-data +WorkingDirectory=/var/www/mi-aplicacion +Environment=NODE_ENV=production + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/var/lib/oggui/oggui.config.hash b/var/lib/oggui/oggui.config.hash new file mode 100644 index 0000000..5111af2 --- /dev/null +++ b/var/lib/oggui/oggui.config.hash @@ -0,0 +1 @@ +986d3c82e05e6ac6d5355aafa1f65148 .env From f0e3a34f006fa13f675861b85b799ad670c19c7a Mon Sep 17 00:00:00 2001 From: Nicolas Arenas Date: Tue, 25 Feb 2025 13:17:34 +0100 Subject: [PATCH 11/38] Update angular.json --- ogWebconsole/angular.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogWebconsole/angular.json b/ogWebconsole/angular.json index aba92ea..81328fa 100644 --- a/ogWebconsole/angular.json +++ b/ogWebconsole/angular.json @@ -7,7 +7,7 @@ "i18n": { "sourceLocale": "es", "locales": { - "en-US": "src/locale/en-US.json" + "en": "src/locale/en.json" } }, "projectType": "application", From 9c121a30279481ba11d3922a3261f36c19c807d2 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 26 Feb 2025 08:42:13 +0100 Subject: [PATCH 12/38] refs #1559. Refactor ogdhcp UX --- ogWebconsole/src/app/app-routing.module.ts | 6 +- ogWebconsole/src/app/app.module.ts | 16 +-- .../components/groups/groups.component.css | 12 +-- .../components/groups/groups.component.html | 32 +++--- .../app/components/groups/groups.component.ts | 2 +- .../src/app/components/groups/model/model.ts | 2 + .../manage-organizational-unit.component.html | 10 +- .../manage-organizational-unit.component.ts | 7 ++ .../app/components/images/images.component.ts | 3 - .../pxe-boot-files.component.ts | 1 - .../ogboot/pxe-images/pxe-images.component.ts | 3 +- .../components/ogboot/pxe/pxe.component.ts | 2 +- .../add-clients-to-subnet.component.css | 0 .../add-clients-to-subnet.component.html | 0 .../add-clients-to-subnet.component.ts | 34 ++++--- .../create-subnet/create-subnet.component.css | 0 .../create-subnet.component.html | 0 .../create-subnet/create-subnet.component.ts | 2 +- .../og-dhcp-subnets.component.css | 0 .../og-dhcp-subnets.component.html | 9 +- .../og-dhcp-subnets.component.spec.ts | 2 +- .../og-dhcp-subnets.component.ts | 19 +++- .../components/ogdhcp/ogdhcp.component.css | 0 .../components/ogdhcp/ogdhcp.component.html | 1 - .../ogdhcp/ogdhcp.component.spec.ts | 23 ----- .../app/components/ogdhcp/ogdhcp.component.ts | 10 -- .../server-info-dialog.component.css | 0 .../server-info-dialog.component.html | 0 .../server-info-dialog.component.spec.ts | 0 .../server-info-dialog.component.ts | 0 .../show-clients/show-clients.component.css | 97 +++++++++++++++++++ .../show-clients/show-clients.component.html | 75 ++++++++++++++ .../show-clients.component.spec.ts | 72 ++++++++++++++ .../show-clients/show-clients.component.ts | 73 ++++++++++++++ .../status/status.component.css | 0 .../status/status.component.html | 0 .../status/status.component.spec.ts | 2 +- .../status/status.component.ts | 0 .../main-repository-view.component.ts | 4 +- .../repository-images.component.ts | 3 +- 40 files changed, 412 insertions(+), 110 deletions(-) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/add-clients-to-subnet/add-clients-to-subnet.component.css (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/add-clients-to-subnet/add-clients-to-subnet.component.html (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/add-clients-to-subnet/add-clients-to-subnet.component.ts (67%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/create-subnet/create-subnet.component.css (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/create-subnet/create-subnet.component.html (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/create-subnet/create-subnet.component.ts (97%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/og-dhcp-subnets.component.css (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/og-dhcp-subnets.component.html (94%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/og-dhcp-subnets.component.spec.ts (97%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/og-dhcp-subnets.component.ts (93%) delete mode 100644 ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.css delete mode 100644 ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.html delete mode 100644 ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.spec.ts delete mode 100644 ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.ts rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/server-info-dialog/server-info-dialog.component.css (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/server-info-dialog/server-info-dialog.component.html (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/server-info-dialog/server-info-dialog.component.spec.ts (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/server-info-dialog/server-info-dialog.component.ts (100%) create mode 100644 ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css create mode 100644 ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html create mode 100644 ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts create mode 100644 ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/status/status.component.css (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/status/status.component.html (100%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/status/status.component.spec.ts (96%) rename ogWebconsole/src/app/components/ogdhcp/{og-dhcp-subnets => }/status/status.component.ts (100%) diff --git a/ogWebconsole/src/app/app-routing.module.ts b/ogWebconsole/src/app/app-routing.module.ts index c87b1d9..241d28a 100644 --- a/ogWebconsole/src/app/app-routing.module.ts +++ b/ogWebconsole/src/app/app-routing.module.ts @@ -13,14 +13,11 @@ import { PXEimagesComponent } from './components/ogboot/pxe-images/pxe-images.co import { PxeComponent } from './components/ogboot/pxe/pxe.component'; import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component'; import {OgbootStatusComponent} from "./components/ogboot/ogboot-status/ogboot-status.component"; -import { OgdhcpComponent } from './components/ogdhcp/ogdhcp.component'; -import { OgDhcpSubnetsComponent } from './components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component'; import { CalendarComponent } from "./components/calendar/calendar.component"; import { CommandsComponent } from './components/commands/main-commands/commands.component'; import { CommandsGroupsComponent } from './components/commands/commands-groups/commands-groups.component'; import { CommandsTaskComponent } from './components/commands/commands-task/commands-task.component'; import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; -import { StatusComponent } from "./components/ogdhcp/og-dhcp-subnets/status/status.component"; import { ClientMainViewComponent } from './components/groups/components/client-main-view/client-main-view.component'; import { ImagesComponent } from './components/images/images.component'; import {SoftwareComponent} from "./components/software/software.component"; @@ -41,6 +38,8 @@ import { } from "./components/repositories/main-repository-view/main-repository-view.component"; import {EnvVarsComponent} from "./components/admin/env-vars/env-vars.component"; import {MenusComponent} from "./components/menus/menus.component"; +import {OgDhcpSubnetsComponent} from "./components/ogdhcp/og-dhcp-subnets.component"; +import {StatusComponent} from "./components/ogdhcp/status/status.component"; const routes: Routes = [ { path: '', redirectTo: 'auth/login', pathMatch: 'full' }, { path: '', component: MainLayoutComponent, @@ -55,7 +54,6 @@ const routes: Routes = [ { path: 'pxe', component: PxeComponent }, { path: 'pxe-boot-file', component: PxeBootFilesComponent }, { path: 'ogboot-status', component: OgbootStatusComponent }, - { path: 'dhcp', component: OgdhcpComponent }, { path: 'subnets', component: OgDhcpSubnetsComponent }, { path: 'ogdhcp-status', component: StatusComponent }, { path: 'commands', component: CommandsComponent }, diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 7af2819..13805e0 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -75,10 +75,6 @@ import { MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component'; import { CreatePxeBootFileComponent } from './components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component'; import { NgxChartsModule } from '@swimlane/ngx-charts'; -import { OgdhcpComponent } from './components/ogdhcp/ogdhcp.component'; -import { OgDhcpSubnetsComponent } from './components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component'; -import { CreateSubnetComponent } from './components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component'; -import { AddClientsToSubnetComponent } from './components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component'; import { CommandsComponent } from './components/commands/main-commands/commands.component'; import { CommandDetailComponent } from './components/commands/main-commands/detail-command/command-detail.component'; import { CreateCommandComponent } from './components/commands/main-commands/create-command/create-command.component'; @@ -95,8 +91,6 @@ import { DetailCommandGroupComponent } from './components/commands/commands-grou import { CreateTaskComponent } from './components/commands/commands-task/create-task/create-task.component'; import { DetailTaskComponent } from './components/commands/commands-task/detail-task/detail-task.component'; import { TaskLogsComponent } from './components/commands/commands-task/task-logs/task-logs.component'; -import { ServerInfoDialogComponent } from './components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component'; -import { StatusComponent } from './components/ogdhcp/og-dhcp-subnets/status/status.component'; import { MatSliderModule } from '@angular/material/slider'; import { ClientMainViewComponent } from './components/groups/components/client-main-view/client-main-view.component'; import { ImagesComponent } from './components/images/images.component'; @@ -131,6 +125,13 @@ import { RepositoryImagesComponent } from './components/repositories/repository- import { InputDialogComponent } from './components/commands/commands-task/task-logs/input-dialog/input-dialog.component'; import { ManageOrganizationalUnitComponent } from './components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component'; import { BackupImageComponent } from './components/repositories/backup-image/backup-image.component'; +import {ServerInfoDialogComponent} from "./components/ogdhcp/server-info-dialog/server-info-dialog.component"; +import {StatusComponent} from "./components/ogdhcp/status/status.component"; +import {OgDhcpSubnetsComponent} from "./components/ogdhcp/og-dhcp-subnets.component"; +import {CreateSubnetComponent} from "./components/ogdhcp/create-subnet/create-subnet.component"; +import {AddClientsToSubnetComponent} from "./components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component"; +import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component'; +import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http, './locale/', '.json'); } @@ -169,7 +170,6 @@ export function HttpLoaderFactory(http: HttpClient) { PxeBootFilesComponent, OgbootStatusComponent, CreatePxeBootFileComponent, - OgdhcpComponent, OgDhcpSubnetsComponent, CreateSubnetComponent, AddClientsToSubnetComponent, @@ -218,6 +218,8 @@ export function HttpLoaderFactory(http: HttpClient) { InputDialogComponent, ManageOrganizationalUnitComponent, BackupImageComponent, + ShowClientsComponent, + OperationResultDialogComponent, ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index 97a7e90..a010ddc 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -359,9 +359,9 @@ mat-tree mat-tree-node.disabled:hover { } .client-image { - width: 60px; - height: 60px; - margin-bottom: 15px; + max-width: 30px !important; + max-height: 30px !important; + height: auto; } .client-name { @@ -500,7 +500,7 @@ mat-tree mat-tree-node.disabled:hover { display: flex; flex-direction: column; } - + } .clients-title-name { @@ -530,7 +530,7 @@ mat-button-toggle-group { } .mat-button-toggle-group .mat-button-toggle { - height: 36px; + height: 36px; background-color: #3f51b5; color: white; border: none; @@ -568,4 +568,4 @@ mat-button-toggle-group { .mat-button-toggle-group .mat-button-toggle.mat-button-toggle-disabled { background-color: #c7c7c7; -} \ No newline at end of file +} diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 6a7420d..5d4c18d 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -264,28 +264,18 @@ - - {{ 'sync' | translate }} - - - - - - {{ 'name' | translate }} -
-
{{ client.name }}
-
{{ client.ip }}
-
{{ client.mac }}
-
+ {{ client.name }} + +
+ + IP + + {{ client.ip }} @@ -328,6 +318,10 @@ visibility {{ 'viewDetails' | translate }} +
- \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index dcdc0fd..fe77fa4 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -62,7 +62,7 @@ export class GroupsComponent implements OnInit, OnDestroy { private originalTreeData: TreeNode[] = []; arrayClients: any[] = []; - displayedColumns: string[] = ['select', 'status', 'sync', 'name', 'oglive', 'subnet', 'pxeTemplate', 'actions']; + displayedColumns: string[] = ['select', 'status', 'ip', 'name', 'oglive', 'subnet', 'pxeTemplate', 'actions']; private _sort!: MatSort; private _paginator!: MatPaginator; diff --git a/ogWebconsole/src/app/components/groups/model/model.ts b/ogWebconsole/src/app/components/groups/model/model.ts index aaa5b3e..96ce710 100644 --- a/ogWebconsole/src/app/components/groups/model/model.ts +++ b/ogWebconsole/src/app/components/groups/model/model.ts @@ -36,6 +36,8 @@ export interface Client { "@type": string; id: number; name: string; + ogLive: any; + pxtTemplate: any; type: string; serialNumber: string; netiface: string; diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html index c5a785f..95fedc9 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.html @@ -101,6 +101,14 @@ Máscara de Red + + Interfaz de red + + + {{ type.name }} + + + Router @@ -174,4 +182,4 @@ [disabled]="!generalFormGroup.valid || !additionalInfoFormGroup.valid || !networkSettingsFormGroup.valid">{{ isEditMode ? 'Editar' : 'Crear' }} - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts index e99f7d3..d7482a1 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component.ts @@ -41,6 +41,11 @@ export class ManageOrganizationalUnitComponent implements OnInit { { "name": 'Half duplex', "value": "half" }, { "name": 'Full duplex', "value": "full" }, ]; + protected netifaceTypes = [ + { name: 'Eth0', value: 'eth0' }, + { name: 'Eth1', value: 'eth1' }, + { name: 'Eth2', value: 'eth2' } + ]; @Output() unitAdded = new EventEmitter(); calendars: any; loading: boolean = false; @@ -75,6 +80,7 @@ export class ManageOrganizationalUnitComponent implements OnInit { netmask: [null], router: [null], ntp: [null], + netiface: [null], p2pMode: [null], p2pTime: [null], mcastIp: [null], @@ -260,6 +266,7 @@ export class ManageOrganizationalUnitComponent implements OnInit { netmask: data.networkSettings.netmask, router: data.networkSettings.router, ntp: data.networkSettings.ntp, + netiface: data.networkSettings.netiface, p2pMode: data.networkSettings.p2pMode, p2pTime: data.networkSettings.p2pTime, mcastIp: data.networkSettings.mcastIp, diff --git a/ogWebconsole/src/app/components/images/images.component.ts b/ogWebconsole/src/app/components/images/images.component.ts index 28e41a7..d59a887 100644 --- a/ogWebconsole/src/app/components/images/images.component.ts +++ b/ogWebconsole/src/app/components/images/images.component.ts @@ -5,11 +5,8 @@ import { MatTableDataSource } from '@angular/material/table'; import { ToastrService } from 'ngx-toastr'; import { DatePipe } from '@angular/common'; import { CreateImageComponent } from './create-image/create-image.component'; -import {DeleteModalComponent} from "../../shared/delete_modal/delete-modal/delete-modal.component"; -import {ServerInfoDialogComponent} from "../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; import {Observable} from "rxjs"; import { JoyrideService } from 'ngx-joyride'; -import {ExportImageComponent} from "./export-image/export-image.component"; @Component({ selector: 'app-images', diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.ts b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.ts index 1d039f2..8fc85f0 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/pxe-boot-files.component.ts @@ -4,7 +4,6 @@ import { HttpClient } from '@angular/common/http'; import { ToastrService } from 'ngx-toastr'; import { PageEvent } from '@angular/material/paginator'; import {Observable} from "rxjs"; -import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; import { JoyrideService } from 'ngx-joyride'; @Component({ diff --git a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts index 9999831..5b1ea3a 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe-images/pxe-images.component.ts @@ -9,10 +9,9 @@ import {ToastrService} from "ngx-toastr"; import { DatePipe } from "@angular/common"; import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component'; import {DataService} from "./data.service"; -import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; -import {ShowTemplateContentComponent} from "../pxe/show-template-content/show-template-content.component"; import {Observable} from "rxjs"; import { JoyrideService } from 'ngx-joyride'; +import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component"; @Component({ selector: 'app-pxe-images', diff --git a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts index c0ff7a7..b9ed0d4 100644 --- a/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts +++ b/ogWebconsole/src/app/components/ogboot/pxe/pxe.component.ts @@ -8,10 +8,10 @@ import { ToastrService } from 'ngx-toastr'; import { DatePipe } from '@angular/common'; import { DataService } from './data.service'; import {ShowTemplateContentComponent} from "./show-template-content/show-template-content.component"; -import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; import {Observable} from "rxjs"; import { JoyrideService } from 'ngx-joyride'; import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; +import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component"; @Component({ selector: 'app-pxe', diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.css similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.css rename to ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.css diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.html similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.html rename to ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.html diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts similarity index 67% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts rename to ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts index c7382ef..7e72ac0 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/add-clients-to-subnet/add-clients-to-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts @@ -1,8 +1,9 @@ import { Component, OnInit, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import {MatDialogRef, MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; import { FormControl } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; +import {OperationResultDialogComponent} from "../operation-result-dialog/operation-result-dialog.component"; @Component({ selector: 'app-add-clients-to-subnet', @@ -22,6 +23,7 @@ export class AddClientsToSubnetComponent implements OnInit { private http: HttpClient, public dialogRef: MatDialogRef, private toastService: ToastrService, + public dialog: MatDialog, @Inject(MAT_DIALOG_DATA) public data: { subnetUuid: string, subnetName: string } ) {} @@ -59,21 +61,25 @@ export class AddClientsToSubnetComponent implements OnInit { } save() { - this.selectedClients.forEach(clientId => { - const postData = { client: `/clients/${clientId}` }; + const postData = { clients: this.selectedClients.map(clientId => `/clients/${clientId}`) }; - this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe( - response => { - this.toastService.success(`Cliente asignado correctamente`); - }, - error => { - console.error(`Error al asignar el cliente:`, error); - this.toastService.error(`Error al asignar el cliente: ${error.error['hydra:description']}`); - } - ); - }); + this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe( + (response: any) => { + this.dialog.open(OperationResultDialogComponent, { + width: '600px', + data: { + success: response.success || [], + errors: response.errors || [] + } + }); - this.dialogRef.close(this.selectedClients); + this.dialogRef.close(this.selectedClients); + }, + error => { + console.error(`Error al asignar el cliente:`, error); + this.toastService.error(`Error al asignar el cliente: ${error.error['hydra:description']}`); + } + ); } close() { diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.css rename to ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.html rename to ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts similarity index 97% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts rename to ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts index ada8414..0f3f710 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/create-subnet/create-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts @@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http'; import { Component, Inject, OnInit } from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import { ToastrService } from 'ngx-toastr'; -import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; +import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; @Component({ selector: 'app-create-subnet', diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.css b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.css similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.css rename to ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.css diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html similarity index 94% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html rename to ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html index 1f3aac2..ae5a071 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html @@ -58,12 +58,7 @@ - - - - + @@ -94,4 +89,4 @@ - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.spec.ts similarity index 97% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.spec.ts rename to ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.spec.ts index 81460b5..0144ed2 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.spec.ts @@ -16,7 +16,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatTableModule } from '@angular/material/table'; import { TranslateModule } from '@ngx-translate/core'; import { JoyrideModule } from 'ngx-joyride'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { LoadingComponent } from '../../shared/loading/loading.component'; describe('OgDhcpSubnetsComponent', () => { let component: OgDhcpSubnetsComponent; diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts similarity index 93% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts rename to ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts index 6305bda..af524d9 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/og-dhcp-subnets.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts @@ -4,12 +4,13 @@ import { MatTableDataSource } from '@angular/material/table'; import { CreateSubnetComponent } from './create-subnet/create-subnet.component'; import { MatDialog } from '@angular/material/dialog'; import { HttpClient } from '@angular/common/http'; -import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component'; import { ToastrService } from 'ngx-toastr'; import { AddClientsToSubnetComponent } from './add-clients-to-subnet/add-clients-to-subnet.component'; import { ServerInfoDialogComponent } from "./server-info-dialog/server-info-dialog.component"; import { Observable } from "rxjs"; import { JoyrideService } from 'ngx-joyride'; +import {DeleteModalComponent} from "../../shared/delete_modal/delete-modal/delete-modal.component"; +import {ShowClientsComponent} from "./show-clients/show-clients.component"; export interface Subnet { '@id': string; @@ -30,7 +31,7 @@ export interface Subnet { } @Component({ - selector: 'app-og-dhcp-subnets', + selector: 'app-ogdhcp', templateUrl: './og-dhcp-subnets.component.html', styleUrls: ['./og-dhcp-subnets.component.css'] }) @@ -207,6 +208,20 @@ export class OgDhcpSubnetsComponent { ); } + openShowClientsDialog(subnet: Subnet) { + const dialogRef = this.dialog.open(ShowClientsComponent, { + width: '100vw', + height: '100vh', + maxWidth: '100vw', + maxHeight: '100vh', + data: { subnetId: subnet.id, subnetName: subnet.name } + }); + + dialogRef.afterClosed().subscribe(result => { + this.loadSubnets(); + }); + } + addClientsToSubnet(subnet: Subnet) { const dialogRef = this.dialog.open(AddClientsToSubnetComponent, { width: '600px', diff --git a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.css b/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.css deleted file mode 100644 index e69de29..0000000 diff --git a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.html b/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.html deleted file mode 100644 index d680125..0000000 --- a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.html +++ /dev/null @@ -1 +0,0 @@ -

ogdhcp works!

diff --git a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.spec.ts deleted file mode 100644 index 0ab958d..0000000 --- a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { OgdhcpComponent } from './ogdhcp.component'; - -describe('OgdhcpComponent', () => { - let component: OgdhcpComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [OgdhcpComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(OgdhcpComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.ts b/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.ts deleted file mode 100644 index a8ee1b5..0000000 --- a/ogWebconsole/src/app/components/ogdhcp/ogdhcp.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-ogdhcp', - templateUrl: './ogdhcp.component.html', - styleUrl: './ogdhcp.component.css' -}) -export class OgdhcpComponent { - -} diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.css b/ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.css similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.css rename to ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.css diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.html b/ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.html similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.html rename to ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.html diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.spec.ts similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.spec.ts rename to ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.spec.ts diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.ts b/ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.ts similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component.ts rename to ogWebconsole/src/app/components/ogdhcp/server-info-dialog/server-info-dialog.component.ts diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css new file mode 100644 index 0000000..f28d4ee --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css @@ -0,0 +1,97 @@ +.full-width { + width: 100%; +} + +form { + padding: 20px; +} + +.spacing-container { + margin-top: 20px; + margin-bottom: 16px; +} + +.list-item-content { + display: flex; + align-items: flex-start; + justify-content: space-between; + width: 100%; +} + +.text-content { + flex-grow: 1; + margin-right: 16px; + margin-left: 10px; +} + +.icon-container { + display: flex; + align-items: center; +} + +.right-icon { + margin-left: 8px; + cursor: pointer; +} + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} +.header-container { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 10px; + border-bottom: 1px solid #ddd; +} + +.header-container-title { + flex-grow: 1; + text-align: left; + margin-left: 1em; +} + +.lists-container { + padding: 16px; +} + +.search-container { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + margin: 1.5rem 0rem 1.5rem 0rem; + box-sizing: border-box; +} + +.search-string { + flex: 2; + padding: 5px; +} + +table { + width: 100%; +} + +.mat-elevation-z8 { + box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.2); +} + +.paginator-container { + display: flex; + justify-content: end; + margin-bottom: 30px; +} + +mat-spinner { + margin: 0 auto; + align-self: center; +} + +.subnets-button-row { + display: flex; + gap: 15px; +} diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html new file mode 100644 index 0000000..0e16228 --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html @@ -0,0 +1,75 @@ + + +

Buscar clientes en {{data.subnetName}}

+ + +
+ + Buscar nombre del cliente + + search + + Pulsar 'enter' para buscar + + + Buscar IP + + search + + Pulsar 'enter' para buscar + + + Buscar Mac + + search + + Pulsar 'enter' para buscar + +
+ + + + + + + + + + +
{{ column.header }} + + Client Icon + + + + {{ client.ogLive?.date | date }} + + + + {{ column.cell(client) }} + +
+ +
+ + +
+ +
+ + + + diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts new file mode 100644 index 0000000..5a64023 --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts @@ -0,0 +1,72 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ShowClientsComponent } from './show-clients.component'; +import {MatExpansionModule} from "@angular/material/expansion"; +import {MatIconModule} from "@angular/material/icon"; +import {MatDividerModule} from "@angular/material/divider"; +import {MatFormFieldModule} from "@angular/material/form-field"; +import {MatSelectModule} from "@angular/material/select"; +import {MatPaginatorModule} from "@angular/material/paginator"; +import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; +import {FormsModule} from "@angular/forms"; +import {MatInputModule} from "@angular/material/input"; +import {MatTableModule} from "@angular/material/table"; +import {TranslateModule} from "@ngx-translate/core"; +import {JoyrideModule} from "ngx-joyride"; +import {MatDialog, MatDialogModule, MatDialogRef} from "@angular/material/dialog"; +import {HttpClient} from "@angular/common/http"; +import {ToastrService} from "ngx-toastr"; +import {of} from "rxjs"; + +describe('ShowClientsComponent', () => { + let component: ShowClientsComponent; + let fixture: ComponentFixture; + let mockDialog: jasmine.SpyObj; + let mockHttpClient: jasmine.SpyObj; + let mockToastrService: jasmine.SpyObj; + + beforeEach(async () => { + mockDialog = jasmine.createSpyObj('MatDialog', ['open']); + mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']); + mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']); + mockHttpClient.get.and.returnValue(of({ 'hydra:member': [], 'hydra:totalItems': 0 })); + mockHttpClient.post.and.returnValue(of({})); + + await TestBed.configureTestingModule({ + declarations: [ShowClientsComponent], + imports: [ + MatExpansionModule, + MatIconModule, + MatDividerModule, + MatFormFieldModule, + MatSelectModule, + MatPaginatorModule, + BrowserAnimationsModule, + FormsModule, + MatInputModule, + MatDialogModule, + MatTableModule, + TranslateModule.forRoot(), + JoyrideModule.forRoot(), + ], + providers: [ + { provide: MatDialog, useValue: mockDialog }, + { provide: HttpClient, useValue: mockHttpClient }, + { provide: ToastrService, useValue: mockToastrService }, + { + provide: MatDialogRef, + useValue: {} + }, + ], + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShowClientsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts new file mode 100644 index 0000000..0b50afc --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts @@ -0,0 +1,73 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {ToastrService} from "ngx-toastr"; +import {HttpClient} from "@angular/common/http"; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog"; +import {MatTableDataSource} from "@angular/material/table"; +import {Subnet} from "../og-dhcp-subnets.component"; +import {Client} from "../../groups/model/model"; + +@Component({ + selector: 'app-show-clients', + templateUrl: './show-clients.component.html', + styleUrl: './show-clients.component.css' +}) +export class ShowClientsComponent implements OnInit { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + dataSource = new MatTableDataSource([]); + length = 0; + itemsPerPage: number = 10; + pageSizeOptions: number[] = [5, 10, 20]; + page = 0; + loading: boolean = false; + filters: { [key: string]: string } = {}; + + columns = [ + { columnDef: 'id', header: 'ID', cell: (client: Client) => client.id }, + { columnDef: 'status', header: 'Estado', cell: (client: Client) => client.status }, + { columnDef: 'name', header: 'Name', cell: (client: Client) => client.name }, + { columnDef: 'ip', header: 'Ip', cell: (client: Client) => client.ip }, + { columnDef: 'mac', header: 'Mac', cell: (client: Client) => client.mac }, + { columnDef: 'ogLive', header: 'OgLive', cell: (client: Client) => client.ogLive?.date }, + ]; + + displayedColumns: string[] = ['id', 'status', 'name', 'ip', 'mac', 'ogLive']; + + constructor( + private toastService: ToastrService, + private http: HttpClient, + public dialogRef: MatDialogRef, + public dialog: MatDialog, + @Inject(MAT_DIALOG_DATA) public data: any + ) { } + + ngOnInit(): void { + if (this.data) { + this.loadData(); + } + } + + loadData() { + this.loading = true; + this.http.get(`${this.baseUrl}/clients?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}&subnet.id=${this.data.subnetId}`, { params: this.filters }).subscribe( + (data) => { + this.dataSource.data = data['hydra:member']; + this.length = data['hydra:totalItems']; + this.loading = false; + }, + (error) => { + this.loading = false; + } + ); + console.log(this.dataSource.data) + } + + onNoClick(): void { + this.dialogRef.close(); + } + + onPageChange(event: any) { + this.page = event.pageIndex; + this.itemsPerPage = event.pageSize; + this.loadData() + } +} diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.css b/ogWebconsole/src/app/components/ogdhcp/status/status.component.css similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.css rename to ogWebconsole/src/app/components/ogdhcp/status/status.component.css diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.html b/ogWebconsole/src/app/components/ogdhcp/status/status.component.html similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.html rename to ogWebconsole/src/app/components/ogdhcp/status/status.component.html diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/status/status.component.spec.ts similarity index 96% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts rename to ogWebconsole/src/app/components/ogdhcp/status/status.component.spec.ts index 2ca1517..6633f82 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/status/status.component.spec.ts @@ -20,7 +20,7 @@ import { ToastrModule } from 'ngx-toastr'; import { NgxChartsModule } from '@swimlane/ngx-charts'; import { TranslateModule } from '@ngx-translate/core'; import { JoyrideModule } from 'ngx-joyride'; -import {LoadingComponent} from "../../../../shared/loading/loading.component"; +import {LoadingComponent} from "../../../shared/loading/loading.component"; describe('StatusComponent', () => { let component: StatusComponent; diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.ts b/ogWebconsole/src/app/components/ogdhcp/status/status.component.ts similarity index 100% rename from ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets/status/status.component.ts rename to ogWebconsole/src/app/components/ogdhcp/status/status.component.ts diff --git a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts index e398311..6d2433c 100644 --- a/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts +++ b/ogWebconsole/src/app/components/repositories/main-repository-view/main-repository-view.component.ts @@ -6,11 +6,9 @@ import {DataService} from "../../images/data.service"; import {ActivatedRoute} from "@angular/router"; import {MatTableDataSource} from "@angular/material/table"; import {DatePipe} from "@angular/common"; -import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; -import {CreateImageComponent} from "../../images/create-image/create-image.component"; -import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; import {Observable} from "rxjs"; import {MatDialog} from "@angular/material/dialog"; +import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component"; @Component({ selector: 'app-main-repository-view', diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts index 652ebcc..2bfa9d1 100644 --- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts +++ b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts @@ -5,12 +5,11 @@ import {MatDialog} from "@angular/material/dialog"; import {HttpClient} from "@angular/common/http"; import {ToastrService} from "ngx-toastr"; import {JoyrideService} from "ngx-joyride"; -import {CreateImageComponent} from "../../images/create-image/create-image.component"; import {Observable} from "rxjs"; -import {ServerInfoDialogComponent} from "../../ogdhcp/og-dhcp-subnets/server-info-dialog/server-info-dialog.component"; import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; import {ExportImageComponent} from "../../images/export-image/export-image.component"; import {BackupImageComponent} from "../backup-image/backup-image.component"; +import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component"; @Component({ selector: 'app-repository-images', From 0d888dec628847494d3172035328cee7b79f1b60 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 26 Feb 2025 08:43:12 +0100 Subject: [PATCH 13/38] refs #1558. Add client/subnet new UX modal --- .../operation-result-dialog.component.css | 0 .../operation-result-dialog.component.html | 1 + .../operation-result-dialog.component.spec.ts | 23 +++++++ .../operation-result-dialog.component.ts | 62 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.css create mode 100644 ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.html create mode 100644 ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts create mode 100644 ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.css b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.css new file mode 100644 index 0000000..e69de29 diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.html b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.html new file mode 100644 index 0000000..3ca5963 --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.html @@ -0,0 +1 @@ +

operation-result-dialog works!

diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts new file mode 100644 index 0000000..21f235c --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OperationResultDialogComponent } from './operation-result-dialog.component'; + +describe('OperationResultDialogComponent', () => { + let component: OperationResultDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [OperationResultDialogComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OperationResultDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts new file mode 100644 index 0000000..5a9117b --- /dev/null +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts @@ -0,0 +1,62 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; + + +@Component({ + selector: 'app-operation-result-dialog', + template: ` +

Resultado de la operación

+ +
+

Éxitos

+
    +
  • {{ success.client }} ✅
  • +
+
+ +
+

Errores

+
    +
  • + {{ error.client }} ❌ - {{ error.error }} +
  • +
+
+
+ + + + `, + styles: [` + mat-dialog-content { max-height: 400px; overflow-y: auto; } + h3 { margin-bottom: 5px; } + + .success-box { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; + padding: 10px; + border-radius: 5px; + margin-bottom: 10px; + } + + .error-box { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + padding: 10px; + border-radius: 5px; + margin-bottom: 10px; + } + `] +}) +export class OperationResultDialogComponent { + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { success: any[], errors: any[] } + ) {} + + close() { + this.dialogRef.close(); + } +} From 1962beaf8a4ebbbe3a11dcd219d284753d0b3730 Mon Sep 17 00:00:00 2001 From: llara Date: Wed, 26 Feb 2025 09:34:29 +0100 Subject: [PATCH 14/38] refs #1608 and #1561 Fix selection in both views. Add multi-selection in cards view. --- .../execute-command.component.html | 18 ++-- .../execute-command.component.ts | 1 + .../components/groups/groups.component.css | 42 ++++---- .../components/groups/groups.component.html | 100 ++++++++++-------- .../app/components/groups/groups.component.ts | 35 ++++-- 5 files changed, 109 insertions(+), 87 deletions(-) diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html index 11353a8..1d6eb62 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html +++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.html @@ -1,20 +1,18 @@ - - - - - + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts index bc7dd55..72a5f59 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts +++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/execute-command.component.ts @@ -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; diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index 97a7e90..dc010f8 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -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; } \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 6a7420d..64592af 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -171,8 +171,8 @@
- + @@ -190,55 +190,63 @@
-
-
-
- - - Client Icon +
+ + +
+
+
+ + + Client Icon -
- {{ client.name }} - {{ client.ip }} - {{ client.mac }} -
- - - - - - - - - - - - - + + + + + + +
+
@@ -314,11 +322,13 @@ + + + + +
{{ 'actions' | translate }} - - + Pulsar 'enter' para buscar Buscar IP - + search - Pulsar 'enter' para buscar Buscar Mac - + search - Pulsar 'enter' para buscar @@ -38,13 +42,12 @@ + text="Visualiza y administra las subredes listadas según los filtros aplicados.">
{{ column.header }} - Client Icon + Client Icon @@ -62,9 +65,9 @@
+ text="Navega entre las páginas de subredes usando el paginador."> + (page)="onPageChange($event)">
@@ -72,4 +75,4 @@ - + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts index 5a64023..be1714b 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts @@ -1,22 +1,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { ShowClientsComponent } from './show-clients.component'; -import {MatExpansionModule} from "@angular/material/expansion"; -import {MatIconModule} from "@angular/material/icon"; -import {MatDividerModule} from "@angular/material/divider"; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatSelectModule} from "@angular/material/select"; -import {MatPaginatorModule} from "@angular/material/paginator"; -import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; -import {FormsModule} from "@angular/forms"; -import {MatInputModule} from "@angular/material/input"; -import {MatTableModule} from "@angular/material/table"; -import {TranslateModule} from "@ngx-translate/core"; -import {JoyrideModule} from "ngx-joyride"; -import {MatDialog, MatDialogModule, MatDialogRef} from "@angular/material/dialog"; -import {HttpClient} from "@angular/common/http"; -import {ToastrService} from "ngx-toastr"; -import {of} from "rxjs"; +import { MatExpansionModule } from "@angular/material/expansion"; +import { MatIconModule } from "@angular/material/icon"; +import { MatDividerModule } from "@angular/material/divider"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatSelectModule } from "@angular/material/select"; +import { MatPaginatorModule } from "@angular/material/paginator"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { FormsModule } from "@angular/forms"; +import { MatInputModule } from "@angular/material/input"; +import { MatTableModule } from "@angular/material/table"; +import { TranslateModule } from "@ngx-translate/core"; +import { JoyrideModule } from "ngx-joyride"; +import { MatDialog, MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; +import { HttpClient } from "@angular/common/http"; +import { ToastrService } from "ngx-toastr"; +import { of } from "rxjs"; +import { LoadingComponent } from '../../../shared/loading/loading.component'; describe('ShowClientsComponent', () => { let component: ShowClientsComponent; @@ -33,7 +33,7 @@ describe('ShowClientsComponent', () => { mockHttpClient.post.and.returnValue(of({})); await TestBed.configureTestingModule({ - declarations: [ShowClientsComponent], + declarations: [ShowClientsComponent, LoadingComponent], imports: [ MatExpansionModule, MatIconModule, @@ -53,13 +53,11 @@ describe('ShowClientsComponent', () => { { provide: MatDialog, useValue: mockDialog }, { provide: HttpClient, useValue: mockHttpClient }, { provide: ToastrService, useValue: mockToastrService }, - { - provide: MatDialogRef, - useValue: {} - }, + { provide: MatDialogRef, useValue: {} }, + { provide: MAT_DIALOG_DATA, useValue: {} }, ], }) - .compileComponents(); + .compileComponents(); fixture = TestBed.createComponent(ShowClientsComponent); component = fixture.componentInstance; @@ -69,4 +67,4 @@ describe('ShowClientsComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); -}); +}); \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts index 0b50afc..ddff94b 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts @@ -1,10 +1,10 @@ -import {Component, Inject, OnInit} from '@angular/core'; -import {ToastrService} from "ngx-toastr"; -import {HttpClient} from "@angular/common/http"; -import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog"; -import {MatTableDataSource} from "@angular/material/table"; -import {Subnet} from "../og-dhcp-subnets.component"; -import {Client} from "../../groups/model/model"; +import { Component, Inject, OnInit } from '@angular/core'; +import { ToastrService } from "ngx-toastr"; +import { HttpClient } from "@angular/common/http"; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog"; +import { MatTableDataSource } from "@angular/material/table"; +import { Subnet } from "../og-dhcp-subnets.component"; +import { Client } from "../../groups/model/model"; @Component({ selector: 'app-show-clients', From dddfcd4e602001f7dbc3c8cc548d2195345e1510 Mon Sep 17 00:00:00 2001 From: llara Date: Wed, 26 Feb 2025 11:33:21 +0100 Subject: [PATCH 16/38] Remove AcctionsModal component and associated files --- ogWebconsole/src/app/app.module.ts | 12 +-- .../acctions-modal.component.css | 13 --- .../acctions-modal.component.html | 14 --- .../acctions-modal.component.ts | 58 ------------ .../create-pxe-boot-file.component.css | 91 ------------------- .../create-pxe-boot-file.component.html | 19 ---- .../create-pxe-boot-file.component.ts | 81 ----------------- 7 files changed, 5 insertions(+), 283 deletions(-) delete mode 100644 ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.css delete mode 100644 ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.html delete mode 100644 ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.ts delete mode 100644 ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.css delete mode 100644 ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html delete mode 100644 ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 13805e0..4c60534 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -64,7 +64,6 @@ import { LegendComponent } from './components/groups/shared/legend/legend.compon import { ClassroomViewDialogComponent } from './components/groups/shared/classroom-view/classroom-view-modal'; import { MatPaginator } from "@angular/material/paginator"; import { SaveFiltersDialogComponent } from './components/groups/shared/save-filters-dialog/save-filters-dialog.component'; -import { AcctionsModalComponent } from './components/groups/shared/acctions-modal/acctions-modal.component'; import { PXEimagesComponent } from './components/ogboot/pxe-images/pxe-images.component'; import { CreatePXEImageComponent } from './components/ogboot/pxe-images/create-image/create-image/create-image.component'; import { InfoImageComponent } from './components/ogboot/pxe-images/info-image/info-image/info-image.component'; @@ -125,11 +124,11 @@ import { RepositoryImagesComponent } from './components/repositories/repository- import { InputDialogComponent } from './components/commands/commands-task/task-logs/input-dialog/input-dialog.component'; import { ManageOrganizationalUnitComponent } from './components/groups/shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component'; import { BackupImageComponent } from './components/repositories/backup-image/backup-image.component'; -import {ServerInfoDialogComponent} from "./components/ogdhcp/server-info-dialog/server-info-dialog.component"; -import {StatusComponent} from "./components/ogdhcp/status/status.component"; -import {OgDhcpSubnetsComponent} from "./components/ogdhcp/og-dhcp-subnets.component"; -import {CreateSubnetComponent} from "./components/ogdhcp/create-subnet/create-subnet.component"; -import {AddClientsToSubnetComponent} from "./components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component"; +import { ServerInfoDialogComponent } from "./components/ogdhcp/server-info-dialog/server-info-dialog.component"; +import { StatusComponent } from "./components/ogdhcp/status/status.component"; +import { OgDhcpSubnetsComponent } from "./components/ogdhcp/og-dhcp-subnets.component"; +import { CreateSubnetComponent } from "./components/ogdhcp/create-subnet/create-subnet.component"; +import { AddClientsToSubnetComponent } from "./components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component"; import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component'; import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component'; export function HttpLoaderFactory(http: HttpClient) { @@ -161,7 +160,6 @@ export function HttpLoaderFactory(http: HttpClient) { LegendComponent, ClassroomViewDialogComponent, SaveFiltersDialogComponent, - AcctionsModalComponent, PXEimagesComponent, CreatePXEImageComponent, InfoImageComponent, diff --git a/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.css b/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.css deleted file mode 100644 index 5b613c8..0000000 --- a/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.css +++ /dev/null @@ -1,13 +0,0 @@ -/* Contenedor de los botones, organizados en 2 columnas */ -.button-container { - display: grid; - grid-template-columns: 1fr 1fr; /* 2 columnas iguales */ - gap: 15px; /* Espacio entre los botones */ - margin-top: 15px; -} - -/* Opcional: ancho 100% para los botones */ -.button-action { - width: 100%; - justify-self: stretch; /* Asegura que los botones se extiendan por toda la columna */ -} diff --git a/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.html b/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.html deleted file mode 100644 index 45870ce..0000000 --- a/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.html +++ /dev/null @@ -1,14 +0,0 @@ -

{{ 'actionsModalTitle' | translate }}

- - -
- -
-
diff --git a/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.ts b/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.ts deleted file mode 100644 index 1a49e71..0000000 --- a/ogWebconsole/src/app/components/groups/shared/acctions-modal/acctions-modal.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -// componente -import { Component, Inject } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; -import { ToastrService } from 'ngx-toastr'; -import { CreatePxeBootFileComponent } from '../../../ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component'; -import { HttpClient } from '@angular/common/http'; -import { CommandDetailComponent } from '../../../commands/main-commands/detail-command/command-detail.component'; -import { RouterLink } from '@angular/router'; -@Component({ - selector: 'app-acctions-modal', - templateUrl: './acctions-modal.component.html', - styleUrls: ['./acctions-modal.component.css'] -}) -export class AcctionsModalComponent { - baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - selectedElements: any; - displayedColumns: string[] = ['name', 'createdBy', 'createdAt']; - - arrayCommands: any[] = [ - {name: 'Enceder', slug: 'power-on'}, - {name: 'Apagar', slug: 'power-off'}, - {name: 'Reiniciar', slug: 'reboot'}, - {name: 'Iniciar Sesión', slug: 'login'}, - {name: 'Inventario Software', slug: 'software-inventory'}, - {name: 'Inventario Hardware', slug: 'hardware-inventory'}, - {name: 'Ejecutar script', slug: 'run-script'}, - ]; - - private apiUrl = `${this.baseUrl}/commands?page=1&itemsPerPage=40`; - - ngOnInit(): void { - } - - constructor( - private toastService: ToastrService, - public dialog: MatDialog, - private http: HttpClient, - @Inject(MAT_DIALOG_DATA) public data: any - ) { - this.selectedElements = data?.selectedElements || []; - } - - onSend(): void { - this.toastService.success('Acción enviada a: ' + this.selectedElements); - } - - onPxeBootFile(): void { - const dialog = this.dialog.open(CreatePxeBootFileComponent, { data: this.selectedElements, width: '400px' }); - dialog.afterClosed().subscribe(() => { - this.dialog.closeAll(); - }); - } - - onCommandClick(command: any): void { - - } - -} diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.css b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.css deleted file mode 100644 index 3b55583..0000000 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.css +++ /dev/null @@ -1,91 +0,0 @@ -mat-form-field { - width: 100%; - margin-bottom: 16px; - padding: 5px; - } - - .button-group { - display: flex; - justify-content: space-between; - } - - button { - width: 48%; - } - - :host { - display: block; - padding: 20px; - background-color: #f5f5f5; - border-radius: 8px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); -} - -.mat-form-field { - width: 100%; - margin-bottom: 16px; -} - -.mat-step-label { - font-weight: bold; - font-size: 1.1em; -} - -button { - margin: 8px 0; -} - -.mat-stepper-header { - background-color: #fff; - padding: 16px; - border-bottom: 1px solid #e0e0e0; - border-radius: 8px 8px 0 0; -} - -.mat-stepper-horizontal-line { - border-color: #3f51b5; -} - -.mat-stepper-horizontal { - background-color: #fff; - padding: 0; - border-radius: 8px; - overflow: hidden; -} - -.mat-step-header { - background-color: #e8eaf6; - color: #3f51b5; -} - -.mat-step-header .mat-step-icon { - background-color: #3f51b5; - color: #fff; -} - -.mat-stepper-content { - padding: 16px; - background-color: #fff; - border-radius: 0 0 8px 8px; -} - -pre { - background-color: #e8eaf6; - padding: 16px; - border-radius: 4px; - font-size: 12px; - overflow-x: auto; -} - -.mat-raised-button { - margin-right: 8px; -} - -.mat-button { - margin-right: 8px; -} - -span{ - margin: 5px; - padding-bottom: 15px; -} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html deleted file mode 100644 index ba5a912..0000000 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
-

{{ isEditMode ? ('editClientTitle' | translate) : ('addClientTitle' | translate) }}

-
- - {{ 'selectPxeTemplateLabel' | translate }} - - - {{ template.name }} - - - -
-
- - -
-
diff --git a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts b/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts deleted file mode 100644 index 68d46bd..0000000 --- a/ogWebconsole/src/app/components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Component, Inject, OnInit } from '@angular/core'; -import { ToastrService } from 'ngx-toastr'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; - -@Component({ - selector: 'app-create-pxe-boot-file', - templateUrl: './create-pxe-boot-file.component.html', - styleUrls: ['./create-pxe-boot-file.component.css'] -}) -export class CreatePxeBootFileComponent implements OnInit { - baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - pxeTemplates: any[] = []; - selectedPxeTemplate: string | undefined; - selectedElements: any; - isEditMode: boolean = false; - - constructor( - private toastService: ToastrService, - private http: HttpClient, - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { clients: any[], bootFile?: any } - ) {} - - ngOnInit(): void { - this.selectedElements = this.data - this.loadPxeTemplates(); - if (this.data.bootFile) { - this.isEditMode = true; - this.selectedPxeTemplate = this.data.bootFile.template.uuid; - } - } - - loadPxeTemplates(): void { - this.http.get(`${this.baseUrl}/pxe-templates?page=1&itemsPerPage=30`) - .subscribe((response: any) => { - this.pxeTemplates = response['hydra:member']; - }, error => { - console.error('Error fetching PXE templates:', error); - }); - } - - onCancel(): void { - this.dialogRef.close(); - } - - onSave(): void { - if (this.selectedPxeTemplate) { - const payload = { - template: `/pxe-templates/${this.selectedPxeTemplate}`, - clients: this.selectedElements - }; - - if (this.isEditMode && this.data.bootFile) { - this.http.put(`${this.baseUrl}/pxe-boot-files/${this.data.bootFile.uuid}`, payload) - .subscribe({ - next: response => { - this.toastService.success('PXE actualizado con éxito'); - this.dialogRef.close(true); - }, - error: error => { - this.toastService.error('Error al actualizar el PXE', error); - } - }); - } else { - this.http.post(`${this.baseUrl}/pxe-boot-files`, payload) - .subscribe({ - next: response => { - this.toastService.success('PXE asignado con éxito'); - this.dialogRef.close(true); - }, - error: error => { - this.toastService.error('Error enviando el payload', error); - } - }); - } - } else { - this.toastService.error('No se ha seleccionado ninguna plantilla PXE'); - } - } -} From 900cb423b32f9531cd52935340fa059d5c4cbea0 Mon Sep 17 00:00:00 2001 From: llara Date: Wed, 26 Feb 2025 11:45:17 +0100 Subject: [PATCH 17/38] Remove unused CreatePxeBootFileComponent from app module --- ogWebconsole/src/app/app.module.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 4c60534..009b857 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -72,7 +72,6 @@ import { CreatePxeTemplateComponent } from './components/ogboot/pxe/create-pxeTe import { PxeBootFilesComponent } from './components/ogboot/pxe-boot-files/pxe-boot-files.component'; import { MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelTitle } from "@angular/material/expansion"; import { OgbootStatusComponent } from './components/ogboot/ogboot-status/ogboot-status.component'; -import { CreatePxeBootFileComponent } from './components/ogboot/pxe-boot-files/create-pxeBootFile/create-pxe-boot-file/create-pxe-boot-file.component'; import { NgxChartsModule } from '@swimlane/ngx-charts'; import { CommandsComponent } from './components/commands/main-commands/commands.component'; import { CommandDetailComponent } from './components/commands/main-commands/detail-command/command-detail.component'; @@ -167,7 +166,6 @@ export function HttpLoaderFactory(http: HttpClient) { CreatePxeTemplateComponent, PxeBootFilesComponent, OgbootStatusComponent, - CreatePxeBootFileComponent, OgDhcpSubnetsComponent, CreateSubnetComponent, AddClientsToSubnetComponent, From 7e06e605981c4e9e9fba810f9137f3d4e9608a6c Mon Sep 17 00:00:00 2001 From: llara Date: Wed, 26 Feb 2025 12:20:21 +0100 Subject: [PATCH 18/38] refs #1617. Fix: handle undefined networkSettings in ClientViewComponent --- .../classroom-view.component.ts | 9 +- .../client-view/client-view.component.ts | 83 ++++++++++--------- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.ts b/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.ts index fed55b0..33c65f9 100644 --- a/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/classroom-view/classroom-view.component.ts @@ -21,8 +21,7 @@ export class ClassroomViewComponent implements OnInit, OnChanges { @Input() pcInTable: number = 5; groupedClients: GroupedClients[] = []; - constructor(public dialog: MatDialog, private http: HttpClient, private toastService: ToastrService) {} - + constructor(public dialog: MatDialog, private http: HttpClient, private toastService: ToastrService) { } ngOnInit(): void { this.groupClientsByOrganizationalUnit(); @@ -61,7 +60,6 @@ export class ClassroomViewComponent implements OnInit, OnChanges { }); } - chunkArray(arr: any[], chunkSize: number): any[][] { const chunks = []; for (let i = 0; i < arr.length; i += chunkSize) { @@ -71,7 +69,8 @@ export class ClassroomViewComponent implements OnInit, OnChanges { } handleClientClick(client: any): void { - const dialogRef = this.dialog.open(ClientViewComponent, { data: { client }, width: '800px', height:'700px' }); + console.log('Client clicked:', client); + this.dialog.open(ClientViewComponent, { data: { client }, width: '800px', height: '700px' }); } onDragMoved(event: CdkDragMove, client: any): void { @@ -106,4 +105,4 @@ export class ClassroomViewComponent implements OnInit, OnChanges { } else this.toastService.success('Cliente actualizado!', 'Éxito'); } -} +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts b/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts index 4193b44..1b7944a 100644 --- a/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/client-view/client-view.component.ts @@ -1,5 +1,5 @@ -import {Component, Inject} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; @Component({ selector: 'app-client-view', @@ -11,54 +11,61 @@ export class ClientViewComponent { displayedColumns: string[] = ['property', 'value']; generalData = [ - {property: 'Nombre', value: this.data.client.name}, - {property: 'Uuid', value: this.data.client.uuid}, - {property: 'IP', value: this.data.client.ip}, - {property: 'MAC', value: this.data.client.mac}, - {property: 'Nº de serie', value: this.data.client.serialNumber}, - {property: 'Netiface', value: this.data.client.netiface}, - {property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : ''}, - {property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : ''}, - {property: 'Fecha de creación', value: this.data.client.createdAt}, - {property: 'Creado por', value: this.data.client.createdBy} + { property: 'Nombre', value: this.data.client.name }, + { property: 'Uuid', value: this.data.client.uuid }, + { property: 'IP', value: this.data.client.ip }, + { property: 'MAC', value: this.data.client.mac }, + { property: 'Nº de serie', value: this.data.client.serialNumber }, + { property: 'Netiface', value: this.data.client.netiface }, + { property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : '' }, + { property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : '' }, + { property: 'Fecha de creación', value: this.data.client.createdAt }, + { property: 'Creado por', value: this.data.client.createdBy } ]; networkData = [ - {property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : ''}, - {property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : ''}, - {property: 'Subred', value: this.data.client.subnet}, - {property: 'OGlive', value: ''}, - {property: 'Autoexec', value: ''}, - {property: 'Repositorio', value: ''}, - {property: 'Validacion', value: ''}, - {property: 'Página login', value: ''}, - {property: 'Fecha de creación', value: this.data.client.createdAt}, - {property: 'Creado por', value: this.data.client.createdBy} + { property: 'Menú', value: this.data.client.menu ? this.data.client.menu.description : '' }, + { property: 'Perfil hardware', value: this.data.client.hardwareProfile ? this.data.client.hardwareProfile.description : '' }, + { property: 'Subred', value: this.data.client.subnet }, + { property: 'OGlive', value: '' }, + { property: 'Autoexec', value: '' }, + { property: 'Repositorio', value: '' }, + { property: 'Validacion', value: '' }, + { property: 'Página login', value: '' }, + { property: 'Fecha de creación', value: this.data.client.createdAt }, + { property: 'NTP', value: this.data.client.organizationalUnit?.networkSettings?.ntp || '' }, + { property: 'Modo p2p', value: this.data.client.organizationalUnit?.networkSettings?.p2pMode || '' }, + { property: 'Tiempo p2p', value: this.data.client.organizationalUnit?.networkSettings?.p2pTime || '' }, + { property: 'IP multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastIp || '' }, + { property: 'Modo multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastMode || '' }, + { property: 'Puerto multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastPort || '' }, + { property: 'Velocidad multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastSpeed || '' }, + { property: 'Perfil hardware', value: this.data.client.organizationalUnit?.networkSettings?.hardwareProfile?.description || '' }, + { property: 'Menú', value: this.data.client.organizationalUnit?.networkSettings?.menu?.description || '' } ]; classroomData = [ - {property: 'Url servidor proxy', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.proxy : ''}, - {property: 'IP DNS', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.dns : ''}, - {property: 'Máscara de red', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.netmask : ''}, - {property: 'Router', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.router : ''}, - {property: 'NTP', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.ntp : ''}, - {property: 'Modo p2p', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.p2pMode : ''}, - {property: 'Tiempo p2p', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.p2pTime : ''}, - {property: 'IP multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastIp : ''}, - {property: 'Modo multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastMode : ''}, - {property: 'Puerto multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastPort : ''}, - {property: 'Velocidad multicast', value: this.data.client.organizationalUnit.networkSettings ? this.data.client.organizationalUnit.networkSettings.mcastSpeed : ''}, - {property: 'Perfil hardware', value: this.data.client.organizationalUnit.networkSettings && this.data.client.organizationalUnit.networkSettings.hardwareProfile ? this.data.client.organizationalUnit.networkSettings.hardwareProfile.description : ''}, - {property: 'Menú', value: this.data.client.organizationalUnit.networkSettings && this.data.client.organizationalUnit.networkSettings.menu ? this.data.client.organizationalUnit.networkSettings.menu.description : ''} + { property: 'Url servidor proxy', value: this.data.client.organizationalUnit?.networkSettings?.proxy || '' }, + { property: 'IP DNS', value: this.data.client.organizationalUnit?.networkSettings?.dns || '' }, + { property: 'Máscara de red', value: this.data.client.organizationalUnit?.networkSettings?.netmask || '' }, + { property: 'Router', value: this.data.client.organizationalUnit?.networkSettings?.router || '' }, + { property: 'NTP', value: this.data.client.organizationalUnit?.networkSettings?.ntp || '' }, + { property: 'Modo p2p', value: this.data.client.organizationalUnit?.networkSettings?.p2pMode || '' }, + { property: 'Tiempo p2p', value: this.data.client.organizationalUnit?.networkSettings?.p2pTime || '' }, + { property: 'IP multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastIp || '' }, + { property: 'Modo multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastMode || '' }, + { property: 'Puerto multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastPort || '' }, + { property: 'Velocidad multicast', value: this.data.client.organizationalUnit?.networkSettings?.mcastSpeed || '' }, + { property: 'Perfil hardware', value: this.data.client.organizationalUnit?.networkSettings?.hardwareProfile?.description || '' }, + { property: 'Menú', value: this.data.client.organizationalUnit?.networkSettings?.menu?.description || '' } ]; constructor( private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any - ) { - } + ) {} onNoClick(): void { this.dialogRef.close(); } -} +} \ No newline at end of file From 1ae55c325441275f310374a3c3dca3080083639c Mon Sep 17 00:00:00 2001 From: llara Date: Wed, 26 Feb 2025 13:14:32 +0100 Subject: [PATCH 19/38] Refactor: simplify client main view by removing unused buttons and updating layout --- .../client-main-view.component.html | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html index 3432ca8..dcb2d9c 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.html @@ -1,24 +1,13 @@
-

{{ 'clientDetailsTitle' | translate }}

- - -
- - - +
- -
From bae2069661b3d99cfccc48919f540d9fb7f02e91 Mon Sep 17 00:00:00 2001 From: llara Date: Thu, 27 Feb 2025 10:35:20 +0100 Subject: [PATCH 20/38] refs #1619. In Progress. Refactor: update layout dimensions and styles for groups component --- .../components/groups/groups.component.css | 99 +-- .../components/groups/groups.component.html | 672 +++++++++--------- .../app/layout/header/header.component.css | 2 +- .../main-layout/main-layout.component.css | 15 +- .../main-layout/main-layout.component.html | 2 +- 5 files changed, 384 insertions(+), 406 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index d461702..dcf9a86 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -1,3 +1,10 @@ +.groups-container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; +} + .header-container { display: flex; justify-content: space-between; @@ -6,6 +13,13 @@ border-bottom: 1px solid #ddd; } +.main-container { + display: flex; + flex-direction: row; + width: 100%; + height: 100%; +} + .header-container-title { flex-grow: 1; text-align: left; @@ -15,6 +29,7 @@ .groups-button-row { display: flex; gap: 15px; + padding-right: 0.5rem; } .button-container { @@ -23,6 +38,23 @@ margin: 20px 0; } +.clients-container { + flex-grow: 1; + box-sizing: border-box; + overflow-y: auto; +} + +.clients-view-header { + display: flex; + flex-direction: row; + justify-content: space-between; + margin-bottom: 0.5rem; + margin-top: 0.5rem; + align-items: center; + padding-right: 1rem; + flex-grow: 1; +} + .actions mat-icon { color: #757575; cursor: pointer; @@ -59,25 +91,6 @@ border-radius: 8px; } -.details-container { - display: flex; - flex-direction: column; - gap: 20px; - padding: 20px; - align-items: center; - text-align: center; -} - -.details-wrapper { - width: 95%; - padding: 20px; - display: block; -} - -.details-placeholder { - width: 100%; -} - @media (max-width: 1024px) { .card-container { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); @@ -105,19 +118,6 @@ } } -.details-container { - display: flex; - flex-direction: column; - align-items: center; - gap: 20px; - padding: 30px; - background-color: #f9f9f9; - border-radius: 12px; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); - max-width: 1200px; - margin: 20px auto; -} - mat-tree { background-color: #f9f9f9; padding: 0px 10px 10px 10px; @@ -232,14 +232,9 @@ mat-tree mat-tree-node.disabled:hover { .filters-container { display: flex; + flex-direction: column; justify-content: start; - gap: 1rem; - margin: 2rem 0px 0.7rem 10px; -} - -.filters-container mat-form-field { - flex: 1 1 100%; - max-width: 250px; + padding: 1em; } .chip-busy { @@ -270,7 +265,6 @@ mat-tree mat-tree-node.disabled:hover { color: white; } - .clients-card-container { display: flex; flex-wrap: wrap; @@ -317,13 +311,7 @@ mat-tree mat-tree-node.disabled:hover { margin: 0 4px; } -.main-container { - display: flex; - flex-direction: row; -} - .tree-container { - width: 25%; overflow-x: hidden; overflow-y: auto; } @@ -353,8 +341,8 @@ mat-tree mat-tree-node.disabled:hover { } .client-image { - max-width: 30px !important; - max-height: 30px !important; + max-width: 35px !important; + max-height: 35px !important; height: auto; } @@ -464,15 +452,6 @@ mat-tree mat-tree-node.disabled:hover { margin-top: 4px; } -.clients-view-header { - display: flex; - flex-direction: row; - justify-content: space-between; - margin-bottom: 1rem; - align-items: center; - padding-right: 1rem; -} - @media (max-width: 1560px) { .clients-view-header { display: flex; @@ -548,12 +527,6 @@ mat-button-toggle-group { background-color: #c7c7c7; } -.clients-container { - width: 75%; - box-sizing: border-box; - overflow-y: auto; -} - .cards-view { display: flex; width: 100%; diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 6ba9d30..b159d54 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -1,358 +1,372 @@ - -
- -
-

- {{ 'adminGroupsTitle' | translate }} -

-
-
- - - - - - +
+

+ {{ 'adminGroupsTitle' | translate }} +

+
+
+ + + + + + - -
-
- -
- -
- - - -
-
- - {{ 'searchTree' | translate }} - - - - - {{ 'searchClient' | translate }} - - - - - - +
- -
- -
- - - - - {{ - node.type === 'organizational-unit' ? 'apartment' - : node.type === 'classrooms-group' ? 'meeting_room' - : node.type === 'classroom' ? 'school' - : node.type === 'clients-group' ? 'lan' - : node.type === 'client' ? 'computer' - : 'group' - }} - - {{ node.name }} - - - - - - {{ - node.type === 'organizational-unit' ? 'apartment' - : node.type === 'classrooms-group' ? 'meeting_room' - : node.type === 'classroom' ? 'school' - : node.type === 'clients-group' ? 'lan' - : node.type === 'client' ? 'computer' - : 'group' - }} - - {{ node.name }} - - - IP: {{ node.ip }} - - - - -
+
+ +
- + + +
- - - - - - - - - - - - - + +
- -
-
-
- - {{ 'clients' | translate }} - {{ selectedNode?.name }} - + +
+
+ + {{ 'searchTree' | translate }} + + + + + {{ 'searchClient' | translate }} + + + + + + +
-
- - - - list {{ 'Vista Lista' | translate }} - - - grid_view {{ 'Vista Tarjeta' | translate }} - - + + +
+ + + + + {{ + node.type === 'organizational-unit' ? 'apartment' + : node.type === 'classrooms-group' ? 'meeting_room' + : node.type === 'classroom' ? 'school' + : node.type === 'clients-group' ? 'lan' + : node.type === 'client' ? 'computer' + : 'group' + }} + + {{ node.name }} + + + + + + {{ + node.type === 'organizational-unit' ? 'apartment' + : node.type === 'classrooms-group' ? 'meeting_room' + : node.type === 'classroom' ? 'school' + : node.type === 'clients-group' ? 'lan' + : node.type === 'client' ? 'computer' + : 'group' + }} + + {{ node.name }} + + - IP: {{ node.ip }} + + + +
+ + + + + + + + + + + + + + +
- + -
-
- -
- - -
-
-
- - - Client Icon + +
-
- {{ client.name }} - {{ client.ip }} - {{ client.mac }} -
- + +
+
+ + {{ 'clients' | translate }} + {{ selectedNode?.name }} + +
+
+ + + + list {{ 'Vista Lista' | translate }} + + + grid_view {{ 'Vista Tarjeta' | translate }} + + +
+
- + - + +
+
+ +
+ + +
+
+
+ + + Client Icon - - - - - - - + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + {{ 'status' | translate }} + Client Icon + {{ 'name' | translate }} + {{ client.name }} + IP + {{ client.ip }} + OG Live {{ client.ogLive?.date | date }} {{ 'maintenance' | translate }} {{ client.maintenance }} {{ 'subnet' | translate }} {{ client.subnet }} {{ 'pxeTemplate' | translate }} {{ client.template?.name }} {{ 'parent' | translate }} {{ client.parentName }} {{ 'actions' | translate }} + + + + + + + + +
+ +
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - {{ 'status' | translate }} - Client Icon - {{ 'name' | translate }} - {{ client.name }} - IP - {{ client.ip }} - OG Live {{ client.ogLive?.date | date }} {{ 'maintenance' | translate }} {{ client.maintenance }} {{ 'subnet' | translate }} {{ client.subnet }} {{ 'pxeTemplate' | translate }} {{ client.template?.name }} {{ 'parent' | translate }} {{ client.parentName }} {{ 'actions' | translate }} - - - - - - - - -
- -
+ + +
+ {{ 'noClients' | translate }} + error_outline +
+
- - -
- {{ 'noClients' | translate }} - error_outline -
-
+
-
- + +
\ No newline at end of file diff --git a/ogWebconsole/src/app/layout/header/header.component.css b/ogWebconsole/src/app/layout/header/header.component.css index b69be3a..52e3147 100644 --- a/ogWebconsole/src/app/layout/header/header.component.css +++ b/ogWebconsole/src/app/layout/header/header.component.css @@ -1,5 +1,5 @@ mat-toolbar { - height: 60px; + height: 7vh; background-color: #3f51b5; color: white; } diff --git a/ogWebconsole/src/app/layout/main-layout/main-layout.component.css b/ogWebconsole/src/app/layout/main-layout/main-layout.component.css index c60e4f2..1fd8655 100644 --- a/ogWebconsole/src/app/layout/main-layout/main-layout.component.css +++ b/ogWebconsole/src/app/layout/main-layout/main-layout.component.css @@ -1,19 +1,10 @@ -.header { - height: 10vh; -} - .container { width: 100vw; - height: calc(100vh - 10vh); + height: calc(100vh - 7vh); } .sidebar { - width: 250px; + width: 15vw; + min-width: 250px; z-index: auto !important; } - -.content { - margin: 0px 10px 10px 10px; - padding: 0px 10px 10px 10px; - box-sizing: border-box; -} diff --git a/ogWebconsole/src/app/layout/main-layout/main-layout.component.html b/ogWebconsole/src/app/layout/main-layout/main-layout.component.html index 43b94b3..59eebe9 100644 --- a/ogWebconsole/src/app/layout/main-layout/main-layout.component.html +++ b/ogWebconsole/src/app/layout/main-layout/main-layout.component.html @@ -1,4 +1,4 @@ - + From b29a3f58f11d02a814ec75320a094bd830c10e66 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 27 Feb 2025 11:05:26 +0100 Subject: [PATCH 21/38] refs #1558. Add client/subnet new UX modal --- .../add-user-modal.component.html | 8 ++ .../add-user-modal.component.ts | 16 +++- .../admin/users/users/users.component.ts | 5 + .../add-clients-to-subnet.component.css | 13 +++ .../add-clients-to-subnet.component.html | 9 +- .../add-clients-to-subnet.component.ts | 37 +++++--- .../create-subnet/create-subnet.component.css | 9 +- .../create-subnet.component.html | 88 ++++++------------ .../create-subnet/create-subnet.component.ts | 28 ------ .../ogdhcp/og-dhcp-subnets.component.html | 9 +- .../ogdhcp/og-dhcp-subnets.component.ts | 9 +- .../operation-result-dialog.component.spec.ts | 61 ++++++++++-- .../operation-result-dialog.component.ts | 13 ++- .../show-clients/show-clients.component.css | 20 ++-- .../show-clients/show-clients.component.html | 29 +++++- .../show-clients.component.spec.ts | 4 +- .../show-clients/show-clients.component.ts | 37 +++++++- .../app/layout/header/header.component.html | 2 +- .../src/app/layout/header/header.component.ts | 2 +- .../assets/images/ordenador_turning-off.png | Bin 0 -> 778 bytes 20 files changed, 243 insertions(+), 156 deletions(-) create mode 100644 ogWebconsole/src/assets/images/ordenador_turning-off.png diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html index b8cee9e..b7b0ef9 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html @@ -27,6 +27,14 @@ + + Vista tarjetas + + + {{ option.name }} + + + diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts index a785e39..86e49ee 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts @@ -24,6 +24,11 @@ export class AddUserModalComponent implements OnInit { organizationalUnits: any[] = []; userId: string | null = null; + protected views = [ + {value: 'card', name: 'Tarjetas'}, + {value: 'list', name: 'Listado'}, + ]; + constructor( public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, @@ -36,6 +41,7 @@ export class AddUserModalComponent implements OnInit { username: ['', Validators.required], password: ['', Validators.required], role: ['', Validators.required], + groupsView: ['card', Validators.required], organizationalUnits: [[]] }); } @@ -55,15 +61,14 @@ export class AddUserModalComponent implements OnInit { load(): void { this.dataService.getUser(this.data).subscribe({ next: (response) => { - console.log(response); const organizationalUnitIds = response.allowedOrganizationalUnits.map((unit: any) => unit['@id']); - // Patch the values to the form this.userForm.patchValue({ username: response.username, - role: response.userGroups[0]['@id'], - organizationalUnits: organizationalUnitIds + role: response.userGroups.length > 0 ? response.userGroups[0]['@id'] : null, + organizationalUnits: organizationalUnitIds, + groupsView: response.groupsView }); this.userId = response['@id']; @@ -85,7 +90,8 @@ export class AddUserModalComponent implements OnInit { allowedOrganizationalUnits: this.userForm.value.organizationalUnit, password: this.userForm.value.password, enabled: true, - userGroups: [this.userForm.value.role ] + userGroups: [this.userForm.value.role ], + groupsView: this.userForm.value.groupsView }; if (this.userId) { diff --git a/ogWebconsole/src/app/components/admin/users/users/users.component.ts b/ogWebconsole/src/app/components/admin/users/users/users.component.ts index 81656e9..3ca3f56 100644 --- a/ogWebconsole/src/app/components/admin/users/users/users.component.ts +++ b/ogWebconsole/src/app/components/admin/users/users/users.component.ts @@ -32,6 +32,11 @@ export class UsersComponent implements OnInit { header: 'Nombre de Usuario', cell: (user: any) => `${user.username}` }, + { + columnDef: 'groupsView', + header: 'Vista de Grupos', + cell: (user: any) => `${user.groupsView}` + }, { columnDef: 'allowedOrganizationalUnits', header: 'Unidades Organizacionales Permitidas', diff --git a/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.css index 3c43c3c..b0c1411 100644 --- a/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.css @@ -27,3 +27,16 @@ mat-dialog-actions { gap: 1em; padding: 1.5em; } + +.clients-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); /* 3 columnas */ + gap: 5px; /* Espaciado entre elementos */ +} + +.checkbox-group label { + font-weight: bold; + display: block; + margin-bottom: 10px; +} + diff --git a/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.html index 4c0b532..826c4b4 100644 --- a/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.html @@ -1,3 +1,5 @@ + +

Añade clientes a {{data.subnetName}}

@@ -10,7 +12,12 @@
-
+ + + +
diff --git a/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts index 7e72ac0..6699e4d 100644 --- a/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component.ts @@ -18,6 +18,7 @@ export class AddClientsToSubnetComponent implements OnInit { loading: boolean = true; unitControl = new FormControl(); childUnitControl = new FormControl(); + allSelected: boolean = false; constructor( private http: HttpClient, @@ -43,7 +44,7 @@ export class AddClientsToSubnetComponent implements OnInit { } loadChildUnits(event: any) { - this.http.get(`${this.baseUrl}/clients?organizationalUnit.id=${event.value.id}`).subscribe( + this.http.get(`${this.baseUrl}/clients?organizationalUnit.id=${event.value.id}&exists[subnet]=false`).subscribe( response => { this.clients = response['hydra:member']; }, @@ -51,37 +52,49 @@ export class AddClientsToSubnetComponent implements OnInit { ); } - toggleClientSelection(clientId: string): void { - const index = this.selectedClients.indexOf(clientId); - if (index >= 0) { - this.selectedClients.splice(index, 1); - } else { - this.selectedClients.push(clientId); - } - } - save() { + this.loading = true; const postData = { clients: this.selectedClients.map(clientId => `/clients/${clientId}`) }; this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe( (response: any) => { this.dialog.open(OperationResultDialogComponent, { - width: '600px', + width: '800px', data: { success: response.success || [], errors: response.errors || [] } }); + this.loading = false; this.dialogRef.close(this.selectedClients); }, error => { - console.error(`Error al asignar el cliente:`, error); this.toastService.error(`Error al asignar el cliente: ${error.error['hydra:description']}`); } ); } + toggleSelectAll() { + if (this.allSelected) { + this.selectedClients = []; + } else { + this.selectedClients = this.clients.map(client => client.uuid); + } + this.allSelected = !this.allSelected; + } + + toggleClientSelection(uuid: string) { + const index = this.selectedClients.indexOf(uuid); + if (index === -1) { + this.selectedClients.push(uuid); + } else { + this.selectedClients.splice(index, 1); + } + + this.allSelected = this.selectedClients.length === this.clients.length; + } + close() { this.dialogRef.close(); } diff --git a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css index 106da2f..24cf3c0 100644 --- a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css @@ -39,4 +39,11 @@ form { justify-content: flex-end; gap: 1em; padding: 1.5em; -} \ No newline at end of file +} + +.step-title { + font-family: 'Roboto', sans-serif; + color: #3f51b5; + margin: 40px 0 15px 0; + display: block; +} diff --git a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html index ed1940e..cbdfc10 100644 --- a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html @@ -1,68 +1,38 @@

{{ isEditMode ? 'Editar' : 'Añadir' }} subred

- - -
- - Nombre - - - - Netmask - - - - Dirección IP - - +
+ + Nombre + + + + Netmask + + + + Dirección IP + + - - - - Parámetros avanzados - - - - Next Server - - - - Boot File Name - - - - Router - - - -
- - - - - - -
- computer -
-
{{ client.name }}
-
{{ client.mac }}
-
-
- -
-
-
-
-
-
- + + Parámetros avanzados + + Next Server + + + + Boot File Name + + + + Router + + +
- \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts index 0f3f710..3dfaea1 100644 --- a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts @@ -18,9 +18,7 @@ export class CreateSubnetComponent implements OnInit { nextServer: string = ''; bootFileName: string = ''; router: string = ''; - syncronized: boolean = false; serverId: number = 0; - clients: any[] = []; isEditMode: boolean = false; constructor( @@ -46,9 +44,7 @@ export class CreateSubnetComponent implements OnInit { this.nextServer = this.data.nextServer; this.bootFileName = this.data.bootFileName; this.router = this.data.router; - this.syncronized = this.data.syncronized; this.serverId = this.data.serverId; - this.clients = this.data.clients } onNoClick(): void { @@ -69,12 +65,10 @@ export class CreateSubnetComponent implements OnInit { this.http.post(`${this.baseUrl}/subnets`, payload) .subscribe({ next: (response) => { - console.log('Success:', response); this.toastService.success('Configuración de red añadida exitosamente'); this.dialogRef.close(); }, error: (error) => { - console.error('Error:', error); this.toastService.error(error.error['hydra:description']); } }); @@ -82,35 +76,13 @@ export class CreateSubnetComponent implements OnInit { this.http.patch(`${this.baseUrl}/subnets/${this.subnetId}`, payload) .subscribe({ next: (response) => { - console.log('Success:', response); this.toastService.success('Configuración de red actualizada exitosamente'); this.dialogRef.close(); }, error: (error) => { - console.error('Error:', error); this.toastService.error(error.error['hydra:description']); } }); } } - - deleteClient(client: any): void { - const dialogRef = this.dialog.open(DeleteModalComponent, { - width: '300px', - data: { name: client.name } - }); - - dialogRef.afterClosed().subscribe(result => { - if (result) { - this.http.delete(`${this.baseUrl}/og-dhcp/server/${this.subnetId}/delete-host/${client.uuid}`, {}).subscribe({ - next: () => { - this.toastService.success('Cliente eliminado exitosamente'); - this.dialogRef.close(); - }, - error: (error) => { - this.toastService.error(error.error['hydra:description']); - } - }); - }}) - } } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html index ae5a071..0a3dc0b 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.html @@ -1,3 +1,5 @@ + +
diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts index af524d9..13d6396 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts @@ -35,7 +35,7 @@ export interface Subnet { templateUrl: './og-dhcp-subnets.component.html', styleUrls: ['./og-dhcp-subnets.component.css'] }) -export class OgDhcpSubnetsComponent { +export class OgDhcpSubnetsComponent implements OnInit { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'synchronized', 'serverId', 'clients', 'actions']; dataSource = new MatTableDataSource([]); @@ -79,7 +79,7 @@ export class OgDhcpSubnetsComponent { this.length = response['hydra:totalItems']; }, error: error => { - console.error('Error al cargar plantillas PXE:', error); + this.toastService.error(error.error['hydra:description']); } }); @@ -94,7 +94,6 @@ export class OgDhcpSubnetsComponent { this.toastService.success('Sincronización con componente DHCP exitosa'); this.loadSubnets() }, error => { - console.error('Error al sincronizar', error); this.toastService.error('Error al sincronizar'); }); } @@ -214,7 +213,7 @@ export class OgDhcpSubnetsComponent { height: '100vh', maxWidth: '100vw', maxHeight: '100vh', - data: { subnetId: subnet.id, subnetName: subnet.name } + data: { subnetId: subnet.id, subnetName: subnet.name, subnetUuid: subnet.uuid } }); dialogRef.afterClosed().subscribe(result => { @@ -224,7 +223,7 @@ export class OgDhcpSubnetsComponent { addClientsToSubnet(subnet: Subnet) { const dialogRef = this.dialog.open(AddClientsToSubnetComponent, { - width: '600px', + width: '800px', data: { subnetUuid: subnet.uuid, subnetName: subnet.name } }); diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts index 54efba1..e98fb7b 100644 --- a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts @@ -1,14 +1,34 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import {MAT_DIALOG_DATA } from '@angular/material/dialog'; import { OperationResultDialogComponent } from './operation-result-dialog.component'; +import {ShowClientsComponent} from "../show-clients/show-clients.component"; +import {MatExpansionModule} from "@angular/material/expansion"; +import {MatIconModule} from "@angular/material/icon"; +import {MatDividerModule} from "@angular/material/divider"; +import {MatFormFieldModule} from "@angular/material/form-field"; +import {MatSelectModule} from "@angular/material/select"; +import {MatPaginatorModule} from "@angular/material/paginator"; +import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; +import {FormsModule} from "@angular/forms"; +import {MatInputModule} from "@angular/material/input"; +import {MatDialog, MatDialogModule, MatDialogRef} from "@angular/material/dialog"; +import {MatTableModule} from "@angular/material/table"; +import {TranslateModule} from "@ngx-translate/core"; +import {JoyrideModule} from "ngx-joyride"; +import {HttpClient} from "@angular/common/http"; +import {ToastrService} from "ngx-toastr"; +import {LoadingComponent} from "../../../shared/loading/loading.component"; describe('OperationResultDialogComponent', () => { - let component: OperationResultDialogComponent; - let fixture: ComponentFixture; + let component: ShowClientsComponent; + let fixture: ComponentFixture; + let mockDialog: jasmine.SpyObj; + let mockHttpClient: jasmine.SpyObj; + let mockToastrService: jasmine.SpyObj; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [OperationResultDialogComponent], + declarations: [OperationResultDialogComponent, LoadingComponent], imports: [MatDialogModule], providers: [ { provide: MatDialogRef, useValue: {} }, @@ -17,7 +37,36 @@ describe('OperationResultDialogComponent', () => { }) .compileComponents(); - fixture = TestBed.createComponent(OperationResultDialogComponent); + await TestBed.configureTestingModule({ + declarations: [ShowClientsComponent], + imports: [ + MatExpansionModule, + MatIconModule, + MatDividerModule, + MatFormFieldModule, + MatSelectModule, + MatPaginatorModule, + BrowserAnimationsModule, + FormsModule, + MatInputModule, + MatDialogModule, + MatTableModule, + TranslateModule.forRoot(), + JoyrideModule.forRoot(), + ], + providers: [ + { provide: MatDialog, useValue: mockDialog }, + { provide: HttpClient, useValue: mockHttpClient }, + { provide: ToastrService, useValue: mockToastrService }, + { + provide: MatDialogRef, + useValue: {} + }, + ], + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShowClientsComponent); component = fixture.componentInstance; fixture.detectChanges(); }); @@ -25,4 +74,4 @@ describe('OperationResultDialogComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); -}); \ No newline at end of file +}); diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts index 5a9117b..b586f35 100644 --- a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.ts @@ -7,13 +7,6 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; template: `

Resultado de la operación

-
-

Éxitos

-
    -
  • {{ success.client }} ✅
  • -
-
-

Errores

    @@ -22,6 +15,12 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
+
+

Éxitos

+
    +
  • {{ success.client }} ✅
  • +
+
diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css index f28d4ee..d092e27 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.css @@ -40,19 +40,6 @@ form { gap: 1em; padding: 1.5em; } -.header-container { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px 10px; - border-bottom: 1px solid #ddd; -} - -.header-container-title { - flex-grow: 1; - text-align: left; - margin-left: 1em; -} .lists-container { padding: 16px; @@ -68,7 +55,12 @@ form { } .search-string { - flex: 2; + flex: 1; + padding: 5px; +} + +.search-select { + flex: 1; padding: 5px; } diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html index 2c6c669..5289199 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html @@ -1,6 +1,6 @@ -

Buscar clientes en {{data.subnetName}}

+

Gestionar clientes en {{data.subnetName}}

@@ -38,6 +38,17 @@ Pulsar 'enter' para buscar + + Estados + + + {{ option.name }} + + + +
@@ -54,12 +65,25 @@ {{ client.ogLive?.date | date }} - + + {{ client.organizationalUnit?.path }} + + + {{ column.cell(client) }}
Acciones + +
@@ -70,7 +94,6 @@ (page)="onPageChange($event)">
- diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts index be1714b..71af393 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts @@ -29,8 +29,6 @@ describe('ShowClientsComponent', () => { mockDialog = jasmine.createSpyObj('MatDialog', ['open']); mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']); mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']); - mockHttpClient.get.and.returnValue(of({ 'hydra:member': [], 'hydra:totalItems': 0 })); - mockHttpClient.post.and.returnValue(of({})); await TestBed.configureTestingModule({ declarations: [ShowClientsComponent, LoadingComponent], @@ -67,4 +65,4 @@ describe('ShowClientsComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); -}); \ No newline at end of file +}); diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts index ddff94b..578ff87 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts @@ -1,10 +1,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { ToastrService } from "ngx-toastr"; import { HttpClient } from "@angular/common/http"; -import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog"; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog"; import { MatTableDataSource } from "@angular/material/table"; -import { Subnet } from "../og-dhcp-subnets.component"; import { Client } from "../../groups/model/model"; +import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; @Component({ selector: 'app-show-clients', @@ -21,16 +21,27 @@ export class ShowClientsComponent implements OnInit { loading: boolean = false; filters: { [key: string]: string } = {}; + protected status = [ + {value: 'off', name: 'Apagado'}, + {value: 'initializing', name: 'Inicializando'}, + {value: 'og-live', name: 'Og Live'}, + {value: 'linux', name: 'Linux'}, + {value: 'linux-session', name: 'Linux Session'}, + {value: 'windows', name: 'Windows'}, + {value: 'mac', name: 'Mac'}, + ]; + columns = [ { columnDef: 'id', header: 'ID', cell: (client: Client) => client.id }, { columnDef: 'status', header: 'Estado', cell: (client: Client) => client.status }, { columnDef: 'name', header: 'Name', cell: (client: Client) => client.name }, { columnDef: 'ip', header: 'Ip', cell: (client: Client) => client.ip }, { columnDef: 'mac', header: 'Mac', cell: (client: Client) => client.mac }, + { columnDef: 'organizationalUnit', header: 'Ruta', cell: (client: Client) => client.organizationalUnit }, { columnDef: 'ogLive', header: 'OgLive', cell: (client: Client) => client.ogLive?.date }, ]; - displayedColumns: string[] = ['id', 'status', 'name', 'ip', 'mac', 'ogLive']; + displayedColumns: string[] = ['id', 'status', 'name', 'ip', 'mac', 'organizationalUnit', 'ogLive', 'actions']; constructor( private toastService: ToastrService, @@ -61,6 +72,26 @@ export class ShowClientsComponent implements OnInit { console.log(this.dataSource.data) } + deleteClient(client: any): void { + const dialogRef = this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: client.name } + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.http.delete(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/delete-host/${client.uuid}`, {}).subscribe({ + next: () => { + this.toastService.success('Cliente eliminado exitosamente de la red'); + this.loadData() + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + }}) + } + onNoClick(): void { this.dialogRef.close(); } diff --git a/ogWebconsole/src/app/layout/header/header.component.html b/ogWebconsole/src/app/layout/header/header.component.html index 852fa13..ce9bb4c 100644 --- a/ogWebconsole/src/app/layout/header/header.component.html +++ b/ogWebconsole/src/app/layout/header/header.component.html @@ -45,4 +45,4 @@
- \ No newline at end of file + diff --git a/ogWebconsole/src/app/layout/header/header.component.ts b/ogWebconsole/src/app/layout/header/header.component.ts index 51ff2ea..e926157 100644 --- a/ogWebconsole/src/app/layout/header/header.component.ts +++ b/ogWebconsole/src/app/layout/header/header.component.ts @@ -46,5 +46,5 @@ export class HeaderComponent implements OnInit { width: '400px', }); } - + } diff --git a/ogWebconsole/src/assets/images/ordenador_turning-off.png b/ogWebconsole/src/assets/images/ordenador_turning-off.png new file mode 100644 index 0000000000000000000000000000000000000000..69da340ebbd6f1cecc252538283033f8a0596e35 GIT binary patch literal 778 zcmV+l1NHogP)L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000Mc zNliru-w6&33nUbt)n)(y0q03XK~y-)g_BWl;~)@(LqSS!V+bt{hj?%tuV}AA7$^S! z|LqoRr%83v%|`OWe4b@2vfKS%!Teic^&>E-+W(l1h#;6?oAwU_*9CYd0$wj)U*r6! z;T7fzjK_BXcJZ=lxa192Qd(vG5akNQBN6PPINx*9zL82<ig+pszFBt2 zWkX4LxhI@VSwWtvz9iq;Z(ux`Qvnox04W>tse||3&jd2bD^uR@sOBB$%tee@7;N;A4N<^`G3M{u7L#-#*$aQHFJ$zj`q;EY4-aK5?humWfFoC9c#^Yxli z&M8l~IbnfQO*kV5u}w+fLI^sqfC`KQp6Q(Vns50UVu)BKxbi#H8hJpGTR`oC2?mUT z9%38N^)aR0LO@2qARIUDz`;O(NX%~?7hp%>No#ai67+!xr$roj1dB-1bzTs z2ukRqYsHPx# literal 0 HcmV?d00001 From 6fd741e7b49a0b5204151442abbf04d53eb089a0 Mon Sep 17 00:00:00 2001 From: llara Date: Thu, 27 Feb 2025 16:12:13 +0100 Subject: [PATCH 22/38] refs #1619.Refactor: update layout dimensions and styles for groups component --- .../components/groups/groups.component.css | 57 +++++- .../components/groups/groups.component.html | 182 +++++++++--------- .../operation-result-dialog.component.spec.ts | 60 +++--- .../show-clients.component.spec.ts | 12 +- .../app/layout/header/header.component.css | 1 + 5 files changed, 172 insertions(+), 140 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index dcf9a86..7bcb7f5 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -3,6 +3,7 @@ flex-direction: column; width: 100%; height: 100%; + overflow: hidden; } .header-container { @@ -18,6 +19,7 @@ flex-direction: row; width: 100%; height: 100%; + overflow: hidden; } .header-container-title { @@ -41,7 +43,10 @@ .clients-container { flex-grow: 1; box-sizing: border-box; - overflow-y: auto; + overflow: hidden; + display: flex; + flex-direction: column; + padding: 0rem 1rem 0rem 0.5rem; } .clients-view-header { @@ -52,7 +57,36 @@ margin-top: 0.5rem; align-items: center; padding-right: 1rem; +} + +.clients-view { flex-grow: 1; + overflow-y: auto; +} + +.cards-view { + display: flex; + flex-grow: 1; + overflow-y: auto; + width: 100%; +} + +.clients-table { + max-height: calc(100vh - 330px); + overflow: auto; + display: flex; + flex-direction: column; +} + +.clients-table table { + flex-grow: 1; + overflow: auto; +} + +.paginator-container { + display: flex; + justify-content: end; + margin-top: auto; } .actions mat-icon { @@ -234,7 +268,7 @@ mat-tree mat-tree-node.disabled:hover { display: flex; flex-direction: column; justify-content: start; - padding: 1em; + padding: 1em 1em 0em 1em; } .chip-busy { @@ -311,9 +345,21 @@ mat-tree mat-tree-node.disabled:hover { margin: 0 4px; } +.filters-and-tree-container { + display: flex; + flex-direction: column; + height: 100%; +} + +.filters-panel { + flex-shrink: 0; +} + .tree-container { - overflow-x: hidden; + flex-grow: 1; overflow-y: auto; + max-height: calc(100% - var(--filters-panel-height)); + margin-bottom: 1rem; } .client-item { @@ -527,11 +573,6 @@ mat-button-toggle-group { background-color: #c7c7c7; } -.cards-view { - display: flex; - width: 100%; -} - .clients-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index b159d54..dd16324 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -198,7 +198,7 @@ -
+
@@ -260,100 +260,102 @@
-
- - - - - - - - - +
+
+
- - - - - - {{ 'status' | translate }} - Client Icon -
+ + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - + - - - -
+ + + + + + {{ 'status' | translate }} + Client Icon + {{ 'name' | translate }} - {{ client.name }} - IP - {{ client.ip }} - OG Live {{ client.ogLive?.date | date }} {{ 'name' | translate }} + {{ client.name }} + IP + {{ client.ip }} + OG Live {{ client.ogLive?.date | date }} {{ 'maintenance' | translate }} {{ client.maintenance }} {{ 'subnet' | translate }} {{ client.subnet }} {{ 'pxeTemplate' | translate }} {{ client.template?.name }} {{ 'maintenance' | translate }} {{ client.maintenance }} {{ 'subnet' | translate }} {{ client.subnet }} {{ 'pxeTemplate' | translate }} {{ client.template?.name }} {{ 'parent' | translate }} {{ client.parentName }} {{ 'parent' | translate }} {{ client.parentName }} {{ 'actions' | translate }} - - - - {{ 'actions' | translate }} + - - - - -
+ + + + + + + + + + + + +
diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts index e98fb7b..e7a0822 100644 --- a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts @@ -1,27 +1,25 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import {MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef, MatDialog } from '@angular/material/dialog'; import { OperationResultDialogComponent } from './operation-result-dialog.component'; -import {ShowClientsComponent} from "../show-clients/show-clients.component"; -import {MatExpansionModule} from "@angular/material/expansion"; -import {MatIconModule} from "@angular/material/icon"; -import {MatDividerModule} from "@angular/material/divider"; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatSelectModule} from "@angular/material/select"; -import {MatPaginatorModule} from "@angular/material/paginator"; -import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; -import {FormsModule} from "@angular/forms"; -import {MatInputModule} from "@angular/material/input"; -import {MatDialog, MatDialogModule, MatDialogRef} from "@angular/material/dialog"; -import {MatTableModule} from "@angular/material/table"; -import {TranslateModule} from "@ngx-translate/core"; -import {JoyrideModule} from "ngx-joyride"; -import {HttpClient} from "@angular/common/http"; -import {ToastrService} from "ngx-toastr"; -import {LoadingComponent} from "../../../shared/loading/loading.component"; +import { MatExpansionModule } from "@angular/material/expansion"; +import { MatIconModule } from "@angular/material/icon"; +import { MatDividerModule } from "@angular/material/divider"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatSelectModule } from "@angular/material/select"; +import { MatPaginatorModule } from "@angular/material/paginator"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { FormsModule } from "@angular/forms"; +import { MatInputModule } from "@angular/material/input"; +import { MatTableModule } from "@angular/material/table"; +import { TranslateModule } from "@ngx-translate/core"; +import { JoyrideModule } from "ngx-joyride"; +import { HttpClient } from "@angular/common/http"; +import { ToastrService } from "ngx-toastr"; +import { LoadingComponent } from "../../../shared/loading/loading.component"; describe('OperationResultDialogComponent', () => { - let component: ShowClientsComponent; - let fixture: ComponentFixture; + let component: OperationResultDialogComponent; + let fixture: ComponentFixture; let mockDialog: jasmine.SpyObj; let mockHttpClient: jasmine.SpyObj; let mockToastrService: jasmine.SpyObj; @@ -29,17 +27,8 @@ describe('OperationResultDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [OperationResultDialogComponent, LoadingComponent], - imports: [MatDialogModule], - providers: [ - { provide: MatDialogRef, useValue: {} }, - { provide: MAT_DIALOG_DATA, useValue: { success: [], errors: [] } } - ] - }) - .compileComponents(); - - await TestBed.configureTestingModule({ - declarations: [ShowClientsComponent], imports: [ + MatDialogModule, MatExpansionModule, MatIconModule, MatDividerModule, @@ -49,24 +38,21 @@ describe('OperationResultDialogComponent', () => { BrowserAnimationsModule, FormsModule, MatInputModule, - MatDialogModule, MatTableModule, TranslateModule.forRoot(), JoyrideModule.forRoot(), ], providers: [ + { provide: MatDialogRef, useValue: {} }, + { provide: MAT_DIALOG_DATA, useValue: { success: [], errors: [] } }, { provide: MatDialog, useValue: mockDialog }, { provide: HttpClient, useValue: mockHttpClient }, { provide: ToastrService, useValue: mockToastrService }, - { - provide: MatDialogRef, - useValue: {} - }, ], }) .compileComponents(); - fixture = TestBed.createComponent(ShowClientsComponent); + fixture = TestBed.createComponent(OperationResultDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); @@ -74,4 +60,4 @@ describe('OperationResultDialogComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); -}); +}); \ No newline at end of file diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts index 71af393..16d442b 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.spec.ts @@ -13,10 +13,12 @@ import { MatTableModule } from "@angular/material/table"; import { TranslateModule } from "@ngx-translate/core"; import { JoyrideModule } from "ngx-joyride"; import { MatDialog, MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; -import { HttpClient } from "@angular/common/http"; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { HttpClient } from '@angular/common/http'; import { ToastrService } from "ngx-toastr"; import { of } from "rxjs"; import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; // Add this import describe('ShowClientsComponent', () => { let component: ShowClientsComponent; @@ -27,7 +29,6 @@ describe('ShowClientsComponent', () => { beforeEach(async () => { mockDialog = jasmine.createSpyObj('MatDialog', ['open']); - mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']); mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']); await TestBed.configureTestingModule({ @@ -46,16 +47,17 @@ describe('ShowClientsComponent', () => { MatTableModule, TranslateModule.forRoot(), JoyrideModule.forRoot(), + HttpClientTestingModule, + MatProgressSpinnerModule // Add this import ], providers: [ { provide: MatDialog, useValue: mockDialog }, - { provide: HttpClient, useValue: mockHttpClient }, { provide: ToastrService, useValue: mockToastrService }, { provide: MatDialogRef, useValue: {} }, { provide: MAT_DIALOG_DATA, useValue: {} }, ], }) - .compileComponents(); + .compileComponents(); fixture = TestBed.createComponent(ShowClientsComponent); component = fixture.componentInstance; @@ -65,4 +67,4 @@ describe('ShowClientsComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); -}); +}); \ No newline at end of file diff --git a/ogWebconsole/src/app/layout/header/header.component.css b/ogWebconsole/src/app/layout/header/header.component.css index 52e3147..aa08889 100644 --- a/ogWebconsole/src/app/layout/header/header.component.css +++ b/ogWebconsole/src/app/layout/header/header.component.css @@ -1,5 +1,6 @@ mat-toolbar { height: 7vh; + min-height: 60px; background-color: #3f51b5; color: white; } From 4ef99a7c9886c0e68c6fba74967237abe345fe37 Mon Sep 17 00:00:00 2001 From: llara Date: Thu, 27 Feb 2025 16:15:32 +0100 Subject: [PATCH 23/38] Refactor: improve test setup by adding mock services for dialog and HTTP client --- .../operation-result-dialog.component.spec.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts index e7a0822..611cc1c 100644 --- a/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts +++ b/ogWebconsole/src/app/components/ogdhcp/operation-result-dialog/operation-result-dialog.component.spec.ts @@ -8,10 +8,10 @@ import { MatFormFieldModule } from "@angular/material/form-field"; import { MatSelectModule } from "@angular/material/select"; import { MatPaginatorModule } from "@angular/material/paginator"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; -import { FormsModule } from "@angular/forms"; -import { MatInputModule } from "@angular/material/input"; -import { MatTableModule } from "@angular/material/table"; -import { TranslateModule } from "@ngx-translate/core"; +import { FormsModule } from '@angular/forms'; +import { MatInputModule } from '@angular/material/input'; +import { MatTableModule } from '@angular/material/table'; +import { TranslateModule } from '@ngx-translate/core'; import { JoyrideModule } from "ngx-joyride"; import { HttpClient } from "@angular/common/http"; import { ToastrService } from "ngx-toastr"; @@ -25,6 +25,10 @@ describe('OperationResultDialogComponent', () => { let mockToastrService: jasmine.SpyObj; beforeEach(async () => { + mockDialog = jasmine.createSpyObj('MatDialog', ['open']); + mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post']); + mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']); + await TestBed.configureTestingModule({ declarations: [OperationResultDialogComponent, LoadingComponent], imports: [ From 20452c83eb360479c48956d5c8ca85ad9c7e05a8 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 27 Feb 2025 16:40:05 +0100 Subject: [PATCH 24/38] refs #1563. New field groupsView in user --- .../add-user-modal.component.html | 2 ++ .../add-user-modal.component.ts | 23 +++++++++++++++---- .../admin/users/users/users.component.html | 13 +++++++++-- .../app/components/groups/groups.component.ts | 3 ++- .../app/components/login/login.component.ts | 10 ++++++-- 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html index b7b0ef9..b074aa4 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.html @@ -1,3 +1,5 @@ + +

{{ 'dialogTitleAddUser' | translate }}

diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts index 86e49ee..5c742c6 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts @@ -23,6 +23,7 @@ export class AddUserModalComponent implements OnInit { userGroups: UserGroup[] = []; organizationalUnits: any[] = []; userId: string | null = null; + loading: boolean = false; protected views = [ {value: 'card', name: 'Tarjetas'}, @@ -50,18 +51,22 @@ export class AddUserModalComponent implements OnInit { this.dataService.getUserGroups().subscribe((data) => { this.userGroups = data['hydra:member']; }); + this.dataService.getOrganizationalUnits().subscribe((data) => { this.organizationalUnits = data['hydra:member'].filter((item: any) => item.type === 'organizational-unit'); }); + if (this.data) { - this.load() + this.load(); + } else { + this.userForm.get('password')?.setValidators([Validators.required]); } } load(): void { + this.loading = true; this.dataService.getUser(this.data).subscribe({ next: (response) => { - const organizationalUnitIds = response.allowedOrganizationalUnits.map((unit: any) => unit['@id']); this.userForm.patchValue({ @@ -72,9 +77,13 @@ export class AddUserModalComponent implements OnInit { }); this.userId = response['@id']; + this.userForm.get('password')?.clearValidators(); + this.userForm.get('password')?.updateValueAndValidity(); + this.loading = false; }, error: (err) => { - console.error('Error fetching remote calendar:', err); + this.loading = false; + console.error('Error fetching user:', err); } }); } @@ -93,16 +102,19 @@ export class AddUserModalComponent implements OnInit { userGroups: [this.userForm.value.role ], groupsView: this.userForm.value.groupsView }; + this.loading = true; if (this.userId) { this.http.put(`${this.baseUrl}${this.userId}`, payload).subscribe( (response) => { this.toastService.success('Usuario editado correctamente'); this.dialogRef.close(); + this.loading = false }, (error) => { this.toastService.error(error['error']['hydra:description']); - console.error('Error al editar el rol', error); + this.loading = false + } ); } else { @@ -110,10 +122,11 @@ export class AddUserModalComponent implements OnInit { (response) => { this.toastService.success('Usuario añadido correctamente'); this.dialogRef.close(); + this.loading = false }, (error) => { this.toastService.error(error['error']['hydra:description']); - console.error('Error al añadir añadido', error); + this.loading = false } ); } diff --git a/ogWebconsole/src/app/components/admin/users/users/users.component.html b/ogWebconsole/src/app/components/admin/users/users/users.component.html index a1cd0ac..efa6f75 100644 --- a/ogWebconsole/src/app/components/admin/users/users/users.component.html +++ b/ogWebconsole/src/app/components/admin/users/users/users.component.html @@ -26,7 +26,16 @@ - + @@ -49,4 +58,4 @@ - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index 4970660..ff484ad 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -54,7 +54,7 @@ export class GroupsComponent implements OnInit, OnDestroy { selectedClients = new MatTableDataSource([]); selection = new SelectionModel(true, []); cols = 4; - currentView: 'card' | 'list' = 'list'; + currentView: string = 'list'; savedFilterNames: [string, string][] = []; selectedTreeFilter = ''; syncStatus = false; @@ -107,6 +107,7 @@ export class GroupsComponent implements OnInit, OnDestroy { ); this.treeDataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); + this.currentView = localStorage.getItem('groupsView') || 'list'; } diff --git a/ogWebconsole/src/app/components/login/login.component.ts b/ogWebconsole/src/app/components/login/login.component.ts index d2347a4..ff328ab 100644 --- a/ogWebconsole/src/app/components/login/login.component.ts +++ b/ogWebconsole/src/app/components/login/login.component.ts @@ -3,6 +3,7 @@ import {Component, signal} from '@angular/core'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import {ToastrService} from "ngx-toastr"; +import {jwtDecode} from "jwt-decode"; @Component({ selector: 'app-login', @@ -16,6 +17,7 @@ export class LoginComponent { }; errorMessage: string = ''; isLoading: boolean = false; + decodedToken: any; baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; @@ -23,7 +25,7 @@ export class LoginComponent { private http: HttpClient, private router: Router, private toastService: ToastrService, - private translateService: TranslateService + private translateService: TranslateService ) { const savedLanguage = localStorage.getItem('language') || 'es'; this.translateService.use(savedLanguage); @@ -56,7 +58,11 @@ export class LoginComponent { localStorage.setItem('loginToken', res.token); localStorage.setItem('refreshToken', res.refreshToken); localStorage.setItem('username', this.loginObj.username); - this.openSnackBar(false, 'Bienvenido ' + this.loginObj.username); + + this.decodedToken = jwtDecode(res.token); + localStorage.setItem('groupsView', this.decodedToken.groupsView); + + this.openSnackBar(false, 'Bienvenido ' + this.loginObj.username); this.router.navigateByUrl('/groups'); } this.isLoading = false; From 7d2c0e4c2997b9f0b7c82a40f2ac1b2254abd966 Mon Sep 17 00:00:00 2001 From: llara Date: Fri, 28 Feb 2025 09:15:39 +0100 Subject: [PATCH 25/38] test: update mock HTTP response in login component tests --- .../components/login/login.component.spec.ts | 2 +- .../app/components/login/login.component.ts | 108 +++++++++--------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/ogWebconsole/src/app/components/login/login.component.spec.ts b/ogWebconsole/src/app/components/login/login.component.spec.ts index 86ecb69..0406e8b 100644 --- a/ogWebconsole/src/app/components/login/login.component.spec.ts +++ b/ogWebconsole/src/app/components/login/login.component.spec.ts @@ -56,7 +56,7 @@ describe('LoginComponent', () => { it('should call onLogin and navigate on successful login', () => { const mockRouter = spyOn(component['router'], 'navigateByUrl'); - const mockHttp = spyOn(component['http'], 'post').and.returnValue(of({ token: '123', refreshToken: '456' })); + const mockHttp = spyOn(component['http'], 'post').and.returnValue(of({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', refreshToken: '456' })); component.loginObj.username = 'testUser'; component.loginObj.password = 'testPass'; diff --git a/ogWebconsole/src/app/components/login/login.component.ts b/ogWebconsole/src/app/components/login/login.component.ts index ff328ab..088d53e 100644 --- a/ogWebconsole/src/app/components/login/login.component.ts +++ b/ogWebconsole/src/app/components/login/login.component.ts @@ -1,9 +1,9 @@ import { HttpClient } from '@angular/common/http'; -import {Component, signal} from '@angular/core'; +import { Component, signal } from '@angular/core'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import {ToastrService} from "ngx-toastr"; -import {jwtDecode} from "jwt-decode"; +import { ToastrService } from "ngx-toastr"; +import { jwtDecode } from "jwt-decode"; @Component({ selector: 'app-login', @@ -11,69 +11,69 @@ import {jwtDecode} from "jwt-decode"; styleUrls: ['./login.component.css'], }) export class LoginComponent { - loginObj: any = { - "username": "", - "password": "" - }; - errorMessage: string = ''; - isLoading: boolean = false; - decodedToken: any; + loginObj: any = { + "username": "", + "password": "" + }; + errorMessage: string = ''; + isLoading: boolean = false; + decodedToken: any; - baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - constructor( - private http: HttpClient, - private router: Router, - private toastService: ToastrService, - private translateService: TranslateService + constructor( + private http: HttpClient, + private router: Router, + private toastService: ToastrService, + private translateService: TranslateService ) { const savedLanguage = localStorage.getItem('language') || 'es'; this.translateService.use(savedLanguage); } - onLogin() { - this.errorMessage = ''; - this.isLoading = true; + onLogin() { + this.errorMessage = ''; + this.isLoading = true; - if (!this.loginObj.username || !this.loginObj.password) { - if (!this.loginObj.username) { - document.getElementById('username')?.classList.add('invalid'); - } else { - document.getElementById('username')?.classList.remove('invalid'); - } + if (!this.loginObj.username || !this.loginObj.password) { + if (!this.loginObj.username) { + document.getElementById('username')?.classList.add('invalid'); + } else { + document.getElementById('username')?.classList.remove('invalid'); + } - if (!this.loginObj.password) { - document.getElementById('password')?.classList.add('invalid'); - } else { - document.getElementById('password')?.classList.remove('invalid'); - } + if (!this.loginObj.password) { + document.getElementById('password')?.classList.add('invalid'); + } else { + document.getElementById('password')?.classList.remove('invalid'); + } - this.isLoading = false; - return; - } - - this.http.post(`${this.baseUrl}/auth/login`, this.loginObj).subscribe({ - next: (res: any) => { - if (res.token) { - localStorage.setItem('loginToken', res.token); - localStorage.setItem('refreshToken', res.refreshToken); - localStorage.setItem('username', this.loginObj.username); - - this.decodedToken = jwtDecode(res.token); - localStorage.setItem('groupsView', this.decodedToken.groupsView); - - this.openSnackBar(false, 'Bienvenido ' + this.loginObj.username); - this.router.navigateByUrl('/groups'); - } - this.isLoading = false; - }, - error: (err) => { - this.isLoading = false; - this.openSnackBar(true, 'Error al iniciar sesión: ' + err.error.message); - } - }); + this.isLoading = false; + return; } + this.http.post(`${this.baseUrl}/auth/login`, this.loginObj).subscribe({ + next: (res: any) => { + if (res.token) { + localStorage.setItem('loginToken', res.token); + localStorage.setItem('refreshToken', res.refreshToken); + localStorage.setItem('username', this.loginObj.username); + + this.decodedToken = jwtDecode(res.token); + localStorage.setItem('groupsView', this.decodedToken.groupsView); + + this.openSnackBar(false, 'Bienvenido ' + this.loginObj.username); + this.router.navigateByUrl('/groups'); + } + this.isLoading = false; + }, + error: (err) => { + this.isLoading = false; + this.openSnackBar(true, 'Error al iniciar sesión: ' + err.error.message); + } + }); + } + hide = signal(true); clickEvent(event: Event) { event.stopPropagation(); From a29670675760e45abd51fed117982c7bb3f62660 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 28 Feb 2025 09:21:08 +0100 Subject: [PATCH 26/38] refs #1567. New subnet field: 'dns' --- .../create-subnet/create-subnet.component.css | 4 - .../create-subnet.component.html | 82 ++++++++++------ .../create-subnet/create-subnet.component.ts | 97 ++++++++++--------- .../ogdhcp/og-dhcp-subnets.component.ts | 4 +- 4 files changed, 105 insertions(+), 82 deletions(-) diff --git a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css index 24cf3c0..c0a1dd5 100644 --- a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.css @@ -2,10 +2,6 @@ width: 100%; } -form { - padding: 20px; -} - .spacing-container { margin-top: 20px; margin-bottom: 16px; diff --git a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html index cbdfc10..9246697 100644 --- a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.html @@ -1,38 +1,62 @@

{{ isEditMode ? 'Editar' : 'Añadir' }} subred

-
- - Nombre - - - - Netmask - - - - Dirección IP - - + +
+ + Nombre + + + El nombre de la subred es obligatorio. + + - - Parámetros avanzados - - Next Server - - - - Boot File Name - - - - Router - - -
+ + Netmask + + + El netmask de la subred es obligatorio. + + + + + Dirección IP + + + La ip de la subred es obligatorio. + + + + + Parámetros avanzados + + + Next Server + + + + + Boot File Name + + + + + Router + + + + + DNS + + + Formato inválido. Introduzca direcciones IP separadas por comas. + + +
+
- + diff --git a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts index 3dfaea1..bf37323 100644 --- a/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/create-subnet/create-subnet.component.ts @@ -1,8 +1,8 @@ import { HttpClient } from '@angular/common/http'; import { Component, Inject, OnInit } from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; -import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component"; @Component({ selector: 'app-create-subnet', @@ -11,23 +11,28 @@ import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/de }) export class CreateSubnetComponent implements OnInit { baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - subnetId: string | null = null; - name: string = ''; - netmask: string = ''; - ipAddress: string = ''; - nextServer: string = ''; - bootFileName: string = ''; - router: string = ''; - serverId: number = 0; + subnetForm: FormGroup; isEditMode: boolean = false; + subnetId: string | null = null; constructor( private toastService: ToastrService, private http: HttpClient, + private fb: FormBuilder, public dialogRef: MatDialogRef, public dialog: MatDialog, @Inject(MAT_DIALOG_DATA) public data: any - ) { } + ) { + this.subnetForm = this.fb.group({ + name: ['', Validators.required], + netmask: ['', Validators.required], + ipAddress: ['', Validators.required], + router: [''], + dns: ['', Validators.pattern(/^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?),)*((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/)], + nextServer: [''], + bootFileName: [''] + }); + } ngOnInit(): void { if (this.data) { @@ -38,13 +43,15 @@ export class CreateSubnetComponent implements OnInit { loadData() { this.subnetId = this.data.uuid; - this.name = this.data.name; - this.netmask = this.data.netmask; - this.ipAddress = this.data.ipAddress; - this.nextServer = this.data.nextServer; - this.bootFileName = this.data.bootFileName; - this.router = this.data.router; - this.serverId = this.data.serverId; + this.subnetForm.patchValue({ + name: this.data.name, + netmask: this.data.netmask, + dns: this.data.dns, + ipAddress: this.data.ipAddress, + nextServer: this.data.nextServer, + bootFileName: this.data.bootFileName, + router: this.data.router + }); } onNoClick(): void { @@ -52,37 +59,33 @@ export class CreateSubnetComponent implements OnInit { } save(): void { - const payload = { - name: this.name, - netmask: this.netmask, - ipAddress: this.ipAddress, - router: this.router || null, - nextServer: this.nextServer || null, - bootFileName: this.bootFileName || null - }; + if (this.subnetForm.invalid) { + this.toastService.error('Por favor, revisa los campos del formulario'); + return; + } - if (!this.data){ - this.http.post(`${this.baseUrl}/subnets`, payload) - .subscribe({ - next: (response) => { - this.toastService.success('Configuración de red añadida exitosamente'); - this.dialogRef.close(); - }, - error: (error) => { - this.toastService.error(error.error['hydra:description']); - } - }); + const payload = this.subnetForm.value; + + if (!this.isEditMode) { + this.http.post(`${this.baseUrl}/subnets`, payload).subscribe({ + next: () => { + this.toastService.success('Configuración de red añadida exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); } else { - this.http.patch(`${this.baseUrl}/subnets/${this.subnetId}`, payload) - .subscribe({ - next: (response) => { - this.toastService.success('Configuración de red actualizada exitosamente'); - this.dialogRef.close(); - }, - error: (error) => { - this.toastService.error(error.error['hydra:description']); - } - }); + this.http.patch(`${this.baseUrl}/subnets/${this.subnetId}`, payload).subscribe({ + next: () => { + this.toastService.success('Configuración de red actualizada exitosamente'); + this.dialogRef.close(); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); } } } diff --git a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts index 13d6396..4932267 100644 --- a/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/og-dhcp-subnets.component.ts @@ -66,10 +66,8 @@ export class OgDhcpSubnetsComponent implements OnInit { ngOnInit() { this.loading = true; - this.loadSubnets(); this.loadAlert() this.syncSubnets() - this.loading = false; } loadSubnets() { @@ -93,7 +91,9 @@ export class OgDhcpSubnetsComponent implements OnInit { .subscribe(response => { this.toastService.success('Sincronización con componente DHCP exitosa'); this.loadSubnets() + this.loading = false; }, error => { + this.loading = false; this.toastService.error('Error al sincronizar'); }); } From a6356e1457cdda31f0f7c3579d33b3db0d0d25d1 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 28 Feb 2025 10:58:33 +0100 Subject: [PATCH 27/38] Updated groups paginator --- .../components/groups/groups.component.html | 10 ++++++++-- .../app/components/groups/groups.component.ts | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index dd16324..e9a6172 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -356,7 +356,13 @@
{{ column.header }} {{ column.cell(user) }} + + + {{ user[column.columnDef] === 'card' ? 'Vista tarjetas' : 'Listado' }} + + + + {{ column.cell(user) }} + +
- + +
@@ -371,4 +377,4 @@
-
\ No newline at end of file +
diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index ff484ad..ebb0b58 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -19,7 +19,7 @@ import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/del import { ClassroomViewDialogComponent } from './shared/classroom-view/classroom-view-modal'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; -import { MatPaginator } from '@angular/material/paginator'; +import {MatPaginator, PageEvent} from '@angular/material/paginator'; import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component"; import { SelectionModel } from "@angular/cdk/collections"; @@ -41,6 +41,10 @@ export class GroupsComponent implements OnInit, OnDestroy { organizationalUnits: UnidadOrganizativa[] = []; selectedUnidad: UnidadOrganizativa | null = null; selectedDetail: UnidadOrganizativa | null = null; + length: number = 0; + itemsPerPage: number = 10; + page: number = 0; + pageSizeOptions: number[] = [5, 10, 20, 40, 100]; initialLoading: boolean = true; isLoadingClients: boolean = false; searchTerm = ''; @@ -334,11 +338,12 @@ export class GroupsComponent implements OnInit, OnDestroy { } - public fetchClientsForNode(node: TreeNode, selectedClientsBeforeEdit: string[] = []): void { + public fetchClientsForNode(node: any, selectedClientsBeforeEdit: string[] = []): void { this.isLoadingClients = true; - this.http.get(`${this.baseUrl}/clients?organizationalUnit.id=${node.id}`).subscribe({ + this.http.get(`${this.baseUrl}/clients?organizationalUnit.id=${node.id}&page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}`).subscribe({ next: (response) => { this.selectedClients.data = response['hydra:member']; + this.length = response['hydra:totalItems']; this.arrayClients = this.selectedClients.data; this.hasClients = node.hasClients ?? false; this.isLoadingClients = false; @@ -732,4 +737,11 @@ export class GroupsComponent implements OnInit, OnDestroy { inputElement.value = ''; this.filterClients(''); } + + onPageChange(event: PageEvent): void { + this.page = event.pageIndex; + this.itemsPerPage = event.pageSize; + this.length = event.length; + this.fetchClientsForNode(this.selectedNode); + } } From b7e059586756ed68b7ae2c4e3809cff3018dd6c7 Mon Sep 17 00:00:00 2001 From: llara Date: Fri, 28 Feb 2025 11:25:33 +0100 Subject: [PATCH 28/38] style: clean up and optimize CSS for groups component; enhance HTML structure and improve responsiveness --- .../components/groups/groups.component.css | 193 ++---------------- .../components/groups/groups.component.html | 14 +- 2 files changed, 28 insertions(+), 179 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index 7bcb7f5..e9499bd 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -34,12 +34,6 @@ padding-right: 0.5rem; } -.button-container { - display: flex; - justify-content: center; - margin: 20px 0; -} - .clients-container { flex-grow: 1; box-sizing: border-box; @@ -99,15 +93,6 @@ color: #1976d2; } -.empty-list { - display: flex; - justify-content: center; - align-items: center; - height: 200px; - font-size: 16px; - color: #777; -} - .search-container { display: flex; gap: 20px; @@ -118,19 +103,7 @@ flex: 1; } -.filters { - padding: 20px; - background-color: #f9f9f9; - border: 1px solid #ddd; - border-radius: 8px; -} - @media (max-width: 1024px) { - .card-container { - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: 15px; - } - .header-container { flex-direction: column; gap: 10px; @@ -142,16 +115,6 @@ } } -@media (max-width: 768px) { - mat-card { - padding: 12px; - } - - .unidad-card { - font-size: 12px; - } -} - mat-tree { background-color: #f9f9f9; padding: 0px 10px 10px 10px; @@ -264,41 +227,6 @@ mat-tree mat-tree-node.disabled:hover { display: none; } -.filters-container { - display: flex; - flex-direction: column; - justify-content: start; - padding: 1em 1em 0em 1em; -} - -.chip-busy { - background-color: indianred !important; - color: black; -} - -.chip-og-live { - background-color: yellow !important; - color: black; -} - -.chip-windows, -.chip-windows-session, -.chip-macos { - background-color: cornflowerblue !important; - color: white; -} - -.chip-linux, -.chip-linux-session { - background-color: mediumpurple !important; - color: white; -} - -.chip-off { - background-color: darkgrey !important; - color: white; -} - .clients-card-container { display: flex; flex-wrap: wrap; @@ -307,42 +235,24 @@ mat-tree mat-tree-node.disabled:hover { justify-content: flex-start; } -.classroom-item { - flex: 1 1 calc(25% - 16px); - max-width: calc(25% - 16px); - box-sizing: border-box; +.client-name { + display: block; + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 5px; + margin-top: 5px; } -.classroom-pc { - border: 1px solid #ccc; - border-radius: 8px; - padding: 16px; +.filters-container { display: flex; flex-direction: column; - align-items: center; - text-align: center; + justify-content: start; + padding: 1em 1em 0em 1em; } -.classroom-pc .pc-image { - width: 64px; - height: 64px; - margin-bottom: 8px; -} - -.pc-details { - margin-bottom: 8px; -} - -.pc-details .client-name, -.pc-details .client-ip, -.pc-details .client-mac { - display: block; - font-size: 14px; - color: #666; -} - -.pc-actions button { - margin: 0 4px; +.filter-form-field { + min-width: 21rem; } .filters-and-tree-container { @@ -369,6 +279,7 @@ mat-tree mat-tree-node.disabled:hover { .client-card { background-color: #fff; + border: 1px solid #ccc; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); @@ -379,25 +290,20 @@ mat-tree mat-tree-node.disabled:hover { align-items: center; text-align: center; transition: transform 0.3s ease, box-shadow 0.3s ease; + position: relative; } + .client-card:hover { transform: translateY(-5px); box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); } .client-image { - max-width: 35px !important; - max-height: 35px !important; - height: auto; -} - -.client-name { - display: block; - font-size: 1.2em; - font-weight: 600; - color: #333; - margin-bottom: 5px; + width: 35px; + height: 35px; + margin-top: 10px; + margin-bottom: 8px; } .client-ip { @@ -412,27 +318,6 @@ mat-tree mat-tree-node.disabled:hover { gap: 4px; } -.client-item-list { - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; -} - -.client-details-list { - display: flex; - flex-direction: column; -} - -.clients-list .list-item-content { - display: flex; - justify-content: space-between; - width: 100%; - align-items: center; -} - .action-icons { display: flex; justify-content: center; @@ -440,18 +325,6 @@ mat-tree mat-tree-node.disabled:hover { margin-top: 10px; } -.client-card, -.list-item-content { - border: 1px solid #ccc; - border-radius: 5px; -} - -.client-image { - width: 50px; - height: 50px; - margin-bottom: 0.5rem; -} - .mat-elevation-z8 { box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.2); } @@ -463,37 +336,10 @@ mat-tree mat-tree-node.disabled:hover { margin: 5px; } -.client-name { - font-size: 16px; - font-weight: bold; -} - -.flex { - display: flex; - justify-self: center; - align-items: center; -} - .client-item { position: relative; } -.client-card { - background: #ffffff; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - overflow: hidden; - position: relative; - text-align: center; -} - -.client-image { - max-width: 100%; - height: auto; - margin-top: 10px; - margin-bottom: 8px; -} - .client-details { margin-top: 4px; } @@ -503,7 +349,6 @@ mat-tree mat-tree-node.disabled:hover { display: flex; flex-direction: column; } - } .clients-title-name { diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index dd16324..435d965 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -41,7 +41,7 @@
- + {{ 'searchTree' | translate }} @@ -50,7 +50,7 @@ close - + {{ 'searchClient' | translate }} @@ -200,9 +200,11 @@
+
- @@ -289,7 +291,7 @@ {{ 'name' | translate }} - {{ client.name }} +

{{ client.name }}

@@ -356,9 +358,11 @@ - +
+
+
From 42b10c63c176813311b2d3dc2582933d7beae6c5 Mon Sep 17 00:00:00 2001 From: llara Date: Fri, 28 Feb 2025 13:58:55 +0100 Subject: [PATCH 29/38] refactor: update paginator settings and improve page change handling in groups component --- .../components/groups/groups.component.html | 10 +++---- .../groups/groups.component.spec.ts | 2 +- .../app/components/groups/groups.component.ts | 27 ++++++------------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index e28e7ea..6be6dc2 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -358,12 +358,8 @@ - +
@@ -381,4 +377,4 @@
-
+
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.spec.ts b/ogWebconsole/src/app/components/groups/groups.component.spec.ts index 76a9f99..311398c 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.spec.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.spec.ts @@ -123,6 +123,6 @@ describe('GroupsComponent', () => { spyOn(component['http'], 'get').and.callThrough(); component.fetchClientsForNode(node); expect(component.isLoadingClients).toBeTrue(); - expect(component['http'].get).toHaveBeenCalledWith(`${component.baseUrl}/clients?organizationalUnit.id=${node.id}`); + expect(component['http'].get).toHaveBeenCalledWith(`${component.baseUrl}/clients?organizationalUnit.id=${node.id}&page=1&itemsPerPage=20`); }); }); \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index ebb0b58..04e6891 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -19,7 +19,7 @@ import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/del import { ClassroomViewDialogComponent } from './shared/classroom-view/classroom-view-modal'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; -import {MatPaginator, PageEvent} from '@angular/material/paginator'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component"; import { SelectionModel } from "@angular/cdk/collections"; @@ -42,9 +42,9 @@ export class GroupsComponent implements OnInit, OnDestroy { selectedUnidad: UnidadOrganizativa | null = null; selectedDetail: UnidadOrganizativa | null = null; length: number = 0; - itemsPerPage: number = 10; + itemsPerPage: number = 20; page: number = 0; - pageSizeOptions: number[] = [5, 10, 20, 40, 100]; + pageSizeOptions: number[] = [5, 10, 20, 50, 100]; initialLoading: boolean = true; isLoadingClients: boolean = false; searchTerm = ''; @@ -69,7 +69,6 @@ export class GroupsComponent implements OnInit, OnDestroy { displayedColumns: string[] = ['select', 'status', 'ip', 'name', 'oglive', 'subnet', 'pxeTemplate', 'actions']; private _sort!: MatSort; - private _paginator!: MatPaginator; @ViewChild(MatSort) set matSort(ms: MatSort) { @@ -79,14 +78,6 @@ export class GroupsComponent implements OnInit, OnDestroy { } } - @ViewChild(MatPaginator) - set matPaginator(mp: MatPaginator) { - this._paginator = mp; - if (this.selectedClients) { - this.selectedClients.paginator = this._paginator; - } - } - private subscriptions: Subscription = new Subscription(); constructor( @@ -363,6 +354,11 @@ export class GroupsComponent implements OnInit, OnDestroy { }); } + onPageChange(event: PageEvent): void { + this.page = event.pageIndex; + this.itemsPerPage = event.pageSize; + this.fetchClientsForNode(this.selectedNode); + } addOU(event: MouseEvent, parent: TreeNode | null = null): void { event.stopPropagation(); @@ -737,11 +733,4 @@ export class GroupsComponent implements OnInit, OnDestroy { inputElement.value = ''; this.filterClients(''); } - - onPageChange(event: PageEvent): void { - this.page = event.pageIndex; - this.itemsPerPage = event.pageSize; - this.length = event.length; - this.fetchClientsForNode(this.selectedNode); - } } From 858db45e0da84e05a09792fa0170f5415e62043f Mon Sep 17 00:00:00 2001 From: llara Date: Mon, 3 Mar 2025 11:53:20 +0100 Subject: [PATCH 30/38] refs #1619. Style: enhance cards view layout and paginator integration in groups component --- .../components/groups/groups.component.css | 30 ++++- .../components/groups/groups.component.html | 106 +++++++++--------- 2 files changed, 82 insertions(+), 54 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/groups.component.css b/ogWebconsole/src/app/components/groups/groups.component.css index e9499bd..9858f90 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.css +++ b/ogWebconsole/src/app/components/groups/groups.component.css @@ -59,10 +59,20 @@ } .cards-view { + max-height: calc(100vh - 330px); + overflow: auto; display: flex; + flex-direction: row; flex-grow: 1; - overflow-y: auto; - width: 100%; + overflow: auto; +} + +.cards-select-all { + position: sticky; + top: 0; + z-index: 1; + padding-top: 0.5rem; + padding-left: 1rem; } .clients-table { @@ -83,6 +93,17 @@ margin-top: auto; } +.cards-paginator { + width: 100%; + margin-left: 1rem; + background-color: #fafafa; +} + +.list-paginator { + width: 100%; + background-color: #f3f3f3; +} + .actions mat-icon { color: #757575; cursor: pointer; @@ -293,7 +314,6 @@ mat-tree mat-tree-node.disabled:hover { position: relative; } - .client-card:hover { transform: translateY(-5px); box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); @@ -348,6 +368,8 @@ mat-tree mat-tree-node.disabled:hover { .clients-view-header { display: flex; flex-direction: column; + margin-bottom: 1rem; + margin-top: 0; } } @@ -422,7 +444,7 @@ mat-button-toggle-group { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px; - padding: 8px 20px 20px 20px; + padding: 0.5rem 1rem 1rem 1rem; width: 100%; box-sizing: border-box; } \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 6be6dc2..694f3fd 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -202,62 +202,68 @@
-
- - -
-
-
- - - Client Icon +
+
+ + +
+
+
+ + + Client Icon -
- {{ client.name }} - {{ client.ip }} - {{ client.mac }} -
- - - - - - - - - - - - - + + + + + + +
+
+
+ +
@@ -354,11 +360,11 @@ - + -
From bc8ba38f018b5ae61c67af1afb742c2f873c54b4 Mon Sep 17 00:00:00 2001 From: llara Date: Mon, 3 Mar 2025 16:15:55 +0100 Subject: [PATCH 31/38] refs #1637 refactor: remove unused client edit and create components; add manage client component --- ogWebconsole/src/app/app.module.ts | 8 +- .../client-main-view.component.ts | 4 +- .../app/components/groups/groups.component.ts | 9 +- .../create-client/create-client.component.css | 51 --- .../create-client.component.html | 115 ------- .../create-client/create-client.component.ts | 217 ------------- .../edit-client/edit-client.component.css | 51 --- .../edit-client/edit-client.component.html | 112 ------- .../edit-client/edit-client.component.ts | 239 -------------- .../manage-client/manage-client.component.css | 51 +++ .../manage-client.component.html | 113 +++++++ .../manage-client.component.spec.ts | 69 ++++ .../manage-client/manage-client.component.ts | 302 ++++++++++++++++++ 13 files changed, 544 insertions(+), 797 deletions(-) delete mode 100644 ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css delete mode 100644 ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html delete mode 100644 ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.ts delete mode 100644 ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css delete mode 100644 ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html delete mode 100644 ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.ts create mode 100644 ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.css create mode 100644 ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.html create mode 100644 ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.spec.ts create mode 100644 ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.ts diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 009b857..277d682 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -35,9 +35,7 @@ import { GroupsComponent } from './components/groups/groups.component'; import { MatDividerModule } from '@angular/material/divider'; import { MatStepperModule } from '@angular/material/stepper'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { CreateClientComponent } from './components/groups/shared/clients/create-client/create-client.component'; import { DeleteModalComponent } from './shared/delete_modal/delete-modal/delete-modal.component'; -import { EditClientComponent } from './components/groups/shared/clients/edit-client/edit-client.component'; import { ClassroomViewComponent } from './components/groups/shared/classroom-view/classroom-view.component'; import { MatProgressSpinner } from "@angular/material/progress-spinner"; import { MatProgressBarModule } from '@angular/material/progress-bar'; @@ -130,6 +128,7 @@ import { CreateSubnetComponent } from "./components/ogdhcp/create-subnet/create- import { AddClientsToSubnetComponent } from "./components/ogdhcp/add-clients-to-subnet/add-clients-to-subnet.component"; import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component'; import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component'; +import { ManageClientComponent } from './components/groups/shared/clients/manage-client/manage-client.component'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http, './locale/', '.json'); } @@ -150,9 +149,8 @@ export function HttpLoaderFactory(http: HttpClient) { AddRoleModalComponent, ChangePasswordModalComponent, GroupsComponent, - CreateClientComponent, + ManageClientComponent, DeleteModalComponent, - EditClientComponent, ClassroomViewComponent, ClientViewComponent, ShowOrganizationalUnitComponent, @@ -215,7 +213,7 @@ export function HttpLoaderFactory(http: HttpClient) { ManageOrganizationalUnitComponent, BackupImageComponent, ShowClientsComponent, - OperationResultDialogComponent, + OperationResultDialogComponent ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts index 2865375..e302018 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/client-main-view.component.ts @@ -5,8 +5,8 @@ import {MatTableDataSource} from "@angular/material/table"; import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component"; import {MatDialog} from "@angular/material/dialog"; import {Router} from "@angular/router"; -import {EditClientComponent} from "../../shared/clients/edit-client/edit-client.component"; import {ToastrService} from "ngx-toastr"; +import { ManageClientComponent } from "../../shared/clients/manage-client/manage-client.component"; interface ClientInfo { property: string; @@ -198,7 +198,7 @@ export class ClientMainViewComponent implements OnInit { onEditClick(event: MouseEvent, uuid: string): void { event.stopPropagation(); - const dialogRef = this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' } ); + const dialogRef = this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' } ); dialogRef.afterClosed().subscribe(); } diff --git a/ogWebconsole/src/app/components/groups/groups.component.ts b/ogWebconsole/src/app/components/groups/groups.component.ts index 04e6891..1047345 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.ts +++ b/ogWebconsole/src/app/components/groups/groups.component.ts @@ -10,9 +10,7 @@ import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree' import { Subscription } from 'rxjs'; import { DataService } from './services/data.service'; import { UnidadOrganizativa, Client, TreeNode, FlatNode, Command } from './model/model'; -import { CreateClientComponent } from './shared/clients/create-client/create-client.component'; import { ManageOrganizationalUnitComponent } from './shared/organizational-units/manage-organizational-unit/manage-organizational-unit.component'; -import { EditClientComponent } from './shared/clients/edit-client/edit-client.component'; import { ShowOrganizationalUnitComponent } from './shared/organizational-units/show-organizational-unit/show-organizational-unit.component'; import { LegendComponent } from './shared/legend/legend.component'; import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/delete-modal.component'; @@ -22,6 +20,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component"; import { SelectionModel } from "@angular/cdk/collections"; +import { ManageClientComponent } from "./shared/clients/manage-client/manage-client.component"; enum NodeType { OrganizationalUnit = 'organizational-unit', @@ -377,7 +376,7 @@ export class GroupsComponent implements OnInit, OnDestroy { addClient(event: MouseEvent, organizationalUnit: TreeNode | null = null): void { event.stopPropagation(); const targetNode = organizationalUnit || this.selectedNode; - const dialogRef = this.dialog.open(CreateClientComponent, { + const dialogRef = this.dialog.open(ManageClientComponent, { data: { organizationalUnit: targetNode }, width: '900px', }); @@ -428,7 +427,7 @@ export class GroupsComponent implements OnInit, OnDestroy { const dialogRef = node?.type !== NodeType.Client ? this.dialog.open(ManageOrganizationalUnitComponent, { data: { uuid }, width: '900px' }) - : this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' }); + : this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' }); dialogRef.afterClosed().subscribe(() => { if (node) { @@ -495,7 +494,7 @@ export class GroupsComponent implements OnInit, OnDestroy { 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' }); + : this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' }); dialogRef.afterClosed().subscribe(() => { this.refreshData(this.selectedNode?.id, selectedClientsBeforeEdit); diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css deleted file mode 100644 index b3c6559..0000000 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.css +++ /dev/null @@ -1,51 +0,0 @@ -h1 { - text-align: center; - font-family: 'Roboto', sans-serif; - font-weight: 400; - color: #3f51b5; - margin-bottom: 20px; - margin-top: 20px; -} - -.form-field { - width: 100%; -} - -.mat-dialog-content { - padding: 15px 50px 15px 50px; -} - -mat-option .unit-name { - display: block; -} - -mat-option .unit-path { - display: block; - font-size: 0.8em; - color: gray; -} - -.loading-spinner { - display: block; - margin: 0 auto; - align-items: center; - justify-content: center; -} - -.create-client-container { - position: relative; -} - -.grid-form { - display: grid; - grid-template-columns: repeat(2, 1fr); - column-gap: 20px; - row-gap: 20px; -} - -.action-container { - display: flex; - justify-content: flex-end; - gap: 1em; - padding: 1.5em; -} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html deleted file mode 100644 index 3cbfd51..0000000 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.html +++ /dev/null @@ -1,115 +0,0 @@ -
-

Añadir Cliente

-
- -
- - Padre - - - {{ getSelectedParentName() }} - - -
{{ unit.name }}
-
{{ unit.path }}
-
-
-
- - - Nombre - - - - - OgLive - - - {{ oglive.name }} - - - - - - Número de Serie - - - - - Interfaz de red - - - {{ type.name }} - - - - - - Controlador de red - - - {{ type.name }} - - - - - - MAC - Ejemplo: 00:11:22:33:44:55 - - Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55 - - - - Dirección IP - Ejemplo: 127.0.0.1 - - Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1 - - - - Plantilla PXE - - - {{ template.name }} - - - - - - Perfil de Hardware - - - {{ unit.description }} - - - Formato de URL inválido. - - - - Repositorio - - - {{ repository.name }} - - - - - - {{ 'menuLabel' | translate }} - - - {{ menu.name }} - - - {{ 'menuError' | translate }} - -
-
- -
- - -
-
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.ts b/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.ts deleted file mode 100644 index c807b1c..0000000 --- a/ogWebconsole/src/app/components/groups/shared/clients/create-client/create-client.component.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Component, Inject, OnInit } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { ToastrService } from 'ngx-toastr'; -import { DataService } from '../../../services/data.service'; - -@Component({ - selector: 'app-create-client', - templateUrl: './create-client.component.html', - styleUrls: ['./create-client.component.css'] -}) -export class CreateClientComponent implements OnInit { - baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - clientForm!: FormGroup; - parentUnits: any[] = []; - parentUnitsWithPaths: { id: string, name: string, path: string }[] = []; - hardwareProfiles: any[] = []; - ogLives: any[] = []; - menus: any[] = []; - templates: any[] = []; - repositories: any[] = []; - loading: boolean = false; - displayedColumns: string[] = ['name', 'ip']; - protected netifaceTypes = [ - { name: 'Eth0', value: 'eth0' }, - { name: 'Eth1', value: 'eth1' }, - { name: 'Eth2', value: 'eth2' } - ]; - protected netDriverTypes = [ - { name: 'Generic', value: 'generic' } - ]; - - constructor( - private fb: FormBuilder, - private dialogRef: MatDialogRef, - private http: HttpClient, - private snackBar: MatSnackBar, - private toastService: ToastrService, - private dataService: DataService, - @Inject(MAT_DIALOG_DATA) public data: any - ) {} - - ngOnInit(): void { - this.loadParentUnits(); - this.loadHardwareProfiles(); - this.loadOgLives(); - this.loadPxeTemplates(); - this.loadRepositories(); - this.loadMenus() - this.initForm(); - } - - initForm(): void { - this.clientForm = this.fb.group({ - organizationalUnit: [ - this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null, - Validators.required - ], - name: ['', Validators.required], - serialNumber: [''], - netiface: null, - netDriver: null, - mac: ['', Validators.required], - ip: ['', Validators.required], - template: [null], - hardwareProfile: [null], - ogLive: [null], - repository: [null], - menu: [null] - }); - } - - loadParentUnits(): void { - this.loading = true; - const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.parentUnits = response['hydra:member']; - this.parentUnitsWithPaths = this.parentUnits.map(unit => ({ - id: unit['@id'], - name: unit.name, - path: this.dataService.getOrganizationalUnitPath(unit, this.parentUnits), - repository: unit.networkSettings?.repository?.['@id'], - hardwareProfile: unit.networkSettings?.hardwareProfile?.['@id'], - ogLive: unit.networkSettings?.ogLive?.['@id'], - menu: unit.networkSettings?.menu?.['@id'] - })); - - // 🚀 Ahora que los datos están listos, aplicamos la configuración inicial - const initialUnitId = this.clientForm.get('organizationalUnit')?.value; - if (initialUnitId) { - this.setOrganizationalUnitDefaults(initialUnitId); - } - - this.loading = false; - }, - error => { - console.error('Error fetching parent units:', error); - this.loading = false; - } - ); - } - - getSelectedParentName(): string | undefined { - const parentId = this.clientForm.get('organizationalUnit')?.value; - return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name; - } - - loadHardwareProfiles(): void { - this.dataService.getHardwareProfiles().subscribe( - (data: any[]) => { - this.hardwareProfiles = data; - this.loading = false; - }, - error => { - console.error('Error fetching hardware profiles:', error); - this.loading = false; - } - ); - } - - loadOgLives(): void { - const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=30`; - - this.http.get(url).subscribe( - response => { - this.ogLives = response['hydra:member']; - }, - error => { - console.error('Error fetching ogLives:', error); - } - ); - } - - loadPxeTemplates(): void { - const url = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.templates = response['hydra:member']; - }, - error => { - console.error('Error fetching PXE templates:', error); - } - ); - } - - loadMenus(): void { - const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.menus = response['hydra:member']; - }, - error => { - console.error('Error fetching menus:', error); - } - ); - } - - loadRepositories(): void { - const url = `${this.baseUrl}/image-repositories?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.repositories = response['hydra:member']; - }, - error => { - console.error('Error fetching ogLives:', error); - } - ); - } - - onParentChange(event: any): void { - this.setOrganizationalUnitDefaults(event.value); - } - - setOrganizationalUnitDefaults(unitId: string): void { - const selectedUnit: any = this.parentUnitsWithPaths.find(unit => unit.id === unitId); - if (selectedUnit) { - this.clientForm.patchValue({ - repository: selectedUnit.repository || null, - hardwareProfile: selectedUnit.hardwareProfile || null, - ogLive: selectedUnit.ogLive || null, - menu: selectedUnit.menu || null - }); - } - } - - onSubmit(): void { - if (this.clientForm.valid) { - const formData = this.clientForm.value; - - this.http.post(`${this.baseUrl}/clients`, formData).subscribe( - (response) => { - this.toastService.success('Cliente creado exitosamente', 'Éxito'); - this.dialogRef.close({ - client: response, - organizationalUnit: formData.organizationalUnit, - }); - }, - (error) => { - this.toastService.error(error.error['hydra:description'], 'Error al crear el cliente'); - } - ); - } else { - this.toastService.error('Formulario inválido. Por favor, revise los campos obligatorios.', 'Error'); - } - } - - onNoClick(): void { - this.dialogRef.close(); - } -} diff --git a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css deleted file mode 100644 index b3c6559..0000000 --- a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.css +++ /dev/null @@ -1,51 +0,0 @@ -h1 { - text-align: center; - font-family: 'Roboto', sans-serif; - font-weight: 400; - color: #3f51b5; - margin-bottom: 20px; - margin-top: 20px; -} - -.form-field { - width: 100%; -} - -.mat-dialog-content { - padding: 15px 50px 15px 50px; -} - -mat-option .unit-name { - display: block; -} - -mat-option .unit-path { - display: block; - font-size: 0.8em; - color: gray; -} - -.loading-spinner { - display: block; - margin: 0 auto; - align-items: center; - justify-content: center; -} - -.create-client-container { - position: relative; -} - -.grid-form { - display: grid; - grid-template-columns: repeat(2, 1fr); - column-gap: 20px; - row-gap: 20px; -} - -.action-container { - display: flex; - justify-content: flex-end; - gap: 1em; - padding: 1.5em; -} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html deleted file mode 100644 index ba47bb9..0000000 --- a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.html +++ /dev/null @@ -1,112 +0,0 @@ -

{{ 'editClientDialogTitle' | translate }}

-
- -
- - - {{ 'organizationalUnitLabel' | translate }} - - - {{ getSelectedParentName() }} - - -
{{ unit.name }}
-
{{ unit.path }}
-
-
-
- - - {{ 'nameLabel' | translate }} - - - - - {{ 'ogLiveLabel' | translate }} - - - {{ ogLive.name }} - - - - - - {{ 'serialNumberLabel' | translate }} - - - - - {{ 'netifaceLabel' | translate }} - - - {{ type.name }} - - - - - - {{ 'netDriverLabel' | translate }} - - - {{ type.name }} - - - - - - {{ 'macLabel' | translate }} - - {{ 'macError' | translate }} - - - - {{ 'ipLabel' | translate }} - - {{ 'ipError' | translate }} - - - - {{ 'templateLabel' | translate }} - - - {{ template.name }} - - - - - - {{ 'hardwareProfileLabel' | translate }} - - - {{ unit.description }} - - - - - - Repositorio - - - {{ repository.name }} - - - - - - {{ 'menuLabel' | translate }} - - - {{ menu.name }} - - - {{ 'menuError' | translate }} - -
-
- -
- - -
diff --git a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.ts b/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.ts deleted file mode 100644 index e53dd47..0000000 --- a/ogWebconsole/src/app/components/groups/shared/clients/edit-client/edit-client.component.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Component, Inject } from '@angular/core'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { CreateClientComponent } from '../create-client/create-client.component'; -import { DataService } from '../../../services/data.service'; -import { ToastrService } from 'ngx-toastr'; - -@Component({ - selector: 'app-edit-client', - templateUrl: './edit-client.component.html', - styleUrls: ['./edit-client.component.css'] -}) -export class EditClientComponent { - baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; - clientForm!: FormGroup; - parentUnits: any[] = []; - parentUnitsWithPaths: { id: string, name: string, path: string }[] = []; - hardwareProfiles: any[] = []; - repositories: any[] = []; - ogLives: any[] = []; - templates: any[] = []; - menus: any[] = []; - isEditMode: boolean; - protected netifaceTypes = [ - { "name": 'Eth0', "value": "eth0" }, - { "name": 'Eth1', "value": "eth1" }, - { "name": 'Eth2', "value": "eth2" }, - ]; - protected netDriverTypes = [ - { "name": 'Generic', "value": "generic" }, - ]; - loading: boolean = false; - - constructor( - private fb: FormBuilder, - private dialogRef: MatDialogRef, - private http: HttpClient, - private dataService: DataService, - private toastService: ToastrService, - @Inject(MAT_DIALOG_DATA) public data: any - ) { - this.isEditMode = !!data?.uuid; - if (this.isEditMode) { - this.loadData(data.uuid); - } - } - - ngOnInit(): void { - this.loadParentUnits(); - this.loadHardwareProfiles(); - this.loadOgLives(); - this.loadPxeTemplates() - this.loadRepositories(); - this.loadMenus() - this.clientForm = this.fb.group({ - organizationalUnit: [null, Validators.required], - name: ['', Validators.required], - serialNumber: null, - netiface: null, - netDriver: null, - mac: null, - ip: null, - template: null, - hardwareProfile: null, - ogLive: null, - repository: null, - menu: null, - }); - } - - loadParentUnits(): void { - this.loading = true; - const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.parentUnits = response['hydra:member']; - this.parentUnitsWithPaths = this.parentUnits.map(unit => ({ - id: unit['@id'], - name: unit.name, - path: this.dataService.getOrganizationalUnitPath(unit, this.parentUnits) - })); - this.loading = false; - }, - error => { - console.error('Error fetching parent units:', error); - this.loading = false; - } - ); - } - - getSelectedParentName(): string | undefined { - const parentId = this.clientForm.get('organizationalUnit')?.value; - return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name; - } - - loadHardwareProfiles(): void { - this.dataService.getHardwareProfiles().subscribe( - (data: any[]) => { - this.hardwareProfiles = data; - }, - (error: any) => { - console.error('Error fetching hardware profiles', error); - } - ); - } - - loadOgLives(): void { - const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.ogLives = response['hydra:member']; - }, - error => { - console.error('Error fetching ogLives:', error); - } - ); - } - - loadMenus(): void { - const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.menus = response['hydra:member']; - }, - error => { - console.error('Error fetching menus:', error); - } - ); - } - - loadRepositories(): void { - const url = `${this.baseUrl}/image-repositories?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.repositories = response['hydra:member']; - }, - error => { - console.error('Error fetching ogLives:', error); - } - ); - } - - loadPxeTemplates(): void { - const url = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=10000`; - - this.http.get(url).subscribe( - response => { - this.templates = response['hydra:member']; - }, - error => { - console.error('Error fetching ogLives:', error); - } - ); - } - - loadData(uuid: string) { - this.loading = true; - const url = `${this.baseUrl}/clients/${uuid}`; - - this.http.get(url).subscribe( - data => { - this.clientForm.patchValue({ - name: data.name, - ip: data.ip, - mac: data.mac, - netiface: data.netiface, - netDriver: data.netDriver, - serialNumber: data.serialNumber, - hardwareProfile: data.hardwareProfile ? data.hardwareProfile['@id'] : null, - organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : null, - repository: data.repository ? data.repository['@id'] : null, - ogLive: data.ogLive ? data.ogLive['@id'] : null, - template: data.template ? data.template['@id'] : null, - menu: data.menu ? data.menu['@id'] : null, - }); - this.loading = false; - }, - error => { - console.error('Error al cargar datos del cliente:', error); - this.loading = false; - } - ); - } - - onSubmit() { - if (this.clientForm.valid) { - const formData = this.clientForm.value; - - if (this.isEditMode) { - // Edit mode: Send PUT request to update the unit - const putUrl = `${this.baseUrl}/clients/${this.data.uuid}`; - const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); - - this.http.patch(putUrl, formData, { headers }).subscribe( - response => { - this.dialogRef.close(); - this.openSnackBar(false, 'Cliente actualizado exitosamente'); - - }, - error => { - console.error('Error al realizar PUT:', error); - this.openSnackBar(true, 'Error al actualizar el cliente: ' + error.error['hydra:description']); - } - ); - } else { - // Create mode: Send POST request to create a new unit - const postUrl = `${this.baseUrl}/clients`; - const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); - - this.http.post(postUrl, formData, { headers }).subscribe( - response => { - this.dialogRef.close(); - this.openSnackBar(false, 'Cliente creado exitosamente'); - }, - error => { - console.error('Error al realizar POST:', error); - this.openSnackBar(true, 'Error al crear el cliente: ' + error.error['hydra:description']); - } - ); - } - } - } - - onNoClick(): void { - this.dialogRef.close(); - } - - openSnackBar(isError: boolean, message: string) { - if (isError) { - this.toastService.error(' Error al crear el cliente: ' + message, 'Error'); - } else - this.toastService.success(message, 'Éxito'); - } -} diff --git a/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.css b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.css new file mode 100644 index 0000000..55a0232 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.css @@ -0,0 +1,51 @@ +h1 { + text-align: center; + font-family: 'Roboto', sans-serif; + font-weight: 400; + color: #3f51b5; + margin-bottom: 20px; + margin-top: 20px; +} + +.form-field { + width: 100%; +} + +.mat-dialog-content { + padding: 15px 50px 15px 50px; +} + +mat-option .unit-name { + display: block; +} + +mat-option .unit-path { + display: block; + font-size: 0.8em; + color: gray; +} + +.loading-spinner { + display: block; + margin: 0 auto; + align-items: center; + justify-content: center; +} + +.create-client-container { + position: relative; +} + +.grid-form { + display: grid; + grid-template-columns: repeat(2, 1fr); + column-gap: 20px; + row-gap: 20px; +} + +.action-container { + display: flex; + justify-content: flex-end; + gap: 1em; + padding: 1.5em; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.html b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.html new file mode 100644 index 0000000..4d90eb2 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.html @@ -0,0 +1,113 @@ +
+

{{ dialogTitle | translate }}

+
+ +
+ + {{ 'organizationalUnitLabel' | translate }} + + + {{ getSelectedParentName() }} + + +
{{ unit.name }}
+
{{ unit.path }}
+
+
+
+ + + {{ 'nameLabel' | translate }} + + + + + {{ 'ogLiveLabel' | translate }} + + + {{ ogLive.name }} + + + + + + {{ 'serialNumberLabel' | translate }} + + + + + {{ 'netifaceLabel' | translate }} + + + {{ type.name }} + + + + + + {{ 'netDriverLabel' | translate }} + + + {{ type.name }} + + + + + + {{ 'macLabel' | translate }} + + {{ 'macError' | translate }} + + + + {{ 'ipLabel' | translate }} + + {{ 'ipError' | translate }} + + + + {{ 'templateLabel' | translate }} + + + {{ template.name }} + + + + + + {{ 'hardwareProfileLabel' | translate }} + + + {{ profile.description }} + + + + + + {{ 'repositoryLabel' | translate }} + + + {{ repository.name }} + + + + + + {{ 'menuLabel' | translate }} + + + {{ menu.name }} + + + {{ 'menuError' | translate }} + +
+
+ +
+ + +
+
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.spec.ts b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.spec.ts new file mode 100644 index 0000000..d357706 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.spec.ts @@ -0,0 +1,69 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { ToastrModule } from 'ngx-toastr'; +import { TranslateModule } from '@ngx-translate/core'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { ManageClientComponent } from './manage-client.component'; +import { DataService } from '../../../services/data.service'; + +describe('ManageClientComponent', () => { + let component: ManageClientComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ManageClientComponent], + imports: [ + HttpClientTestingModule, + ReactiveFormsModule, + MatDialogModule, + MatSnackBarModule, + ToastrModule.forRoot(), + TranslateModule.forRoot(), + MatProgressSpinnerModule + ], + providers: [ + { provide: MatDialogRef, useValue: {} }, + { provide: MAT_DIALOG_DATA, useValue: { uuid: '123', organizationalUnit: { '@id': '/units/1' } } }, + DataService + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ManageClientComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should initialize form', () => { + expect(component.clientForm).toBeDefined(); + expect(component.clientForm.controls['name']).toBeDefined(); + expect(component.clientForm.controls['mac']).toBeDefined(); + expect(component.clientForm.controls['ip']).toBeDefined(); + }); + + it('should set dialog title for edit mode', () => { + component.isEditMode = true; + component.data = { uuid: '123', organizationalUnit: { '@id': '/units/1' } }; + component.ngOnInit(); + expect(component.dialogTitle).toBe('editClientDialogTitle'); + }); + + it('should call onSubmit when form is valid', () => { + spyOn(component, 'onSubmit'); + component.clientForm.controls['name'].setValue('Test Client'); + component.clientForm.controls['mac'].setValue('00:11:22:33:44:55'); + component.clientForm.controls['ip'].setValue('192.168.1.1'); + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector('.submit-button'); + button.click(); + expect(component.onSubmit).toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.ts b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.ts new file mode 100644 index 0000000..a9d7863 --- /dev/null +++ b/ogWebconsole/src/app/components/groups/shared/clients/manage-client/manage-client.component.ts @@ -0,0 +1,302 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Component, Inject, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ToastrService } from 'ngx-toastr'; +import { DataService } from '../../../services/data.service'; + +@Component({ + selector: 'app-manage-client', + templateUrl: './manage-client.component.html', + styleUrls: ['./manage-client.component.css'] +}) +export class ManageClientComponent implements OnInit { + baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; + clientForm!: FormGroup; + parentUnits: any[] = []; + parentUnitsWithPaths: { id: string, name: string, path: string }[] = []; + hardwareProfiles: any[] = []; + ogLives: any[] = []; + menus: any[] = []; + templates: any[] = []; + repositories: any[] = []; + loading: boolean = false; + displayedColumns: string[] = ['name', 'ip']; + dialogTitle: string; + protected netifaceTypes = [ + { name: 'Eth0', value: 'eth0' }, + { name: 'Eth1', value: 'eth1' }, + { name: 'Eth2', value: 'eth2' } + ]; + protected netDriverTypes = [ + { name: 'Generic', value: 'generic' } + ]; + isEditMode: boolean; + + constructor( + private fb: FormBuilder, + private dialogRef: MatDialogRef, + private http: HttpClient, + private snackBar: MatSnackBar, + private toastService: ToastrService, + private dataService: DataService, + @Inject(MAT_DIALOG_DATA) public data: any + ) { + this.isEditMode = !!data?.uuid; + this.dialogTitle = this.isEditMode ? 'editClientDialogTitle' : 'addClientDialogTitle'; + } + + ngOnInit(): void { + this.loading = true; + this.initForm(); + const observables = [ + this.loadParentUnits(), + this.loadHardwareProfiles(), + this.loadOgLives(), + this.loadPxeTemplates(), + this.loadRepositories(), + this.loadMenus() + ]; + + Promise.all(observables).then(() => { + if (this.isEditMode) { + this.loadData(this.data.uuid).then(() => { + this.loading = false; + }); + } else { + this.loading = false; + } + }).catch(error => { + console.error('Error loading data:', error); + this.loading = false; + }); + } + + initForm(): void { + this.clientForm = this.fb.group({ + organizationalUnit: [ + this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null, + Validators.required + ], + name: ['', Validators.required], + serialNumber: [''], + netiface: null, + netDriver: null, + mac: ['', Validators.required], + ip: ['', Validators.required], + template: [null], + hardwareProfile: [null], + ogLive: [null], + repository: [null], + menu: [null] + }); + } + + loadParentUnits(): Promise { + return new Promise((resolve, reject) => { + const url = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=10000`; + + this.http.get(url).subscribe( + response => { + this.parentUnits = response['hydra:member']; + this.parentUnitsWithPaths = this.parentUnits.map(unit => ({ + id: unit['@id'], + name: unit.name, + path: this.dataService.getOrganizationalUnitPath(unit, this.parentUnits), + repository: unit.networkSettings?.repository?.['@id'], + hardwareProfile: unit.networkSettings?.hardwareProfile?.['@id'], + ogLive: unit.networkSettings?.ogLive?.['@id'], + menu: unit.networkSettings?.menu?.['@id'] + })); + + const initialUnitId = this.clientForm.get('organizationalUnit')?.value; + if (initialUnitId) { + this.setOrganizationalUnitDefaults(initialUnitId); + } + + resolve(); + }, + error => { + console.error('Error fetching parent units:', error); + reject(error); + } + ); + }); + } + + getSelectedParentName(): string | undefined { + const parentId = this.clientForm.get('organizationalUnit')?.value; + return this.parentUnitsWithPaths.find(unit => unit.id === parentId)?.name; + } + + loadHardwareProfiles(): Promise { + return new Promise((resolve, reject) => { + this.dataService.getHardwareProfiles().subscribe( + (data: any[]) => { + this.hardwareProfiles = data; + resolve(); + }, + error => { + console.error('Error fetching hardware profiles:', error); + reject(error); + } + ); + }); + } + + loadOgLives(): Promise { + return new Promise((resolve, reject) => { + const url = `${this.baseUrl}/og-lives?page=1&itemsPerPage=30`; + + this.http.get(url).subscribe( + response => { + this.ogLives = response['hydra:member']; + resolve(); + }, + error => { + console.error('Error fetching ogLives:', error); + reject(error); + } + ); + }); + } + + loadPxeTemplates(): Promise { + return new Promise((resolve, reject) => { + const url = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=10000`; + + this.http.get(url).subscribe( + response => { + this.templates = response['hydra:member']; + resolve(); + }, + error => { + console.error('Error fetching PXE templates:', error); + reject(error); + } + ); + }); + } + + loadMenus(): Promise { + return new Promise((resolve, reject) => { + const url = `${this.baseUrl}/menus?page=1&itemsPerPage=10000`; + + this.http.get(url).subscribe( + response => { + this.menus = response['hydra:member']; + resolve(); + }, + error => { + console.error('Error fetching menus:', error); + reject(error); + } + ); + }); + } + + loadRepositories(): Promise { + return new Promise((resolve, reject) => { + const url = `${this.baseUrl}/image-repositories?page=1&itemsPerPage=10000`; + + this.http.get(url).subscribe( + response => { + this.repositories = response['hydra:member']; + resolve(); + }, + error => { + console.error('Error fetching ogLives:', error); + reject(error); + } + ); + }); + } + + onParentChange(event: any): void { + this.setOrganizationalUnitDefaults(event.value); + } + + setOrganizationalUnitDefaults(unitId: string): void { + const selectedUnit: any = this.parentUnitsWithPaths.find(unit => unit.id === unitId); + if (selectedUnit) { + this.clientForm.patchValue({ + repository: selectedUnit.repository || null, + hardwareProfile: selectedUnit.hardwareProfile || null, + ogLive: selectedUnit.ogLive || null, + menu: selectedUnit.menu || null + }); + } + } + + loadData(uuid: string): Promise { + return new Promise((resolve, reject) => { + const url = `${this.baseUrl}/clients/${uuid}`; + + this.http.get(url).subscribe( + data => { + this.clientForm.patchValue({ + name: data.name, + ip: data.ip, + mac: data.mac, + netiface: data.netiface, + netDriver: data.netDriver, + serialNumber: data.serialNumber, + hardwareProfile: data.hardwareProfile ? data.hardwareProfile['@id'] : null, + organizationalUnit: data.organizationalUnit ? data.organizationalUnit['@id'] : null, + repository: data.repository ? data.repository['@id'] : null, + ogLive: data.ogLive ? data.ogLive['@id'] : null, + template: data.template ? data.template['@id'] : null, + menu: data.menu ? data.menu['@id'] : null, + }); + resolve(); + }, + error => { + console.error('Error al cargar datos del cliente:', error); + reject(error); + } + ); + }); + } + + onSubmit(): void { + if (this.clientForm.valid) { + const formData = this.clientForm.value; + + if (this.isEditMode) { + const putUrl = `${this.baseUrl}/clients/${this.data.uuid}`; + const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); + + this.http.patch(putUrl, formData, { headers }).subscribe( + response => { + this.dialogRef.close(); + this.toastService.success('Cliente actualizado exitosamente', 'Éxito'); + }, + error => { + console.error('Error al realizar PUT:', error); + this.toastService.error('Error al actualizar el cliente: ' + error.error['hydra:description'], 'Error'); + } + ); + } else { + this.http.post(`${this.baseUrl}/clients`, formData).subscribe( + (response) => { + this.toastService.success('Cliente creado exitosamente', 'Éxito'); + this.dialogRef.close({ + client: response, + organizationalUnit: formData.organizationalUnit, + }); + }, + (error) => { + this.toastService.error(error.error['hydra:description'], 'Error al crear el cliente'); + } + ); + } + } else { + this.toastService.error('Formulario inválido. Por favor, revise los campos obligatorios.', 'Error'); + } + } + + onNoClick(): void { + this.dialogRef.close(); + } +} \ No newline at end of file From 9c004441a8e19a98830d244a2f049f45c58be816 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 5 Mar 2025 09:02:07 +0100 Subject: [PATCH 32/38] Chagned filter groups and user improvements --- .../add-user-modal.component.ts | 23 ++++++----- .../components/groups/groups.component.html | 14 ++++++- .../app/components/groups/groups.component.ts | 39 +++++++++++++++++-- .../groups/services/data.service.ts | 2 +- .../app/layout/header/header.component.css | 4 +- 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts index 5c742c6..c5987ba 100644 --- a/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts +++ b/ogWebconsole/src/app/components/admin/users/users/add-user-modal/add-user-modal.component.ts @@ -94,14 +94,20 @@ export class AddUserModalComponent implements OnInit { onSubmit(): void { if (this.userForm.valid) { - const payload = { + const payload: any = { username: this.userForm.value.username, - allowedOrganizationalUnits: this.userForm.value.organizationalUnit, - password: this.userForm.value.password, + allowedOrganizationalUnits: this.userForm.value.organizationalUnits, enabled: true, - userGroups: [this.userForm.value.role ], + userGroups: [this.userForm.value.role], groupsView: this.userForm.value.groupsView }; + + if (!this.userId && this.userForm.value.password) { + payload.password = this.userForm.value.password; + } else if (this.userId && this.userForm.value.password.trim() !== '') { + payload.password = this.userForm.value.password; + } + this.loading = true; if (this.userId) { @@ -109,12 +115,11 @@ export class AddUserModalComponent implements OnInit { (response) => { this.toastService.success('Usuario editado correctamente'); this.dialogRef.close(); - this.loading = false + this.loading = false; }, (error) => { this.toastService.error(error['error']['hydra:description']); - this.loading = false - + this.loading = false; } ); } else { @@ -122,11 +127,11 @@ export class AddUserModalComponent implements OnInit { (response) => { this.toastService.success('Usuario añadido correctamente'); this.dialogRef.close(); - this.loading = false + this.loading = false; }, (error) => { this.toastService.error(error['error']['hydra:description']); - this.loading = false + this.loading = false; } ); } diff --git a/ogWebconsole/src/app/components/groups/groups.component.html b/ogWebconsole/src/app/components/groups/groups.component.html index 694f3fd..6eac0b7 100644 --- a/ogWebconsole/src/app/components/groups/groups.component.html +++ b/ogWebconsole/src/app/components/groups/groups.component.html @@ -59,6 +59,18 @@ close + + + + {{ option.name }} + + + + + +
@@ -73,31 +73,40 @@
- - {{ - trace.status === 'failed' ? 'Fallido' : - trace.status === 'in-progress' ? 'En ejecución' : - trace.status === 'success' ? 'Finalizado con éxito' : - trace.status === 'pending' ? 'Pendiente de ejecutar' : - trace.status - }} - +
+ + {{ + trace.status === 'failed' ? 'Fallido' : + trace.status === 'in-progress' ? 'En ejecución' : + trace.status === 'success' ? 'Finalizado con éxito' : + trace.status === 'pending' ? 'Pendiente de ejecutar' : + trace.status === 'cancelled' ? 'Cancelado' : + trace.status + }} + + +
- - {{ column.cell(trace) }} diff --git a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts index 2c9e24a..8637c6c 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/task-logs/task-logs.component.ts @@ -8,6 +8,8 @@ import { JoyrideService } from 'ngx-joyride'; import { MatDialog } from "@angular/material/dialog"; import { InputDialogComponent } from "./input-dialog/input-dialog.component"; import { ProgressBarMode, MatProgressBarModule } from '@angular/material/progress-bar'; +import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component"; +import {ToastrService} from "ngx-toastr"; @Component({ selector: 'app-task-logs', @@ -88,7 +90,8 @@ export class TaskLogsComponent implements OnInit { constructor(private http: HttpClient, private joyrideService: JoyrideService, private dialog: MatDialog, - private cdr: ChangeDetectorRef + private cdr: ChangeDetectorRef, + private toastService: ToastrService ) { } ngOnInit(): void { @@ -173,6 +176,26 @@ export class TaskLogsComponent implements OnInit { }); } + cancelTrace(trace: any): void { + this.dialog.open(DeleteModalComponent, { + width: '300px', + data: { name: trace.jobId }, + }).afterClosed().subscribe((result) => { + if (result) { + this.http.post(`${this.baseUrl}/traces/server/${trace.uuid}/cancel`, {}).subscribe({ + next: () => { + this.toastService.success('Transmision de imagen cancelada'); + this.loadTraces(); + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + console.error(error.error['hydra:description']); + } + }); + } + }); + } + loadTraces(): void { this.loading = true; const url = `${this.baseUrl}/traces?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}`; From 2b69ef3bd64ac852a0f4867532ad96ff48606b2d Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 5 Mar 2025 17:32:45 +0100 Subject: [PATCH 36/38] Added getImage api call --- .../repository-images.component.html | 1 + .../repository-images/repository-images.component.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html index eca724f..b59ce8d 100644 --- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html +++ b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.html @@ -74,6 +74,7 @@ + diff --git a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts index 2bfa9d1..170ff11 100644 --- a/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts +++ b/ogWebconsole/src/app/components/repositories/repository-images/repository-images.component.ts @@ -237,6 +237,17 @@ export class RepositoryImagesComponent implements OnInit { } }); break; + case 'status': + this.http.post(`${this.baseUrl}/image-image-repositories/server/${image.uuid}/status`, {}).subscribe({ + next: () => { + this.toastService.success('Integridad de la imagen comprobada con éxito'); + this.search() + }, + error: (error) => { + this.toastService.error(error.error['hydra:description']); + } + }); + break; case 'transfer': this.http.get(`${this.baseUrl}${image.image['@id']}`).subscribe({ next: (response) => { From 754dc8ed158201539066c1bb6ff140e406e81771 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 5 Mar 2025 17:33:11 +0100 Subject: [PATCH 37/38] UX and CSS improvements --- .../deploy-image/deploy-image.component.css | 4 + .../deploy-image/deploy-image.component.html | 95 ++++++++++--------- .../deploy-image/deploy-image.component.ts | 2 +- .../show-clients/show-clients.component.html | 4 +- .../show-clients/show-clients.component.ts | 6 ++ 5 files changed, 62 insertions(+), 49 deletions(-) diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.css b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.css index f952a3d..227dfc3 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.css +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.css @@ -31,6 +31,10 @@ table { gap: 10px; } +.options-container { + padding: 10px; +} + .select-container { margin-top: 20px; align-items: center; diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html index 4de8d9d..9bed9a1 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.html @@ -89,56 +89,59 @@ -

Opciones multicast

-

Opciones torrent

-
- - Puerto - - +
+

Opciones multicast

+

Opciones torrent

+
+ + Puerto + + - - Dirección - - + + Dirección + + - - Modo Multicast - - - {{ option.name }} - - - + + Modo Multicast + + + {{ option.name }} + + + - - Velocidad - - + + Velocidad + + - - Máximo Clientes - - + + Máximo Clientes + + - - Tiempo Máximo de Espera - - + + Tiempo Máximo de Espera + + +
+ +
+ + Modo P2P + + + {{ option.name }} + + + + + + Semilla + + +
-
- - Modo P2P - - - {{ option.name }} - - - - - - Semilla - - -
diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.ts index 841f960..2195ed4 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/deploy-image/deploy-image.component.ts @@ -24,7 +24,7 @@ export class DeployImageComponent { selectedMethod: string | null = null; selectedPartition: any = null; mcastIp: string = ''; - mcastPort: string = ''; + mcastPort: Number = 0; mcastMode: string = ''; mcastSpeed: Number = 0; mcastMaxClients: Number = 0; diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html index 5289199..9167cb1 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.html @@ -45,7 +45,7 @@ {{ option.name }} - @@ -98,4 +98,4 @@ - \ No newline at end of file + diff --git a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts index 578ff87..11affe5 100644 --- a/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts +++ b/ogWebconsole/src/app/components/ogdhcp/show-clients/show-clients.component.ts @@ -96,6 +96,12 @@ export class ShowClientsComponent implements OnInit { this.dialogRef.close(); } + clearStatusFilter(event: Event) { + event.stopPropagation(); + delete this.filters['status']; + this.loadData(); + } + onPageChange(event: any) { this.page = event.pageIndex; this.itemsPerPage = event.pageSize; From 83c3b3caeda7ae910304155f67339e14c32277ae Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 6 Mar 2025 08:09:09 +0100 Subject: [PATCH 38/38] Added changeLol 0.9.0 --- CHANGELOG.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cfe3ad..eb2e5f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,24 @@ # Changelog +## [0.9.0] - 2025-3-4 +### 🔹 Added +- Integracion con Mercure. Subscriber tanto en "Trazas" con en "Clientes". +- Nueva funcionalidad para checkear la integridad de una imagen. Boton en apartado "imagenes" dentro del repositorio. +- Centralizacion de estilos. +- Nueva funcionalidad para realizar backup de imágenes. + +### ⚡ Changed +- Nueva interfaz en "Grupos". Se ha aprovechado mejor el espacio y acortado el tamaño de las filas, para poder tener mas elementos por pantalla. +- Cambios en filtros de "Grupos". Ahora se pueden filtrar por "Centro" y "Unidad Organizativa" y estado. Ahora se busca en base de datos, y no en una lista de clientes dados. +- Refactorizados compontentes de crear/editar clientes en uno solo. +- Cambios en DHCP. Nueva UX en "ver clientes". Ahora tenemos un buscador detallado. +- Para gestionar/añadir clientes a subredes ahora tenemos un botón para "añadir todos" y tan solo nos aparecn los equipos que no estén previamente asignados en una subred. ## [0.7.0] - 2024-12-10 ### Refactored - Refactored the group screen, removing the separate tabs for clients, advanced search, and organizational units. - Added support for partitioning functionality in the client detail view. +- Boton para cancelar despliegues de imagenes. Aparece en "trazas" tan solo para los comendos "deploy" y para el estado "en progreos". ## [0.6.1] - 2024-11-19 @@ -15,7 +29,7 @@ ## [0.6.0] - 2024-11-19 -### Added +### 🔹 Added - Added functionality to execute actions from the menu in the general groups screen. - Displayed the selected center on the general screen for better context. - Implemented the option to collapse the sidebar for improved usability.