refactor: fix bugs et réduire duplication + extraire modales BrowseComponent

- fix(dto): ajouter @IsEmail() sur contactFunctionalEmail/TechnicalEmail dans UpdateApiEntryDto
- fix(docs): corriger stringify des erreurs (String(error) → error.message)
- refactor(mapper): extraire toApiEntryListItem() dans api-entry.mapper.ts partagé
- refactor(categories): supprimer CONVENTION_LABELS et toApiEntryListItem locaux dupliqués
- refactor(browse): extraire CategoryFormModalComponent et CategoryDeleteModalComponent
- refactor(api-detail): convertir editPreviewTitle() en computed()

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:
z3n
2026-06-11 15:10:38 +00:00
parent e939d592f8
commit 1adb6820dd
9 changed files with 317 additions and 276 deletions

View File

@@ -0,0 +1,19 @@
import { ApiEntryEntity } from './api-entry.entity';
import { ApiEntryListItem, API_CONVENTION_LABELS } from '@datacat/shared';
export function toApiEntryListItem(entity: ApiEntryEntity): ApiEntryListItem {
return {
id: entity.id,
title: `${API_CONVENTION_LABELS[entity.convention]} ${entity.name}`,
name: entity.name,
convention: entity.convention,
version: `${entity.versionMajor}.${entity.versionMinor}.${entity.versionPatch}`,
description: entity.description,
type: entity.type,
provider: entity.provider,
status: entity.status,
categoryId: entity.categoryId,
createdAt: entity.createdAt.toISOString(),
updatedAt: entity.updatedAt.toISOString(),
};
}

View File

@@ -4,7 +4,8 @@ import { Repository } from 'typeorm';
import { ApiEntryEntity } from './api-entry.entity';
import { CreateApiEntryDto } from './dto/create-api-entry.dto';
import { UpdateApiEntryDto } from './dto/update-api-entry.dto';
import { ApiListResponse, ApiListQuery, ApiEntry, ApiEntryListItem, ApiType, ApiStatus, ApiConvention, API_CONVENTION_LABELS } from '@datacat/shared';
import { ApiListResponse, ApiListQuery, ApiEntry, ApiType, ApiConvention, API_CONVENTION_LABELS } from '@datacat/shared';
import { toApiEntryListItem } from './api-entry.mapper';
import { DocsGenerationService } from '../docs-generation/docs-generation.service';
/** Champs internes mis à jour par DocsGenerationService */
@@ -151,19 +152,3 @@ function toApiEntry(entity: ApiEntryEntity): ApiEntry {
};
}
function toApiEntryListItem(entity: ApiEntryEntity): ApiEntryListItem {
return {
id: entity.id,
title: buildTitle(entity.convention, entity.name),
name: entity.name,
convention: entity.convention,
version: buildVersion(entity.versionMajor, entity.versionMinor, entity.versionPatch),
description: entity.description,
type: entity.type,
provider: entity.provider,
status: entity.status,
categoryId: entity.categoryId,
createdAt: entity.createdAt.toISOString(),
updatedAt: entity.updatedAt.toISOString(),
};
}

View File

@@ -1,4 +1,4 @@
import { IsString, IsOptional, IsUUID, IsIn, IsInt, Min } from 'class-validator';
import { IsString, IsOptional, IsUUID, IsIn, IsInt, Min, IsEmail } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiConvention } from '@datacat/shared';
@@ -49,7 +49,7 @@ export class UpdateApiEntryDto {
@IsOptional()
contactFunctionalEntity?: string;
@IsString()
@IsEmail()
@IsOptional()
contactFunctionalEmail?: string;
@@ -61,7 +61,7 @@ export class UpdateApiEntryDto {
@IsOptional()
contactTechnicalEntity?: string;
@IsString()
@IsEmail()
@IsOptional()
contactTechnicalEmail?: string;
}

View File

@@ -10,11 +10,8 @@ import {
CategoryWithCounts,
CategoryBrowseResponse,
CategoryListResponse,
ApiEntryListItem,
ApiType,
ApiStatus,
ApiConvention,
} from '@datacat/shared';
import { toApiEntryListItem } from '../apis/api-entry.mapper';
@Injectable()
export class CategoriesService {
@@ -151,25 +148,3 @@ function toCategory(entity: CategoryEntity): Category {
};
}
const CONVENTION_LABELS: Record<ApiConvention, string> = {
CONSULTER: 'Consulter',
ENREGISTRER: 'Enregistrer',
ETRE_NOTIFIE: 'Être notifié',
};
function toApiEntryListItem(entity: ApiEntryEntity): ApiEntryListItem {
return {
id: entity.id,
title: `${CONVENTION_LABELS[entity.convention] ?? entity.convention} ${entity.name}`,
name: entity.name,
convention: entity.convention,
version: `${entity.versionMajor}.${entity.versionMinor}.${entity.versionPatch}`,
description: entity.description,
type: entity.type as ApiType,
provider: entity.provider,
status: entity.status as ApiStatus,
categoryId: entity.categoryId,
createdAt: entity.createdAt.toISOString(),
updatedAt: entity.updatedAt.toISOString(),
};
}

View File

@@ -46,7 +46,7 @@ export class DocsGenerationService {
} catch (error) {
await this.apisService.updateInternal(entryId, {
status: 'ERROR',
errorMessage: String(error),
errorMessage: error instanceof Error ? error.message : String(error),
});
}
}