refs #2158. Added script to existint command-task
parent
4e23723717
commit
f94d522420
|
@ -6,6 +6,11 @@
|
|||
padding: 20px;
|
||||
}
|
||||
|
||||
.select-task {
|
||||
padding: 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,40 @@
|
|||
<h2 mat-dialog-title class="dialog-title">{{ editing ? ('editTask' | translate) : ('createTask' | translate) }}</h2>
|
||||
<h2 mat-dialog-title class="dialog-title">
|
||||
{{ editing ? ('editTask' | translate) : ('createTask' | translate) }}
|
||||
</h2>
|
||||
|
||||
<mat-dialog-content class="dialog-content">
|
||||
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
||||
|
||||
<form *ngIf="taskForm && !loading" [formGroup]="taskForm" class="task-form">
|
||||
<!-- Toggle entre crear o añadir -->
|
||||
<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>
|
||||
|
||||
<!-- Selección de tarea existente -->
|
||||
<div *ngIf="taskMode === 'add'" class="select-task">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Seleccione una tarea</mat-label>
|
||||
<mat-select [(ngModel)]="selectedExistingTask" name="existingTask">
|
||||
<mat-option *ngFor="let task of existingTasks" [value]="task">{{ task.name }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Orden de ejecución</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="executionOrder"
|
||||
name="executionOrder"
|
||||
min="1"
|
||||
placeholder="Introduce el orden"
|
||||
>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Formulario de nueva tarea -->
|
||||
<form *ngIf="taskMode === 'create' && taskForm && !loading" [formGroup]="taskForm" class="task-form">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'nameLabel' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" placeholder="{{ 'nameLabel' | translate }}">
|
||||
|
@ -17,17 +48,17 @@
|
|||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Ámbito</mat-label>
|
||||
<mat-select formControlName="scope" class="full-width" (selectionChange)="onScopeChange($event.value)">
|
||||
<mat-option [value]="'organizational-unit'">Unidad Organizativa</mat-option>
|
||||
<mat-option [value]="'classrooms-group'">Grupo de aulas</mat-option>
|
||||
<mat-option [value]="'classroom'">Aulas</mat-option>
|
||||
<mat-option [value]="'clients-group'">Grupos de clientes</mat-option>
|
||||
<mat-select formControlName="scope" (selectionChange)="onScopeChange($event.value)">
|
||||
<mat-option value="organizational-unit">Unidad Organizativa</mat-option>
|
||||
<mat-option value="classrooms-group">Grupo de aulas</mat-option>
|
||||
<mat-option value="classroom">Aulas</mat-option>
|
||||
<mat-option value="clients-group">Grupos de clientes</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
|
||||
<mat-select formControlName="organizationalUnit" >
|
||||
<mat-select formControlName="organizationalUnit">
|
||||
<mat-option *ngFor="let unit of availableOrganizationalUnits" [value]="unit['@id']">
|
||||
<div class="unit-name">{{ unit.name }}</div>
|
||||
<div style="font-size: smaller; color: gray;">{{ unit.path }}</div>
|
||||
|
@ -35,11 +66,18 @@
|
|||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="!editing" formControlName="scheduleAfterCreate">¿Quieres programar la tarea al finalizar su creación?</mat-checkbox>
|
||||
<mat-checkbox *ngIf="!editing" formControlName="scheduleAfterCreate">
|
||||
¿Quieres programar la tarea al finalizar su creación?
|
||||
</mat-checkbox>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" [disabled]="!taskForm.valid" (click)="saveTask()">{{ 'buttonSave' | translate }}</button>
|
||||
<button
|
||||
class="submit-button"
|
||||
(click)="taskMode === 'create' ? saveTask() : addToExistingTask()"
|
||||
>
|
||||
{{ 'buttonSave' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
@ -25,6 +25,10 @@ export class CreateTaskComponent implements OnInit {
|
|||
clients: any[] = [];
|
||||
allOrganizationalUnits: any[] = [];
|
||||
loading: boolean = false;
|
||||
taskMode: 'create' | 'add' = 'create';
|
||||
existingTasks: any[] = [];
|
||||
selectedExistingTask: string | null = null;
|
||||
executionOrder: number | null = null;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
|
@ -53,6 +57,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
this.loadIndividualCommands(),
|
||||
this.loadOrganizationalUnits(),
|
||||
this.startUnitsFilter(),
|
||||
this.loadTasks()
|
||||
];
|
||||
|
||||
Promise.all(observables).then(() => {
|
||||
|
@ -90,6 +95,21 @@ export class CreateTaskComponent implements OnInit {
|
|||
})
|
||||
}
|
||||
|
||||
loadTasks(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get<any>(`${this.apiUrl}?page=1&itemsPerPage=100`).subscribe(
|
||||
(data) => {
|
||||
this.existingTasks = data['hydra:member'];
|
||||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
this.toastr.error('Error al cargar las tareas existentes');
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onScopeChange(scope: string): void {
|
||||
this.filterUnits(scope).subscribe(filteredUnits => {
|
||||
this.availableOrganizationalUnits = filteredUnits;
|
||||
|
@ -161,6 +181,27 @@ export class CreateTaskComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
addToExistingTask() {
|
||||
if (!this.selectedExistingTask) {
|
||||
this.toastr.error('Debes seleccionar una tarea existente.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.executionOrder == null || this.executionOrder < 1) {
|
||||
this.toastr.error('Debes introducir un orden de ejecución válido (mayor que 0).');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
taskId: this.selectedExistingTask,
|
||||
executionOrder: this.executionOrder
|
||||
};
|
||||
|
||||
this.toastr.success('Tarea actualizada con éxito');
|
||||
this.dialogRef.close(data);
|
||||
}
|
||||
|
||||
|
||||
saveTask(): void {
|
||||
if (this.taskForm.invalid) {
|
||||
this.toastr.error('Por favor, rellene todos los campos obligatorios');
|
||||
|
|
|
@ -10,11 +10,15 @@
|
|||
</h4>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" [disabled]="!allSelected || !selectedModelClient || !selectedImage || !selectedMethod || !selectedPartition" (click)="save()">Ejecutar</button>
|
||||
<button class="action-button"
|
||||
[disabled]="!isFormValid()"
|
||||
(click)="save()">Ejecutar</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button mat-stroked-button color="accent" [disabled]="!allSelected || !selectedModelClient || !selectedImage || !selectedMethod || !selectedPartition" (click)="openScheduleModal()">
|
||||
<button mat-stroked-button color="accent"
|
||||
[disabled]="!isFormValid()"
|
||||
(click)="openScheduleModal()">
|
||||
<mat-icon>schedule</mat-icon> Opciones de programación
|
||||
</button>
|
||||
</div>
|
||||
|
@ -142,18 +146,21 @@
|
|||
<div *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')" class="input-group">
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Puerto</mat-label>
|
||||
<input matInput [(ngModel)]="mcastPort" name="mcastPort" type="number">
|
||||
<input matInput [(ngModel)]="mcastPort" name="mcastPort" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Dirección</mat-label>
|
||||
<input matInput [(ngModel)]="mcastIp" name="mcastIp">
|
||||
<input matInput [(ngModel)]="mcastIp" name="mcastIp"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label>
|
||||
<mat-select [(ngModel)]="mcastMode" name="mcastMode">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
|
||||
<mat-select [(ngModel)]="mcastMode" name="mcastMode"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
@ -161,25 +168,29 @@
|
|||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Velocidad</mat-label>
|
||||
<input matInput [(ngModel)]="mcastSpeed" name="mcastSpeed" type="number">
|
||||
<input matInput [(ngModel)]="mcastSpeed" name="mcastSpeed" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Máximo Clientes</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxClients" name="mcastMaxClients" type="number">
|
||||
<input matInput [(ngModel)]="mcastMaxClients" name="mcastMaxClients" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Tiempo Máximo de Espera</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxTime" name="mcastMaxTime" type="number">
|
||||
<input matInput [(ngModel)]="mcastMaxTime" name="mcastMaxTime" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isMethod('p2p')" class="input-group">
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label>
|
||||
<mat-select [(ngModel)]="p2pMode" name="p2pMode">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
|
||||
<mat-select [(ngModel)]="p2pMode" name="p2pMode"
|
||||
[required]="isMethod('p2p')">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
@ -187,7 +198,8 @@
|
|||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Semilla</mat-label>
|
||||
<input matInput [(ngModel)]="p2pTime" name="p2pTime" type="number">
|
||||
<input matInput [(ngModel)]="p2pTime" name="p2pTime" type="number"
|
||||
[required]="isMethod('p2p')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -332,13 +332,34 @@ export class DeployImageComponent implements OnInit{
|
|||
});
|
||||
}
|
||||
|
||||
isFormValid(): boolean {
|
||||
if (!this.allSelected || !this.selectedModelClient || !this.selectedImage || !this.selectedMethod || !this.selectedPartition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isMethod('udpcast') || this.isMethod('uftp') || this.isMethod('udpcast-direct')) {
|
||||
if (!this.mcastPort || !this.mcastIp || !this.mcastMode || !this.mcastSpeed || !this.mcastMaxClients || !this.mcastMaxTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isMethod('p2p')) {
|
||||
if (!this.p2pMode || !this.p2pTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
openScheduleModal(): void {
|
||||
const dialogRef = this.dialog.open(CreateTaskComponent, {
|
||||
width: '800px',
|
||||
data: {
|
||||
scope: this.runScriptContext.type,
|
||||
organizationalUnit: this.runScriptContext['@id']
|
||||
organizationalUnit: this.runScriptContext['@id'],
|
||||
source: 'assistant'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -359,9 +380,9 @@ export class DeployImageComponent implements OnInit{
|
|||
};
|
||||
|
||||
this.http.post(`${this.baseUrl}/command-task-scripts`, {
|
||||
commandTask: result['@id'],
|
||||
commandTask: result['taskId'] ? result['taskId']['@id'] : result['@id'],
|
||||
parameters: payload,
|
||||
order: 1,
|
||||
order: result['executionOrder'] || 1,
|
||||
type: 'deploy-image',
|
||||
}).subscribe({
|
||||
next: () => {
|
||||
|
|
|
@ -267,5 +267,18 @@ button.remove-btn:hover {
|
|||
font-weight: 500;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
<button class="action-button" [disabled]="data.status === 'busy' || !selectedModelClient || !allSelected || !selectedDisk || (selectedDisk.totalDiskSize - selectedDisk.used) <= 0" (click)="save()">Ejecutar</button>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
<button class="action-button" (click)="generateInstructions()">
|
||||
Generar instrucciones
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button mat-stroked-button color="accent" [disabled]="data.status === 'busy' || !selectedModelClient || !allSelected || !selectedDisk || (selectedDisk.totalDiskSize - selectedDisk.used) <= 0" (click)="openScheduleModal()">
|
||||
<mat-icon>schedule</mat-icon> Opciones de programación
|
||||
|
@ -86,6 +92,13 @@
|
|||
</div>
|
||||
|
||||
<div class="partition-assistant" *ngIf="selectedDisk">
|
||||
|
||||
<div *ngIf="generatedInstructions" class="instructions-box">
|
||||
<mat-form-field class="instructions-textarea" appearance="fill" style="width: 100%;">
|
||||
<textarea matInput rows="10" readonly [value]="generatedInstructions"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="row-button">
|
||||
<button class="action-button" [disabled]="partitionCode === 'MSDOS'" (click)="addPartition(selectedDisk.diskNumber)">Añadir partición</button>
|
||||
<mat-chip *ngIf="selectedModelClient.firmwareType">
|
||||
|
|
|
@ -52,6 +52,7 @@ export class PartitionAssistantComponent implements OnInit{
|
|||
selectedClients: any[] = [];
|
||||
selectedModelClient: any = null;
|
||||
partitionCode: string = '';
|
||||
generatedInstructions: string = '';
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
|
@ -426,7 +427,8 @@ export class PartitionAssistantComponent implements OnInit{
|
|||
width: '800px',
|
||||
data: {
|
||||
scope: this.runScriptContext.type,
|
||||
organizationalUnit: this.runScriptContext['@id']
|
||||
organizationalUnit: this.runScriptContext['@id'],
|
||||
source: 'assistant'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -473,4 +475,39 @@ export class PartitionAssistantComponent implements OnInit{
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
generateInstructions(): void {
|
||||
if (!this.selectedDisk || !this.selectedDisk.partitions) {
|
||||
this.generatedInstructions = 'No hay particiones configuradas para generar instrucciones.';
|
||||
return;
|
||||
}
|
||||
|
||||
const diskNumber = this.selectedDisk.diskNumber;
|
||||
const partitionTable = this.partitionCode || 'MSDOS';
|
||||
|
||||
let instructions = `ogCreatePartitionTable ${diskNumber} ${partitionTable}\n`;
|
||||
instructions += `ogEcho log session "[0] $MSG_HELP_ogCreatePartitions"\n`;
|
||||
instructions += `ogEcho session "[10] $MSG_HELP_ogUnmountAll ${diskNumber}"\n`;
|
||||
instructions += `ogUnmountAll ${diskNumber} 2>/dev/null\n`;
|
||||
instructions += `ogUnmountCache\n`;
|
||||
instructions += `ogEcho session "[30] $MSG_HELP_ogUpdatePartitionTable ${diskNumber}"\n`;
|
||||
instructions += `ogDeletePartitionTable ${diskNumber}\n`;
|
||||
instructions += `ogUpdatePartitionTable ${diskNumber}\n`;
|
||||
|
||||
this.selectedDisk.partitions.forEach((partition: { removed: any; partitionNumber: any; partitionCode: any; filesystem: any; size: any; format: any; }, index: any) => {
|
||||
if (partition.removed) return;
|
||||
|
||||
const partNumber = partition.partitionNumber;
|
||||
const partType = partition.partitionCode;
|
||||
const fs = partition.filesystem;
|
||||
const size = partition.size;
|
||||
const shouldFormat = partition.format ? 'yes' : 'no';
|
||||
|
||||
instructions += `ogCreatePartition ${diskNumber} ${partNumber} ${partType} ${fs} ${size}MB ${shouldFormat}\n`;
|
||||
});
|
||||
|
||||
instructions += `ogExecAndLog command session ogListPartitions ${diskNumber}\n`;
|
||||
|
||||
this.generatedInstructions = instructions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,7 +203,8 @@ export class RunScriptAssistantComponent implements OnInit{
|
|||
width: '800px',
|
||||
data: {
|
||||
scope: this.runScriptContext.type,
|
||||
organizationalUnit: this.runScriptContext['@id']
|
||||
organizationalUnit: this.runScriptContext['@id'],
|
||||
source: 'assistant'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue