refs #2769. Some improvements
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

pull/45/head
Manuel Aranda Rosales 2025-09-10 11:48:44 +02:00
parent 486e8e625e
commit 4575ee9b00
5 changed files with 105 additions and 27 deletions

View File

@ -5,10 +5,18 @@
<mat-dialog-content class="dialog-content">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<mat-radio-group *ngIf="data?.source === 'assistant'" [(ngModel)]="taskMode" class="task-mode-selection" name="taskMode">
<mat-radio-button value="create">Crear tarea</mat-radio-button>
<mat-radio-button value="add">Introducir en tarea existente</mat-radio-button>
</mat-radio-group>
<div class="task-form" *ngIf="!loading">
<mat-button-toggle-group *ngIf="data?.source === 'assistant'" [(ngModel)]="taskMode" class="task-mode-selection" name="taskMode" appearance="standard">
<mat-button-toggle value="create">
<mat-icon>add_task</mat-icon>
Crear tarea
</mat-button-toggle>
<mat-button-toggle value="add">
<mat-icon>playlist_add</mat-icon>
Introducir en tarea existente
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div *ngIf="taskMode === 'add'" class="select-task">
<mat-form-field appearance="fill" class="full-width">
@ -43,6 +51,12 @@
<textarea matInput formControlName="notes" placeholder="{{ 'notesPlaceholder' | translate }}"></textarea>
</mat-form-field>
<mat-checkbox *ngIf="!editing" formControlName="scheduleAfterCreate" class="schedule-checkbox">
¿Quieres programar la tarea al finalizar su creación?
</mat-checkbox>
<mat-divider style="margin: 15px 0;"></mat-divider>
<mat-form-field appearance="fill" class="full-width">
<mat-label>Ámbito</mat-label>
<mat-select formControlName="scope" (selectionChange)="onScopeChange($event.value)"
@ -98,10 +112,6 @@
</div>
</div>
</div>
<mat-checkbox *ngIf="!editing" formControlName="scheduleAfterCreate">
¿Quieres programar la tarea al finalizar su creación?
</mat-checkbox>
</form>
</mat-dialog-content>

View File

@ -126,7 +126,7 @@ export class DeployImageComponent implements OnInit{
this.clientData = JSON.parse(params['clientData']);
}
if (params['runScriptContext']) {
this.runScriptContext = params['runScriptContext'];
this.runScriptContext = JSON.parse(params['runScriptContext']);
}
});
this.clientId = this.clientData?.length ? this.clientData[0]['@id'] : null;
@ -289,6 +289,8 @@ export class DeployImageComponent implements OnInit{
}
save(): void {
// Función para ejecutar inmediatamente el despliegue de imagen
// Maneja tanto contextos de clientes individuales como unidades organizacionales (aulas, grupos, etc.)
if (!this.selectedClients.length) {
this.toastService.error('Debe seleccionar al menos un cliente');
return;
@ -333,7 +335,6 @@ export class DeployImageComponent implements OnInit{
if (this.imageType === 'git') {
payload = {
type: 'git',
clients: this.selectedClients.map((client: any) => client.uuid),
diskNumber: this.selectedPartition.diskNumber,
partitionNumber: this.selectedPartition.partitionNumber,
repositoryName: this.selectedGitRepository,
@ -341,10 +342,19 @@ export class DeployImageComponent implements OnInit{
hexsha: this.selectedCommit.hexsha,
queue: result
};
// Determinar el ámbito correcto basado en runScriptContext
const isOrganizationalContext = this.runScriptContext?.type &&
['organizational-unit', 'classroom', 'classrooms-group', 'clients-group'].includes(this.runScriptContext.type);
if (isOrganizationalContext) {
payload.organizationalUnit = this.runScriptContext['@id'];
} else {
payload.clients = this.selectedClients.map((client: any) => client.uuid);
}
url = `${this.baseUrl}/git-repositories/deploy-image`;
} else {
payload = {
clients: this.selectedClients.map((client: any) => client.uuid),
method: this.selectedMethod,
diskNumber: this.selectedPartition.diskNumber,
partitionNumber: this.selectedPartition.partitionNumber,
@ -359,6 +369,16 @@ export class DeployImageComponent implements OnInit{
type: this.imageType,
queue: result
};
// Determinar el ámbito correcto basado en runScriptContext
const isOrganizationalContext = this.runScriptContext?.type &&
['organizational-unit', 'classroom', 'classrooms-group', 'clients-group'].includes(this.runScriptContext.type);
if (isOrganizationalContext) {
payload.organizationalUnit = this.runScriptContext['@id'];
} else {
payload.clients = this.selectedClients.map((client: any) => client.uuid);
}
url = `${this.baseUrl}/image-image-repositories/${this.selectedImage.uuid}/deploy-image`;
}
@ -423,13 +443,25 @@ export class DeployImageComponent implements OnInit{
openScheduleModal(): void {
let scope = this.runScriptContext.type;
// Función para programar la ejecución del despliegue de imagen
// Maneja tanto contextos de clientes individuales como unidades organizacionales (aulas, grupos, etc.)
let scope = this.runScriptContext?.type || 'clients';
let selectedClients = null;
if ((!this.runScriptContext || this.runScriptContext.type === 'client' || this.selectedClients.length === 1) && this.selectedClients && this.selectedClients.length > 0) {
if (this.selectedClients.length === 0 && this.clientData.length > 0) {
this.updateSelectedClients();
}
// Determinar si es un contexto organizacional
const isOrganizationalContext = this.runScriptContext?.type &&
['organizational-unit', 'classroom', 'classrooms-group', 'clients-group'].includes(this.runScriptContext.type);
if (!isOrganizationalContext && this.selectedClients && this.selectedClients.length > 0) {
scope = 'clients';
selectedClients = this.selectedClients;
} else if (isOrganizationalContext) {
scope = this.runScriptContext.type;
selectedClients = null;
}
const dialogRef = this.dialog.open(CreateTaskComponent, {
@ -444,7 +476,8 @@ export class DeployImageComponent implements OnInit{
});
dialogRef.afterClosed().subscribe((result: { [x: string]: any; }) => {
if (result !== undefined) {
console.log(result);
if (result) {
const basePayload: any = {
method: this.selectedMethod,
diskNumber: this.selectedPartition.diskNumber,

View File

@ -95,7 +95,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
this.clientData = JSON.parse(params['clientData']);
}
if (params['runScriptContext']) {
this.runScriptContext = params['runScriptContext'];
this.runScriptContext = JSON.parse(params['runScriptContext']);
}
});
this.clientId = this.clientData?.length ? this.clientData[0]['@id'] : null;
@ -267,6 +267,26 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
});
disksMap.forEach((disk, diskNumber) => {
console.log(this.selectedModelClient?.firmwareType);
const isUEFI = this.selectedModelClient?.firmwareType === 'UEFI';
const hasNoPartitions = disk.partitions.length === 0;
if (isUEFI && hasNoPartitions && disk.totalDiskSize > 0) {
console.log('Creando partición EFI automática para sistema UEFI');
disk.partitions.push({
partitionNumber: 1,
size: 512,
partitionCode: 'EFI',
filesystem: 'FAT32',
memoryUsage: 0,
sizeBytes: 512,
format: false,
color: this.getColorForPartition(1),
percentage: 0,
removed: false
});
}
this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
const used = this.calculateUsedSpace(disk.partitions);
@ -468,12 +488,20 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
format: partition.format || false,
}));
const bulkPayload = {
const bulkPayload: any = {
partitions: newPartitions,
clients: this.selectedClients.map((client: any) => client.uuid),
queue: result
};
const isOrganizationalContext = this.runScriptContext?.type &&
['organizational-unit', 'classroom', 'classrooms-group', 'clients-group'].includes(this.runScriptContext.type);
if (isOrganizationalContext) {
bulkPayload.organizationalUnit = this.runScriptContext['@id'];
} else {
bulkPayload.clients = this.selectedClients.map((client: any) => client.uuid);
}
this.http.post(this.apiUrl, bulkPayload).subscribe(
(response) => {
this.toastService.success('Particiones creadas exitosamente para el disco seleccionado.');
@ -612,9 +640,15 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
this.updateSelectedClients();
}
if (this.selectedClients && this.selectedClients.length > 0) {
const isOrganizationalContext = this.runScriptContext?.type &&
['organizational-unit', 'classroom', 'classrooms-group', 'clients-group'].includes(this.runScriptContext.type);
if (!isOrganizationalContext && this.selectedClients && this.selectedClients.length > 0) {
scope = 'clients';
selectedClients = this.selectedClients;
} else if (isOrganizationalContext) {
scope = this.runScriptContext.type;
selectedClients = null;
}
const dialogRef = this.dialog.open(CreateTaskComponent, {

View File

@ -195,7 +195,7 @@ export class RunScriptAssistantComponent implements OnInit{
});
dialogRef.afterClosed().subscribe(result => {
if (result !== undefined) {
if (result) {
this.loading = true;
this.http.post(`${this.baseUrl}/commands/run-script`, {
clients: this.selectedClients.map((client: any) => client.uuid),
@ -247,10 +247,10 @@ export class RunScriptAssistantComponent implements OnInit{
});
dialogRef.afterClosed().subscribe(result => {
console.log(result);
if (result) {
const commandTaskId = result['@id'] || result.taskId['@id'];
this.http.post(`${this.baseUrl}/command-task-scripts`, {
commandTask: result['@id'],
commandTask: commandTaskId,
content: this.commandType === 'existing' ? this.scriptContent : this.newScript,
order: result['executionOrder'] || 1,
type: 'run-script',

View File

@ -897,15 +897,16 @@ export class GroupsComponent implements OnInit, OnDestroy {
getRunScriptContext(clientData: any[]): any {
const selectedClientNames = clientData.map(client => client.name);
if (clientData.length === 1) {
return clientData[0]; // devuelve el objeto cliente completo
} else if (
if (
this.selectedNode &&
clientData.length === this.selectedClients.data.length &&
selectedClientNames.every(name => this.selectedClients.data.some(c => c.name === name))
) {
return this.selectedNode || null; // devuelve el nodo completo
return this.selectedNode;
} else if (clientData.length === 1) {
return clientData[0];
} else if (clientData.length > 1) {
return clientData; // devuelve array de objetos cliente
return clientData;
} else if (this.selectedNode && clientData.length === 0) {
return this.selectedNode;
}