Merge pull request 'refs #2669. Added button and componente 'create-backup'' (#42) from develop into main
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details
oggui-debian-package/pipeline/head This commit looks good Details
oggui-debian-package/pipeline/tag This commit looks good Details

Reviewed-on: #42
pull/43/head 0.23.0
Manuel Aranda Rosales 2025-09-08 18:06:20 +02:00
commit f64e17cd71
6 changed files with 227 additions and 3 deletions

View File

@ -163,6 +163,7 @@ import { ScrollToTopComponent } from './shared/scroll-to-top/scroll-to-top.compo
import { CreateTagModalComponent } from './components/repositories/show-git-images/create-tag-modal/create-tag-modal.component';
import { CreateBranchModalComponent } from './components/repositories/show-git-images/create-branch-modal/create-branch-modal.component';
import { ClientLogsModalComponent } from './components/groups/shared/client-logs-modal/client-logs-modal.component';
import { BackupRepositoryModalComponent } from './components/repositories/show-git-images/backup-repository-modal/backup-repository-modal.component';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './locale/', '.json');
@ -282,7 +283,8 @@ registerLocaleData(localeEs, 'es-ES');
CreateTagModalComponent,
CreateBranchModalComponent,
ClientLogsModalComponent,
SafePipe
SafePipe,
BackupRepositoryModalComponent
],
bootstrap: [AppComponent],
imports: [BrowserModule,

View File

@ -0,0 +1,68 @@
.dialog-content {
min-width: 500px;
max-width: 600px;
}
.repository-info {
background-color: #f5f5f5;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #3f51b5;
}
.repository-info p {
margin: 0;
color: #333;
}
.backup-form {
display: flex;
flex-direction: column;
gap: 20px;
}
.form-field {
width: 100%;
}
.action-container {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
padding: 0 24px 24px 24px;
}
.ordinary-button {
background-color: #6c757d;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.ordinary-button:hover {
background-color: #5a6268;
}
.submit-button {
background-color: #28a745;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.submit-button:hover:not(:disabled) {
background-color: #218838;
}
.submit-button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}

View File

@ -0,0 +1,66 @@
<app-loading [isLoading]="loading"></app-loading>
<h2 mat-dialog-title>Crear Backup del Repositorio</h2>
<mat-dialog-content class="dialog-content">
<div class="repository-info">
<p><strong>Repositorio:</strong> {{ data.repositoryName }}</p>
</div>
<form [formGroup]="backupForm" (ngSubmit)="createBackup()" class="backup-form">
<mat-form-field appearance="fill" class="form-field">
<mat-label>Servidor SSH</mat-label>
<input matInput formControlName="ssh_server" placeholder="ej: backup.example.com" required>
<mat-error *ngIf="backupForm.get('ssh_server')?.hasError('required')">
El servidor SSH es obligatorio
</mat-error>
<mat-error *ngIf="backupForm.get('ssh_server')?.hasError('pattern')">
El servidor SSH debe ser una dirección válida (ej: server.com, 192.168.1.100)
</mat-error>
<mat-hint>Dirección del servidor SSH donde se enviará el backup</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field">
<mat-label>Puerto SSH</mat-label>
<input matInput type="number" formControlName="ssh_port" placeholder="22" required>
<mat-error *ngIf="backupForm.get('ssh_port')?.hasError('required')">
El puerto SSH es obligatorio
</mat-error>
<mat-error *ngIf="backupForm.get('ssh_port')?.hasError('min') || backupForm.get('ssh_port')?.hasError('max')">
El puerto debe estar entre 1 y 65535
</mat-error>
<mat-hint>Puerto del servidor SSH (por defecto: 22)</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field">
<mat-label>Usuario SSH</mat-label>
<input matInput formControlName="ssh_user" placeholder="ej: backup_user" required>
<mat-error *ngIf="backupForm.get('ssh_user')?.hasError('required')">
El usuario SSH es obligatorio
</mat-error>
<mat-error *ngIf="backupForm.get('ssh_user')?.hasError('pattern')">
El usuario SSH solo puede contener letras, números, puntos, guiones y guiones bajos
</mat-error>
<mat-hint>Usuario para conectarse al servidor SSH</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field">
<mat-label>Nombre del archivo</mat-label>
<input matInput formControlName="filename" placeholder="ej: backup_repo_2024.tar.gz" required>
<mat-error *ngIf="backupForm.get('filename')?.hasError('required')">
El nombre del archivo es obligatorio
</mat-error>
<mat-error *ngIf="backupForm.get('filename')?.hasError('pattern')">
El archivo debe tener extensión .tar.gz, .zip o .tar
</mat-error>
<mat-hint>Nombre del archivo de backup (debe terminar en .tar.gz, .zip o .tar)</mat-hint>
</mat-form-field>
</form>
</mat-dialog-content>
<div mat-dialog-actions class="action-container">
<button class="ordinary-button" (click)="close()">Cancelar</button>
<button class="submit-button" (click)="createBackup()" [disabled]="backupForm.invalid || loading">
Crear Backup
</button>
</div>

View File

@ -0,0 +1,66 @@
import { Component, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
import { ConfigService } from '@services/config.service';
@Component({
selector: 'app-backup-repository-modal',
templateUrl: './backup-repository-modal.component.html',
styleUrl: './backup-repository-modal.component.css'
})
export class BackupRepositoryModalComponent {
backupForm: FormGroup;
loading: boolean = false;
baseUrl: string;
constructor(
private fb: FormBuilder,
private http: HttpClient,
public dialogRef: MatDialogRef<BackupRepositoryModalComponent>,
private toastService: ToastrService,
private configService: ConfigService,
@Inject(MAT_DIALOG_DATA) public data: { repositoryName: string, repositoryUuid: string }
) {
this.baseUrl = this.configService.apiUrl;
this.backupForm = this.fb.group({
ssh_server: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9.-]+$/)]],
ssh_port: ['22', [Validators.required, Validators.min(1), Validators.max(65535)]],
ssh_user: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9._-]+$/)]],
filename: ['', [Validators.required, Validators.pattern(/\.(tar\.gz|zip|tar)$/)]]
});
}
createBackup(): void {
if (this.backupForm.valid) {
this.loading = true;
const payload = {
repository: this.data.repositoryName,
sshServer: this.backupForm.value.ssh_server,
sshPort: parseInt(this.backupForm.value.ssh_port),
sshUser: this.backupForm.value.ssh_user,
filename: this.backupForm.value.filename
};
const url = `${this.baseUrl}/image-repositories/server/git/${this.data.repositoryUuid}/create-backup`;
this.http.post(url, payload).subscribe({
next: (response) => {
this.toastService.success('Backup iniciado correctamente');
this.dialogRef.close(response);
},
error: (error) => {
this.toastService.error(error.error?.message || 'Error al iniciar el backup');
this.loading = false;
}
});
} else {
this.toastService.error('Por favor, complete todos los campos requeridos correctamente');
}
}
close(): void {
this.dialogRef.close();
}
}

View File

@ -10,6 +10,7 @@
</div>
<div class="images-button-row">
<button class="action-button" (click)="openImageInfoDialog()">Ver Información</button>
<button class="action-button" (click)="openBackupDialog()">Crear Backup</button>
</div>
</div>

View File

@ -10,6 +10,7 @@ import {Router} from "@angular/router";
import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
import {CreateTagModalComponent} from "./create-tag-modal/create-tag-modal.component";
import {CreateBranchModalComponent} from "./create-branch-modal/create-branch-modal.component";
import { BackupRepositoryModalComponent } from './backup-repository-modal/backup-repository-modal.component';
@Component({
selector: 'app-show-git-commits',
@ -267,12 +268,33 @@ export class ShowGitCommitsComponent implements OnInit{
dialogRef.afterClosed().subscribe(result => {
if (result) {
// Recargar los datos para mostrar el nuevo tag
this.loadData();
}
});
}
openBackupDialog() {
if (!this.selectedRepository) {
this.toastService.warning('Por favor, selecciona un repositorio primero');
return;
}
const dialogRef = this.dialog.open(BackupRepositoryModalComponent, {
width: '600px',
data: {
repositoryName: this.selectedRepository,
repositoryUuid: this.data.repositoryUuid
}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.toastService.success('Backup iniciado correctamente');
}
});
}
openCreateBranchDialog(commit: any) {
const dialogRef = this.dialog.open(CreateBranchModalComponent, {
width: '500px',
@ -285,7 +307,6 @@ export class ShowGitCommitsComponent implements OnInit{
dialogRef.afterClosed().subscribe(result => {
if (result) {
// Recargar los datos para mostrar la nueva rama
this.loadBranches();
this.loadData();
}