commit
7bff91aa42
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,21 +1,37 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
## [0.10.0] - 2025-3-25
|
||||||
|
### Added
|
||||||
|
- Nuevo componenten de estado global.
|
||||||
|
- Servicio para que el ogGui obtenga de forma dinamica las variables de entorno.
|
||||||
|
- Nueva funcionalidad para convertir imagen en imagen virtual.
|
||||||
|
- Nueva funcionalidad para importar imágenes externas al sistema.
|
||||||
|
- Despliegue de imangenes sin cache. Cambios en el formulario de "despliegue".
|
||||||
|
|
||||||
|
### Improved
|
||||||
|
- Mejoras en la internacionalización.
|
||||||
|
- Nueva UX ogRepository. Ahora se gestionan las imagenes de forma mas sencilla.
|
||||||
|
- Cambios en ogLive. Mejora en la sincronizacion y obtención de datos en la API
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Cambios en la expresion regular para la validacion de documentos DHCP en la carga masiva de pc.
|
||||||
|
|
||||||
## [0.9.2] - 2025-03-19
|
## [0.9.2] - 2025-03-19
|
||||||
### Changed
|
### Changed
|
||||||
- Jenkinsfile to pubilsh packages in repo in case og release
|
- Jenkinsfile to pubilsh packages in repo in case og release
|
||||||
|
|
||||||
## [0.9.1] - 2025-03-12
|
## [0.9.1] - 2025-03-12
|
||||||
### ⚡ Changed
|
### Changed
|
||||||
- Se ha modificado el acceso a Mercure añadiendo nueva variable de entorno.
|
- Se ha modificado el acceso a Mercure añadiendo nueva variable de entorno.
|
||||||
|
|
||||||
|
|
||||||
## [0.9.0] - 2025-3-4
|
## [0.9.0] - 2025-3-4
|
||||||
### 🔹 Added
|
### Added
|
||||||
- Integracion con Mercure. Subscriber tanto en "Trazas" con en "Clientes".
|
- Integracion con Mercure. Subscriber tanto en "Trazas" con en "Clientes".
|
||||||
- Nueva funcionalidad para checkear la integridad de una imagen. Boton en apartado "imagenes" dentro del repositorio.
|
- Nueva funcionalidad para checkear la integridad de una imagen. Boton en apartado "imagenes" dentro del repositorio.
|
||||||
- Centralizacion de estilos.
|
- Centralizacion de estilos.
|
||||||
- Nueva funcionalidad para realizar backup de imágenes.
|
- Nueva funcionalidad para realizar backup de imágenes.
|
||||||
|
- Botón para cancelar despliegues de imagenes. Aparece en "trazas" tan solo para los comendos "deploy" y para el estado "en progreso".
|
||||||
|
|
||||||
### ⚡ Changed
|
### Changed
|
||||||
- Nueva interfaz en "Grupos". Se ha aprovechado mejor el espacio y acortado el tamaño de las filas, para poder tener mas elementos por pantalla.
|
- Nueva interfaz en "Grupos". Se ha aprovechado mejor el espacio y acortado el tamaño de las filas, para poder tener mas elementos por pantalla.
|
||||||
- Cambios en filtros de "Grupos". Ahora se pueden filtrar por "Centro" y "Unidad Organizativa" y estado. Ahora se busca en base de datos, y no en una lista de clientes dados.
|
- Cambios en filtros de "Grupos". Ahora se pueden filtrar por "Centro" y "Unidad Organizativa" y estado. Ahora se busca en base de datos, y no en una lista de clientes dados.
|
||||||
- Refactorizados compontentes de crear/editar clientes en uno solo.
|
- Refactorizados compontentes de crear/editar clientes en uno solo.
|
||||||
|
@ -23,22 +39,18 @@
|
||||||
- Para gestionar/añadir clientes a subredes ahora tenemos un botón para "añadir todos" y tan solo nos aparecn los equipos que no estén previamente asignados en una subred.
|
- Para gestionar/añadir clientes a subredes ahora tenemos un botón para "añadir todos" y tan solo nos aparecn los equipos que no estén previamente asignados en una subred.
|
||||||
|
|
||||||
## [0.7.0] - 2024-12-10
|
## [0.7.0] - 2024-12-10
|
||||||
|
|
||||||
### Refactored
|
### Refactored
|
||||||
- Refactored the group screen, removing the separate tabs for clients, advanced search, and organizational units.
|
- Refactored the group screen, removing the separate tabs for clients, advanced search, and organizational units.
|
||||||
- Added support for partitioning functionality in the client detail view.
|
- Added support for partitioning functionality in the client detail view.
|
||||||
- Boton para cancelar despliegues de imagenes. Aparece en "trazas" tan solo para los comendos "deploy" y para el estado "en progreos".
|
|
||||||
|
|
||||||
## [0.6.1] - 2024-11-19
|
## [0.6.1] - 2024-11-19
|
||||||
|
|
||||||
### Improved
|
### Improved
|
||||||
- Introduced a new automatic sync mode for the ogdhcp and ogBoot components.
|
- Introduced a new automatic sync mode for the ogdhcp and ogBoot components.
|
||||||
- Improve test coverage.
|
- Improve test coverage.
|
||||||
- New view for clients inside the classroom on the main page.
|
- New view for clients inside the classroom on the main page.
|
||||||
|
|
||||||
## [0.6.0] - 2024-11-19
|
## [0.6.0] - 2024-11-19
|
||||||
|
### Added
|
||||||
### 🔹 Added
|
|
||||||
- Added functionality to execute actions from the menu in the general groups screen.
|
- Added functionality to execute actions from the menu in the general groups screen.
|
||||||
- Displayed the selected center on the general screen for better context.
|
- Displayed the selected center on the general screen for better context.
|
||||||
- Implemented the option to collapse the sidebar for improved usability.
|
- Implemented the option to collapse the sidebar for improved usability.
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
NG_APP_BASE_API_URL=https://127.0.0.1:8443
|
# NG_APP_BASE_API_URL=https://127.0.0.1:8443
|
||||||
NG_APP_OGCORE_MERCURE_BASE_URL=http://localhost:3000/.well-known/mercure
|
# NG_APP_OGCORE_MERCURE_BASE_URL=http://localhost:3000/.well-known/mercure
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
NG_APP_BASE_API_URL=https://localhost:8443
|
||||||
|
NG_APP_OGCORE_MERCURE_BASE_URL=http://localhost:3000/.well-known/mercure
|
|
@ -41,3 +41,5 @@ testem.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
test-results/
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,6 @@
|
||||||
"newProjectRoot": "projects",
|
"newProjectRoot": "projects",
|
||||||
"projects": {
|
"projects": {
|
||||||
"ogWebconsole": {
|
"ogWebconsole": {
|
||||||
"i18n": {
|
|
||||||
"sourceLocale": "es",
|
|
||||||
"locales": {
|
|
||||||
"en": "src/locale/en.json"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"@schematics/angular:component": {
|
"@schematics/angular:component": {
|
||||||
|
@ -30,7 +24,7 @@
|
||||||
"builder": "@ngx-env/builder:application",
|
"builder": "@ngx-env/builder:application",
|
||||||
"options": {
|
"options": {
|
||||||
"baseHref": "/oggui/",
|
"baseHref": "/oggui/",
|
||||||
"localize": true,
|
"localize": false,
|
||||||
"aot": true,
|
"aot": true,
|
||||||
"outputPath": "dist/og-webconsole",
|
"outputPath": "dist/og-webconsole",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
|
@ -48,13 +42,16 @@
|
||||||
"input": "src/locale",
|
"input": "src/locale",
|
||||||
"output": "/locale"
|
"output": "/locale"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/custom-theme.scss",
|
"src/custom-theme.scss",
|
||||||
"src/styles.css",
|
"src/styles.css",
|
||||||
"node_modules/ngx-toastr/toastr.css"
|
"node_modules/ngx-toastr/toastr.css"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": [],
|
||||||
|
"allowedCommonJsDependencies": [
|
||||||
|
"rfdc"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
@ -66,7 +63,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
"maximumWarning": "4kb",
|
"maximumWarning": "7kb",
|
||||||
"maximumError": "10kb"
|
"maximumError": "10kb"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -76,16 +73,6 @@
|
||||||
"optimization": false,
|
"optimization": false,
|
||||||
"extractLicenses": false,
|
"extractLicenses": false,
|
||||||
"sourceMap": false
|
"sourceMap": false
|
||||||
},
|
|
||||||
"es": {
|
|
||||||
"localize": [
|
|
||||||
"es-ES"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"en": {
|
|
||||||
"localize": [
|
|
||||||
"en-US"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "production"
|
"defaultConfiguration": "production"
|
||||||
|
@ -104,29 +91,16 @@
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"buildTarget": "ogWebconsole:build:development"
|
"buildTarget": "ogWebconsole:build:development"
|
||||||
},
|
|
||||||
"es": {
|
|
||||||
"buildTarget": "ogWebconsole:build:es"
|
|
||||||
},
|
|
||||||
"en": {
|
|
||||||
"buildTarget": "ogWebconsole:build:en"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
},
|
},
|
||||||
"extract-i18n": {
|
|
||||||
"builder": "@ngx-env/builder:extract-i18n",
|
|
||||||
"options": {
|
|
||||||
"buildTarget": "ogWebconsole:build"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test": {
|
"test": {
|
||||||
"builder": "@ngx-env/builder:karma",
|
"builder": "@ngx-env/builder:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"polyfills": [
|
"polyfills": [
|
||||||
"zone.js",
|
"zone.js",
|
||||||
"zone.js/testing",
|
"zone.js/testing"
|
||||||
"@angular/localize/init"
|
|
||||||
],
|
],
|
||||||
"tsConfig": "tsconfig.spec.json",
|
"tsConfig": "tsconfig.spec.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
|
|
|
@ -65,7 +65,6 @@ const routes: Routes = [
|
||||||
{ path: 'clients/partition-assistant', component: PartitionAssistantComponent },
|
{ path: 'clients/partition-assistant', component: PartitionAssistantComponent },
|
||||||
{ path: 'clients/:id', component: ClientMainViewComponent },
|
{ path: 'clients/:id', component: ClientMainViewComponent },
|
||||||
{ path: 'clients/:id/create-image', component: CreateClientImageComponent },
|
{ path: 'clients/:id/create-image', component: CreateClientImageComponent },
|
||||||
{ path: 'images', component: ImagesComponent },
|
|
||||||
{ path: 'repositories', component: RepositoriesComponent },
|
{ path: 'repositories', component: RepositoriesComponent },
|
||||||
{ path: 'repository/:id', component: MainRepositoryViewComponent },
|
{ path: 'repository/:id', component: MainRepositoryViewComponent },
|
||||||
{ path: 'software', component: SoftwareComponent },
|
{ path: 'software', component: SoftwareComponent },
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, LOCALE_ID, APP_INITIALIZER } from '@angular/core';
|
||||||
|
import { ConfigService } from './services/config.service';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
@ -101,7 +102,7 @@ import { OperativeSystemComponent } from './components/operative-system/operativ
|
||||||
import { CreateOperativeSystemComponent } from './components/operative-system/create-operative-system/create-operative-system.component';
|
import { CreateOperativeSystemComponent } from './components/operative-system/create-operative-system/create-operative-system.component';
|
||||||
import { ShowTemplateContentComponent } from './components/ogboot/pxe/show-template-content/show-template-content.component';
|
import { ShowTemplateContentComponent } from './components/ogboot/pxe/show-template-content/show-template-content.component';
|
||||||
import { RepositoriesComponent } from './components/repositories/repositories.component';
|
import { RepositoriesComponent } from './components/repositories/repositories.component';
|
||||||
import { CreateRepositoryComponent } from './components/repositories/create-repository/create-repository.component';
|
import { ManageRepositoryComponent } from './components/repositories/manage-repository/manage-repository.component';
|
||||||
import { ExecuteCommandComponent } from './components/commands/main-commands/execute-command/execute-command.component';
|
import { ExecuteCommandComponent } from './components/commands/main-commands/execute-command/execute-command.component';
|
||||||
import { DeployImageComponent } from './components/groups/components/client-main-view/deploy-image/deploy-image.component';
|
import { DeployImageComponent } from './components/groups/components/client-main-view/deploy-image/deploy-image.component';
|
||||||
import { MainRepositoryViewComponent } from './components/repositories/main-repository-view/main-repository-view.component';
|
import { MainRepositoryViewComponent } from './components/repositories/main-repository-view/main-repository-view.component';
|
||||||
|
@ -129,10 +130,24 @@ import { AddClientsToSubnetComponent } from "./components/ogdhcp/add-clients-to-
|
||||||
import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component';
|
import { ShowClientsComponent } from './components/ogdhcp/show-clients/show-clients.component';
|
||||||
import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component';
|
import { OperationResultDialogComponent } from './components/ogdhcp/operation-result-dialog/operation-result-dialog.component';
|
||||||
import { ManageClientComponent } from './components/groups/shared/clients/manage-client/manage-client.component';
|
import { ManageClientComponent } from './components/groups/shared/clients/manage-client/manage-client.component';
|
||||||
|
import { ConvertImageComponent } from './components/repositories/convert-image/convert-image.component';
|
||||||
|
import { registerLocaleData } from '@angular/common';
|
||||||
|
import localeEs from '@angular/common/locales/es';
|
||||||
|
import { GlobalStatusComponent } from './components/global-status/global-status.component';
|
||||||
|
import { ShowImagesComponent } from './components/repositories/show-images/show-images.component';
|
||||||
|
import { StatusTabComponent } from './components/global-status/status-tab/status-tab.component';
|
||||||
|
import { ConvertImageToVirtualComponent } from './components/repositories/convert-image-to-virtual/convert-image-to-virtual.component';
|
||||||
|
|
||||||
export function HttpLoaderFactory(http: HttpClient) {
|
export function HttpLoaderFactory(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initializeApp(configService: ConfigService) {
|
||||||
|
return () => configService.loadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocaleData(localeEs, 'es-ES');
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
|
@ -195,7 +210,7 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
CreateOperativeSystemComponent,
|
CreateOperativeSystemComponent,
|
||||||
ShowTemplateContentComponent,
|
ShowTemplateContentComponent,
|
||||||
RepositoriesComponent,
|
RepositoriesComponent,
|
||||||
CreateRepositoryComponent,
|
ManageRepositoryComponent,
|
||||||
ExecuteCommandComponent,
|
ExecuteCommandComponent,
|
||||||
ExecuteCommandOuComponent,
|
ExecuteCommandOuComponent,
|
||||||
DeployImageComponent,
|
DeployImageComponent,
|
||||||
|
@ -213,7 +228,12 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
ManageOrganizationalUnitComponent,
|
ManageOrganizationalUnitComponent,
|
||||||
BackupImageComponent,
|
BackupImageComponent,
|
||||||
ShowClientsComponent,
|
ShowClientsComponent,
|
||||||
OperationResultDialogComponent
|
OperationResultDialogComponent,
|
||||||
|
ConvertImageComponent,
|
||||||
|
GlobalStatusComponent,
|
||||||
|
ShowImagesComponent,
|
||||||
|
StatusTabComponent,
|
||||||
|
ConvertImageToVirtualComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
imports: [BrowserModule,
|
imports: [BrowserModule,
|
||||||
|
@ -273,8 +293,16 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
useClass: CustomInterceptor,
|
useClass: CustomInterceptor,
|
||||||
multi: true
|
multi: true
|
||||||
},
|
},
|
||||||
|
{ provide: LOCALE_ID, useValue: 'es-ES' },
|
||||||
provideAnimationsAsync(),
|
provideAnimationsAsync(),
|
||||||
provideHttpClient(withInterceptorsFromDi())
|
provideHttpClient(withInterceptorsFromDi()),
|
||||||
|
ConfigService,
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: initializeApp,
|
||||||
|
deps: [ConfigService],
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -13,12 +13,17 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { ToastrModule, ToastrService } from 'ngx-toastr';
|
import { ToastrModule, ToastrService } from 'ngx-toastr';
|
||||||
import { DataService } from '../users/users/data.service';
|
import { DataService } from '../users/users/data.service';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('EnvVarsComponent', () => {
|
describe('EnvVarsComponent', () => {
|
||||||
let component: EnvVarsComponent;
|
let component: EnvVarsComponent;
|
||||||
let fixture: ComponentFixture<EnvVarsComponent>;
|
let fixture: ComponentFixture<EnvVarsComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [EnvVarsComponent],
|
declarations: [EnvVarsComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -47,6 +52,10 @@ describe('EnvVarsComponent', () => {
|
||||||
{
|
{
|
||||||
provide: MAT_DIALOG_DATA,
|
provide: MAT_DIALOG_DATA,
|
||||||
useValue: {}
|
useValue: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: ConfigService,
|
||||||
|
useValue: mockConfigService
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-env-vars',
|
selector: 'app-env-vars',
|
||||||
|
@ -8,16 +9,17 @@ import {ToastrService} from "ngx-toastr";
|
||||||
styleUrl: './env-vars.component.css'
|
styleUrl: './env-vars.component.css'
|
||||||
})
|
})
|
||||||
export class EnvVarsComponent {
|
export class EnvVarsComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
|
||||||
envVars: { name: string; value: string }[] = [];
|
envVars: { name: string; value: string }[] = [];
|
||||||
displayedColumns: string[] = ['name', 'value'];
|
displayedColumns: string[] = ['name', 'value'];
|
||||||
|
private apiUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/env-vars`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
) {}
|
private configService: ConfigService
|
||||||
|
) {
|
||||||
|
this.apiUrl = `${this.configService.apiUrl}/env-vars`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadEnvVars();
|
this.loadEnvVars();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||||
import {DataService} from "../data.service";
|
import {DataService} from "../data.service";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-role-modal',
|
selector: 'app-add-role-modal',
|
||||||
|
@ -11,9 +12,9 @@ import {ToastrService} from "ngx-toastr";
|
||||||
styleUrls: ['./add-role-modal.component.css']
|
styleUrls: ['./add-role-modal.component.css']
|
||||||
})
|
})
|
||||||
export class AddRoleModalComponent {
|
export class AddRoleModalComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
|
||||||
roleForm: FormGroup<any>;
|
roleForm: FormGroup<any>;
|
||||||
roleId: string | null = null;
|
roleId: string | null = null;
|
||||||
|
baseUrl: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: MatDialogRef<AddRoleModalComponent>,
|
public dialogRef: MatDialogRef<AddRoleModalComponent>,
|
||||||
|
@ -21,8 +22,10 @@ export class AddRoleModalComponent {
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.roleForm = this.fb.group({
|
this.roleForm = this.fb.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
superAdmin: [false],
|
superAdmin: [false],
|
||||||
|
|
|
@ -2,15 +2,19 @@ import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/user-groups?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/user-groups?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getUserGroups(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
getUserGroups(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { DataService } from './data.service';
|
import { DataService } from './data.service';
|
||||||
import { of } from 'rxjs';
|
import { ConfigService } from '@services/config.service';
|
||||||
import { MatDivider } from '@angular/material/divider';
|
import { MatDivider } from '@angular/material/divider';
|
||||||
import { MatFormField } from '@angular/material/form-field';
|
import { MatFormField } from '@angular/material/form-field';
|
||||||
import { MatLabel } from '@angular/material/form-field';
|
import { MatLabel } from '@angular/material/form-field';
|
||||||
|
@ -20,12 +20,14 @@ describe('RolesComponent', () => {
|
||||||
let mockHttpClient: jasmine.SpyObj<HttpClient>;
|
let mockHttpClient: jasmine.SpyObj<HttpClient>;
|
||||||
let mockToastrService: jasmine.SpyObj<ToastrService>;
|
let mockToastrService: jasmine.SpyObj<ToastrService>;
|
||||||
let mockDataService: jasmine.SpyObj<DataService>;
|
let mockDataService: jasmine.SpyObj<DataService>;
|
||||||
|
let mockConfigService: jasmine.SpyObj<ConfigService>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const matDialogSpy = jasmine.createSpyObj('MatDialog', ['open']);
|
const matDialogSpy = jasmine.createSpyObj('MatDialog', ['open']);
|
||||||
const httpClientSpy = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
|
const httpClientSpy = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
|
||||||
const toastrServiceSpy = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
const toastrServiceSpy = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
||||||
const dataServiceSpy = jasmine.createSpyObj('DataService', ['getRoles']);
|
const dataServiceSpy = jasmine.createSpyObj('DataService', ['getRoles']);
|
||||||
|
const configServiceSpy = jasmine.createSpyObj('ConfigService', [], { apiUrl: 'http://mock-api-url' });
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [RolesComponent, LoadingComponent],
|
declarations: [RolesComponent, LoadingComponent],
|
||||||
|
@ -35,7 +37,8 @@ describe('RolesComponent', () => {
|
||||||
{ provide: MatDialog, useValue: matDialogSpy },
|
{ provide: MatDialog, useValue: matDialogSpy },
|
||||||
{ provide: HttpClient, useValue: httpClientSpy },
|
{ provide: HttpClient, useValue: httpClientSpy },
|
||||||
{ provide: ToastrService, useValue: toastrServiceSpy },
|
{ provide: ToastrService, useValue: toastrServiceSpy },
|
||||||
{ provide: DataService, useValue: dataServiceSpy }
|
{ provide: DataService, useValue: dataServiceSpy },
|
||||||
|
{ provide: ConfigService, useValue: configServiceSpy }
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
|
@ -47,6 +50,7 @@ describe('RolesComponent', () => {
|
||||||
mockHttpClient = TestBed.inject(HttpClient) as jasmine.SpyObj<HttpClient>;
|
mockHttpClient = TestBed.inject(HttpClient) as jasmine.SpyObj<HttpClient>;
|
||||||
mockToastrService = TestBed.inject(ToastrService) as jasmine.SpyObj<ToastrService>;
|
mockToastrService = TestBed.inject(ToastrService) as jasmine.SpyObj<ToastrService>;
|
||||||
mockDataService = TestBed.inject(DataService) as jasmine.SpyObj<DataService>;
|
mockDataService = TestBed.inject(DataService) as jasmine.SpyObj<DataService>;
|
||||||
|
mockConfigService = TestBed.inject(ConfigService) as jasmine.SpyObj<ConfigService>;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { DataService } from "./data.service";
|
||||||
import { PageEvent } from "@angular/material/paginator";
|
import { PageEvent } from "@angular/material/paginator";
|
||||||
import { DeleteModalComponent } from '../../../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
import { AddRoleModalComponent } from './add-role-modal/add-role-modal.component';
|
import { AddRoleModalComponent } from './add-role-modal/add-role-modal.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-roles',
|
selector: 'app-roles',
|
||||||
|
@ -14,7 +15,7 @@ import { AddRoleModalComponent } from './add-role-modal/add-role-modal.component
|
||||||
styleUrls: ['./roles.component.css']
|
styleUrls: ['./roles.component.css']
|
||||||
})
|
})
|
||||||
export class RolesComponent implements OnInit {
|
export class RolesComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string = this.configService.apiUrl;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
filters: { [key: string]: string } = {};
|
filters: { [key: string]: string } = {};
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
@ -48,7 +49,8 @@ export class RolesComponent implements OnInit {
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { ToastrService } from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import { DataService } from "../data.service";
|
import { DataService } from "../data.service";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
interface UserGroup {
|
interface UserGroup {
|
||||||
'@id': string;
|
'@id': string;
|
||||||
|
@ -17,7 +18,7 @@ interface UserGroup {
|
||||||
styleUrls: ['./add-user-modal.component.css']
|
styleUrls: ['./add-user-modal.component.css']
|
||||||
})
|
})
|
||||||
export class AddUserModalComponent implements OnInit {
|
export class AddUserModalComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
@Output() userAdded = new EventEmitter<void>();
|
@Output() userAdded = new EventEmitter<void>();
|
||||||
@Output() userEdited = new EventEmitter<void>();
|
@Output() userEdited = new EventEmitter<void>();
|
||||||
userForm: FormGroup<any>;
|
userForm: FormGroup<any>;
|
||||||
|
@ -38,8 +39,10 @@ export class AddUserModalComponent implements OnInit {
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.userForm = this.fb.group({
|
this.userForm = this.fb.group({
|
||||||
username: ['', Validators.required],
|
username: ['', Validators.required],
|
||||||
password: ['', Validators.required],
|
password: ['', Validators.required],
|
||||||
|
|
|
@ -3,15 +3,19 @@ import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/users?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/users?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getUsers(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
getUsers(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { ToastrService } from 'ngx-toastr';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
class MockToastrService {
|
class MockToastrService {
|
||||||
success() {}
|
success() {}
|
||||||
|
@ -18,6 +19,11 @@ describe('UsersComponent', () => {
|
||||||
let fixture: ComponentFixture<UsersComponent>;
|
let fixture: ComponentFixture<UsersComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [UsersComponent],
|
declarations: [UsersComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -28,6 +34,7 @@ describe('UsersComponent', () => {
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ToastrService, useClass: MockToastrService },
|
{ provide: ToastrService, useClass: MockToastrService },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA], // Ignorar elementos desconocidos
|
schemas: [NO_ERRORS_SCHEMA], // Ignorar elementos desconocidos
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { AddUserModalComponent } from './add-user-modal/add-user-modal.component
|
||||||
import { DeleteModalComponent } from '../../../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { DataService } from "./data.service";
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-users',
|
selector: 'app-users',
|
||||||
|
@ -13,7 +13,8 @@ import { DataService } from "./data.service";
|
||||||
styleUrls: ['./users.component.css']
|
styleUrls: ['./users.component.css']
|
||||||
})
|
})
|
||||||
export class UsersComponent implements OnInit {
|
export class UsersComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
filters: { [key: string]: string } = {};
|
filters: { [key: string]: string } = {};
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
@ -50,14 +51,15 @@ export class UsersComponent implements OnInit {
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
private apiUrl = `${this.baseUrl}/users`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
|
private configService: ConfigService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dataService: DataService,
|
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/users`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.search();
|
this.search();
|
||||||
|
|
|
@ -16,12 +16,18 @@ import { MatProgressSpinner } from '@angular/material/progress-spinner';
|
||||||
import { JoyrideModule, JoyrideService } from 'ngx-joyride';
|
import { JoyrideModule, JoyrideService } from 'ngx-joyride';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoadingComponent } from '../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../shared/loading/loading.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('CalendarComponent', () => {
|
describe('CalendarComponent', () => {
|
||||||
let component: CalendarComponent;
|
let component: CalendarComponent;
|
||||||
let fixture: ComponentFixture<CalendarComponent>;
|
let fixture: ComponentFixture<CalendarComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [CalendarComponent, LoadingComponent],
|
declarations: [CalendarComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -41,6 +47,9 @@ describe('CalendarComponent', () => {
|
||||||
JoyrideModule.forRoot(),
|
JoyrideModule.forRoot(),
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
],
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { PageEvent } from "@angular/material/paginator";
|
||||||
import { CreateCalendarComponent } from "./create-calendar/create-calendar.component";
|
import { CreateCalendarComponent } from "./create-calendar/create-calendar.component";
|
||||||
import { DeleteModalComponent } from "../../shared/delete_modal/delete-modal/delete-modal.component";
|
import { DeleteModalComponent } from "../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-calendar',
|
selector: 'app-calendar',
|
||||||
|
@ -16,7 +17,8 @@ import { JoyrideService } from 'ngx-joyride';
|
||||||
styleUrl: './calendar.component.css'
|
styleUrl: './calendar.component.css'
|
||||||
})
|
})
|
||||||
export class CalendarComponent implements OnInit {
|
export class CalendarComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
images: { downloadUrl: string; name: string; uuid: string }[] = [];
|
images: { downloadUrl: string; name: string; uuid: string }[] = [];
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
|
@ -52,15 +54,18 @@ export class CalendarComponent implements OnInit {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
private apiUrl = `${this.baseUrl}/remote-calendars`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private joyrideService: JoyrideService
|
private joyrideService: JoyrideService
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/remote-calendars`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.search();
|
this.search();
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import {Component, Inject} from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-calendar-rule',
|
selector: 'app-create-calendar-rule',
|
||||||
|
@ -9,7 +10,7 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
styleUrl: './create-calendar-rule.component.css'
|
styleUrl: './create-calendar-rule.component.css'
|
||||||
})
|
})
|
||||||
export class CreateCalendarRuleComponent {
|
export class CreateCalendarRuleComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
name: string = '';
|
name: string = '';
|
||||||
remoteCalendarRules: any[] = [];
|
remoteCalendarRules: any[] = [];
|
||||||
weekDays: string[] = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'];
|
weekDays: string[] = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'];
|
||||||
|
@ -29,20 +30,23 @@ export class CreateCalendarRuleComponent {
|
||||||
constructor(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
private configService: ConfigService,
|
||||||
public dialogRef: MatDialogRef<CreateCalendarRuleComponent>,
|
public dialogRef: MatDialogRef<CreateCalendarRuleComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
) { }
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.calendarId = this.data.calendar
|
this.calendarId = this.data.calendar
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
this.isEditMode = true;
|
this.isEditMode = true;
|
||||||
this.availableFromDate = this.data.rule? this.data.rule.availableFromDate : null;
|
this.availableFromDate = this.data.rule ? this.data.rule.availableFromDate : null;
|
||||||
this.availableToDate = this.data.rule? this.data.rule.availableToDate : null;
|
this.availableToDate = this.data.rule ? this.data.rule.availableToDate : null;
|
||||||
this.isRemoteAvailable = this.data.rule? this.data.rule.isRemoteAvailable : false;
|
this.isRemoteAvailable = this.data.rule ? this.data.rule.isRemoteAvailable : false;
|
||||||
this.availableReason = this.data.rule? this.data.rule.availableReason : null;
|
this.availableReason = this.data.rule ? this.data.rule.availableReason : null;
|
||||||
this.busyFromHour = this.data.rule? this.data.rule.busyFromHour : null;
|
this.busyFromHour = this.data.rule ? this.data.rule.busyFromHour : null;
|
||||||
this.busyToHour = this.data.rule? this.data.rule.busyToHour : null;
|
this.busyToHour = this.data.rule ? this.data.rule.busyToHour : null;
|
||||||
if (this.data.rule && this.data.rule.busyWeekDays) {
|
if (this.data.rule && this.data.rule.busyWeekDays) {
|
||||||
this.busyWeekDays = this.data.rule.busyWeekDays.reduce((acc: {
|
this.busyWeekDays = this.data.rule.busyWeekDays.reduce((acc: {
|
||||||
[x: string]: boolean;
|
[x: string]: boolean;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog";
|
||||||
import {CreateCalendarRuleComponent} from "../create-calendar-rule/create-calendar-rule.component";
|
import { CreateCalendarRuleComponent } from "../create-calendar-rule/create-calendar-rule.component";
|
||||||
import {DataService} from "../data.service";
|
import { DataService } from "../data.service";
|
||||||
import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
import { DeleteModalComponent } from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-calendar',
|
selector: 'app-create-calendar',
|
||||||
|
@ -12,7 +13,7 @@ import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/de
|
||||||
styleUrl: './create-calendar.component.css'
|
styleUrl: './create-calendar.component.css'
|
||||||
})
|
})
|
||||||
export class CreateCalendarComponent implements OnInit {
|
export class CreateCalendarComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
name: string = '';
|
name: string = '';
|
||||||
remoteCalendarRules: any[] = [];
|
remoteCalendarRules: any[] = [];
|
||||||
isEditMode: boolean = false;
|
isEditMode: boolean = false;
|
||||||
|
@ -22,11 +23,14 @@ export class CreateCalendarComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
private configService: ConfigService,
|
||||||
public dialogRef: MatDialogRef<CreateCalendarComponent>,
|
public dialogRef: MatDialogRef<CreateCalendarComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
) { }
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/remote-calendars?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getRemoteCalendars(filters: { [key: string]: string }): Observable<any[]> {
|
getRemoteCalendars(filters: { [key: string]: string }): Observable<any[]> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/
|
||||||
import { MatTableDataSource } from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import { DatePipe } from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-commands-groups',
|
selector: 'app-commands-groups',
|
||||||
|
@ -15,7 +16,8 @@ import { JoyrideService } from 'ngx-joyride';
|
||||||
styleUrls: ['./commands-groups.component.css']
|
styleUrls: ['./commands-groups.component.css']
|
||||||
})
|
})
|
||||||
export class CommandsGroupsComponent implements OnInit {
|
export class CommandsGroupsComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
filters: { [key: string]: string | boolean } = {};
|
filters: { [key: string]: string | boolean } = {};
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
|
@ -47,10 +49,12 @@ export class CommandsGroupsComponent implements OnInit {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
private apiUrl = `${this.baseUrl}/command-groups`;
|
|
||||||
|
|
||||||
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
|
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
|
||||||
private joyrideService: JoyrideService) {}
|
private configService: ConfigService, private joyrideService: JoyrideService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/command-groups`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.search();
|
this.search();
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-command-group',
|
selector: 'app-create-command-group',
|
||||||
|
@ -10,21 +11,25 @@ import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||||
styleUrls: ['./create-command-group.component.css']
|
styleUrls: ['./create-command-group.component.css']
|
||||||
})
|
})
|
||||||
export class CreateCommandGroupComponent implements OnInit {
|
export class CreateCommandGroupComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
availableCommands: any[] = [];
|
availableCommands: any[] = [];
|
||||||
selectedCommands: any[] = [];
|
selectedCommands: any[] = [];
|
||||||
groupName: string = '';
|
groupName: string = '';
|
||||||
enabled: boolean = true;
|
enabled: boolean = true;
|
||||||
editing: boolean = false;
|
editing: boolean = false;
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
private apiUrl = `${this.baseUrl}/commands`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dialogRef: MatDialogRef<CreateCommandGroupComponent>,
|
private dialogRef: MatDialogRef<CreateCommandGroupComponent>,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/commands`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadAvailableCommands();
|
this.loadAvailableCommands();
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-detail-command-group',
|
selector: 'app-detail-command-group',
|
||||||
|
@ -10,7 +11,7 @@ import { ToastrService } from 'ngx-toastr';
|
||||||
styleUrls: ['./detail-command-group.component.css']
|
styleUrls: ['./detail-command-group.component.css']
|
||||||
})
|
})
|
||||||
export class DetailCommandGroupComponent implements OnInit {
|
export class DetailCommandGroupComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
form!: FormGroup;
|
form!: FormGroup;
|
||||||
clients: any[] = [];
|
clients: any[] = [];
|
||||||
showClientSelect = false;
|
showClientSelect = false;
|
||||||
|
@ -21,9 +22,12 @@ export class DetailCommandGroupComponent implements OnInit {
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
private dialogRef: MatDialogRef<DetailCommandGroupComponent>,
|
private dialogRef: MatDialogRef<DetailCommandGroupComponent>,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
|
private configService: ConfigService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService
|
||||||
) { }
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
|
|
|
@ -13,11 +13,16 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
||||||
import { JoyrideModule, JoyrideService, JoyrideStepService } from 'ngx-joyride';
|
import { JoyrideModule, JoyrideService, JoyrideStepService } from 'ngx-joyride';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('CommandsTaskComponent', () => {
|
describe('CommandsTaskComponent', () => {
|
||||||
let component: CommandsTaskComponent;
|
let component: CommandsTaskComponent;
|
||||||
let fixture: ComponentFixture<CommandsTaskComponent>;
|
let fixture: ComponentFixture<CommandsTaskComponent>;
|
||||||
|
let mockConfigService: jasmine.SpyObj<ConfigService>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const configServiceSpy = jasmine.createSpyObj('ConfigService', [], { apiUrl: 'http://mock-api-url' });
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
HttpClientTestingModule,
|
HttpClientTestingModule,
|
||||||
|
@ -33,8 +38,13 @@ describe('CommandsTaskComponent', () => {
|
||||||
JoyrideModule.forRoot(),
|
JoyrideModule.forRoot(),
|
||||||
],
|
],
|
||||||
declarations: [CommandsTaskComponent, LoadingComponent],
|
declarations: [CommandsTaskComponent, LoadingComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: ConfigService, useValue: configServiceSpy }
|
||||||
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
mockConfigService = TestBed.inject(ConfigService) as jasmine.SpyObj<ConfigService>;
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { CreateTaskComponent } from './create-task/create-task.component';
|
||||||
import { DetailTaskComponent } from './detail-task/detail-task.component';
|
import { DetailTaskComponent } from './detail-task/detail-task.component';
|
||||||
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-commands-task',
|
selector: 'app-commands-task',
|
||||||
|
@ -13,7 +14,7 @@ import { JoyrideService } from 'ngx-joyride';
|
||||||
styleUrls: ['./commands-task.component.css']
|
styleUrls: ['./commands-task.component.css']
|
||||||
})
|
})
|
||||||
export class CommandsTaskComponent implements OnInit {
|
export class CommandsTaskComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
tasks: any[] = [];
|
tasks: any[] = [];
|
||||||
filters: { [key: string]: string | boolean } = {};
|
filters: { [key: string]: string | boolean } = {};
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
|
@ -22,10 +23,14 @@ export class CommandsTaskComponent implements OnInit {
|
||||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||||
displayedColumns: string[] = ['taskid', 'notes', 'name', 'scheduledDate', 'enabled', 'actions'];
|
displayedColumns: string[] = ['taskid', 'notes', 'name', 'scheduledDate', 'enabled', 'actions'];
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
private apiUrl = `${this.baseUrl}/command-tasks`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
|
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
|
||||||
private joyrideService: JoyrideService) {}
|
private configService: ConfigService,
|
||||||
|
private joyrideService: JoyrideService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/command-tasks`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadTasks();
|
this.loadTasks();
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-task',
|
selector: 'app-create-task',
|
||||||
|
@ -10,12 +11,12 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
styleUrls: ['./create-task.component.css']
|
styleUrls: ['./create-task.component.css']
|
||||||
})
|
})
|
||||||
export class CreateTaskComponent implements OnInit {
|
export class CreateTaskComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
taskForm: FormGroup;
|
taskForm: FormGroup;
|
||||||
availableCommandGroups: any[] = [];
|
availableCommandGroups: any[] = [];
|
||||||
selectedGroupCommands: any[] = [];
|
selectedGroupCommands: any[] = [];
|
||||||
availableIndividualCommands: any[] = [];
|
availableIndividualCommands: any[] = [];
|
||||||
apiUrl = `${this.baseUrl}/command-tasks`;
|
apiUrl: string;
|
||||||
editing: boolean = false;
|
editing: boolean = false;
|
||||||
availableOrganizationalUnits: any[] = [];
|
availableOrganizationalUnits: any[] = [];
|
||||||
selectedUnitChildren: any[] = [];
|
selectedUnitChildren: any[] = [];
|
||||||
|
@ -25,10 +26,13 @@ export class CreateTaskComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastr: ToastrService,
|
private toastr: ToastrService,
|
||||||
public dialogRef: MatDialogRef<CreateTaskComponent>,
|
public dialogRef: MatDialogRef<CreateTaskComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/command-tasks`;
|
||||||
this.taskForm = this.fb.group({
|
this.taskForm = this.fb.group({
|
||||||
commandGroup: ['', Validators.required],
|
commandGroup: ['', Validators.required],
|
||||||
extraCommands: [[]],
|
extraCommands: [[]],
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
|
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Observable, forkJoin } from 'rxjs';
|
import { Observable, forkJoin } from 'rxjs';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
|
@ -7,9 +7,10 @@ import { DatePipe } from '@angular/common';
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
import { MatDialog } from "@angular/material/dialog";
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
import { InputDialogComponent } from "./input-dialog/input-dialog.component";
|
import { InputDialogComponent } from "./input-dialog/input-dialog.component";
|
||||||
import { ProgressBarMode, MatProgressBarModule } from '@angular/material/progress-bar';
|
import { ProgressBarMode } from '@angular/material/progress-bar';
|
||||||
import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
|
import { DeleteModalComponent } from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task-logs',
|
selector: 'app-task-logs',
|
||||||
|
@ -17,8 +18,8 @@ import {ToastrService} from "ngx-toastr";
|
||||||
styleUrls: ['./task-logs.component.css']
|
styleUrls: ['./task-logs.component.css']
|
||||||
})
|
})
|
||||||
export class TaskLogsComponent implements OnInit {
|
export class TaskLogsComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
mercureUrl: string = import.meta.env.NG_APP_OGCORE_MERCURE_BASE_URL;
|
mercureUrl: string;
|
||||||
traces: any[] = [];
|
traces: any[] = [];
|
||||||
groupedTraces: any[] = [];
|
groupedTraces: any[] = [];
|
||||||
commands: any[] = [];
|
commands: any[] = [];
|
||||||
|
@ -92,8 +93,12 @@ export class TaskLogsComponent implements OnInit {
|
||||||
private joyrideService: JoyrideService,
|
private joyrideService: JoyrideService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private cdr: ChangeDetectorRef,
|
private cdr: ChangeDetectorRef,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService
|
||||||
) { }
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.mercureUrl = this.configService.mercureUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadTraces();
|
this.loadTraces();
|
||||||
|
|
|
@ -20,12 +20,18 @@ import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { JoyrideModule } from 'ngx-joyride';
|
import { JoyrideModule } from 'ngx-joyride';
|
||||||
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('CommandsComponent', () => {
|
describe('CommandsComponent', () => {
|
||||||
let component: CommandsComponent;
|
let component: CommandsComponent;
|
||||||
let fixture: ComponentFixture<CommandsComponent>;
|
let fixture: ComponentFixture<CommandsComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [CommandsComponent, LoadingComponent],
|
declarations: [CommandsComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -53,7 +59,8 @@ describe('CommandsComponent', () => {
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: {} },
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: {} }
|
{ provide: MAT_DIALOG_DATA, useValue: {} },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
|
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { CreateCommandComponent } from './create-command/create-command.componen
|
||||||
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { ExecuteCommandComponent } from './execute-command/execute-command.component';
|
import { ConfigService } from '@services/config.service';
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -16,7 +16,8 @@ import { JoyrideService } from 'ngx-joyride';
|
||||||
styleUrls: ['./commands.component.css']
|
styleUrls: ['./commands.component.css']
|
||||||
})
|
})
|
||||||
export class CommandsComponent implements OnInit {
|
export class CommandsComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
filters: { [key: string]: string | boolean } = {};
|
filters: { [key: string]: string | boolean } = {};
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
|
@ -48,10 +49,12 @@ export class CommandsComponent implements OnInit {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
private apiUrl = `${this.baseUrl}/commands`;
|
|
||||||
|
|
||||||
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
|
constructor(private http: HttpClient, private dialog: MatDialog, private toastService: ToastrService,
|
||||||
private joyrideService: JoyrideService) {}
|
private joyrideService: JoyrideService, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/commands`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.search();
|
this.search();
|
||||||
|
|
|
@ -13,12 +13,18 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('CreateCommandComponent', () => {
|
describe('CreateCommandComponent', () => {
|
||||||
let component: CreateCommandComponent;
|
let component: CreateCommandComponent;
|
||||||
let fixture: ComponentFixture<CreateCommandComponent>;
|
let fixture: ComponentFixture<CreateCommandComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [CreateCommandComponent],
|
declarations: [CreateCommandComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -45,7 +51,8 @@ describe('CreateCommandComponent', () => {
|
||||||
{
|
{
|
||||||
provide: MAT_DIALOG_DATA,
|
provide: MAT_DIALOG_DATA,
|
||||||
useValue: {}
|
useValue: {}
|
||||||
}
|
},
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import {DataService} from "../data.service";
|
import { DataService } from "../data.service";
|
||||||
|
import { ConfigService } from "@services/config.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-command',
|
selector: 'app-create-command',
|
||||||
|
@ -11,9 +12,8 @@ import {DataService} from "../data.service";
|
||||||
styleUrls: ['./create-command.component.css']
|
styleUrls: ['./create-command.component.css']
|
||||||
})
|
})
|
||||||
export class CreateCommandComponent {
|
export class CreateCommandComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
createCommandForm: FormGroup<any>;
|
createCommandForm: FormGroup<any>;
|
||||||
private apiUrl = `${this.baseUrl}/commands`;
|
|
||||||
commandId: string | null = null;
|
commandId: string | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -21,9 +21,11 @@ export class CreateCommandComponent {
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
public dialogRef: MatDialogRef<CreateCommandComponent>,
|
public dialogRef: MatDialogRef<CreateCommandComponent>,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.createCommandForm = this.fb.group({
|
this.createCommandForm = this.fb.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
script: [''],
|
script: [''],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@ -8,10 +8,16 @@ import { catchError, map } from 'rxjs/operators';
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/commands?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
private configService: ConfigService
|
||||||
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/commands?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getCommands(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
getCommands(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dial
|
||||||
import { CreateCommandComponent } from '../create-command/create-command.component';
|
import { CreateCommandComponent } from '../create-command/create-command.component';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-command-detail',
|
selector: 'app-command-detail',
|
||||||
|
@ -11,7 +12,7 @@ import { ToastrService } from 'ngx-toastr';
|
||||||
styleUrls: ['./command-detail.component.css']
|
styleUrls: ['./command-detail.component.css']
|
||||||
})
|
})
|
||||||
export class CommandDetailComponent implements OnInit {
|
export class CommandDetailComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
form!: FormGroup;
|
form!: FormGroup;
|
||||||
clients: any[] = [];
|
clients: any[] = [];
|
||||||
showClientSelect = false;
|
showClientSelect = false;
|
||||||
|
@ -20,12 +21,15 @@ export class CommandDetailComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
|
private configService: ConfigService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
public dialogRef: MatDialogRef<CommandDetailComponent>,
|
public dialogRef: MatDialogRef<CommandDetailComponent>,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) { }
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
|
@ -52,7 +56,7 @@ export class CommandDetailComponent implements OnInit {
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(result => {
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.toastService.success('Comando editado' );
|
this.toastService.success('Comando editado');
|
||||||
this.data.command = result;
|
this.data.command = result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ExecuteCommandComponent } from './execute-command.component';
|
import { ExecuteCommandComponent } from './execute-command.component';
|
||||||
import { provideHttpClient } from '@angular/common/http';
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||||
|
@ -17,12 +16,18 @@ import { ToastrModule, ToastrService } from 'ngx-toastr';
|
||||||
import { DataService } from '../data.service';
|
import { DataService } from '../data.service';
|
||||||
import {MatIconModule} from "@angular/material/icon";
|
import {MatIconModule} from "@angular/material/icon";
|
||||||
import {MatMenu, MatMenuModule} from "@angular/material/menu";
|
import {MatMenu, MatMenuModule} from "@angular/material/menu";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('ExecuteCommandComponent', () => {
|
describe('ExecuteCommandComponent', () => {
|
||||||
let component: ExecuteCommandComponent;
|
let component: ExecuteCommandComponent;
|
||||||
let fixture: ComponentFixture<ExecuteCommandComponent>;
|
let fixture: ComponentFixture<ExecuteCommandComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ExecuteCommandComponent],
|
declarations: [ExecuteCommandComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -54,7 +59,8 @@ describe('ExecuteCommandComponent', () => {
|
||||||
{
|
{
|
||||||
provide: MAT_DIALOG_DATA,
|
provide: MAT_DIALOG_DATA,
|
||||||
useValue: {}
|
useValue: {}
|
||||||
}
|
},
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import {Component, Inject, Input, OnInit, SimpleChanges} from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { Router } from "@angular/router";
|
||||||
import {Router} from "@angular/router";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-execute-command',
|
selector: 'app-execute-command',
|
||||||
|
@ -16,32 +15,32 @@ export class ExecuteCommandComponent implements OnInit {
|
||||||
@Input() buttonText: string = 'Ejecutar Comandos';
|
@Input() buttonText: string = 'Ejecutar Comandos';
|
||||||
@Input() icon: string = 'terminal';
|
@Input() icon: string = 'terminal';
|
||||||
@Input() disabled: boolean = false;
|
@Input() disabled: boolean = false;
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
loading: boolean = true;
|
loading: boolean = true;
|
||||||
|
|
||||||
arrayCommands: any[] = [
|
arrayCommands: any[] = [
|
||||||
{name: 'Enceder', slug: 'power-on', disabled: false},
|
{ name: 'Enceder', slug: 'power-on', disabled: false },
|
||||||
{name: 'Apagar', slug: 'power-off', disabled: false},
|
{ name: 'Apagar', slug: 'power-off', disabled: false },
|
||||||
{name: 'Reiniciar', slug: 'reboot', disabled: false},
|
{ name: 'Reiniciar', slug: 'reboot', disabled: false },
|
||||||
{name: 'Iniciar Sesión', slug: 'login', disabled: true},
|
{ name: 'Iniciar Sesión', slug: 'login', disabled: true },
|
||||||
{name: 'Crear imagen', slug: 'create-image', disabled: false},
|
{ name: 'Crear imagen', slug: 'create-image', disabled: false },
|
||||||
{name: 'Clonar/desplegar imagen', slug: 'deploy-image', disabled: false},
|
{ name: 'Clonar/desplegar imagen', slug: 'deploy-image', disabled: false },
|
||||||
{name: 'Eliminar Imagen Cache', slug: 'delete-image-cache', disabled: true},
|
{ name: 'Eliminar Imagen Cache', slug: 'delete-image-cache', disabled: true },
|
||||||
{name: 'Particionar y Formatear', slug: 'partition', disabled: false},
|
{ name: 'Particionar y Formatear', slug: 'partition', disabled: false },
|
||||||
{name: 'Inventario Software', slug: 'software-inventory', disabled: true},
|
{ name: 'Inventario Software', slug: 'software-inventory', disabled: true },
|
||||||
{name: 'Inventario Hardware', slug: 'hardware-inventory', disabled: true},
|
{ name: 'Inventario Hardware', slug: 'hardware-inventory', disabled: true },
|
||||||
{name: 'Ejecutar script', slug: 'run-script', disabled: true},
|
{ name: 'Ejecutar script', slug: 'run-script', disabled: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
client: any = {};
|
client: any = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dialog: MatDialog,
|
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private fb: FormBuilder,
|
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
mat-dialog-content {
|
||||||
|
height: calc(100% - 64px);
|
||||||
|
overflow: auto;
|
||||||
|
padding-top: 0.5em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 1em;
|
||||||
|
padding: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-card {
|
||||||
|
margin: 20px auto;
|
||||||
|
max-width: 600px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgb(243, 243, 243);
|
||||||
|
color: rgb(48, 48, 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-card p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
<header>
|
||||||
|
<h1 mat-dialog-title>{{'GlobalStatus' | translate}}</h1>
|
||||||
|
</header>
|
||||||
|
<mat-dialog-content [ngClass]="{'loading': loading}">
|
||||||
|
<div class="spinner-container" *ngIf="loading">
|
||||||
|
<mat-spinner class="loading-spinner"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
<mat-tab-group (selectedTabChange)="onTabChange($event)">
|
||||||
|
<mat-tab label="OgBoot">
|
||||||
|
<div *ngIf="!loading && !errorOgBoot" class="content-container">
|
||||||
|
<app-status-tab
|
||||||
|
[loading]="loading"
|
||||||
|
[diskUsage]="ogBootDiskUsage"
|
||||||
|
[servicesStatus]="ogBootServicesStatus"
|
||||||
|
[installedOgLives]="installedOgLives"
|
||||||
|
[diskUsageChartData]="ogBootDiskUsageChartData"
|
||||||
|
[view]="view"
|
||||||
|
[colorScheme]="colorScheme"
|
||||||
|
[isDoughnut]="isDoughnut"
|
||||||
|
[showLabels]="showLabels"
|
||||||
|
[isDhcp]="isDhcp"
|
||||||
|
[isRepository]="false">
|
||||||
|
</app-status-tab>
|
||||||
|
</div>
|
||||||
|
<mat-card *ngIf="!loading && errorOgBoot" class="error-card">
|
||||||
|
<mat-card-content>
|
||||||
|
<p>{{ 'errorLoadingData' | translate }}</p>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Dhcp">
|
||||||
|
<div *ngIf="!loading && !errorDhcp" class="content-container">
|
||||||
|
<app-status-tab
|
||||||
|
[loading]="loading"
|
||||||
|
[diskUsage]="dhcpDiskUsage"
|
||||||
|
[servicesStatus]="dhcpServicesStatus"
|
||||||
|
[subnets]="subnets"
|
||||||
|
[diskUsageChartData]="dhcpDiskUsageChartData"
|
||||||
|
[view]="view"
|
||||||
|
[colorScheme]="colorScheme"
|
||||||
|
[isDoughnut]="isDoughnut"
|
||||||
|
[showLabels]="showLabels"
|
||||||
|
[isDhcp]="isDhcp"
|
||||||
|
[isRepository]="false">
|
||||||
|
</app-status-tab>
|
||||||
|
</div>
|
||||||
|
<mat-card *ngIf="!loading && errorDhcp" class="error-card">
|
||||||
|
<mat-card-content>
|
||||||
|
<p>{{ 'errorLoadingData' | translate }}</p>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Repositorios">
|
||||||
|
<mat-tab-group>
|
||||||
|
<mat-tab *ngFor="let repository of repositories" [label]="repository.name">
|
||||||
|
<div *ngIf="!loading && !errorRepositories[repository.uuid] && repositoryStatuses[repository.uuid]">
|
||||||
|
<app-status-tab
|
||||||
|
[loading]="loading"
|
||||||
|
[diskUsage]="repositoryStatuses[repository.uuid].disk"
|
||||||
|
[servicesStatus]="repositoryStatuses[repository.uuid].services"
|
||||||
|
[processesStatus]="repositoryStatuses[repository.uuid].processes"
|
||||||
|
[ramUsage]="repositoryStatuses[repository.uuid].ram"
|
||||||
|
[cpuUsage]="repositoryStatuses[repository.uuid].cpu"
|
||||||
|
[diskUsageChartData]="[
|
||||||
|
{ name: 'Usado', value: repositoryStatuses[repository.uuid].disk.used },
|
||||||
|
{ name: 'Disponible', value: repositoryStatuses[repository.uuid].disk.available }
|
||||||
|
]"
|
||||||
|
[ramUsageChartData]="[
|
||||||
|
{ name: 'Usado', value: repositoryStatuses[repository.uuid].ram.used },
|
||||||
|
{ name: 'Disponible', value: repositoryStatuses[repository.uuid].ram.available }
|
||||||
|
]"
|
||||||
|
[view]="view"
|
||||||
|
[colorScheme]="colorScheme"
|
||||||
|
[isDoughnut]="isDoughnut"
|
||||||
|
[showLabels]="showLabels"
|
||||||
|
[isDhcp]="false"
|
||||||
|
[isRepository]="true">
|
||||||
|
</app-status-tab>
|
||||||
|
</div>
|
||||||
|
<mat-card *ngIf="!loading && errorRepositories[repository.uuid]" class="error-card">
|
||||||
|
<mat-card-content>
|
||||||
|
<p>{{ 'errorLoadingData' | translate }}</p>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions class="action-container">
|
||||||
|
<button class="ordinary-button" [mat-dialog-close]="true">{{ 'closeButton' | translate }}</button>
|
||||||
|
</mat-dialog-actions>
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { GlobalStatusComponent } from './global-status.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { LoadingComponent } from '../../shared/loading/loading.component';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
|
||||||
|
describe('GlobalStatusComponent', () => {
|
||||||
|
let component: GlobalStatusComponent;
|
||||||
|
let fixture: ComponentFixture<GlobalStatusComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url'
|
||||||
|
};
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [GlobalStatusComponent, LoadingComponent],
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
ToastrModule.forRoot(),
|
||||||
|
MatDialogModule,
|
||||||
|
MatTabsModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
NgxChartsModule,
|
||||||
|
BrowserAnimationsModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(GlobalStatusComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,194 @@
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { MatTabChangeEvent } from '@angular/material/tabs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-global-status',
|
||||||
|
templateUrl: './global-status.component.html',
|
||||||
|
styleUrl: './global-status.component.css'
|
||||||
|
})
|
||||||
|
export class GlobalStatusComponent implements OnInit {
|
||||||
|
baseUrl: string;
|
||||||
|
loading: boolean = false;
|
||||||
|
errorOgBoot: boolean = false;
|
||||||
|
errorDhcp: boolean = false;
|
||||||
|
errorRepositories: { [key: string]: boolean } = {};
|
||||||
|
installedOgLives: any[] = [];
|
||||||
|
subnets: any[] = [];
|
||||||
|
showLabels: boolean = true;
|
||||||
|
isDoughnut: boolean = true;
|
||||||
|
colorScheme: any = {
|
||||||
|
domain: ['#df200d', '#26a700']
|
||||||
|
};
|
||||||
|
view: [number, number] = [400, 220];
|
||||||
|
repositoriesUrl: string;
|
||||||
|
repositories: any[] = [];
|
||||||
|
repositoryStatuses: { [key: string]: any } = {};
|
||||||
|
|
||||||
|
ogBootApiUrl: string;
|
||||||
|
ogBootDiskUsage: any = {};
|
||||||
|
ogBootServicesStatus: any = {};
|
||||||
|
ogBootDiskUsageChartData: any[] = [];
|
||||||
|
|
||||||
|
dhcpApiUrl: string;
|
||||||
|
dhcpDiskUsage: any = {};
|
||||||
|
dhcpServicesStatus: any = {};
|
||||||
|
dhcpDiskUsageChartData: any[] = [];
|
||||||
|
isDhcp: boolean = false;
|
||||||
|
isRepository: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private configService: ConfigService,
|
||||||
|
private http: HttpClient
|
||||||
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.ogBootApiUrl = `${this.baseUrl}/og-boot/status`;
|
||||||
|
this.dhcpApiUrl = `${this.baseUrl}/og-dhcp/status`;
|
||||||
|
this.repositoriesUrl = `${this.baseUrl}/image-repositories`;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadOgBootStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
[key: string]: any;
|
||||||
|
|
||||||
|
loadStatus(apiUrl: string, diskUsage: any, servicesStatus: any, diskUsageChartData: any[], installedOgLives: any[], isDhcp: boolean, errorState: string): void {
|
||||||
|
this.loading = true;
|
||||||
|
this[errorState] = false;
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
this.loading = false;
|
||||||
|
this[errorState] = true;
|
||||||
|
}, 3500);
|
||||||
|
this.http.get<any>(apiUrl).subscribe({
|
||||||
|
next: data => {
|
||||||
|
diskUsage.used = data.message.disk_usage.used;
|
||||||
|
diskUsage.available = data.message.disk_usage.available;
|
||||||
|
diskUsage.total = data.message.disk_usage.total;
|
||||||
|
diskUsage.percentage = data.message.disk_usage.percentage;
|
||||||
|
|
||||||
|
Object.assign(servicesStatus, data.message.services_status);
|
||||||
|
|
||||||
|
if (isDhcp) {
|
||||||
|
this.subnets.length = 0;
|
||||||
|
if (data.message.subnets) {
|
||||||
|
this.subnets.push(...data.message.subnets);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
installedOgLives.length = 0;
|
||||||
|
if (data.message.installed_oglives) {
|
||||||
|
installedOgLives.push(...data.message.installed_oglives);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diskUsageChartData.length = 0;
|
||||||
|
diskUsageChartData.push(
|
||||||
|
{ name: 'Usado', value: parseFloat(diskUsage.used) },
|
||||||
|
{ name: 'Disponible', value: parseFloat(diskUsage.available) }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
console.log(error);
|
||||||
|
this.loading = false;
|
||||||
|
this[errorState] = true;
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRepositories(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.errorRepositories = {};
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
this.loading = false;
|
||||||
|
this.repositories.forEach(repository => {
|
||||||
|
this.errorRepositories[repository.uuid] = true;
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
this.http.get<any>(`${this.repositoriesUrl}?page=1&itemsPerPage=10`).subscribe(
|
||||||
|
data => {
|
||||||
|
this.repositories = data['hydra:member'];
|
||||||
|
let remainingRepositories = this.repositories.length;
|
||||||
|
this.repositories.forEach(repository => {
|
||||||
|
this.loadRepositoryStatus(repository.uuid, (errorOccurred: boolean) => {
|
||||||
|
remainingRepositories--;
|
||||||
|
if (remainingRepositories === 0) {
|
||||||
|
this.loading = false;
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
if (errorOccurred) {
|
||||||
|
this.errorRepositories[repository.uuid] = true;
|
||||||
|
} else {
|
||||||
|
this.errorRepositories[repository.uuid] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('Error fetching repositories', error);
|
||||||
|
this.loading = false;
|
||||||
|
this.repositories.forEach(repository => {
|
||||||
|
this.errorRepositories[repository.uuid] = true;
|
||||||
|
});
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRepositoryStatus(repositoryUuid: string, callback: (errorOccurred: boolean) => void): void {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
callback(true);
|
||||||
|
}, 5000);
|
||||||
|
this.http.get<any>(`${this.baseUrl}/image-repositories/server/${repositoryUuid}/status`).subscribe(
|
||||||
|
data => {
|
||||||
|
const output = data.output;
|
||||||
|
this.repositoryStatuses[repositoryUuid] = {
|
||||||
|
...output,
|
||||||
|
disk: {
|
||||||
|
...output.disk,
|
||||||
|
used: parseFloat(output.disk.used),
|
||||||
|
available: parseFloat(output.disk.available)
|
||||||
|
},
|
||||||
|
ram: {
|
||||||
|
...output.ram,
|
||||||
|
used: parseFloat(output.ram.used),
|
||||||
|
available: parseFloat(output.ram.available)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
callback(false);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error(`Error fetching status for repository ${repositoryUuid}`, error);
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
callback(true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadOgBootStatus(): void {
|
||||||
|
this.isDhcp = false;
|
||||||
|
this.loadStatus(this.ogBootApiUrl, this.ogBootDiskUsage, this.ogBootServicesStatus, this.ogBootDiskUsageChartData, this.installedOgLives, this.isDhcp, 'errorOgBoot');
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDhcpStatus(): void {
|
||||||
|
this.isDhcp = true;
|
||||||
|
this.loadStatus(this.dhcpApiUrl, this.dhcpDiskUsage, this.dhcpServicesStatus, this.dhcpDiskUsageChartData, this.installedOgLives, this.isDhcp, 'errorDhcp');
|
||||||
|
}
|
||||||
|
|
||||||
|
onTabChange(event: MatTabChangeEvent): void {
|
||||||
|
if (event.tab.textLabel === 'OgBoot') {
|
||||||
|
this.loadOgBootStatus();
|
||||||
|
} else if (event.tab.textLabel === 'Dhcp') {
|
||||||
|
this.loadDhcpStatus();
|
||||||
|
} else if (event.tab.textLabel === 'Repositorios') {
|
||||||
|
if (this.repositories.length === 0) {
|
||||||
|
this.loadRepositories();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
.dashboard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disk-usage-container,
|
||||||
|
.ram-usage-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disk-usage,
|
||||||
|
.ram-usage {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-list,
|
||||||
|
.process-list {
|
||||||
|
margin-top: 0em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-status,
|
||||||
|
.processes-status {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-status li {
|
||||||
|
margin: 5px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.processes-status li {
|
||||||
|
margin: 5px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led.active {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led.inactive {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disk-title,
|
||||||
|
.ram-title {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-title,
|
||||||
|
.process-title {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
<app-loading [isLoading]="loading"></app-loading>
|
||||||
|
<div *ngIf="!loading" class="dashboard">
|
||||||
|
<!-- Disk Usage Section -->
|
||||||
|
<div class="disk-usage-container">
|
||||||
|
<h3 class="disk-title">{{ 'diskUsageTitle' | translate }}</h3>
|
||||||
|
<div class="disk-usage" joyrideStep="diskUsageStep" text="{{ 'diskUsageDescription' | translate }}">
|
||||||
|
<ngx-charts-pie-chart [view]="view" [scheme]="colorScheme" [results]="diskUsageChartData" [doughnut]="isDoughnut"
|
||||||
|
[labels]="showLabels">
|
||||||
|
</ngx-charts-pie-chart>
|
||||||
|
<div class="disk-usage-info">
|
||||||
|
<p>{{ 'totalLabel' | translate }}: <strong>{{ isRepository ? diskUsage.total : formatBytes(diskUsage.total) }}</strong></p>
|
||||||
|
<p>{{ 'usedLabel' | translate }}: <strong>{{ isRepository ? diskUsage.used : formatBytes(diskUsage.used) }}</strong></p>
|
||||||
|
<p>{{ 'availableLabel' | translate }}: <strong>{{ isRepository ? diskUsage.available : formatBytes(diskUsage.available) }}</strong></p>
|
||||||
|
<p>{{ 'usedPercentageLabel' | translate }}: <strong>{{ isRepository ? diskUsage.used_percentage : diskUsage.percentage }}</strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- RAM Usage Section -->
|
||||||
|
<div class="ram-usage-container" *ngIf="isRepository">
|
||||||
|
<h3 class="ram-title">{{ 'RamUsage' | translate }}</h3>
|
||||||
|
<div class="ram-usage">
|
||||||
|
<ngx-charts-pie-chart [view]="view" [scheme]="colorScheme" [results]="ramUsageChartData" [doughnut]="isDoughnut"
|
||||||
|
[labels]="showLabels">
|
||||||
|
</ngx-charts-pie-chart>
|
||||||
|
<div class="ram-usage-info">
|
||||||
|
<p>{{ 'totalLabel' | translate }}: <strong>{{ ramUsage.total }}</strong></p>
|
||||||
|
<p>{{ 'usedLabel' | translate }}: <strong>{{ ramUsage.used }}</strong></p>
|
||||||
|
<p>{{ 'availableLabel' | translate }}: <strong>{{ ramUsage.available }}</strong></p>
|
||||||
|
<p>{{ 'usedPercentageLabel' | translate }}: <strong>{{ ramUsage.used_percentage }}</strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CPU Usage Section -->
|
||||||
|
<div class="cpu-usage-container" *ngIf="isRepository">
|
||||||
|
<h3 class="cpu-title">{{ 'CpuUsage' | translate }}</h3>
|
||||||
|
<div class="cpu-usage">
|
||||||
|
<p>{{ 'usedLabel' | translate }}: <strong>{{ cpuUsage.used_percentage }}</strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Services Status Section -->
|
||||||
|
<div class="services-status" joyrideStep="servicesStatusStep" text="{{ 'servicesStatusDescription' | translate }}">
|
||||||
|
<h3 class="service-title">{{ 'servicesTitle' | translate }}</h3>
|
||||||
|
<ul class="service-list">
|
||||||
|
<li *ngFor="let service of getServices()">
|
||||||
|
<span class="status-led"
|
||||||
|
[ngClass]="{ 'active': service.status === 'active', 'inactive': service.status !== 'active' }"></span>
|
||||||
|
{{ service.name }}: {{ service.status | translate }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Processes Status Section -->
|
||||||
|
<div class="processes-status" *ngIf="isRepository">
|
||||||
|
<h3 class="process-title">{{ 'processes' | translate }}</h3>
|
||||||
|
<ul class="process-list">
|
||||||
|
<li *ngFor="let process of getProcesses()">
|
||||||
|
<span class="status-led"
|
||||||
|
[ngClass]="{ 'active': process.status === 'running', 'inactive': process.status !== 'running' }"></span>
|
||||||
|
{{ process.name }}: {{ process.status }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Installed OgLives / Subnets Section -->
|
||||||
|
<div *ngIf="!isRepository && !isDhcp">
|
||||||
|
<h3>{{ 'InstalledOglivesTitle' | translate }}</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'idLabel' | translate }}</th>
|
||||||
|
<th>{{ 'kernelLabel' | translate }}</th>
|
||||||
|
<th>{{ 'architectureLabel' | translate }}</th>
|
||||||
|
<th>{{ 'revisionLabel' | translate }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let item of installedOgLives">
|
||||||
|
<td>{{ item.id }}</td>
|
||||||
|
<td>{{ item.kernel }}</td>
|
||||||
|
<td>{{ item.architecture }}</td>
|
||||||
|
<td>{{ item.revision }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="isDhcp">
|
||||||
|
<h3>{{ 'subnets' | translate }}</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'idLabel' | translate }}</th>
|
||||||
|
<th>{{ 'bootFileNameLabel' | translate }}</th>
|
||||||
|
<th>{{ 'nextServerLabel' | translate }}</th>
|
||||||
|
<th>{{ 'ipLabel' | translate }}</th>
|
||||||
|
<th>{{ 'clientsLabel' | translate }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let item of subnets">
|
||||||
|
<td>{{ item.id }}</td>
|
||||||
|
<td>{{ item['boot-file-name'] }}</td>
|
||||||
|
<td>{{ item['next-server'] }}</td>
|
||||||
|
<td>{{ item.subnet }}</td>
|
||||||
|
<td>{{ item.reservations.length }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { LoadingComponent } from 'src/app/shared/loading/loading.component';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { StatusTabComponent } from './status-tab.component';
|
||||||
|
|
||||||
|
describe('StatusTabComponent', () => {
|
||||||
|
let component: StatusTabComponent;
|
||||||
|
let fixture: ComponentFixture<StatusTabComponent>;
|
||||||
|
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url'
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [StatusTabComponent, LoadingComponent],
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
ToastrModule.forRoot(),
|
||||||
|
MatDialogModule,
|
||||||
|
MatTabsModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
NgxChartsModule,
|
||||||
|
BrowserAnimationsModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(StatusTabComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-status-tab',
|
||||||
|
templateUrl: './status-tab.component.html',
|
||||||
|
styleUrl: './status-tab.component.css'
|
||||||
|
})
|
||||||
|
export class StatusTabComponent {
|
||||||
|
@Input() loading: boolean = false;
|
||||||
|
@Input() diskUsage: any = {};
|
||||||
|
@Input() servicesStatus: any = {};
|
||||||
|
@Input() installedOgLives: any[] = [];
|
||||||
|
@Input() subnets: any[] = [];
|
||||||
|
@Input() diskUsageChartData: any[] = [];
|
||||||
|
@Input() showLabels: boolean = true;
|
||||||
|
@Input() isDoughnut: boolean = true;
|
||||||
|
@Input() colorScheme: any = {
|
||||||
|
domain: ['#df200d', '#26a700']
|
||||||
|
};
|
||||||
|
@Input() view: [number, number] = [400, 220];
|
||||||
|
@Input() isDhcp: boolean = false;
|
||||||
|
@Input() processesStatus: any = {};
|
||||||
|
@Input() ramUsage: any = {};
|
||||||
|
@Input() cpuUsage: any = {};
|
||||||
|
@Input() ramUsageChartData: any[] = [];
|
||||||
|
@Input() isRepository: boolean = false;
|
||||||
|
|
||||||
|
getServices(): { name: string, status: string }[] {
|
||||||
|
if (!this.servicesStatus) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const services = Object.keys(this.servicesStatus).map(key => ({
|
||||||
|
name: key,
|
||||||
|
status: this.servicesStatus[key]
|
||||||
|
}))
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
getProcesses(): { name: string, status: string }[] {
|
||||||
|
if (!this.processesStatus) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return Object.keys(this.processesStatus).map(key => ({
|
||||||
|
name: key,
|
||||||
|
status: this.processesStatus[key]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
formatBytes(bytes: number): string {
|
||||||
|
if (bytes >= 1e9) {
|
||||||
|
return (bytes / 1e9).toFixed(2) + ' GB';
|
||||||
|
} else if (bytes >= 1e6) {
|
||||||
|
return (bytes / 1e6).toFixed(2) + ' MB';
|
||||||
|
} else if (bytes >= 1e3) {
|
||||||
|
return (bytes / 1e3).toFixed(2) + ' KB';
|
||||||
|
} else {
|
||||||
|
return bytes + ' B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,15 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-container {
|
||||||
|
flex-grow: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0rem 1rem 0rem 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.client-icon {
|
.client-icon {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
@ -258,27 +267,72 @@
|
||||||
.disk-container {
|
.disk-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
border: 2px solid #d1d9e6;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center; /* Centra contenido verticalmente */
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-container {
|
.table-container {
|
||||||
flex: 3;
|
flex: 1;
|
||||||
overflow-x: auto;
|
display: flex;
|
||||||
|
justify-content: center; /* Centrar la tabla */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.mat-elevation-z8 {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 800px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-header-cell {
|
||||||
|
background-color: #d1d9e6 !important; /* Encabezado más moderno */
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-cell {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-chip {
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.charts-container {
|
.charts-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-wrap: wrap;
|
||||||
gap: 10px;
|
justify-content: center; /* Centra los gráficos */
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disk-usage {
|
.disk-usage {
|
||||||
|
background-color: white;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
justify-self: center;
|
||||||
|
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.back-button {
|
.back-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
<div class="header-container">
|
<app-loading [isLoading]="loading"></app-loading>
|
||||||
<h2 class="title">{{ 'clientDetailsTitle' | translate }}</h2>
|
|
||||||
|
<div class="client-container">
|
||||||
|
<div class="header-container">
|
||||||
|
<h2 class="title">{{ 'clientDetailsTitle' | translate }} {{ clientData.name }}</h2>
|
||||||
<div class="client-button-row">
|
<div class="client-button-row">
|
||||||
<button class="back-button" (click)="navigateToGroups()">
|
<button class="back-button" (click)="navigateToGroups()">
|
||||||
<mat-icon>arrow_back</mat-icon>
|
<mat-icon>arrow_back</mat-icon>
|
||||||
{{ 'Back' | translate }}
|
{{ 'back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-loading [isLoading]="loading"></app-loading>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
<div *ngIf="!loading" class="client-info">
|
<div *ngIf="!loading" class="client-info">
|
||||||
<div class="info-section">
|
<div class="info-section">
|
||||||
<div class="two-column-table">
|
<div class="two-column-table">
|
||||||
<div class="table-row" *ngFor="let clientData of generalData">
|
<div class="table-row" *ngFor="let clientData of generalData">
|
||||||
|
@ -25,12 +28,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<h2 class="title" i18n="@@adminImagesTitle">Discos/Particiones</h2>
|
<h2 class="title" i18n="@@adminImagesTitle">Discos/Particiones</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="disk-container">
|
<div class="disk-container">
|
||||||
<!-- Tabla de particiones -->
|
<!-- Tabla de particiones -->
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||||
|
@ -56,7 +59,7 @@
|
||||||
<div class="charts-container">
|
<div class="charts-container">
|
||||||
<ng-container *ngIf="diskUsageData && diskUsageData.length > 0">
|
<ng-container *ngIf="diskUsageData && diskUsageData.length > 0">
|
||||||
<div *ngFor="let disk of chartDisk" class="disk-usage">
|
<div *ngFor="let disk of chartDisk" class="disk-usage">
|
||||||
<ngx-charts-pie-chart [view]="view" [results]="disk.chartData" [doughnut]="true">
|
<ngx-charts-pie-chart class="chart" [view]="view" [results]="disk.chartData" [doughnut]="true">
|
||||||
</ngx-charts-pie-chart>
|
</ngx-charts-pie-chart>
|
||||||
|
|
||||||
<h3>Disco {{ disk.diskNumber }}</h3>
|
<h3>Disco {{ disk.diskNumber }}</h3>
|
||||||
|
@ -65,4 +68,6 @@
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import {DatePipe} from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import {MatTableDataSource} from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component";
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import { Router } from "@angular/router";
|
||||||
import {Router} from "@angular/router";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {ToastrService} from "ngx-toastr";
|
|
||||||
import { ManageClientComponent } from "../../shared/clients/manage-client/manage-client.component";
|
import { ManageClientComponent } from "../../shared/clients/manage-client/manage-client.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
interface ClientInfo {
|
interface ClientInfo {
|
||||||
property: string;
|
property: string;
|
||||||
|
@ -19,7 +19,7 @@ interface ClientInfo {
|
||||||
styleUrl: './client-main-view.component.css'
|
styleUrl: './client-main-view.component.css'
|
||||||
})
|
})
|
||||||
export class ClientMainViewComponent implements OnInit {
|
export class ClientMainViewComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
@ViewChild('assistantContainer') assistantContainer!: ElementRef;
|
@ViewChild('assistantContainer') assistantContainer!: ElementRef;
|
||||||
clientUuid: string;
|
clientUuid: string;
|
||||||
clientData: any = {};
|
clientData: any = {};
|
||||||
|
@ -38,17 +38,17 @@ export class ClientMainViewComponent implements OnInit {
|
||||||
showLegend: boolean = true;
|
showLegend: boolean = true;
|
||||||
|
|
||||||
arrayCommands: any[] = [
|
arrayCommands: any[] = [
|
||||||
{name: 'Enceder', slug: 'power-on'},
|
{ name: 'Enceder', slug: 'power-on' },
|
||||||
{name: 'Apagar', slug: 'power-off'},
|
{ name: 'Apagar', slug: 'power-off' },
|
||||||
{name: 'Reiniciar', slug: 'reboot'},
|
{ name: 'Reiniciar', slug: 'reboot' },
|
||||||
{name: 'Iniciar Sesión', slug: 'login'},
|
{ name: 'Iniciar Sesión', slug: 'login' },
|
||||||
{name: 'Crear imagen', slug: 'create-image'},
|
{ name: 'Crear imagen', slug: 'create-image' },
|
||||||
{name: 'Clonar/desplegar imagen', slug: 'deploy-image'},
|
{ name: 'Clonar/desplegar imagen', slug: 'deploy-image' },
|
||||||
{name: 'Eliminar Imagen Cache', slug: 'delete-image-cache'},
|
{ name: 'Eliminar Imagen Cache', slug: 'delete-image-cache' },
|
||||||
{name: 'Particionar y Formatear', slug: 'partition'},
|
{ name: 'Particionar y Formatear', slug: 'partition' },
|
||||||
{name: 'Inventario Software', slug: 'software-inventory'},
|
{ name: 'Inventario Software', slug: 'software-inventory' },
|
||||||
{name: 'Inventario Hardware', slug: 'hardware-inventory'},
|
{ name: 'Inventario Hardware', slug: 'hardware-inventory' },
|
||||||
{name: 'Ejecutar script', slug: 'run-script'},
|
{ name: 'Ejecutar script', slug: 'run-script' },
|
||||||
];
|
];
|
||||||
|
|
||||||
datePipe: DatePipe = new DatePipe('es-ES');
|
datePipe: DatePipe = new DatePipe('es-ES');
|
||||||
|
@ -91,9 +91,11 @@ export class ClientMainViewComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
|
private configService: ConfigService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private toastService: ToastrService
|
private toastService: ToastrService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
const url = window.location.href;
|
const url = window.location.href;
|
||||||
const segments = url.split('/');
|
const segments = url.split('/');
|
||||||
this.clientUuid = segments[segments.length - 1];
|
this.clientUuid = segments[segments.length - 1];
|
||||||
|
@ -198,15 +200,16 @@ export class ClientMainViewComponent implements OnInit {
|
||||||
|
|
||||||
onEditClick(event: MouseEvent, uuid: string): void {
|
onEditClick(event: MouseEvent, uuid: string): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dialogRef = this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' } );
|
const dialogRef = this.dialog.open(ManageClientComponent, { data: { uuid }, width: '900px' });
|
||||||
dialogRef.afterClosed().subscribe();
|
dialogRef.afterClosed().subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPartitions(): void {
|
loadPartitions(): void {
|
||||||
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[diskNumber, partitionNumber]=ASC`).subscribe({
|
this.http.get<any>(`${this.baseUrl}/partitions?client.id=${this.clientData?.id}&order[diskNumber, partitionNumber]=ASC`).subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
this.dataSource = data['hydra:member'];
|
const filteredPartitions = data['hydra:member'].filter((partition: any) => partition.partitionNumber !== 0);
|
||||||
this.partitions = data['hydra:member'];
|
this.dataSource = filteredPartitions;
|
||||||
|
this.partitions = filteredPartitions;
|
||||||
this.calculateDiskUsage();
|
this.calculateDiskUsage();
|
||||||
},
|
},
|
||||||
error: error => {
|
error: error => {
|
||||||
|
@ -215,6 +218,7 @@ export class ClientMainViewComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
loadCommands(): void {
|
loadCommands(): void {
|
||||||
this.http.get<any>(`${this.baseUrl}/commands?`).subscribe({
|
this.http.get<any>(`${this.baseUrl}/commands?`).subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
|
|
|
@ -43,8 +43,8 @@ table {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-width {
|
.custom-width {
|
||||||
width: 100%;
|
width: 50%;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,8 @@ table {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 10px;
|
padding: 10px 10px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-elevation-z8 {
|
.mat-elevation-z8 {
|
||||||
|
@ -74,3 +75,15 @@ table {
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-container-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-row {
|
||||||
|
display: flex;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
Crear imagen desde {{ clientName }}
|
Crear imagen desde {{ clientName }}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="subnets-button-row">
|
<div class="button-row">
|
||||||
<button class="action-button" (click)="save()">Ejecutar</button>
|
<button class="action-button" (click)="save()">Ejecutar</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
<div class="select-container">
|
<div class="select-container">
|
||||||
<mat-form-field appearance="fill" class="full-width">
|
<mat-form-field appearance="fill" class="custom-width">
|
||||||
<mat-label>Nombre canónico</mat-label>
|
<mat-label>Nombre canónico</mat-label>
|
||||||
<input matInput [(ngModel)]="name" placeholder="Nombre canónico. En minúscula y sin espacios" required>
|
<input matInput [(ngModel)]="name" placeholder="Nombre canónico. En minúscula y sin espacios" required>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import {Component, EventEmitter, Output} from '@angular/core';
|
import { Component, EventEmitter, Output } from '@angular/core';
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import {MatTableDataSource} from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import {SelectionModel} from "@angular/cdk/collections";
|
import { SelectionModel } from "@angular/cdk/collections";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-image',
|
selector: 'app-create-image',
|
||||||
templateUrl: './create-image.component.html',
|
templateUrl: './create-image.component.html',
|
||||||
styleUrl: './create-image.component.css'
|
styleUrl: './create-image.component.css'
|
||||||
})
|
})
|
||||||
export class CreateClientImageComponent {
|
export class CreateClientImageComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
@Output() dataChange = new EventEmitter<any>();
|
@Output() dataChange = new EventEmitter<any>();
|
||||||
|
|
||||||
errorMessage = '';
|
errorMessage = '';
|
||||||
|
@ -57,10 +59,12 @@ export class CreateClientImageComponent {
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
) {
|
||||||
) {}
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.clientId = this.route.snapshot.paramMap.get('id');
|
this.clientId = this.route.snapshot.paramMap.get('id');
|
||||||
|
|
|
@ -75,6 +75,8 @@ table {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 10px 10px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-elevation-z8 {
|
.mat-elevation-z8 {
|
||||||
|
@ -130,3 +132,8 @@ table {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-row {
|
||||||
|
display: flex;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{{ 'deployImage' | translate }}
|
{{ 'deployImage' | translate }}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="subnets-button-row">
|
<div class="button-row">
|
||||||
<button class="action-button" (click)="save()">Ejecutar</button>
|
<button class="action-button" (click)="save()">Ejecutar</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,13 +41,6 @@
|
||||||
<mat-divider style="margin-top: 20px;"></mat-divider>
|
<mat-divider style="margin-top: 20px;"></mat-divider>
|
||||||
|
|
||||||
<div class="select-container">
|
<div class="select-container">
|
||||||
<div class="option-container">
|
|
||||||
<mat-radio-group [(ngModel)]="selectedOption" name="selectedOption" aria-label="Selecciona una opcion">
|
|
||||||
<mat-radio-button value="update-cache">Actualizar cache</mat-radio-button>
|
|
||||||
<mat-radio-button value="deploy-image">Desplegar imagen</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="deploy-container">
|
<div class="deploy-container">
|
||||||
<mat-form-field appearance="fill" class="full-width">
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
<mat-label>Seleccione imagen</mat-label>
|
<mat-label>Seleccione imagen</mat-label>
|
||||||
|
@ -60,7 +53,7 @@
|
||||||
<mat-form-field appearance="fill" class="full-width">
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
<mat-label>Seleccione método de deploy</mat-label>
|
<mat-label>Seleccione método de deploy</mat-label>
|
||||||
<mat-select [(ngModel)]="selectedMethod" name="selectedMethod">
|
<mat-select [(ngModel)]="selectedMethod" name="selectedMethod">
|
||||||
<mat-option *ngFor="let method of deployMethods" [value]="method">{{ method }}</mat-option>
|
<mat-option *ngFor="let method of allMethods" [value]="method">{{ method }}</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,9 +83,9 @@
|
||||||
|
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<div class="options-container">
|
<div class="options-container">
|
||||||
<h3 *ngIf="isMethod('udpcast') || isMethod('uftp')" class="input-group">Opciones multicast</h3>
|
<h3 *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')" class="input-group">Opciones multicast</h3>
|
||||||
<h3 *ngIf="isMethod('p2p')" class="input-group">Opciones torrent</h3>
|
<h3 *ngIf="isMethod('p2p')" class="input-group">Opciones torrent</h3>
|
||||||
<div *ngIf="isMethod('udpcast') || isMethod('uftp')" class="input-group">
|
<div *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')" class="input-group">
|
||||||
<mat-form-field appearance="fill" class="input-field">
|
<mat-form-field appearance="fill" class="input-field">
|
||||||
<mat-label>Puerto</mat-label>
|
<mat-label>Puerto</mat-label>
|
||||||
<input matInput [(ngModel)]="mcastPort" name="mcastPort" type="number">
|
<input matInput [(ngModel)]="mcastPort" name="mcastPort" type="number">
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { DeployImageComponent } from './deploy-image.component';
|
import { DeployImageComponent } from './deploy-image.component';
|
||||||
import { provideHttpClient } from '@angular/common/http';
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||||
|
@ -11,7 +10,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
import { MatRadioModule } from '@angular/material/radio'; // Importar MatRadioModule
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { ToastrModule, ToastrService } from 'ngx-toastr';
|
import { ToastrModule, ToastrService } from 'ngx-toastr';
|
||||||
|
@ -19,12 +18,18 @@ import { provideRouter } from '@angular/router';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import {MatExpansionModule} from "@angular/material/expansion";
|
import {MatExpansionModule} from "@angular/material/expansion";
|
||||||
import {LoadingComponent} from "../../../../../shared/loading/loading.component";
|
import {LoadingComponent} from "../../../../../shared/loading/loading.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('DeployImageComponent', () => {
|
describe('DeployImageComponent', () => {
|
||||||
let component: DeployImageComponent;
|
let component: DeployImageComponent;
|
||||||
let fixture: ComponentFixture<DeployImageComponent>;
|
let fixture: ComponentFixture<DeployImageComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [DeployImageComponent, LoadingComponent],
|
declarations: [DeployImageComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -57,7 +62,8 @@ describe('DeployImageComponent', () => {
|
||||||
{
|
{
|
||||||
provide: MAT_DIALOG_DATA,
|
provide: MAT_DIALOG_DATA,
|
||||||
useValue: {}
|
useValue: {}
|
||||||
}
|
},
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
import { Component, EventEmitter, Output } from '@angular/core';
|
||||||
import {MatTableDataSource} from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import {SelectionModel} from "@angular/cdk/collections";
|
import { SelectionModel } from "@angular/cdk/collections";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-deploy-image',
|
selector: 'app-deploy-image',
|
||||||
|
@ -11,7 +12,7 @@ import {ActivatedRoute, Router} from "@angular/router";
|
||||||
styleUrl: './deploy-image.component.css'
|
styleUrl: './deploy-image.component.css'
|
||||||
})
|
})
|
||||||
export class DeployImageComponent {
|
export class DeployImageComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
@Output() dataChange = new EventEmitter<any>();
|
@Output() dataChange = new EventEmitter<any>();
|
||||||
|
|
||||||
errorMessage = '';
|
errorMessage = '';
|
||||||
|
@ -20,7 +21,6 @@ export class DeployImageComponent {
|
||||||
images: any[] = [];
|
images: any[] = [];
|
||||||
clientName: string = '';
|
clientName: string = '';
|
||||||
selectedImage: any = null;
|
selectedImage: any = null;
|
||||||
selectedOption: string | null = 'deploy-image';
|
|
||||||
selectedMethod: string | null = null;
|
selectedMethod: string | null = null;
|
||||||
selectedPartition: any = null;
|
selectedPartition: any = null;
|
||||||
mcastIp: string = '';
|
mcastIp: string = '';
|
||||||
|
@ -42,25 +42,19 @@ export class DeployImageComponent {
|
||||||
{ name: 'Seeder', value: 'seeder' },
|
{ name: 'Seeder', value: 'seeder' },
|
||||||
];
|
];
|
||||||
protected multicastModeOptions = [
|
protected multicastModeOptions = [
|
||||||
{ name: 'Half duplex', value: "half"},
|
{ name: 'Half duplex', value: "half" },
|
||||||
{ name: 'Full duplex', value: "full"},
|
{ name: 'Full duplex', value: "full" },
|
||||||
];
|
];
|
||||||
|
|
||||||
allMethods = [
|
allMethods = [
|
||||||
'uftp',
|
'uftp',
|
||||||
'udpcast',
|
'udpcast',
|
||||||
|
'udpcast-direct',
|
||||||
'unicast',
|
'unicast',
|
||||||
'unicast-direct',
|
'unicast-direct',
|
||||||
'p2p'
|
'p2p'
|
||||||
];
|
];
|
||||||
|
|
||||||
updateCacheMethods = [
|
|
||||||
'uftp',
|
|
||||||
'udpcast',
|
|
||||||
'unicast',
|
|
||||||
'p2p'
|
|
||||||
];
|
|
||||||
|
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
columns = [
|
columns = [
|
||||||
{
|
{
|
||||||
|
@ -96,9 +90,10 @@ export class DeployImageComponent {
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private route: ActivatedRoute,
|
private configService: ConfigService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
const navigation = this.router.getCurrentNavigation();
|
const navigation = this.router.getCurrentNavigation();
|
||||||
this.clientData = navigation?.extras?.state?.['clientData'];
|
this.clientData = navigation?.extras?.state?.['clientData'];
|
||||||
this.clientId = this.clientData?.[0]['@id'];
|
this.clientId = this.clientData?.[0]['@id'];
|
||||||
|
@ -106,10 +101,6 @@ export class DeployImageComponent {
|
||||||
this.loadPartitions()
|
this.loadPartitions()
|
||||||
}
|
}
|
||||||
|
|
||||||
get deployMethods() {
|
|
||||||
return this.selectedOption === 'update-cache' ? this.updateCacheMethods : this.allMethods;
|
|
||||||
}
|
|
||||||
|
|
||||||
isMethod(method: string): boolean {
|
isMethod(method: string): boolean {
|
||||||
return this.selectedMethod === method;
|
return this.selectedMethod === method;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {ActivatedRoute, Router} from "@angular/router";
|
||||||
import { PARTITION_TYPES } from '../../../../../shared/constants/partition-types';
|
import { PARTITION_TYPES } from '../../../../../shared/constants/partition-types';
|
||||||
import { FILESYSTEM_TYPES } from '../../../../../shared/constants/filesystem-types';
|
import { FILESYSTEM_TYPES } from '../../../../../shared/constants/filesystem-types';
|
||||||
import {toUnredirectedSourceFile} from "@angular/compiler-cli/src/ngtsc/util/src/typescript";
|
import {toUnredirectedSourceFile} from "@angular/compiler-cli/src/ngtsc/util/src/typescript";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
interface Partition {
|
interface Partition {
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
|
@ -27,7 +28,8 @@ interface Partition {
|
||||||
styleUrls: ['./partition-assistant.component.css']
|
styleUrls: ['./partition-assistant.component.css']
|
||||||
})
|
})
|
||||||
export class PartitionAssistantComponent {
|
export class PartitionAssistantComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
@Output() dataChange = new EventEmitter<any>();
|
@Output() dataChange = new EventEmitter<any>();
|
||||||
partitionTypes = PARTITION_TYPES;
|
partitionTypes = PARTITION_TYPES;
|
||||||
filesystemTypes = FILESYSTEM_TYPES;
|
filesystemTypes = FILESYSTEM_TYPES;
|
||||||
|
@ -42,8 +44,6 @@ export class PartitionAssistantComponent {
|
||||||
clientData: any = [];
|
clientData: any = [];
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
|
||||||
private apiUrl: string = this.baseUrl + '/partitions';
|
|
||||||
|
|
||||||
view: [number, number] = [400, 300];
|
view: [number, number] = [400, 300];
|
||||||
showLegend = true;
|
showLegend = true;
|
||||||
showLabels = true;
|
showLabels = true;
|
||||||
|
@ -53,7 +53,10 @@ export class PartitionAssistantComponent {
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private configService: ConfigService,
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = this.baseUrl + '/partitions';
|
||||||
const navigation = this.router.getCurrentNavigation();
|
const navigation = this.router.getCurrentNavigation();
|
||||||
this.clientData = navigation?.extras?.state?.['clientData'];
|
this.clientData = navigation?.extras?.state?.['clientData'];
|
||||||
this.clientId = this.clientData[0]['@id'];
|
this.clientId = this.clientData[0]['@id'];
|
||||||
|
|
|
@ -258,11 +258,11 @@ mat-tree mat-tree-node.disabled:hover {
|
||||||
|
|
||||||
.client-name {
|
.client-name {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 16px;
|
font-weight: 500;
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters-container {
|
.filters-container {
|
||||||
|
@ -319,11 +319,26 @@ mat-tree mat-tree-node.disabled:hover {
|
||||||
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-image {
|
.client-details {
|
||||||
width: 35px;
|
flex-grow: 1;
|
||||||
height: 35px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-icons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 8px;
|
}
|
||||||
|
|
||||||
|
.client-status-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-ip {
|
.client-ip {
|
||||||
|
@ -338,11 +353,9 @@ mat-tree mat-tree-node.disabled:hover {
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-icons {
|
.sync-spinner {
|
||||||
display: flex;
|
margin-left: 1em;
|
||||||
justify-content: center;
|
margin-right: 1em;
|
||||||
gap: 1px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-elevation-z8 {
|
.mat-elevation-z8 {
|
||||||
|
@ -360,10 +373,6 @@ mat-tree mat-tree-node.disabled:hover {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-details {
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1560px) {
|
@media (max-width: 1560px) {
|
||||||
.clients-view-header {
|
.clients-view-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -60,12 +60,14 @@
|
||||||
</button>
|
</button>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="form-field search-select" appearance="outline">
|
<mat-form-field class="form-field search-select" appearance="outline">
|
||||||
<mat-select placeholder="Buscar por estado..." #clientSearchStatusInput (selectionChange)="onClientFilterStatusInput($event.value)">
|
<mat-select placeholder="Buscar por estado..." #clientSearchStatusInput
|
||||||
|
(selectionChange)="onClientFilterStatusInput($event.value)">
|
||||||
<mat-option *ngFor="let option of status" [value]="option.value">
|
<mat-option *ngFor="let option of status" [value]="option.value">
|
||||||
{{ option.name }}
|
{{ option.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
<button *ngIf="clientSearchStatusInput.value" mat-icon-button matSuffix aria-label="Clear tree search" (click)="clearStatusFilter($event, clientSearchStatusInput)">
|
<button *ngIf="clientSearchStatusInput.value" mat-icon-button matSuffix aria-label="Clear tree search"
|
||||||
|
(click)="clearStatusFilter($event, clientSearchStatusInput)">
|
||||||
<mat-icon>close</mat-icon>
|
<mat-icon>close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
@ -226,7 +228,7 @@
|
||||||
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(client)"
|
<mat-checkbox (click)="$event.stopPropagation()" (change)="toggleRow(client)"
|
||||||
[checked]="selection.isSelected(client)" [disabled]="client.status === 'busy'">
|
[checked]="selection.isSelected(client)" [disabled]="client.status === 'busy'">
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
|
<img style="margin-top: 0.5em;" [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
|
||||||
class="client-image" />
|
class="client-image" />
|
||||||
|
|
||||||
<div class="client-details">
|
<div class="client-details">
|
||||||
|
@ -234,14 +236,6 @@
|
||||||
<span class="client-ip">{{ client.ip }}</span>
|
<span class="client-ip">{{ client.ip }}</span>
|
||||||
<span class="client-ip">{{ client.mac }}</span>
|
<span class="client-ip">{{ client.mac }}</span>
|
||||||
<div class="action-icons">
|
<div class="action-icons">
|
||||||
<button *ngIf="(!syncStatus || syncingClientId !== client.uuid)" mat-icon-button
|
|
||||||
color="primary" (click)="getStatus(client, selectedNode)">
|
|
||||||
<mat-icon>sync</mat-icon>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button *ngIf="syncStatus && syncingClientId === client.uuid" mat-icon-button color="primary">
|
|
||||||
<mat-spinner diameter="24"></mat-spinner>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
|
<app-execute-command [clientData]="[client]" [buttonType]="'icon'" [icon]="'terminal'"
|
||||||
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
|
[disabled]="selection.selected.length > 1 || (selection.selected.length === 1 && !selection.isSelected(client))"></app-execute-command>
|
||||||
|
@ -252,6 +246,10 @@
|
||||||
<mat-icon>more_vert</mat-icon>
|
<mat-icon>more_vert</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<span class="sync-spinner" *ngIf="syncStatus && syncingClientId === client.uuid">
|
||||||
|
<mat-spinner diameter="24"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
|
||||||
<mat-menu #clientMenu="matMenu">
|
<mat-menu #clientMenu="matMenu">
|
||||||
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
<button mat-menu-item (click)="onEditClick($event, client.type, client.uuid)">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
|
@ -261,6 +259,11 @@
|
||||||
<mat-icon>visibility</mat-icon>
|
<mat-icon>visibility</mat-icon>
|
||||||
<span>{{ 'viewDetails' | translate }}</span>
|
<span>{{ 'viewDetails' | translate }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button mat-menu-item *ngIf="(!syncStatus || syncingClientId !== client.uuid)"
|
||||||
|
(click)="getStatus(client, selectedNode)">
|
||||||
|
<mat-icon>sync</mat-icon>
|
||||||
|
<span>{{ 'sync' | translate }}</span>
|
||||||
|
</button>
|
||||||
<button mat-menu-item (click)="onDeleteClick($event, client)">
|
<button mat-menu-item (click)="onDeleteClick($event, client)">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
<span>{{ 'delete' | translate }}</span>
|
<span>{{ 'delete' | translate }}</span>
|
||||||
|
@ -300,8 +303,13 @@
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'status' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'status' | translate }} </th>
|
||||||
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}"
|
<td mat-cell *matCellDef="let client" matTooltip="{{ getClientPath(client) }}"
|
||||||
matTooltipPosition="left" matTooltipShowDelay="500">
|
matTooltipPosition="left" matTooltipShowDelay="500">
|
||||||
|
<div class="client-status-container">
|
||||||
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
|
<img [src]="'assets/images/ordenador_' + client.status + '.png'" alt="Client Icon"
|
||||||
class="client-image" />
|
class="client-image" />
|
||||||
|
<span *ngIf="syncStatus && syncingClientId === client.uuid">
|
||||||
|
<mat-spinner diameter="24"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -372,7 +380,8 @@
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<tr mat-header-row style="background-color: #f3f3f3;" *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
<tr mat-header-row style="background-color: #f3f3f3;"
|
||||||
|
*matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -27,12 +27,18 @@ import { MatTreeModule } from '@angular/material/tree';
|
||||||
import { TreeNode } from './model/model';
|
import { TreeNode } from './model/model';
|
||||||
import { LoadingComponent } from '../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../shared/loading/loading.component';
|
||||||
import { ExecuteCommandComponent } from '../commands/main-commands/execute-command/execute-command.component';
|
import { ExecuteCommandComponent } from '../commands/main-commands/execute-command/execute-command.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('GroupsComponent', () => {
|
describe('GroupsComponent', () => {
|
||||||
let component: GroupsComponent;
|
let component: GroupsComponent;
|
||||||
let fixture: ComponentFixture<GroupsComponent>;
|
let fixture: ComponentFixture<GroupsComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [GroupsComponent, ExecuteCommandComponent, LoadingComponent],
|
declarations: [GroupsComponent, ExecuteCommandComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -63,7 +69,8 @@ describe('GroupsComponent', () => {
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: {} },
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: { data: { id: 123 } } }
|
{ provide: MAT_DIALOG_DATA, useValue: { data: { id: 123 } } },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
@ -128,4 +135,4 @@ describe('GroupsComponent', () => {
|
||||||
{ params: jasmine.any(Object) }
|
{ params: jasmine.any(Object) }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
})
|
|
@ -17,12 +17,14 @@ import { DeleteModalComponent } from '../../shared/delete_modal/delete-modal/del
|
||||||
import { ClassroomViewDialogComponent } from './shared/classroom-view/classroom-view-modal';
|
import { ClassroomViewDialogComponent } from './shared/classroom-view/classroom-view-modal';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
import { PageEvent } from '@angular/material/paginator';
|
||||||
import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component";
|
import { CreateMultipleClientComponent } from "./shared/clients/create-multiple-client/create-multiple-client.component";
|
||||||
import { SelectionModel } from "@angular/cdk/collections";
|
import { SelectionModel } from "@angular/cdk/collections";
|
||||||
import { ManageClientComponent } from "./shared/clients/manage-client/manage-client.component";
|
import { ManageClientComponent } from "./shared/clients/manage-client/manage-client.component";
|
||||||
import { debounceTime } from 'rxjs/operators';
|
import { debounceTime } from 'rxjs/operators';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { GlobalStatusComponent } from '../global-status/global-status.component';
|
||||||
|
|
||||||
enum NodeType {
|
enum NodeType {
|
||||||
OrganizationalUnit = 'organizational-unit',
|
OrganizationalUnit = 'organizational-unit',
|
||||||
|
@ -38,8 +40,8 @@ enum NodeType {
|
||||||
styleUrls: ['./groups.component.css'],
|
styleUrls: ['./groups.component.css'],
|
||||||
})
|
})
|
||||||
export class GroupsComponent implements OnInit, OnDestroy {
|
export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
mercureUrl: string = import.meta.env.NG_APP_OGCORE_MERCURE_BASE_URL;
|
mercureUrl: string;
|
||||||
organizationalUnits: UnidadOrganizativa[] = [];
|
organizationalUnits: UnidadOrganizativa[] = [];
|
||||||
selectedUnidad: UnidadOrganizativa | null = null;
|
selectedUnidad: UnidadOrganizativa | null = null;
|
||||||
selectedDetail: UnidadOrganizativa | null = null;
|
selectedDetail: UnidadOrganizativa | null = null;
|
||||||
|
@ -103,8 +105,11 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private bottomSheet: MatBottomSheet,
|
private bottomSheet: MatBottomSheet,
|
||||||
private joyrideService: JoyrideService,
|
private joyrideService: JoyrideService,
|
||||||
private toastr: ToastrService
|
private toastr: ToastrService,
|
||||||
|
private configService: ConfigService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.mercureUrl = this.configService.mercureUrl;
|
||||||
this.treeFlattener = new MatTreeFlattener<TreeNode, FlatNode>(
|
this.treeFlattener = new MatTreeFlattener<TreeNode, FlatNode>(
|
||||||
this.transformer,
|
this.transformer,
|
||||||
(node) => node.level,
|
(node) => node.level,
|
||||||
|
@ -167,6 +172,7 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.selectedClients.data = updatedClients;
|
this.selectedClients.data = updatedClients;
|
||||||
|
this.arrayClients = updatedClients;
|
||||||
|
|
||||||
console.log(`Estado actualizado para el cliente ${clientUuid}: ${newStatus}`);
|
console.log(`Estado actualizado para el cliente ${clientUuid}: ${newStatus}`);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,18 +3,22 @@ import {HttpClient, HttpParams} from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
import { UnidadOrganizativa } from '../model/model';
|
import { UnidadOrganizativa } from '../model/model';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
|
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
|
private clientsUrl: string;
|
||||||
|
|
||||||
private apiUrl = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=1000`;
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
private clientsUrl = `${this.baseUrl}/clients`;
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/organizational-units?page=1&itemsPerPage=1000`;
|
||||||
constructor(private http: HttpClient) {}
|
this.clientsUrl = `${this.baseUrl}/clients`;
|
||||||
|
}
|
||||||
|
|
||||||
getOrganizationalUnits(search: string = ''): Observable<UnidadOrganizativa[]> {
|
getOrganizationalUnits(search: string = ''): Observable<UnidadOrganizativa[]> {
|
||||||
let url = `${this.apiUrl}&type=organizational-unit`;
|
let url = `${this.apiUrl}&type=organizational-unit`;
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { ClientViewComponent } from "../client-view/client-view.component";
|
||||||
import { CdkDragMove } from '@angular/cdk/drag-drop';
|
import { CdkDragMove } from '@angular/cdk/drag-drop';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
interface GroupedClients {
|
interface GroupedClients {
|
||||||
organizationalUnitName: string;
|
organizationalUnitName: string;
|
||||||
|
@ -16,12 +17,14 @@ interface GroupedClients {
|
||||||
styleUrls: ['./classroom-view.component.css']
|
styleUrls: ['./classroom-view.component.css']
|
||||||
})
|
})
|
||||||
export class ClassroomViewComponent implements OnInit, OnChanges {
|
export class ClassroomViewComponent implements OnInit, OnChanges {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
@Input() clients: any[] = [];
|
@Input() clients: any[] = [];
|
||||||
@Input() pcInTable: number = 5;
|
@Input() pcInTable: number = 5;
|
||||||
groupedClients: GroupedClients[] = [];
|
groupedClients: GroupedClients[] = [];
|
||||||
|
|
||||||
constructor(public dialog: MatDialog, private http: HttpClient, private toastService: ToastrService) { }
|
constructor(public dialog: MatDialog, private http: HttpClient, private toastService: ToastrService, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.groupClientsByOrganizationalUnit();
|
this.groupClientsByOrganizationalUnit();
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import {Component, Inject, OnInit, Optional} from '@angular/core';
|
import { Component, Inject, OnInit, Optional } from '@angular/core';
|
||||||
import {MatDialogRef} from "@angular/material/dialog";
|
import { MatDialogRef } from "@angular/material/dialog";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { MAT_DIALOG_DATA } from "@angular/material/dialog";
|
||||||
import {MAT_DIALOG_DATA} from "@angular/material/dialog";
|
|
||||||
import { DataService } from '../../../services/data.service';
|
import { DataService } from '../../../services/data.service';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-multiple-client',
|
selector: 'app-create-multiple-client',
|
||||||
templateUrl: './create-multiple-client.component.html',
|
templateUrl: './create-multiple-client.component.html',
|
||||||
styleUrl: './create-multiple-client.component.css'
|
styleUrl: './create-multiple-client.component.css'
|
||||||
})
|
})
|
||||||
export class CreateMultipleClientComponent implements OnInit{
|
export class CreateMultipleClientComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string = this.configService.apiUrl;
|
||||||
parentUnits: any[] = [];
|
parentUnits: any[] = [];
|
||||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||||
uploadedClients: any[] = [];
|
uploadedClients: any[] = [];
|
||||||
|
@ -20,16 +20,18 @@ export class CreateMultipleClientComponent implements OnInit{
|
||||||
displayedColumns: string[] = ['name', 'ip', 'mac'];
|
displayedColumns: string[] = ['name', 'ip', 'mac'];
|
||||||
showTextarea: boolean = true;
|
showTextarea: boolean = true;
|
||||||
organizationalUnit: any;
|
organizationalUnit: any;
|
||||||
regex: RegExp = /host\s+(\S+)\s+\{\s+hardware\s+ethernet\s+([a-zA-Z0-9]{2}(:[a-zA-Z0-9]{2}){5});\s+fixed-address\s+((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?));\s+\}/g;
|
regex: RegExp = /host\s+(\S+)\s*\{\s*hardware\s+ethernet\s+([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5});\s*fixed-address\s+((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?));\s*\}/g;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Optional() private dialogRef: MatDialogRef<CreateMultipleClientComponent>,
|
@Optional() private dialogRef: MatDialogRef<CreateMultipleClientComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) private data: any,
|
@Inject(MAT_DIALOG_DATA) private data: any,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private snackBar: MatSnackBar,
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private dataService: DataService
|
private dataService: DataService
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadParentUnits();
|
this.loadParentUnits();
|
||||||
|
|
|
@ -101,6 +101,10 @@
|
||||||
</mat-select>
|
</mat-select>
|
||||||
<mat-error>{{ 'menuError' | translate }}</mat-error>
|
<mat-error>{{ 'menuError' | translate }}</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-checkbox formControlName="maintenance">
|
||||||
|
{{ 'maintenance' | translate }}
|
||||||
|
</mat-checkbox>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,18 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { ManageClientComponent } from './manage-client.component';
|
import { ManageClientComponent } from './manage-client.component';
|
||||||
import { DataService } from '../../../services/data.service';
|
import { DataService } from '../../../services/data.service';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('ManageClientComponent', () => {
|
describe('ManageClientComponent', () => {
|
||||||
let component: ManageClientComponent;
|
let component: ManageClientComponent;
|
||||||
let fixture: ComponentFixture<ManageClientComponent>;
|
let fixture: ComponentFixture<ManageClientComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ManageClientComponent],
|
declarations: [ManageClientComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -28,6 +34,7 @@ describe('ManageClientComponent', () => {
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: {} },
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: { uuid: '123', organizationalUnit: { '@id': '/units/1' } } },
|
{ provide: MAT_DIALOG_DATA, useValue: { uuid: '123', organizationalUnit: { '@id': '/units/1' } } },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService },
|
||||||
DataService
|
DataService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { DataService } from '../../../services/data.service';
|
import { DataService } from '../../../services/data.service';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-manage-client',
|
selector: 'app-manage-client',
|
||||||
|
@ -12,7 +12,7 @@ import { DataService } from '../../../services/data.service';
|
||||||
styleUrls: ['./manage-client.component.css']
|
styleUrls: ['./manage-client.component.css']
|
||||||
})
|
})
|
||||||
export class ManageClientComponent implements OnInit {
|
export class ManageClientComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
clientForm!: FormGroup;
|
clientForm!: FormGroup;
|
||||||
parentUnits: any[] = [];
|
parentUnits: any[] = [];
|
||||||
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
parentUnitsWithPaths: { id: string, name: string, path: string }[] = [];
|
||||||
|
@ -38,11 +38,12 @@ export class ManageClientComponent implements OnInit {
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private dialogRef: MatDialogRef<ManageClientComponent>,
|
private dialogRef: MatDialogRef<ManageClientComponent>,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private snackBar: MatSnackBar,
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.isEditMode = !!data?.uuid;
|
this.isEditMode = !!data?.uuid;
|
||||||
this.dialogTitle = this.isEditMode ? 'editClientDialogTitle' : 'addClientDialogTitle';
|
this.dialogTitle = this.isEditMode ? 'editClientDialogTitle' : 'addClientDialogTitle';
|
||||||
}
|
}
|
||||||
|
@ -89,7 +90,8 @@ export class ManageClientComponent implements OnInit {
|
||||||
hardwareProfile: [null],
|
hardwareProfile: [null],
|
||||||
ogLive: [null],
|
ogLive: [null],
|
||||||
repository: [null],
|
repository: [null],
|
||||||
menu: [null]
|
menu: [null],
|
||||||
|
maintenance: [false]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,6 +250,7 @@ export class ManageClientComponent implements OnInit {
|
||||||
ogLive: data.ogLive ? data.ogLive['@id'] : null,
|
ogLive: data.ogLive ? data.ogLive['@id'] : null,
|
||||||
template: data.template ? data.template['@id'] : null,
|
template: data.template ? data.template['@id'] : null,
|
||||||
menu: data.menu ? data.menu['@id'] : null,
|
menu: data.menu ? data.menu['@id'] : null,
|
||||||
|
maintenance: data.maintenance
|
||||||
});
|
});
|
||||||
resolve();
|
resolve();
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-execute-command-ou',
|
selector: 'app-execute-command-ou',
|
||||||
|
@ -14,15 +15,17 @@ export class ExecuteCommandOuComponent implements OnInit {
|
||||||
clients: any[] = [];
|
clients: any[] = [];
|
||||||
commands: any[] = [];
|
commands: any[] = [];
|
||||||
commandGroups: any[] = [];
|
commandGroups: any[] = [];
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dialogRef: MatDialogRef<ExecuteCommandOuComponent>,
|
private dialogRef: MatDialogRef<ExecuteCommandOuComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
selectedCommand: [null],
|
selectedCommand: [null],
|
||||||
selectedCommandGroup: [null],
|
selectedCommandGroup: [null],
|
||||||
|
|
|
@ -13,12 +13,18 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoadingComponent } from '../../../../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../../../../shared/loading/loading.component';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('ManageOrganizationalUnitComponent', () => {
|
describe('ManageOrganizationalUnitComponent', () => {
|
||||||
let component: ManageOrganizationalUnitComponent;
|
let component: ManageOrganizationalUnitComponent;
|
||||||
let fixture: ComponentFixture<ManageOrganizationalUnitComponent>;
|
let fixture: ComponentFixture<ManageOrganizationalUnitComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ManageOrganizationalUnitComponent, LoadingComponent],
|
declarations: [ManageOrganizationalUnitComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -36,7 +42,8 @@ describe('ManageOrganizationalUnitComponent', () => {
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: {} },
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: {} }
|
{ provide: MAT_DIALOG_DATA, useValue: {} },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { DataService } from "../../../services/data.service";
|
import { DataService } from "../../../services/data.service";
|
||||||
import { ToastrService } from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-manage-organizational-unit',
|
selector: 'app-manage-organizational-unit',
|
||||||
|
@ -11,7 +12,7 @@ import { ToastrService } from "ngx-toastr";
|
||||||
styleUrls: ['./manage-organizational-unit.component.css']
|
styleUrls: ['./manage-organizational-unit.component.css']
|
||||||
})
|
})
|
||||||
export class ManageOrganizationalUnitComponent implements OnInit {
|
export class ManageOrganizationalUnitComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
isLinear = true;
|
isLinear = true;
|
||||||
generalFormGroup: FormGroup;
|
generalFormGroup: FormGroup;
|
||||||
additionalInfoFormGroup: FormGroup;
|
additionalInfoFormGroup: FormGroup;
|
||||||
|
@ -55,11 +56,12 @@ export class ManageOrganizationalUnitComponent implements OnInit {
|
||||||
private dialogRef: MatDialogRef<ManageOrganizationalUnitComponent>,
|
private dialogRef: MatDialogRef<ManageOrganizationalUnitComponent>,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
this.isEditMode = !!data?.uuid;
|
this.isEditMode = !!data?.uuid;
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.generalFormGroup = this._formBuilder.group({
|
this.generalFormGroup = this._formBuilder.group({
|
||||||
name: [null, Validators.required],
|
name: [null, Validators.required],
|
||||||
parent: [data?.parent ? data.parent['@id'] : null],
|
parent: [data?.parent ? data.parent['@id'] : null],
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||||
import {DatePipe} from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-show-organizational-unit',
|
selector: 'app-show-organizational-unit',
|
||||||
|
@ -9,7 +10,7 @@ import {DatePipe} from "@angular/common";
|
||||||
styleUrl: './show-organizational-unit.component.css'
|
styleUrl: './show-organizational-unit.component.css'
|
||||||
})
|
})
|
||||||
export class ShowOrganizationalUnitComponent implements OnInit {
|
export class ShowOrganizationalUnitComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
displayedColumns: string[] = ['property', 'value'];
|
displayedColumns: string[] = ['property', 'value'];
|
||||||
currentCalendar: any;
|
currentCalendar: any;
|
||||||
ou: any;
|
ou: any;
|
||||||
|
@ -26,8 +27,10 @@ export class ShowOrganizationalUnitComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
private dialogRef: MatDialogRef<ShowOrganizationalUnitComponent>,
|
private dialogRef: MatDialogRef<ShowOrganizationalUnitComponent>,
|
||||||
|
private configService: ConfigService,
|
||||||
private http: HttpClient
|
private http: HttpClient
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
.dialog-content {
|
.create-image-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
padding: 1rem;
|
||||||
/* Espacio entre los elementos del formulario */
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-dialog-content.loading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-dialog-content {
|
||||||
|
padding-left: 1.5em;
|
||||||
|
padding-right: 1.5em;
|
||||||
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-form {
|
.image-form {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<app-loading [isLoading]="loading"></app-loading>
|
<div class="create-image-container">
|
||||||
|
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Crear' }} imagen</h2>
|
||||||
<h2 mat-dialog-title>{{ imageId ? 'Editar' : 'Crear' }} imagen</h2>
|
<div class="mat-dialog-content" [ngClass]="{'loading': loading}">
|
||||||
|
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
|
||||||
<mat-dialog-content class="dialog-content">
|
<form *ngIf="!loading" [formGroup]="imageForm" (ngSubmit)="saveImage()" class="image-form">
|
||||||
<form [formGroup]="imageForm" (ngSubmit)="saveImage()" class="image-form">
|
|
||||||
<mat-card *ngIf="showWarning" class="warning-card">
|
<mat-card *ngIf="showWarning" class="warning-card">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-icon color="warn">warning</mat-icon>
|
<mat-icon color="warn">warning</mat-icon>
|
||||||
Ha marcado la casilla <strong>"Imagen Global"</strong>. Se transferirá la imagen al resto de repositorios en el
|
Ha marcado la casilla <strong>"Imagen Global"</strong>. Se transferirá la imagen al resto de repositorios en
|
||||||
|
el
|
||||||
caso de que no exista previamente.
|
caso de que no exista previamente.
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
@ -63,10 +63,10 @@
|
||||||
<p>Código de partición: {{ partitionInfo['partitionCode'] }}</p>
|
<p>Código de partición: {{ partitionInfo['partitionCode'] }}</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
</mat-dialog-content>
|
<mat-dialog-actions class="action-container">
|
||||||
|
|
||||||
<mat-dialog-actions class="action-container">
|
|
||||||
<button class="ordinary-button" (click)="close()">{{ 'cancelButton' | translate }}</button>
|
<button class="ordinary-button" (click)="close()">{{ 'cancelButton' | translate }}</button>
|
||||||
<button class="submit-button" (click)="saveImage()">{{ 'saveButton' | translate }}</button>
|
<button class="submit-button" (click)="saveImage()" [disabled]="loading">{{ 'saveButton' | translate }}</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
</div>
|
|
@ -1,9 +1,10 @@
|
||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import {ToastrService} from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
|
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||||
import {DataService} from "../data.service";
|
import { DataService } from "../data.service";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-image',
|
selector: 'app-create-image',
|
||||||
|
@ -11,12 +12,13 @@ import {DataService} from "../data.service";
|
||||||
styleUrls: ['./create-image.component.css']
|
styleUrls: ['./create-image.component.css']
|
||||||
})
|
})
|
||||||
export class CreateImageComponent implements OnInit {
|
export class CreateImageComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
imageForm: FormGroup<any>;
|
imageForm: FormGroup<any>;
|
||||||
imageId: string | null = null;
|
imageId: string | null = null;
|
||||||
softwareProfiles: any[] = [];
|
softwareProfiles: any[] = [];
|
||||||
repositories: any[] = [];
|
repositories: any[] = [];
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
isEditMode: boolean = false;
|
||||||
partitionInfo: { [key: string]: string } = {};
|
partitionInfo: { [key: string]: string } = {};
|
||||||
showWarning: boolean = false;
|
showWarning: boolean = false;
|
||||||
|
|
||||||
|
@ -25,9 +27,11 @@ export class CreateImageComponent implements OnInit {
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
public dialogRef: MatDialogRef<CreateImageComponent>,
|
public dialogRef: MatDialogRef<CreateImageComponent>,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.imageForm = this.fb.group({
|
this.imageForm = this.fb.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
description: [''],
|
description: [''],
|
||||||
|
@ -42,30 +46,34 @@ export class CreateImageComponent implements OnInit {
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
this.load()
|
this.isEditMode = true;
|
||||||
|
this.load();
|
||||||
|
} else {
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
this.fetchSoftwareProfiles();
|
this.fetchSoftwareProfiles();
|
||||||
this.fetchRepositories();
|
this.fetchRepositories();
|
||||||
this.loading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
load(): void {
|
load(): void {
|
||||||
this.dataService.getImage(this.data).subscribe({
|
this.dataService.getImage(this.data).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
this.imageForm = this.fb.group({
|
this.imageForm.patchValue({
|
||||||
name: [response.name, Validators.required],
|
name: response.name,
|
||||||
description: [response.description],
|
description: response.description,
|
||||||
comments: [response.comments],
|
comments: response.comments,
|
||||||
remotePc: [response.remotePc],
|
remotePc: response.remotePc,
|
||||||
isGlobal: [response.isGlobal],
|
isGlobal: response.isGlobal,
|
||||||
softwareProfile: [response.softwareProfile ? response.softwareProfile['@id'] : null, Validators.required],
|
softwareProfile: response.softwareProfile ? response.softwareProfile['@id'] : null,
|
||||||
imageRepositories: [response.imageRepositories ? response.imageRepositories.map((r: any) => r.imageRepository['@id']) : [], Validators.required],
|
imageRepositories: response.imageRepositories ? response.imageRepositories.map((r: any) => r.imageRepository['@id']) : [],
|
||||||
});
|
});
|
||||||
this.imageId = response['@id'];
|
this.imageId = response['@id'];
|
||||||
this.partitionInfo = response.partitionInfo;
|
this.partitionInfo = response.partitionInfo;
|
||||||
|
this.loading = false;
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
console.error('Error fetching remote calendar:', err);
|
console.error('Error fetching remote calendar:', err);
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/images?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/images?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getImages(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
getImages(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ExportImageComponent } from './export-image.component';
|
import { ExportImageComponent } from './export-image.component';
|
||||||
import {FormBuilder, ReactiveFormsModule} from "@angular/forms";
|
import {FormBuilder, ReactiveFormsModule} from "@angular/forms";
|
||||||
import {ToastrModule, ToastrService} from "ngx-toastr";
|
import {ToastrModule, ToastrService} from "ngx-toastr";
|
||||||
|
@ -14,12 +13,18 @@ import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||||
import {TranslateModule} from "@ngx-translate/core";
|
import {TranslateModule} from "@ngx-translate/core";
|
||||||
import {LoadingComponent} from "../../../shared/loading/loading.component";
|
import {LoadingComponent} from "../../../shared/loading/loading.component";
|
||||||
import {MatProgressSpinner} from "@angular/material/progress-spinner";
|
import {MatProgressSpinner} from "@angular/material/progress-spinner";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('ExportImageComponent', () => {
|
describe('ExportImageComponent', () => {
|
||||||
let component: ExportImageComponent;
|
let component: ExportImageComponent;
|
||||||
let fixture: ComponentFixture<ExportImageComponent>;
|
let fixture: ComponentFixture<ExportImageComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ExportImageComponent, LoadingComponent],
|
declarations: [ExportImageComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -46,7 +51,9 @@ describe('ExportImageComponent', () => {
|
||||||
{
|
{
|
||||||
provide: MAT_DIALOG_DATA,
|
provide: MAT_DIALOG_DATA,
|
||||||
useValue: {}
|
useValue: {}
|
||||||
}]
|
},
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {Router} from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-export-image',
|
selector: 'app-export-image',
|
||||||
|
@ -10,7 +11,7 @@ import {Router} from "@angular/router";
|
||||||
styleUrl: './export-image.component.css'
|
styleUrl: './export-image.component.css'
|
||||||
})
|
})
|
||||||
export class ExportImageComponent implements OnInit {
|
export class ExportImageComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
loading: boolean = true;
|
loading: boolean = true;
|
||||||
repositories: any[] = [];
|
repositories: any[] = [];
|
||||||
selectedRepositories: any[] = [];
|
selectedRepositories: any[] = [];
|
||||||
|
@ -19,10 +20,11 @@ export class ExportImageComponent implements OnInit {
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
public dialogRef: MatDialogRef<ExportImageComponent>,
|
public dialogRef: MatDialogRef<ExportImageComponent>,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { image: any, imageImageRepository: any }
|
@Inject(MAT_DIALOG_DATA) public data: { image: any, imageImageRepository: any }
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import {Component, Input, OnInit} from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { CreateImageComponent } from './create-image/create-image.component';
|
import { CreateImageComponent } from './create-image/create-image.component';
|
||||||
import {Observable} from "rxjs";
|
import { ConfigService } from '@services/config.service';
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -14,7 +13,8 @@ import { JoyrideService } from 'ngx-joyride';
|
||||||
styleUrls: ['./images.component.css']
|
styleUrls: ['./images.component.css']
|
||||||
})
|
})
|
||||||
export class ImagesComponent implements OnInit {
|
export class ImagesComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
itemsPerPage: number = 10;
|
itemsPerPage: number = 10;
|
||||||
|
@ -57,16 +57,18 @@ export class ImagesComponent implements OnInit {
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
private apiUrl = `${this.baseUrl}/images`;
|
|
||||||
@Input() repositoryUuid: any
|
@Input() repositoryUuid: any
|
||||||
private repositoryId: any;
|
private repositoryId: any;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private configService: ConfigService,
|
||||||
private joyrideService: JoyrideService,
|
private joyrideService: JoyrideService,
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/images`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.repositoryUuid) {
|
if (this.repositoryUuid) {
|
||||||
|
@ -100,7 +102,7 @@ export class ImagesComponent implements OnInit {
|
||||||
|
|
||||||
search(): void {
|
search(): void {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.http.get<any>(`${this.apiUrl}?page=${this.page +1 }&itemsPerPage=${this.itemsPerPage}&repositoryId=${this.repositoryId}`, { params: this.filters }).subscribe(
|
this.http.get<any>(`${this.apiUrl}?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}&repositoryId=${this.repositoryId}`, { params: this.filters }).subscribe(
|
||||||
data => {
|
data => {
|
||||||
this.dataSource.data = data['hydra:member'];
|
this.dataSource.data = data['hydra:member'];
|
||||||
this.length = data['hydra:totalItems'];
|
this.length = data['hydra:totalItems'];
|
||||||
|
|
|
@ -9,12 +9,18 @@ import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('LoginComponent', () => {
|
describe('LoginComponent', () => {
|
||||||
let component: LoginComponent;
|
let component: LoginComponent;
|
||||||
let fixture: ComponentFixture<LoginComponent>;
|
let fixture: ComponentFixture<LoginComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [LoginComponent],
|
declarations: [LoginComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -26,7 +32,10 @@ describe('LoginComponent', () => {
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
TranslateModule.forRoot()
|
TranslateModule.forRoot()
|
||||||
],
|
],
|
||||||
providers: [provideHttpClient(withInterceptorsFromDi())]
|
providers: [
|
||||||
|
provideHttpClient(withInterceptorsFromDi()),
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(LoginComponent);
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Router } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { ToastrService } from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import { jwtDecode } from "jwt-decode";
|
import { jwtDecode } from "jwt-decode";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
|
@ -19,14 +20,16 @@ export class LoginComponent {
|
||||||
isLoading: boolean = false;
|
isLoading: boolean = false;
|
||||||
decodedToken: any;
|
decodedToken: any;
|
||||||
|
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private translateService: TranslateService
|
private translateService: TranslateService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
const savedLanguage = localStorage.getItem('language') || 'es';
|
const savedLanguage = localStorage.getItem('language') || 'es';
|
||||||
this.translateService.use(savedLanguage);
|
this.translateService.use(savedLanguage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
|
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {DataService} from "../data.service";
|
import { DataService } from "../data.service";
|
||||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-menu',
|
selector: 'app-create-menu',
|
||||||
templateUrl: './create-menu.component.html',
|
templateUrl: './create-menu.component.html',
|
||||||
styleUrl: './create-menu.component.css'
|
styleUrl: './create-menu.component.css'
|
||||||
})
|
})
|
||||||
export class CreateMenuComponent implements OnInit{
|
export class CreateMenuComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
menuForm: FormGroup<any>;
|
menuForm: FormGroup<any>;
|
||||||
menuId: string | null = null;
|
menuId: string | null = null;
|
||||||
softwareProfiles: any[] = [];
|
softwareProfiles: any[] = [];
|
||||||
|
@ -24,9 +25,11 @@ export class CreateMenuComponent implements OnInit{
|
||||||
public dialogRef: MatDialogRef<CreateMenuComponent>,
|
public dialogRef: MatDialogRef<CreateMenuComponent>,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
|
private configService: ConfigService,
|
||||||
private sanitizer: DomSanitizer,
|
private sanitizer: DomSanitizer,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.menuForm = this.fb.group({
|
this.menuForm = this.fb.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
publicUrl: ['', Validators.required],
|
publicUrl: ['', Validators.required],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@ -8,10 +8,13 @@ import { catchError, map } from 'rxjs/operators';
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/menus?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/menus?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getMenus(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
getMenus(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { MenusComponent } from './menus.component';
|
import { MenusComponent } from './menus.component';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
@ -23,15 +22,21 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { JoyrideModule } from 'ngx-joyride';
|
import { JoyrideModule } from 'ngx-joyride';
|
||||||
import { ToastrModule } from 'ngx-toastr';
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('MenusComponent', () => {
|
describe('MenusComponent', () => {
|
||||||
let component: MenusComponent;
|
let component: MenusComponent;
|
||||||
let fixture: ComponentFixture<MenusComponent>;
|
let fixture: ComponentFixture<MenusComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [MenusComponent],
|
declarations: [MenusComponent],
|
||||||
imports: [ HttpClientTestingModule, ToastrModule.forRoot(), BrowserAnimationsModule, MatDividerModule, MatFormFieldModule, MatInputModule, MatIconModule, MatButtonModule, MatTableModule, MatPaginatorModule, MatTooltipModule, FormsModule, ReactiveFormsModule, MatProgressSpinnerModule, MatDialogModule, MatSelectModule, MatTabsModule, MatAutocompleteModule, MatListModule, MatCardModule, MatMenuModule, TranslateModule.forRoot(), JoyrideModule.forRoot(), ],
|
imports: [ HttpClientTestingModule, ToastrModule.forRoot(), BrowserAnimationsModule, MatDividerModule, MatFormFieldModule, MatInputModule, MatIconModule, MatButtonModule, MatTableModule, MatPaginatorModule, MatTooltipModule, FormsModule, ReactiveFormsModule, MatProgressSpinnerModule, MatDialogModule, MatSelectModule, MatTabsModule, MatAutocompleteModule, MatListModule, MatCardModule, MatMenuModule, TranslateModule.forRoot(), JoyrideModule.forRoot(), ],
|
||||||
|
providers: [ { provide: ConfigService, useValue: mockConfigService } ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import {Component, OnInit} from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {MatTableDataSource} from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import {DatePipe} from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import {JoyrideService} from "ngx-joyride";
|
import { JoyrideService } from "ngx-joyride";
|
||||||
import {Router} from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
import {DeleteModalComponent} from "../../shared/delete_modal/delete-modal/delete-modal.component";
|
import { DeleteModalComponent } from "../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
import {CreateMenuComponent} from "./create-menu/create-menu.component";
|
import { CreateMenuComponent } from "./create-menu/create-menu.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-menus',
|
selector: 'app-menus',
|
||||||
|
@ -15,7 +16,8 @@ import {CreateMenuComponent} from "./create-menu/create-menu.component";
|
||||||
styleUrl: './menus.component.css'
|
styleUrl: './menus.component.css'
|
||||||
})
|
})
|
||||||
export class MenusComponent implements OnInit {
|
export class MenusComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
itemsPerPage: number = 10;
|
itemsPerPage: number = 10;
|
||||||
|
@ -57,15 +59,17 @@ export class MenusComponent implements OnInit {
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
private apiUrl = `${this.baseUrl}/menus`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private joyrideService: JoyrideService,
|
private joyrideService: JoyrideService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
) {}
|
private configService: ConfigService
|
||||||
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/menus`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.search();
|
this.search();
|
||||||
|
@ -83,7 +87,7 @@ export class MenusComponent implements OnInit {
|
||||||
|
|
||||||
search(): void {
|
search(): void {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.http.get<any>(`${this.apiUrl}?page=${this.page +1 }&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe(
|
this.http.get<any>(`${this.apiUrl}?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}`, { params: this.filters }).subscribe(
|
||||||
data => {
|
data => {
|
||||||
this.dataSource.data = data['hydra:member'];
|
this.dataSource.data = data['hydra:member'];
|
||||||
this.length = data['hydra:totalItems'];
|
this.length = data['hydra:totalItems'];
|
||||||
|
|
|
@ -19,11 +19,17 @@ import { ToastrModule } from 'ngx-toastr';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { JoyrideModule } from 'ngx-joyride';
|
import { JoyrideModule } from 'ngx-joyride';
|
||||||
import {LoadingComponent} from "../../../shared/loading/loading.component";
|
import {LoadingComponent} from "../../../shared/loading/loading.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('OgbootStatusComponent', () => {
|
describe('OgbootStatusComponent', () => {
|
||||||
let component: OgbootStatusComponent;
|
let component: OgbootStatusComponent;
|
||||||
let fixture: ComponentFixture<OgbootStatusComponent>;
|
let fixture: ComponentFixture<OgbootStatusComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [OgbootStatusComponent, LoadingComponent],
|
declarations: [OgbootStatusComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -50,7 +56,8 @@ describe('OgbootStatusComponent', () => {
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: {} },
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: {} }
|
{ provide: MAT_DIALOG_DATA, useValue: {} },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-ogboot-status',
|
selector: 'app-ogboot-status',
|
||||||
|
@ -9,7 +10,7 @@ import {ToastrService} from "ngx-toastr";
|
||||||
styleUrls: ['./ogboot-status.component.css']
|
styleUrls: ['./ogboot-status.component.css']
|
||||||
})
|
})
|
||||||
export class OgbootStatusComponent implements OnInit {
|
export class OgbootStatusComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
diskUsage: any = {};
|
diskUsage: any = {};
|
||||||
servicesStatus: any = {};
|
servicesStatus: any = {};
|
||||||
installedOglives: any[] = [];
|
installedOglives: any[] = [];
|
||||||
|
@ -29,8 +30,11 @@ export class OgbootStatusComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private joyrideService: JoyrideService,
|
private joyrideService: JoyrideService,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadStatus();
|
this.loadStatus();
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { DataService as TemplateDataService } from './../pxe/data.service';
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string = this.configService.apiUrl;
|
||||||
private apiUrl = `${this.baseUrl}/pxe-boot-files?page=1&itemsPerPage=1000`;
|
private apiUrl = `${this.baseUrl}/pxe-boot-files?page=1&itemsPerPage=1000`;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -14,12 +14,18 @@ import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { JoyrideModule } from 'ngx-joyride';
|
import { JoyrideModule } from 'ngx-joyride';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('PxeBootFilesComponent', () => {
|
describe('PxeBootFilesComponent', () => {
|
||||||
let component: PxeBootFilesComponent;
|
let component: PxeBootFilesComponent;
|
||||||
let fixture: ComponentFixture<PxeBootFilesComponent>;
|
let fixture: ComponentFixture<PxeBootFilesComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [PxeBootFilesComponent],
|
declarations: [PxeBootFilesComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -43,7 +49,7 @@ describe('PxeBootFilesComponent', () => {
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
JoyrideModule.forRoot(),
|
JoyrideModule.forRoot(),
|
||||||
],
|
],
|
||||||
providers: [NgControl]
|
providers: [NgControl, { provide: ConfigService, useValue: mockConfigService }]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { PageEvent } from '@angular/material/paginator';
|
import { ConfigService } from '@services/config.service';
|
||||||
import {Observable} from "rxjs";
|
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -12,7 +11,7 @@ import { JoyrideService } from 'ngx-joyride';
|
||||||
styleUrls: ['./pxe-boot-files.component.css']
|
styleUrls: ['./pxe-boot-files.component.css']
|
||||||
})
|
})
|
||||||
export class PxeBootFilesComponent implements OnInit {
|
export class PxeBootFilesComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
|
||||||
availableOrganizationalUnits: any[] = [];
|
availableOrganizationalUnits: any[] = [];
|
||||||
selectedUnitChildren: any[] = [];
|
selectedUnitChildren: any[] = [];
|
||||||
|
@ -33,8 +32,10 @@ export class PxeBootFilesComponent implements OnInit {
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private joyrideService: JoyrideService
|
private joyrideService: JoyrideService
|
||||||
) {
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
this.taskForm = this.fb.group({
|
this.taskForm = this.fb.group({
|
||||||
organizationalUnit: ['', Validators.required],
|
organizationalUnit: ['', Validators.required],
|
||||||
selectedChild: ['', Validators.required]
|
selectedChild: ['', Validators.required]
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http';
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-image',
|
selector: 'app-create-image',
|
||||||
|
@ -9,7 +10,7 @@ import { ToastrService } from 'ngx-toastr';
|
||||||
styleUrls: ['./create-image.component.css']
|
styleUrls: ['./create-image.component.css']
|
||||||
})
|
})
|
||||||
export class CreatePXEImageComponent implements OnInit {
|
export class CreatePXEImageComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
downloads: any[] = [];
|
downloads: any[] = [];
|
||||||
selectedDownload: any;
|
selectedDownload: any;
|
||||||
isEditMode: boolean = false;
|
isEditMode: boolean = false;
|
||||||
|
@ -18,10 +19,13 @@ export class CreatePXEImageComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
private configService: ConfigService,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
public dialogRef: MatDialogRef<CreatePXEImageComponent>,
|
public dialogRef: MatDialogRef<CreatePXEImageComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) { }
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.fetchDownloads();
|
this.fetchDownloads();
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/og-lives?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/og-lives?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getImages(filters: { [key: string]: string }): Observable<any[]> {
|
getImages(filters: { [key: string]: string }): Observable<any[]> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -49,3 +49,23 @@ table {
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-active {
|
||||||
|
background-color: #46c446 !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-inactive {
|
||||||
|
background-color: #e87979 !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-installing {
|
||||||
|
background-color: #f5a623 !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-failed {
|
||||||
|
background-color: #9e9e9e !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
<app-loading [isLoading]="loading"></app-loading>
|
||||||
|
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
||||||
<mat-icon>help</mat-icon>
|
<mat-icon>help</mat-icon>
|
||||||
|
@ -10,8 +12,8 @@
|
||||||
<div class="images-button-row">
|
<div class="images-button-row">
|
||||||
<button class="action-button" (click)="openSubnetInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
|
<button class="action-button" (click)="openSubnetInfoDialog()">{{ 'viewInfoButton' | translate }}</button>
|
||||||
<button class="action-button" (click)="addImage()" joyrideStep="addImageStep"
|
<button class="action-button" (click)="addImage()" joyrideStep="addImageStep"
|
||||||
[text]="'addImageButtonDescription' | translate">
|
[text]="'addOgLiveButtonDescription' | translate">
|
||||||
{{ 'addImageButton' | translate }}
|
{{ 'addOgLiveButton' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,12 +41,13 @@
|
||||||
|
|
||||||
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchInstalledStep"
|
<mat-form-field appearance="fill" class="search-boolean" joyrideStep="searchInstalledStep"
|
||||||
[text]="'searchInstalledDescription' | translate">
|
[text]="'searchInstalledDescription' | translate">
|
||||||
<mat-label>{{ 'searchInstalledLabel' | translate }}</mat-label>
|
<mat-label>{{ 'status' | translate }}</mat-label>
|
||||||
<mat-select [(ngModel)]="filters['installed']" (selectionChange)="search()"
|
<mat-select [(ngModel)]="filters['status']" (selectionChange)="search()"
|
||||||
[placeholder]="'selectOptionPlaceholder' | translate">
|
[placeholder]="'selectOptionPlaceholder' | translate">
|
||||||
<mat-option [value]="''">{{ 'allOption' | translate }}</mat-option>
|
<mat-option [value]="'inactive'">{{ 'inactiveOption' | translate }}</mat-option>
|
||||||
<mat-option [value]="true">{{ 'yesOption' | translate }}</mat-option>
|
<mat-option [value]="'active'">{{ 'activeOption' | translate }}</mat-option>
|
||||||
<mat-option [value]="false">{{ 'noOption' | translate }}</mat-option>
|
<mat-option [value]="'failed'">{{ 'failedOption' | translate }}</mat-option>
|
||||||
|
<mat-option [value]="'pending'">{{ 'pendingOption' | translate }}</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,7 +58,7 @@
|
||||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
<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 }}</th>
|
||||||
<td mat-cell *matCellDef="let image">
|
<td mat-cell *matCellDef="let image">
|
||||||
<ng-container *ngIf="column.columnDef === 'isDefault' || column.columnDef === 'installed'">
|
<ng-container *ngIf="column.columnDef === 'isDefault'">
|
||||||
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
||||||
<ng-container *ngIf="image[column.columnDef]; else cancelIcon">
|
<ng-container *ngIf="image[column.columnDef]; else cancelIcon">
|
||||||
{{ 'checkCircle' | translate }}
|
{{ 'checkCircle' | translate }}
|
||||||
|
@ -79,13 +82,13 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngIf="column.columnDef === 'status'">
|
<ng-container *ngIf="column.columnDef === 'status'">
|
||||||
<mat-chip>
|
<mat-chip [ngClass]="getStatusLabel(image.status).class">
|
||||||
{{ column.cell(image) }}
|
{{ getStatusLabel(image.status).label }}
|
||||||
</mat-chip>
|
</mat-chip>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'installed' && column.columnDef !== 'downloadUrl' && column.columnDef !== 'status' && column.columnDef !== 'name'">
|
*ngIf="column.columnDef !== 'isDefault' && column.columnDef !== 'downloadUrl' && column.columnDef !== 'status' && column.columnDef !== 'name'">
|
||||||
{{ column.cell(image) }}
|
{{ column.cell(image) }}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</td>
|
</td>
|
||||||
|
@ -108,12 +111,12 @@
|
||||||
<mat-icon>menu</mat-icon>
|
<mat-icon>menu</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-menu #menu="matMenu">
|
<mat-menu #menu="matMenu">
|
||||||
<button mat-menu-item [disabled]="image.installed" (click)="toggleAction(image, 'install')">{{ 'installOption' |
|
<button mat-menu-item [disabled]="image.status !== 'inactive'" (click)="toggleAction(image, 'install')">{{ 'installOption' |
|
||||||
translate }}</button>
|
translate }}</button>
|
||||||
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'uninstall')">
|
<button mat-menu-item [disabled]="image.status !== 'active'" (click)="toggleAction(image, 'uninstall')">
|
||||||
{{ 'uninstallOption' | translate }}
|
{{ 'uninstallOption' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item [disabled]="!image.installed" (click)="toggleAction(image, 'set-default')">
|
<button mat-menu-item [disabled]="image.status !== 'active'" (click)="toggleAction(image, 'set-default')">
|
||||||
{{ 'setDefaultOption' | translate }}
|
{{ 'setDefaultOption' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { MatTableModule } from '@angular/material/table';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { JoyrideModule } from 'ngx-joyride';
|
import { JoyrideModule } from 'ngx-joyride';
|
||||||
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('PXEimagesComponent', () => {
|
describe('PXEimagesComponent', () => {
|
||||||
let component: PXEimagesComponent;
|
let component: PXEimagesComponent;
|
||||||
|
@ -25,6 +26,11 @@ describe('PXEimagesComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [PXEimagesComponent, LoadingComponent],
|
declarations: [PXEimagesComponent, LoadingComponent],
|
||||||
|
@ -47,7 +53,8 @@ describe('PXEimagesComponent', () => {
|
||||||
JoyrideModule.forRoot(),
|
JoyrideModule.forRoot(),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ToastrService, useValue: mockToastrService }
|
{ provide: ToastrService, useValue: mockToastrService },
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
]
|
]
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import {Component, OnInit, signal} from '@angular/core';
|
import { Component, OnInit, signal } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { CreatePXEImageComponent } from './create-image/create-image/create-image.component';
|
import { CreatePXEImageComponent } from './create-image/create-image/create-image.component';
|
||||||
import { InfoImageComponent } from './info-image/info-image/info-image.component';
|
import { InfoImageComponent } from './info-image/info-image/info-image.component';
|
||||||
import { MatTableDataSource } from "@angular/material/table";
|
import { MatTableDataSource } from "@angular/material/table";
|
||||||
import {PageEvent} from "@angular/material/paginator";
|
import { PageEvent } from "@angular/material/paginator";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import { DatePipe } from "@angular/common";
|
import { DatePipe } from "@angular/common";
|
||||||
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
import { DeleteModalComponent } from '../../../shared/delete_modal/delete-modal/delete-modal.component';
|
||||||
import {DataService} from "./data.service";
|
import { DataService } from "./data.service";
|
||||||
import {Observable} from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
|
import { ServerInfoDialogComponent } from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pxe-images',
|
selector: 'app-pxe-images',
|
||||||
|
@ -19,7 +20,8 @@ import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-
|
||||||
styleUrls: ['./pxe-images.component.css']
|
styleUrls: ['./pxe-images.component.css']
|
||||||
})
|
})
|
||||||
export class PXEimagesComponent implements OnInit {
|
export class PXEimagesComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
images: { downloadUrl: string; name: string; uuid: string }[] = [];
|
images: { downloadUrl: string; name: string; uuid: string }[] = [];
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
|
@ -27,7 +29,7 @@ export class PXEimagesComponent implements OnInit {
|
||||||
page: number = 1;
|
page: number = 1;
|
||||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||||
selectedElements: string[] = [];
|
selectedElements: string[] = [];
|
||||||
loading:boolean = false;
|
loading: boolean = false;
|
||||||
filters: { [key: string]: string } = {};
|
filters: { [key: string]: string } = {};
|
||||||
alertMessage: string | null = null;
|
alertMessage: string | null = null;
|
||||||
readonly panelOpenState = signal(false);
|
readonly panelOpenState = signal(false);
|
||||||
|
@ -48,11 +50,6 @@ export class PXEimagesComponent implements OnInit {
|
||||||
header: 'Imagen por defecto',
|
header: 'Imagen por defecto',
|
||||||
cell: (user: any) => `${user.isDefault}`
|
cell: (user: any) => `${user.isDefault}`
|
||||||
},
|
},
|
||||||
{
|
|
||||||
columnDef: 'installed',
|
|
||||||
header: 'Imagen instalada',
|
|
||||||
cell: (user: any) => `${user.installed}`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
columnDef: 'status',
|
columnDef: 'status',
|
||||||
header: 'Estado',
|
header: 'Estado',
|
||||||
|
@ -66,15 +63,17 @@ export class PXEimagesComponent implements OnInit {
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
private apiUrl = `${this.baseUrl}/og-lives`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private joyrideService: JoyrideService
|
private joyrideService: JoyrideService
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/og-lives`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
@ -106,14 +105,19 @@ export class PXEimagesComponent implements OnInit {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showInfo(image: any): void {
|
getStatusLabel(status: string): { label: string; class: string } {
|
||||||
const dialogRef = this.dialog.open(InfoImageComponent, {
|
const statusMap: { [key: string]: { label: string; class: string } } = {
|
||||||
width: '700px',
|
active: { label: 'Instalada', class: 'status-active' },
|
||||||
data: image
|
inactive: { label: 'Sin instalar', class: 'status-inactive' },
|
||||||
});
|
pending: { label: 'Instalando...', class: 'status-installing' },
|
||||||
|
failed: { label: 'Fallido', class: 'status-failed' }
|
||||||
|
};
|
||||||
|
|
||||||
|
return statusMap[status] || { label: 'Desconocido', class: 'status-default' };
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleAction(image: any, action:string): void {
|
|
||||||
|
toggleAction(image: any, action: string): void {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'set-default':
|
case 'set-default':
|
||||||
this.http.post(`${this.apiUrl}/server/${image.uuid}/set-default`, {}).subscribe({
|
this.http.post(`${this.apiUrl}/server/${image.uuid}/set-default`, {}).subscribe({
|
||||||
|
@ -197,7 +201,7 @@ export class PXEimagesComponent implements OnInit {
|
||||||
|
|
||||||
showOgLive(event: MouseEvent, data: any): void {
|
showOgLive(event: MouseEvent, data: any): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dialogRef = this.dialog.open(InfoImageComponent, { data: { data }, width: '700px'});
|
const dialogRef = this.dialog.open(InfoImageComponent, { data: { data }, width: '700px' });
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilter() {
|
applyFilter() {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
|
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { DeleteModalComponent } from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
|
import { DeleteModalComponent } from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-pxe-template',
|
selector: 'app-create-pxe-template',
|
||||||
|
@ -11,7 +12,7 @@ import { DeleteModalComponent } from "../../../../shared/delete_modal/delete-mod
|
||||||
styleUrls: ['./create-pxe-template.component.css']
|
styleUrls: ['./create-pxe-template.component.css']
|
||||||
})
|
})
|
||||||
export class CreatePxeTemplateComponent implements OnInit {
|
export class CreatePxeTemplateComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
templateForm!: FormGroup;
|
templateForm!: FormGroup;
|
||||||
previewContent: string = '';
|
previewContent: string = '';
|
||||||
isEditMode: boolean = false;
|
isEditMode: boolean = false;
|
||||||
|
@ -54,10 +55,13 @@ exit`
|
||||||
public dialogRef: MatDialogRef<CreatePxeTemplateComponent>,
|
public dialogRef: MatDialogRef<CreatePxeTemplateComponent>,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
private configService: ConfigService,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {}
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.isEditMode = !!this.data;
|
this.isEditMode = !!this.data;
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
private apiUrl = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=1000`;
|
private apiUrl: string;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, private configService: ConfigService) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/pxe-templates?page=1&itemsPerPage=1000`;
|
||||||
|
}
|
||||||
|
|
||||||
getPxeTemplates(filters: { [key: string]: string }): Observable<any[]> {
|
getPxeTemplates(filters: { [key: string]: string }): Observable<any[]> {
|
||||||
const params = new HttpParams({ fromObject: filters });
|
const params = new HttpParams({ fromObject: filters });
|
||||||
|
|
|
@ -17,18 +17,25 @@ import { MatHint } from '@angular/material/form-field';
|
||||||
import { MatSelect } from '@angular/material/select';
|
import { MatSelect } from '@angular/material/select';
|
||||||
import { MatOption } from '@angular/material/select';
|
import { MatOption } from '@angular/material/select';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { JoyrideModule } from 'ngx-joyride';
|
import { JoyrideModule } from 'ngx-joyride';
|
||||||
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
describe('PxeComponent', () => {
|
describe('PxeComponent', () => {
|
||||||
let component: PxeComponent;
|
let component: PxeComponent;
|
||||||
let fixture: ComponentFixture<PxeComponent>;
|
let fixture: ComponentFixture<PxeComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url',
|
||||||
|
mercureUrl: 'http://mock-mercure-url'
|
||||||
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [PxeComponent, LoadingComponent],
|
declarations: [PxeComponent, LoadingComponent],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -55,6 +62,7 @@ describe('PxeComponent', () => {
|
||||||
providers: [
|
providers: [
|
||||||
DatePipe,
|
DatePipe,
|
||||||
DataService,
|
DataService,
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService },
|
||||||
provideHttpClient(),
|
provideHttpClient(),
|
||||||
provideHttpClientTesting()
|
provideHttpClientTesting()
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template.component'; // Asegúrate de que el path sea correcto
|
import { CreatePxeTemplateComponent } from './create-pxeTemplate/create-pxe-template.component';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { PageEvent } from '@angular/material/paginator';
|
import { PageEvent } from '@angular/material/paginator';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { DataService } from './data.service';
|
import { DataService } from './data.service';
|
||||||
import {ShowTemplateContentComponent} from "./show-template-content/show-template-content.component";
|
import { ShowTemplateContentComponent } from "./show-template-content/show-template-content.component";
|
||||||
import {Observable} from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
import { DeleteModalComponent } from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
|
import { ServerInfoDialogComponent } from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pxe',
|
selector: 'app-pxe',
|
||||||
|
@ -19,7 +20,8 @@ import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-
|
||||||
styleUrls: ['./pxe.component.css']
|
styleUrls: ['./pxe.component.css']
|
||||||
})
|
})
|
||||||
export class PxeComponent {
|
export class PxeComponent {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string;
|
||||||
|
private apiUrl: string;
|
||||||
pxeTemplates: any[] = [];
|
pxeTemplates: any[] = [];
|
||||||
currentPage: number = 1;
|
currentPage: number = 1;
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
|
@ -28,7 +30,7 @@ export class PxeComponent {
|
||||||
page: number = 1;
|
page: number = 1;
|
||||||
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
pageSizeOptions: number[] = [5, 10, 20, 40, 100];
|
||||||
selectedElements: string[] = [];
|
selectedElements: string[] = [];
|
||||||
loading:boolean = false;
|
loading: boolean = false;
|
||||||
filters: { [key: string]: string } = {};
|
filters: { [key: string]: string } = {};
|
||||||
alertMessage: string | null = null;
|
alertMessage: string | null = null;
|
||||||
datePipe: DatePipe = new DatePipe('es-ES');
|
datePipe: DatePipe = new DatePipe('es-ES');
|
||||||
|
@ -58,15 +60,17 @@ export class PxeComponent {
|
||||||
];
|
];
|
||||||
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
displayedColumns = [...this.columns.map(column => column.columnDef), 'actions'];
|
||||||
|
|
||||||
private apiUrl = `${this.baseUrl}/pxe-templates`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private joyrideService: JoyrideService
|
private joyrideService: JoyrideService,
|
||||||
) { }
|
private configService: ConfigService
|
||||||
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
this.apiUrl = `${this.baseUrl}/pxe-templates`;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
@ -140,7 +144,7 @@ export class PxeComponent {
|
||||||
|
|
||||||
showTemplate(event: MouseEvent, data: any): void {
|
showTemplate(event: MouseEvent, data: any): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const dialogRef = this.dialog.open(ShowTemplateContentComponent, { data: { data }, width: '700px'});
|
const dialogRef = this.dialog.open(ShowTemplateContentComponent, { data: { data }, width: '700px' });
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTemplates() {
|
syncTemplates() {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue