ogRepo new endpoints. Export/Import image
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
parent
b2bf6b8c96
commit
bdbb16d3fd
|
@ -124,6 +124,8 @@ import { MatSortModule } from '@angular/material/sort';
|
||||||
import { MenusComponent } from './components/menus/menus.component';
|
import { MenusComponent } from './components/menus/menus.component';
|
||||||
import { CreateMenuComponent } from './components/menus/create-menu/create-menu.component';
|
import { CreateMenuComponent } from './components/menus/create-menu/create-menu.component';
|
||||||
import { CreateMultipleClientComponent } from './components/groups/shared/clients/create-multiple-client/create-multiple-client.component';
|
import { CreateMultipleClientComponent } from './components/groups/shared/clients/create-multiple-client/create-multiple-client.component';
|
||||||
|
import { ExportImageComponent } from './components/images/export-image/export-image.component';
|
||||||
|
import {ImportImageComponent} from "./components/repositories/import-image/import-image.component";
|
||||||
export function HttpLoaderFactory(http: HttpClient) {
|
export function HttpLoaderFactory(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||||
}
|
}
|
||||||
|
@ -206,6 +208,8 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||||
MenusComponent,
|
MenusComponent,
|
||||||
CreateMenuComponent,
|
CreateMenuComponent,
|
||||||
CreateMultipleClientComponent,
|
CreateMultipleClientComponent,
|
||||||
|
ExportImageComponent,
|
||||||
|
ImportImageComponent,
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
imports: [BrowserModule,
|
imports: [BrowserModule,
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-dialog-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<h2 mat-dialog-title>Exportar imagen {{data.image?.name}}</h2>
|
||||||
|
|
||||||
|
<mat-dialog-content>
|
||||||
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
|
<mat-label>Seleccione repositorio destino</mat-label>
|
||||||
|
<mat-select [(value)]="selectedRepository">
|
||||||
|
<mat-option *ngFor="let repository of repositories" [value]="repository['@id']">{{ repository.name }}</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
|
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<button mat-button (click)="close()">Cancelar</button>
|
||||||
|
<button mat-button (click)="save()">Continuar</button>
|
||||||
|
</mat-dialog-actions>
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ExportImageComponent } from './export-image.component';
|
||||||
|
import {FormBuilder, ReactiveFormsModule} from "@angular/forms";
|
||||||
|
import {ToastrModule, ToastrService} from "ngx-toastr";
|
||||||
|
import {provideHttpClient} from "@angular/common/http";
|
||||||
|
import {provideHttpClientTesting} from "@angular/common/http/testing";
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
|
import {MatInputModule} from "@angular/material/input";
|
||||||
|
import {MatButtonModule} from "@angular/material/button";
|
||||||
|
import {MatSelectModule} from "@angular/material/select";
|
||||||
|
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||||
|
import {TranslateModule} from "@ngx-translate/core";
|
||||||
|
|
||||||
|
describe('ExportImageComponent', () => {
|
||||||
|
let component: ExportImageComponent;
|
||||||
|
let fixture: ComponentFixture<ExportImageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ExportImageComponent],
|
||||||
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatSelectModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
ToastrModule.forRoot(),
|
||||||
|
TranslateModule.forRoot()
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
FormBuilder,
|
||||||
|
ToastrService,
|
||||||
|
provideHttpClient(),
|
||||||
|
provideHttpClientTesting(),
|
||||||
|
{
|
||||||
|
provide: MatDialogRef,
|
||||||
|
useValue: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: MAT_DIALOG_DATA,
|
||||||
|
useValue: {}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ExportImageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,59 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import {HttpClient} from "@angular/common/http";
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-export-image',
|
||||||
|
templateUrl: './export-image.component.html',
|
||||||
|
styleUrl: './export-image.component.css'
|
||||||
|
})
|
||||||
|
export class ExportImageComponent implements OnInit {
|
||||||
|
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||||
|
loading: boolean = true;
|
||||||
|
repositories: any[] = [];
|
||||||
|
selectedRepository: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
public dialogRef: MatDialogRef<ExportImageComponent>,
|
||||||
|
private toastService: ToastrService,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: { image: any }
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.loadRepositories();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRepositories() {
|
||||||
|
this.http.get<any>(`${this.baseUrl}/image-repositories?page=1&itemsPerPage=50`).subscribe(
|
||||||
|
response => {
|
||||||
|
this.repositories = response['hydra:member'];
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
error => console.error('Error fetching organizational units:', error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.http.post<any>(`${this.baseUrl}${this.selectedRepository}/export-image`, {
|
||||||
|
images: [this.data.image['@id']]
|
||||||
|
}).subscribe({
|
||||||
|
next: (response) => {
|
||||||
|
this.toastService.success('Imagen exportada correctamente');
|
||||||
|
this.dialogRef.close();
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
console.error('Error al exportar imagen:', error);
|
||||||
|
this.toastService.error('Error al exportar imagen');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,3 +91,9 @@ table {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-container-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
<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>
|
||||||
</button>
|
</button>
|
||||||
<h2 class="title">{{ 'imagesTitle' | translate }}</h2>
|
<div class="header-container-title">
|
||||||
|
<h2 joyrideStep="groupsTitleStepText" text="{{ 'groupsTitleStepText' | translate }}">
|
||||||
|
{{ 'imagesTitle' | translate }}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
<div class="images-button-row">
|
<div class="images-button-row">
|
||||||
<button mat-flat-button color="primary" (click)="addImage()">
|
<button mat-flat-button color="primary" (click)="addImage()">
|
||||||
{{ 'addImageButton' | translate }}
|
{{ 'addImageButton' | translate }}
|
||||||
|
@ -62,7 +66,7 @@
|
||||||
<button mat-menu-item (click)="toggleAction(image, 'get-aux')">Obtener ficheros auxiliares</button>
|
<button mat-menu-item (click)="toggleAction(image, 'get-aux')">Obtener ficheros auxiliares</button>
|
||||||
<button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'success'" (click)="toggleAction(image, 'delete-trash')">Eliminar imagen temporalmente</button>
|
<button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'success'" (click)="toggleAction(image, 'delete-trash')">Eliminar imagen temporalmente</button>
|
||||||
<button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'trash'" (click)="toggleAction(image, 'recover')">Recuperar imagen de la papelera</button>
|
<button mat-menu-item [disabled]="!image.imageFullsum || image.status !== 'trash'" (click)="toggleAction(image, 'recover')">Recuperar imagen de la papelera</button>
|
||||||
|
<button mat-menu-item (click)="toggleAction(image, 'export')">Exportar imagen</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {ServerInfoDialogComponent} from "../ogdhcp/og-dhcp-subnets/server-info-d
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from "rxjs";
|
||||||
import {InfoImageComponent} from "../ogboot/pxe-images/info-image/info-image/info-image.component";
|
import {InfoImageComponent} from "../ogboot/pxe-images/info-image/info-image/info-image.component";
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
|
import {ExportImageComponent} from "./export-image/export-image.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-images',
|
selector: 'app-images',
|
||||||
|
@ -216,6 +217,14 @@ export class ImagesComponent implements OnInit {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'export':
|
||||||
|
this.dialog.open(ExportImageComponent, {
|
||||||
|
width: '600px',
|
||||||
|
data: {
|
||||||
|
image: image
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error('Acción no soportada:', action);
|
console.error('Acción no soportada:', action);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-dialog-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<h2 mat-dialog-title>Importar imagenes a {{data.repository?.name}}</h2>
|
||||||
|
|
||||||
|
<mat-dialog-content>
|
||||||
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
|
<mat-label>Seleccione imagenes a importar</mat-label>
|
||||||
|
<mat-select [(value)]="selectedClients" multiple>
|
||||||
|
<mat-option *ngFor="let image of images" [value]="image['@id']">{{ image.name }}</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
|
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<button mat-button (click)="close()">Cancelar</button>
|
||||||
|
<button mat-button (click)="save()">Continuar</button>
|
||||||
|
</mat-dialog-actions>
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ImportImageComponent } from './import-image.component';
|
||||||
|
import {FormBuilder, ReactiveFormsModule} from "@angular/forms";
|
||||||
|
import {ToastrModule, ToastrService} from "ngx-toastr";
|
||||||
|
import {DataService} from "../../calendar/data.service";
|
||||||
|
import {provideHttpClient} from "@angular/common/http";
|
||||||
|
import {provideHttpClientTesting} from "@angular/common/http/testing";
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
|
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||||
|
import {TranslateModule} from "@ngx-translate/core";
|
||||||
|
import {MatButtonModule} from "@angular/material/button";
|
||||||
|
import {MatInputModule} from "@angular/material/input";
|
||||||
|
import {MatSelectModule} from "@angular/material/select";
|
||||||
|
|
||||||
|
describe('ImportImageComponent', () => {
|
||||||
|
let component: ImportImageComponent;
|
||||||
|
let fixture: ComponentFixture<ImportImageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ImportImageComponent],
|
||||||
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatSelectModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
ToastrModule.forRoot(),
|
||||||
|
TranslateModule.forRoot()
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
FormBuilder,
|
||||||
|
ToastrService,
|
||||||
|
provideHttpClient(),
|
||||||
|
provideHttpClientTesting(),
|
||||||
|
{
|
||||||
|
provide: MatDialogRef,
|
||||||
|
useValue: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: MAT_DIALOG_DATA,
|
||||||
|
useValue: {}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ImportImageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,58 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import {HttpClient} from "@angular/common/http";
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-import-image',
|
||||||
|
templateUrl: './import-image.component.html',
|
||||||
|
styleUrl: './import-image.component.css'
|
||||||
|
})
|
||||||
|
export class ImportImageComponent implements OnInit{
|
||||||
|
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||||
|
loading: boolean = true;
|
||||||
|
images: any[] = [];
|
||||||
|
selectedClients: any[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
public dialogRef: MatDialogRef<ImportImageComponent>,
|
||||||
|
private toastService: ToastrService,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: { repository: any }
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.loadImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadImages() {
|
||||||
|
this.http.get<any>(`${this.baseUrl}/images?page=1&itemsPerPage=50`).subscribe(
|
||||||
|
response => {
|
||||||
|
this.images = response['hydra:member'];
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
error => console.error('Error fetching organizational units:', error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.http.post<any>(`${this.baseUrl}${this.data.repository['@id']}/import-image`, {
|
||||||
|
images: this.selectedClients
|
||||||
|
}).subscribe({
|
||||||
|
next: (response) => {
|
||||||
|
this.toastService.success('Peticion de importacion de imagen enviada correctamente');
|
||||||
|
this.dialogRef.close();
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
this.toastService.error('Error al importar imagenes');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -135,6 +135,10 @@
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-container {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.mat-tab-body-wrapper {
|
.mat-tab-body-wrapper {
|
||||||
min-height: inherit;
|
min-height: inherit;
|
||||||
}
|
}
|
||||||
|
@ -210,13 +214,6 @@ p {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-led {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-led.active {
|
.status-led.active {
|
||||||
background-color: green;
|
background-color: green;
|
||||||
|
@ -304,4 +301,85 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dashboard {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row .card {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: white;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
flex: 1;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inactive {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cpu-usage-bar {
|
||||||
|
background: lightgray;
|
||||||
|
width: 100%;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cpu-bar {
|
||||||
|
height: 100%;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cpu-bar.high {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.top-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row .card {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,91 @@
|
||||||
<mat-tab-group dynamicHeight>
|
<mat-tab-group class="main-container" dynamicHeight>
|
||||||
<mat-tab label="Estado servidor">
|
<mat-tab label="Estado servidor">
|
||||||
<div class="dashboard">
|
<div class="dashboard">
|
||||||
<h2>OgRepository server Status</h2>
|
<h2>OgRepository Server Status</h2>
|
||||||
<div class="disk-usage-container">
|
|
||||||
<div class="disk-usage">
|
<div class="row top-row">
|
||||||
<h3>Uso de disco</h3>
|
<div class="card">
|
||||||
|
<h3>Uso de Disco</h3>
|
||||||
<ngx-charts-pie-chart
|
<ngx-charts-pie-chart
|
||||||
[view]="view"
|
[view]="view"
|
||||||
[scheme]="colorScheme"
|
[scheme]="colorScheme"
|
||||||
[results]="diskUsageChartData"
|
[results]="diskUsageChartData"
|
||||||
[gradient]="gradient"
|
[gradient]="gradient"
|
||||||
[doughnut]="isDoughnut"
|
[doughnut]="isDoughnut"
|
||||||
[labels]="showLabels"
|
[labels]="showLabels" >
|
||||||
[legend]="showLegend">
|
|
||||||
</ngx-charts-pie-chart>
|
</ngx-charts-pie-chart>
|
||||||
<div class="disk-usage-info">
|
<div class="info">
|
||||||
<p>Total: {{ diskUsage.total }}</p>
|
<p>Total: {{ diskUsage.total }}</p>
|
||||||
<p>Ocupado: {{ diskUsage.used }}</p>
|
<p>Ocupado: {{ diskUsage.used }}</p>
|
||||||
<p>Disponible: {{ diskUsage.available }}</p>
|
<p>Disponible: {{ diskUsage.available }}</p>
|
||||||
<p>Ocupado ( % ): {{ diskUsage.percentage }}</p>
|
<p>Ocupado (%): {{ diskUsage.percentage }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="services-status">
|
<div class="card">
|
||||||
|
<h3>Uso de RAM</h3>
|
||||||
|
<ngx-charts-pie-chart
|
||||||
|
[view]="view"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[results]="ramUsageChartData"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[doughnut]="isDoughnut"
|
||||||
|
[labels]="showLabels">
|
||||||
|
</ngx-charts-pie-chart>
|
||||||
|
<div class="info">
|
||||||
|
<p>Total: {{ ramUsage.total }}</p>
|
||||||
|
<p>Ocupado: {{ ramUsage.used }}</p>
|
||||||
|
<p>Disponible: {{ ramUsage.available }}</p>
|
||||||
|
<p>Ocupado (%): {{ ramUsage.percentage }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row bottom-row">
|
||||||
|
<div class="card">
|
||||||
|
<h3>Uso de CPU</h3>
|
||||||
|
<div class="cpu-usage-bar">
|
||||||
|
<div class="cpu-bar" [style.width]="cpuUsage.percentage" [ngClass]="{'high': cpuUsage.percentage > '80%'}"></div>
|
||||||
|
</div>
|
||||||
|
<p>Usado: {{ cpuUsage.percentage }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
<h3>Servicios</h3>
|
<h3>Servicios</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="let service of getServices()">
|
<li *ngFor="let service of getServices()">
|
||||||
<span
|
<span class="status-led" [ngClass]="{
|
||||||
class="status-led"
|
'active': service.status === 'active',
|
||||||
[ngClass]="{
|
'inactive': service.status === 'stopped' || service.status === 'status not accesible'
|
||||||
'active': service.status === 'active',
|
}"></span>
|
||||||
'inactive': service.status === 'stopped' || service.status === 'status not accesible'
|
|
||||||
}"
|
|
||||||
></span>
|
|
||||||
{{ service.name }}:
|
{{ service.name }}:
|
||||||
<span [ngSwitch]="service.status">
|
<span [ngSwitch]="service.status">
|
||||||
<span *ngSwitchCase="'active'">Activo</span>
|
<span *ngSwitchCase="'active'">Activo</span>
|
||||||
<span *ngSwitchCase="'stopped'">Detenido</span>
|
<span *ngSwitchCase="'stopped'">Detenido</span>
|
||||||
<span *ngSwitchCase="'status not accesible'">No accesible</span>
|
<span *ngSwitchCase="'status not accesible'">No accesible</span>
|
||||||
<span *ngSwitchDefault>{{ service.status }}</span>
|
<span *ngSwitchDefault>{{ service.status }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h3>Procesos</h3>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let process of getProcesses()">
|
||||||
|
<span class="status-led" [ngClass]="{
|
||||||
|
'active': process.status === 'running',
|
||||||
|
'inactive': process.status === 'stopped'
|
||||||
|
}"></span>
|
||||||
|
{{ process.name }}: {{ process.status }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
|
|
||||||
|
|
||||||
<mat-tab label="Datos generales">
|
<mat-tab label="Datos generales">
|
||||||
<div class="dashboard">
|
<div class="dashboard">
|
||||||
<div class="header-button-container">
|
<div class="header-button-container">
|
||||||
|
@ -83,59 +123,6 @@
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
|
|
||||||
<mat-tab label="Listado de imágenes">
|
<mat-tab label="Listado de imágenes">
|
||||||
<div class="dashboard">
|
<app-images />
|
||||||
<h2>Imágenes</h2>
|
|
||||||
<div class="search-container">
|
|
||||||
<mat-form-field appearance="fill" class="search-string">
|
|
||||||
<mat-label>Buscar nombre de imagen</mat-label>
|
|
||||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="searchImages()" i18n-placeholder="@@searchPlaceholder">
|
|
||||||
<mat-icon matSuffix>search</mat-icon>
|
|
||||||
<mat-hint>Pulsar 'enter' para buscar</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
|
||||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
|
||||||
<td mat-cell *matCellDef="let image" >
|
|
||||||
<ng-container *ngIf="column.columnDef === 'remotePc' || column.columnDef === 'created'">
|
|
||||||
<mat-icon [color]="image[column.columnDef] ? 'primary' : 'warn'">
|
|
||||||
{{ image[column.columnDef] ? 'check_circle' : 'cancel' }}
|
|
||||||
</mat-icon>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="column.columnDef !== 'remotePc' && column.columnDef !== 'created'">
|
|
||||||
{{ column.cell(image) }}
|
|
||||||
</ng-container>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="actions">
|
|
||||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
|
||||||
<td mat-cell *matCellDef="let image" style="text-align: center;">
|
|
||||||
<button mat-icon-button color="info" (click)="showImageInfo($event, image)"><mat-icon i18n="@@deleteElementTooltip">visibility</mat-icon></button>
|
|
||||||
<button mat-icon-button color="primary" (click)="editImage($event, image)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
|
||||||
<button mat-icon-button color="warn" (click)="toggleAction(image, 'delete')">
|
|
||||||
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
|
||||||
<mat-icon>menu</mat-icon>
|
|
||||||
</button>
|
|
||||||
<mat-menu #menu="matMenu">
|
|
||||||
<button mat-menu-item [disabled]="!image.imageFullsum" (click)="toggleAction(image, 'get-aux')">Obtener ficheros auxiliares</button>
|
|
||||||
</mat-menu>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
<div class="paginator-container">
|
|
||||||
<mat-paginator [length]="length"
|
|
||||||
[pageSize]="itemsPerPage"
|
|
||||||
[pageIndex]="page"
|
|
||||||
[pageSizeOptions]="[5, 10, 20, 40, 100]"
|
|
||||||
(page)="onPageChange($event)">
|
|
||||||
</mat-paginator>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Component, Inject} 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 {ToastrService} from "ngx-toastr";
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
@ -17,7 +17,7 @@ import {MatDialog} from "@angular/material/dialog";
|
||||||
templateUrl: './main-repository-view.component.html',
|
templateUrl: './main-repository-view.component.html',
|
||||||
styleUrl: './main-repository-view.component.css'
|
styleUrl: './main-repository-view.component.css'
|
||||||
})
|
})
|
||||||
export class MainRepositoryViewComponent {
|
export class MainRepositoryViewComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||||
repositoryForm: FormGroup<any>;
|
repositoryForm: FormGroup<any>;
|
||||||
repositoryId: string | null = null;
|
repositoryId: string | null = null;
|
||||||
|
@ -25,16 +25,20 @@ export class MainRepositoryViewComponent {
|
||||||
loading: boolean = true;
|
loading: boolean = true;
|
||||||
diskUsage: any = {};
|
diskUsage: any = {};
|
||||||
servicesStatus: any = {};
|
servicesStatus: any = {};
|
||||||
|
processesStatus: any = {};
|
||||||
diskUsageChartData: any[] = [];
|
diskUsageChartData: any[] = [];
|
||||||
|
ramUsageChartData: any[] = [];
|
||||||
|
ramUsage: any = {};
|
||||||
|
cpuUsage: any = {};
|
||||||
alertMessage: string | null = null;
|
alertMessage: string | null = null;
|
||||||
length: number = 0;
|
length: number = 0;
|
||||||
itemsPerPage: number = 10;
|
itemsPerPage: number = 10;
|
||||||
page: number = 0;
|
page: number = 0;
|
||||||
view: [number, number] = [800, 500];
|
view: [number, number] = [800, 500];
|
||||||
gradient: boolean = true;
|
gradient: boolean = true;
|
||||||
showLegend: boolean = true;
|
|
||||||
showLabels: boolean = true;
|
showLabels: boolean = true;
|
||||||
isDoughnut: boolean = true;
|
isDoughnut: boolean = true;
|
||||||
|
status: boolean = false;
|
||||||
repositoryData: any = {};
|
repositoryData: any = {};
|
||||||
colorScheme: any = {
|
colorScheme: any = {
|
||||||
domain: ['#FF6384', '#3f51b5']
|
domain: ['#FF6384', '#3f51b5']
|
||||||
|
@ -115,7 +119,6 @@ export class MainRepositoryViewComponent {
|
||||||
comments: [response.comments],
|
comments: [response.comments],
|
||||||
});
|
});
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
// Llamar searchImages() solo cuando la data de repository esté cargada
|
|
||||||
this.searchImages();
|
this.searchImages();
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
@ -157,28 +160,33 @@ export class MainRepositoryViewComponent {
|
||||||
|
|
||||||
loadStatus(): void {
|
loadStatus(): void {
|
||||||
this.http.get<any>(`${this.baseUrl}/image-repositories/server/${this.repositoryId}/status`).subscribe(data => {
|
this.http.get<any>(`${this.baseUrl}/image-repositories/server/${this.repositoryId}/status`).subscribe(data => {
|
||||||
const diskData = data.output.disk;
|
if (!data.success) {
|
||||||
const servicesData = data.output.services;
|
console.error('Error: No se pudo obtener los datos del servidor');
|
||||||
|
this.status = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.diskUsage = {
|
this.status = true;
|
||||||
total: diskData.total,
|
|
||||||
used: diskData.used,
|
|
||||||
available: diskData.available,
|
|
||||||
percentage: diskData.used_percentage
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const { disk, services, ram, cpu, processes } = data.output;
|
||||||
|
|
||||||
|
this.diskUsage = { ...disk };
|
||||||
this.diskUsageChartData = [
|
this.diskUsageChartData = [
|
||||||
{
|
{ name: 'Usado', value: parseFloat(disk.used.replace('GB', '')) },
|
||||||
name: 'Usado',
|
{ name: 'Disponible', value: parseFloat(disk.available.replace('GB', '')) }
|
||||||
value: parseFloat(diskData.used)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Disponible',
|
|
||||||
value: parseFloat(diskData.available)
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
this.servicesStatus = servicesData;
|
this.ramUsage = { ...ram };
|
||||||
|
this.ramUsageChartData = [
|
||||||
|
{ name: 'Usado', value: parseFloat(ram.used.replace('GB', '')) },
|
||||||
|
{ name: 'Disponible', value: parseFloat(ram.available.replace('GB', '')) }
|
||||||
|
];
|
||||||
|
|
||||||
|
this.cpuUsage = { percentage: cpu.used_percentage };
|
||||||
|
|
||||||
|
this.servicesStatus = Object.entries(services).map(([name, status]) => ({ name, status }));
|
||||||
|
|
||||||
|
this.processesStatus = Object.entries(processes).map(([name, status]) => ({ name, status }));
|
||||||
|
|
||||||
}, error => {
|
}, error => {
|
||||||
console.error('Error fetching status', error);
|
console.error('Error fetching status', error);
|
||||||
|
@ -186,10 +194,17 @@ export class MainRepositoryViewComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getServices(): { name: string, status: string }[] {
|
getServices(): { name: string, status: string }[] {
|
||||||
return Object.keys(this.servicesStatus).map(key => ({
|
if (!this.status) {
|
||||||
name: key,
|
return [];
|
||||||
status: this.servicesStatus[key]
|
}
|
||||||
}));
|
return this.servicesStatus ? this.servicesStatus : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getProcesses(): { name: string, status: string }[] {
|
||||||
|
if (!this.status) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return this.processesStatus ? this.processesStatus : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
searchImages(): void {
|
searchImages(): void {
|
||||||
|
@ -207,64 +222,6 @@ export class MainRepositoryViewComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
editImage(event: MouseEvent, image: any): void {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.dialog.open(CreateImageComponent, {
|
|
||||||
width: '800px',
|
|
||||||
data: image['@id']
|
|
||||||
}).afterClosed().subscribe(() => this.searchImages());
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteImage(image: any): void {
|
|
||||||
this.dialog.open(DeleteModalComponent, {
|
|
||||||
width: '300px',
|
|
||||||
data: { name: image.name },
|
|
||||||
}).afterClosed().subscribe((result) => {
|
|
||||||
if (result) {
|
|
||||||
this.http.delete(`${this.apiUrl}/server/${image.uuid}/delete`).subscribe({
|
|
||||||
next: () => {
|
|
||||||
this.toastService.success('Imagen eliminada con éxito');
|
|
||||||
this.searchImages();
|
|
||||||
},
|
|
||||||
error: (error) => {
|
|
||||||
this.toastService.error(error.error['hydra:description']);
|
|
||||||
console.error('Error al eliminar la imagen:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadImageAlert(image: any): Observable<any> {
|
|
||||||
return this.http.get<any>(`${this.apiUrl}/server/${image.uuid}/get`, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
showImageInfo(event: MouseEvent, image:any) {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.loadImageAlert(image).subscribe(
|
|
||||||
response => {
|
|
||||||
this.alertMessage = response.output;
|
|
||||||
|
|
||||||
this.dialog.open(ServerInfoDialogComponent, {
|
|
||||||
width: '600px',
|
|
||||||
data: {
|
|
||||||
message: this.alertMessage
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
this.toastService.error(error.error['hydra:description']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onPageChange(event: any): void {
|
|
||||||
this.page = event.pageIndex;
|
|
||||||
this.itemsPerPage = event.pageSize;
|
|
||||||
this.length = event.length;
|
|
||||||
this.searchImages();
|
|
||||||
}
|
|
||||||
|
|
||||||
loadAlert(): Observable<any> {
|
loadAlert(): Observable<any> {
|
||||||
return this.http.get<any>(`${this.baseUrl}/image-repositories/server/get-collection`);
|
return this.http.get<any>(`${this.baseUrl}/image-repositories/server/get-collection`);
|
||||||
}
|
}
|
||||||
|
@ -280,29 +237,6 @@ export class MainRepositoryViewComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
toggleAction(image: any, action:string): void {
|
|
||||||
switch (action) {
|
|
||||||
case 'get-aux':
|
|
||||||
this.http.post(`${this.baseUrl}/images/server/${image.uuid}/create-aux-files`, {}).subscribe({
|
|
||||||
next: () => {
|
|
||||||
this.toastService.success('Petición de creación de archivos auxiliares enviada');
|
|
||||||
this.searchImages()
|
|
||||||
},
|
|
||||||
error: (error) => {
|
|
||||||
this.toastService.error(error.error['hydra:description']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
this.deleteImage(image);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error('Acción no soportada:', action);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openImageInfoDialog() {
|
openImageInfoDialog() {
|
||||||
this.loadAlert().subscribe(
|
this.loadAlert().subscribe(
|
||||||
response => {
|
response => {
|
||||||
|
|
|
@ -100,3 +100,10 @@ table {
|
||||||
margin: 8px 8px 8px 0;
|
margin: 8px 8px 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-container-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
<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>
|
||||||
</button>
|
</button>
|
||||||
<h2 class="title" joyrideStep="titleStep" text="Desde esta pantalla podrás ver y administrar los respositioros exitentes.">Administrar repositorios</h2>
|
<div class="header-container-title">
|
||||||
|
<h2 joyrideStep="groupsTitleStepText" text="{{ 'groupsTitleStepText' | translate }}">
|
||||||
|
{{ 'repositoryTitle' | translate }}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
<div class="images-button-row">
|
<div class="images-button-row">
|
||||||
<button mat-flat-button color="primary" (click)="addImage()" joyrideStep="addStep" text="Utiliza este botón para añadir un nuevo repositorio.">Añadir repositorio</button>
|
<button mat-flat-button color="primary" (click)="addImage()" joyrideStep="addStep" text="Utiliza este botón para añadir un nuevo repositorio.">Añadir repositorio</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,11 +15,17 @@
|
||||||
|
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<mat-form-field appearance="fill" class="search-string">
|
<mat-form-field appearance="fill" class="search-string">
|
||||||
<mat-label>Buscar nombre de imagen</mat-label>
|
<mat-label>Buscar nombre de repositorio</mat-label>
|
||||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
|
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['name']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
|
||||||
<mat-icon matSuffix>search</mat-icon>
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
<mat-hint>Pulsar 'enter' para buscar</mat-hint>
|
<mat-hint>Pulsar 'enter' para buscar</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
<mat-form-field appearance="fill" class="search-string">
|
||||||
|
<mat-label>Buscar IP de repositorio</mat-label>
|
||||||
|
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['ip']" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
|
||||||
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
|
<mat-hint>Pulsar 'enter' para buscar</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
|
||||||
|
@ -30,9 +40,10 @@
|
||||||
|
|
||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||||
<td mat-cell *matCellDef="let client" style="text-align: center;">
|
<td mat-cell *matCellDef="let repository" style="text-align: center;">
|
||||||
<button mat-icon-button color="primary" (click)="editRepository($event, client)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
<button mat-icon-button color="primary" (click)="importImage($event, repository)" i18n="@@editImage"> <mat-icon>download</mat-icon></button>
|
||||||
<button mat-icon-button color="warn" (click)="deleteRepository($event, client)">
|
<button mat-icon-button color="primary" (click)="editRepository($event, repository)" i18n="@@editImage"> <mat-icon>edit</mat-icon></button>
|
||||||
|
<button mat-icon-button color="warn" (click)="deleteRepository($event, repository)">
|
||||||
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
|
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {DeleteModalComponent} from "../../shared/delete_modal/delete-modal/delet
|
||||||
import { JoyrideService } from 'ngx-joyride';
|
import { JoyrideService } from 'ngx-joyride';
|
||||||
import {CreateRepositoryComponent} from "./create-repository/create-repository.component";
|
import {CreateRepositoryComponent} from "./create-repository/create-repository.component";
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import {ImportImageComponent} from "./import-image/import-image.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-repositories',
|
selector: 'app-repositories',
|
||||||
|
@ -91,6 +92,16 @@ export class RepositoriesComponent {
|
||||||
this.router.navigate(['repository', repository.uuid]);
|
this.router.navigate(['repository', repository.uuid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
importImage(event: MouseEvent, repository: any): void {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.dialog.open(ImportImageComponent, {
|
||||||
|
width: '600px',
|
||||||
|
data: { repository }
|
||||||
|
}).afterClosed().subscribe(() => {
|
||||||
|
this.search();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
deleteRepository(event: MouseEvent,command: any): void {
|
deleteRepository(event: MouseEvent,command: any): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.dialog.open(DeleteModalComponent, {
|
this.dialog.open(DeleteModalComponent, {
|
||||||
|
|
|
@ -275,6 +275,7 @@
|
||||||
"ogliveColumn": "OgLive",
|
"ogliveColumn": "OgLive",
|
||||||
"selectImageOption": "Select image",
|
"selectImageOption": "Select image",
|
||||||
"selectOgLiveOption": "Select OgLive",
|
"selectOgLiveOption": "Select OgLive",
|
||||||
|
"repositoryTitle": "Admin Repository",
|
||||||
"saveAssociationsButton": "Save Associations",
|
"saveAssociationsButton": "Save Associations",
|
||||||
"partitionAssistantTitle": "Partition assistant",
|
"partitionAssistantTitle": "Partition assistant",
|
||||||
"diskSizeLabel": "Size",
|
"diskSizeLabel": "Size",
|
||||||
|
|
|
@ -300,6 +300,7 @@
|
||||||
"internalUnits": "Unidades internas",
|
"internalUnits": "Unidades internas",
|
||||||
"noResultsMessage": "No hay resultados para mostrar.",
|
"noResultsMessage": "No hay resultados para mostrar.",
|
||||||
"imagesTitle": "Administrar imágenes",
|
"imagesTitle": "Administrar imágenes",
|
||||||
|
"repositoryTitle": "Administrar repositorios",
|
||||||
"addImageButton": "Añadir imagen",
|
"addImageButton": "Añadir imagen",
|
||||||
"searchNameDescription": "Busca imágenes por nombre para encontrar rápidamente una imagen específica.",
|
"searchNameDescription": "Busca imágenes por nombre para encontrar rápidamente una imagen específica.",
|
||||||
"searchDefaultDescription": "Filtra las imágenes para mostrar solo las imágenes por defecto o no por defecto.",
|
"searchDefaultDescription": "Filtra las imágenes para mostrar solo las imágenes por defecto o no por defecto.",
|
||||||
|
|
Loading…
Reference in New Issue