refs #2467. Create tag component
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

develop
Manuel Aranda Rosales 2025-07-15 15:25:40 +02:00
parent 0248067d14
commit 0a14bbd486
7 changed files with 275 additions and 8 deletions

View File

@ -159,6 +159,7 @@ import { ClientPendingTasksComponent } from './components/task-logs/client-pendi
import { QueueConfirmationModalComponent } from './shared/queue-confirmation-modal/queue-confirmation-modal.component';
import { ModalOverlayComponent } from './shared/modal-overlay/modal-overlay.component';
import { ScrollToTopComponent } from './shared/scroll-to-top/scroll-to-top.component';
import { CreateTagModalComponent } from './components/repositories/show-git-images/create-tag-modal/create-tag-modal.component';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './locale/', '.json');
@ -274,7 +275,8 @@ registerLocaleData(localeEs, 'es-ES');
SoftwareProfilePartitionComponent,
ClientPendingTasksComponent,
ModalOverlayComponent,
ScrollToTopComponent
ScrollToTopComponent,
CreateTagModalComponent
],
bootstrap: [AppComponent],
imports: [BrowserModule,

View File

@ -0,0 +1,78 @@
.dialog-content {
min-width: 400px;
max-width: 500px;
padding: 0 24px 24px 24px;
}
h2[mat-dialog-title] {
padding: 24px 24px 0 24px;
margin: 0;
}
.commit-info {
background-color: #f5f5f5;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #3f51b5;
}
.commit-info p {
margin: 5px 0;
font-size: 14px;
}
.commit-info strong {
color: #3f51b5;
}
.tag-form {
display: flex;
flex-direction: column;
gap: 15px;
}
.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: #f5f5f5;
color: #333;
border: 1px solid #ddd;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.ordinary-button:hover {
background-color: #e0e0e0;
}
.submit-button {
background-color: #3f51b5;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.submit-button:hover:not(:disabled) {
background-color: #303f9f;
}
.submit-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}

View File

@ -0,0 +1,40 @@
<app-loading [isLoading]="loading"></app-loading>
<h2 mat-dialog-title>Crear Tag para Commit</h2>
<mat-dialog-content class="dialog-content">
<div class="commit-info">
<p><strong>Commit ID:</strong> {{ data.commit.hexsha }}</p>
<p><strong>Mensaje:</strong> {{ data.commit.message }}</p>
</div>
<form [formGroup]="tagForm" (ngSubmit)="createTag()" class="tag-form">
<mat-form-field appearance="fill" class="form-field">
<mat-label>Nombre del tag</mat-label>
<input matInput formControlName="name" placeholder="ej: v1.0.0" required>
<mat-error *ngIf="tagForm.get('name')?.hasError('required')">
El nombre del tag es obligatorio
</mat-error>
<mat-error *ngIf="tagForm.get('name')?.hasError('pattern')">
El nombre del tag solo puede contener letras, números, puntos, guiones y guiones bajos
</mat-error>
<mat-hint>Ejemplo: v1.0.0, release-2024-01, hotfix-bug-123</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="form-field">
<mat-label>Mensaje del tag</mat-label>
<textarea matInput formControlName="message" placeholder="Descripción del tag" required rows="3"></textarea>
<mat-error *ngIf="tagForm.get('message')?.hasError('required')">
El mensaje del tag es obligatorio
</mat-error>
<mat-hint>Descripción del tag (ej: "Release estable de la versión 1.0")</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)="createTag()" [disabled]="tagForm.invalid || loading">
Crear Tag
</button>
</div>

View File

@ -0,0 +1,63 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CreateTagModalComponent } from './create-tag-modal.component';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { ToastrService } from 'ngx-toastr';
import { ConfigService } from '@services/config.service';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
describe('CreateTagModalComponent', () => {
let component: CreateTagModalComponent;
let fixture: ComponentFixture<CreateTagModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [CreateTagModalComponent],
imports: [
MatDialogModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule,
NoopAnimationsModule
],
providers: [
FormBuilder,
HttpClient,
ToastrService,
ConfigService,
provideHttpClient(),
provideHttpClientTesting(),
{
provide: MatDialogRef,
useValue: {}
},
{
provide: MAT_DIALOG_DATA,
useValue: {
commit: {
hexsha: 'test-commit-id',
message: 'Test commit message'
},
repositoryName: 'test-repo'
}
}
]
})
.compileComponents();
fixture = TestBed.createComponent(CreateTagModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,64 @@
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-create-tag-modal',
templateUrl: './create-tag-modal.component.html',
styleUrl: './create-tag-modal.component.css'
})
export class CreateTagModalComponent {
tagForm: FormGroup;
loading: boolean = false;
baseUrl: string;
constructor(
private fb: FormBuilder,
private http: HttpClient,
public dialogRef: MatDialogRef<CreateTagModalComponent>,
private toastService: ToastrService,
private configService: ConfigService,
@Inject(MAT_DIALOG_DATA) public data: { commit: any, repositoryName: string, repositoryUuid: string }
) {
this.baseUrl = this.configService.apiUrl;
this.tagForm = this.fb.group({
name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9._-]+$/)]],
message: ['', Validators.required]
});
}
createTag(): void {
if (this.tagForm.valid) {
this.loading = true;
const payload = {
commit: this.data.commit.hexsha,
name: this.tagForm.value.name,
message: this.tagForm.value.message,
repository: this.data.repositoryName
};
const url = `${this.baseUrl}/image-repositories/server/git/${this.data.repositoryUuid}/create-tag`;
this.http.post(url, payload).subscribe({
next: (response) => {
this.toastService.success('Tag creado correctamente');
this.dialogRef.close(response);
},
error: (error) => {
console.error('Error creating tag:', error);
this.toastService.error(error.error?.message || 'Error al crear el tag');
this.loading = false;
}
});
} else {
this.toastService.error('Por favor, complete todos los campos requeridos');
}
}
close(): void {
this.dialogRef.close();
}
}

View File

@ -95,6 +95,10 @@
<button mat-icon-button color="primary" (click)="toggleAction(commit, 'view-details')" matTooltip="Ver detalles">
<mat-icon>info</mat-icon>
</button>
<button mat-icon-button color="accent" (click)="toggleAction(commit, 'create-tag')" matTooltip="Crear tag">
<mat-icon>local_offer</mat-icon>
</button>
</div>
</td>
</ng-container>

View File

@ -1,4 +1,4 @@
import {Component, Inject, Input, isDevMode, OnInit} from '@angular/core';
import {Component, Inject, isDevMode, OnInit} from '@angular/core';
import {MatTableDataSource} from "@angular/material/table";
import {DatePipe} from "@angular/common";
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
@ -7,13 +7,8 @@ import {ToastrService} from "ngx-toastr";
import {JoyrideService} from "ngx-joyride";
import {ConfigService} from "@services/config.service";
import {Router} from "@angular/router";
import {Observable} from "rxjs";
import {ServerInfoDialogComponent} from "../../ogdhcp/server-info-dialog/server-info-dialog.component";
import {ImportImageComponent} from "../import-image/import-image.component";
import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
import {ExportImageComponent} from "../../images/export-image/export-image.component";
import {BackupImageComponent} from "../backup-image/backup-image.component";
import {EditImageComponent} from "../edit-image/edit-image.component";
import {CreateTagModalComponent} from "./create-tag-modal/create-tag-modal.component";
@Component({
selector: 'app-show-git-commits',
@ -212,6 +207,9 @@ export class ShowGitCommitsComponent implements OnInit{
this.toastService.success('Commit ID copiado al portapapeles');
});
break;
case 'create-tag':
this.openCreateTagDialog(commit);
break;
default:
console.error('Acción no soportada:', action);
break;
@ -253,6 +251,24 @@ export class ShowGitCommitsComponent implements OnInit{
});
}
openCreateTagDialog(commit: any) {
const dialogRef = this.dialog.open(CreateTagModalComponent, {
width: '500px',
data: {
commit: commit,
repositoryName: this.selectedRepository,
repositoryUuid: this.data.repositoryUuid
}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
// Recargar los datos para mostrar el nuevo tag
this.loadData();
}
});
}
goToPage(commit: any) {
window.open(`http://localhost:3100/oggit/${this.selectedRepository}/commit/${commit.hexsha}`, '_blank');
}