diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts
index ed2d3f9..a172a3c 100644
--- a/ogWebconsole/src/app/app.module.ts
+++ b/ogWebconsole/src/app/app.module.ts
@@ -153,6 +153,7 @@ import { ClientTaskLogsComponent } from './components/task-logs/client-task-logs
import { BootSoPartitionComponent } from './components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component';
import { RemoveCacheImageComponent } from './components/commands/main-commands/execute-command/remove-cache-image/remove-cache-image.component';
import { ChangeParentComponent } from './components/groups/shared/change-parent/change-parent.component';
+import { SoftwareProfilePartitionComponent } from './components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './locale/', '.json');
@@ -263,7 +264,8 @@ registerLocaleData(localeEs, 'es-ES');
ClientTaskLogsComponent,
BootSoPartitionComponent,
RemoveCacheImageComponent,
- ChangeParentComponent
+ ChangeParentComponent,
+ SoftwareProfilePartitionComponent
],
bootstrap: [AppComponent],
imports: [BrowserModule,
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 0efcd55..0912afc 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
@@ -7,6 +7,7 @@ import { BootSoPartitionComponent } from "./boot-so-partition/boot-so-partition.
import { MatDialog } from "@angular/material/dialog";
import { RemoveCacheImageComponent } from "./remove-cache-image/remove-cache-image.component";
import { AuthService } from '@services/auth.service';
+import {SoftwareProfilePartitionComponent} from "./software-profile-partition/software-profile-partition.component";
@Component({
selector: 'app-execute-command',
@@ -33,7 +34,7 @@ export class ExecuteCommandComponent implements OnInit {
{ translationKey: 'executeCommands.deployImage', slug: 'deploy-image', disabled: false },
{ translationKey: 'executeCommands.deleteImageCache', slug: 'remove-cache-image', disabled: false },
{ translationKey: 'executeCommands.partition', slug: 'partition', disabled: false },
- { translationKey: 'executeCommands.softwareInventory', slug: 'software-inventory', disabled: true },
+ { translationKey: 'executeCommands.softwareInventory', slug: 'software-inventory', disabled: false },
{ translationKey: 'executeCommands.hardwareInventory', slug: 'hardware-inventory', disabled: true },
{ translationKey: 'executeCommands.runScript', slug: 'run-script', disabled: false },
];
@@ -111,10 +112,10 @@ export class ExecuteCommandComponent implements OnInit {
if (states[0] === 'off' || states[0] === 'disconnected') {
command.disabled = command.slug !== 'power-on';
} else {
- command.disabled = !['power-off', 'reboot', 'login', 'create-image', 'deploy-image', 'remove-cache-image', 'partition', 'run-script'].includes(command.slug);
+ command.disabled = !['power-off', 'reboot', 'login', 'create-image', 'deploy-image', 'remove-cache-image', 'partition', 'run-script', 'software-inventory'].includes(command.slug);
}
} else {
- if (command.slug === 'create-image') {
+ if (command.slug === 'create-image'|| command.slug === 'software-inventory') {
command.disabled = multipleClients;
} else if (
['power-on', 'power-off', 'reboot', 'login', 'deploy-image', 'partition', 'remove-cache-image', 'run-script'].includes(command.slug)
@@ -164,6 +165,14 @@ export class ExecuteCommandComponent implements OnInit {
if (action === 'remove-cache-image') {
this.removeImageCache();
}
+
+ if (action === 'hardware-inventory') {
+ this.hardwareInventory();
+ }
+
+ if (action === 'software-inventory') {
+ this.softwareInventory();
+ }
}
rebootClient(): void {
@@ -174,7 +183,7 @@ export class ExecuteCommandComponent implements OnInit {
this.toastService.success('Cliente actualizado correctamente');
},
error => {
- this.toastService.error('Error de conexión con el cliente');
+ this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
}
);
}
@@ -227,6 +236,55 @@ export class ExecuteCommandComponent implements OnInit {
});
}
+ hardwareInventory(): void {
+ if (this.clientData.length === 0) {
+ this.toastService.error('No hay clientes seleccionados');
+ return;
+ }
+
+ const clientId = this.clientData[0].uuid;
+
+ this.http.post(`${this.baseUrl}/clients/server/${clientId}/hardware-inventory`, {
+ clients: this.clientData.map((client: any) => client['@id'])
+ }).subscribe(
+ response => {
+ this.toastService.success('Inventario de hardware actualizado correctamente');
+ },
+ error => {
+ this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
+ }
+ );
+ }
+
+ softwareInventory(): void {
+ if (this.clientData.length === 0) {
+ this.toastService.error('No hay clientes seleccionados');
+ return;
+ }
+
+ const clientDataToSend = {
+ clientId: this.clientData[0].uuid,
+ name: this.clientData[0].name,
+ mac: this.clientData[0].mac,
+ status: this.clientData[0].status,
+ partitions: this.clientData[0].partitions,
+ firmwareType: this.clientData[0].firmwareType,
+ ip: this.clientData[0].ip
+ }
+
+ const clientId = this.clientData[0].uuid;
+
+ const dialogRef = this.dialog.open(SoftwareProfilePartitionComponent, {
+ width: '70vw',
+ height: 'auto',
+ data: { client: clientDataToSend }
+ });
+
+ dialogRef.afterClosed().subscribe(result => {
+
+ });
+ }
+
powerOnClient(): void {
this.http.post(`${this.baseUrl}/image-repositories/wol`, {
clients: this.clientData.map((client: any) => client['@id'])
@@ -235,7 +293,7 @@ export class ExecuteCommandComponent implements OnInit {
this.toastService.success('Petición de encendido enviada correctamente');
},
error => {
- this.toastService.error('Error de conexión con el cliente');
+ this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
}
);
}
@@ -248,7 +306,7 @@ export class ExecuteCommandComponent implements OnInit {
this.toastService.success('Petición de apagado enviada correctamente');
},
error => {
- this.toastService.error('Error de conexión con el cliente');
+ this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
}
);
}
diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.css b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.css
new file mode 100644
index 0000000..9f58e44
--- /dev/null
+++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.css
@@ -0,0 +1,117 @@
+.dialog-content {
+ display: flex;
+ flex-direction: column;
+ padding: 40px;
+}
+
+.action-container {
+ display: flex;
+ justify-content: flex-end;
+ gap: 1em;
+ padding: 1.5em;
+}
+
+.select-container {
+ margin-top: 20px;
+ align-items: center;
+ padding: 20px;
+ box-sizing: border-box;
+}
+
+.clients-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
+ gap: 8px;
+}
+
+.client-card {
+ background: #ffffff;
+ border-radius: 6px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+ position: relative;
+ padding: 8px;
+ text-align: center;
+ cursor: pointer;
+ transition: background-color 0.3s, transform 0.2s;
+
+ &:hover {
+ background-color: #f0f0f0;
+ transform: scale(1.02);
+ }
+}
+
+.button-row {
+ display: flex;
+ padding-right: 1em;
+}
+
+.action-button {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.client-item {
+ position: relative;
+}
+
+.mat-expansion-panel-header-description {
+ justify-content: space-between;
+ align-items: center;
+}
+
+.selected-client {
+ background-color: #a0c2e5 !important;
+ color: white !important;
+}
+
+.loading-spinner {
+ display: block;
+ margin: 0 auto;
+ align-items: center;
+ justify-content: center;
+}
+
+.client-details {
+ margin-top: 4px;
+}
+
+.client-name {
+ font-size: 0.9em;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 5px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 150px;
+ display: inline-block;
+}
+
+.client-ip {
+ display: block;
+ font-size: 0.9em;
+ color: #666;
+}
+
+
+.mat-elevation-z8 {
+ box-shadow: 0px 0px 0px rgba(0,0,0,0.2);
+}
+
+@media (max-width: 600px) {
+ .form-field {
+ width: 100%;
+ }
+
+ .dialog-actions {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ button {
+ width: 100%;
+ margin-left: 0;
+ margin-bottom: 8px;
+ }
+}
diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.html b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.html
new file mode 100644
index 0000000..3f7bf5c
--- /dev/null
+++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.html
@@ -0,0 +1,55 @@
+
Seleccionar partición para inventariar
+
+
+
+
+
+
+
+
+
+ Seleccionar imagen |
+
+
+
+
+
+ |
+
+
+
+ {{ column.header }} |
+
+
+ {{ column.cell(image) }}
+
+
+
+
+ {{ image.size }} MB
+ {{ image.size / 1024 }} GB
+
+
+
+
+
+ {{ image.operativeSystem?.name }}
+ {{ image.image?.name}}
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.spec.ts b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.spec.ts
new file mode 100644
index 0000000..98afae3
--- /dev/null
+++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SoftwareProfilePartitionComponent } from './software-profile-partition.component';
+
+describe('SoftwareProfilePartitionComponent', () => {
+ let component: SoftwareProfilePartitionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [SoftwareProfilePartitionComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(SoftwareProfilePartitionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.ts b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.ts
new file mode 100644
index 0000000..5110f2a
--- /dev/null
+++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/software-profile-partition/software-profile-partition.component.ts
@@ -0,0 +1,107 @@
+import {Component, Inject, OnInit} from '@angular/core';
+import {MatTableDataSource} from "@angular/material/table";
+import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
+import {ConfigService} from "@services/config.service";
+import {HttpClient} from "@angular/common/http";
+import {ToastrService} from "ngx-toastr";
+
+@Component({
+ selector: 'app-software-profile-partition',
+ templateUrl: './software-profile-partition.component.html',
+ styleUrl: './software-profile-partition.component.css'
+})
+export class SoftwareProfilePartitionComponent implements OnInit{
+ baseUrl: string;
+ selectedPartition: any = null;
+ dataSource = new MatTableDataSource();
+ clientId: string | null = null;
+ selectedClients: any[] = [];
+ selectedModelClient: any = null;
+ filteredPartitions: any[] = [];
+ allSelected: boolean = false;
+ clientData: any[] = [];
+ loading: boolean = false;
+ columns = [
+ {
+ columnDef: 'diskNumber',
+ header: 'Disco',
+ cell: (partition: any) => partition.diskNumber
+ },
+ {
+ columnDef: 'partitionNumber',
+ header: 'Particion',
+ cell: (partition: any) => partition.partitionNumber
+ },
+ {
+ columnDef: 'size',
+ header: 'Tamaño',
+ cell: (partition: any) => `${partition.size} MB`
+ },
+ {
+ columnDef: 'partitionCode',
+ header: 'Tipo de partición',
+ cell: (partition: any) => partition.partitionCode
+ },
+ {
+ columnDef: 'filesystem',
+ header: 'Sistema de ficheros',
+ cell: (partition: any) => partition.filesystem
+ },
+ {
+ columnDef: 'operativeSystem',
+ header: 'SO',
+ cell: (partition: any) => partition.operativeSystem?.name
+ }
+ ];
+
+ displayedColumns = ['select', ...this.columns.map(column => column.columnDef)];
+
+ constructor(
+ @Inject(MAT_DIALOG_DATA) public data: { client: any },
+ private dialogRef: MatDialogRef,
+ private configService: ConfigService,
+ private http: HttpClient,
+ private toastService: ToastrService,
+ ) {
+ this.baseUrl = this.configService.apiUrl;
+ this.clientId = this.data.client.clientId
+ }
+
+ ngOnInit() {
+ this.loadPartitions();
+ }
+
+ loadPartitions() {
+ const url = `${this.baseUrl}/clients/${this.data.client.clientId}`;
+ this.http.get(url).subscribe(
+ (response: any) => {
+ if (response.partitions) {
+ this.dataSource.data = response.partitions;
+ }
+ },
+ (error) => {
+ console.error('Error al cargar los datos del cliente:', error);
+ }
+ );
+ }
+
+ close() {
+ this.dialogRef.close();
+ }
+
+ execute(): void {
+ this.loading = true;
+
+ this.http.post(`${this.baseUrl}/clients/server/${this.data.client.clientId}/software-inventory`, {
+ partition: this.selectedPartition['@id'],
+ }).subscribe(
+ response => {
+ this.toastService.success('Inventario de software actualizado correctamente');
+ this.dialogRef.close(response);
+ },
+ error => {
+ this.toastService.error(error.error['hydra:description'] || 'Error al actualizar el inventario de software');
+ }
+ );
+ }
+}
diff --git a/ogWebconsole/src/app/components/global-status/global-status.component.ts b/ogWebconsole/src/app/components/global-status/global-status.component.ts
index 8115ba7..e55179e 100644
--- a/ogWebconsole/src/app/components/global-status/global-status.component.ts
+++ b/ogWebconsole/src/app/components/global-status/global-status.component.ts
@@ -69,7 +69,7 @@ export class GlobalStatusComponent implements OnInit {
},
error: (error) => {
clearTimeout(timeoutId);
- this.toastService.error('Error al sincronizar las subredes DHCP');
+ this.toastService.error(error.error['hydra:description'] || 'Error al sincronizar las subredes');
}
});
}
@@ -85,7 +85,7 @@ export class GlobalStatusComponent implements OnInit {
this.toastService.success('Sincronización de las plantillas Pxe completada');
}, error => {
clearTimeout(timeoutId);
- this.toastService.error('Error al sincronizar las plantillas Pxe');
+ this.toastService.error(error.error['hydra:description'] || 'Error al sincronizar las plantillas Pxe');
});
}
@@ -100,7 +100,7 @@ export class GlobalStatusComponent implements OnInit {
this.toastService.success('Sincronización con los ogLives completada');
}, error => {
clearTimeout(timeoutId);
- this.toastService.error('Error al sincronizar imágenes ogLive');
+ this.toastService.error(error.error['hydra:description'] || 'Error al sincronizar las imagenes ogLive');
});
}
@@ -144,7 +144,7 @@ export class GlobalStatusComponent implements OnInit {
clearTimeout(timeoutId);
},
error: error => {
- console.log(error);
+ this.toastService.error(error.error['hydra:description'] || 'Error al cargar el estado de ogBoot');
this.loading = false;
this[errorState] = true;
clearTimeout(timeoutId);
@@ -217,7 +217,7 @@ export class GlobalStatusComponent implements OnInit {
callback(false);
},
error => {
- console.error(`Error fetching status for repository ${repositoryUuid}`, error);
+ this.toastService.error(error.error['hydra:description'] || 'Error al cargar el estado del repositorio');
clearTimeout(timeoutId);
callback(true);
}
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 f932c98..69ad087 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
@@ -196,3 +196,24 @@ mat-option .unit-name {
justify-content: space-between;
align-items: center;
}
+
+.instructions-box {
+ margin-top: 15px;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ padding: 15px;
+ border-radius: 6px;
+}
+
+.instructions-textarea textarea {
+ font-family: monospace;
+ white-space: pre;
+}
+
+.instructions-card {
+ background-color: #f5f5f5;
+ box-shadow: none !important;
+ margin-top: 15px;
+}
+
+
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 006f2e8..1a5bd76 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
@@ -15,6 +15,12 @@
(click)="save()">Ejecutar
+
+
+
+