translations #72
|
|
@ -1,5 +1,9 @@
|
|||
# Changelog
|
||||
|
||||
## [1.5.1] - 2026-04-23
|
||||
### Improved
|
||||
- Creadas claves de traducción para idiomas, añadido menu para cambiar de idioma en la barra superior
|
||||
|
||||
## [1.5.0] - 2026-04-21
|
||||
### Added
|
||||
- Añadida gestión de múltiples ogBoot Servers
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ export class AppComponent {
|
|||
this.translateService.use(savedLanguage);
|
||||
}
|
||||
ngOnInit() {
|
||||
sessionStorage.setItem('language', 'es');
|
||||
// Language is already handled in constructor
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,6 +204,8 @@ export function HttpLoaderFactory(http: HttpClient) {
|
|||
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||
}
|
||||
|
||||
import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component';
|
||||
|
||||
export function initializeApp(configService: ConfigService) {
|
||||
return () => configService.loadConfig();
|
||||
}
|
||||
|
|
@ -338,7 +340,8 @@ registerLocaleData(localeEs, 'es-ES');
|
|||
OgcoreStatusComponent,
|
||||
GlobalOgbootStatusComponent,
|
||||
OgrepositoryStatusComponent,
|
||||
OgdhcpStatusComponent
|
||||
OgdhcpStatusComponent,
|
||||
PageNotFoundComponent
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [BrowserModule,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
<div class="env-settings">
|
||||
<div class="header-container">
|
||||
<div class="header-container-title">
|
||||
<h2>Editar Variables de Entorno</h2>
|
||||
<h2>{{ 'editEnvVarsTitle' | translate }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-table [dataSource]="envVars" class="mat-elevation-z8">
|
||||
<!-- Nombre de la variable -->
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef> Variable </mat-header-cell>
|
||||
<mat-header-cell *matHeaderCellDef> {{ 'labelVariable' | translate }}</mat-header-cell>
|
||||
<mat-cell *matCellDef="let variable">{{ variable.name }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Valor de la variable -->
|
||||
<ng-container matColumnDef="value">
|
||||
<mat-header-cell *matHeaderCellDef> Valor </mat-header-cell>
|
||||
<mat-header-cell *matHeaderCellDef> {{ 'labelValue' | translate }}</mat-header-cell>
|
||||
<mat-cell *matCellDef="let variable">
|
||||
<!-- Si es booleano, usamos checkbox -->
|
||||
<mat-checkbox *ngIf="isBoolean(variable.value)"
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
</mat-table>
|
||||
|
||||
<div class="actions">
|
||||
<button class="action-button" (click)="loadEnvVars()">Recargar</button>
|
||||
<button class="submit-button" (click)="saveEnvVars()">Guardar Cambios</button>
|
||||
<button class="action-button" (click)="loadEnvVars()">{{ 'buttonReload' | translate }}</button>
|
||||
<button class="submit-button" (click)="saveEnvVars()">{{ 'buttonSaveChanges' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
|
|
@ -9,6 +11,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrl: './env-vars.component.css'
|
||||
})
|
||||
export class EnvVarsComponent {
|
||||
public translate = inject(TranslateService);
|
||||
envVars: { name: string; value: string }[] = [];
|
||||
displayedColumns: string[] = ['name', 'value'];
|
||||
private apiUrl: string;
|
||||
|
|
@ -31,7 +34,7 @@ export class EnvVarsComponent {
|
|||
this.envVars = Object.entries(response.vars).map(([name, value]) => ({ name, value }));
|
||||
},
|
||||
error: (err) => {
|
||||
this.toastService.error('No se pudieron cargar las variables de entorno.');
|
||||
this.toastService.error(this.translate.instant('couldNotBeLoaded'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -48,11 +51,11 @@ export class EnvVarsComponent {
|
|||
|
||||
this.http.post(this.apiUrl, { vars }).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Variables de entorno guardadas correctamente.');
|
||||
this.toastService.success(this.translate.instant('environmentVariablesSavedCorrectly'));
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error al guardar las variables de entorno:', err);
|
||||
this.toastService.error('No se pudieron cargar las variables de entorno.');
|
||||
console.error(this.translate.instant('errorSavingVariables'), err);
|
||||
this.toastService.error(this.translate.instant('couldNotBeLoaded'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<p><mat-checkbox formControlName="orgAdmin">{{ 'checkboxOrgAdmin' | translate }}</mat-checkbox></p>
|
||||
<p><mat-checkbox formControlName="orgOperator">{{ 'checkboxOrgOperator' | translate }}</mat-checkbox></p>
|
||||
<p><mat-checkbox formControlName="orgMinimal">{{ 'checkboxOrgMinimal' | translate }}</mat-checkbox></p>
|
||||
<p><mat-checkbox formControlName="userRole">{{ 'checkboxUserRole' | translate }}</mat-checkbox></p>
|
||||
<p><mat-checkbox formControlName="userRole">{{ 'labelUser' | translate }}</mat-checkbox></p>
|
||||
</section>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
|
@ -12,6 +14,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./add-role-modal.component.css']
|
||||
})
|
||||
export class AddRoleModalComponent {
|
||||
public translate = inject(TranslateService);
|
||||
roleForm: FormGroup<any>;
|
||||
roleId: string | null = null;
|
||||
baseUrl: string;
|
||||
|
|
@ -56,7 +59,7 @@ export class AddRoleModalComponent {
|
|||
this.roleId = response['@id'];
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error fetching remote calendar:', err);
|
||||
console.error(this.translate.instant('errorFetchingRemoteCalendar'), err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -85,23 +88,23 @@ export class AddRoleModalComponent {
|
|||
if (this.roleId) {
|
||||
this.http.put(`${this.baseUrl}${this.roleId}`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Rol actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('roleUpdatedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
(error) => {
|
||||
this.toastService.error('Error al editar el rol:', error);
|
||||
console.error('Error al editar el rol', error);
|
||||
this.toastService.error(this.translate.instant('errorEditingRole1'), error);
|
||||
console.error(this.translate.instant('errorEditingRole'), error);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.http.post(`${this.baseUrl}/user-groups`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Rol añadido correctamente');
|
||||
this.toastService.success(this.translate.instant('roleAddedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
(error) => {
|
||||
this.toastService.error('Error al añadir rol:', error);
|
||||
console.error('Error al añadir rol', error);
|
||||
this.toastService.error(this.translate.instant('errorAddingRole1'), error);
|
||||
console.error(this.translate.instant('errorAddingRole'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
|
|
@ -8,6 +10,7 @@ import { ConfigService } from '@services/config.service';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
|
||||
|
|
@ -31,7 +34,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching user groups', error);
|
||||
console.error(this.translate.instant('errorFetchingUserGroups'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -47,7 +50,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching user group', error);
|
||||
console.error(this.translate.instant('errorFetchingUserGroup'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label>{{ 'searchRoleLabel' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']"
|
||||
<mat-label>{{ 'labelSearchRole' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'labelSearch' | translate }}" [(ngModel)]="filters['name']"
|
||||
(keyup.enter)="search()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
|
||||
|
|
@ -24,12 +24,12 @@
|
|||
<div *ngIf="!loading">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let role"> {{ column.cell(role) }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let role" style="text-align: center;">
|
||||
<button mat-icon-button color="primary" (click)="editRole(role)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
|
@ -15,6 +17,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./roles.component.css']
|
||||
})
|
||||
export class RolesComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string = this.configService.apiUrl;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
filters: { [key: string]: string } = {};
|
||||
|
|
@ -27,17 +30,17 @@ export class RolesComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'id',
|
||||
header: 'ID',
|
||||
header: 'labelId',
|
||||
cell: (role: any) => `${role.id}`
|
||||
},
|
||||
{
|
||||
columnDef: 'name',
|
||||
header: 'Nombre',
|
||||
header: 'labelName',
|
||||
cell: (role: any) => `${role.name}`
|
||||
},
|
||||
{
|
||||
columnDef: 'permissions',
|
||||
header: 'Permisos',
|
||||
header: 'permissions',
|
||||
cell: (role: any) => `${role.permissions.join(', ')}`
|
||||
}
|
||||
];
|
||||
|
|
@ -66,7 +69,7 @@ export class RolesComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching roles', error);
|
||||
console.error(this.translate.instant('errorFetchingRoles'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -108,10 +111,10 @@ export class RolesComponent implements OnInit {
|
|||
this.http.delete(apiUrl).subscribe({
|
||||
next: () => {
|
||||
this.search();
|
||||
this.toastService.success('Role deleted successfully');
|
||||
this.toastService.success(this.translate.instant('roleDeletedSuccessfully'));
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error('Error deleting role:', error);
|
||||
this.toastService.error(this.translate.instant('errorDeletingRole'), error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
<mat-dialog-content class="form-container">
|
||||
<form [formGroup]="userForm" class="user-form">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'addUserlabelUsername' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelAddUserUsername' | translate }}</mat-label>
|
||||
<input matInput formControlName="username" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'addUserlabelPassword' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelAddUserPassword' | translate }}</mat-label>
|
||||
<input matInput formControlName="password" type="password" required>
|
||||
</mat-form-field>
|
||||
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Vista tarjetas</mat-label>
|
||||
<mat-label>{{ 'cardView' | translate }}</mat-label>
|
||||
<mat-select formControlName="groupsView" required>
|
||||
<mat-option *ngFor="let option of views" [value]="option.value">
|
||||
{{ option.name }}
|
||||
|
|
@ -40,9 +40,9 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Clientes por página</mat-label>
|
||||
<input matInput formControlName="clientsPerPage" type="number" min="1" placeholder="Por defecto (20)">
|
||||
<mat-hint>Número de clientes mostrados por página en el listado</mat-hint>
|
||||
<mat-label>{{ 'clientsPerPage' | translate }}</mat-label>
|
||||
<input matInput formControlName="clientsPerPage" type="number" min="1" [placeholder]="'default20' | translate">
|
||||
<mat-hint>{{ 'clientsPerPageHint' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
|
@ -18,6 +20,7 @@ interface UserGroup {
|
|||
styleUrls: ['./add-user-modal.component.css']
|
||||
})
|
||||
export class AddUserModalComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
@Output() userAdded = new EventEmitter<void>();
|
||||
@Output() userEdited = new EventEmitter<void>();
|
||||
|
|
@ -94,7 +97,7 @@ export class AddUserModalComponent implements OnInit {
|
|||
},
|
||||
error: (err) => {
|
||||
this.loading = false;
|
||||
console.error('Error fetching user:', err);
|
||||
console.error(this.translate.instant('fetchingUserError'), err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -125,7 +128,7 @@ export class AddUserModalComponent implements OnInit {
|
|||
if (this.userId) {
|
||||
this.http.put(`${this.baseUrl}${this.userId}`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Usuario editado correctamente');
|
||||
this.toastService.success(this.translate.instant('userEditedSuccessfully'));
|
||||
this.userEdited.emit();
|
||||
this.dialogRef.close();
|
||||
this.loading = false;
|
||||
|
|
@ -138,7 +141,7 @@ export class AddUserModalComponent implements OnInit {
|
|||
} else {
|
||||
this.http.post(`${this.baseUrl}/users`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Usuario añadido correctamente');
|
||||
this.toastService.success(this.translate.instant('userAddedSuccessfully'));
|
||||
this.userAdded.emit();
|
||||
this.dialogRef.close();
|
||||
this.loading = false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<h1 mat-dialog-title>{{ 'dialogTitleChangePassword' | translate }}</h1>
|
||||
<h1 mat-dialog-title>{{ 'changePassword' | translate }}</h1>
|
||||
<mat-dialog-content class="form-container">
|
||||
<form [formGroup]="userForm" class="user-form">
|
||||
<mat-form-field class="form-field">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, EventEmitter, Inject, Output } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
|
@ -10,6 +12,7 @@ import {ToastrService} from "ngx-toastr";
|
|||
styleUrl: './change-password-modal.component.css'
|
||||
})
|
||||
export class ChangePasswordModalComponent {
|
||||
public translate = inject(TranslateService);
|
||||
@Output() userEdited = new EventEmitter<void>();
|
||||
userForm: FormGroup;
|
||||
passwordMismatch: boolean = false;
|
||||
|
|
@ -55,10 +58,10 @@ export class ChangePasswordModalComponent {
|
|||
next: () => {
|
||||
this.userEdited.emit();
|
||||
this.dialogRef.close();
|
||||
this.toastService.success('Contraseña cambiada con éxito');
|
||||
this.toastService.success(this.translate.instant('passwordChangedSuccessfully'));
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error changing password:', err);
|
||||
console.error(this.translate.instant('errorChangingPassword'), err);
|
||||
this.toastService.error(err.error['hydra:description']);
|
||||
this.resetPasswordError = err.error.message;
|
||||
this.updateError = true;
|
||||
|
|
@ -66,7 +69,7 @@ export class ChangePasswordModalComponent {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
console.error('Form is invalid');
|
||||
console.error(this.translate.instant('formIsInvalid'));
|
||||
this.passwordMismatch = this.userForm.hasError('mismatch');
|
||||
this.updateError = true;
|
||||
this.loading = false
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
|
|
@ -9,6 +11,7 @@ import { ConfigService } from '@services/config.service';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
|
||||
|
|
@ -32,7 +35,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching users', error);
|
||||
console.error(this.translate.instant('fetchingUsersError'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -48,7 +51,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching user group', error);
|
||||
console.error(this.translate.instant('errorFetchingUserGroup'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -64,7 +67,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching user groups', error);
|
||||
console.error(this.translate.instant('errorFetchingUserGroups'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -80,7 +83,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching organizational units', error);
|
||||
console.error(this.translate.instant('errorFetchingOrganizationalUnits'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label>{{ 'searchLabel' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']"
|
||||
<mat-label>{{ 'labelSearch' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'labelSearch' | translate }}" [(ngModel)]="filters['name']"
|
||||
(keyup.enter)="search()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<div *ngIf="!loading">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let user">
|
||||
<ng-container *ngIf="column.columnDef === 'groupsView'">
|
||||
<mat-chip>
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let user" style="text-align: center;">
|
||||
<button mat-icon-button color="primary" (click)="editUser(user)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
|
@ -13,6 +15,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./users.component.css']
|
||||
})
|
||||
export class UsersComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
|
|
@ -25,32 +28,32 @@ export class UsersComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'id',
|
||||
header: 'ID',
|
||||
header: 'labelId',
|
||||
cell: (user: any) => `${user.id}`
|
||||
},
|
||||
{
|
||||
columnDef: 'username',
|
||||
header: 'Nombre de Usuario',
|
||||
header: 'userName',
|
||||
cell: (user: any) => `${user.username}`
|
||||
},
|
||||
{
|
||||
columnDef: 'groupsView',
|
||||
header: 'Vista de Grupos',
|
||||
header: 'groupView',
|
||||
cell: (user: any) => `${user.groupsView}`
|
||||
},
|
||||
{
|
||||
columnDef: 'clientsPerPage',
|
||||
header: 'Clientes por página',
|
||||
header: 'clientsPerPage',
|
||||
cell: (user: any) => user.clientsPerPage != null ? `${user.clientsPerPage}` : '-'
|
||||
},
|
||||
{
|
||||
columnDef: 'allowedOrganizationalUnits',
|
||||
header: 'Unidades Organizacionales Permitidas',
|
||||
header: 'allowedOrganizationalUnits',
|
||||
cell: (user: any) => `${user.allowedOrganizationalUnits.map((unit: { name: any; }) => unit.name).join(', ')}`
|
||||
},
|
||||
{
|
||||
columnDef: 'roles',
|
||||
header: 'Roles',
|
||||
header: 'labelRoles',
|
||||
cell: (user: any) => `${user.roles.join(', ')}`
|
||||
}
|
||||
];
|
||||
|
|
@ -79,7 +82,7 @@ export class UsersComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching users', error);
|
||||
console.error(this.translate.instant('fetchingUsersError'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -123,11 +126,11 @@ export class UsersComponent implements OnInit {
|
|||
this.http.delete(apiUrl).subscribe({
|
||||
next: () => {
|
||||
console.log('User deleted successfully');
|
||||
this.toastService.success('User deleted successfully');
|
||||
this.toastService.success(this.translate.instant('userDeletedSuccessfully'));
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error deleting user:', error);
|
||||
console.error(this.translate.instant('errorDeletingUser'), error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
<div class="search-container">
|
||||
<mat-form-field joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}" appearance="fill"
|
||||
class="search-string">
|
||||
<mat-label>{{ 'searchCalendarLabel' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']"
|
||||
<mat-label>{{ 'labelSearchCalendar' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'labelSearch' | translate }}" [(ngModel)]="filters['name']"
|
||||
(keyup.enter)="search()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep"
|
||||
text="{{ 'tableStepText' | translate }}">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'">
|
||||
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let calendar" style="text-align: center;">
|
||||
<button mat-icon-button color="primary" (click)="editCalendar(calendar)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, signal } from '@angular/core';
|
||||
import { MatTableDataSource } from "@angular/material/table";
|
||||
import { DatePipe } from "@angular/common";
|
||||
|
|
@ -17,6 +19,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrl: './calendar.component.css'
|
||||
})
|
||||
export class CalendarComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
images: { downloadUrl: string; name: string; uuid: string }[] = [];
|
||||
|
|
@ -34,22 +37,22 @@ export class CalendarComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'id',
|
||||
header: 'ID',
|
||||
header: 'labelId',
|
||||
cell: (remoteCalendar: any) => `${remoteCalendar.id}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'name',
|
||||
header: 'Nombre',
|
||||
header: 'labelName',
|
||||
cell: (remoteCalendar: any) => `${remoteCalendar.name}`
|
||||
},
|
||||
{
|
||||
columnDef: 'rulesLength',
|
||||
header: 'Nº de reglas',
|
||||
header: 'numberOfRules',
|
||||
cell: (remoteCalendar: any) => `${remoteCalendar.remoteCalendarRules.length}`
|
||||
},
|
||||
{
|
||||
columnDef: 'createdAt',
|
||||
header: 'Fecha de creación',
|
||||
header: 'creationDate',
|
||||
cell: (remoteCalendar: any) => `${this.datePipe.transform(remoteCalendar.createdAt, 'dd/MM/yyyy hh:mm:ss')}`,
|
||||
}
|
||||
];
|
||||
|
|
@ -89,7 +92,7 @@ export class CalendarComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching calendars', error);
|
||||
console.error(this.translate.instant('errorFetchingCalendars'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -99,7 +102,7 @@ export class CalendarComponent implements OnInit {
|
|||
this.syncUds = true;
|
||||
this.http.post(`${this.apiUrl}/${calendar.uuid}/sync-uds`, {}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Calendarios sincronizados correctamente');
|
||||
this.toastService.success(this.translate.instant('calendarsSynchronizedCorrectly'));
|
||||
this.search();
|
||||
this.syncUds = false;
|
||||
},
|
||||
|
|
@ -136,10 +139,10 @@ export class CalendarComponent implements OnInit {
|
|||
this.http.delete(apiUrl).subscribe({
|
||||
next: () => {
|
||||
this.search();
|
||||
this.toastService.success('Calendar deleted successfully');
|
||||
this.toastService.success(this.translate.instant('calendarDeletedSuccessfully'));
|
||||
},
|
||||
error: () => {
|
||||
this.toastService.error('Error deleting calendar');
|
||||
this.toastService.error(this.translate.instant('errorDeletingCalendar'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<div *ngIf="!isRemoteAvailable" class="form-group">
|
||||
<mat-label>{{ 'selectWeekDays' | translate }}</mat-label>
|
||||
<p class="custom-text"> (Los dias y horas seleccionados se marcarán como aula no disponible para remote pc.) </p>
|
||||
<p class="custom-text"> {{ 'remotePcCalendarRuleInfo' | translate }}</p>
|
||||
<div class="weekday-toggle-group full-width">
|
||||
<button
|
||||
*ngFor="let day of weekDays"
|
||||
|
|
@ -38,31 +38,29 @@
|
|||
<div class="unavailability-summary" *ngIf="busyFromHour && busyToHour && busyWeekDays && getSelectedDays().length">
|
||||
<mat-icon style="width: 50px;" color="warn">block</mat-icon>
|
||||
<span class="summary-text">
|
||||
El aula estará <strong>no disponible</strong> para Remote PC los días:
|
||||
<strong>{{ getSelectedDays().join(', ') }}</strong> de
|
||||
<strong>{{ busyFromHour }}</strong> a <strong>{{ busyToHour }}</strong>.
|
||||
{{ 'classroomWillBe' | translate }}<strong>{{ 'notAvailableLowercase' | translate }}</strong> {{ 'forRemotePcOnDays' | translate }}<strong>{{ getSelectedDays().join(', ') }}</strong> {{ 'labelOf' | translate }}<strong>{{ busyFromHour }}</strong> a <strong>{{ busyToHour }}</strong>.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isRemoteAvailable" class="form-group">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'reasonLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelReason' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="availableReason" placeholder="{{ 'reasonPlaceholder' | translate }}" [required]="isRemoteAvailable">
|
||||
<mat-hint>Razón por la cual el aula SI está disponible para su uso en Remote PC</mat-hint>
|
||||
<mat-hint>{{ 'reasonAvailableRemotePc' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
<div class="time-fields">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'startDate' | translate }}</mat-label>
|
||||
<input matInput [matDatepicker]="picker1" [(ngModel)]="availableFromDate" [required]="isRemoteAvailable">
|
||||
<mat-hint>MM/DD/YYYY</mat-hint>
|
||||
<mat-hint>{{ 'dateFormatPlaceholder' | translate }}</mat-hint>
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker1></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'endDate' | translate }}</mat-label>
|
||||
<input matInput [matDatepicker]="picker2" [(ngModel)]="availableToDate" [required]="isRemoteAvailable">
|
||||
<mat-hint>MM/DD/YYYY</mat-hint>
|
||||
<mat-hint>{{ 'dateFormatPlaceholder' | translate }}</mat-hint>
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker2></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
|
@ -84,11 +82,9 @@
|
|||
<div class="availability-summary" *ngIf="availableFromDate && availableToDate">
|
||||
<mat-icon color="primary" style="width: 50px;">info</mat-icon>
|
||||
<span class="summary-text">
|
||||
El aula estará <strong>disponible</strong> para reserva desde el
|
||||
<strong>{{ availableFromDate | date:'fullDate' }}</strong> hasta el
|
||||
<strong>{{ availableToDate | date:'fullDate' }}</strong>
|
||||
{{ 'classroomWillBe' | translate }}<strong>{{ 'statusAvailableLowercase' | translate }}</strong> {{ 'forReservationFrom' | translate }}<strong>{{ availableFromDate | date:'fullDate' }}</strong> {{ 'untilThe' | translate }}<strong>{{ availableToDate | date:'fullDate' }}</strong>
|
||||
<span *ngIf="busyFromHour && busyToHour">
|
||||
en el horario de <strong>{{ busyFromHour }}</strong> a <strong>{{ busyToHour }}</strong>.
|
||||
{{ 'inScheduleOf' | translate }}<strong>{{ busyFromHour }}</strong> a <strong>{{ busyToHour }}</strong>.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
|
|
@ -10,6 +12,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrl: './create-calendar-rule.component.css'
|
||||
})
|
||||
export class CreateCalendarRuleComponent {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
name: string = '';
|
||||
remoteCalendarRules: any[] = [];
|
||||
|
|
@ -98,7 +101,7 @@ export class CreateCalendarRuleComponent {
|
|||
this.http.put(`${this.baseUrl}${this.ruleId}`, formData)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Calendar rule updated successfully');
|
||||
this.toastService.success(this.translate.instant('calendarRuleUpdatedSuccessfully'));
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: (error) => {
|
||||
|
|
@ -110,7 +113,7 @@ export class CreateCalendarRuleComponent {
|
|||
this.http.post(`${this.baseUrl}/remote-calendar-rules`, formData)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Calendar rule created successfully');
|
||||
this.toastService.success(this.translate.instant('calendarRuleCreatedSuccessfully'));
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: (error) => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<mat-dialog-content class="form-container">
|
||||
<!-- Campo para el nombre -->
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'labelName' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelRoleName' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="name" required>
|
||||
<mat-icon *ngIf="isEditMode" matSuffix (click)="submitForm()">mode_edit</mat-icon>
|
||||
</mat-form-field>
|
||||
|
|
@ -28,9 +28,9 @@
|
|||
<mat-icon matListItemIcon>event_available</mat-icon>
|
||||
<div class="text-content">
|
||||
<div matListItemTitle>{{ rule.isRemoteAvailable ? ('remotePcStatusAvailable' | translate) : ('remotePcStatusUnavailable' | translate) }}</div>
|
||||
<div matListItemLine *ngIf="!rule.isRemoteAvailable">Días: <strong>{{ rule.busyWeekDaysMap }}</strong></div>
|
||||
<div matListItemLine *ngIf="!rule.isRemoteAvailable">{{ 'labelDays' | translate }}<strong>{{ rule.busyWeekDaysMap }}</strong></div>
|
||||
<div matListItemLine *ngIf="rule.isRemoteAvailable">Razón: {{ rule.availableReason }}</div>
|
||||
<div matListItemLine *ngIf="rule.isRemoteAvailable">Días: <strong>{{ rule.availableFromDate | date }} - {{ rule.availableToDate | date }}</strong></div>
|
||||
<div matListItemLine *ngIf="rule.isRemoteAvailable">{{ 'labelDays' | translate }}<strong>{{ rule.availableFromDate | date }} - {{ rule.availableToDate | date }}</strong></div>
|
||||
<div matListItemLine>Horario: {{ rule.busyFromHour }} - {{ rule.busyToHour }}</div>
|
||||
</div>
|
||||
<div class="icon-container">
|
||||
|
|
@ -50,6 +50,6 @@
|
|||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="submitForm()" [disabled]="!name || name === ''" cdkFocusInitial>
|
||||
{{ 'buttonSave' | translate }}
|
||||
{{ 'labelSaveButton' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
|
|
@ -13,6 +15,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrl: './create-calendar.component.css'
|
||||
})
|
||||
export class CreateCalendarComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
name: string = '';
|
||||
remoteCalendarRules: any[] = [];
|
||||
|
|
@ -50,7 +53,7 @@ export class CreateCalendarComponent implements OnInit {
|
|||
});
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error fetching remote calendar:', err);
|
||||
console.error(this.translate.instant('errorFetchingRemoteCalendar'), err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -75,7 +78,7 @@ export class CreateCalendarComponent implements OnInit {
|
|||
this.http.patch(`${this.baseUrl}${this.calendarId}`, payload)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Calendar updated successfully');
|
||||
this.toastService.success(this.translate.instant('calendarUpdatedSuccessfully'));
|
||||
this.dialogRef.close(true);
|
||||
this.load()
|
||||
},
|
||||
|
|
@ -88,7 +91,7 @@ export class CreateCalendarComponent implements OnInit {
|
|||
this.http.post(`${this.baseUrl}/remote-calendars`, payload)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Calendar created successfully');
|
||||
this.toastService.success(this.translate.instant('calendarCreatedSuccessfully'));
|
||||
this.dialogRef.close(true);
|
||||
this.load()
|
||||
},
|
||||
|
|
@ -129,10 +132,10 @@ export class CreateCalendarComponent implements OnInit {
|
|||
next: () => {
|
||||
console.log('Calendar deleted successfully');
|
||||
this.load();
|
||||
this.toastService.success('Calendar deleted successfully');
|
||||
this.toastService.success(this.translate.instant('calendarDeletedSuccessfully'));
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error('Error deleting calendar');
|
||||
this.toastService.error(this.translate.instant('errorDeletingCalendar'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
|
|
@ -8,6 +10,7 @@ import { ConfigService } from '@services/config.service';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
|
||||
|
|
@ -28,7 +31,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching remote calendars', error);
|
||||
console.error(this.translate.instant('errorFetchingRemoteCalendars'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -44,7 +47,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching calendar', error);
|
||||
console.error(this.translate.instant('fetchingCalendarError'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
<div class="search-container" joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label>{{ 'searchGroupNameLabel' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
|
||||
<mat-label>{{ 'labelSearchGroupName' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'labelSearch' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<div *ngIf="!loading">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let commandGroup">
|
||||
<ng-container *ngIf="column.columnDef !== 'commands'">
|
||||
{{ column.cell(commandGroup) }}
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let client" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
|
||||
<button mat-icon-button color="info" (click)="viewGroupDetails(client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
|
@ -16,6 +18,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./commands-groups.component.css']
|
||||
})
|
||||
export class CommandsGroupsComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
|
|
@ -29,22 +32,22 @@ export class CommandsGroupsComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'id',
|
||||
header: 'ID',
|
||||
header: 'labelId',
|
||||
cell: (group: any) => `${group.id}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'name',
|
||||
header: 'Nombre',
|
||||
header: 'labelName',
|
||||
cell: (group: any) => `${group.name}`
|
||||
},
|
||||
{
|
||||
columnDef: 'commands',
|
||||
header: 'Lista de comandos',
|
||||
header: 'commandList',
|
||||
cell: (group: any) => `${group.commands}`
|
||||
},
|
||||
{
|
||||
columnDef: 'createdAt',
|
||||
header: 'Fecha de creación',
|
||||
header: 'creationDate',
|
||||
cell: (group: any) => `${this.datePipe.transform(group.createdAt, 'dd/MM/yyyy hh:mm:ss')}`,
|
||||
}
|
||||
];
|
||||
|
|
@ -69,7 +72,7 @@ export class CommandsGroupsComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching command groups', error);
|
||||
console.error(this.translate.instant('fetchingCommandGroupsError'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -103,11 +106,11 @@ export class CommandsGroupsComponent implements OnInit {
|
|||
if (result) {
|
||||
this.http.delete(`${this.apiUrl}/${group.uuid}`).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Grupo de comandos eliminado con éxito');
|
||||
this.toastService.success(this.translate.instant('commandGroupRemovedWith'));
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al eliminar el grupo de comandos:', error);
|
||||
console.error(this.translate.instant('errorDeletingGroup'), error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
<form *ngIf="!loading" class="command-group-form" (ngSubmit)="onSubmit()">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'groupNameLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelGroupName' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="groupName" name="groupName" required />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-slide-toggle [(ngModel)]="enabled" name="enabled">{{ 'enabledToggle' | translate }}</mat-slide-toggle>
|
||||
<mat-slide-toggle [(ngModel)]="enabled" name="enabled">{{ 'labelEnabled' | translate }}</mat-slide-toggle>
|
||||
|
||||
<div class="command-selection">
|
||||
<div class="available-commands">
|
||||
|
|
@ -16,12 +16,12 @@
|
|||
<div class="table-wrapper">
|
||||
<table mat-table [dataSource]="availableCommands" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'nameColumn' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelRoleName' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'actionsColumn' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'actions' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let command">
|
||||
<button mat-icon-button type="button" (click)="addCommand(command)">
|
||||
<mat-icon>add</mat-icon>
|
||||
|
|
@ -55,5 +55,5 @@
|
|||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="onSubmit()" cdkFocusInitial>{{ 'buttonSave' | translate }}</button>
|
||||
<button class="submit-button" (click)="onSubmit()" cdkFocusInitial>{{ 'labelSaveButton' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
|
@ -11,6 +13,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./create-command-group.component.css']
|
||||
})
|
||||
export class CreateCommandGroupComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
availableCommands: any[] = [];
|
||||
selectedCommands: any[] = [];
|
||||
|
|
@ -48,7 +51,7 @@ export class CreateCommandGroupComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching available commands', error);
|
||||
console.error(this.translate.instant('errorFetchingAvailableCommands'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -88,23 +91,23 @@ export class CreateCommandGroupComponent implements OnInit {
|
|||
const groupId = this.data.group.uuid;
|
||||
this.http.patch(`${this.baseUrl}/command-groups/${groupId}`, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Grupo de comandos actualizado con éxito');
|
||||
this.toastService.success(this.translate.instant('commandGroupUpdatedWith'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error actualizando el grupo de comandos', error);
|
||||
this.toastService.error('Error al actualizar el grupo de comandos');
|
||||
console.error(this.translate.instant('errorUpdatingGroup'), error);
|
||||
this.toastService.error(this.translate.instant('errorUpdatingGroup'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.http.post(`${this.baseUrl}/command-groups`, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Grupo de comandos creado con éxito');
|
||||
this.toastService.success(this.translate.instant('commandGroupCreatedWith'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error creando el grupo de comandos', error);
|
||||
this.toastService.error('Error al crear el grupo de comandos');
|
||||
console.error(this.translate.instant('errorCreatingGroup'), error);
|
||||
this.toastService.error(this.translate.instant('errorCreatingGroup'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
<h3>{{ 'includedCommands' | translate }}</h3>
|
||||
<table mat-table [dataSource]="data.commands" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'nameColumn' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelRoleName' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let command"> {{ command.name }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="uuid">
|
||||
<th mat-header-cell *matHeaderCellDef> UUID </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelUuid' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let command"> {{ command.uuid }} </td>
|
||||
</ng-container>
|
||||
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
<form [formGroup]="form">
|
||||
<h4>{{ 'selectClients' | translate }}</h4>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{ 'clientsLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelClients' | translate }}</mat-label>
|
||||
<mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)">
|
||||
<mat-option *ngFor="let client of clients" [value]="client.uuid">
|
||||
{{ client.name }}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
|
@ -11,6 +13,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./detail-command-group.component.css']
|
||||
})
|
||||
export class DetailCommandGroupComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
form!: FormGroup;
|
||||
clients: any[] = [];
|
||||
|
|
@ -45,7 +48,7 @@ export class DetailCommandGroupComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error fetching clients:', error);
|
||||
console.error(this.translate.instant('fetchingClients1Error'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
|
|
@ -70,11 +73,11 @@ export class DetailCommandGroupComponent implements OnInit {
|
|||
this.http.post(apiUrl, payload).subscribe({
|
||||
next: () => {
|
||||
this.dialogRef.close();
|
||||
this.toastService.success('Grupo de comandos ejecutado exitosamente');
|
||||
this.toastService.success(this.translate.instant('groupOfCommandsExecutedSuccessfully'));
|
||||
this.loading = false;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error ejecutando grupo de comandos:', error);
|
||||
console.error(this.translate.instant('errorExecutingGroupOfCommands'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
<div class="search-container" joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label>{{ 'searchTaskLabel' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()" />
|
||||
<mat-label>{{ 'labelSearchTask' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'labelSearch' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()" />
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<div *ngIf="!loading">
|
||||
<table mat-table [dataSource]="tasks" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let task">
|
||||
<ng-container *ngIf="column.columnDef !== 'management' && column.columnDef !== 'scope' && column.columnDef !== 'organizationalUnit'">
|
||||
{{ column.cell(task) }}
|
||||
|
|
@ -50,14 +50,14 @@
|
|||
</button>
|
||||
<button class="action-button script-btn" (click)="openShowScriptDialog(task)">
|
||||
<mat-icon>code</mat-icon>
|
||||
<span>{{ 'taskActions' | translate }}</span>
|
||||
<span>{{ 'actions' | translate }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let task" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
|
||||
<button mat-icon-button color="primary" (click)="editTask(task)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
|
@ -16,6 +18,7 @@ import {DatePipe} from "@angular/common";
|
|||
styleUrls: ['./commands-task.component.css']
|
||||
})
|
||||
export class CommandsTaskComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
tasks: any[] = [];
|
||||
filters: { [key: string]: string | boolean } = {};
|
||||
|
|
@ -26,13 +29,13 @@ export class CommandsTaskComponent implements OnInit {
|
|||
datePipe: DatePipe = new DatePipe('es-ES');
|
||||
|
||||
columns = [
|
||||
{ columnDef: 'id', header: 'ID', cell: (task: any) => task.id },
|
||||
{ columnDef: 'name', header: 'Nombre de tarea', cell: (task: any) => task.name },
|
||||
{ columnDef: 'scope', header: 'Ámbito', cell: (task: any) => task.scope },
|
||||
{ columnDef: 'organizationalUnit', header: 'Unidad Organizativa', cell: (task: any) => task.organizationalUnit?.name || '' },
|
||||
{ columnDef: 'management', header: 'Gestiones', cell: (task: any) => task.schedules },
|
||||
{ columnDef: 'nextExecution', header: 'Próxima ejecución', cell: (task: any) => this.datePipe.transform(task.nextExecution, 'dd/MM/yyyy HH:mm:ss') },
|
||||
{ columnDef: 'createdBy', header: 'Creado por', cell: (task: any) => task.createdBy },
|
||||
{ columnDef: 'id', header: 'labelId', cell: (task: any) => task.id },
|
||||
{ columnDef: 'name', header: 'taskName', cell: (task: any) => task.name },
|
||||
{ columnDef: 'scope', header: 'labelScope', cell: (task: any) => task.scope },
|
||||
{ columnDef: 'organizationalUnit', header: 'organizationalUnit', cell: (task: any) => task.organizationalUnit?.name || '' },
|
||||
{ columnDef: 'management', header: 'efforts', cell: (task: any) => task.schedules },
|
||||
{ columnDef: 'nextExecution', header: 'nextExecution', cell: (task: any) => this.datePipe.transform(task.nextExecution, 'dd/MM/yyyy HH:mm:ss') },
|
||||
{ columnDef: 'createdBy', header: 'createdBy', cell: (task: any) => task.createdBy },
|
||||
];
|
||||
|
||||
displayedColumns: string[] = ['id', 'name', 'scope', 'management', 'nextExecution', 'createdBy', 'actions'];
|
||||
|
|
@ -65,7 +68,7 @@ export class CommandsTaskComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching tasks', error);
|
||||
console.error(this.translate.instant('fetchingTasksError'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -133,11 +136,11 @@ export class CommandsTaskComponent implements OnInit {
|
|||
if (result) {
|
||||
this.http.delete(`${this.apiUrl}/${task.uuid}`).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Tarea eliminada con éxito');
|
||||
this.toastService.success(this.translate.instant('taskDeletedSuccessfully'));
|
||||
this.loadTasks();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al eliminar la tarea:', error);
|
||||
console.error(this.translate.instant('errorDeletingTask'), error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
</mat-form-field>
|
||||
|
||||
<div *ngIf="form.get('recurrenceType')?.value !== 'none'" class="mb-4">
|
||||
<label class="section-label">{{ 'weekDaysLabel' | translate }}:</label>
|
||||
<label class="section-label">{{ 'labelWeekDays' | translate }}:</label>
|
||||
<div class="weekday-toggle-group">
|
||||
<button
|
||||
*ngFor="let day of weekDays"
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
</div>
|
||||
|
||||
<div *ngIf="form.get('recurrenceType')?.value !== 'none'" >
|
||||
<label class="section-label">{{ 'monthsLabel' | translate }}:</label>
|
||||
<label class="section-label">{{ 'labelMonths' | translate }}:</label>
|
||||
<div class="month-toggle-row" *ngFor="let row of monthRows">
|
||||
<button
|
||||
*ngFor="let month of row"
|
||||
|
|
@ -106,6 +106,6 @@
|
|||
<button class="ordinary-button" (click)="onCancel()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" [disabled]="!form.valid" (click)="onSubmit()">
|
||||
<mat-icon>save</mat-icon>
|
||||
{{ 'buttonSave' | translate }}
|
||||
{{ 'labelSaveButton' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, Inject, OnInit } from '@angular/core';
|
||||
import {FormBuilder, FormGroup} from "@angular/forms";
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
|
|
@ -11,12 +13,13 @@ import {ConfigService} from "@services/config.service";
|
|||
styleUrl: './create-task-schedule.component.css'
|
||||
})
|
||||
export class CreateTaskScheduleComponent implements OnInit{
|
||||
public translate = inject(TranslateService);
|
||||
form: FormGroup;
|
||||
baseUrl: string;
|
||||
apiUrl: string;
|
||||
recurrenceTypes = [
|
||||
{ value: 'none', label: 'Sin repetición' },
|
||||
{ value: 'custom', label: 'Repetición personalizada' }
|
||||
{ value: 'none', label : this.translate.instant('withoutRepetition') },
|
||||
{ value: 'custom', label : this.translate.instant('customRepeat') }
|
||||
];
|
||||
weekDays: string[] = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
|
||||
isSingleDateSelected: boolean = true;
|
||||
|
|
@ -105,7 +108,7 @@ export class CreateTaskScheduleComponent implements OnInit{
|
|||
}, {});
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error loading schedule data', error);
|
||||
console.error(this.translate.instant('errorLoadingScheduleData'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -173,12 +176,12 @@ export class CreateTaskScheduleComponent implements OnInit{
|
|||
const selectedMonthNames = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]);
|
||||
|
||||
if (selectedDayNames.length === 0) {
|
||||
this.toastr.error('Debe seleccionar al menos un día de la semana');
|
||||
this.toastr.error(this.translate.instant('youMustSelectAtLeastOne1'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedMonthNames.length === 0) {
|
||||
this.toastr.error('Debe seleccionar al menos un mes');
|
||||
this.toastr.error(this.translate.instant('youMustSelectAtLeastOne2'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -186,12 +189,12 @@ export class CreateTaskScheduleComponent implements OnInit{
|
|||
const endDate = formData.recurrenceDetails?.endDate;
|
||||
|
||||
if (!initDate || !endDate) {
|
||||
this.toastr.error('Debe especificar fecha de inicio y fecha de fin');
|
||||
this.toastr.error(this.translate.instant('youMustSpecifyStartDate'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (new Date(endDate) <= new Date(initDate)) {
|
||||
this.toastr.error('La fecha de fin debe ser posterior a la fecha de inicio');
|
||||
this.toastr.error(this.translate.instant('theEndDateMust'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,21 +218,21 @@ export class CreateTaskScheduleComponent implements OnInit{
|
|||
const taskId = this.data.task.uuid;
|
||||
this.http.patch<any>(`${this.baseUrl}${this.data.schedule['@id']}`, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastr.success('Programacion de tarea actualizada con éxito');
|
||||
this.toastr.success(this.translate.instant('updatedTaskScheduleWith'));
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: () => {
|
||||
this.toastr.error('Error al actualizar la tarea');
|
||||
this.toastr.error(this.translate.instant('errorUpdatingTask'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.http.post<any>(this.apiUrl, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastr.success('Programacion de tarea creada con éxito');
|
||||
this.toastr.success(this.translate.instant('taskScheduleCreatedWith'));
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: () => {
|
||||
this.toastr.error('Error al crear la tarea');
|
||||
this.toastr.error(this.translate.instant('errorCreatingTask'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
</div>
|
||||
|
||||
<div class="info-supported-ops">
|
||||
<p class="info-supported-label">{{ 'supportedOpsLabel' | translate }}:</p>
|
||||
<p class="info-supported-label">{{ 'labelSupportedOps' | translate }}:</p>
|
||||
<ng-container *ngFor="let cat of categories">
|
||||
<ng-container *ngIf="cat.id === selectedCategory">
|
||||
<div *ngFor="let action of cat.actions" class="info-op-chip">
|
||||
|
|
@ -131,7 +131,7 @@
|
|||
<mat-label>{{ 'enterScript' | translate }}</mat-label>
|
||||
<textarea matInput [(ngModel)]="newScript" rows="6" [placeholder]="'writeScriptHere' | translate"></textarea>
|
||||
</mat-form-field>
|
||||
<button mat-flat-button color="primary" (click)="saveNewScript()">{{ 'saveScript' | translate }}</button>
|
||||
<button mat-flat-button color="primary" (click)="saveNewScript()">{{ 'buttonSaveScript' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="commandType === 'existing'">
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
|
||||
<div *ngIf="selectedScript && commandType === 'existing'" class="script-container">
|
||||
<div class="script-content">
|
||||
<h3>{{ 'scriptLabel' | translate }}:</h3>
|
||||
<h3>{{ 'labelScript' | translate }}:</h3>
|
||||
<div class="script-preview" [innerHTML]="scriptContent"></div>
|
||||
</div>
|
||||
<div class="script-params" *ngIf="parameterNames.length > 0">
|
||||
|
|
@ -165,5 +165,5 @@
|
|||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onCancel()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="onSubmit()" *ngIf="selectedAction">{{ 'buttonSave' | translate }}</button>
|
||||
<button class="submit-button" (click)="onSubmit()" *ngIf="selectedAction">{{ 'labelSaveButton' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ export class CreateTaskScriptComponent implements OnInit {
|
|||
|
||||
saveNewScript(): void {
|
||||
if (!this.newScript.trim()) {
|
||||
this.toastService.error('Debe ingresar un script antes de guardar.');
|
||||
this.toastService.error(this.translate.instant('youMustEnterAScriptBefore'));
|
||||
return;
|
||||
}
|
||||
const dialogRef = this.dialog.open(SaveScriptComponent, {
|
||||
|
|
@ -209,7 +209,7 @@ export class CreateTaskScriptComponent implements OnInit {
|
|||
});
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Script guardado correctamente');
|
||||
this.toastService.success(this.translate.instant('scriptSavedSuccessfully'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@ export class CreateTaskScriptComponent implements OnInit {
|
|||
break;
|
||||
|
||||
default:
|
||||
this.toastService.error('Tipo de acción no reconocido');
|
||||
this.toastService.error(this.translate.instant('unrecognizedActionType'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -269,12 +269,12 @@ export class CreateTaskScriptComponent implements OnInit {
|
|||
private validateScript(): boolean {
|
||||
if (this.commandType === 'new') {
|
||||
if (!this.newScript.trim()) {
|
||||
this.toastService.error('Debe ingresar un script');
|
||||
this.toastService.error(this.translate.instant('youMustEnterAScript'));
|
||||
return false;
|
||||
}
|
||||
} else if (this.commandType === 'existing') {
|
||||
if (!this.selectedScript) {
|
||||
this.toastService.error('Debe seleccionar un script');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAScript'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<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>
|
||||
{{ 'createTaskLabel' | translate }}
|
||||
{{ 'labelCreateTask' | translate }}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle value="add">
|
||||
<mat-icon>playlist_add</mat-icon>
|
||||
|
|
@ -41,13 +41,13 @@
|
|||
|
||||
<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>
|
||||
<mat-label>{{ 'labelRoleName' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" [placeholder]="'nameLabel' | translate">
|
||||
<mat-error *ngIf="taskForm.get('name')?.invalid">{{ 'requiredFieldError' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'notesLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelNotes' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="notes" [placeholder]="'notesPlaceholder' | translate"></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
|
|
@ -58,19 +58,19 @@
|
|||
<mat-divider style="margin: 15px 0;"></mat-divider>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'scopeLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelScope' | translate }}</mat-label>
|
||||
<mat-select formControlName="scope" (selectionChange)="onScopeChange($event.value)"
|
||||
[disabled]="data?.clients && data.clients.length >= 1">
|
||||
<mat-option value="organizational-unit">{{ 'scopeOrganizationalUnit' | translate }}</mat-option>
|
||||
<mat-option value="organizational-unit">{{ 'organizationalUnit' | translate }}</mat-option>
|
||||
<mat-option value="classrooms-group">{{ 'scopeClassroomsGroup' | translate }}</mat-option>
|
||||
<mat-option value="classroom">{{ 'scopeClassroom' | translate }}</mat-option>
|
||||
<mat-option value="clients-group">{{ 'scopeClientsGroup' | translate }}</mat-option>
|
||||
<mat-option value="clients">{{ 'scopeClients' | translate }}</mat-option>
|
||||
<mat-option value="classroom">{{ 'classrooms' | translate }}</mat-option>
|
||||
<mat-option value="clients-group">{{ 'clientGroupsTitle' | translate }}</mat-option>
|
||||
<mat-option value="clients">{{ 'labelClients' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field *ngIf="taskForm.get('scope')?.value !== 'clients'" appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelOrganizationalUnit' | translate }}</mat-label>
|
||||
<mat-select formControlName="organizationalUnit">
|
||||
<mat-option *ngFor="let unit of availableOrganizationalUnits" [value]="unit['@id']">
|
||||
<div class="unit-name">{{ unit.name }}</div>
|
||||
|
|
@ -121,6 +121,6 @@
|
|||
class="submit-button"
|
||||
(click)="taskMode === 'create' ? saveTask() : addToExistingTask()"
|
||||
>
|
||||
{{ 'buttonSave' | translate }}
|
||||
{{ 'labelSaveButton' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
|
||||
|
|
@ -15,6 +17,7 @@ import {ShowTaskScriptComponent} from "../show-task-script/show-task-script.comp
|
|||
styleUrls: ['./create-task.component.css']
|
||||
})
|
||||
export class CreateTaskComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
taskForm: FormGroup;
|
||||
availableCommandGroups: any[] = [];
|
||||
|
|
@ -109,7 +112,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
this.toastr.error('Error al cargar los datos de la tarea');
|
||||
this.toastr.error(this.translate.instant('errorLoadingData'));
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -124,7 +127,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
this.toastr.error('Error al cargar las tareas existentes');
|
||||
this.toastr.error(this.translate.instant('errorLoadingTasks'));
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -137,7 +140,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
this.selectedClients = [...this.data.selectedClients];
|
||||
this.clients = [...this.data.selectedClients];
|
||||
} else {
|
||||
this.toastr.error('No hay clientes pre-seleccionados para este ámbito');
|
||||
this.toastr.error(this.translate.instant('thereAreNoPreselectedClientsFor'));
|
||||
this.taskForm.get('scope')?.setValue('');
|
||||
return;
|
||||
}
|
||||
|
|
@ -168,7 +171,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
this.availableOrganizationalUnits = filteredUnits;
|
||||
resolve();
|
||||
}, error => {
|
||||
this.toastr.error('Error al filtrar las unidades organizacionales');
|
||||
this.toastr.error(this.translate.instant('errorWhenFilteringUnits'));
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
|
|
@ -187,7 +190,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
this.toastr.error('Error al cargar los grupos de comandos');
|
||||
this.toastr.error(this.translate.instant('errorLoadingGroups'));
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
|
@ -201,7 +204,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
this.toastr.error('Error al cargar los comandos individuales');
|
||||
this.toastr.error(this.translate.instant('errorLoadingCommands'));
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
|
@ -216,7 +219,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
(error) => {
|
||||
this.toastr.error('Error al cargar las unidades organizacionales');
|
||||
this.toastr.error(this.translate.instant('errorLoadingUnits'));
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -225,12 +228,12 @@ export class CreateTaskComponent implements OnInit {
|
|||
|
||||
addToExistingTask() {
|
||||
if (!this.selectedExistingTask) {
|
||||
this.toastr.error('Debes seleccionar una tarea existente.');
|
||||
this.toastr.error(this.translate.instant('youMustSelectAnExistingTask'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.executionOrder == null || this.executionOrder < 1) {
|
||||
this.toastr.error('Debes introducir un orden de ejecución válido (mayor que 0).');
|
||||
this.toastr.error(this.translate.instant('youMustEnterAnOrderOf'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -239,14 +242,14 @@ export class CreateTaskComponent implements OnInit {
|
|||
executionOrder: this.executionOrder
|
||||
};
|
||||
|
||||
this.toastr.success('Tarea actualizada con éxito');
|
||||
this.toastr.success(this.translate.instant('taskUpdatedSuccessfully'));
|
||||
this.dialogRef.close(data);
|
||||
}
|
||||
|
||||
|
||||
saveTask(): void {
|
||||
if (this.taskForm.invalid) {
|
||||
this.toastr.error('Por favor, rellene todos los campos obligatorios');
|
||||
this.toastr.error(this.translate.instant('pleaseFillOutAll'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -254,12 +257,12 @@ export class CreateTaskComponent implements OnInit {
|
|||
const scope = formData.scope;
|
||||
|
||||
if (scope === 'clients' && this.selectedClients.length === 0) {
|
||||
this.toastr.error('Debe seleccionar al menos un cliente');
|
||||
this.toastr.error(this.translate.instant('youMustSelectAtLeastOne'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (scope !== 'clients' && !formData.organizationalUnit) {
|
||||
this.toastr.error('Debe seleccionar una unidad organizativa');
|
||||
this.toastr.error(this.translate.instant('youMustSelectAnOrganizationalUnit'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -280,17 +283,17 @@ export class CreateTaskComponent implements OnInit {
|
|||
const taskId = this.data.task.uuid;
|
||||
this.http.patch<any>(`${this.apiUrl}/${taskId}`, payload).subscribe({
|
||||
next: () => {
|
||||
this.toastr.success('Tarea actualizada con éxito');
|
||||
this.toastr.success(this.translate.instant('taskUpdatedSuccessfully'));
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: () => {
|
||||
this.toastr.error('Error al actualizar la tarea');
|
||||
this.toastr.error(this.translate.instant('errorUpdatingTask'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.http.post<any>(this.apiUrl, payload).subscribe({
|
||||
next: response => {
|
||||
this.toastr.success('Tarea creada con éxito');
|
||||
this.toastr.success(this.translate.instant('taskCreatedSuccessfully'));
|
||||
this.dialogRef.close(response);
|
||||
if (this.data?.source === 'assistant') {
|
||||
if (formData.scheduleAfterCreate) {
|
||||
|
|
@ -301,7 +304,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
error: () => {
|
||||
this.toastr.error('Error al crear la tarea');
|
||||
this.toastr.error(this.translate.instant('errorCreatingTask'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -313,7 +316,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
data: { task: task }
|
||||
}).afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastr.success('Tarea programada correctamente');
|
||||
this.toastr.success(this.translate.instant('successfullyScheduledTask'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -334,7 +337,7 @@ export class CreateTaskComponent implements OnInit {
|
|||
data: { task: task }
|
||||
}).afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastr.success('Tarea programada correctamente');
|
||||
this.toastr.success(this.translate.instant('successfullyScheduledTask'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,27 +9,26 @@
|
|||
<mat-card-content>
|
||||
<p><strong>{{ 'taskId' | translate }}:</strong> {{ task.uuid }}</p>
|
||||
<p><strong>{{ 'creationDate' | translate }}:</strong> {{ task.createdAt | date: 'short' }}</p>
|
||||
<p><strong>{{ 'notes' | translate }}:</strong> {{ task.notes }}</p>
|
||||
<p><strong>{{ 'labelNotes' | translate }}:</strong> {{ task.notes }}</p>
|
||||
|
||||
<h3>{{ 'commandsToExecute' | translate }}</h3>
|
||||
<table mat-table [dataSource]="task.commandTaskScripts || []" class="mat-elevation-z8" *ngIf="task.commandTaskScripts?.length > 0">
|
||||
<ng-container matColumnDef="order">
|
||||
<th mat-header-cell *matHeaderCellDef>Orden</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelOrder' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let script">{{ script.order }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef>Tipo</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelType' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let script">{{ script.type }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="content">
|
||||
<th mat-header-cell *matHeaderCellDef>Contenido</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelContent' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let script">
|
||||
<span *ngIf="script.content">{{ script.content }}</span>
|
||||
<span *ngIf="!script.content && script.parameters">
|
||||
(parámetros configurados)
|
||||
</span>
|
||||
{{ 'configuredParameters' | translate }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
|
@ -37,7 +36,7 @@
|
|||
<tr mat-row *matRowDef="let row; columns: ['order', 'type', 'content'];"></tr>
|
||||
</table>
|
||||
|
||||
<p *ngIf="!task.commandTaskScripts?.length">No hay acciones configuradas.</p>
|
||||
<p *ngIf="!task.commandTaskScripts?.length">{{ 'noActionsConfigured' | translate }}</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label>{{ 'searchScheduleLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelSearchSchedule' | translate }}</mat-label>
|
||||
<input matInput [placeholder]="'searchPlaceholder' | translate" [(ngModel)]="filters['name']"
|
||||
(keyup.enter)="loadData()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<app-loading [isLoading]="loading"></app-loading>
|
||||
<table *ngIf="!loading" mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let schedule">
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'recurrenceType'">
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let schedule" style="text-align: center;">
|
||||
<button mat-icon-button color="primary" (click)="editSchedule(schedule)" [matTooltip]="'editScheduleTooltip' | translate">
|
||||
<mat-icon>edit</mat-icon>
|
||||
|
|
@ -120,5 +120,5 @@
|
|||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'close' | translate }}</button>
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonClose' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, Inject, OnInit } from '@angular/core';
|
||||
import {MatTableDataSource} from "@angular/material/table";
|
||||
import {Client} from "../../../groups/model/model";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
|
|
@ -15,6 +17,7 @@ import {DatePipe} from "@angular/common";
|
|||
styleUrl: './show-task-schedule.component.css'
|
||||
})
|
||||
export class ShowTaskScheduleComponent implements OnInit{
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
dataSource = new MatTableDataSource<any>([]);
|
||||
length = 0;
|
||||
|
|
@ -26,13 +29,13 @@ export class ShowTaskScheduleComponent implements OnInit{
|
|||
datePipe: DatePipe = new DatePipe('es-ES');
|
||||
|
||||
columns = [
|
||||
{ columnDef: 'id', header: 'ID', cell: (schedule: any) => schedule.id },
|
||||
{ columnDef: 'recurrenceType', header: 'Tipo de Programación', cell: (schedule: any) => this.getRecurrenceTypeDisplay(schedule) },
|
||||
{ columnDef: 'executionTime', header: 'Hora de ejecución', cell: (schedule: any) => this.formatExecutionTimeForDisplay(schedule.executionTime) },
|
||||
{ columnDef: 'nextExecution', header: 'Próxima ejecución', cell: (schedule: any) => this.calculateNextExecution(schedule) },
|
||||
{ columnDef: 'daysOfWeek', header: 'Días de la semana', cell: (schedule: any) => this.formatDaysOfWeek(schedule.recurrenceDetails?.daysOfWeek) },
|
||||
{ columnDef: 'months', header: 'Meses', cell: (schedule: any) => this.formatMonths(schedule.recurrenceDetails?.months) },
|
||||
{ columnDef: 'enabled', header: 'Estado', cell: (schedule: any) => schedule.enabled }
|
||||
{ columnDef: 'id', header: 'labelId', cell: (schedule: any) => schedule.id },
|
||||
{ columnDef: 'recurrenceType', header: 'typeOfProgramming', cell: (schedule: any) => this.getRecurrenceTypeDisplay(schedule) },
|
||||
{ columnDef: 'executionTime', header: 'executionTime', cell: (schedule: any) => this.formatExecutionTimeForDisplay(schedule.executionTime) },
|
||||
{ columnDef: 'nextExecution', header: 'nextExecution', cell: (schedule: any) => this.calculateNextExecution(schedule) },
|
||||
{ columnDef: 'daysOfWeek', header: 'daysOfTheWeek', cell: (schedule: any) => this.formatDaysOfWeek(schedule.recurrenceDetails?.daysOfWeek) },
|
||||
{ columnDef: 'months', header: 'labelMonths', cell: (schedule: any) => this.formatMonths(schedule.recurrenceDetails?.months) },
|
||||
{ columnDef: 'enabled', header: 'state', cell: (schedule: any) => schedule.enabled }
|
||||
];
|
||||
|
||||
displayedColumns: string[] = ['id', 'recurrenceType', 'executionTime', 'nextExecution', 'daysOfWeek', 'months', 'enabled', 'actions'];
|
||||
|
|
@ -67,7 +70,7 @@ export class ShowTaskScheduleComponent implements OnInit{
|
|||
},
|
||||
(error) => {
|
||||
this.loading = false;
|
||||
this.toastService.error('Error al cargar las programaciones');
|
||||
this.toastService.error(this.translate.instant('errorLoadingProgramming'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -79,7 +82,7 @@ export class ShowTaskScheduleComponent implements OnInit{
|
|||
}).afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.loadData();
|
||||
this.toastService.success('Programación creada correctamente');
|
||||
this.toastService.success(this.translate.instant('programmingCreatedCorrectly'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -91,7 +94,7 @@ export class ShowTaskScheduleComponent implements OnInit{
|
|||
}).afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.loadData();
|
||||
this.toastService.success('Programación actualizada correctamente');
|
||||
this.toastService.success(this.translate.instant('programmingUpdatedCorrectly'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -106,7 +109,7 @@ export class ShowTaskScheduleComponent implements OnInit{
|
|||
if (result) {
|
||||
this.http.delete(`${this.baseUrl}${schedule['@id']}`).subscribe(
|
||||
() => {
|
||||
this.toastService.success('Programación eliminada correctamente');
|
||||
this.toastService.success(this.translate.instant('programmingRemovedCorrectly'));
|
||||
this.loadData();
|
||||
},
|
||||
(error) => {
|
||||
|
|
@ -317,7 +320,7 @@ export class ShowTaskScheduleComponent implements OnInit{
|
|||
if (schedule.recurrenceType === 'none') {
|
||||
return {
|
||||
type: 'none',
|
||||
label: 'Ejecución única',
|
||||
label : this.translate.instant('uniqueExecution'),
|
||||
icon: 'event',
|
||||
color: 'primary',
|
||||
details: schedule.executionDate ?
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="content">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'scriptLabel' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelScript' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div *ngIf="item.content" class="script-content-cell">
|
||||
<code>{{ item.content }}</code>
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let item" style="text-align: center;">
|
||||
<button mat-icon-button color="warn" (click)="deleteTaskScript(item)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
|
|
@ -92,5 +92,5 @@
|
|||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'close' | translate }}</button>
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonClose' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import {MatTableDataSource} from "@angular/material/table";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
|
||||
import {ConfigService} from "@services/config.service";
|
||||
import {CreateTaskScheduleComponent} from "../create-task-schedule/create-task-schedule.component";
|
||||
import {CreateTaskScriptComponent} from "../create-task-script/create-task-script.component";
|
||||
import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||
import {ViewParametersModalComponent} from "./view-parameters-modal/view-parameters-modal.component";
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MatTableDataSource } from "@angular/material/table";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog";
|
||||
import { ConfigService } from "@services/config.service";
|
||||
import { CreateTaskScheduleComponent } from "../create-task-schedule/create-task-schedule.component";
|
||||
import { CreateTaskScriptComponent } from "../create-task-script/create-task-script.component";
|
||||
import { DeleteModalComponent } from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||
import { ViewParametersModalComponent } from "./view-parameters-modal/view-parameters-modal.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-task-script',
|
||||
templateUrl: './show-task-script.component.html',
|
||||
styleUrl: './show-task-script.component.css'
|
||||
})
|
||||
export class ShowTaskScriptComponent implements OnInit{
|
||||
export class ShowTaskScriptComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
dataSource = new MatTableDataSource<any>([]);
|
||||
length = 0;
|
||||
|
|
@ -25,26 +28,26 @@ export class ShowTaskScriptComponent implements OnInit{
|
|||
filters: { [key: string]: string } = {};
|
||||
|
||||
columns = [
|
||||
{ columnDef: 'id', header: 'ID', cell: (item: any) => item.id },
|
||||
{ columnDef: 'order', header: 'Orden', cell: (item: any) => item.order },
|
||||
{ columnDef: 'type', header: 'Tipo', cell: (item: any) => item.type },
|
||||
{ columnDef: 'parameters', header: 'Parámetros', cell: (item: any) => item.parameters },
|
||||
{ columnDef: 'content', header: 'Contenido', cell: (item: any) => item.content },
|
||||
{ columnDef: 'id', header: 'labelId', cell: (item: any) => item.id },
|
||||
{ columnDef: 'order', header: 'labelOrder', cell: (item: any) => item.order },
|
||||
{ columnDef: 'type', header: 'labelType', cell: (item: any) => item.type },
|
||||
{ columnDef: 'parameters', header: 'labelParameters', cell: (item: any) => item.parameters },
|
||||
{ columnDef: 'content', header: 'labelContent', cell: (item: any) => item.content },
|
||||
];
|
||||
|
||||
displayedColumns: string[] = ['order', 'type', 'content', 'parameters', 'actions'];
|
||||
|
||||
typeLabels: { [key: string]: { label: string, icon: string } } = {
|
||||
'partition-and-format': { label: 'Particionar y formatear', icon: 'storage' },
|
||||
'partition-assistant': { label: 'Asistente de particionado', icon: 'storage' },
|
||||
'deploy-image': { label: 'Desplegar imagen', icon: 'cloud_download' },
|
||||
'create-image': { label: 'Crear imagen', icon: 'cloud_upload' },
|
||||
'run-script': { label: 'Ejecutar script', icon: 'code' },
|
||||
'partition-and-format': { label: this.translate.instant('partitionAndFormat'), icon: 'storage' },
|
||||
'partition-assistant': { label: this.translate.instant('partitionTitle'), icon: 'storage' },
|
||||
'deploy-image': { label: this.translate.instant('displayImage'), icon: 'cloud_download' },
|
||||
'create-image': { label: this.translate.instant('createImage'), icon: 'cloud_upload' },
|
||||
'run-script': { label: this.translate.instant('runScript'), icon: 'code' },
|
||||
'reboot': { label: 'Reiniciar', icon: 'restart_alt' },
|
||||
'shutdown': { label: 'Apagar', icon: 'power_off' },
|
||||
'poweron': { label: 'Encender', icon: 'power' },
|
||||
'power-on': { label: 'Encender', icon: 'power' },
|
||||
'login': { label: 'Iniciar sesión', icon: 'login' },
|
||||
'login': { label: this.translate.instant('login'), icon: 'login' },
|
||||
};
|
||||
|
||||
getTypeDisplay(type: string): { label: string, icon: string } {
|
||||
|
|
@ -94,7 +97,7 @@ export class ShowTaskScriptComponent implements OnInit{
|
|||
if (result) {
|
||||
this.http.delete(`${this.baseUrl}${schedule['@id']}`).subscribe(
|
||||
() => {
|
||||
this.toastService.success('Eliminado correctamente');
|
||||
this.toastService.success(this.translate.instant('removedSuccessfully'));
|
||||
this.loadData();
|
||||
},
|
||||
(error) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<h2 mat-dialog-title>Parámetros</h2>
|
||||
<h2 mat-dialog-title>{{ 'labelParameters' | translate }}</h2>
|
||||
<mat-dialog-content>
|
||||
<pre>{{ data | json }}</pre>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button (click)="close()">Cerrar</button>
|
||||
<button mat-button (click)="close()">{{ 'buttonClose' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
<div class="search-container" joyrideStep="searchStep" text="{{ 'searchStepText' | translate }}">
|
||||
<mat-form-field appearance="fill" class="search-string">
|
||||
<mat-label>{{ 'searchCommandLabel' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'searchPlaceholder' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()" />
|
||||
<mat-label>{{ 'labelSearchCommand' | translate }}</mat-label>
|
||||
<input matInput placeholder="{{ 'labelSearch' | translate }}" [(ngModel)]="filters['name']" (keyup.enter)="search()" />
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>{{ 'searchHint' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<div *ngIf="!loading">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" joyrideStep="tableStep" text="{{ 'tableStepText' | translate }}">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let command">
|
||||
<ng-container *ngIf="column.columnDef !== 'readOnly'">
|
||||
{{ column.cell(command) }}
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'columnActions' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: center;">{{ 'actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let command" style="text-align: center;" joyrideStep="actionsStep" text="{{ 'actionsStepText' | translate }}">
|
||||
<button mat-icon-button color="info" (click)="viewDetails($event, command)"><mat-icon>visibility</mat-icon></button>
|
||||
<button mat-icon-button color="primary" [disabled]="command.readOnly" (click)="editCommand($event, command)"><mat-icon>edit</mat-icon></button>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
|
@ -16,6 +18,7 @@ import { JoyrideService } from 'ngx-joyride';
|
|||
styleUrls: ['./commands.component.css']
|
||||
})
|
||||
export class CommandsComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
|
|
@ -29,22 +32,22 @@ export class CommandsComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'id',
|
||||
header: 'ID',
|
||||
header: 'labelId',
|
||||
cell: (command: any) => `${command.id}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'name',
|
||||
header: 'Nombre',
|
||||
header: 'labelName',
|
||||
cell: (command: any) => `${command.name}`
|
||||
},
|
||||
{
|
||||
columnDef: 'readOnly',
|
||||
header: 'Solo Lectura',
|
||||
header: 'readOnly',
|
||||
cell: (command: any) => `${command.readOnly}`
|
||||
},
|
||||
{
|
||||
columnDef: 'createdAt',
|
||||
header: 'Fecha de creación',
|
||||
header: 'creationDate',
|
||||
cell: (command: any) => `${this.datePipe.transform(command.createdAt, 'dd/MM/yyyy hh:mm:ss')}`,
|
||||
}
|
||||
];
|
||||
|
|
@ -69,7 +72,7 @@ export class CommandsComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching commands', error);
|
||||
console.error(this.translate.instant('fetchingCommandsError'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -106,11 +109,11 @@ export class CommandsComponent implements OnInit {
|
|||
if (result) {
|
||||
this.http.delete(`${this.apiUrl}/${command.uuid}`).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Comando eliminado con éxito');
|
||||
this.toastService.success(this.translate.instant('commandRemovedSuccessfully'));
|
||||
this.search();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al eliminar el comando:', error);
|
||||
console.error(this.translate.instant('errorDeletingCommand'), error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,28 +2,28 @@
|
|||
<mat-dialog-content class="form-container">
|
||||
<form [formGroup]="createCommandForm" (ngSubmit)="onSubmit()" class="command-form">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'nameLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelRoleName' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" placeholder="{{ 'commandNamePlaceholder' | translate }}" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'scriptLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelScript' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="script" placeholder="{{ 'commandScriptPlaceholder' | translate }}"></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<mat-checkbox formControlName="readOnly">{{ 'readOnlyLabel' | translate }}</mat-checkbox>
|
||||
<mat-checkbox formControlName="readOnly">{{ 'labelReadOnly' | translate }}</mat-checkbox>
|
||||
|
||||
<mat-checkbox formControlName="enabled">{{ 'enabledLabel' | translate }}</mat-checkbox>
|
||||
<mat-checkbox formControlName="enabled">{{ 'labelEnabled' | translate }}</mat-checkbox>
|
||||
|
||||
<div class="checkbox-with-hint">
|
||||
<mat-checkbox formControlName="parameters">{{ 'parameters' | translate }}</mat-checkbox>
|
||||
<span class="hint-text">Si se selecciona esta opción los parámetros deben indicarse en el script con el símbolo @.</span>
|
||||
<mat-checkbox formControlName="parameters">{{ 'labelParameters' | translate }}</mat-checkbox>
|
||||
<span class="hint-text">{{ 'scriptParameterHint' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>{{ 'commentsLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelComments' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="comments" placeholder="{{ 'commentsPlaceholder' | translate }}"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
|
@ -31,5 +31,5 @@
|
|||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onCancel($event)">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="onSubmit()" cdkFocusInitial>{{ 'buttonSave' | translate }}</button>
|
||||
<button class="submit-button" (click)="onSubmit()" cdkFocusInitial>{{ 'labelSaveButton' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
|
@ -12,6 +14,7 @@ import { ConfigService } from "@services/config.service";
|
|||
styleUrls: ['./create-command.component.css']
|
||||
})
|
||||
export class CreateCommandComponent implements OnInit{
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
createCommandForm: FormGroup<any>;
|
||||
commandId: string | null = null;
|
||||
|
|
@ -56,7 +59,7 @@ export class CreateCommandComponent implements OnInit{
|
|||
this.commandId = response['@id'];
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error fetching remote calendar:', err);
|
||||
console.error(this.translate.instant('errorFetchingRemoteCalendar'), err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -81,7 +84,7 @@ export class CreateCommandComponent implements OnInit{
|
|||
if (this.commandId) {
|
||||
this.http.put(`${this.baseUrl}${this.commandId}`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Comando editado correctamente');
|
||||
this.toastService.success(this.translate.instant('commandEditedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
(error) => {
|
||||
|
|
@ -91,7 +94,7 @@ export class CreateCommandComponent implements OnInit{
|
|||
} else {
|
||||
this.http.post(`${this.baseUrl}/commands`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Comando añadido correctamente');
|
||||
this.toastService.success(this.translate.instant('commandAddedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
(error) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
|
|
@ -8,6 +10,7 @@ import { catchError, map } from 'rxjs/operators';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
|
||||
|
|
@ -34,7 +37,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching commands', error);
|
||||
console.error(this.translate.instant('fetchingCommandsError'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -50,7 +53,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching user group', error);
|
||||
console.error(this.translate.instant('errorFetchingUserGroup'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
<div class="modal-container">
|
||||
<h3 class="modal-title">{{ 'commandDetailsTitle' | translate }}</h3>
|
||||
<div class="modal-content">
|
||||
<p><strong>{{ 'nameLabel' | translate }}:</strong> {{ data.name }}</p>
|
||||
<p><strong>{{ 'commentsLabel' | translate }}:</strong> {{ data.comments }}</p>
|
||||
<p><strong>{{ 'createdByLabel' | translate }}:</strong> {{ data.createdBy }}</p>
|
||||
<p><strong>{{ 'creationDateLabel' | translate }}:</strong> {{ data.createdAt | date:'medium' }}</p>
|
||||
<p><strong>{{ 'labelRoleName' | translate }}:</strong> {{ data.name }}</p>
|
||||
<p><strong>{{ 'labelComments' | translate }}:</strong> {{ data.comments }}</p>
|
||||
<p><strong>{{ 'labelCreatedBy' | translate }}:</strong> {{ data.createdBy }}</p>
|
||||
<p><strong>{{ 'labelCreationDate' | translate }}:</strong> {{ data.createdAt | date:'medium' }}</p>
|
||||
|
||||
<div class="script-display">
|
||||
<h4>{{ 'scriptLabel' | translate }}:</h4>
|
||||
<h4>{{ 'labelScript' | translate }}:</h4>
|
||||
<pre>{{ data.script }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="additional-section" *ngIf="showClientSelect">
|
||||
<form [formGroup]="form">
|
||||
<h4>{{ 'selectClientsTitle' | translate }}</h4>
|
||||
<h4>{{ 'selectClients' | translate }}</h4>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{ 'clientsLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelClients' | translate }}</mat-label>
|
||||
<mat-select formControlName="selectedClients" multiple (selectionChange)="onClientSelectionChange($event)">
|
||||
<mat-option *ngFor="let client of clients" [value]="client.uuid">
|
||||
{{ client.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="form.get('selectedClients')?.invalid && form.get('selectedClients')?.touched">
|
||||
{{ 'selectAtLeastOneClientError' | translate }}
|
||||
{{ 'selectAtLeastOneClient' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
|
|
@ -12,6 +14,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./command-detail.component.css']
|
||||
})
|
||||
export class CommandDetailComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
form!: FormGroup;
|
||||
clients: any[] = [];
|
||||
|
|
@ -56,7 +59,7 @@ export class CommandDetailComponent implements OnInit {
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Comando editado');
|
||||
this.toastService.success(this.translate.instant('editedCommand'));
|
||||
this.data.command = result;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<h2 mat-dialog-title> Seleccionar particion para arrancar SO</h2>
|
||||
<h2 mat-dialog-title> {{ 'selectPartitionToBootOs' | translate }}</h2>
|
||||
|
||||
<mat-dialog-content class="dialog-content">
|
||||
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
||||
|
|
@ -6,10 +6,9 @@
|
|||
<div *ngIf="!loading" class="select-container">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Clientes </mat-panel-title>
|
||||
<mat-panel-title> {{ 'labelClients' | translate }}</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Listado de clientes para arrancar un SO
|
||||
<mat-icon>desktop_windows</mat-icon>
|
||||
{{ 'clientListBootOs' | translate }}<mat-icon>desktop_windows</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
|
|
@ -42,8 +41,7 @@
|
|||
color="primary"
|
||||
[disabled]="!client.selected"
|
||||
(click)="$event.stopPropagation()">
|
||||
Modelo
|
||||
</mat-radio-button>
|
||||
{{ 'labelModel' | translate }}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -57,7 +55,7 @@
|
|||
<div *ngIf="!loading" class="partition-table-container">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">Seleccionar partición</th>
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">{{ 'buttonSelectPartition' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group
|
||||
[(ngModel)]="selectedPartition"
|
||||
|
|
@ -70,7 +68,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<ng-container *ngIf="column.columnDef !== 'size'">
|
||||
{{ column.cell(image) }}
|
||||
|
|
@ -95,6 +93,6 @@
|
|||
</mat-dialog-content>
|
||||
|
||||
<div mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||
<button class="submit-button" (click)="execute()" [disabled]="!selectedPartition">Ejecutar</button>
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="execute()" [disabled]="!selectedPartition">{{ 'buttonExecute' | translate }}</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||
import { MatTableDataSource } from "@angular/material/table";
|
||||
|
|
@ -11,6 +13,7 @@ import { ToastrService } from "ngx-toastr";
|
|||
styleUrl: './boot-so-partition.component.css'
|
||||
})
|
||||
export class BootSoPartitionComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
selectedPartition: any = null;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
|
|
@ -24,32 +27,32 @@ export class BootSoPartitionComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'diskNumber',
|
||||
header: 'Disco',
|
||||
header: 'labelDisk',
|
||||
cell: (partition: any) => partition.diskNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Particion',
|
||||
header: 'partition',
|
||||
cell: (partition: any) => partition.partitionNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'size',
|
||||
header: 'Tamaño',
|
||||
header: 'labelDiskSize',
|
||||
cell: (partition: any) => `${partition.size} MB`
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionCode',
|
||||
header: 'Tipo de partición',
|
||||
header: 'partitionType',
|
||||
cell: (partition: any) => partition.partitionCode
|
||||
},
|
||||
{
|
||||
columnDef: 'filesystem',
|
||||
header: 'Sistema de ficheros',
|
||||
header: 'fileSystem',
|
||||
cell: (partition: any) => partition.filesystem
|
||||
},
|
||||
{
|
||||
columnDef: 'operativeSystem',
|
||||
header: 'SO',
|
||||
header: 'sW',
|
||||
cell: (partition: any) => partition.operativeSystem?.name
|
||||
}
|
||||
];
|
||||
|
|
@ -92,7 +95,7 @@ export class BootSoPartitionComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar los datos del cliente:', error);
|
||||
console.error(this.translate.instant('errorLoadingData1'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -133,7 +136,7 @@ export class BootSoPartitionComponent implements OnInit {
|
|||
partition: this.selectedPartition['@id']
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Cliente actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('clientUpdatedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
this.loading = false;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Router } from "@angular/router";
|
||||
|
|
@ -15,6 +17,7 @@ import {SoftwareProfilePartitionComponent} from "./software-profile-partition/so
|
|||
styleUrls: ['./execute-command.component.css']
|
||||
})
|
||||
export class ExecuteCommandComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
@Input() runScriptContext: any = null;
|
||||
@Input() clientState: string = 'off';
|
||||
@Input() clientData: any[] = [];
|
||||
|
|
@ -197,7 +200,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
clients: this.clientData.map((client: any) => client['@id'])
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Cliente actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('clientUpdatedSuccessfully'));
|
||||
},
|
||||
error => {
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
|
||||
|
|
@ -210,7 +213,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
clients: this.clientData.map((client: any) => client['@id'])
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Petición de refresco enviada correctamente');
|
||||
this.toastService.success(this.translate.instant('refreshmentRequestSentCorrectly'));
|
||||
},
|
||||
error => {
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
|
||||
|
|
@ -237,7 +240,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Petición de arranque de SO enviada correctamente');
|
||||
this.toastService.success(this.translate.instant('oSBootRequest'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -261,14 +264,14 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Petición de borrado de caché de imagen enviada correctamente');
|
||||
this.toastService.success(this.translate.instant('cacheClearRequest'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hardwareInventory(): void {
|
||||
if (this.clientData.length === 0) {
|
||||
this.toastService.error('No hay clientes seleccionados');
|
||||
this.toastService.error(this.translate.instant('noClientsSelected'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +281,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
clients: this.clientData.map((client: any) => client['@id'])
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Inventario de hardware actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('hardwareInventorySuccessfullyUpdated'));
|
||||
},
|
||||
error => {
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
|
||||
|
|
@ -288,7 +291,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
|
||||
softwareInventory(): void {
|
||||
if (this.clientData.length === 0) {
|
||||
this.toastService.error('No hay clientes seleccionados');
|
||||
this.toastService.error(this.translate.instant('noClientsSelected'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +323,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
clients: this.clientData.map((client: any) => client['@id'])
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Petición de encendido enviada correctamente');
|
||||
this.toastService.success(this.translate.instant('ignitionRequestSentCorrectly'));
|
||||
},
|
||||
error => {
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
|
||||
|
|
@ -333,7 +336,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
clients: this.clientData.map((client: any) => client['@id'])
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Petición de apagado enviada correctamente');
|
||||
this.toastService.success(this.translate.instant('shutdownRequestSentCorrectly'));
|
||||
},
|
||||
error => {
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error de conexión con el cliente');
|
||||
|
|
@ -404,7 +407,7 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
|
||||
deleteClientLease(): void {
|
||||
if (this.clientData.length === 0) {
|
||||
this.toastService.error('No hay clientes seleccionados');
|
||||
this.toastService.error(this.translate.instant('noClientsSelected'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -415,11 +418,11 @@ export class ExecuteCommandComponent implements OnInit {
|
|||
Promise.allSettled(requests).then(results => {
|
||||
const errors = results.filter(r => r.status === 'rejected');
|
||||
if (errors.length === 0) {
|
||||
this.toastService.success('Lease(s) DHCP eliminada(s) correctamente');
|
||||
this.toastService.success(this.translate.instant('dhcpLeasesRemovedSuccessfully'));
|
||||
} else if (errors.length < results.length) {
|
||||
this.toastService.warning(`${results.length - errors.length} lease(s) eliminada(s), ${errors.length} con error`);
|
||||
} else {
|
||||
this.toastService.error('Error al eliminar las leases DHCP');
|
||||
this.toastService.error(this.translate.instant('errorWhenDeletingLeases'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<h2 mat-dialog-title> Seleccionar imagen para eliminar de la cache</h2>
|
||||
<h2 mat-dialog-title> {{ 'selectImageToDeleteFromCache' | translate }}</h2>
|
||||
|
||||
<mat-dialog-content class="dialog-content">
|
||||
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
||||
|
|
@ -6,10 +6,9 @@
|
|||
<div *ngIf="!loading" class="select-container">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Clientes </mat-panel-title>
|
||||
<mat-panel-title> {{ 'labelClients' | translate }}</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Listado de clientes para arrancar un SO
|
||||
<mat-icon>desktop_windows</mat-icon>
|
||||
{{ 'clientListBootOs' | translate }}<mat-icon>desktop_windows</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
|
|
@ -42,8 +41,7 @@
|
|||
color="primary"
|
||||
[disabled]="!client.selected"
|
||||
(click)="$event.stopPropagation()">
|
||||
Modelo
|
||||
</mat-radio-button>
|
||||
{{ 'labelModel' | translate }}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -57,7 +55,7 @@
|
|||
<div *ngIf="!loading" class="partition-table-container">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">Seleccionar imagen</th>
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">{{ 'buttonSelectImage' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group
|
||||
[(ngModel)]="selectedPartition"
|
||||
|
|
@ -70,7 +68,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<ng-container *ngIf="column.columnDef !== 'size' && column.columnDef !== 'operativeSystem'">
|
||||
{{ column.cell(image) }}
|
||||
|
|
@ -100,6 +98,6 @@
|
|||
</mat-dialog-content>
|
||||
|
||||
<div mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||
<button class="submit-button" (click)="execute()" [disabled]="!selectedPartition">Ejecutar</button>
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="execute()" [disabled]="!selectedPartition">{{ 'buttonExecute' | translate }}</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, Inject } from '@angular/core';
|
||||
import {MatTableDataSource} from "@angular/material/table";
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {ConfigService} from "@services/config.service";
|
||||
|
|
@ -11,6 +13,7 @@ import {ToastrService} from "ngx-toastr";
|
|||
styleUrl: './remove-cache-image.component.css'
|
||||
})
|
||||
export class RemoveCacheImageComponent {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
selectedPartition: any = null;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
|
|
@ -24,32 +27,32 @@ export class RemoveCacheImageComponent {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'diskNumber',
|
||||
header: 'Disco',
|
||||
header: 'labelDisk',
|
||||
cell: (partition: any) => partition.diskNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Particion',
|
||||
header: 'partition',
|
||||
cell: (partition: any) => partition.partitionNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'size',
|
||||
header: 'Tamaño',
|
||||
header: 'labelDiskSize',
|
||||
cell: (partition: any) => `${partition.size} MB`
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionCode',
|
||||
header: 'Tipo de partición',
|
||||
header: 'partitionType',
|
||||
cell: (partition: any) => partition.partitionCode
|
||||
},
|
||||
{
|
||||
columnDef: 'filesystem',
|
||||
header: 'Sistema de ficheros',
|
||||
header: 'fileSystem',
|
||||
cell: (partition: any) => partition.filesystem
|
||||
},
|
||||
{
|
||||
columnDef: 'operativeSystem',
|
||||
header: 'SO',
|
||||
header: 'sW',
|
||||
cell: (partition: any) => partition.operativeSystem?.name
|
||||
}
|
||||
];
|
||||
|
|
@ -100,7 +103,7 @@ export class RemoveCacheImageComponent {
|
|||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar los datos del cliente:', error);
|
||||
console.error(this.translate.instant('errorLoadingData1'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -141,7 +144,7 @@ export class RemoveCacheImageComponent {
|
|||
partition: this.selectedPartition['@id']
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Cliente actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('clientUpdatedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
this.loading = false;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<h2 mat-dialog-title> Seleccionar partición para inventariar</h2>
|
||||
<h2 mat-dialog-title> {{ 'selectPartitionToInventory' | translate }}</h2>
|
||||
|
||||
<mat-dialog-content class="dialog-content">
|
||||
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<div *ngIf="!loading" class="partition-table-container">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">Seleccionar imagen</th>
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">{{ 'buttonSelectImage' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group
|
||||
[(ngModel)]="selectedPartition"
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<ng-container *ngIf="column.columnDef !== 'size' && column.columnDef !== 'operativeSystem'">
|
||||
{{ column.cell(image) }}
|
||||
|
|
@ -50,6 +50,6 @@
|
|||
</mat-dialog-content>
|
||||
|
||||
<div mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||
<button class="submit-button" (click)="execute()" [disabled]="!selectedPartition">Ejecutar</button>
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="execute()" [disabled]="!selectedPartition">{{ 'buttonExecute' | translate }}</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
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";
|
||||
|
|
@ -11,6 +13,7 @@ import {ToastrService} from "ngx-toastr";
|
|||
styleUrl: './software-profile-partition.component.css'
|
||||
})
|
||||
export class SoftwareProfilePartitionComponent implements OnInit{
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
selectedPartition: any = null;
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
|
|
@ -24,32 +27,32 @@ export class SoftwareProfilePartitionComponent implements OnInit{
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'diskNumber',
|
||||
header: 'Disco',
|
||||
header: 'labelDisk',
|
||||
cell: (partition: any) => partition.diskNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Particion',
|
||||
header: 'partition',
|
||||
cell: (partition: any) => partition.partitionNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'size',
|
||||
header: 'Tamaño',
|
||||
header: 'labelDiskSize',
|
||||
cell: (partition: any) => `${partition.size} MB`
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionCode',
|
||||
header: 'Tipo de partición',
|
||||
header: 'partitionType',
|
||||
cell: (partition: any) => partition.partitionCode
|
||||
},
|
||||
{
|
||||
columnDef: 'filesystem',
|
||||
header: 'Sistema de ficheros',
|
||||
header: 'fileSystem',
|
||||
cell: (partition: any) => partition.filesystem
|
||||
},
|
||||
{
|
||||
columnDef: 'operativeSystem',
|
||||
header: 'SO',
|
||||
header: 'sW',
|
||||
cell: (partition: any) => partition.operativeSystem?.name
|
||||
}
|
||||
];
|
||||
|
|
@ -80,7 +83,7 @@ export class SoftwareProfilePartitionComponent implements OnInit{
|
|||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar los datos del cliente:', error);
|
||||
console.error(this.translate.instant('errorLoadingData1'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -96,7 +99,7 @@ export class SoftwareProfilePartitionComponent implements OnInit{
|
|||
partition: this.selectedPartition['@id'],
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Inventario de software actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('successfullyUpdatedSoftwareInventory'));
|
||||
this.dialogRef.close(response);
|
||||
},
|
||||
error => {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
</div>
|
||||
<div class="welcome-text">
|
||||
<h1 class="welcome-title">{{ 'GlobalStatus' | translate }}</h1>
|
||||
<p class="welcome-subtitle">Bienvenido a la consola de administración de OpenGnsys</p>
|
||||
<p class="welcome-description">Estado general de todos los componentes de la plataforma</p>
|
||||
<p class="welcome-subtitle">{{ 'welcomeTitle' | translate }}</p>
|
||||
<p class="welcome-description">{{ 'generalPlatformStatus' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="welcome-actions">
|
||||
<button mat-icon-button class="refresh-button" (click)="refreshAll()" matTooltip="Actualizar datos">
|
||||
<button mat-icon-button class="refresh-button" (click)="refreshAll()" [matTooltip]="'buttonUpdateData' | translate">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<div class="spinner-container">
|
||||
<div class="loading-content">
|
||||
<mat-spinner class="loading-spinner"></mat-spinner>
|
||||
<p class="loading-text">Cargando estado del sistema...</p>
|
||||
<p class="loading-text">{{ 'loadingSystemStatus' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -35,8 +35,8 @@
|
|||
<mat-icon>cloud</mat-icon>
|
||||
</div>
|
||||
<div class="overview-content">
|
||||
<h3>Repositorios</h3>
|
||||
<p>Total: <span class="status-badge info">{{ repositories.length }}</span></p>
|
||||
<h3>{{ 'labelRepository' | translate }}</h3>
|
||||
<p>{{ 'labelTotalColon' | translate }}<span class="status-badge info">{{ repositories.length }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -46,8 +46,8 @@
|
|||
<mat-icon>storage</mat-icon>
|
||||
</div>
|
||||
<div class="overview-content">
|
||||
<h3>Servidores OgBoot</h3>
|
||||
<p>Total: <span class="status-badge info">{{ bootServers.length }}</span></p>
|
||||
<h3>{{ 'ogbootServers' | translate }}</h3>
|
||||
<p>{{ 'labelTotalColon' | translate }}<span class="status-badge info">{{ bootServers.length }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -57,8 +57,8 @@
|
|||
<mat-icon>router</mat-icon>
|
||||
</div>
|
||||
<div class="overview-content">
|
||||
<h3>Servidores DHCP</h3>
|
||||
<p>Total: <span class="status-badge info">{{ dhcps.length }}</span></p>
|
||||
<h3>{{ 'dhcpServers' | translate }}</h3>
|
||||
<p>{{ 'labelTotalColon' | translate }}<span class="status-badge info">{{ dhcps.length }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -68,8 +68,8 @@
|
|||
<mat-icon>dns</mat-icon>
|
||||
</div>
|
||||
<div class="overview-content">
|
||||
<h3>OgCore Server</h3>
|
||||
<p>Logs del servidor</p>
|
||||
<h3>{{ 'ogCoreServer' | translate }}</h3>
|
||||
<p>{{ 'serverLogs' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -102,10 +102,9 @@
|
|||
<div class="action-buttons">
|
||||
<button mat-button class="secondary-button" (click)="refreshAll()">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
Actualizar
|
||||
</button>
|
||||
{{ 'buttonUpdate' | translate }}</button>
|
||||
<button mat-raised-button color="primary" [mat-dialog-close]="true">
|
||||
{{ 'closeButton' | translate }}
|
||||
{{ 'buttonClose' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</mat-dialog-actions>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
|
|
@ -9,6 +11,7 @@ import { ToastrService } from "ngx-toastr";
|
|||
styleUrl: './global-status.component.css'
|
||||
})
|
||||
export class GlobalStatusComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
loading: boolean = false;
|
||||
loadingDhcps: boolean = false;
|
||||
|
|
@ -81,7 +84,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (!hasError) {
|
||||
this.toastService.error('Error al sincronizar las subredes: tiempo de espera agotado');
|
||||
this.toastService.error(this.translate.instant('errorSyncingSubnets'));
|
||||
hasError = true;
|
||||
}
|
||||
}, 5000);
|
||||
|
|
@ -92,7 +95,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
pending--;
|
||||
if (pending === 0 && !hasError) {
|
||||
clearTimeout(timeoutId);
|
||||
this.toastService.success('Sincronización de subredes de servidores DHCP exitosa');
|
||||
this.toastService.success(this.translate.instant('serverSubnetSynchronization'));
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
|
|
@ -106,7 +109,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
});
|
||||
});
|
||||
}, error => {
|
||||
console.error('Error fetching DHCP servers for subnet sync', error);
|
||||
console.error(this.translate.instant('errorFetchingDhcpServersFor'), error);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +121,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (!hasError) {
|
||||
this.toastService.error('Error al sincronizar las plantillas Pxe: tiempo de espera agotado');
|
||||
this.toastService.error(this.translate.instant('errorSyncingTemplates'));
|
||||
hasError = true;
|
||||
}
|
||||
}, 5000);
|
||||
|
|
@ -129,7 +132,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
pending--;
|
||||
if (pending === 0 && !hasError) {
|
||||
clearTimeout(timeoutId);
|
||||
this.toastService.success('Sincronización de plantillas Pxe exitosa');
|
||||
this.toastService.success(this.translate.instant('successfulPxeTemplateSynchronization'));
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
|
|
@ -152,7 +155,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (!hasError) {
|
||||
this.toastService.error('Error al sincronizar imagenes ogLive: tiempo de espera agotado');
|
||||
this.toastService.error(this.translate.instant('errorWhenSynchronizingOgliveImages'));
|
||||
hasError = true;
|
||||
}
|
||||
}, 5000);
|
||||
|
|
@ -163,7 +166,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
pending--;
|
||||
if (pending === 0 && !hasError) {
|
||||
clearTimeout(timeoutId);
|
||||
this.toastService.success('Sincronización con ogLives completada');
|
||||
this.toastService.success(this.translate.instant('synchronizationWithOglivesCompleted'));
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
|
|
@ -190,7 +193,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
this.repositories = [];
|
||||
if (showLoading) this.loadingRepositories = false;
|
||||
this.checkOverallLoading();
|
||||
this.toastService.error('Error al cargar la lista de repositorios');
|
||||
this.toastService.error(this.translate.instant('errorLoadingList2'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -213,7 +216,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
this.bootServers = [];
|
||||
if (showLoading) this.loadingBootServers = false;
|
||||
this.checkOverallLoading();
|
||||
this.toastService.error('Error al cargar la lista de Servidores de Boot');
|
||||
this.toastService.error(this.translate.instant('errorLoadingList1'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -230,7 +233,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
this.dhcps = [];
|
||||
if (showLoading) this.loadingDhcps = false;
|
||||
this.checkOverallLoading();
|
||||
this.toastService.error('Error al cargar la lista de Dhcps');
|
||||
this.toastService.error(this.translate.instant('errorLoadingList'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -250,7 +253,7 @@ export class GlobalStatusComponent implements OnInit {
|
|||
this.loadDhcps(true);
|
||||
this.loadRepositories(true);
|
||||
this.syncSubnets();
|
||||
this.toastService.success('Datos actualizados correctamente');
|
||||
this.toastService.success(this.translate.instant('dataUpdatedCorrectly'));
|
||||
}
|
||||
|
||||
updateLastUpdateTime(): void {
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
@if(bootServers.length === 0) {
|
||||
<div class="no-repositories">
|
||||
<mat-icon class="no-data-icon">cloud_off</mat-icon>
|
||||
<h3>No hay servidores de boot disponibles</h3>
|
||||
<p>No se encontraron servidores OgBoot configurados en el sistema.</p>
|
||||
<h3>{{ 'noBootServersAvailable' | translate }}</h3>
|
||||
<p>{{ 'noConfiguredBootServers' | translate }}</p>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="repositories-selector-container">
|
||||
} @else {<div class="repositories-selector-container">
|
||||
<div class="repository-selector">
|
||||
<mat-form-field appearance="outline" class="repository-select-field">
|
||||
<mat-label>Seleccionar servidor OgBoot</mat-label>
|
||||
<mat-label>{{ 'selectOgBootServer' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedBootServerUuid" (selectionChange)="onBootServerChange($event.value)">
|
||||
@for(server of bootServers; track server.uuid) {
|
||||
<mat-option [value]="server.uuid">
|
||||
|
|
@ -29,7 +28,7 @@
|
|||
<h2>{{ getSelectedBootServerName() }}</h2>
|
||||
<button class="logs-button" (click)="scrollToLogs()">
|
||||
<mat-icon>article</mat-icon>
|
||||
<span>Ver logs</span>
|
||||
<span>{{ 'buttonViewLogs' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -45,8 +44,8 @@
|
|||
|
||||
<div class="logs-section" id="ogboot-logs-section">
|
||||
<div class="logs-header">
|
||||
<h3>Logs de OgBoot</h3>
|
||||
<p>Logs en tiempo real del servidor OgBoot seleccionado</p>
|
||||
<h3>{{ 'ogbootLogs' | translate }}</h3>
|
||||
<p>{{ 'realTimeOgbootLogs' | translate }}</p>
|
||||
</div>
|
||||
<div class="logs-container">
|
||||
<iframe [src]="getBootServerIframeUrl()" width="100%" height="800" frameborder="0" class="ogboot-logs-iframe">
|
||||
|
|
@ -59,8 +58,8 @@
|
|||
@if(!selectedBootServerUuid) {
|
||||
<div class="no-repository-selected">
|
||||
<mat-icon class="no-data-icon">storage</mat-icon>
|
||||
<h3>Selecciona un servidor de boot</h3>
|
||||
<p>Elige un servidor de boot de la lista para ver su estado detallado.</p>
|
||||
<h3>{{ 'selectABootServer' | translate }}</h3>
|
||||
<p>{{ 'selectBootServerToView' | translate }}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -68,12 +67,11 @@
|
|||
<div class="error-container">
|
||||
<div class="error-card">
|
||||
<mat-icon class="error-icon">error_outline</mat-icon>
|
||||
<h3>Error de conexión</h3>
|
||||
<p>No se pudo conectar con el servidor OgBoot seleccionado</p>
|
||||
<h3>{{ 'connectionError' | translate }}</h3>
|
||||
<p>{{ 'cannotConnectBootServer' | translate }}</p>
|
||||
<button mat-raised-button color="primary" (click)="retryBootServerStatus(selectedBootServerUuid)">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
Reintentar
|
||||
</button>
|
||||
{{ 'buttonRetry' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
|
|
@ -10,6 +12,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
|||
styleUrl: './ogboot-status.component.css'
|
||||
})
|
||||
export class GlobalOgbootStatusComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
loadingBootServers: boolean = false;
|
||||
|
||||
|
|
@ -117,9 +120,9 @@ export class GlobalOgbootStatusComponent implements OnInit {
|
|||
this.loadBootServerStatus(bootServerUuid, (errorOccurred: boolean) => {
|
||||
this.errorBootServers[bootServerUuid] = errorOccurred;
|
||||
if (!errorOccurred) {
|
||||
this.toastService.success('Estado del servidor de boot actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('bootServerStatus'));
|
||||
} else {
|
||||
this.toastService.error('Error al cargar el estado del servidor de boot');
|
||||
this.toastService.error(this.translate.instant('errorLoadingState2'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<div class="section-content">
|
||||
<div class="tab-content">
|
||||
<div class="section-header">
|
||||
<h2>OgCore Server</h2>
|
||||
<h2>{{ 'ogCoreServer' | translate }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="logs-section" id="ogcore-logs-section">
|
||||
<div class="logs-header">
|
||||
<h3>Logs de OgCore</h3>
|
||||
<p>Logs en tiempo real del servidor OgCore</p>
|
||||
<h3>{{ 'ogcoreLogs' | translate }}</h3>
|
||||
<p>{{ 'realTimeOgcoreLogs' | translate }}</p>
|
||||
</div>
|
||||
<div class="logs-container">
|
||||
<iframe [src]="getOgCoreIframeUrl()" width="100%" height="800" frameborder="0" class="ogcore-logs-iframe">
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
@if(dhcps.length === 0) {
|
||||
<div class="no-repositories">
|
||||
<mat-icon class="no-data-icon">cloud_off</mat-icon>
|
||||
<h3>No hay dhcps disponibles</h3>
|
||||
<p>No se encontraron dhcps configurados en el sistema.</p>
|
||||
<h3>{{ 'noDhcpsAvailable' | translate }}</h3>
|
||||
<p>{{ 'noConfiguredDhcps' | translate }}</p>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="repositories-selector-container">
|
||||
} @else {<div class="repositories-selector-container">
|
||||
<div class="repository-selector">
|
||||
<mat-form-field appearance="outline" class="repository-select-field">
|
||||
<mat-label>Seleccionar dhcp</mat-label>
|
||||
<mat-label>{{ 'buttonSelectDhcp' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedDhcpUuid" (selectionChange)="onDhcpChange($event.value)">
|
||||
@for(dhcp of dhcps; track dhcp.uuid) {
|
||||
<mat-option [value]="dhcp.uuid">
|
||||
|
|
@ -29,7 +28,7 @@
|
|||
<h2>{{ getSelectedDhcpName() }}</h2>
|
||||
<button class="logs-button" (click)="scrollToLogs()">
|
||||
<mat-icon>article</mat-icon>
|
||||
<span>Ver logs</span>
|
||||
<span>{{ 'buttonViewLogs' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -45,8 +44,8 @@
|
|||
|
||||
<div class="logs-section" id="dhcp-logs-section">
|
||||
<div class="logs-header">
|
||||
<h3>Logs de DHCP</h3>
|
||||
<p>Logs en tiempo real del servidor DHCP</p>
|
||||
<h3>{{ 'dhcpLogs' | translate }}</h3>
|
||||
<p>{{ 'realTimeDhcpLogs' | translate }}</p>
|
||||
</div>
|
||||
<div class="logs-container">
|
||||
<iframe [src]="getDhcpIframeUrl()" width="100%" height="800" frameborder="0" class="dhcp-logs-iframe">
|
||||
|
|
@ -59,8 +58,8 @@
|
|||
@if(!selectedDhcpUuid) {
|
||||
<div class="no-repository-selected">
|
||||
<mat-icon class="no-data-icon">storage</mat-icon>
|
||||
<h3>Selecciona un dhcp</h3>
|
||||
<p>Elige un dhcp de la lista para ver su estado detallado.</p>
|
||||
<h3>{{ 'selectADhcp' | translate }}</h3>
|
||||
<p>{{ 'selectDhcpToView' | translate }}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -68,12 +67,11 @@
|
|||
<div class="error-container">
|
||||
<div class="error-card">
|
||||
<mat-icon class="error-icon">error_outline</mat-icon>
|
||||
<h3>Error de conexión</h3>
|
||||
<p>No se pudo conectar con el dhcp seleccionado</p>
|
||||
<h3>{{ 'connectionError' | translate }}</h3>
|
||||
<p>{{ 'cannotConnectDhcp' | translate }}</p>
|
||||
<button mat-raised-button color="primary" (click)="retryDhcpStatus(selectedDhcpUuid)">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
Reintentar
|
||||
</button>
|
||||
{{ 'buttonRetry' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
|
|
@ -10,6 +12,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
|||
styleUrl: './ogdhcp-status.component.css'
|
||||
})
|
||||
export class OgdhcpStatusComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
loadingDhcps: boolean = false;
|
||||
|
||||
|
|
@ -120,9 +123,9 @@ export class OgdhcpStatusComponent implements OnInit {
|
|||
this.loadDhcpStatus(dhcpUuid, (errorOccurred: boolean) => {
|
||||
this.errorDhcps[dhcpUuid] = errorOccurred;
|
||||
if (!errorOccurred) {
|
||||
this.toastService.success('Estado del dhcp actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('dhcpStatusUpdatedSuccessfully'));
|
||||
} else {
|
||||
this.toastService.error('Error al cargar el estado del dhcp');
|
||||
this.toastService.error(this.translate.instant('errorLoadingState'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
@if(repositories.length === 0) {
|
||||
<div class="no-repositories">
|
||||
<mat-icon class="no-data-icon">cloud_off</mat-icon>
|
||||
<h3>No hay repositorios disponibles</h3>
|
||||
<p>No se encontraron repositorios configurados en el sistema.</p>
|
||||
<h3>{{ 'noReposAvailable' | translate }}</h3>
|
||||
<p>{{ 'noConfiguredRepos' | translate }}</p>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="repositories-selector-container">
|
||||
} @else {<div class="repositories-selector-container">
|
||||
<div class="repository-selector">
|
||||
<mat-form-field appearance="outline" class="repository-select-field">
|
||||
<mat-label>Seleccionar repositorio</mat-label>
|
||||
<mat-label>{{ 'selectRepository' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedRepositoryUuid" (selectionChange)="onRepositoryChange($event.value)">
|
||||
@for(repository of repositories; track repository.uuid) {
|
||||
<mat-option [value]="repository.uuid">
|
||||
|
|
@ -29,7 +28,7 @@
|
|||
<h2>{{ getSelectedRepositoryName() }}</h2>
|
||||
<button class="logs-button" (click)="scrollToLogs()">
|
||||
<mat-icon>article</mat-icon>
|
||||
<span>Ver logs</span>
|
||||
<span>{{ 'buttonViewLogs' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -53,7 +52,7 @@
|
|||
<div class="repository-logs-section" id="repository-logs-section">
|
||||
<div class="logs-header">
|
||||
<h3>Datos del repositorio: {{ getSelectedRepositoryName() }}</h3>
|
||||
<p>Información específica del repositorio seleccionado</p>
|
||||
<p>{{ 'specificRepoInfo' | translate }}</p>
|
||||
</div>
|
||||
<div class="logs-container">
|
||||
<iframe [src]="getRepositoryIframeUrl()" width="100%" height="600" frameborder="0"
|
||||
|
|
@ -67,8 +66,8 @@
|
|||
@if(!selectedRepositoryUuid) {
|
||||
<div class="no-repository-selected">
|
||||
<mat-icon class="no-data-icon">storage</mat-icon>
|
||||
<h3>Selecciona un repositorio</h3>
|
||||
<p>Elige un repositorio de la lista para ver su estado detallado.</p>
|
||||
<h3>{{ 'selectARepository' | translate }}</h3>
|
||||
<p>{{ 'selectRepoToView' | translate }}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -76,12 +75,11 @@
|
|||
<div class="error-container">
|
||||
<div class="error-card">
|
||||
<mat-icon class="error-icon">error_outline</mat-icon>
|
||||
<h3>Error de conexión</h3>
|
||||
<p>No se pudo conectar con el repositorio seleccionado</p>
|
||||
<h3>{{ 'connectionError' | translate }}</h3>
|
||||
<p>{{ 'cannotConnectRepo' | translate }}</p>
|
||||
<button mat-raised-button color="primary" (click)="retryRepositoryStatus(selectedRepositoryUuid)">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
Reintentar
|
||||
</button>
|
||||
{{ 'buttonRetry' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
|
|
@ -10,6 +12,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
|||
styleUrl: './ogrepository-status.component.css'
|
||||
})
|
||||
export class OgrepositoryStatusComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
loading: boolean = false;
|
||||
|
||||
|
|
@ -119,9 +122,9 @@ export class OgrepositoryStatusComponent implements OnInit {
|
|||
this.loadRepositoryStatus(repositoryUuid, (errorOccurred: boolean) => {
|
||||
this.errorRepositories[repositoryUuid] = errorOccurred;
|
||||
if (!errorOccurred) {
|
||||
this.toastService.success('Estado del repositorio actualizado correctamente');
|
||||
this.toastService.success(this.translate.instant('successfullyUpdatedRepositoryStatus'));
|
||||
} else {
|
||||
this.toastService.error('Error al cargar el estado del repositorio');
|
||||
this.toastService.error(this.translate.instant('errorLoadingState1'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,19 +17,19 @@
|
|||
</div>
|
||||
<div class="resource-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'totalLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelDiskTotal' | translate }}:</span>
|
||||
<span class="info-value">{{ isRepository ? diskUsage.total : formatBytes(diskUsage.total) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'usedLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelDiskUsed' | translate }}:</span>
|
||||
<span class="info-value">{{ isRepository ? diskUsage.used : formatBytes(diskUsage.used) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'availableLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelAvailable' | translate }}:</span>
|
||||
<span class="info-value">{{ isRepository ? diskUsage.available : formatBytes(diskUsage.available) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'usedPercentageLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelDiskUsed' | translate }}:</span>
|
||||
<span class="info-value usage-percentage">{{ isRepository ? diskUsage.used_percentage : diskUsage.percentage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -51,19 +51,19 @@
|
|||
</div>
|
||||
<div class="resource-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'totalLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelDiskTotal' | translate }}:</span>
|
||||
<span class="info-value">{{ ramUsage.total }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'usedLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelDiskUsed' | translate }}:</span>
|
||||
<span class="info-value">{{ ramUsage.used }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'availableLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelAvailable' | translate }}:</span>
|
||||
<span class="info-value">{{ ramUsage.available }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ 'usedPercentageLabel' | translate }}:</span>
|
||||
<span class="info-label">{{ 'labelDiskUsed' | translate }}:</span>
|
||||
<span class="info-value usage-percentage">{{ ramUsage.used_percentage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
<div class="cpu-usage-display">
|
||||
<div class="cpu-circle">
|
||||
<div class="cpu-percentage">{{ cpuUsage.used_percentage }}</div>
|
||||
<div class="cpu-label">Uso actual</div>
|
||||
<div class="cpu-label">{{ 'currentUsage' | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
<div class="service-icon">
|
||||
<mat-icon>settings</mat-icon>
|
||||
</div>
|
||||
<h3 class="service-title">{{ 'servicesTitle' | translate }}</h3>
|
||||
<h3 class="service-title">{{ 'labelServices' | translate }}</h3>
|
||||
</div>
|
||||
<div class="service-list">
|
||||
<div class="service-item" *ngFor="let service of getServices()">
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
<div class="service-icon">
|
||||
<mat-icon>list_alt</mat-icon>
|
||||
</div>
|
||||
<h3 class="service-title">{{ 'processes' | translate }}</h3>
|
||||
<h3 class="service-title">{{ 'labelProcesses' | translate }}</h3>
|
||||
</div>
|
||||
<div class="service-list">
|
||||
<div class="service-item" *ngFor="let process of getProcesses()">
|
||||
|
|
@ -144,10 +144,10 @@
|
|||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'idLabel' | translate }}</th>
|
||||
<th>{{ 'labelId' | translate }}</th>
|
||||
<th>{{ 'kernelLabel' | translate }}</th>
|
||||
<th>{{ 'architectureLabel' | translate }}</th>
|
||||
<th>{{ 'revisionLabel' | translate }}</th>
|
||||
<th>{{ 'labelArchitecture' | translate }}</th>
|
||||
<th>{{ 'labelRevision' | translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -173,11 +173,11 @@
|
|||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'idLabel' | translate }}</th>
|
||||
<th>{{ 'bootFileNameLabel' | translate }}</th>
|
||||
<th>{{ 'nextServerLabel' | translate }}</th>
|
||||
<th>{{ 'ipLabel' | translate }}</th>
|
||||
<th>{{ 'clientsLabel' | translate }}</th>
|
||||
<th>{{ 'labelId' | translate }}</th>
|
||||
<th>{{ 'labelBootFileName' | translate }}</th>
|
||||
<th>{{ 'labelNextServer' | translate }}</th>
|
||||
<th>{{ 'labelIp' | translate }}</th>
|
||||
<th>{{ 'labelClients' | translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="table-header-container">
|
||||
<h2 class="title" i18n="@@adminImagesTitle">Discos/Particiones</h2>
|
||||
<h2 class="title" i18n="@@adminImagesTitle">{{ 'labelDisksPartitions' | translate }}</h2>
|
||||
<mat-chip *ngIf="clientData.firmwareType" class="firmware-chip">
|
||||
<mat-icon>memory</mat-icon>
|
||||
{{ clientData.firmwareType }}
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
<div class="table-container">
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<ng-container *ngIf="column.columnDef !== 'size'">
|
||||
{{ column.cell(image) }}
|
||||
|
|
|
|||
|
|
@ -14,21 +14,20 @@
|
|||
<div class="destination-badge">
|
||||
<mat-icon class="destination-icon">cloud_upload</mat-icon>
|
||||
<div class="destination-content">
|
||||
<span class="destination-label">Destino</span>
|
||||
<span class="destination-label">{{ 'labelDestination' | translate }}</span>
|
||||
<span class="destination-value">{{ selectedRepository?.name || 'No hay repositorio asociado' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" id="execute-button" [disabled]="!selectedPartition || loading" (click)="save()">Ejecutar</button>
|
||||
<button class="action-button" id="execute-button" [disabled]="!selectedPartition || loading" (click)="save()">{{ 'buttonExecute' | translate }}</button>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" color="accent"
|
||||
[disabled]="!isFormValid()"
|
||||
(click)="openScheduleModal()">
|
||||
Opciones de programación
|
||||
</button>
|
||||
{{ 'schedulingOptions' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -37,13 +36,12 @@
|
|||
<div class="form-section compact-section type-section">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>settings</mat-icon>
|
||||
Tipo de imagen
|
||||
</div>
|
||||
{{ 'imageType' | translate }}</div>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Tipo de imagen</mat-label>
|
||||
<mat-label>{{ 'imageType' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="imageType" class="full-width" (selectionChange)="onImageTypeSelected($event.value)">
|
||||
<mat-option [value]="'monolithic'">Monolítica</mat-option>
|
||||
<mat-option [value]="'git'">Git</mat-option>
|
||||
<mat-option [value]="'monolithic'">{{ 'labelMonolithic' | translate }}</mat-option>
|
||||
<mat-option [value]="'git'">{{ 'labelGit' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -51,40 +49,39 @@
|
|||
<div class="form-section compact-section config-section" *ngIf="imageType === 'monolithic'">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>image</mat-icon>
|
||||
Configuración
|
||||
</div>
|
||||
{{ 'configurationTitle' | translate }}</div>
|
||||
|
||||
<div class="action-chips-container">
|
||||
<mat-chip-listbox [(ngModel)]="monolithicAction" required class="action-chip-listbox">
|
||||
<mat-chip-option value="create" class="action-chip create-chip firmware-chip" (click)="onMonolithicActionSelected({value: 'create'})">
|
||||
<span>Crear imagen</span>
|
||||
<span>{{ 'buttonCreateImage' | translate }}</span>
|
||||
</mat-chip-option>
|
||||
<mat-chip-option value="update" class="action-chip update-chip firmware-chip" (click)="onMonolithicActionSelected({value: 'update'})">
|
||||
<span>Actualizar imagen</span>
|
||||
<span>{{ 'buttonUpdateImage' | translate }}</span>
|
||||
</mat-chip-option>
|
||||
</mat-chip-listbox>
|
||||
</div>
|
||||
|
||||
<div *ngIf="monolithicAction === 'create'">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Nombre canónico</mat-label>
|
||||
<input matInput [(ngModel)]="name" placeholder="Nombre canónico. En minúscula y sin espacios" required>
|
||||
<mat-hint>Nombre para la nueva imagen</mat-hint>
|
||||
<mat-label>{{ 'canonicalName' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="name" [placeholder]="'canonicalNameFormatHint' | translate" required>
|
||||
<mat-hint>{{ 'labelNewImageName' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div *ngIf="monolithicAction === 'update'">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Seleccione imagen</mat-label>
|
||||
<mat-label>{{ 'selectImagePrompt' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedImage" name="selectedImage" (selectionChange)="resetCanonicalName()" required>
|
||||
<mat-option [value]="null">Seleccionar imagen para actualizar</mat-option>
|
||||
<mat-option [value]="null">{{ 'selectImageToUpdate' | translate }}</mat-option>
|
||||
<mat-option *ngFor="let image of images" [value]="image">{{ image?.name }}</mat-option>
|
||||
</mat-select>
|
||||
<button *ngIf="selectedImage" mat-icon-button matSuffix aria-label="Clear client search"
|
||||
<button *ngIf="selectedImage" mat-icon-button matSuffix [attr.aria-label]="'clearClientSearch' | translate"
|
||||
(click)="selectedImage = null; resetCanonicalName()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<mat-hint>Selecciona la imagen existente que quieres actualizar.</mat-hint>
|
||||
<mat-hint>{{ 'selectImageToUpdateHint' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -92,14 +89,13 @@
|
|||
<div class="form-section compact-section config-section" *ngIf="imageType === 'git'">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>code</mat-icon>
|
||||
Configuración Git
|
||||
</div>
|
||||
{{ 'gitConfiguration' | translate }}</div>
|
||||
|
||||
<div class="git-info-container" *ngIf="selectedPartition && imageType === 'git' && (hasValidGitData || loadingGitData)">
|
||||
<div class="git-info-card">
|
||||
<div class="git-info-header">
|
||||
<mat-icon class="git-info-icon">info</mat-icon>
|
||||
<span class="git-info-title">La imagen en caché a actualizar es:</span>
|
||||
<span class="git-info-title">{{ 'cacheImageToUpdateIs' | translate }}</span>
|
||||
<mat-spinner *ngIf="loadingGitData" diameter="20" class="git-loading-spinner"></mat-spinner>
|
||||
</div>
|
||||
<div *ngIf="!loadingGitData && hasValidGitData">
|
||||
|
|
@ -108,8 +104,7 @@
|
|||
<mat-form-field appearance="outline" class="git-form-field">
|
||||
<mat-label>
|
||||
<mat-icon class="git-item-icon">folder</mat-icon>
|
||||
Repositorio
|
||||
</mat-label>
|
||||
{{ 'labelRepository' | translate }}</mat-label>
|
||||
<input matInput [value]="gitData.repo" readonly>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -117,8 +112,7 @@
|
|||
<mat-form-field appearance="outline" class="git-form-field">
|
||||
<mat-label>
|
||||
<mat-icon class="git-item-icon">account_tree</mat-icon>
|
||||
Rama origen
|
||||
</mat-label>
|
||||
{{ 'sourceBranch' | translate }}</mat-label>
|
||||
<input matInput [value]="gitData.branch" readonly>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -126,12 +120,11 @@
|
|||
<mat-form-field appearance="outline" class="git-form-field">
|
||||
<mat-label>
|
||||
<mat-icon class="git-item-icon">call_split</mat-icon>
|
||||
Rama destino
|
||||
</mat-label>
|
||||
{{ 'destinationBranch' | translate }}</mat-label>
|
||||
<input matInput
|
||||
[(ngModel)]="destinationBranch"
|
||||
[readonly]="!isDestinationBranchEditable"
|
||||
placeholder="Nombre de la rama destino"
|
||||
[placeholder]="'destinationBranchNameLabel' | translate"
|
||||
[matTooltip]="isDestinationBranchEditable ? 'Guardar cambios' : 'Editar nombre de la rama destino'">
|
||||
<button mat-icon-button
|
||||
matSuffix
|
||||
|
|
@ -146,7 +139,7 @@
|
|||
<div class="repository-warning" *ngIf="repositoryNotFound">
|
||||
<mat-icon class="warning-icon">warning</mat-icon>
|
||||
<div class="warning-content">
|
||||
<div class="warning-title">Repositorio no encontrado</div>
|
||||
<div class="warning-title">{{ 'repositoryNotFound' | translate }}</div>
|
||||
<div class="warning-message">
|
||||
El repositorio "{{ gitData.repo }}" no existe en el listado de repositorios disponibles.
|
||||
Es posible que necesites crearlo primero.
|
||||
|
|
@ -155,18 +148,17 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="git-info-loading" *ngIf="loadingGitData">
|
||||
<span>Cargando información de Git...</span>
|
||||
<span>{{ 'loadingGitInfo' | translate }}</span>
|
||||
</div>
|
||||
<div class="git-info-empty" *ngIf="!loadingGitData && !hasValidGitData">
|
||||
<span>No se encontró información de Git para esta partición</span>
|
||||
<span>{{ 'noGitInfoForPartition' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="force-push-container" *ngIf="imageType === 'git' && hasValidGitData">
|
||||
<mat-checkbox [(ngModel)]="forcePush" class="force-push-checkbox">
|
||||
Opción 'Forzar push'
|
||||
</mat-checkbox>
|
||||
{{ 'forcePushOption' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="repository-header" *ngIf="!hasValidGitData">
|
||||
|
|
@ -175,24 +167,22 @@
|
|||
(click)="openCreateRepositoryModal()"
|
||||
[disabled]="creatingRepository">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>Crear nuevo repositorio / SO</span>
|
||||
<span>{{ 'createNewRepoOs' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="selector" *ngIf="!hasValidGitData">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Seleccionar repositorio Git</mat-label>
|
||||
<mat-label>{{ 'selectGitRepository' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedGitRepository" (selectionChange)="onGitRepositorySelected($event.value)" required>
|
||||
<mat-option [value]="null">Seleccionar repositorio git / SO</mat-option>
|
||||
<mat-option [value]="null">{{ 'selectGitRepoOs' | translate }}</mat-option>
|
||||
<mat-option *ngFor="let repo of gitRepositories" [value]="repo">{{ repo.name }}</mat-option>
|
||||
</mat-select>
|
||||
<mat-spinner *ngIf="loadingGitRepositories" matSuffix diameter="20"></mat-spinner>
|
||||
<mat-hint>
|
||||
<mat-icon>info</mat-icon>
|
||||
Selecciona el repositorio git para obtener las imágenes disponibles.
|
||||
<span *ngIf="gitRepositories.length === 0" class="no-repositories-hint">
|
||||
No hay repositorios disponibles. Crea uno nuevo para continuar.
|
||||
</span>
|
||||
{{ 'selectGitRepoHint' | translate }}<span *ngIf="gitRepositories.length === 0" class="no-repositories-hint">
|
||||
{{ 'noReposAvailableCreateNew' | translate }}</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -202,8 +192,7 @@
|
|||
<div class="form-section" #partitionSection id="partition-selection">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>storage</mat-icon>
|
||||
Selección de partición
|
||||
</div>
|
||||
{{ 'partitionSelection' | translate }}</div>
|
||||
|
||||
<div class="partition-table-container">
|
||||
<app-disk-partition-selector
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, EventEmitter, OnInit, Output, ViewChild, ElementRef} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, EventEmitter, OnInit, Output, ViewChild, ElementRef } from '@angular/core';
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
|
@ -17,6 +19,7 @@ import {CreateTaskComponent} from "../../../../commands/commands-task/create-tas
|
|||
styleUrl: './create-image.component.css'
|
||||
})
|
||||
export class CreateClientImageComponent implements OnInit{
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
@Output() dataChange = new EventEmitter<any>();
|
||||
@ViewChild('partitionSection', { static: false }) partitionSection!: ElementRef;
|
||||
|
|
@ -69,27 +72,27 @@ export class CreateClientImageComponent implements OnInit{
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Particion',
|
||||
header: 'partition',
|
||||
cell: (partition: any) => partition.partitionNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'size',
|
||||
header: 'Tamaño',
|
||||
header: 'labelDiskSize',
|
||||
cell: (partition: any) => `${partition.size} MB`
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionCode',
|
||||
header: 'Tipo de partición',
|
||||
header: 'partitionType',
|
||||
cell: (partition: any) => partition.partitionCode
|
||||
},
|
||||
{
|
||||
columnDef: 'filesystem',
|
||||
header: 'Sistema de ficheros',
|
||||
header: 'fileSystem',
|
||||
cell: (partition: any) => partition.filesystem
|
||||
},
|
||||
{
|
||||
columnDef: 'operativeSystem',
|
||||
header: 'SO',
|
||||
header: 'sW',
|
||||
cell: (partition: any) => partition.operativeSystem?.name
|
||||
}
|
||||
];
|
||||
|
|
@ -139,7 +142,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar los datos del cliente:', error);
|
||||
console.error(this.translate.instant('errorLoadingData1'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -155,7 +158,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
this.images = response['hydra:member'];
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar las imágenes:', error);
|
||||
console.error(this.translate.instant('errorLoadingImages3'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -186,7 +189,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
this.checkRepositoryExists();
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar los repositorios git:', error);
|
||||
console.error(this.translate.instant('errorLoadingRepositories2'), error);
|
||||
this.loadingGitRepositories = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -201,7 +204,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
this.loadingGitImageRepositories = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar las imágenes de repositorio git:', error);
|
||||
console.error(this.translate.instant('errorLoadingImages'), error);
|
||||
this.loadingGitImageRepositories = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -237,8 +240,8 @@ export class CreateClientImageComponent implements OnInit{
|
|||
}
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching branches', error);
|
||||
this.toastService.error('Error al cargar las ramas del repositorio');
|
||||
console.error(this.translate.instant('fetchingBranchesError'), error);
|
||||
this.toastService.error(this.translate.instant('errorLoadingBranches1'));
|
||||
this.loadingBranches = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -261,7 +264,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Rama creada correctamente');
|
||||
this.toastService.success(this.translate.instant('branchCreatedSuccessfully'));
|
||||
this.destinationBranch = result.branchName || result;
|
||||
this.loadBranches();
|
||||
}
|
||||
|
|
@ -270,7 +273,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
}
|
||||
|
||||
if (!this.selectedGitRepository) {
|
||||
this.toastService.error('Debe seleccionar un repositorio primero');
|
||||
this.toastService.error(this.translate.instant('youMustSelectARepositoryFirst'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +288,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Rama creada correctamente');
|
||||
this.toastService.success(this.translate.instant('branchCreatedSuccessfully'));
|
||||
this.destinationBranch = result.branchName || result;
|
||||
this.loadBranches();
|
||||
}
|
||||
|
|
@ -319,9 +322,9 @@ export class CreateClientImageComponent implements OnInit{
|
|||
this.loadingExistingImages = false;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar las imágenes existentes:', error);
|
||||
console.error(this.translate.instant('errorLoadingImages2'), error);
|
||||
this.loadingExistingImages = false;
|
||||
this.toastService.error('Error al cargar las imágenes existentes');
|
||||
this.toastService.error(this.translate.instant('errorLoadingImages1'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -347,18 +350,18 @@ export class CreateClientImageComponent implements OnInit{
|
|||
|
||||
save(): void {
|
||||
if (!this.selectedPartition) {
|
||||
this.toastService.error('Debes seleccionar una partición');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAPartition'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.imageType === 'monolithic') {
|
||||
if (this.monolithicAction === 'create' && !this.name) {
|
||||
this.toastService.error('Debes introducir un nombre canónico para la imagen');
|
||||
this.toastService.error(this.translate.instant('youMustEnterACanonicalName'));
|
||||
return;
|
||||
}
|
||||
if (this.monolithicAction === 'update' && !this.selectedImage) {
|
||||
this.toastService.error('Debes seleccionar una imagen para actualizar');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAnImageTo'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -572,8 +575,8 @@ export class CreateClientImageComponent implements OnInit{
|
|||
}
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al cargar datos de Git:', error);
|
||||
this.toastService.error('Error al cargar información de Git');
|
||||
console.error(this.translate.instant('errorLoadingData'), error);
|
||||
this.toastService.error(this.translate.instant('errorLoadingInformation'));
|
||||
this.loadingGitData = false;
|
||||
}
|
||||
});
|
||||
|
|
@ -603,7 +606,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
this.loadingBranches = false;
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching branches for Git data', error);
|
||||
console.error(this.translate.instant('errorFetchingBranchesForGit'), error);
|
||||
this.loadingBranches = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -643,7 +646,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
let scope = 'clients';
|
||||
|
||||
if (!this.client) {
|
||||
this.toastService.error('No se ha cargado la información del cliente');
|
||||
this.toastService.error(this.translate.instant('hasNotBeenLoaded'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -663,7 +666,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
dialogRef.afterClosed().subscribe((result: any) => {
|
||||
if (result) {
|
||||
if (!this.selectedPartition) {
|
||||
this.toastService.error('Debe seleccionar una partición');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAPartition'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -699,7 +702,7 @@ export class CreateClientImageComponent implements OnInit{
|
|||
type: 'create-image',
|
||||
}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Tarea de creación de imagen programada con éxito');
|
||||
this.toastService.success(this.translate.instant('imageCreationTask'));
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error(error.error['hydra:description'] || 'Error al programar la tarea');
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<app-loading [isLoading]="loading"></app-loading>
|
||||
|
||||
<h2 mat-dialog-title>Crear nuevo repositorio de imágenes git</h2>
|
||||
<h2 mat-dialog-title>{{ 'createNewGitRepo' | translate }}</h2>
|
||||
|
||||
<mat-dialog-content class="dialog-content">
|
||||
<form [formGroup]="repositoryForm" (ngSubmit)="save()" class="repository-form">
|
||||
<mat-form-field appearance="fill" class="form-field">
|
||||
<mat-label>Nombre del repositorio</mat-label>
|
||||
<mat-label>{{ 'labelRepoName' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" required>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
|
||||
<div mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||
<button class="submit-button" (click)="save()">Guardar</button>
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="save()">{{ 'labelSaveButton' | translate }}</button>
|
||||
</div>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
|
|
@ -11,6 +13,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrl: './create-repository-modal.component.css'
|
||||
})
|
||||
export class CreateRepositoryModalComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
repositoryForm: FormGroup<any>;
|
||||
loading: boolean = false;
|
||||
|
|
@ -45,7 +48,7 @@ export class CreateRepositoryModalComponent implements OnInit {
|
|||
|
||||
this.http.post(`${this.baseUrl}/git-repositories`, payload).subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Repositorio creado correctamente');
|
||||
this.toastService.success(this.translate.instant('successfullyCreatedRepository'));
|
||||
this.dialogRef.close(response);
|
||||
},
|
||||
error: (error) => {
|
||||
|
|
@ -54,7 +57,7 @@ export class CreateRepositoryModalComponent implements OnInit {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
this.toastService.error('Por favor, complete todos los campos requeridos');
|
||||
this.toastService.error(this.translate.instant('pleaseCompleteAll'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,45 +9,40 @@
|
|||
<div class="destination-badge">
|
||||
<mat-icon class="destination-icon">cloud_download</mat-icon>
|
||||
<div class="destination-content">
|
||||
<span class="destination-label">Destino</span>
|
||||
<span class="destination-label">{{ 'labelDestination' | translate }}</span>
|
||||
<span class="destination-value">{{ runScriptTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" id="execute-button" [disabled]="!isFormValid()" (click)="save()">Ejecutar</button>
|
||||
<button class="action-button" id="execute-button" [disabled]="!isFormValid()" (click)="save()">{{ 'buttonExecute' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
<button class="action-button" (click)="generateOgInstructions()">
|
||||
Generar instrucciones
|
||||
</button>
|
||||
{{ 'generateInstructions' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
<button class="action-button" color="accent" [disabled]="!isFormValid()" (click)="openScheduleModal()">
|
||||
Opciones de programación
|
||||
</button>
|
||||
{{ 'schedulingOptions' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-container">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Clientes </mat-panel-title>
|
||||
<mat-panel-title> {{ 'labelClients' | translate }}</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Listado de clientes donde se desplegará la imagen
|
||||
<mat-icon>desktop_windows</mat-icon>
|
||||
{{ 'clientListDeployImage' | translate }}<mat-icon>desktop_windows</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="section-hint" (click)="$event.stopPropagation()">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>
|
||||
Puedes marcar o desmarcar un cliente haciendo clic en el área del ordenador. Además, selecciona con "Modelo" el
|
||||
equipo que actuará como modelo.
|
||||
</span>
|
||||
{{ 'markClientModelInstruction' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
|
|
@ -74,8 +69,7 @@
|
|||
<div class="model-selector" (click)="$event.stopPropagation()">
|
||||
<mat-radio-group [(ngModel)]="selectedModelClient" (change)="onModelSelected(selectedModelClient)">
|
||||
<mat-radio-button [value]="client" color="primary" (click)="$event.stopPropagation()">
|
||||
Modelo
|
||||
</mat-radio-button>
|
||||
{{ 'labelModel' | translate }}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -92,15 +86,14 @@
|
|||
<div class="form-section compact-section image-config-section">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>image</mat-icon>
|
||||
Configuración de imagen
|
||||
</div>
|
||||
{{ 'imageConfiguration' | translate }}</div>
|
||||
|
||||
<div class="selector">
|
||||
<mat-form-field appearance="fill" class="half-width">
|
||||
<mat-label>Tipo de imagen</mat-label>
|
||||
<mat-label>{{ 'imageType' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="imageType" (selectionChange)="onImageTypeSelected($event.value)">
|
||||
<mat-option [value]="'monolithic'">Monolítica</mat-option>
|
||||
<mat-option [value]="'git'">Git</mat-option>
|
||||
<mat-option [value]="'monolithic'">{{ 'labelMonolithic' | translate }}</mat-option>
|
||||
<mat-option [value]="'git'">{{ 'labelGit' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -108,13 +101,13 @@
|
|||
<!-- Campos monolítica -->
|
||||
<div class="monolithic-row" *ngIf="imageType === 'monolithic'">
|
||||
<mat-form-field appearance="fill" class="half-width">
|
||||
<mat-label>Seleccione método de deploy</mat-label>
|
||||
<mat-label>{{ 'selectDeployMethod' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedMethod" name="selectedMethod" (selectionChange)="validateImageSize()">
|
||||
<mat-option *ngFor="let method of allMethods" [value]="method.value">{{ method.name }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Seleccione imagen</mat-label>
|
||||
<mat-label>{{ 'selectImagePrompt' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedImage" name="selectedImage" [disabled]="!imageType">
|
||||
<mat-option *ngFor="let image of images" [value]="image">
|
||||
<div class="unit-name"> {{ image.name }}</div>
|
||||
|
|
@ -127,7 +120,7 @@
|
|||
<!-- Campos Git -->
|
||||
<div *ngIf="imageType === 'git'" class="filters-row git-gap">
|
||||
<mat-form-field appearance="fill" style="width: 300px;">
|
||||
<mat-label>Seleccionar Repositorio</mat-label>
|
||||
<mat-label>{{ 'buttonSelectRepository' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedGitRepository" (selectionChange)="onGitRepositoryChange($event.value)"
|
||||
[disabled]="loadingRepositories">
|
||||
<mat-option *ngFor="let repo of repositories" [value]="repo">
|
||||
|
|
@ -138,7 +131,7 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" style="width: 300px;">
|
||||
<mat-label>Seleccionar Rama</mat-label>
|
||||
<mat-label>{{ 'buttonSelectBranch' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedBranch" (selectionChange)="onGitBranchChange()"
|
||||
[disabled]="loadingBranches || !selectedRepository">
|
||||
<mat-option *ngFor="let branch of branches" [value]="branch">
|
||||
|
|
@ -149,10 +142,10 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" style="width: 200px;">
|
||||
<mat-label>Tag</mat-label>
|
||||
<mat-label>{{ 'labelTag' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="showOnlyTagged" (selectionChange)="onTagFilterChange()" [disabled]="!commits.length">
|
||||
<mat-option [value]="false">No</mat-option>
|
||||
<mat-option [value]="true">Sí</mat-option>
|
||||
<mat-option [value]="false">{{ 'buttonNo' | translate }}</mat-option>
|
||||
<mat-option [value]="true">{{ 'buttonYes' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -175,8 +168,7 @@
|
|||
<span class="summary-text">{{ getMethodConfigSummary() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="method-config-pending">
|
||||
} @else {<div class="method-config-pending">
|
||||
<div class="pending-message">
|
||||
<mat-icon class="pending-icon">warning</mat-icon>
|
||||
<span class="pending-text">Se requiere configurar los parámetros de {{ getMethodLabel() }}</span>
|
||||
|
|
@ -204,15 +196,15 @@
|
|||
<div class="form-section-row deploy-mode-row">
|
||||
<div class="deploy-mode-label">
|
||||
<mat-icon>cached</mat-icon>
|
||||
<span>Modo de operación</span>
|
||||
<span>{{ 'operationMode' | translate }}</span>
|
||||
</div>
|
||||
<mat-radio-group [(ngModel)]="deployMode" name="deployMode" class="deploy-mode-radio-group">
|
||||
<mat-radio-button value="deploy" color="primary" class="deploy-mode-radio">
|
||||
<div class="deploy-mode-option">
|
||||
<mat-icon>storage</mat-icon>
|
||||
<div>
|
||||
<span class="deploy-mode-option-title">Despliegue completo</span>
|
||||
<span class="deploy-mode-option-desc">Actualiza caché y restaura partición</span>
|
||||
<span class="deploy-mode-option-title">{{ 'fullDeployment' | translate }}</span>
|
||||
<span class="deploy-mode-option-desc">{{ 'updateCacheRestorePartition' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-radio-button>
|
||||
|
|
@ -220,8 +212,8 @@
|
|||
<div class="deploy-mode-option">
|
||||
<mat-icon>download</mat-icon>
|
||||
<div>
|
||||
<span class="deploy-mode-option-title">Solo actualizar caché</span>
|
||||
<span class="deploy-mode-option-desc">Descarga imagen sin restaurar partición</span>
|
||||
<span class="deploy-mode-option-title">{{ 'onlyUpdateCache' | translate }}</span>
|
||||
<span class="deploy-mode-option-desc">{{ 'downloadImageNoRestore' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-radio-button>
|
||||
|
|
@ -234,15 +226,13 @@
|
|||
<div class="form-section compact-section partition-select-section" id="partition-selection">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>storage</mat-icon>
|
||||
Selección de partición
|
||||
</div>
|
||||
{{ 'partitionSelection' | translate }}</div>
|
||||
|
||||
<div class="partition-table-container">
|
||||
<div *ngIf="showInstructions" class="instructions-box">
|
||||
<mat-card class="instructions-card">
|
||||
<mat-card-title>
|
||||
Instrucciones generadas
|
||||
<button mat-icon-button (click)="showInstructions = false" style="float: right;">
|
||||
{{ 'generatedInstructions' | translate }}<button mat-icon-button (click)="showInstructions = false" style="float: right;">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-card-title>
|
||||
|
|
@ -267,8 +257,7 @@
|
|||
<div class="form-section compact-section partition-select-section" id="partition-info">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>info</mat-icon>
|
||||
Estado actual de particiones
|
||||
</div>
|
||||
{{ 'currentPartitionState' | translate }}</div>
|
||||
<div class="partition-table-container">
|
||||
<app-disk-partition-selector
|
||||
[(selectedPartition)]="selectedPartition"
|
||||
|
|
@ -288,13 +277,12 @@
|
|||
<div *ngIf="imageType === 'git' && filteredCommits.length > 0" class="form-section compact-section">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>history</mat-icon>
|
||||
Selección de commit
|
||||
</div>
|
||||
{{ 'commitSelection' | translate }}</div>
|
||||
|
||||
<div class="commits-table-container">
|
||||
<table mat-table [dataSource]="filteredCommits" class="mat-elevation-z8">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef>Seleccionar</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'buttonSelect' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let commit">
|
||||
<mat-radio-group [(ngModel)]="selectedCommit" name="selectedCommit">
|
||||
<mat-radio-button [value]="commit"></mat-radio-button>
|
||||
|
|
@ -302,7 +290,7 @@
|
|||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="hexsha">
|
||||
<th mat-header-cell *matHeaderCellDef>Commit ID</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'commitId' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let commit">
|
||||
<code style="background-color: #f5f5f5; padding: 2px 4px; border-radius: 3px; font-family: monospace;">
|
||||
{{ commit.hexsha }}
|
||||
|
|
@ -310,22 +298,22 @@
|
|||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="message">
|
||||
<th mat-header-cell *matHeaderCellDef>Mensaje</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelMessage' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let commit">{{ commit.message }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="committed_date">
|
||||
<th mat-header-cell *matHeaderCellDef>Fecha</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelDate' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let commit">{{ commit.committed_date * 1000 | date:'dd/MM/yyyy HH:mm:ss' }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="tags">
|
||||
<th mat-header-cell *matHeaderCellDef>Tags</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelTags' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let commit">
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let tag of commit.tags" color="primary" selected class="custom-tag-chip"
|
||||
style="background: rgba(102, 126, 234, 0.1) !important; color: #667eea !important; border: 1px solid rgba(102, 126, 234, 0.3) !important; border-radius: 8px !important; font-weight: 500 !important; font-size: 10px !important; padding: 2px 6px !important; margin: 1px !important; box-shadow: none !important;">
|
||||
{{ tag }}
|
||||
</mat-chip>
|
||||
<span *ngIf="!commit.tags || commit.tags.length === 0" class="no-tags-text">Sin tags</span>
|
||||
<span *ngIf="!commit.tags || commit.tags.length === 0" class="no-tags-text">{{ 'noTags' | translate }}</span>
|
||||
</mat-chip-list>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||
import { MatTableDataSource } from "@angular/material/table";
|
||||
import { SelectionModel } from "@angular/cdk/collections";
|
||||
|
|
@ -16,6 +18,7 @@ import { QueueConfirmationModalComponent } from "../../../../../shared/queue-con
|
|||
styleUrl: './deploy-image.component.css'
|
||||
})
|
||||
export class DeployImageComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
@Output() dataChange = new EventEmitter<any>();
|
||||
|
||||
|
|
@ -75,22 +78,22 @@ export class DeployImageComponent implements OnInit {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Partición',
|
||||
header: 'labelPartition',
|
||||
cell: (partition: any) => `${partition.partitionNumber}`
|
||||
},
|
||||
{
|
||||
columnDef: 'size',
|
||||
header: 'Tamaño',
|
||||
header: 'labelDiskSize',
|
||||
cell: (partition: any) => `${partition.size} MB`
|
||||
},
|
||||
{
|
||||
columnDef: 'filesystem',
|
||||
header: 'Sistema de ficheros',
|
||||
header: 'fileSystem',
|
||||
cell: (partition: any) => `${partition.filesystem}`
|
||||
},
|
||||
{
|
||||
columnDef: 'operativeSystem',
|
||||
header: 'SO',
|
||||
header: 'sW',
|
||||
cell: (partition: any) => `${partition.operativeSystem?.name}`
|
||||
}
|
||||
];
|
||||
|
|
@ -229,7 +232,7 @@ export class DeployImageComponent implements OnInit {
|
|||
this.loadImages();
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar las particiones:', error);
|
||||
console.error(this.translate.instant('errorLoadingPartitions'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -261,7 +264,7 @@ export class DeployImageComponent implements OnInit {
|
|||
this.images = response?.['hydra:member'] || [];
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar las imágenes:', error);
|
||||
console.error(this.translate.instant('errorLoadingImages3'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -350,27 +353,27 @@ export class DeployImageComponent implements OnInit {
|
|||
const needsPartition = this.deployMode !== 'update-cache';
|
||||
|
||||
if (!this.selectedClients.length) {
|
||||
this.toastService.error('Debe seleccionar al menos un cliente');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAtLeastOne'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.selectedImage && this.imageType !== 'git') {
|
||||
this.toastService.error('Debe seleccionar una imagen');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAnImage'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.selectedMethod && this.imageType !== 'git') {
|
||||
this.toastService.error('Debe seleccionar un método');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAMethod'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (needsPartition && !this.selectedPartition) {
|
||||
this.toastService.error('Debe seleccionar una partición');
|
||||
this.toastService.error(this.translate.instant('youMustSelectAPartition'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.imageType === 'git' && !this.selectedCommit) {
|
||||
this.toastService.error('Debe seleccionar un commit');
|
||||
this.toastService.error(this.translate.instant('youMustSelectACommit'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -381,7 +384,7 @@ export class DeployImageComponent implements OnInit {
|
|||
backdropClass: 'non-clickable-backdrop'
|
||||
});
|
||||
|
||||
this.toastService.info('Preparando petición de despliegue');
|
||||
this.toastService.info(this.translate.instant('preparingDeploymentRequest'));
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result !== undefined) {
|
||||
|
|
@ -428,7 +431,7 @@ export class DeployImageComponent implements OnInit {
|
|||
this.http.post(url, payload)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Petición de despliegue enviada correctamente');
|
||||
this.toastService.success(this.translate.instant('deployRequestSentCorrectly'));
|
||||
this.loading = false;
|
||||
this.router.navigate(['/commands-logs']);
|
||||
},
|
||||
|
|
@ -573,7 +576,7 @@ export class DeployImageComponent implements OnInit {
|
|||
type: 'deploy-image',
|
||||
}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Script añadido con éxito a la tarea');
|
||||
this.toastService.success(this.translate.instant('scriptSuccessfullyAddedTo'));
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
|
|
@ -632,7 +635,7 @@ export class DeployImageComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
error => {
|
||||
this.toastService.error('Error al cargar los repositorios git');
|
||||
this.toastService.error(this.translate.instant('errorLoadingRepositories1'));
|
||||
this.loadingRepositories = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -662,7 +665,7 @@ export class DeployImageComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
error => {
|
||||
this.toastService.error('Error al cargar las ramas');
|
||||
this.toastService.error(this.translate.instant('errorLoadingBranches'));
|
||||
this.loadingBranches = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -694,7 +697,7 @@ export class DeployImageComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
error => {
|
||||
this.toastService.error('Error al cargar los commits');
|
||||
this.toastService.error(this.translate.instant('errorLoadingCommits'));
|
||||
this.loadingCommits = false;
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@
|
|||
<!-- Multicast options -->
|
||||
<div *ngIf="isMulticast()" class="config-grid">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Dirección</mat-label>
|
||||
<mat-label>{{ 'labelAddress' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="mcastIp" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Puerto</mat-label>
|
||||
<mat-label>{{ 'labelPort' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="mcastPort" type="number" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Modo Multicast</mat-label>
|
||||
<mat-label>{{ 'labelMcastMode' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="mcastMode" required>
|
||||
<mat-option *ngFor="let option of data.multicastModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
|
|
@ -26,17 +26,17 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Velocidad</mat-label>
|
||||
<mat-label>{{ 'labelSpeed' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="mcastSpeed" type="number" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Máx. Clientes</mat-label>
|
||||
<mat-label>{{ 'maxClients' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxClients" type="number" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Tiempo máx. espera</mat-label>
|
||||
<mat-label>{{ 'maxWaitTime' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxTime" type="number" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
<!-- P2P options -->
|
||||
<div *ngIf="isP2P()" class="config-grid">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Modo P2P</mat-label>
|
||||
<mat-label>{{ 'labelP2pMode' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="p2pMode" required>
|
||||
<mat-option *ngFor="let option of data.p2pModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
|
|
@ -53,15 +53,14 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" *ngIf="p2pMode === 'seeder'">
|
||||
<mat-label>Semilla (minutos)</mat-label>
|
||||
<mat-label>{{ 'seedMinutes' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="p2pTime" type="number" required>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button (click)="onCancel()">Cancelar</button>
|
||||
<button mat-button (click)="onCancel()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button mat-flat-button color="primary" [disabled]="!isValid()" (click)="onSave()">
|
||||
Guardar configuración
|
||||
</button>
|
||||
{{ 'buttonSaveConfig' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -9,30 +9,27 @@
|
|||
<div class="destination-badge">
|
||||
<mat-icon class="destination-icon">cloud_download</mat-icon>
|
||||
<div class="destination-content">
|
||||
<span class="destination-label">Destino</span>
|
||||
<span class="destination-label">{{ 'labelDestination' | translate }}</span>
|
||||
<span class="destination-value">{{ runScriptTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" [disabled]="!selectedModelClient || !allSelected || !selectedDisk || (selectedDisk.totalDiskSize - selectedDisk.used) <= 0 || partitionValidationStatus === 'error'" (click)="save()">Ejecutar</button>
|
||||
<button class="action-button" [disabled]="!selectedModelClient || !allSelected || !selectedDisk || (selectedDisk.totalDiskSize - selectedDisk.used) <= 0 || partitionValidationStatus === 'error'" (click)="save()">{{ 'buttonExecute' | translate }}</button>
|
||||
<button class="action-button secondary-button" (click)="generateInstructions()">
|
||||
Generar instrucciones
|
||||
</button>
|
||||
{{ 'generateInstructions' | translate }}</button>
|
||||
<button class="action-button" color="accent" [disabled]="!selectedModelClient || !allSelected || !selectedDisk || (selectedDisk.totalDiskSize - selectedDisk.used) <= 0" (click)="openScheduleModal()">
|
||||
Opciones de programación
|
||||
</button>
|
||||
{{ 'schedulingOptions' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="showInstructions" class="instructions-box instructions-top" (click)="$event.stopPropagation()">
|
||||
<mat-card class="instructions-card">
|
||||
<mat-card-title>
|
||||
Script generado
|
||||
<span style="float: right;">
|
||||
<button mat-icon-button matTooltip="Copiar" (click)="copyInstructions()"><mat-icon>content_copy</mat-icon></button>
|
||||
<button mat-icon-button matTooltip="Cerrar" (click)="showInstructions = false"><mat-icon>close</mat-icon></button>
|
||||
{{ 'generatedScript' | translate }}<span style="float: right;">
|
||||
<button mat-icon-button [matTooltip]="'buttonCopy' | translate" (click)="copyInstructions()"><mat-icon>content_copy</mat-icon></button>
|
||||
<button mat-icon-button [matTooltip]="'buttonClose' | translate" (click)="showInstructions = false"><mat-icon>close</mat-icon></button>
|
||||
</span>
|
||||
</mat-card-title>
|
||||
<mat-card-content>
|
||||
|
|
@ -44,18 +41,16 @@
|
|||
<div class="select-container">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Clientes </mat-panel-title>
|
||||
<mat-panel-title> {{ 'labelClients' | translate }}</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Listado de clientes donde se realizará el particionado
|
||||
<mat-icon>desktop_windows</mat-icon>
|
||||
{{ 'clientListPartition' | translate }}<mat-icon>desktop_windows</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="section-hint" (click)="$event.stopPropagation()">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>
|
||||
Puedes marcar o desmarcar un cliente haciendo clic en el área del ordenador. Además, selecciona con "Modelo" el equipo que actuará como modelo.
|
||||
</span>
|
||||
{{ 'markClientModelInstruction2' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
|
|
@ -90,8 +85,7 @@
|
|||
<mat-radio-button [value]="client"
|
||||
color="primary"
|
||||
(click)="$event.stopPropagation()">
|
||||
Modelo
|
||||
</mat-radio-button>
|
||||
{{ 'labelModel' | translate }}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
|
||||
|
|
@ -105,7 +99,7 @@
|
|||
<div class="disk-and-partitions-container" id="disk-selector">
|
||||
<div class="disk-toolbar">
|
||||
<mat-form-field appearance="fill" class="disk-toolbar-select">
|
||||
<mat-label>Disco</mat-label>
|
||||
<mat-label>{{ 'labelDisk' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedDiskNumber" (selectionChange)="onDiskSelectionChange()">
|
||||
<mat-option *ngFor="let disk of disks" [value]="disk.diskNumber">
|
||||
<div class="disk-option">
|
||||
|
|
@ -123,15 +117,15 @@
|
|||
|
||||
<div class="disk-toolbar-info" *ngIf="selectedDisk">
|
||||
<div class="disk-stat">
|
||||
<span class="disk-stat-label">Usado</span>
|
||||
<span class="disk-stat-label">{{ 'labelDiskUsed' | translate }}</span>
|
||||
<span class="disk-stat-value used">{{ selectedDisk.used | number:'1.0-0' }} MB</span>
|
||||
</div>
|
||||
<div class="disk-stat">
|
||||
<span class="disk-stat-label">Libre</span>
|
||||
<span class="disk-stat-label">{{ 'labelFree' | translate }}</span>
|
||||
<span class="disk-stat-value free" [ngClass]="{'warning': (selectedDisk.used / selectedDisk.totalDiskSize) >= 0.9 && (selectedDisk.used / selectedDisk.totalDiskSize) < 1, 'danger': (selectedDisk.used / selectedDisk.totalDiskSize) >= 1}">{{ (selectedDisk.totalDiskSize - selectedDisk.used) | number:'1.0-0' }} MB</span>
|
||||
</div>
|
||||
<div class="disk-stat">
|
||||
<span class="disk-stat-label">Total</span>
|
||||
<span class="disk-stat-label">{{ 'labelDiskTotal' | translate }}</span>
|
||||
<span class="disk-stat-value">{{ selectedDisk.totalDiskSize | number:'1.0-0' }} MB</span>
|
||||
</div>
|
||||
<div class="disk-usage-bar-inline">
|
||||
|
|
@ -154,15 +148,14 @@
|
|||
</div>
|
||||
|
||||
<button class="action-button add-partition-btn" *ngIf="selectedDisk" (click)="addPartition(selectedDisk.diskNumber)">
|
||||
<mat-icon>add</mat-icon> Añadir partición
|
||||
</button>
|
||||
<mat-icon>add</mat-icon> {{ 'addPartition' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="no-disks-message" *ngIf="!disks || disks.length === 0">
|
||||
<mat-icon class="warning-icon">warning</mat-icon>
|
||||
<div class="message-text">
|
||||
<span class="message-title">No hay discos disponibles</span>
|
||||
<span class="message-subtitle">Asegúrate de que el cliente modelo tenga discos configurados</span>
|
||||
<span class="message-title">{{ 'noDisksAvailable' | translate }}</span>
|
||||
<span class="message-subtitle">{{ 'ensureModelClientHasDisks' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -176,7 +169,7 @@
|
|||
<div class="validation-status" [ngClass]="partitionValidationStatus">
|
||||
<mat-icon *ngIf="partitionValidationStatus === 'loading'" class="validation-icon loading">hourglass_empty</mat-icon>
|
||||
<mat-icon *ngIf="partitionValidationStatus === 'success'" class="validation-icon success">check_circle</mat-icon>
|
||||
<mat-icon *ngIf="partitionValidationStatus === 'error'" class="validation-icon error">error</mat-icon>
|
||||
<mat-icon *ngIf="partitionValidationStatus === 'error'" class="validation-icon error">{{ 'labelError' | translate }}</mat-icon>
|
||||
<span class="validation-message" *ngIf="partitionValidationMessage">{{ partitionValidationMessage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -184,12 +177,12 @@
|
|||
<table class="partition-table" id="partition-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Partición</th>
|
||||
<th>Tipo partición</th>
|
||||
<th>S. ficheros</th>
|
||||
<th>Tamaño (MB)</th>
|
||||
<th>Tamaño (%)</th>
|
||||
<th>Formatear</th>
|
||||
<th>{{ 'labelPartition' | translate }}</th>
|
||||
<th>{{ 'partitionType' | translate }}</th>
|
||||
<th>{{ 'labelFsShort' | translate }}</th>
|
||||
<th>{{ 'labelSizeMb' | translate }}</th>
|
||||
<th>{{ 'labelSizePercentage' | translate }}</th>
|
||||
<th>{{ 'buttonFormat' | translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -232,7 +225,7 @@
|
|||
|
||||
<div class="chart-container" *ngIf="selectedDisk" #chartContainer>
|
||||
<div class="chart-header">
|
||||
<h3>Distribución de Particiones</h3>
|
||||
<h3>{{ 'partitionDistribution' | translate }}</h3>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<ngx-charts-pie-chart
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, EventEmitter, Inject, Input, OnInit, Output, AfterViewInit, OnDestroy, ViewChild, ElementRef, HostListener} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, EventEmitter, Inject, Input, OnInit, Output, AfterViewInit, OnDestroy, ViewChild, ElementRef, HostListener } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
|
|
@ -32,6 +34,7 @@ interface Partition {
|
|||
styleUrls: ['./partition-assistant.component.css']
|
||||
})
|
||||
export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDestroy{
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
@Output() dataChange = new EventEmitter<any>();
|
||||
|
|
@ -190,7 +193,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
this.initializeDisks();
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error al cargar los datos del cliente:', error);
|
||||
console.error(this.translate.instant('errorLoadingData1'), error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -412,7 +415,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
this.resizeChart();
|
||||
}, 100);
|
||||
} else {
|
||||
this.toastService.error('No hay suficiente espacio libre en el disco para crear una nueva partición.');
|
||||
this.toastService.error(this.translate.instant('notEnoughFreeSpace'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -457,7 +460,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
}
|
||||
|
||||
if (!this.selectedDisk) {
|
||||
this.toastService.error('No se ha seleccionado un disco.');
|
||||
this.toastService.error(this.translate.instant('noOneHasBeenSelected'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -466,14 +469,14 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
.reduce((sum: any, partition: any) => sum + partition.size, 0);
|
||||
|
||||
if (totalPartitionSize > this.selectedDisk.totalDiskSize) {
|
||||
this.toastService.error('El tamaño total de las particiones en el disco seleccionado excede el tamaño total del disco.');
|
||||
this.toastService.error(this.translate.instant('theTotalSizeOfThe'));
|
||||
return;
|
||||
}
|
||||
|
||||
const modifiedPartitions = this.selectedDisk.partitions.filter((partition: { removed: any; format: any; }) => !partition.removed || partition.format);
|
||||
|
||||
if (modifiedPartitions.length === 0) {
|
||||
this.toastService.info('No hay cambios para guardar en el disco seleccionado.');
|
||||
this.toastService.info(this.translate.instant('noChangesToSave'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -507,13 +510,13 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
|
||||
this.http.post(this.apiUrl, bulkPayload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Particiones creadas exitosamente para el disco seleccionado.');
|
||||
this.toastService.success(this.translate.instant('partitionsSuccessfullyCreatedForThe'));
|
||||
this.loading = false;
|
||||
this.router.navigate(['/commands-logs']);
|
||||
},
|
||||
(error) => {
|
||||
this.loading = false;
|
||||
this.toastService.error('Error al crear las particiones.');
|
||||
this.toastService.error(this.translate.instant('errorCreatingPartitions'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -680,7 +683,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
|
||||
if (modifiedPartitions.length === 0) {
|
||||
this.loading = false;
|
||||
this.toastService.info('No hay cambios para guardar en el disco seleccionado.');
|
||||
this.toastService.info(this.translate.instant('noChangesToSave'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -711,7 +714,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
type: 'partition-assistant',
|
||||
}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Script añadido con éxito a la tarea');
|
||||
this.toastService.success(this.translate.instant('scriptSuccessfullyAddedTo'));
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
|
|
@ -723,7 +726,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
|
||||
generateInstructions(): void {
|
||||
if (!this.selectedModelClient || !this.selectedDisk) {
|
||||
this.toastService.error('Selecciona un cliente modelo y un disco.');
|
||||
this.toastService.error(this.translate.instant('selectAModelClientAnd'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -777,8 +780,8 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
copyInstructions(): void {
|
||||
if (!this.generatedInstructions) { return; }
|
||||
navigator.clipboard?.writeText(this.generatedInstructions)
|
||||
.then(() => this.toastService.success('Script copiado al portapapeles'))
|
||||
.catch(() => this.toastService.error('No se pudo copiar el script.'));
|
||||
.then(() => this.toastService.success(this.translate.instant('scriptCopiedToClipboard')))
|
||||
.catch(() => this.toastService.error(this.translate.instant('couldNotCopy')));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -837,7 +840,7 @@ export class PartitionAssistantComponent implements OnInit, AfterViewInit, OnDes
|
|||
});
|
||||
console.log('Scroll hacia botón ejecutar completado');
|
||||
} else {
|
||||
console.error('No se encontró el botón execute-button');
|
||||
console.error(this.translate.instant('theButtonWasNotFound'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,38 +9,35 @@
|
|||
<div class="destination-badge">
|
||||
<mat-icon class="destination-icon">terminal</mat-icon>
|
||||
<div class="destination-content">
|
||||
<span class="destination-label">Destino</span>
|
||||
<span class="destination-label">{{ 'labelDestination' | translate }}</span>
|
||||
<span class="destination-value">{{ runScriptTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" [disabled]="selectedClients.length < 1 || (commandType === 'existing' && !selectedScript) || (commandType === 'new' && !newScript.trim()) || loading" (click)="save()">Ejecutar</button>
|
||||
<button class="action-button" [disabled]="selectedClients.length < 1 || (commandType === 'existing' && !selectedScript) || (commandType === 'new' && !newScript.trim()) || loading" (click)="save()">{{ 'buttonExecute' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
<button color="accent" class="action-button" [disabled]="selectedClients.length < 1 || (commandType === 'existing' && !selectedScript) || (commandType === 'new' && !newScript.trim()) || loading" (click)="openScheduleModal()">
|
||||
Opciones de programación
|
||||
</button>
|
||||
{{ 'schedulingOptions' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-container">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Clientes </mat-panel-title>
|
||||
<mat-panel-title> {{ 'labelClients' | translate }}</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Listado de clientes donde se ejecutara el script seleccionado
|
||||
<mat-icon>desktop_windows</mat-icon>
|
||||
{{ 'clientListExecuteScript' | translate }}<mat-icon>desktop_windows</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="section-hint" (click)="$event.stopPropagation()">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>
|
||||
Puedes marcar o desmarcar un cliente haciendo clic en el área del ordenador.
|
||||
</span>
|
||||
{{ 'markClientInstruction' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
|
|
@ -79,24 +76,22 @@
|
|||
<div class="form-section">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>code</mat-icon>
|
||||
Configuración de script
|
||||
</div>
|
||||
{{ 'scriptConfiguration' | translate }}</div>
|
||||
|
||||
<div class="run-as-admin-container">
|
||||
<mat-checkbox [(ngModel)]="runAsAdmin" color="primary">
|
||||
Ejecutar como administrador
|
||||
</mat-checkbox>
|
||||
{{ 'executeAsAdmin' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="action-chips-container">
|
||||
<mat-chip-listbox [(ngModel)]="commandType" required class="action-chip-listbox">
|
||||
<mat-chip-option value="new" class="action-chip create-chip firmware-chip" (click)="commandType = 'new'">
|
||||
<mat-icon>add_circle</mat-icon>
|
||||
<span>Nuevo Script</span>
|
||||
<span>{{ 'newScript' | translate }}</span>
|
||||
</mat-chip-option>
|
||||
<mat-chip-option value="existing" class="action-chip update-chip firmware-chip" (click)="commandType = 'existing'">
|
||||
<mat-icon>folder</mat-icon>
|
||||
<span>Script Guardado</span>
|
||||
<span>{{ 'savedScript' | translate }}</span>
|
||||
</mat-chip-option>
|
||||
</mat-chip-listbox>
|
||||
</div>
|
||||
|
|
@ -106,8 +101,7 @@
|
|||
<div class="script-input-header">
|
||||
<h4>
|
||||
<mat-icon>edit_note</mat-icon>
|
||||
Editor de Script
|
||||
</h4>
|
||||
{{ 'scriptEditorTitle' | translate }}</h4>
|
||||
<div class="script-stats" *ngIf="newScript.trim()">
|
||||
<span class="stat-item">
|
||||
<mat-icon>format_list_numbered</mat-icon>
|
||||
|
|
@ -125,23 +119,22 @@
|
|||
</div>
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Ingrese el script</mat-label>
|
||||
<mat-label>{{ 'enterScript' | translate }}</mat-label>
|
||||
<textarea
|
||||
matInput
|
||||
[(ngModel)]="newScript"
|
||||
(ngModelChange)="onNewScriptChange()"
|
||||
rows="8"
|
||||
placeholder="#!/bin/bash # Escriba su script aquí echo 'Iniciando script...' # Sus comandos aquí"
|
||||
[placeholder]="'bashScriptBoilerplate'|translate"
|
||||
class="script-textarea"></textarea>
|
||||
<mat-hint>Escriba comandos de shell/bash. Use @parametro para variables dinámicas.</mat-hint>
|
||||
<mat-hint>{{ 'writeShellCommandsHint' | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Vista previa de parámetros detectados en nuevo script -->
|
||||
<div *ngIf="newScriptParameters.length > 0" class="detected-params">
|
||||
<h4>
|
||||
<mat-icon>tune</mat-icon>
|
||||
Parámetros detectados
|
||||
</h4>
|
||||
{{ 'detectedParameters' | translate }}</h4>
|
||||
<div class="params-grid">
|
||||
<mat-chip-listbox>
|
||||
<mat-chip-option *ngFor="let param of newScriptParameters" class="param-chip" selected>
|
||||
|
|
@ -159,8 +152,7 @@
|
|||
[disabled]="!isScriptValid(newScript)"
|
||||
(click)="saveNewScript()">
|
||||
<mat-icon>save</mat-icon>
|
||||
Guardar Script
|
||||
</button>
|
||||
{{ 'buttonSaveScript' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -168,7 +160,7 @@
|
|||
<div *ngIf="commandType === 'existing'">
|
||||
<div class="script-selector-container">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Seleccione script a ejecutar</mat-label>
|
||||
<mat-label>{{ 'selectScriptToRun' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="selectedScript" (selectionChange)="onScriptChange()">
|
||||
<mat-option *ngFor="let script of scripts" [value]="script">
|
||||
<div class="script-option">
|
||||
|
|
@ -177,7 +169,7 @@
|
|||
</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-hint *ngIf="scripts.length === 0">No hay scripts guardados disponibles</mat-hint>
|
||||
<mat-hint *ngIf="scripts.length === 0">{{ 'noSavedScripts' | translate }}</mat-hint>
|
||||
<mat-hint *ngIf="scripts.length > 0">{{ scripts.length }} script(s) disponible(s)</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
|
@ -188,8 +180,7 @@
|
|||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<mat-icon>preview</mat-icon>
|
||||
Vista previa del script
|
||||
</mat-card-title>
|
||||
{{ 'scriptPreview' | translate }}</mat-card-title>
|
||||
<mat-card-subtitle>{{ selectedScript.name }}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
|
|
@ -206,10 +197,9 @@
|
|||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<mat-icon>settings</mat-icon>
|
||||
Parámetros del script
|
||||
<mat-chip class="params-count">{{ parameterNames.length }}</mat-chip>
|
||||
{{ 'scriptParameters' | translate }}<mat-chip class="params-count">{{ parameterNames.length }}</mat-chip>
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle>Configure los valores para los parámetros requeridos</mat-card-subtitle>
|
||||
<mat-card-subtitle>{{ 'configureRequiredParameters' | translate }}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
|
|
@ -225,7 +215,7 @@
|
|||
[required]="true">
|
||||
<mat-icon matPrefix>label</mat-icon>
|
||||
<mat-hint>Parámetro: @{{ paramName }}</mat-hint>
|
||||
<mat-error *ngIf="!parameters[paramName]">Este parámetro es requerido</mat-error>
|
||||
<mat-error *ngIf="!parameters[paramName]">{{ 'parameterRequired' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -239,8 +229,8 @@
|
|||
<div *ngIf="commandType === 'existing' && !selectedScript" class="empty-state">
|
||||
<div class="empty-state-content">
|
||||
<mat-icon>folder_open</mat-icon>
|
||||
<h3>Selecciona un script</h3>
|
||||
<p>Elige un script guardado de la lista para ver su contenido y configurar parámetros.</p>
|
||||
<h3>{{ 'selectAScript' | translate }}</h3>
|
||||
<p>{{ 'selectScriptToView' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -248,8 +238,8 @@
|
|||
<div *ngIf="commandType === 'new' && !newScript.trim()" class="empty-state">
|
||||
<div class="empty-state-content">
|
||||
<mat-icon>edit_note</mat-icon>
|
||||
<h3>Escribe tu script</h3>
|
||||
<p>Crea un nuevo script escribiendo comandos de shell/bash en el editor de texto.</p>
|
||||
<h3>{{ 'writeYourScript' | translate }}</h3>
|
||||
<p>{{ 'createScriptHint' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||
import { SelectionModel } from "@angular/cdk/collections";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
|
|
@ -15,6 +17,7 @@ import {QueueConfirmationModalComponent} from "../../../../../shared/queue-confi
|
|||
styleUrl: './run-script-assistant.component.css'
|
||||
})
|
||||
export class RunScriptAssistantComponent implements OnInit{
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
@Output() dataChange = new EventEmitter<any>();
|
||||
|
||||
|
|
@ -96,7 +99,7 @@ export class RunScriptAssistantComponent implements OnInit{
|
|||
|
||||
saveNewScript() {
|
||||
if (!this.newScript.trim()) {
|
||||
this.toastService.error('Debe ingresar un script antes de guardar.');
|
||||
this.toastService.error(this.translate.instant('youMustEnterAScriptBefore'));
|
||||
return;
|
||||
}
|
||||
const dialogRef = this.dialog.open(SaveScriptComponent, {
|
||||
|
|
@ -106,7 +109,7 @@ export class RunScriptAssistantComponent implements OnInit{
|
|||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.toastService.success('Script guardado correctamente');
|
||||
this.toastService.success(this.translate.instant('scriptSavedSuccessfully'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -205,13 +208,13 @@ export class RunScriptAssistantComponent implements OnInit{
|
|||
runAsAdmin: this.runAsAdmin
|
||||
}).subscribe(
|
||||
response => {
|
||||
this.toastService.success('Script ejecutado correctamente');
|
||||
this.toastService.success(this.translate.instant('scriptExecutedSuccessfully'));
|
||||
this.dataChange.emit();
|
||||
this.router.navigate(['/commands-logs']);
|
||||
this.loading = false;
|
||||
},
|
||||
error => {
|
||||
this.toastService.error('Error al ejecutar el script');
|
||||
this.toastService.error(this.translate.instant('errorWhenRunningScript'));
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -258,7 +261,7 @@ export class RunScriptAssistantComponent implements OnInit{
|
|||
type: 'run-script',
|
||||
}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Script añadido con éxito a la tarea');
|
||||
this.toastService.success(this.translate.instant('scriptSuccessfullyAddedTo'));
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<h2 mat-dialog-title>Guardar Comando</h2>
|
||||
<h2 mat-dialog-title>{{ 'buttonSaveCommand' | translate }}</h2>
|
||||
<mat-dialog-content>
|
||||
<p>Introduce un nombre para el comando:</p>
|
||||
<p>{{ 'enterCommandName' | translate }}</p>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Nombre del Comando</mat-label>
|
||||
<mat-label>{{ 'commandNameTitle' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="commandName">
|
||||
</mat-form-field>
|
||||
</mat-dialog-content>
|
||||
<div mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||
<button class="submit-button" (click)="save()">Guardar</button>
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="save()">{{ 'labelSaveButton' | translate }}</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Component, Inject } from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {FormBuilder, Validators} from "@angular/forms";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
|
|
@ -12,6 +14,7 @@ import {DataService} from "../../../../../commands/main-commands/data.service";
|
|||
styleUrl: './save-script.component.css'
|
||||
})
|
||||
export class SaveScriptComponent {
|
||||
public translate = inject(TranslateService);
|
||||
commandName: string = '';
|
||||
baseUrl: string;
|
||||
|
||||
|
|
@ -36,7 +39,7 @@ export class SaveScriptComponent {
|
|||
|
||||
this.http.post(`${this.baseUrl}/commands`, payload).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Comando añadido correctamente');
|
||||
this.toastService.success(this.translate.instant('commandAddedSuccessfully'));
|
||||
this.dialogRef.close();
|
||||
},
|
||||
(error) => {
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@
|
|||
</div>
|
||||
<button class="ordinary-button" (click)="openBottomSheet()" joyrideStep="keyStep"
|
||||
text="{{ 'keyStepText' | translate }}" matTooltipShowDelay="1000">
|
||||
{{ 'legendButton' | translate }}
|
||||
{{ 'Legend' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Menú desplegable para pantallas pequeñas -->
|
||||
<div *ngIf="isSmallScreen" class="groups-menu">
|
||||
<button mat-icon-button [matMenuTriggerFor]="smallScreenMenu" matTooltip="Opciones" matTooltipShowDelay="1000">
|
||||
<button mat-icon-button [matMenuTriggerFor]="smallScreenMenu" [matTooltip]="'labelOptions' | translate" matTooltipShowDelay="1000">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<mat-menu #smallScreenMenu="matMenu">
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
{{ 'newMultipleClientButton' | translate }}
|
||||
</button>
|
||||
<button mat-menu-item (click)="openBottomSheet()">
|
||||
{{ 'legendButton' | translate }}
|
||||
{{ 'Legend' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
|
@ -76,8 +76,8 @@
|
|||
<mat-form-field class="filter-form-field" appearance="outline">
|
||||
<mat-label>{{ 'searchTree' | translate }}</mat-label>
|
||||
<input matInput #treeSearchInput (input)="onTreeFilterInput($event)"
|
||||
placeholder="Centro, aula, grupos ..." />
|
||||
<button *ngIf="treeSearchInput.value" mat-icon-button matSuffix aria-label="Clear tree search"
|
||||
[placeholder]="'placeholderOrgUnitTypes' | translate" />
|
||||
<button *ngIf="treeSearchInput.value" mat-icon-button matSuffix [attr.aria-label]="'clearTreeSearch' | translate"
|
||||
(click)="clearTreeSearch(treeSearchInput)">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
|
@ -85,8 +85,8 @@
|
|||
<mat-form-field class="filter-form-field" appearance="outline">
|
||||
<mat-label>{{ 'searchClient' | translate }}</mat-label>
|
||||
<input matInput #clientSearchInput (input)="onClientFilterInput($event)"
|
||||
placeholder="Nombre, IP, estado o MAC" />
|
||||
<button *ngIf="clientSearchInput.value" mat-icon-button matSuffix aria-label="Clear client search"
|
||||
[placeholder]="'searchNameIpStatusMac' | translate" />
|
||||
<button *ngIf="clientSearchInput.value" mat-icon-button matSuffix [attr.aria-label]="'clearClientSearch' | translate"
|
||||
(click)="clearClientSearch(clientSearchInput)">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
|
@ -98,7 +98,7 @@
|
|||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<button *ngIf="clientSearchStatusInput.value" mat-icon-button matSuffix aria-label="Clear tree search"
|
||||
<button *ngIf="clientSearchStatusInput.value" mat-icon-button matSuffix [attr.aria-label]="'clearTreeSearch' | translate"
|
||||
(click)="clearStatusFilter($event, clientSearchStatusInput)">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
|
@ -116,7 +116,7 @@
|
|||
|
||||
<!-- Funcionalidad actualmente deshabilitada-->
|
||||
<!-- <mat-form-field appearance="outline">
|
||||
<mat-select (selectionChange)="loadSelectedFilter($event.value)" placeholder="Cargar filtro" disabled>
|
||||
<mat-select (selectionChange)="loadSelectedFilter($event.value)" [placeholder]="'buttonLoadFilter' | translate" disabled>
|
||||
<mat-option *ngFor="let savedFilter of savedFilterNames" [value]="savedFilter">
|
||||
{{ savedFilter[0] }}
|
||||
</mat-option>
|
||||
|
|
@ -270,11 +270,11 @@
|
|||
</button>
|
||||
<button mat-menu-item (click)="onEditNode($event, selectedNode)" *ngIf="auth.userCategory !== 'ou-minimal'">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>{{ 'edit' | translate }}</span>
|
||||
<span>{{ 'buttonEdit' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, selectedNode)" *ngIf="auth.userCategory !== 'ou-minimal'">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'delete' | translate }}</span>
|
||||
<span>{{ 'buttonDelete' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="openPartitionTypeModal($event, selectedNode)">
|
||||
<mat-icon>storage</mat-icon>
|
||||
|
|
@ -300,7 +300,7 @@
|
|||
<!-- CLIENTS HEADER -->
|
||||
<div class="clients-view-header">
|
||||
<span [ngStyle]="{ visibility: isLoadingClients ? 'hidden' : 'visible' }" class="clients-title-name">
|
||||
{{ 'clients' | translate }}
|
||||
{{ 'labelClients' | translate }}
|
||||
<strong>{{ selectedNode?.name }}</strong>
|
||||
</span>
|
||||
<div class="view-type-container">
|
||||
|
|
@ -308,7 +308,7 @@
|
|||
(change)="toggleAllCards()"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
matTooltip="Seleccionar todos">
|
||||
[matTooltip]="'buttonSelectAll' | translate">
|
||||
</mat-checkbox>
|
||||
<button class="action-button" [disabled]="selection.selected.length === 0" (click)="changeParent($event)"
|
||||
matTooltip="{{ 'moveClientsTooltip' | translate }}" matTooltipShowDelay="1000">
|
||||
|
|
@ -325,7 +325,7 @@
|
|||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-button-toggle-group name="viewType" aria-label="View Type" [hideSingleSelectionIndicator]="true"
|
||||
<mat-button-toggle-group name="viewType" [attr.aria-label]="'viewType' | translate" [hideSingleSelectionIndicator]="true"
|
||||
(change)="toggleView($event.value)" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
|
||||
<mat-button-toggle value="list" [disabled]="currentView === 'list'">
|
||||
<mat-icon>list</mat-icon> <span class="type-view-text">{{ 'vistalista' | translate }}</span>
|
||||
|
|
@ -419,16 +419,16 @@
|
|||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)" *ngIf="auth.userCategory !== 'ou-minimal'">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>{{ 'edit' | translate }}</span>
|
||||
<span>{{ 'buttonEdit' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>{{ 'viewDetails' | translate }}</span>
|
||||
<span>{{ 'buttonViewDetails' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item *ngIf="!syncingClientIds.has(client.uuid)"
|
||||
(click)="getStatus(client, selectedNode)">
|
||||
<mat-icon>sync</mat-icon>
|
||||
<span>{{ 'sync' | translate }}</span>
|
||||
<span>{{ 'buttonSync' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="openClientTaskLogs($event, client)">
|
||||
<mat-icon>list_alt</mat-icon>
|
||||
|
|
@ -440,15 +440,15 @@
|
|||
</button>
|
||||
<button mat-menu-item (click)="openClientLogsInNewTab($event, client)">
|
||||
<mat-icon>article</mat-icon>
|
||||
<span>Logs en tiempo real</span>
|
||||
<span>{{ 'realTimeLogs' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="openClientLogsModal($event, client)">
|
||||
<mat-icon>analytics</mat-icon>
|
||||
<span>Logs de cliente</span>
|
||||
<span>{{ 'clientLogs' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client)" *ngIf="auth.userCategory !== 'ou-minimal'">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'delete' | translate }}</span>
|
||||
<span>{{ 'buttonDelete' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
|
@ -471,7 +471,7 @@
|
|||
<span>{{ 'showingResults' | translate: { from: getPaginationFrom(), to: getPaginationTo(), total: getPaginationTotal() } }}</span>
|
||||
</div>
|
||||
<div class="table-actions">
|
||||
<button mat-icon-button (click)="refreshClientData()" matTooltip="{{ 'refresh' | translate }}">
|
||||
<button mat-icon-button (click)="refreshClientData()" matTooltip="{{ 'buttonUpdate' | translate }}">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="exportToCSV()" matTooltip="{{ 'exportCSV' | translate }}">
|
||||
|
|
@ -498,7 +498,7 @@
|
|||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<div class="column-header">
|
||||
<span>{{ 'status' | translate }}</span>
|
||||
<span>{{ 'labelState' | translate }}</span>
|
||||
<button mat-icon-button (click)="sortColumn('status')" class="sort-button">
|
||||
<mat-icon>{{ getSortIcon('status') }}</mat-icon>
|
||||
</button>
|
||||
|
|
@ -535,7 +535,7 @@
|
|||
<ng-container matColumnDef="ip">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<div class="column-header">
|
||||
<span>IP</span>
|
||||
<span>{{ 'labelIpCaps' | translate }}</span>
|
||||
<button mat-icon-button (click)="sortColumn('ip')" class="sort-button">
|
||||
<mat-icon>{{ getSortIcon('ip') }}</mat-icon>
|
||||
</button>
|
||||
|
|
@ -567,7 +567,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="oglive">
|
||||
<th mat-header-cell *matHeaderCellDef> OG Live </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'ogLiveTitle' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let client">
|
||||
<div class="oglive-cell">
|
||||
<span class="oglive-kernel">{{ client.ogLive?.kernel }}</span>
|
||||
|
|
@ -590,7 +590,7 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="parentName">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'parent' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelEditOrgUnitParent' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let client" class="truncate-cell-medium" [matTooltip]="client.parentName"> {{ client.parentName }} </td>
|
||||
</ng-container>
|
||||
|
||||
|
|
@ -608,22 +608,22 @@
|
|||
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"
|
||||
[runScriptContext]="getRunScriptContext([client])" matTooltip="{{ 'executeCommand' | translate }}">
|
||||
</app-execute-command>
|
||||
<button mat-icon-button color="primary" (click)="onShowClientDetail($event, client)" matTooltip="{{ 'viewDetails' | translate }}">
|
||||
<button mat-icon-button color="primary" (click)="onShowClientDetail($event, client)" matTooltip="{{ 'buttonViewDetails' | translate }}">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<mat-menu #clientMenu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)" *ngIf="auth.userCategory !== 'ou-minimal'">
|
||||
<mat-icon>edit</mat-icon>
|
||||
<span>{{ 'edit' | translate }}</span>
|
||||
<span>{{ 'buttonEdit' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onShowClientDetail($event, client)">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<span>{{ 'viewDetails' | translate }}</span>
|
||||
<span>{{ 'buttonViewDetails' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="getStatus(client, selectedNode)">
|
||||
<mat-icon>sync</mat-icon>
|
||||
<span>{{ 'sync' | translate }}</span>
|
||||
<span>{{ 'buttonSync' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="openClientTaskLogs($event, client)">
|
||||
<mat-icon>list_alt</mat-icon>
|
||||
|
|
@ -635,15 +635,15 @@
|
|||
</button>
|
||||
<button mat-menu-item *ngIf="client.status === 'og-live'" (click)="openClientLogsInNewTab($event, client)">
|
||||
<mat-icon>article</mat-icon>
|
||||
<span>Logs en tiempo real</span>
|
||||
<span>{{ 'realTimeLogs' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="openClientLogsModal($event, client)">
|
||||
<mat-icon>analytics</mat-icon>
|
||||
<span>Logs de cliente</span>
|
||||
<span>{{ 'clientLogs' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onDeleteClick($event, client)" *ngIf="auth.userCategory !== 'ou-minimal'">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'delete' | translate }}</span>
|
||||
<span>{{ 'buttonDelete' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, OnInit, OnDestroy, ViewChild, QueryList, ViewChildren, ChangeDetectorRef } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
|
|
@ -48,6 +50,7 @@ enum NodeType {
|
|||
styleUrls: ['./groups.component.css'],
|
||||
})
|
||||
export class GroupsComponent implements OnInit, OnDestroy {
|
||||
public translate = inject(TranslateService);
|
||||
@ViewChildren(MatMenuTrigger) menuTriggers!: QueryList<MatMenuTrigger>;
|
||||
isSmallScreen: boolean = false;
|
||||
baseUrl: string;
|
||||
|
|
@ -283,7 +286,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
// this.savedFilterNames = data.map((filter: { name: string; uuid: string; }) => [filter.name, filter.uuid]);
|
||||
// },
|
||||
// (error) => {
|
||||
// console.error('Error fetching filters:', error);
|
||||
// console.error(this.translate.instant('errorFetchingFilters1'), error);
|
||||
// }
|
||||
// )
|
||||
// );
|
||||
|
|
@ -297,7 +300,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
this.savedFilterNames = data.map((filter: { name: string; uuid: string; }) => [filter.name, filter.uuid]);
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching filters:', error);
|
||||
console.error(this.translate.instant('errorFetchingFilters1'), error);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
|
@ -350,8 +353,8 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error fetching organizational units', error);
|
||||
this.toastr.error('Ocurrió un error al cargar las unidades organizativas');
|
||||
console.error(this.translate.instant('errorFetchingOrganizationalUnits'), error);
|
||||
this.toastr.error(this.translate.instant('anErrorOccurredWhileLoading'));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -561,7 +564,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
console.log('Nodo padre encontrado para actualización:', parentNode);
|
||||
this.refreshData(parentNode.uuid);
|
||||
} else {
|
||||
console.error('No se encontró el nodo padre después de la creación masiva.');
|
||||
console.error(this.translate.instant('nodeNotFound'));
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
|
|
@ -635,7 +638,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error deleting entity:', error);
|
||||
console.error(this.translate.instant('errorDeletingEntity'), error);
|
||||
const entityType = type === NodeType.Client ? 'cliente' : 'entidad';
|
||||
this.toastr.error(`Error al eliminar el ${entityType}`);
|
||||
},
|
||||
|
|
@ -675,7 +678,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
},
|
||||
(error) => {
|
||||
console.error('Error fetching room data:', error);
|
||||
console.error(this.translate.instant('errorFetchingRoomData'), error);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
|
@ -685,7 +688,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
executeCommand(command: Command, selectedNode: TreeNode | null): void {
|
||||
this.loading = true;
|
||||
if (!selectedNode) {
|
||||
this.toastr.error('No hay un nodo seleccionado.');
|
||||
this.toastr.error(this.translate.instant('thereIsNoNodeSelected'));
|
||||
return;
|
||||
} else {
|
||||
this.toastr.success(`Ejecutando comando: ${command.name} en ${selectedNode.name}`);
|
||||
|
|
@ -834,7 +837,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
this.subscriptions.add(
|
||||
this.http.post(`${this.baseUrl}${client['@id']}/agent/status`, {}).subscribe(
|
||||
() => {
|
||||
this.toastr.success('Cliente actualizado correctamente');
|
||||
this.toastr.success(this.translate.instant('clientUpdatedSuccessfully'));
|
||||
this.syncingClientIds.delete(client.uuid);
|
||||
this.refreshData(parentNodeId)
|
||||
},
|
||||
|
|
@ -869,12 +872,12 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
this.arrayClients = this.selectedClients.data;
|
||||
this.calculateLocalStats();
|
||||
this.toastr.success('Estado del aula actualizado');
|
||||
this.toastr.success(this.translate.instant('classroomStatusUpdated'));
|
||||
},
|
||||
error: () => {
|
||||
this.isCheckingNodeStatus = false;
|
||||
this.selectedClients.data.forEach(c => c.uuid && this.syncingClientIds.delete(c.uuid));
|
||||
this.toastr.error('Error al comprobar el estado del aula');
|
||||
this.toastr.error(this.translate.instant('errorCheckingStatus'));
|
||||
},
|
||||
})
|
||||
);
|
||||
|
|
@ -1054,14 +1057,14 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
`);
|
||||
}
|
||||
} else {
|
||||
this.toastr.error('No se puede acceder a los logs: IP del cliente no disponible', 'Error');
|
||||
this.toastr.error(this.translate.instant('cannotAccess'), 'Error');
|
||||
}
|
||||
}
|
||||
|
||||
openClientLogsModal(event: MouseEvent, client: Client): void {
|
||||
event.stopPropagation();
|
||||
if (!client.mac) {
|
||||
this.toastr.error('No se puede acceder a los logs: MAC del cliente no disponible', 'Error');
|
||||
this.toastr.error(this.translate.instant('cantAccess1'), 'Error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1088,7 +1091,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
const allClients = response['hydra:member'] || [];
|
||||
|
||||
if (allClients.length === 0) {
|
||||
this.toastr.warning('Esta unidad organizativa no tiene clientes');
|
||||
this.toastr.warning(this.translate.instant('thisOrganizationalUnitDoesNotHave'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1113,8 +1116,8 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error al obtener los clientes de la unidad organizativa:', error);
|
||||
this.toastr.error('Error al cargar los clientes de la unidad organizativa');
|
||||
console.error(this.translate.instant('errorGettingClients1'), error);
|
||||
this.toastr.error(this.translate.instant('errorLoadingClients'));
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
|
|
@ -1135,7 +1138,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
|
||||
refreshClientData(): void {
|
||||
this.fetchClientsForNode(this.selectedNode);
|
||||
this.toastr.success('Datos actualizados', 'Éxito');
|
||||
this.toastr.success(this.translate.instant('updatedData'), 'Éxito');
|
||||
}
|
||||
|
||||
exportToCSV(): void {
|
||||
|
|
@ -1164,7 +1167,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
this.toastr.success('Archivo CSV exportado correctamente', 'Éxito');
|
||||
this.toastr.success(this.translate.instant('csvFileExportedSuccessfully'), 'Éxito');
|
||||
}
|
||||
|
||||
private calculateLocalStats(): void {
|
||||
|
|
@ -1318,7 +1321,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
event.stopPropagation();
|
||||
|
||||
if (this.selection.selected.length === 0) {
|
||||
this.toastr.warning('No hay clientes seleccionados para eliminar');
|
||||
this.toastr.warning(this.translate.instant('thereAreNoClientsSelectedFor'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1355,8 +1358,8 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||
},
|
||||
error: (error) => {
|
||||
this.loading = false;
|
||||
console.error('Error deleting multiple clients:', error);
|
||||
this.toastr.error('Error al eliminar los clientes seleccionados');
|
||||
console.error(this.translate.instant('errorDeletingMultipleClients1'), error);
|
||||
this.toastr.error(this.translate.instant('errorDeletingClients'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
|
|
@ -9,6 +11,7 @@ import { ConfigService } from '@services/config.service';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
public translate = inject(TranslateService);
|
||||
|
||||
baseUrl: string;
|
||||
private apiUrl: string;
|
||||
|
|
@ -35,7 +38,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching unidades organizativas', error);
|
||||
console.error(this.translate.instant('errorFetchingOrganizationalUnits'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -51,7 +54,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching children', error);
|
||||
console.error(this.translate.instant('errorFetchingChildren'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -67,7 +70,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching clients', error);
|
||||
console.error(this.translate.instant('errorFetchingClients'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -84,7 +87,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching clients', error);
|
||||
console.error(this.translate.instant('errorFetchingClients'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -101,7 +104,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching clients', error);
|
||||
console.error(this.translate.instant('errorFetchingClients'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -118,7 +121,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching clients', error);
|
||||
console.error(this.translate.instant('errorFetchingClients'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -132,7 +135,7 @@ export class DataService {
|
|||
console.log('DELETE URL:', url); // Depuración
|
||||
return this.http.delete<void>(url).pipe(
|
||||
catchError(error => {
|
||||
console.error('Error deleting element', error);
|
||||
console.error(this.translate.instant('errorDeletingElement'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -144,7 +147,7 @@ export class DataService {
|
|||
// @ts-ignore
|
||||
return this.http.post<void>(url).pipe(
|
||||
catchError(error => {
|
||||
console.error('Error deleting element', error);
|
||||
console.error(this.translate.instant('errorDeletingElement'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -185,7 +188,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching data', error);
|
||||
console.error(this.translate.instant('fetchingDataError'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -201,7 +204,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching filters', error);
|
||||
console.error(this.translate.instant('errorFetchingFilters'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -219,7 +222,7 @@ export class DataService {
|
|||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching filters', error);
|
||||
console.error(this.translate.instant('errorFetchingFilters'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -229,7 +232,7 @@ export class DataService {
|
|||
const url = `${this.baseUrl}/organizational-units/${id}`;
|
||||
return this.http.get<any>(url).pipe(
|
||||
catchError(error => {
|
||||
console.error('Error fetching organizational unit', error);
|
||||
console.error(this.translate.instant('errorFetchingOrganizationalUnit'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
@ -255,7 +258,7 @@ export class DataService {
|
|||
|
||||
return this.http.post<any>(url, body).pipe(
|
||||
catchError(error => {
|
||||
console.error('Error deleting multiple clients', error);
|
||||
console.error(this.translate.instant('errorDeletingMultipleClients'), error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<h2 mat-dialog-title>Mover clientes a:</h2>
|
||||
<h2 mat-dialog-title>{{ 'moveClientsTo' | translate }}</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Seleccione aula</mat-label>
|
||||
<mat-label>{{ 'selectClassroomPrompt' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="newOU">
|
||||
<mat-option *ngFor="let unit of units" [value]="unit">{{ unit.name }}</mat-option>
|
||||
</mat-select>
|
||||
|
|
@ -10,6 +10,6 @@
|
|||
</mat-dialog-content>
|
||||
|
||||
<div class="action-container">
|
||||
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||
<button class="submit-button" (click)="save()" [disabled]="!newOU">Continuar</button>
|
||||
<button class="ordinary-button" (click)="close()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" (click)="save()" [disabled]="!newOU">{{ 'buttonContinue' | translate }}</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
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";
|
||||
|
|
@ -11,6 +13,7 @@ import {ConfigService} from "@services/config.service";
|
|||
styleUrl: './change-parent.component.css'
|
||||
})
|
||||
export class ChangeParentComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
loading: boolean = true;
|
||||
units: any[] = [];
|
||||
|
|
@ -38,7 +41,7 @@ export class ChangeParentComponent implements OnInit {
|
|||
this.units = response['hydra:member'];
|
||||
this.loading = false;
|
||||
},
|
||||
error => console.error('Error fetching organizational units:', error)
|
||||
error => console.error(this.translate.instant('errorFetchingOrganizationalUnits1'), error)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +51,7 @@ export class ChangeParentComponent implements OnInit {
|
|||
organizationalUnit: this.newOU['@id']
|
||||
}).subscribe({
|
||||
next: (response) => {
|
||||
this.toastService.success('Parent changed successfully');
|
||||
this.toastService.success(this.translate.instant('parentChangedSuccessfully'));
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: error => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<div class="client-box" (dblclick)="handleClientClick(client)">
|
||||
<mat-card appearance="outlined">
|
||||
<div class="client-image-container">
|
||||
<img mat-card-image src="assets/images/client.png" alt="{{ 'clientAlt' | translate }}" class="client-image"/>
|
||||
<img mat-card-image src="assets/images/client.png" alt="{{ 'client' | translate }}" class="client-image"/>
|
||||
</div>
|
||||
<div class="client-info">
|
||||
<span><strong>{{ client.name }}</strong></span>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Input, OnInit, OnChanges } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ClientViewComponent } from "../client-view/client-view.component";
|
||||
|
|
@ -17,6 +19,7 @@ interface GroupedClients {
|
|||
styleUrls: ['./classroom-view.component.css']
|
||||
})
|
||||
export class ClassroomViewComponent implements OnInit, OnChanges {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
@Input() clients: any[] = [];
|
||||
@Input() pcInTable: number = 5;
|
||||
|
|
@ -93,7 +96,7 @@ export class ClassroomViewComponent implements OnInit, OnChanges {
|
|||
this.http.patch(url, payload).subscribe(response => {
|
||||
this.openSnackBar(false, 'Plano actualizado!');
|
||||
}, error => {
|
||||
console.error('Error al actualizar cliente:', error);
|
||||
console.error(this.translate.instant('errorUpdatingClient1'), error);
|
||||
this.openSnackBar(true, error);
|
||||
});
|
||||
});
|
||||
|
|
@ -103,8 +106,8 @@ export class ClassroomViewComponent implements OnInit, OnChanges {
|
|||
|
||||
openSnackBar(isError: boolean, message: string) {
|
||||
if (isError) {
|
||||
this.toastService.error(' Error al actualizar cliente: ' + message, 'Error');
|
||||
this.toastService.error(this.translate.instant('errorUpdatingClient') + message, 'Error');
|
||||
} else
|
||||
this.toastService.success('Cliente actualizado!', 'Éxito');
|
||||
this.toastService.success(this.translate.instant('updatedClient'), 'Éxito');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@
|
|||
</div>
|
||||
|
||||
<div class="notes-card">
|
||||
<div class="label">{{ 'notesLabel' | translate }}</div>
|
||||
<div class="label">{{ 'labelNotes' | translate }}</div>
|
||||
<div class="notes-value">{{ clientNotes || '--' }}</div>
|
||||
</div>
|
||||
|
||||
<div class="table-header-container">
|
||||
<h2 i18n="@@adminImagesTitle">Discos/Particiones</h2>
|
||||
<h2 i18n="@@adminImagesTitle">{{ 'labelDisksPartitions' | translate }}</h2>
|
||||
@if (clientData.firmwareType) {
|
||||
<mat-chip> {{ clientData.firmwareType }}</mat-chip>
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
<table mat-table [dataSource]="disk.partitions" class="disk-table">
|
||||
@for (column of columns; track column.columnDef) {
|
||||
<ng-container [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
@if (column.columnDef !== 'size' && column.columnDef !== 'operativeSystem') {
|
||||
{{ column.cell(image) }}
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
@if (column.columnDef === 'operativeSystem') {
|
||||
<div class="os-col-wrapper">
|
||||
@if (image.filesystem === 'CACHE' && image.cacheContent) {
|
||||
<span class="cache-title">Contenido:</span>
|
||||
<span class="cache-title">{{ 'labelContentColon' | translate }}</span>
|
||||
@for (item of parseCacheContent(image.cacheContent); track item.name) {
|
||||
<div class="cache-item">
|
||||
• {{ item.name }} ({{ item.size }})
|
||||
|
|
@ -121,5 +121,5 @@
|
|||
}
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'closeButton' | translate }}</button>
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonClose' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
|
@ -20,6 +22,7 @@ interface ClientInfo {
|
|||
styleUrl: './client-details.component.css'
|
||||
})
|
||||
export class ClientDetailsComponent {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
@ViewChild('assistantContainer') assistantContainer!: ElementRef;
|
||||
clientUuid: string;
|
||||
|
|
@ -43,32 +46,32 @@ export class ClientDetailsComponent {
|
|||
columns = [
|
||||
{
|
||||
columnDef: 'partition',
|
||||
header: 'Partición',
|
||||
header: 'labelPartition',
|
||||
cell: (partition: any) => `${partition.partitionNumber}`
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionCode',
|
||||
header: 'Tipo de partición',
|
||||
header: 'partitionType',
|
||||
cell: (partition: any) => partition.partitionCode
|
||||
},
|
||||
{
|
||||
columnDef: 'description',
|
||||
header: 'Sistema de ficheros',
|
||||
header: 'fileSystem',
|
||||
cell: (partition: any) => partition.filesystem
|
||||
},
|
||||
{
|
||||
columnDef: 'size',
|
||||
header: 'Tamaño',
|
||||
header: 'labelDiskSize',
|
||||
cell: (partition: any) => `${(partition.size / 1024).toFixed(2)} GB`
|
||||
},
|
||||
{
|
||||
columnDef: 'memoryUsage',
|
||||
header: 'Uso',
|
||||
header: 'use',
|
||||
cell: (partition: any) => `${partition.memoryUsage}%`
|
||||
},
|
||||
{
|
||||
columnDef: 'operativeSystem',
|
||||
header: 'SO/Imagen',
|
||||
header: 'soimage',
|
||||
cell: (partition: any) => partition.operativeSystem?.name
|
||||
}
|
||||
];
|
||||
|
|
@ -99,7 +102,7 @@ export class ClientDetailsComponent {
|
|||
this.loadPartitions();
|
||||
this.loading = false;
|
||||
} else {
|
||||
console.error('No se recibieron datos del cliente.');
|
||||
console.error(this.translate.instant('noDataWasReceivedFrom'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +193,7 @@ export class ClientDetailsComponent {
|
|||
this.calculateDiskUsage();
|
||||
},
|
||||
error: error => {
|
||||
console.error('Error al obtener las particiones:', error);
|
||||
console.error(this.translate.instant('errorGettingPartitions'), error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Logs de cliente - {{ data.client.name }}
|
||||
</h2>
|
||||
<div class="header-actions">
|
||||
<button mat-icon-button (click)="openGrafanaInNewTab()" matTooltip="Abrir en Grafana" class="grafana-button">
|
||||
<button mat-icon-button (click)="openGrafanaInNewTab()" [matTooltip]="'openInGrafana' | translate" class="grafana-button">
|
||||
<mat-icon>open_in_new</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
<div class="modal-content">
|
||||
<div class="client-info">
|
||||
<p><strong>Cliente:</strong> {{ data.client.name }}</p>
|
||||
<p><strong>IP:</strong> {{ data.client.ip }}</p>
|
||||
<p><strong>MAC:</strong> {{ data.client.mac }}</p>
|
||||
<p><strong>{{ 'labelClient' | translate }}</strong> {{ data.client.name }}</p>
|
||||
<p><strong>{{ 'labelIpColon' | translate }}</strong> {{ data.client.ip }}</p>
|
||||
<p><strong>{{ 'labelMacColon' | translate }}</strong> {{ data.client.mac }}</p>
|
||||
</div>
|
||||
|
||||
<div class="iframe-container">
|
||||
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
<div class="modal-actions">
|
||||
<button class="action-button" (click)="closeModal()">
|
||||
Cerrar
|
||||
</button>
|
||||
{{ 'buttonClose' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
<td mat-cell *matCellDef="let element" class="fixed-column"> {{ element.property }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelValue' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let element"> {{ element.value }} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<td mat-cell *matCellDef="let element" class="fixed-column"> {{ element.property }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelValue' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let element"> {{ element.value }} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<td mat-cell *matCellDef="let element" class="fixed-column"> {{ element.property }} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'valueHeader' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labelValue' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let element"> {{ element.value }} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
|
|
@ -52,5 +52,5 @@
|
|||
</mat-tab-group>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">{{ 'closeButton' | translate }}</button>
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">{{ 'buttonClose' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<form class="client-form grid-form" *ngIf="!loading">
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelOrganizationalUnit' | translate }}</mat-label>
|
||||
<mat-select (selectionChange)="setOrganizationalUnit($event)" [value]="organizationalUnit">
|
||||
<mat-select-trigger>
|
||||
{{ getSelectedParentName() }}
|
||||
|
|
@ -20,33 +20,33 @@
|
|||
|
||||
<div>
|
||||
<div class="upload-container">
|
||||
<button class="action-button" (click)="fileInput.click()">Subir fichero</button>
|
||||
<button class="action-button" (click)="fileInput.click()">{{ 'buttonUploadFile' | translate }}</button>
|
||||
<input #fileInput type="file" (change)="onFileUpload($event)" accept="*" hidden>
|
||||
<p>o añadelos manualmente:</p>
|
||||
<p>{{ 'orAddThemManually' | translate }}</p>
|
||||
<div *ngIf="showTextarea">
|
||||
<textarea #textarea matInput
|
||||
placeholder="Ejemplo: host bbaa-it1-11 { hardware ethernet a0:48:1c:8a:f1:5b; fixed-address 172.17.69.11; };"
|
||||
[placeholder]="'dhcpHostExample' | translate"
|
||||
rows="20" cols="100"></textarea>
|
||||
<button class="action-button" style="margin-top: 0.5em;"
|
||||
(click)="onTextarea(textarea.value)">Previsualizar</button>
|
||||
(click)="onTextarea(textarea.value)">{{ 'buttonPreview' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 *ngIf="uploadedClients.length > 0">Clientes importados:</h4>
|
||||
<h4 *ngIf="uploadedClients.length > 0">{{ 'importedClientsZero' | translate }}</h4>
|
||||
<div *ngIf="uploadedClients.length > 0" class="scrollable-table">
|
||||
<table mat-table [dataSource]="uploadedClients" class="mat-elevation-z8" *ngIf="uploadedClients.length > 0">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> Nombre </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelRoleName' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.name }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="ip">
|
||||
<th mat-header-cell *matHeaderCellDef> IP </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelIpCaps' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.ip }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="mac">
|
||||
<th mat-header-cell *matHeaderCellDef> Mac </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'labelMac' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let client"> {{ client.mac }} </td>
|
||||
</ng-container>
|
||||
|
||||
|
|
@ -59,7 +59,6 @@
|
|||
</div>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||
<button class="submit-button" [disabled]="!organizationalUnit" (click)="onSubmit()">{{ 'saveButton' | translate
|
||||
}}</button>
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" [disabled]="!organizationalUnit" (click)="onSubmit()">{{ 'labelSaveButton' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Component, Inject, OnInit, Optional } from '@angular/core';
|
||||
import { MatDialogRef } from "@angular/material/dialog";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
|
|
@ -12,6 +14,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrl: './create-multiple-client.component.css'
|
||||
})
|
||||
export class CreateMultipleClientComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string = this.configService.apiUrl;
|
||||
parentUnits: any[] = [];
|
||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||
|
|
@ -56,7 +59,7 @@ export class CreateMultipleClientComponent implements OnInit {
|
|||
this.loading = false;
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching parent units:', error);
|
||||
console.error(this.translate.instant('errorFetchingParentUnits'), error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
|
|
@ -91,10 +94,10 @@ export class CreateMultipleClientComponent implements OnInit {
|
|||
|
||||
if (clients.length > 0) {
|
||||
this.uploadedClients = clients;
|
||||
this.toastService.success('Archivo cargado correctamente, los datos están listos para enviarse.', 'Éxito');
|
||||
this.toastService.success(this.translate.instant('fileSuccessfullyUploadedData'), 'Éxito');
|
||||
this.showTextarea = false;
|
||||
} else {
|
||||
this.toastService.error('No se encontraron datos válidos', 'Error');
|
||||
this.toastService.error(this.translate.instant('notValidDataFound'), 'Error');
|
||||
this.showTextarea = true;
|
||||
}
|
||||
};
|
||||
|
|
@ -117,10 +120,10 @@ export class CreateMultipleClientComponent implements OnInit {
|
|||
|
||||
if (clients.length > 0) {
|
||||
this.uploadedClients = clients;
|
||||
this.toastService.success('Datos cargados correctamente, los datos están listos para enviarse.', 'Éxito');
|
||||
this.toastService.success(this.translate.instant('dataSuccessfullyLoadedData'), 'Éxito');
|
||||
this.showTextarea = false;
|
||||
} else {
|
||||
this.toastService.error('No se encontraron datos válidos', 'Error');
|
||||
this.toastService.error(this.translate.instant('notValidDataFound'), 'Error');
|
||||
this.showTextarea = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -154,7 +157,7 @@ export class CreateMultipleClientComponent implements OnInit {
|
|||
);
|
||||
});
|
||||
} else {
|
||||
this.toastService.error('No hay clientes cargados para añadir', 'Error');
|
||||
this.toastService.error(this.translate.instant('noClientsLoadedFor'), 'Error');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<form *ngIf="clientForm && !loading" [formGroup]="clientForm" class="client-form grid-form">
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'organizationalUnitLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelOrganizationalUnit' | translate }}</mat-label>
|
||||
<mat-select formControlName="organizationalUnit" (selectionChange)="onParentChange($event)">
|
||||
<mat-select-trigger>
|
||||
{{ getSelectedParentName() }}
|
||||
|
|
@ -20,17 +20,17 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'nameLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelRoleName' | translate }}</mat-label>
|
||||
<input matInput formControlName="name" required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'serialNumberLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelSerialNumber' | translate }}</mat-label>
|
||||
<input matInput formControlName="serialNumber">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'netifaceLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelNetiface' | translate }}</mat-label>
|
||||
<mat-select formControlName="netiface">
|
||||
@for (type of netifaceTypes; track type.value) {
|
||||
<mat-option [value]="type.value">{{ type.name }}</mat-option>
|
||||
|
|
@ -39,19 +39,19 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'macLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelMac' | translate }}</mat-label>
|
||||
<input matInput formControlName="mac" required>
|
||||
<mat-error>{{ 'macError' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'ipLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelIp' | translate }}</mat-label>
|
||||
<input matInput formControlName="ip" required>
|
||||
<mat-error>{{ 'ipError' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'repositoryLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelRepository' | translate }}</mat-label>
|
||||
<mat-select formControlName="repository">
|
||||
@for (repository of repositories; track repository['@id']) {
|
||||
<mat-option [value]="repository['@id']">{{ repository.name }}</mat-option>
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'menuLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelMenu' | translate }}</mat-label>
|
||||
<mat-select formControlName="menu">
|
||||
@for (menu of menus; track menu['@id']) {
|
||||
<mat-option [value]="menu['@id']">{{ menu.name }}</mat-option>
|
||||
|
|
@ -70,20 +70,20 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'resolutionLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelResolution' | translate }}</mat-label>
|
||||
<mat-select formControlName="resolution" required>
|
||||
<mat-option value="769">640×480 (8-bit - 256 colores)</mat-option>
|
||||
<mat-option value="771">800×600 (8-bit - 256 colores)</mat-option>
|
||||
<mat-option value="773">1024×768 (8-bit - 256 colores)</mat-option>
|
||||
<mat-option value="775">1280×1024 (8-bit - 256 colores)</mat-option>
|
||||
<mat-option value="784">640×480 (16-bit - 65k colores)</mat-option>
|
||||
<mat-option value="787">800×600 (16-bit - 65k colores)</mat-option>
|
||||
<mat-option value="791">1024×768 (16-bit - 65k colores)</mat-option>
|
||||
<mat-option value="794">1280×1024 (16-bit - 65k colores)</mat-option>
|
||||
<mat-option value="785">640×480 (24-bit - 16M colores)</mat-option>
|
||||
<mat-option value="788">800×600 (24-bit - 16M colores)</mat-option>
|
||||
<mat-option value="792">1024×768 (24-bit - 16M colores)</mat-option>
|
||||
<mat-option value="795">1280×1024 (24-bit - 16M colores)</mat-option>
|
||||
<mat-option value="769">{{ 'resolution640x480x8' | translate }}</mat-option>
|
||||
<mat-option value="771">{{ 'resolution800x600x8' | translate }}</mat-option>
|
||||
<mat-option value="773">{{ 'resolution1024x768x8' | translate }}</mat-option>
|
||||
<mat-option value="775">{{ 'resolution1280x1024x8' | translate }}</mat-option>
|
||||
<mat-option value="784">{{ 'resolution640x480x16' | translate }}</mat-option>
|
||||
<mat-option value="787">{{ 'resolution800x600x16' | translate }}</mat-option>
|
||||
<mat-option value="791">{{ 'resolution1024x768x16' | translate }}</mat-option>
|
||||
<mat-option value="794">{{ 'resolution1280x1024x16' | translate }}</mat-option>
|
||||
<mat-option value="785">{{ 'resolution640x480x24' | translate }}</mat-option>
|
||||
<mat-option value="788">{{ 'resolution800x600x24' | translate }}</mat-option>
|
||||
<mat-option value="792">{{ 'resolution1024x768x24' | translate }}</mat-option>
|
||||
<mat-option value="795">{{ 'resolution1280x1024x24' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>{{ 'resolutionError' | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
|
@ -94,11 +94,11 @@
|
|||
|
||||
<!-- ===== Agrupación: Configuración de arranque ===== -->
|
||||
<fieldset class="boot-group">
|
||||
<legend class="boot-group-legend">Configuración de arranque</legend>
|
||||
<legend class="boot-group-legend">{{ 'bootConfiguration' | translate }}</legend>
|
||||
<div class="boot-group-grid">
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>Servidor Boot</mat-label>
|
||||
<mat-label>{{ 'bootServer' | translate }}</mat-label>
|
||||
<mat-select formControlName="bootServer" (selectionChange)="onBootServerChange($event)">
|
||||
@for (server of bootServers; track server['@id']) {
|
||||
<mat-option [value]="server['@id']">{{ server.name }}</mat-option>
|
||||
|
|
@ -107,25 +107,25 @@
|
|||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'ogLiveLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelOgLive' | translate }}</mat-label>
|
||||
<mat-select formControlName="ogLive">
|
||||
@for (ogLive of ogLives; track ogLive['@id']) {
|
||||
<mat-option [value]="ogLive['@id']">{{ ogLive.name }}</mat-option>
|
||||
}
|
||||
@if (ogLives.length === 0 && clientForm.get('bootServer')?.value) {
|
||||
<mat-option disabled>No hay OgLives en este servidor</mat-option>
|
||||
<mat-option disabled>{{ 'noOgLivesInServer' | translate }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="form-field">
|
||||
<mat-label>{{ 'templateLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelTemplate' | translate }}</mat-label>
|
||||
<mat-select formControlName="pxeTemplate">
|
||||
@for (template of templates; track template['@id']) {
|
||||
<mat-option [value]="template['@id']">{{ template.name }}</mat-option>
|
||||
}
|
||||
@if (templates.length === 0 && clientForm.get('bootServer')?.value) {
|
||||
<mat-option disabled>No hay plantillas en este servidor</mat-option>
|
||||
<mat-option disabled>{{ 'noTemplatesInServer' | translate }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
</fieldset>
|
||||
|
||||
<mat-form-field class="form-field full-width">
|
||||
<mat-label>{{ 'notesLabel' | translate }}</mat-label>
|
||||
<mat-label>{{ 'labelNotes' | translate }}</mat-label>
|
||||
<textarea matInput formControlName="notes" rows="4"
|
||||
[placeholder]="'notesPlaceholder' | translate"></textarea>
|
||||
</mat-form-field>
|
||||
|
|
@ -142,7 +142,7 @@
|
|||
</div>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'cancelButton' | translate }}</button>
|
||||
<button class="ordinary-button" (click)="onNoClick()">{{ 'buttonCancel' | translate }}</button>
|
||||
<button class="submit-button" [disabled]="!clientForm.valid" (click)="onSubmit()">
|
||||
{{ isEditMode ? 'Guardar' : 'Crear' }}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
|
@ -12,6 +14,7 @@ import { ConfigService } from '@services/config.service';
|
|||
styleUrls: ['./manage-client.component.css']
|
||||
})
|
||||
export class ManageClientComponent implements OnInit {
|
||||
public translate = inject(TranslateService);
|
||||
baseUrl: string;
|
||||
clientForm!: FormGroup;
|
||||
parentUnits: any[] = [];
|
||||
|
|
@ -66,7 +69,7 @@ export class ManageClientComponent implements OnInit {
|
|||
this.loading = false;
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('Error loading data:', error);
|
||||
console.error(this.translate.instant('errorLoadingData'), error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
|
@ -122,7 +125,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching parent units:', error);
|
||||
console.error(this.translate.instant('errorFetchingParentUnits'), error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -145,7 +148,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching ogLives by server:', error);
|
||||
console.error(this.translate.instant('errorFetchingOglivesByServer'), error);
|
||||
this.ogLives = [];
|
||||
resolve(); // resolve anyway so form doesn't block
|
||||
}
|
||||
|
|
@ -163,7 +166,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching PXE templates by server:', error);
|
||||
console.error(this.translate.instant('errorFetchingPxeTemplatesBy'), error);
|
||||
this.templates = [];
|
||||
resolve();
|
||||
}
|
||||
|
|
@ -181,7 +184,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching BootServers:', error);
|
||||
console.error(this.translate.instant('fetchingBootserversError'), error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -212,7 +215,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching menus:', error);
|
||||
console.error(this.translate.instant('errorFetchingMenus1'), error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -229,7 +232,7 @@ export class ManageClientComponent implements OnInit {
|
|||
resolve();
|
||||
},
|
||||
error => {
|
||||
console.error('Error fetching repositories:', error);
|
||||
console.error(this.translate.instant('fetchingRepositories1Error'), error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -313,7 +316,7 @@ export class ManageClientComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
error => {
|
||||
console.error('Error al cargar datos del cliente:', error);
|
||||
console.error(this.translate.instant('errorLoadingData'), error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
|
|
@ -331,17 +334,17 @@ export class ManageClientComponent implements OnInit {
|
|||
this.http.patch<any>(putUrl, formData, { headers }).subscribe(
|
||||
response => {
|
||||
this.dialogRef.close({ success: true });
|
||||
this.toastService.success('Cliente actualizado exitosamente', 'Éxito');
|
||||
this.toastService.success(this.translate.instant('clientUpdatedSuccessfully'), 'Éxito');
|
||||
},
|
||||
error => {
|
||||
console.error('Error al realizar PUT:', error);
|
||||
this.toastService.error('Error al actualizar el cliente: ' + error.error['hydra:description'], 'Error');
|
||||
console.error(this.translate.instant('errorWhenMakingPut'), error);
|
||||
this.toastService.error(this.translate.instant('errorUpdatingClient') + error.error['hydra:description'], 'Error');
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.http.post(`${this.baseUrl}/clients`, formData).subscribe(
|
||||
(response) => {
|
||||
this.toastService.success('Cliente creado exitosamente', 'Éxito');
|
||||
this.toastService.success(this.translate.instant('clientCreatedSuccessfully'), 'Éxito');
|
||||
this.dialogRef.close({
|
||||
success: true,
|
||||
client: response,
|
||||
|
|
@ -354,7 +357,7 @@ export class ManageClientComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
this.toastService.error('Formulario inválido. Por favor, revise los campos obligatorios.', 'Error');
|
||||
this.toastService.error(this.translate.instant('invalidFormPleaseReview'), 'Error');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@
|
|||
}">
|
||||
{{ isCompleteSuccess ? 'check_circle' : isPartialSuccess ? 'warning' : 'error' }}
|
||||
</mat-icon>
|
||||
Resultados de Eliminación
|
||||
</h2>
|
||||
{{ 'deletionResults' | translate }}</h2>
|
||||
<button mat-icon-button (click)="onClose()" class="close-button">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
|
@ -50,7 +49,7 @@
|
|||
<!-- Lista de errores si los hay -->
|
||||
<div class="error-list" *ngIf="hasErrors">
|
||||
<h4>
|
||||
<mat-icon>error</mat-icon>
|
||||
<mat-icon>{{ 'labelError' | translate }}</mat-icon>
|
||||
Errores Encontrados ({{ errorCount }})
|
||||
</h4>
|
||||
<div class="error-details">
|
||||
|
|
@ -68,7 +67,6 @@
|
|||
<div mat-dialog-actions class="modal-actions">
|
||||
<button mat-button (click)="onClose()" class="close-btn">
|
||||
<mat-icon>close</mat-icon>
|
||||
Cerrar
|
||||
</button>
|
||||
{{ 'buttonClose' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<table mat-table [dataSource]="disk.partitions" class="disk-table">
|
||||
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: start">Seleccionar</th>
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: start">{{ 'buttonSelect' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group [ngModel]="selectedPartition" (ngModelChange)="onPartitionSelected($event)"
|
||||
name="selectedPartitionGroup" [disabled]="readonly || disableCondition(row)">
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
@for (column of columns; track column.columnDef) {
|
||||
<ng-container [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header | translate }} </th>
|
||||
<td mat-cell *matCellDef="let partition">
|
||||
@if (column.columnDef === 'size') {
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
@else if (column.columnDef === 'operativeSystem') {
|
||||
<div class="os-col-wrapper">
|
||||
@if (partition.filesystem === 'CACHE' && partition.cacheContent) {
|
||||
<span class="cache-title">Contenido:</span>
|
||||
<span class="cache-title">{{ 'labelContentColon' | translate }}</span>
|
||||
@for (item of parseCacheContent(partition.cacheContent); track item.name) {
|
||||
<div class="cache-item">
|
||||
• {{ item.name }} ({{ item.size }})
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ import { MatCardModule } from '@angular/material/card';
|
|||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { TranslateModule, TranslatePipe } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-disk-partition-selector',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MatCardModule, MatTableModule, MatRadioModule, FormsModule],
|
||||
imports: [CommonModule, MatCardModule, MatTableModule, MatRadioModule, FormsModule, TranslatePipe],
|
||||
templateUrl: './disk-partition-selector.component.html',
|
||||
styleUrl: './disk-partition-selector.component.css'
|
||||
})
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue