test(apis): ajouter tests unitaires ApisService + fix upload nouvelle version
- 21 nouveaux tests couvrant create, findOneOrThrow, remove, findVersionsOf, setCurrent et regenerate (pattern vi.fn() sans NestJS TestingModule) - apis.service.ts : ConflictException sur doublon de version (name+convention+version) - upload.component.ts : verrouillage convention/name/type lors d'une nouvelle version, bannière d'info, alerte et blocage si version déjà existante Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||||
|
import { ConflictException, NotFoundException } from '@nestjs/common';
|
||||||
import { ApisService } from './apis.service';
|
import { ApisService } from './apis.service';
|
||||||
import { ApiType } from '@datacat/shared';
|
import { ApiType } from '@datacat/shared';
|
||||||
|
|
||||||
@@ -154,3 +155,193 @@ describe('ApisService.parseSearchTokens()', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Mocks partagés pour les tests unitaires de ApisService ───────────────────
|
||||||
|
|
||||||
|
const mockRepo = {
|
||||||
|
findOne: vi.fn(),
|
||||||
|
count: vi.fn(),
|
||||||
|
create: vi.fn(),
|
||||||
|
save: vi.fn(),
|
||||||
|
find: vi.fn(),
|
||||||
|
update: vi.fn(),
|
||||||
|
delete: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockDocsService = { generate: vi.fn() };
|
||||||
|
|
||||||
|
let service: ApisService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
service = new ApisService(mockRepo as any, mockDocsService as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
function makeEntity(overrides: Record<string, unknown> = {}) {
|
||||||
|
return {
|
||||||
|
id: 'uuid-1', name: 'Petstore', convention: 'CONSULTER',
|
||||||
|
versionMajor: 1, versionMinor: 0, versionPatch: 0,
|
||||||
|
type: 'OPENAPI', provider: 'DINUM', description: null,
|
||||||
|
yamlContent: 'openapi: "3.0.0"', htmlPath: null,
|
||||||
|
status: 'PENDING', errorMessage: null, categoryId: null,
|
||||||
|
isCurrent: true,
|
||||||
|
contactFunctionalName: '', contactFunctionalEntity: '', contactFunctionalEmail: '',
|
||||||
|
contactTechnicalName: '', contactTechnicalEntity: '', contactTechnicalEmail: '',
|
||||||
|
createdAt: new Date(), updatedAt: new Date(),
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseDto = {
|
||||||
|
name: 'Petstore', convention: 'CONSULTER' as const,
|
||||||
|
versionMajor: 1, versionMinor: 0, versionPatch: 0,
|
||||||
|
type: 'OPENAPI' as const, provider: 'DINUM',
|
||||||
|
yamlContent: 'openapi: "3.0.0"',
|
||||||
|
contactFunctionalName: 'Alice', contactFunctionalEntity: 'DINUM', contactFunctionalEmail: 'alice@dinum.fr',
|
||||||
|
contactTechnicalName: 'Bob', contactTechnicalEntity: 'DINUM', contactTechnicalEmail: 'bob@dinum.fr',
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── ApisService.create() ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('ApisService.create()', () => {
|
||||||
|
it('crée l\'entrée et la retourne', async () => {
|
||||||
|
const entity = makeEntity();
|
||||||
|
mockRepo.findOne.mockResolvedValue(null);
|
||||||
|
mockRepo.count.mockResolvedValue(0);
|
||||||
|
mockRepo.create.mockReturnValue(entity);
|
||||||
|
mockRepo.save.mockResolvedValue(entity);
|
||||||
|
|
||||||
|
const result = await service.create(baseDto as any);
|
||||||
|
|
||||||
|
expect(result.id).toBe('uuid-1');
|
||||||
|
expect(result.title).toBe('Consulter Petstore');
|
||||||
|
expect(result.version).toBe('1.0.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('lève ConflictException si doublon', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(makeEntity());
|
||||||
|
|
||||||
|
await expect(service.create(baseDto as any)).rejects.toThrow(ConflictException);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isCurrent=true si première version', async () => {
|
||||||
|
const entity = makeEntity({ isCurrent: true });
|
||||||
|
mockRepo.findOne.mockResolvedValue(null);
|
||||||
|
mockRepo.count.mockResolvedValue(0);
|
||||||
|
mockRepo.create.mockReturnValue(entity);
|
||||||
|
mockRepo.save.mockResolvedValue(entity);
|
||||||
|
|
||||||
|
await service.create(baseDto as any);
|
||||||
|
|
||||||
|
expect(mockRepo.create).toHaveBeenCalledWith(expect.objectContaining({ isCurrent: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isCurrent=false si version ultérieure', async () => {
|
||||||
|
const entity = makeEntity({ isCurrent: false });
|
||||||
|
mockRepo.findOne.mockResolvedValue(null);
|
||||||
|
mockRepo.count.mockResolvedValue(1);
|
||||||
|
mockRepo.create.mockReturnValue(entity);
|
||||||
|
mockRepo.save.mockResolvedValue(entity);
|
||||||
|
|
||||||
|
await service.create(baseDto as any);
|
||||||
|
|
||||||
|
expect(mockRepo.create).toHaveBeenCalledWith(expect.objectContaining({ isCurrent: false }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── ApisService.findOneOrThrow() ────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('ApisService.findOneOrThrow()', () => {
|
||||||
|
it('retourne l\'entrée mappée si trouvée', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(makeEntity());
|
||||||
|
|
||||||
|
const result = await service.findOneOrThrow('uuid-1');
|
||||||
|
|
||||||
|
expect(result.id).toBe('uuid-1');
|
||||||
|
expect(result.title).toBe('Consulter Petstore');
|
||||||
|
expect(result.version).toBe('1.0.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('lève NotFoundException si absente', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(null);
|
||||||
|
|
||||||
|
await expect(service.findOneOrThrow('uuid-unknown')).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── ApisService.remove() ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('ApisService.remove()', () => {
|
||||||
|
it('supprime l\'entrée si elle existe', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(makeEntity());
|
||||||
|
mockRepo.delete.mockResolvedValue({ affected: 1 });
|
||||||
|
|
||||||
|
await service.remove('uuid-1');
|
||||||
|
|
||||||
|
expect(mockRepo.delete).toHaveBeenCalledWith('uuid-1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('lève NotFoundException si absente', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(null);
|
||||||
|
|
||||||
|
await expect(service.remove('uuid-unknown')).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── ApisService.findVersionsOf() ────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('ApisService.findVersionsOf()', () => {
|
||||||
|
it('retourne toutes les versions (même name+convention)', async () => {
|
||||||
|
const entity1 = makeEntity({ id: 'uuid-1', versionMajor: 2 });
|
||||||
|
const entity2 = makeEntity({ id: 'uuid-2', versionMajor: 1 });
|
||||||
|
mockRepo.findOne.mockResolvedValue(entity1);
|
||||||
|
mockRepo.find.mockResolvedValue([entity1, entity2]);
|
||||||
|
|
||||||
|
const result = await service.findVersionsOf('uuid-1');
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2);
|
||||||
|
expect(result[0].id).toBe('uuid-1');
|
||||||
|
expect(result[1].id).toBe('uuid-2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('lève NotFoundException si id inconnu', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(null);
|
||||||
|
|
||||||
|
await expect(service.findVersionsOf('uuid-unknown')).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── ApisService.setCurrent() ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('ApisService.setCurrent()', () => {
|
||||||
|
it('met isCurrent=false sur les siblings puis true sur la cible', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(makeEntity());
|
||||||
|
mockRepo.update.mockResolvedValue({ affected: 1 });
|
||||||
|
|
||||||
|
await service.setCurrent('uuid-1');
|
||||||
|
|
||||||
|
expect(mockRepo.update).toHaveBeenCalledWith(
|
||||||
|
{ name: 'Petstore', convention: 'CONSULTER' },
|
||||||
|
{ isCurrent: false },
|
||||||
|
);
|
||||||
|
expect(mockRepo.update).toHaveBeenCalledWith(
|
||||||
|
{ id: 'uuid-1' },
|
||||||
|
{ isCurrent: true },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── ApisService.regenerate() ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('ApisService.regenerate()', () => {
|
||||||
|
it('remet le statut à PENDING et appelle docsService.generate()', async () => {
|
||||||
|
mockRepo.findOne.mockResolvedValue(makeEntity());
|
||||||
|
mockRepo.update.mockResolvedValue({ affected: 1 });
|
||||||
|
mockDocsService.generate.mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
await service.regenerate('uuid-1');
|
||||||
|
|
||||||
|
expect(mockRepo.update).toHaveBeenCalledWith('uuid-1', { status: 'PENDING', errorMessage: null });
|
||||||
|
expect(mockDocsService.generate).toHaveBeenCalledWith('uuid-1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable, NotFoundException, Inject, forwardRef } from '@nestjs/common';
|
import { Injectable, NotFoundException, ConflictException, Inject, forwardRef } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { ApiEntryEntity } from './api-entry.entity';
|
import { ApiEntryEntity } from './api-entry.entity';
|
||||||
@@ -25,6 +25,22 @@ export class ApisService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(dto: CreateApiEntryDto): Promise<ApiEntry> {
|
async create(dto: CreateApiEntryDto): Promise<ApiEntry> {
|
||||||
|
// Vérifier qu'il n'existe pas déjà une entrée avec le même tuple (name, convention, version)
|
||||||
|
const duplicate = await this.repo.findOne({
|
||||||
|
where: {
|
||||||
|
name: dto.name,
|
||||||
|
convention: dto.convention,
|
||||||
|
versionMajor: dto.versionMajor,
|
||||||
|
versionMinor: dto.versionMinor,
|
||||||
|
versionPatch: dto.versionPatch,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (duplicate) {
|
||||||
|
throw new ConflictException(
|
||||||
|
`La version ${dto.versionMajor}.${dto.versionMinor}.${dto.versionPatch} existe déjà pour l'API "${dto.name}".`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Première version si aucune entrée avec le même name + convention
|
// Première version si aucune entrée avec le même name + convention
|
||||||
const existingCount = await this.repo.count({
|
const existingCount = await this.repo.count({
|
||||||
where: { name: dto.name, convention: dto.convention },
|
where: { name: dto.name, convention: dto.convention },
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
|
|||||||
import { Router, RouterLink, ActivatedRoute } from '@angular/router';
|
import { Router, RouterLink, ActivatedRoute } from '@angular/router';
|
||||||
import { ApiService } from '../../core/api.service';
|
import { ApiService } from '../../core/api.service';
|
||||||
import { CategoryService } from '../../core/category.service';
|
import { CategoryService } from '../../core/category.service';
|
||||||
import { ApiEntry, Category, API_CONVENTION_LABELS, ApiConvention } from '@datacat/shared';
|
import { ApiEntry, ApiEntryListItem, Category, API_CONVENTION_LABELS, ApiConvention } from '@datacat/shared';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-upload',
|
selector: 'app-upload',
|
||||||
@@ -137,6 +137,16 @@ import { ApiEntry, Category, API_CONVENTION_LABELS, ApiConvention } from '@datac
|
|||||||
|
|
||||||
<!-- Étape 2 : Informations -->
|
<!-- Étape 2 : Informations -->
|
||||||
@if (step() === 2) {
|
@if (step() === 2) {
|
||||||
|
<!-- Bannière nouvelle version -->
|
||||||
|
@if (fromApi(); as origin) {
|
||||||
|
<div class="fr-callout fr-callout--blue-cumulus fr-mb-3w">
|
||||||
|
<p class="fr-callout__text">
|
||||||
|
Nouvelle version de : <strong>{{ origin.title }}</strong> (v{{ origin.version }})
|
||||||
|
— le nom et la convention sont verrouillés.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<form [formGroup]="metaForm" (ngSubmit)="goToStep3()" novalidate>
|
<form [formGroup]="metaForm" (ngSubmit)="goToStep3()" novalidate>
|
||||||
|
|
||||||
<!-- Titre : convention + nom -->
|
<!-- Titre : convention + nom -->
|
||||||
@@ -240,7 +250,7 @@ import { ApiEntry, Category, API_CONVENTION_LABELS, ApiConvention } from '@datac
|
|||||||
|
|
||||||
<!-- Version X.Y.Z -->
|
<!-- Version X.Y.Z -->
|
||||||
<p class="fr-label fr-mb-1w">Version <span style="color:var(--text-default-error)">*</span></p>
|
<p class="fr-label fr-mb-1w">Version <span style="color:var(--text-default-error)">*</span></p>
|
||||||
<div class="fr-grid-row fr-grid-row--gutters fr-mb-3w">
|
<div class="fr-grid-row fr-grid-row--gutters fr-mb-1w">
|
||||||
<div class="fr-col-4">
|
<div class="fr-col-4">
|
||||||
<div class="fr-input-group" [class.fr-input-group--error]="versionMajorInvalid()">
|
<div class="fr-input-group" [class.fr-input-group--error]="versionMajorInvalid()">
|
||||||
<label class="fr-label" for="version-major-input">Majeure (X)</label>
|
<label class="fr-label" for="version-major-input">Majeure (X)</label>
|
||||||
@@ -285,8 +295,18 @@ import { ApiEntry, Category, API_CONVENTION_LABELS, ApiConvention } from '@datac
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (versionAlreadyExists()) {
|
||||||
|
<div class="fr-alert fr-alert--warning fr-mb-3w">
|
||||||
|
<p class="fr-alert__title">Version déjà existante</p>
|
||||||
|
<p>
|
||||||
|
La version {{ formValues().versionMajor }}.{{ formValues().versionMinor }}.{{ formValues().versionPatch }}
|
||||||
|
existe déjà pour cette API. Choisissez un numéro de version différent.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="fr-btns-group fr-btns-group--inline-sm">
|
<div class="fr-btns-group fr-btns-group--inline-sm">
|
||||||
<button type="submit" class="fr-btn">Suivant</button>
|
<button type="submit" class="fr-btn" [disabled]="versionAlreadyExists()">Suivant</button>
|
||||||
<button type="button" class="fr-btn fr-btn--secondary" (click)="step.set(1)">
|
<button type="button" class="fr-btn fr-btn--secondary" (click)="step.set(1)">
|
||||||
Retour
|
Retour
|
||||||
</button>
|
</button>
|
||||||
@@ -411,7 +431,7 @@ import { ApiEntry, Category, API_CONVENTION_LABELS, ApiConvention } from '@datac
|
|||||||
</div>
|
</div>
|
||||||
<div class="fr-col-12 fr-col-md-6">
|
<div class="fr-col-12 fr-col-md-6">
|
||||||
<dt class="fr-text--bold">Type</dt>
|
<dt class="fr-text--bold">Type</dt>
|
||||||
<dd>{{ metaForm.value.type }}</dd>
|
<dd>{{ displayType() }}</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="fr-col-12">
|
<div class="fr-col-12">
|
||||||
<dt class="fr-text--bold">Titre</dt>
|
<dt class="fr-text--bold">Titre</dt>
|
||||||
@@ -499,6 +519,10 @@ export class UploadComponent implements OnInit {
|
|||||||
validationDone = signal(false);
|
validationDone = signal(false);
|
||||||
validationErrors = signal<Array<{ file: string; message: string }>>([]);
|
validationErrors = signal<Array<{ file: string; message: string }>>([]);
|
||||||
categories = signal<Category[]>([]);
|
categories = signal<Category[]>([]);
|
||||||
|
/* API d'origine lors d'une création de nouvelle version (from=<id>) */
|
||||||
|
fromApi = signal<ApiEntry | null>(null);
|
||||||
|
/* Versions existantes de l'API d'origine (pour détecter les doublons) */
|
||||||
|
existingVersions = signal<ApiEntryListItem[]>([]);
|
||||||
|
|
||||||
readonly stepTitles = [
|
readonly stepTitles = [
|
||||||
'Choisir le fichier',
|
'Choisir le fichier',
|
||||||
@@ -540,16 +564,35 @@ export class UploadComponent implements OnInit {
|
|||||||
|
|
||||||
previewTitle = computed(() => {
|
previewTitle = computed(() => {
|
||||||
const values = this.formValues();
|
const values = this.formValues();
|
||||||
const convention = (values.convention ?? 'CONSULTER') as ApiConvention;
|
const origin = this.fromApi();
|
||||||
const name = values.name ?? '';
|
/* Quand convention/name sont désactivés, ils sont absents de valueChanges → fallback sur fromApi */
|
||||||
|
const convention = (values.convention ?? origin?.convention ?? 'CONSULTER') as ApiConvention;
|
||||||
|
const name = values.name ?? origin?.name ?? '';
|
||||||
return `${API_CONVENTION_LABELS[convention]} ${name}`.trim();
|
return `${API_CONVENTION_LABELS[convention]} ${name}`.trim();
|
||||||
});
|
});
|
||||||
|
|
||||||
selectedCategoryName = computed(() => {
|
selectedCategoryName = computed(() => {
|
||||||
const id = this.formValues().categoryId;
|
const id = this.formValues().categoryId;
|
||||||
if (!id) return '';
|
if (!id) return '';
|
||||||
return this.categories().find((c) => c.id === id)?.name ?? '';
|
return this.categories().find((c) => c.id === id)?.name ?? '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* Vérifie si la version saisie existe déjà parmi les versions de l'API d'origine */
|
||||||
|
versionAlreadyExists = computed(() => {
|
||||||
|
const versions = this.existingVersions();
|
||||||
|
if (versions.length === 0) return false;
|
||||||
|
const values = this.formValues();
|
||||||
|
const candidate = `${values.versionMajor ?? 0}.${values.versionMinor ?? 0}.${values.versionPatch ?? 0}`;
|
||||||
|
return versions.some((v) => v.version === candidate);
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Type effectif : getRawValue() inclut les champs désactivés */
|
||||||
|
displayType = computed(() => {
|
||||||
|
const origin = this.fromApi();
|
||||||
|
if (origin) return origin.type;
|
||||||
|
return (this.formValues().type ?? null) as 'ASYNCAPI' | 'OPENAPI' | null;
|
||||||
|
});
|
||||||
|
|
||||||
/* Méthodes de validation (pas de computed — la re-exécution est déclenchée par les événements DOM blur/input) */
|
/* Méthodes de validation (pas de computed — la re-exécution est déclenchée par les événements DOM blur/input) */
|
||||||
conventionInvalid(): boolean {
|
conventionInvalid(): boolean {
|
||||||
return !!(this.metaForm.get('convention')?.invalid && this.metaForm.get('convention')?.touched);
|
return !!(this.metaForm.get('convention')?.invalid && this.metaForm.get('convention')?.touched);
|
||||||
@@ -599,10 +642,15 @@ export class UploadComponent implements OnInit {
|
|||||||
next: (api) => this.prefillFromApi(api),
|
next: (api) => this.prefillFromApi(api),
|
||||||
error: () => {},
|
error: () => {},
|
||||||
});
|
});
|
||||||
|
this.apiService.getVersions(fromId).subscribe({
|
||||||
|
next: (versions) => this.existingVersions.set(versions),
|
||||||
|
error: () => {},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private prefillFromApi(api: ApiEntry): void {
|
private prefillFromApi(api: ApiEntry): void {
|
||||||
|
this.fromApi.set(api);
|
||||||
this.metaForm.patchValue({
|
this.metaForm.patchValue({
|
||||||
convention: api.convention,
|
convention: api.convention,
|
||||||
name: api.name,
|
name: api.name,
|
||||||
@@ -619,6 +667,10 @@ export class UploadComponent implements OnInit {
|
|||||||
contactTechnicalEntity: api.contactTechnicalEntity,
|
contactTechnicalEntity: api.contactTechnicalEntity,
|
||||||
contactTechnicalEmail: api.contactTechnicalEmail,
|
contactTechnicalEmail: api.contactTechnicalEmail,
|
||||||
});
|
});
|
||||||
|
/* Verrouiller les champs qui définissent l'identité de l'API */
|
||||||
|
this.metaForm.get('convention')?.disable();
|
||||||
|
this.metaForm.get('name')?.disable();
|
||||||
|
this.metaForm.get('type')?.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryLabel(cat: Category): string {
|
categoryLabel(cat: Category): string {
|
||||||
@@ -634,7 +686,10 @@ export class UploadComponent implements OnInit {
|
|||||||
this.detectedMainFilename.set(null);
|
this.detectedMainFilename.set(null);
|
||||||
this.validationErrors.set([]);
|
this.validationErrors.set([]);
|
||||||
this.validationDone.set(false);
|
this.validationDone.set(false);
|
||||||
this.metaForm.get('type')?.enable();
|
/* Ne pas réactiver le type s'il est verrouillé par fromApi */
|
||||||
|
if (!this.fromApi()) {
|
||||||
|
this.metaForm.get('type')?.enable();
|
||||||
|
}
|
||||||
|
|
||||||
const input = event.target as HTMLInputElement;
|
const input = event.target as HTMLInputElement;
|
||||||
const fileList = input.files;
|
const fileList = input.files;
|
||||||
@@ -671,6 +726,7 @@ export class UploadComponent implements OnInit {
|
|||||||
this.INFO_FIELDS.forEach((f) => this.metaForm.get(f)?.markAsTouched());
|
this.INFO_FIELDS.forEach((f) => this.metaForm.get(f)?.markAsTouched());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.versionAlreadyExists()) return;
|
||||||
this.step.set(3);
|
this.step.set(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,19 +754,26 @@ export class UploadComponent implements OnInit {
|
|||||||
this.validationDone.set(true);
|
this.validationDone.set(true);
|
||||||
if (!result.valid) {
|
if (!result.valid) {
|
||||||
this.validationErrors.set(result.errors);
|
this.validationErrors.set(result.errors);
|
||||||
this.metaForm.get('type')?.enable();
|
/* Ne pas réactiver le type s'il est verrouillé par fromApi */
|
||||||
|
if (!this.fromApi()) {
|
||||||
|
this.metaForm.get('type')?.enable();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.validationErrors.set([]);
|
this.validationErrors.set([]);
|
||||||
if (result.type) {
|
if (result.type) {
|
||||||
this.detectedType.set(result.type);
|
this.detectedType.set(result.type);
|
||||||
this.metaForm.patchValue({ type: result.type });
|
/* Ne pas modifier le type s'il est verrouillé par fromApi */
|
||||||
this.metaForm.get('type')?.disable();
|
if (!this.fromApi()) {
|
||||||
|
this.metaForm.patchValue({ type: result.type });
|
||||||
|
this.metaForm.get('type')?.disable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (result.mainFile) {
|
if (result.mainFile) {
|
||||||
this.detectedMainFilename.set(result.mainFile);
|
this.detectedMainFilename.set(result.mainFile);
|
||||||
}
|
}
|
||||||
/* Pré-remplissage du formulaire depuis les métadonnées du fichier */
|
/* Pré-remplissage du formulaire depuis les métadonnées du fichier */
|
||||||
if (result.name) this.metaForm.patchValue({ name: result.name });
|
/* Ne pas écraser le nom s'il est verrouillé par fromApi */
|
||||||
|
if (result.name && !this.fromApi()) this.metaForm.patchValue({ name: result.name });
|
||||||
if (result.versionMajor !== null) this.metaForm.patchValue({ versionMajor: result.versionMajor });
|
if (result.versionMajor !== null) this.metaForm.patchValue({ versionMajor: result.versionMajor });
|
||||||
if (result.versionMinor !== null) this.metaForm.patchValue({ versionMinor: result.versionMinor });
|
if (result.versionMinor !== null) this.metaForm.patchValue({ versionMinor: result.versionMinor });
|
||||||
if (result.versionPatch !== null) this.metaForm.patchValue({ versionPatch: result.versionPatch });
|
if (result.versionPatch !== null) this.metaForm.patchValue({ versionPatch: result.versionPatch });
|
||||||
@@ -781,13 +844,13 @@ export class UploadComponent implements OnInit {
|
|||||||
if (/^openapi\s*:/m.test(content)) {
|
if (/^openapi\s*:/m.test(content)) {
|
||||||
this.detectedType.set('OPENAPI');
|
this.detectedType.set('OPENAPI');
|
||||||
this.detectedMainFilename.set(file.name);
|
this.detectedMainFilename.set(file.name);
|
||||||
this.metaForm.patchValue({ type: 'OPENAPI' });
|
if (!this.fromApi()) this.metaForm.patchValue({ type: 'OPENAPI' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (/^asyncapi\s*:/m.test(content)) {
|
if (/^asyncapi\s*:/m.test(content)) {
|
||||||
this.detectedType.set('ASYNCAPI');
|
this.detectedType.set('ASYNCAPI');
|
||||||
this.detectedMainFilename.set(file.name);
|
this.detectedMainFilename.set(file.name);
|
||||||
this.metaForm.patchValue({ type: 'ASYNCAPI' });
|
if (!this.fromApi()) this.metaForm.patchValue({ type: 'ASYNCAPI' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user